[Vulkan] Bind shared memory persistently for texture loads and resolves
Co-authored-by: Herman S. <429230+has207@users.noreply.github.com>
This commit is contained in:
committed by
Radosław Gliński
parent
cb240560df
commit
7101021150
@@ -1184,12 +1184,22 @@ bool VulkanRenderTargetCache::Resolve(
|
||||
} else {
|
||||
// TODO(Triang3l): Switching between descriptors if exceeding
|
||||
// maxStorageBufferRange.
|
||||
// TODO(Triang3l): Use a single 512 MB shared memory binding if
|
||||
// possible.
|
||||
// Bind the whole shared memory buffer persistently when possible
|
||||
// (passing the destination byte offset via dest_base) instead of
|
||||
// allocating and writing a per-resolve descriptor. Scaled resolves
|
||||
// write to separate scaled buffers, so they use transient descriptors.
|
||||
// Decided per resolve, as native copies write to shared memory even
|
||||
// with resolution scaling on.
|
||||
const bool use_persistent_dest =
|
||||
texture_cache.shared_memory_persistent_descriptor_set() !=
|
||||
VK_NULL_HANDLE &&
|
||||
!copy_dest_scaled;
|
||||
VkDescriptorSet descriptor_set_dest =
|
||||
command_processor_.AllocateSingleTransientDescriptor(
|
||||
VulkanCommandProcessor::SingleTransientDescriptorLayout ::
|
||||
kStorageBufferCompute);
|
||||
use_persistent_dest
|
||||
? texture_cache.shared_memory_persistent_descriptor_set()
|
||||
: command_processor_.AllocateSingleTransientDescriptor(
|
||||
VulkanCommandProcessor::SingleTransientDescriptorLayout ::
|
||||
kStorageBufferCompute);
|
||||
if (descriptor_set_dest != VK_NULL_HANDLE) {
|
||||
// Write the destination descriptor.
|
||||
VkDescriptorBufferInfo write_descriptor_set_dest_buffer_info;
|
||||
@@ -1256,7 +1266,7 @@ bool VulkanRenderTargetCache::Resolve(
|
||||
}
|
||||
}
|
||||
|
||||
if (!scaled_buffer_ready) {
|
||||
if (!scaled_buffer_ready && !use_persistent_dest) {
|
||||
// Write unscaled or native resolves to shared memory.
|
||||
if (copy_dest_scaled) {
|
||||
XELOGW(
|
||||
@@ -1273,22 +1283,24 @@ bool VulkanRenderTargetCache::Resolve(
|
||||
resolve_info.copy_dest_base +
|
||||
resolve_info.copy_dest_extent_length;
|
||||
}
|
||||
VkWriteDescriptorSet write_descriptor_set_dest;
|
||||
write_descriptor_set_dest.sType =
|
||||
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
write_descriptor_set_dest.pNext = nullptr;
|
||||
write_descriptor_set_dest.dstSet = descriptor_set_dest;
|
||||
write_descriptor_set_dest.dstBinding = 0;
|
||||
write_descriptor_set_dest.dstArrayElement = 0;
|
||||
write_descriptor_set_dest.descriptorCount = 1;
|
||||
write_descriptor_set_dest.descriptorType =
|
||||
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
|
||||
write_descriptor_set_dest.pImageInfo = nullptr;
|
||||
write_descriptor_set_dest.pBufferInfo =
|
||||
&write_descriptor_set_dest_buffer_info;
|
||||
write_descriptor_set_dest.pTexelBufferView = nullptr;
|
||||
dfn.vkUpdateDescriptorSets(device, 1, &write_descriptor_set_dest, 0,
|
||||
nullptr);
|
||||
if (!use_persistent_dest) {
|
||||
VkWriteDescriptorSet write_descriptor_set_dest;
|
||||
write_descriptor_set_dest.sType =
|
||||
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
write_descriptor_set_dest.pNext = nullptr;
|
||||
write_descriptor_set_dest.dstSet = descriptor_set_dest;
|
||||
write_descriptor_set_dest.dstBinding = 0;
|
||||
write_descriptor_set_dest.dstArrayElement = 0;
|
||||
write_descriptor_set_dest.descriptorCount = 1;
|
||||
write_descriptor_set_dest.descriptorType =
|
||||
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
|
||||
write_descriptor_set_dest.pImageInfo = nullptr;
|
||||
write_descriptor_set_dest.pBufferInfo =
|
||||
&write_descriptor_set_dest_buffer_info;
|
||||
write_descriptor_set_dest.pTexelBufferView = nullptr;
|
||||
dfn.vkUpdateDescriptorSets(device, 1, &write_descriptor_set_dest, 0,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
// Submit the resolve.
|
||||
if (!scaled_buffer_ready) {
|
||||
@@ -1345,11 +1357,15 @@ bool VulkanRenderTargetCache::Resolve(
|
||||
sizeof(copy_shader_constants.dest_relative),
|
||||
©_shader_constants.dest_relative);
|
||||
} else {
|
||||
// TODO(Triang3l): Proper dest_base in case of one 512 MB shared
|
||||
// memory binding, or multiple shared memory bindings in case of
|
||||
// TODO(Triang3l): Multiple shared memory bindings in case of
|
||||
// splitting due to maxStorageBufferRange overflow.
|
||||
copy_shader_constants.dest_base -=
|
||||
uint32_t(write_descriptor_set_dest_buffer_info.offset);
|
||||
if (!use_persistent_dest) {
|
||||
// The descriptor is offset to the destination, so make dest_base
|
||||
// relative to it. With the whole buffer bound persistently,
|
||||
// dest_base stays the absolute byte offset.
|
||||
copy_shader_constants.dest_base -=
|
||||
uint32_t(write_descriptor_set_dest_buffer_info.offset);
|
||||
}
|
||||
command_buffer.CmdVkPushConstants(
|
||||
copy_pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 0,
|
||||
sizeof(copy_shader_constants), ©_shader_constants);
|
||||
|
||||
@@ -475,6 +475,10 @@ VulkanTextureCache::~VulkanTextureCache() {
|
||||
if (load_pipeline_layout_ != VK_NULL_HANDLE) {
|
||||
dfn.vkDestroyPipelineLayout(device, load_pipeline_layout_, nullptr);
|
||||
}
|
||||
if (shared_memory_persistent_descriptor_pool_ != VK_NULL_HANDLE) {
|
||||
dfn.vkDestroyDescriptorPool(
|
||||
device, shared_memory_persistent_descriptor_pool_, nullptr);
|
||||
}
|
||||
|
||||
// Textures memory is allocated using the Vulkan Memory Allocator, destroy all
|
||||
// textures before destroying VMA.
|
||||
@@ -1345,6 +1349,13 @@ bool VulkanTextureCache::LoadTextureDataFromResidentMemoryImpl(Texture& texture,
|
||||
const VkDevice device = vulkan_device->device();
|
||||
VulkanSharedMemory& vulkan_shared_memory =
|
||||
static_cast<VulkanSharedMemory&>(shared_memory());
|
||||
// Bind the whole shared memory buffer persistently when possible (passing the
|
||||
// texture's byte offset via guest_offset) instead of allocating and writing
|
||||
// per-load source descriptors. Scaled resolve textures read from separate
|
||||
// scaled buffers, so they always use transient descriptors.
|
||||
const bool use_persistent_source =
|
||||
shared_memory_persistent_descriptor_set_ != VK_NULL_HANDLE &&
|
||||
!texture_key.scaled_resolve;
|
||||
std::array<VkWriteDescriptorSet, 3> write_descriptor_sets;
|
||||
uint32_t write_descriptor_set_count = 0;
|
||||
VkDescriptorSet descriptor_set_dest =
|
||||
@@ -1380,12 +1391,16 @@ bool VulkanTextureCache::LoadTextureDataFromResidentMemoryImpl(Texture& texture,
|
||||
VkDescriptorBufferInfo write_descriptor_set_source_base_buffer_info;
|
||||
VkDescriptorBufferInfo write_descriptor_set_source_mips_buffer_info;
|
||||
if (level_first == 0) {
|
||||
descriptor_set_source_base =
|
||||
command_processor_.AllocateSingleTransientDescriptor(
|
||||
VulkanCommandProcessor::SingleTransientDescriptorLayout ::
|
||||
kStorageBufferCompute);
|
||||
if (!descriptor_set_source_base) {
|
||||
return false;
|
||||
if (use_persistent_source) {
|
||||
descriptor_set_source_base = shared_memory_persistent_descriptor_set_;
|
||||
} else {
|
||||
descriptor_set_source_base =
|
||||
command_processor_.AllocateSingleTransientDescriptor(
|
||||
VulkanCommandProcessor::SingleTransientDescriptorLayout ::
|
||||
kStorageBufferCompute);
|
||||
if (!descriptor_set_source_base) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (texture_key.scaled_resolve) {
|
||||
// For scaled textures, read from scaled resolve buffers
|
||||
@@ -1434,7 +1449,7 @@ bool VulkanTextureCache::LoadTextureDataFromResidentMemoryImpl(Texture& texture,
|
||||
guest_address);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
} else if (!use_persistent_source) {
|
||||
// Regular unscaled texture - use shared memory
|
||||
write_descriptor_set_source_base_buffer_info.buffer =
|
||||
vulkan_shared_memory.buffer();
|
||||
@@ -1445,57 +1460,96 @@ bool VulkanTextureCache::LoadTextureDataFromResidentMemoryImpl(Texture& texture,
|
||||
write_descriptor_set_source_base_buffer_info.range =
|
||||
xe::align(vulkan_texture.GetGuestBaseSize(), uint32_t(16));
|
||||
}
|
||||
VkWriteDescriptorSet& write_descriptor_set_source_base =
|
||||
write_descriptor_sets[write_descriptor_set_count++];
|
||||
write_descriptor_set_source_base.sType =
|
||||
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
write_descriptor_set_source_base.pNext = nullptr;
|
||||
write_descriptor_set_source_base.dstSet = descriptor_set_source_base;
|
||||
write_descriptor_set_source_base.dstBinding = 0;
|
||||
write_descriptor_set_source_base.dstArrayElement = 0;
|
||||
write_descriptor_set_source_base.descriptorCount = 1;
|
||||
write_descriptor_set_source_base.descriptorType =
|
||||
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
|
||||
write_descriptor_set_source_base.pImageInfo = nullptr;
|
||||
write_descriptor_set_source_base.pBufferInfo =
|
||||
&write_descriptor_set_source_base_buffer_info;
|
||||
write_descriptor_set_source_base.pTexelBufferView = nullptr;
|
||||
}
|
||||
// For scaled resolve textures, we don't load mips from buffers - they will
|
||||
// be generated via blit from the base level. For unscaled textures, load
|
||||
// mips from shared memory as usual.
|
||||
if (level_last != 0 && !texture_key.scaled_resolve) {
|
||||
descriptor_set_source_mips =
|
||||
command_processor_.AllocateSingleTransientDescriptor(
|
||||
VulkanCommandProcessor::SingleTransientDescriptorLayout ::
|
||||
kStorageBufferCompute);
|
||||
if (!descriptor_set_source_mips) {
|
||||
return false;
|
||||
if (!use_persistent_source) {
|
||||
VkWriteDescriptorSet& write_descriptor_set_source_base =
|
||||
write_descriptor_sets[write_descriptor_set_count++];
|
||||
write_descriptor_set_source_base.sType =
|
||||
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
write_descriptor_set_source_base.pNext = nullptr;
|
||||
write_descriptor_set_source_base.dstSet = descriptor_set_source_base;
|
||||
write_descriptor_set_source_base.dstBinding = 0;
|
||||
write_descriptor_set_source_base.dstArrayElement = 0;
|
||||
write_descriptor_set_source_base.descriptorCount = 1;
|
||||
write_descriptor_set_source_base.descriptorType =
|
||||
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
|
||||
write_descriptor_set_source_base.pImageInfo = nullptr;
|
||||
write_descriptor_set_source_base.pBufferInfo =
|
||||
&write_descriptor_set_source_base_buffer_info;
|
||||
write_descriptor_set_source_base.pTexelBufferView = nullptr;
|
||||
}
|
||||
}
|
||||
// Set up the mips source: scaled resolve buffer or shared memory.
|
||||
if (level_last != 0) {
|
||||
if (use_persistent_source) {
|
||||
descriptor_set_source_mips = shared_memory_persistent_descriptor_set_;
|
||||
} else {
|
||||
descriptor_set_source_mips =
|
||||
command_processor_.AllocateSingleTransientDescriptor(
|
||||
VulkanCommandProcessor::SingleTransientDescriptorLayout ::
|
||||
kStorageBufferCompute);
|
||||
if (!descriptor_set_source_mips) {
|
||||
return false;
|
||||
}
|
||||
if (texture_key.scaled_resolve) {
|
||||
// Scaled resolved mips live in the scaled buffer, like the base.
|
||||
uint32_t guest_address = texture_key.mip_page << 12;
|
||||
uint32_t guest_size = vulkan_texture.GetGuestMipsSize();
|
||||
if (EnsureScaledResolveMemoryCommitted(guest_address, guest_size) &&
|
||||
MakeScaledResolveRangeCurrent(guest_address, guest_size)) {
|
||||
VkBuffer scaled_buffer = GetCurrentScaledResolveBuffer();
|
||||
if (scaled_buffer != VK_NULL_HANDLE) {
|
||||
uint32_t draw_resolution_scale_area =
|
||||
draw_resolution_scale_x() * draw_resolution_scale_y();
|
||||
uint64_t scaled_offset =
|
||||
uint64_t(guest_address) * draw_resolution_scale_area;
|
||||
uint64_t buffer_relative_offset =
|
||||
scaled_offset - GetCurrentScaledResolveBufferBaseOffset();
|
||||
write_descriptor_set_source_mips_buffer_info.buffer = scaled_buffer;
|
||||
write_descriptor_set_source_mips_buffer_info.offset =
|
||||
buffer_relative_offset;
|
||||
write_descriptor_set_source_mips_buffer_info.range = xe::align(
|
||||
guest_size * draw_resolution_scale_area, uint32_t(16));
|
||||
} else {
|
||||
XELOGE(
|
||||
"Scaled resolve texture load: Failed to get current scaled "
|
||||
"buffer for mips at 0x{:08X}",
|
||||
guest_address);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
XELOGE(
|
||||
"Scaled resolve texture load: Failed to make range current for "
|
||||
"mips at 0x{:08X}",
|
||||
guest_address);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// Regular unscaled texture - use shared memory
|
||||
write_descriptor_set_source_mips_buffer_info.buffer =
|
||||
vulkan_shared_memory.buffer();
|
||||
write_descriptor_set_source_mips_buffer_info.offset =
|
||||
texture_key.mip_page << 12;
|
||||
// Align (primarily the last row of a linear packed mip tail) because
|
||||
// shaders use up to 16-byte loads for multiple blocks at once.
|
||||
write_descriptor_set_source_mips_buffer_info.range =
|
||||
xe::align(vulkan_texture.GetGuestMipsSize(), uint32_t(16));
|
||||
}
|
||||
VkWriteDescriptorSet& write_descriptor_set_source_mips =
|
||||
write_descriptor_sets[write_descriptor_set_count++];
|
||||
write_descriptor_set_source_mips.sType =
|
||||
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
write_descriptor_set_source_mips.pNext = nullptr;
|
||||
write_descriptor_set_source_mips.dstSet = descriptor_set_source_mips;
|
||||
write_descriptor_set_source_mips.dstBinding = 0;
|
||||
write_descriptor_set_source_mips.dstArrayElement = 0;
|
||||
write_descriptor_set_source_mips.descriptorCount = 1;
|
||||
write_descriptor_set_source_mips.descriptorType =
|
||||
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
|
||||
write_descriptor_set_source_mips.pImageInfo = nullptr;
|
||||
write_descriptor_set_source_mips.pBufferInfo =
|
||||
&write_descriptor_set_source_mips_buffer_info;
|
||||
write_descriptor_set_source_mips.pTexelBufferView = nullptr;
|
||||
}
|
||||
// Regular unscaled texture - use shared memory
|
||||
write_descriptor_set_source_mips_buffer_info.buffer =
|
||||
vulkan_shared_memory.buffer();
|
||||
write_descriptor_set_source_mips_buffer_info.offset = texture_key.mip_page
|
||||
<< 12;
|
||||
// Align (primarily the last row of a linear packed mip tail) because
|
||||
// shaders use up to 16-byte loads for multiple blocks at once.
|
||||
write_descriptor_set_source_mips_buffer_info.range =
|
||||
xe::align(vulkan_texture.GetGuestMipsSize(), uint32_t(16));
|
||||
VkWriteDescriptorSet& write_descriptor_set_source_mips =
|
||||
write_descriptor_sets[write_descriptor_set_count++];
|
||||
write_descriptor_set_source_mips.sType =
|
||||
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
write_descriptor_set_source_mips.pNext = nullptr;
|
||||
write_descriptor_set_source_mips.dstSet = descriptor_set_source_mips;
|
||||
write_descriptor_set_source_mips.dstBinding = 0;
|
||||
write_descriptor_set_source_mips.dstArrayElement = 0;
|
||||
write_descriptor_set_source_mips.descriptorCount = 1;
|
||||
write_descriptor_set_source_mips.descriptorType =
|
||||
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
|
||||
write_descriptor_set_source_mips.pImageInfo = nullptr;
|
||||
write_descriptor_set_source_mips.pBufferInfo =
|
||||
&write_descriptor_set_source_mips_buffer_info;
|
||||
write_descriptor_set_source_mips.pTexelBufferView = nullptr;
|
||||
}
|
||||
if (write_descriptor_set_count) {
|
||||
dfn.vkUpdateDescriptorSets(device, write_descriptor_set_count,
|
||||
@@ -1541,8 +1595,13 @@ bool VulkanTextureCache::LoadTextureDataFromResidentMemoryImpl(Texture& texture,
|
||||
kLoadDescriptorSetIndexSource, 1, &descriptor_set_source, 0, nullptr);
|
||||
}
|
||||
|
||||
// TODO(Triang3l): guest_offset relative to the storage buffer origin.
|
||||
load_constants.guest_offset = 0;
|
||||
// With the whole buffer bound persistently, guest_offset is relative to the
|
||||
// buffer origin. With a per-load source descriptor, it's already offset to
|
||||
// the texture's base or mip page, so it stays relative to that.
|
||||
load_constants.guest_offset =
|
||||
use_persistent_source
|
||||
? ((is_base ? texture_key.base_page : texture_key.mip_page) << 12)
|
||||
: 0;
|
||||
if (!is_base) {
|
||||
load_constants.guest_offset +=
|
||||
guest_layout.mip_offsets_bytes[level] *
|
||||
@@ -2521,6 +2580,71 @@ bool VulkanTextureCache::Initialize() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the whole shared memory buffer fits within maxStorageBufferRange, create
|
||||
// a persistent descriptor set binding it for texture load sources, so
|
||||
// per-load transient source descriptors don't need to be allocated and
|
||||
// written. The texture's byte offset is passed via guest_offset instead, as
|
||||
// on Direct3D 12. When the buffer doesn't fit, the per-load sub-range
|
||||
// descriptors are used.
|
||||
if (device_properties.maxStorageBufferRange >= SharedMemory::kBufferSize) {
|
||||
VkDescriptorPoolSize shared_memory_persistent_pool_size;
|
||||
shared_memory_persistent_pool_size.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
|
||||
shared_memory_persistent_pool_size.descriptorCount = 1;
|
||||
VkDescriptorPoolCreateInfo shared_memory_persistent_pool_create_info;
|
||||
shared_memory_persistent_pool_create_info.sType =
|
||||
VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
||||
shared_memory_persistent_pool_create_info.pNext = nullptr;
|
||||
shared_memory_persistent_pool_create_info.flags = 0;
|
||||
shared_memory_persistent_pool_create_info.maxSets = 1;
|
||||
shared_memory_persistent_pool_create_info.poolSizeCount = 1;
|
||||
shared_memory_persistent_pool_create_info.pPoolSizes =
|
||||
&shared_memory_persistent_pool_size;
|
||||
if (dfn.vkCreateDescriptorPool(
|
||||
device, &shared_memory_persistent_pool_create_info, nullptr,
|
||||
&shared_memory_persistent_descriptor_pool_) == VK_SUCCESS) {
|
||||
VkDescriptorSetAllocateInfo shared_memory_persistent_set_allocate_info;
|
||||
shared_memory_persistent_set_allocate_info.sType =
|
||||
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
||||
shared_memory_persistent_set_allocate_info.pNext = nullptr;
|
||||
shared_memory_persistent_set_allocate_info.descriptorPool =
|
||||
shared_memory_persistent_descriptor_pool_;
|
||||
shared_memory_persistent_set_allocate_info.descriptorSetCount = 1;
|
||||
shared_memory_persistent_set_allocate_info.pSetLayouts =
|
||||
&load_descriptor_set_layout_storage_buffer;
|
||||
if (dfn.vkAllocateDescriptorSets(
|
||||
device, &shared_memory_persistent_set_allocate_info,
|
||||
&shared_memory_persistent_descriptor_set_) == VK_SUCCESS) {
|
||||
VkDescriptorBufferInfo shared_memory_persistent_buffer_info;
|
||||
shared_memory_persistent_buffer_info.buffer =
|
||||
static_cast<VulkanSharedMemory&>(shared_memory()).buffer();
|
||||
shared_memory_persistent_buffer_info.offset = 0;
|
||||
shared_memory_persistent_buffer_info.range = SharedMemory::kBufferSize;
|
||||
VkWriteDescriptorSet shared_memory_persistent_write;
|
||||
shared_memory_persistent_write.sType =
|
||||
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
shared_memory_persistent_write.pNext = nullptr;
|
||||
shared_memory_persistent_write.dstSet =
|
||||
shared_memory_persistent_descriptor_set_;
|
||||
shared_memory_persistent_write.dstBinding = 0;
|
||||
shared_memory_persistent_write.dstArrayElement = 0;
|
||||
shared_memory_persistent_write.descriptorCount = 1;
|
||||
shared_memory_persistent_write.descriptorType =
|
||||
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
|
||||
shared_memory_persistent_write.pImageInfo = nullptr;
|
||||
shared_memory_persistent_write.pBufferInfo =
|
||||
&shared_memory_persistent_buffer_info;
|
||||
shared_memory_persistent_write.pTexelBufferView = nullptr;
|
||||
dfn.vkUpdateDescriptorSets(device, 1, &shared_memory_persistent_write,
|
||||
0, nullptr);
|
||||
} else {
|
||||
dfn.vkDestroyDescriptorPool(
|
||||
device, shared_memory_persistent_descriptor_pool_, nullptr);
|
||||
shared_memory_persistent_descriptor_pool_ = VK_NULL_HANDLE;
|
||||
shared_memory_persistent_descriptor_set_ = VK_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Load pipelines, only the ones needed for the formats that will be used.
|
||||
|
||||
bool load_shaders_needed[kLoadShaderCount] = {};
|
||||
|
||||
@@ -97,6 +97,14 @@ class VulkanTextureCache final : public TextureCache {
|
||||
xenos::FetchOpDimension dimension,
|
||||
bool is_signed);
|
||||
|
||||
// Descriptor set (kStorageBufferCompute layout) binding the whole shared
|
||||
// memory buffer for compute load/store, or VK_NULL_HANDLE if the buffer
|
||||
// doesn't fit in maxStorageBufferRange. When valid, the byte offset into the
|
||||
// buffer must be supplied via push constants. Shared with resolve.
|
||||
VkDescriptorSet shared_memory_persistent_descriptor_set() const {
|
||||
return shared_memory_persistent_descriptor_set_;
|
||||
}
|
||||
|
||||
SamplerParameters GetSamplerParameters(
|
||||
const VulkanShader::SamplerBinding& binding) const;
|
||||
|
||||
@@ -441,6 +449,16 @@ class VulkanTextureCache final : public TextureCache {
|
||||
std::array<VkPipeline, kLoadShaderCount> load_pipelines_{};
|
||||
std::array<VkPipeline, kLoadShaderCount> load_pipelines_scaled_{};
|
||||
|
||||
// Persistent descriptor binding the whole shared memory buffer
|
||||
// (kStorageBufferCompute layout) for compute load/store, so per-operation
|
||||
// transient descriptors don't need to be allocated and written. Only created
|
||||
// when the buffer fits in maxStorageBufferRange. The byte offset into the
|
||||
// buffer is passed via push constants instead. Used as the source of texture
|
||||
// loads here, and shared as the destination of resolves in the render target
|
||||
// cache.
|
||||
VkDescriptorPool shared_memory_persistent_descriptor_pool_ = VK_NULL_HANDLE;
|
||||
VkDescriptorSet shared_memory_persistent_descriptor_set_ = VK_NULL_HANDLE;
|
||||
|
||||
// If both images can be placed in the same allocation, it's one allocation,
|
||||
// otherwise it's two separate.
|
||||
std::array<VkDeviceMemory, 2> null_images_memory_{};
|
||||
|
||||
Reference in New Issue
Block a user