TextureCache: Speed up descriptor writes (no more vector usage)
WIP TextureCube uploading skeleton
This commit is contained in:
parent
450ca87120
commit
f194d261b1
|
@ -160,6 +160,11 @@ TextureCache::TextureCache(Memory* memory, RegisterFile* register_file,
|
||||||
invalidated_textures_sets_[0].reserve(64);
|
invalidated_textures_sets_[0].reserve(64);
|
||||||
invalidated_textures_sets_[1].reserve(64);
|
invalidated_textures_sets_[1].reserve(64);
|
||||||
invalidated_textures_ = &invalidated_textures_sets_[0];
|
invalidated_textures_ = &invalidated_textures_sets_[0];
|
||||||
|
|
||||||
|
std::memset(update_set_info_.image_writes, 0,
|
||||||
|
sizeof(update_set_info_.image_writes));
|
||||||
|
std::memset(update_set_info_.image_infos, 0,
|
||||||
|
sizeof(update_set_info_.image_infos));
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureCache::~TextureCache() {
|
TextureCache::~TextureCache() {
|
||||||
|
@ -408,17 +413,12 @@ TextureCache::Texture* TextureCache::Demand(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!command_buffer) {
|
if (!command_buffer || texture_info.dimension != Dimension::k2D) {
|
||||||
// Texture not found and no command buffer was passed, preventing us from
|
// Texture not found and no command buffer was passed, preventing us from
|
||||||
// uploading a new one.
|
// uploading a new one.
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (texture_info.dimension != Dimension::k2D) {
|
|
||||||
// Abort.
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a new texture and cache it.
|
// Create a new texture and cache it.
|
||||||
auto texture = AllocateTexture(texture_info);
|
auto texture = AllocateTexture(texture_info);
|
||||||
if (!texture) {
|
if (!texture) {
|
||||||
|
@ -433,6 +433,10 @@ TextureCache::Texture* TextureCache::Demand(
|
||||||
uploaded = UploadTexture2D(command_buffer, completion_fence, texture,
|
uploaded = UploadTexture2D(command_buffer, completion_fence, texture,
|
||||||
texture_info);
|
texture_info);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case Dimension::kCube: {
|
||||||
|
} break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
assert_unhandled_case(texture_info.dimension);
|
assert_unhandled_case(texture_info.dimension);
|
||||||
break;
|
break;
|
||||||
|
@ -463,8 +467,11 @@ TextureCache::Texture* TextureCache::Demand(
|
||||||
// woods yet. This texture could either be a portion of another texture or
|
// woods yet. This texture could either be a portion of another texture or
|
||||||
// vice versa. Copy any overlapping textures into this texture.
|
// vice versa. Copy any overlapping textures into this texture.
|
||||||
// TODO: Byte count -> pixel count (on x and y axes)
|
// TODO: Byte count -> pixel count (on x and y axes)
|
||||||
|
/*
|
||||||
for (auto it = textures_.begin(); it != textures_.end(); ++it) {
|
for (auto it = textures_.begin(); it != textures_.end(); ++it) {
|
||||||
|
// TODO(DrChat)
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// Okay. Now that the texture is uploaded from system memory, put a writewatch
|
// Okay. Now that the texture is uploaded from system memory, put a writewatch
|
||||||
// on it to tell us if it's been modified from the guest.
|
// on it to tell us if it's been modified from the guest.
|
||||||
|
@ -778,7 +785,8 @@ bool TextureCache::UploadTexture2D(
|
||||||
|
|
||||||
assert_true(src.dimension == Dimension::k2D);
|
assert_true(src.dimension == Dimension::k2D);
|
||||||
|
|
||||||
if (!staging_buffer_.CanAcquire(src.input_length)) {
|
size_t unpack_length = src.output_length;
|
||||||
|
if (!staging_buffer_.CanAcquire(unpack_length)) {
|
||||||
// Need to have unique memory for every upload for at least one frame. If we
|
// Need to have unique memory for every upload for at least one frame. If we
|
||||||
// run out of memory, we need to flush all queued upload commands to the
|
// run out of memory, we need to flush all queued upload commands to the
|
||||||
// GPU.
|
// GPU.
|
||||||
|
@ -787,7 +795,6 @@ bool TextureCache::UploadTexture2D(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Grab some temporary memory for staging.
|
// Grab some temporary memory for staging.
|
||||||
size_t unpack_length = src.output_length;
|
|
||||||
auto alloc = staging_buffer_.Acquire(unpack_length, completion_fence);
|
auto alloc = staging_buffer_.Acquire(unpack_length, completion_fence);
|
||||||
assert_not_null(alloc);
|
assert_not_null(alloc);
|
||||||
|
|
||||||
|
@ -896,6 +903,13 @@ bool TextureCache::UploadTexture2D(
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TextureCache::UploadTextureCube(
|
||||||
|
VkCommandBuffer command_buffer,
|
||||||
|
std::shared_ptr<ui::vulkan::Fence> completion_fence, Texture* dest,
|
||||||
|
TextureInfo src) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
VkDescriptorSet TextureCache::PrepareTextureSet(
|
VkDescriptorSet TextureCache::PrepareTextureSet(
|
||||||
VkCommandBuffer command_buffer,
|
VkCommandBuffer command_buffer,
|
||||||
std::shared_ptr<ui::vulkan::Fence> completion_fence,
|
std::shared_ptr<ui::vulkan::Fence> completion_fence,
|
||||||
|
@ -939,74 +953,14 @@ VkDescriptorSet TextureCache::PrepareTextureSet(
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write all updated descriptors.
|
|
||||||
// TODO(benvanik): optimize? split into multiple sets? set per type?
|
|
||||||
// First: Reorganize and pool image update infos.
|
|
||||||
struct DescriptorInfo {
|
|
||||||
Dimension dimension;
|
|
||||||
uint32_t tf_binding_base;
|
|
||||||
std::vector<VkDescriptorImageInfo> infos;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<DescriptorInfo> descriptor_update_infos;
|
|
||||||
for (uint32_t i = 0; i < update_set_info->image_write_count; i++) {
|
for (uint32_t i = 0; i < update_set_info->image_write_count; i++) {
|
||||||
auto& image_info = update_set_info->image_infos[i];
|
update_set_info->image_writes[i].dstSet = descriptor_set;
|
||||||
if (descriptor_update_infos.size() > 0) {
|
|
||||||
// Check last write to see if we can pool more into it.
|
|
||||||
DescriptorInfo& last_write =
|
|
||||||
descriptor_update_infos[descriptor_update_infos.size() - 1];
|
|
||||||
if (last_write.dimension == image_info.dimension &&
|
|
||||||
last_write.tf_binding_base + last_write.infos.size() ==
|
|
||||||
image_info.tf_binding) {
|
|
||||||
// Compatible! Pool into it.
|
|
||||||
last_write.infos.push_back(image_info.info);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Push a new descriptor write entry.
|
|
||||||
DescriptorInfo desc_info;
|
|
||||||
desc_info.dimension = image_info.dimension;
|
|
||||||
desc_info.tf_binding_base = image_info.tf_binding;
|
|
||||||
desc_info.infos.push_back(image_info.info);
|
|
||||||
descriptor_update_infos.push_back(desc_info);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finalize the writes so they're consumable by Vulkan.
|
// Update the descriptor set.
|
||||||
std::vector<VkWriteDescriptorSet> descriptor_writes;
|
if (update_set_info->image_write_count > 0) {
|
||||||
descriptor_writes.resize(descriptor_update_infos.size());
|
vkUpdateDescriptorSets(*device_, update_set_info->image_write_count,
|
||||||
for (size_t i = 0; i < descriptor_update_infos.size(); i++) {
|
update_set_info->image_writes, 0, nullptr);
|
||||||
auto& update_info = descriptor_update_infos[i];
|
|
||||||
auto& write_info = descriptor_writes[i];
|
|
||||||
std::memset(&write_info, 0, sizeof(VkWriteDescriptorSet));
|
|
||||||
|
|
||||||
write_info.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
|
||||||
write_info.dstSet = descriptor_set;
|
|
||||||
|
|
||||||
switch (update_info.dimension) {
|
|
||||||
case Dimension::k1D:
|
|
||||||
write_info.dstBinding = 0;
|
|
||||||
break;
|
|
||||||
case Dimension::k2D:
|
|
||||||
write_info.dstBinding = 1;
|
|
||||||
break;
|
|
||||||
case Dimension::k3D:
|
|
||||||
write_info.dstBinding = 2;
|
|
||||||
break;
|
|
||||||
case Dimension::kCube:
|
|
||||||
write_info.dstBinding = 3;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
write_info.dstArrayElement = update_info.tf_binding_base;
|
|
||||||
write_info.descriptorCount = uint32_t(update_info.infos.size());
|
|
||||||
write_info.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
|
||||||
write_info.pImageInfo = update_info.infos.data();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (descriptor_writes.size() > 0) {
|
|
||||||
vkUpdateDescriptorSets(*device_, uint32_t(descriptor_writes.size()),
|
|
||||||
descriptor_writes.data(), 0, nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
in_flight_sets_.push_back({descriptor_set, completion_fence});
|
in_flight_sets_.push_back({descriptor_set, completion_fence});
|
||||||
|
@ -1077,13 +1031,38 @@ bool TextureCache::SetupTextureBinding(
|
||||||
trace_writer_->WriteMemoryRead(texture_info.guest_address,
|
trace_writer_->WriteMemoryRead(texture_info.guest_address,
|
||||||
texture_info.input_length);
|
texture_info.input_length);
|
||||||
|
|
||||||
|
auto image_info =
|
||||||
|
&update_set_info->image_infos[update_set_info->image_write_count];
|
||||||
auto image_write =
|
auto image_write =
|
||||||
&update_set_info->image_infos[update_set_info->image_write_count++];
|
&update_set_info->image_writes[update_set_info->image_write_count];
|
||||||
image_write->dimension = texture_info.dimension;
|
update_set_info->image_write_count++;
|
||||||
image_write->tf_binding = binding.fetch_constant;
|
|
||||||
image_write->info.imageView = view->view;
|
std::memset(image_write, 0, sizeof(VkWriteDescriptorSet));
|
||||||
image_write->info.imageLayout = texture->image_layout;
|
image_write->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||||
image_write->info.sampler = sampler->sampler;
|
|
||||||
|
switch (texture_info.dimension) {
|
||||||
|
case Dimension::k1D:
|
||||||
|
image_write->dstBinding = 0;
|
||||||
|
break;
|
||||||
|
case Dimension::k2D:
|
||||||
|
image_write->dstBinding = 1;
|
||||||
|
break;
|
||||||
|
case Dimension::k3D:
|
||||||
|
image_write->dstBinding = 2;
|
||||||
|
break;
|
||||||
|
case Dimension::kCube:
|
||||||
|
image_write->dstBinding = 3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
image_write->dstArrayElement = binding.fetch_constant;
|
||||||
|
image_write->descriptorCount = 1;
|
||||||
|
image_write->descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||||
|
image_write->pImageInfo = image_info;
|
||||||
|
|
||||||
|
image_info->imageView = view->view;
|
||||||
|
image_info->imageLayout = texture->image_layout;
|
||||||
|
image_info->sampler = sampler->sampler;
|
||||||
texture->in_flight_fence = completion_fence;
|
texture->in_flight_fence = completion_fence;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -153,6 +153,10 @@ class TextureCache {
|
||||||
std::shared_ptr<ui::vulkan::Fence> completion_fence,
|
std::shared_ptr<ui::vulkan::Fence> completion_fence,
|
||||||
Texture* dest, TextureInfo src);
|
Texture* dest, TextureInfo src);
|
||||||
|
|
||||||
|
bool UploadTextureCube(VkCommandBuffer command_buffer,
|
||||||
|
std::shared_ptr<ui::vulkan::Fence> completion_fence,
|
||||||
|
Texture* dest, TextureInfo src);
|
||||||
|
|
||||||
bool SetupTextureBindings(
|
bool SetupTextureBindings(
|
||||||
VkCommandBuffer command_buffer,
|
VkCommandBuffer command_buffer,
|
||||||
std::shared_ptr<ui::vulkan::Fence> completion_fence,
|
std::shared_ptr<ui::vulkan::Fence> completion_fence,
|
||||||
|
@ -192,11 +196,8 @@ class TextureCache {
|
||||||
// This prevents duplication across the vertex and pixel shader.
|
// This prevents duplication across the vertex and pixel shader.
|
||||||
uint32_t has_setup_fetch_mask;
|
uint32_t has_setup_fetch_mask;
|
||||||
uint32_t image_write_count = 0;
|
uint32_t image_write_count = 0;
|
||||||
struct ImageSetInfo {
|
VkWriteDescriptorSet image_writes[32];
|
||||||
Dimension dimension;
|
VkDescriptorImageInfo image_infos[32];
|
||||||
uint32_t tf_binding;
|
|
||||||
VkDescriptorImageInfo info;
|
|
||||||
} image_infos[32];
|
|
||||||
} update_set_info_;
|
} update_set_info_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue