GS/Vulkan: Use push descriptors instead of per-frame allocations

This commit is contained in:
Stenzek 2023-08-09 00:27:12 +10:00 committed by Connor McLaughlin
parent 906d87c4b8
commit cf523d4215
7 changed files with 192 additions and 256 deletions

View File

@ -352,16 +352,16 @@ layout(set = 1, binding = 1) uniform texture2D Palette;
#if PS_FEEDBACK_LOOP_IS_NEEDED
#if defined(DISABLE_TEXTURE_BARRIER) || defined(HAS_FEEDBACK_LOOP_LAYOUT)
layout(set = 2, binding = 0) uniform texture2D RtSampler;
layout(set = 1, binding = 2) uniform texture2D RtSampler;
vec4 sample_from_rt() { return texelFetch(RtSampler, ivec2(gl_FragCoord.xy), 0); }
#else
layout(input_attachment_index = 0, set = 2, binding = 0) uniform subpassInput RtSampler;
layout(input_attachment_index = 0, set = 1, binding = 2) uniform subpassInput RtSampler;
vec4 sample_from_rt() { return subpassLoad(RtSampler); }
#endif
#endif
#if PS_DATE > 0
layout(set = 2, binding = 1) uniform texture2D PrimMinTexture;
layout(set = 1, binding = 3) uniform texture2D PrimMinTexture;
#endif
#if NEEDS_TEX

View File

@ -312,6 +312,12 @@ bool GSDeviceVK::SelectDeviceExtensions(ExtensionList* extension_list, bool enab
if (enable_surface && !SupportsExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME, true))
return false;
// Required extensions.
if (!SupportsExtension(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME, true))
{
return false;
}
m_optional_extensions.vk_ext_provoking_vertex = SupportsExtension(VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME, false);
m_optional_extensions.vk_ext_memory_budget = SupportsExtension(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME, false);
m_optional_extensions.vk_ext_calibrated_timestamps =
@ -570,7 +576,8 @@ bool GSDeviceVK::CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer
queue_family_properties[m_graphics_queue_family_index].timestampValidBits,
m_device_properties.limits.timestampPeriod);
ProcessDeviceExtensions();
if (!ProcessDeviceExtensions())
return false;
if (m_spinning_supported)
{
@ -591,7 +598,7 @@ bool GSDeviceVK::CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer
return true;
}
void GSDeviceVK::ProcessDeviceExtensions()
bool GSDeviceVK::ProcessDeviceExtensions()
{
// advanced feature checks
VkPhysicalDeviceFeatures2 features2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2};
@ -626,18 +633,28 @@ void GSDeviceVK::ProcessDeviceExtensions()
(attachment_feedback_loop_feature.attachmentFeedbackLoopLayout == VK_TRUE);
VkPhysicalDeviceProperties2 properties2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2};
void** pNext = &properties2.pNext;
if (m_optional_extensions.vk_khr_driver_properties)
{
m_device_driver_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES;
*pNext = &m_device_driver_properties;
pNext = &m_device_driver_properties.pNext;
Vulkan::AddPointerToChain(&properties2, &m_device_driver_properties);
}
VkPhysicalDevicePushDescriptorPropertiesKHR push_descriptor_properties = {
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR};
Vulkan::AddPointerToChain(&properties2, &push_descriptor_properties);
// query
vkGetPhysicalDeviceProperties2(m_physical_device, &properties2);
// confirm we actually support it
if (push_descriptor_properties.maxPushDescriptors < NUM_TFX_TEXTURES)
{
Console.Error("maxPushDescriptors (%u) is below required (%u)", push_descriptor_properties.maxPushDescriptors,
NUM_TFX_TEXTURES);
return false;
}
// VK_EXT_calibrated_timestamps checking
if (m_optional_extensions.vk_ext_calibrated_timestamps)
{
@ -674,14 +691,26 @@ void GSDeviceVK::ProcessDeviceExtensions()
Console.WriteLn(
"VK_EXT_provoking_vertex is %s", m_optional_extensions.vk_ext_provoking_vertex ? "supported" : "NOT supported");
Console.WriteLn("VK_EXT_line_rasterization is %s",
m_optional_extensions.vk_ext_line_rasterization ? "supported" : "NOT supported");
Console.WriteLn(
"VK_EXT_memory_budget is %s", m_optional_extensions.vk_ext_memory_budget ? "supported" : "NOT supported");
Console.WriteLn("VK_EXT_calibrated_timestamps is %s",
m_optional_extensions.vk_ext_calibrated_timestamps ? "supported" : "NOT supported");
Console.WriteLn("VK_EXT_line_rasterization is %s",
m_optional_extensions.vk_ext_line_rasterization ? "supported" : "NOT supported");
Console.WriteLn("VK_EXT_rasterization_order_attachment_access is %s",
m_optional_extensions.vk_ext_rasterization_order_attachment_access ? "supported" : "NOT supported");
Console.WriteLn("VK_EXT_attachment_feedback_loop_layout is %s",
m_optional_extensions.vk_ext_attachment_feedback_loop_layout ? "supported" : "NOT supported");
Console.WriteLn("VK_EXT_full_screen_exclusive is %s",
m_optional_extensions.vk_ext_full_screen_exclusive ? "supported" : "NOT supported");
Console.WriteLn("VK_KHR_driver_properties is %s",
m_optional_extensions.vk_khr_driver_properties ? "supported" : "NOT supported");
Console.WriteLn("VK_KHR_fragment_shader_barycentric is %s",
m_optional_extensions.vk_khr_fragment_shader_barycentric ? "supported" : "NOT supported");
Console.WriteLn("VK_KHR_shader_draw_parameters is %s",
m_optional_extensions.vk_khr_shader_draw_parameters ? "supported" : "NOT supported");
return true;
}
bool GSDeviceVK::CreateAllocator()
@ -788,26 +817,6 @@ bool GSDeviceVK::CreateCommandBuffers()
return false;
}
Vulkan::SetObjectName(m_device, resources.fence, "Frame Fence %u", frame_index);
// TODO: A better way to choose the number of descriptors.
VkDescriptorPoolSize pool_sizes[] = {
{VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, MAX_COMBINED_IMAGE_SAMPLER_DESCRIPTORS_PER_FRAME},
{VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, MAX_SAMPLED_IMAGE_DESCRIPTORS_PER_FRAME},
{VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, MAX_STORAGE_IMAGE_DESCRIPTORS_PER_FRAME},
{VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, MAX_INPUT_ATTACHMENT_IMAGE_DESCRIPTORS_PER_FRAME},
};
VkDescriptorPoolCreateInfo pool_create_info = {VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, nullptr, 0,
MAX_DESCRIPTOR_SETS_PER_FRAME, static_cast<u32>(std::size(pool_sizes)), pool_sizes};
res = vkCreateDescriptorPool(m_device, &pool_create_info, nullptr, &resources.descriptor_pool);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateDescriptorPool failed: ");
return false;
}
Vulkan::SetObjectName(
m_device, resources.descriptor_pool, "Frame Descriptor Pool %u", frame_index);
++frame_index;
}
@ -918,23 +927,6 @@ VkCommandBuffer GSDeviceVK::GetCurrentInitCommandBuffer()
return buf;
}
VkDescriptorSet GSDeviceVK::AllocateDescriptorSet(VkDescriptorSetLayout set_layout)
{
VkDescriptorSetAllocateInfo allocate_info = {VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, nullptr,
m_frame_resources[m_current_frame].descriptor_pool, 1, &set_layout};
VkDescriptorSet descriptor_set;
VkResult res = vkAllocateDescriptorSets(m_device, &allocate_info, &descriptor_set);
if (res != VK_SUCCESS)
{
// Failing to allocate a descriptor set is not a fatal error, we can
// recover by moving to the next command buffer.
return VK_NULL_HANDLE;
}
return descriptor_set;
}
VkDescriptorSet GSDeviceVK::AllocatePersistentDescriptorSet(VkDescriptorSetLayout set_layout)
{
VkDescriptorSetAllocateInfo allocate_info = {
@ -1345,11 +1337,6 @@ void GSDeviceVK::ActivateCommandBuffer(u32 index)
if (res != VK_SUCCESS)
LOG_VULKAN_ERROR(res, "vkBeginCommandBuffer failed: ");
// Also can do the same for the descriptor pools
res = vkResetDescriptorPool(m_device, resources.descriptor_pool, 0);
if (res != VK_SUCCESS)
LOG_VULKAN_ERROR(res, "vkResetDescriptorPool failed: ");
bool wants_timestamp = m_gpu_timing_enabled || m_spin_timer;
if (wants_timestamp)
{
@ -3472,7 +3459,7 @@ void GSDeviceVK::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector
{
// need to update descriptors to reflect the new layout
if ((feedback_loop & FeedbackLoopFlag_ReadDS) && vkDs->GetLayout() != GSTextureVK::Layout::FeedbackLoop)
m_dirty_flags |= DIRTY_FLAG_TFX_SAMPLERS_DS;
m_dirty_flags |= (DIRTY_FLAG_TFX_TEXTURE_0 << TFX_TEXTURE_RT);
vkDs->TransitionToLayout((feedback_loop & FeedbackLoopFlag_ReadDS) ?
GSTextureVK::Layout::FeedbackLoop :
@ -3549,7 +3536,8 @@ static void AddMacro(std::stringstream& ss, const char* name, int value)
static void AddShaderHeader(std::stringstream& ss)
{
const GSDevice::FeatureSupport features(g_gs_device->Features());
const GSDeviceVK* dev = GSDeviceVK::GetInstance();
const GSDevice::FeatureSupport features = dev->Features();
ss << "#version 460 core\n";
ss << "#extension GL_EXT_samplerless_texture_functions : require\n";
@ -3561,7 +3549,7 @@ static void AddShaderHeader(std::stringstream& ss)
ss << "#define DISABLE_TEXTURE_BARRIER 1\n";
if (!features.dual_source_blend)
ss << "#define DISABLE_DUAL_SOURCE 1\n";
if (features.texture_barrier && GSDeviceVK::GetInstance()->UseFeedbackLoopLayout())
if (features.texture_barrier && dev->UseFeedbackLoopLayout())
ss << "#define HAS_FEEDBACK_LOOP_LAYOUT 1\n";
}
@ -3691,7 +3679,8 @@ bool GSDeviceVK::CreatePipelineLayouts()
// Convert Pipeline Layout
//////////////////////////////////////////////////////////////////////////
dslb.AddBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, NUM_CONVERT_SAMPLERS, VK_SHADER_STAGE_FRAGMENT_BIT);
dslb.SetPushFlag();
dslb.AddBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, NUM_UTILITY_SAMPLERS, VK_SHADER_STAGE_FRAGMENT_BIT);
if ((m_utility_ds_layout = dslb.Create(dev)) == VK_NULL_HANDLE)
return false;
Vulkan::SetObjectName(dev, m_utility_ds_layout, "Convert descriptor layout");
@ -3713,23 +3702,21 @@ bool GSDeviceVK::CreatePipelineLayouts()
if ((m_tfx_ubo_ds_layout = dslb.Create(dev)) == VK_NULL_HANDLE)
return false;
Vulkan::SetObjectName(dev, m_tfx_ubo_ds_layout, "TFX UBO descriptor layout");
dslb.AddBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
dslb.AddBinding(1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
if ((m_tfx_sampler_ds_layout = dslb.Create(dev)) == VK_NULL_HANDLE)
return false;
Vulkan::SetObjectName(dev, m_tfx_sampler_ds_layout, "TFX sampler descriptor layout");
dslb.AddBinding(0,
dslb.SetPushFlag();
dslb.AddBinding(TFX_TEXTURE_TEXTURE, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
dslb.AddBinding(TFX_TEXTURE_PALETTE, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
dslb.AddBinding(TFX_TEXTURE_RT,
(m_features.texture_barrier && !UseFeedbackLoopLayout()) ? VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT :
VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
1, VK_SHADER_STAGE_FRAGMENT_BIT);
dslb.AddBinding(1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
if ((m_tfx_rt_texture_ds_layout = dslb.Create(dev)) == VK_NULL_HANDLE)
dslb.AddBinding(TFX_TEXTURE_PRIMID, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
if ((m_tfx_texture_ds_layout = dslb.Create(dev)) == VK_NULL_HANDLE)
return false;
Vulkan::SetObjectName(dev, m_tfx_rt_texture_ds_layout, "TFX RT texture descriptor layout");
Vulkan::SetObjectName(dev, m_tfx_texture_ds_layout, "TFX texture descriptor layout");
plb.AddDescriptorSet(m_tfx_ubo_ds_layout);
plb.AddDescriptorSet(m_tfx_sampler_ds_layout);
plb.AddDescriptorSet(m_tfx_rt_texture_ds_layout);
plb.AddDescriptorSet(m_tfx_texture_ds_layout);
if ((m_tfx_pipeline_layout = plb.Create(dev)) == VK_NULL_HANDLE)
return false;
Vulkan::SetObjectName(dev, m_tfx_pipeline_layout, "TFX pipeline layout");
@ -4264,6 +4251,7 @@ bool GSDeviceVK::CompileCASPipelines()
Vulkan::DescriptorSetLayoutBuilder dslb;
Vulkan::PipelineLayoutBuilder plb;
dslb.SetPushFlag();
dslb.AddBinding(0, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT);
dslb.AddBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT);
if ((m_cas_ds_layout = dslb.Create(dev)) == VK_NULL_HANDLE)
@ -4459,10 +4447,6 @@ bool GSDeviceVK::DoCAS(GSTexture* sTex, GSTexture* dTex, bool sharpen_only, cons
{
EndRenderPass();
VkDescriptorSet ds = AllocateDescriptorSet(m_cas_ds_layout);
if (ds == VK_NULL_HANDLE)
return false;
GSTextureVK* const sTexVK = static_cast<GSTextureVK*>(sTex);
GSTextureVK* const dTexVK = static_cast<GSTextureVK*>(dTex);
VkCommandBuffer cmdbuf = GetCurrentCommandBuffer();
@ -4472,16 +4456,15 @@ bool GSDeviceVK::DoCAS(GSTexture* sTex, GSTexture* dTex, bool sharpen_only, cons
// only happening once a frame, so the update isn't a huge deal.
Vulkan::DescriptorSetUpdateBuilder dsub;
dsub.AddImageDescriptorWrite(ds, 0, sTexVK->GetView(), sTexVK->GetVkLayout());
dsub.AddStorageImageDescriptorWrite(ds, 1, dTexVK->GetView(), dTexVK->GetVkLayout());
dsub.Update(m_device, false);
dsub.AddImageDescriptorWrite(VK_NULL_HANDLE, 0, sTexVK->GetView(), sTexVK->GetVkLayout());
dsub.AddStorageImageDescriptorWrite(VK_NULL_HANDLE, 1, dTexVK->GetView(), dTexVK->GetVkLayout());
dsub.PushUpdate(cmdbuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_cas_pipeline_layout, 0, false);
// the actual meat and potatoes! only four commands.
static const int threadGroupWorkRegionDim = 16;
const int dispatchX = (dTex->GetWidth() + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
const int dispatchY = (dTex->GetHeight() + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
vkCmdBindDescriptorSets(cmdbuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_cas_pipeline_layout, 0, 1, &ds, 0, nullptr);
vkCmdPushConstants(cmdbuf, m_cas_pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, NUM_CAS_CONSTANTS * sizeof(u32), constants.data());
vkCmdBindPipeline(cmdbuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_cas_pipelines[static_cast<u8>(sharpen_only)]);
vkCmdDispatch(cmdbuf, dispatchX, dispatchY, 1);
@ -4580,10 +4563,8 @@ void GSDeviceVK::DestroyResources()
if (m_tfx_pipeline_layout != VK_NULL_HANDLE)
vkDestroyPipelineLayout(m_device, m_tfx_pipeline_layout, nullptr);
if (m_tfx_rt_texture_ds_layout != VK_NULL_HANDLE)
vkDestroyDescriptorSetLayout(m_device, m_tfx_rt_texture_ds_layout, nullptr);
if (m_tfx_sampler_ds_layout != VK_NULL_HANDLE)
vkDestroyDescriptorSetLayout(m_device, m_tfx_sampler_ds_layout, nullptr);
if (m_tfx_texture_ds_layout != VK_NULL_HANDLE)
vkDestroyDescriptorSetLayout(m_device, m_tfx_texture_ds_layout, nullptr);
if (m_tfx_ubo_ds_layout != VK_NULL_HANDLE)
vkDestroyDescriptorSetLayout(m_device, m_tfx_ubo_ds_layout, nullptr);
if (m_utility_pipeline_layout != VK_NULL_HANDLE)
@ -4605,8 +4586,6 @@ void GSDeviceVK::DestroyResources()
if (resources.fence != VK_NULL_HANDLE)
vkDestroyFence(m_device, resources.fence, nullptr);
if (resources.descriptor_pool != VK_NULL_HANDLE)
vkDestroyDescriptorPool(m_device, resources.descriptor_pool, nullptr);
if (resources.command_buffers[0] != VK_NULL_HANDLE)
{
vkFreeCommandBuffers(m_device, resources.command_pool, static_cast<u32>(resources.command_buffers.size()),
@ -4995,10 +4974,7 @@ void GSDeviceVK::ExecuteCommandBufferForReadback()
void GSDeviceVK::InvalidateCachedState()
{
m_dirty_flags |= DIRTY_FLAG_TFX_SAMPLERS_DS | DIRTY_FLAG_TFX_RT_TEXTURE_DS | DIRTY_FLAG_TFX_DYNAMIC_OFFSETS |
DIRTY_FLAG_UTILITY_TEXTURE | DIRTY_FLAG_BLEND_CONSTANTS | DIRTY_FLAG_LINE_WIDTH | DIRTY_FLAG_VERTEX_BUFFER |
DIRTY_FLAG_INDEX_BUFFER | DIRTY_FLAG_VIEWPORT | DIRTY_FLAG_SCISSOR | DIRTY_FLAG_PIPELINE |
DIRTY_FLAG_VS_CONSTANT_BUFFER | DIRTY_FLAG_PS_CONSTANT_BUFFER;
m_dirty_flags = ALL_DIRTY_STATE;
if (m_vertex_buffer != VK_NULL_HANDLE)
m_dirty_flags |= DIRTY_FLAG_VERTEX_BUFFER;
if (m_index_buffer != VK_NULL_HANDLE)
@ -5084,8 +5060,7 @@ void GSDeviceVK::PSSetShaderResource(int i, GSTexture* sr, bool check_state)
return;
m_tfx_textures[i] = vkTex;
m_dirty_flags |= (i < 2) ? DIRTY_FLAG_TFX_SAMPLERS_DS : DIRTY_FLAG_TFX_RT_TEXTURE_DS;
m_dirty_flags |= (DIRTY_FLAG_TFX_TEXTURE_0 << i);
}
void GSDeviceVK::PSSetSampler(GSHWDrawConfig::SamplerSelector sel)
@ -5095,7 +5070,7 @@ void GSDeviceVK::PSSetSampler(GSHWDrawConfig::SamplerSelector sel)
m_tfx_sampler_sel = sel.key;
m_tfx_sampler = GetSampler(sel);
m_dirty_flags |= DIRTY_FLAG_TFX_SAMPLERS_DS;
m_dirty_flags |= DIRTY_FLAG_TFX_TEXTURE_0;
}
void GSDeviceVK::SetUtilityTexture(GSTexture* tex, VkSampler sampler)
@ -5133,7 +5108,7 @@ void GSDeviceVK::UnbindTexture(GSTextureVK* tex)
if (m_tfx_textures[i] == tex)
{
m_tfx_textures[i] = m_null_texture.get();
m_dirty_flags |= (i < 2) ? DIRTY_FLAG_TFX_SAMPLERS_DS : DIRTY_FLAG_TFX_RT_TEXTURE_DS;
m_dirty_flags |= (DIRTY_FLAG_TFX_TEXTURE_0 << i);
}
}
if (m_utility_texture == tex)
@ -5272,10 +5247,9 @@ bool GSDeviceVK::ApplyTFXState(bool already_execed)
if (m_current_pipeline_layout == PipelineLayout::TFX && m_dirty_flags == 0)
return true;
const VkDevice dev = m_device;
const VkCommandBuffer cmdbuf = GetCurrentCommandBuffer();
u32 flags = m_dirty_flags;
m_dirty_flags &= ~(DIRTY_TFX_STATE | DIRTY_CONSTANT_BUFFER_STATE | DIRTY_FLAG_TFX_DYNAMIC_OFFSETS);
m_dirty_flags &= ~(DIRTY_TFX_STATE | DIRTY_CONSTANT_BUFFER_STATE | DIRTY_FLAG_TFX_UBO);
// do cbuffer first, because it's the most likely to cause an exec
if (flags & DIRTY_FLAG_VS_CONSTANT_BUFFER)
@ -5296,7 +5270,7 @@ bool GSDeviceVK::ApplyTFXState(bool already_execed)
std::memcpy(m_vertex_uniform_stream_buffer.GetCurrentHostPointer(), &m_vs_cb_cache, sizeof(m_vs_cb_cache));
m_tfx_dynamic_offsets[0] = m_vertex_uniform_stream_buffer.GetCurrentOffset();
m_vertex_uniform_stream_buffer.CommitMemory(sizeof(m_vs_cb_cache));
flags |= DIRTY_FLAG_TFX_DYNAMIC_OFFSETS;
flags |= DIRTY_FLAG_TFX_UBO;
}
if (flags & DIRTY_FLAG_PS_CONSTANT_BUFFER)
@ -5317,116 +5291,62 @@ bool GSDeviceVK::ApplyTFXState(bool already_execed)
std::memcpy(m_fragment_uniform_stream_buffer.GetCurrentHostPointer(), &m_ps_cb_cache, sizeof(m_ps_cb_cache));
m_tfx_dynamic_offsets[1] = m_fragment_uniform_stream_buffer.GetCurrentOffset();
m_fragment_uniform_stream_buffer.CommitMemory(sizeof(m_ps_cb_cache));
flags |= DIRTY_FLAG_TFX_DYNAMIC_OFFSETS;
flags |= DIRTY_FLAG_TFX_UBO;
}
Vulkan::DescriptorSetUpdateBuilder dsub;
std::array<VkDescriptorSet, NUM_TFX_DESCRIPTOR_SETS> dsets;
u32 num_dsets = 0;
u32 start_dset = 0;
const bool layout_changed = (m_current_pipeline_layout != PipelineLayout::TFX);
if (!layout_changed && flags & DIRTY_FLAG_TFX_DYNAMIC_OFFSETS)
dsets[num_dsets++] = m_tfx_ubo_descriptor_set;
if ((flags & DIRTY_FLAG_TFX_SAMPLERS_DS) || m_tfx_texture_descriptor_set == VK_NULL_HANDLE)
{
m_tfx_texture_descriptor_set = AllocateDescriptorSet(m_tfx_sampler_ds_layout);
if (m_tfx_texture_descriptor_set == VK_NULL_HANDLE)
{
if (already_execed)
{
Console.Error("Failed to allocate TFX texture descriptors");
return false;
}
ExecuteCommandBufferAndRestartRenderPass(false, "Ran out of TFX texture descriptors");
return ApplyTFXState(true);
}
dsub.AddCombinedImageSamplerDescriptorWrite(m_tfx_texture_descriptor_set, 0, m_tfx_textures[0]->GetView(),
m_tfx_sampler, m_tfx_textures[0]->GetVkLayout());
dsub.AddImageDescriptorWrite(
m_tfx_texture_descriptor_set, 1, m_tfx_textures[1]->GetView(), m_tfx_textures[1]->GetVkLayout());
dsub.Update(dev);
if (!layout_changed)
{
start_dset = (num_dsets == 0) ? TFX_DESCRIPTOR_SET_TEXTURES : start_dset;
dsets[num_dsets++] = m_tfx_texture_descriptor_set;
}
}
if ((flags & DIRTY_FLAG_TFX_RT_TEXTURE_DS) || m_tfx_rt_descriptor_set == VK_NULL_HANDLE)
{
m_tfx_rt_descriptor_set = AllocateDescriptorSet(m_tfx_rt_texture_ds_layout);
if (m_tfx_rt_descriptor_set == VK_NULL_HANDLE)
{
if (already_execed)
{
Console.Error("Failed to allocate TFX sampler descriptors");
return false;
}
ExecuteCommandBufferAndRestartRenderPass(false, "Ran out of TFX sampler descriptors");
return ApplyTFXState(true);
}
if (m_features.texture_barrier && !UseFeedbackLoopLayout())
{
dsub.AddInputAttachmentDescriptorWrite(
m_tfx_rt_descriptor_set, 0, m_tfx_textures[NUM_TFX_DRAW_TEXTURES]->GetView(), VK_IMAGE_LAYOUT_GENERAL);
}
else
{
dsub.AddImageDescriptorWrite(m_tfx_rt_descriptor_set, 0, m_tfx_textures[NUM_TFX_DRAW_TEXTURES]->GetView(),
m_tfx_textures[NUM_TFX_DRAW_TEXTURES]->GetVkLayout());
}
dsub.AddImageDescriptorWrite(m_tfx_rt_descriptor_set, 1, m_tfx_textures[NUM_TFX_DRAW_TEXTURES + 1]->GetView(),
m_tfx_textures[NUM_TFX_DRAW_TEXTURES + 1]->GetVkLayout());
dsub.Update(dev);
if (!layout_changed)
{
// need to add textures in, can't leave a gap
if (start_dset == TFX_DESCRIPTOR_SET_UBO && num_dsets == 1)
dsets[num_dsets++] = m_tfx_texture_descriptor_set;
else
start_dset = (num_dsets == 0) ? TFX_DESCRIPTOR_SET_RT : start_dset;
dsets[num_dsets++] = m_tfx_rt_descriptor_set;
}
}
if (layout_changed)
if (m_current_pipeline_layout != PipelineLayout::TFX)
{
m_current_pipeline_layout = PipelineLayout::TFX;
flags |= DIRTY_FLAG_TFX_UBO | DIRTY_FLAG_TFX_TEXTURES;
dsets[0] = m_tfx_ubo_descriptor_set;
dsets[1] = m_tfx_texture_descriptor_set;
dsets[2] = m_tfx_rt_descriptor_set;
vkCmdBindDescriptorSets(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_tfx_pipeline_layout, 0,
NUM_TFX_DESCRIPTOR_SETS, dsets.data(), NUM_TFX_DYNAMIC_OFFSETS, m_tfx_dynamic_offsets.data());
// Clear out the RT binding if feedback loop isn't on, because it'll be in the wrong state and make
// the validation layer cranky. Not a big deal since we need to write it anyway.
const GSTextureVK::Layout rt_tex_layout = m_tfx_textures[TFX_TEXTURE_RT]->GetLayout();
if (rt_tex_layout != GSTextureVK::Layout::FeedbackLoop && rt_tex_layout != GSTextureVK::Layout::ShaderReadOnly)
m_tfx_textures[TFX_TEXTURE_RT] = m_null_texture.get();
}
else if (num_dsets > 0)
if (flags & DIRTY_FLAG_TFX_UBO)
{
u32 dynamic_count;
const u32* dynamic_offsets;
if (start_dset == TFX_DESCRIPTOR_SET_UBO)
// Still need to bind the UBO descriptor set.
vkCmdBindDescriptorSets(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_tfx_pipeline_layout, 0, 1,
&m_tfx_ubo_descriptor_set, NUM_TFX_DYNAMIC_OFFSETS, m_tfx_dynamic_offsets.data());
}
if (flags & DIRTY_FLAG_TFX_TEXTURES)
{
if (flags & DIRTY_FLAG_TFX_TEXTURE_TEX)
{
dynamic_count = NUM_TFX_DYNAMIC_OFFSETS;
dynamic_offsets = m_tfx_dynamic_offsets.data();
dsub.AddCombinedImageSamplerDescriptorWrite(VK_NULL_HANDLE, TFX_TEXTURE_TEXTURE,
m_tfx_textures[TFX_TEXTURE_TEXTURE]->GetView(), m_tfx_sampler,
m_tfx_textures[TFX_TEXTURE_TEXTURE]->GetVkLayout());
}
else
if (flags & DIRTY_FLAG_TFX_TEXTURE_PALETTE)
{
dynamic_count = 0;
dynamic_offsets = nullptr;
dsub.AddImageDescriptorWrite(VK_NULL_HANDLE, TFX_TEXTURE_PALETTE,
m_tfx_textures[TFX_TEXTURE_PALETTE]->GetView(), m_tfx_textures[TFX_TEXTURE_PALETTE]->GetVkLayout());
}
if (flags & DIRTY_FLAG_TFX_TEXTURE_RT)
{
if (m_features.texture_barrier && !UseFeedbackLoopLayout())
{
dsub.AddInputAttachmentDescriptorWrite(
VK_NULL_HANDLE, TFX_TEXTURE_RT, m_tfx_textures[TFX_TEXTURE_RT]->GetView(), VK_IMAGE_LAYOUT_GENERAL);
}
else
{
dsub.AddImageDescriptorWrite(VK_NULL_HANDLE, TFX_TEXTURE_RT, m_tfx_textures[TFX_TEXTURE_RT]->GetView(),
m_tfx_textures[TFX_TEXTURE_RT]->GetVkLayout());
}
}
if (flags & DIRTY_FLAG_TFX_TEXTURE_PRIMID)
{
dsub.AddImageDescriptorWrite(VK_NULL_HANDLE, TFX_TEXTURE_PRIMID,
m_tfx_textures[TFX_TEXTURE_PRIMID]->GetView(), m_tfx_textures[TFX_TEXTURE_PRIMID]->GetVkLayout());
}
vkCmdBindDescriptorSets(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_tfx_pipeline_layout, start_dset, num_dsets,
dsets.data(), dynamic_count, dynamic_offsets);
dsub.PushUpdate(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_tfx_pipeline_layout, TFX_DESCRIPTOR_SET_TEXTURES);
}
ApplyBaseState(flags, cmdbuf);
@ -5443,37 +5363,16 @@ bool GSDeviceVK::ApplyUtilityState(bool already_execed)
u32 flags = m_dirty_flags;
m_dirty_flags &= ~DIRTY_UTILITY_STATE;
bool rebind = (m_current_pipeline_layout != PipelineLayout::Utility);
if ((flags & DIRTY_FLAG_UTILITY_TEXTURE) || m_utility_descriptor_set == VK_NULL_HANDLE)
if (m_current_pipeline_layout != PipelineLayout::Utility || flags & DIRTY_FLAG_UTILITY_TEXTURE)
{
m_utility_descriptor_set = AllocateDescriptorSet(m_utility_ds_layout);
if (m_utility_descriptor_set == VK_NULL_HANDLE)
{
if (already_execed)
{
Console.Error("Failed to allocate utility descriptors");
return false;
}
ExecuteCommandBufferAndRestartRenderPass(false, "Ran out of utility descriptors");
return ApplyUtilityState(true);
}
m_current_pipeline_layout = PipelineLayout::Utility;
Vulkan::DescriptorSetUpdateBuilder dsub;
dsub.AddCombinedImageSamplerDescriptorWrite(m_utility_descriptor_set, 0, m_utility_texture->GetView(),
m_utility_sampler, m_utility_texture->GetVkLayout());
dsub.Update(dev);
rebind = true;
dsub.AddCombinedImageSamplerDescriptorWrite(
VK_NULL_HANDLE, 0, m_utility_texture->GetView(), m_utility_sampler, m_utility_texture->GetVkLayout());
dsub.PushUpdate(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_utility_pipeline_layout, 0, false);
}
if (rebind)
{
vkCmdBindDescriptorSets(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_utility_pipeline_layout, 0, 1,
&m_utility_descriptor_set, 0, nullptr);
}
m_current_pipeline_layout = PipelineLayout::Utility;
ApplyBaseState(flags, cmdbuf);
return true;

View File

@ -16,10 +16,10 @@
#pragma once
#include "GS/Renderers/Common/GSDevice.h"
#include "GS/GSVector.h"
#include "GS/Renderers/Vulkan/GSTextureVK.h"
#include "GS/Renderers/Vulkan/VKLoader.h"
#include "GS/Renderers/Vulkan/VKStreamBuffer.h"
#include "GS/GSVector.h"
#include "common/HashCombine.h"
#include "common/ReadbackSpinManager.h"
@ -108,9 +108,6 @@ public:
__fi VKStreamBuffer& GetTextureUploadBuffer() { return m_texture_stream_buffer; }
VkCommandBuffer GetCurrentInitCommandBuffer();
/// Allocates a descriptor set from the pool reserved for the current frame.
VkDescriptorSet AllocateDescriptorSet(VkDescriptorSetLayout set_layout);
/// Allocates a descriptor set from the pool reserved for the current frame.
VkDescriptorSet AllocatePersistentDescriptorSet(VkDescriptorSetLayout set_layout);
@ -199,12 +196,11 @@ private:
};
using ExtensionList = std::vector<const char*>;
static bool SelectInstanceExtensions(
ExtensionList* extension_list, const WindowInfo& wi, bool enable_debug_utils);
static bool SelectInstanceExtensions(ExtensionList* extension_list, const WindowInfo& wi, bool enable_debug_utils);
bool SelectDeviceExtensions(ExtensionList* extension_list, bool enable_surface);
bool SelectDeviceFeatures();
bool CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer);
void ProcessDeviceExtensions();
bool ProcessDeviceExtensions();
bool CreateAllocator();
bool CreateCommandBuffers();
@ -237,7 +233,6 @@ private:
// [0] - Init (upload) command buffer, [1] - draw command buffer
VkCommandPool command_pool = VK_NULL_HANDLE;
std::array<VkCommandBuffer, 2> command_buffers{VK_NULL_HANDLE, VK_NULL_HANDLE};
VkDescriptorPool descriptor_pool = VK_NULL_HANDLE;
VkFence fence = VK_NULL_HANDLE;
u64 fence_counter = 0;
s32 spin_id = -1;
@ -388,11 +383,7 @@ public:
enum : u32
{
NUM_TFX_DYNAMIC_OFFSETS = 2,
NUM_TFX_DRAW_TEXTURES = 2,
NUM_TFX_RT_TEXTURES = 2,
NUM_TFX_TEXTURES = NUM_TFX_DRAW_TEXTURES + NUM_TFX_RT_TEXTURES,
NUM_CONVERT_TEXTURES = 1,
NUM_CONVERT_SAMPLERS = 1,
NUM_UTILITY_SAMPLERS = 1,
CONVERT_PUSH_CONSTANTS_SIZE = 96,
NUM_CAS_PIPELINES = 2,
@ -401,10 +392,18 @@ public:
{
TFX_DESCRIPTOR_SET_UBO,
TFX_DESCRIPTOR_SET_TEXTURES,
TFX_DESCRIPTOR_SET_RT,
NUM_TFX_DESCRIPTOR_SETS,
};
enum TFX_TEXTURES : u32
{
TFX_TEXTURE_TEXTURE,
TFX_TEXTURE_PALETTE,
TFX_TEXTURE_RT,
TFX_TEXTURE_PRIMID,
NUM_TFX_TEXTURES
};
enum DATE_RENDER_PASS : u32
{
DATE_RENDER_PASS_NONE = 0,
@ -419,8 +418,7 @@ private:
VkPipelineLayout m_utility_pipeline_layout = VK_NULL_HANDLE;
VkDescriptorSetLayout m_tfx_ubo_ds_layout = VK_NULL_HANDLE;
VkDescriptorSetLayout m_tfx_sampler_ds_layout = VK_NULL_HANDLE;
VkDescriptorSetLayout m_tfx_rt_texture_ds_layout = VK_NULL_HANDLE;
VkDescriptorSetLayout m_tfx_texture_ds_layout = VK_NULL_HANDLE;
VkPipelineLayout m_tfx_pipeline_layout = VK_NULL_HANDLE;
VKStreamBuffer m_vertex_stream_buffer;
@ -449,7 +447,8 @@ private:
VkPipeline m_shadeboost_pipeline = {};
std::unordered_map<u32, VkShaderModule> m_tfx_vertex_shaders;
std::unordered_map<GSHWDrawConfig::PSSelector, VkShaderModule, GSHWDrawConfig::PSSelectorHash> m_tfx_fragment_shaders;
std::unordered_map<GSHWDrawConfig::PSSelector, VkShaderModule, GSHWDrawConfig::PSSelectorHash>
m_tfx_fragment_shaders;
std::unordered_map<PipelineSelector, VkPipeline, PipelineSelectorHash> m_tfx_pipelines;
VkRenderPass m_utility_color_render_pass_load = VK_NULL_HANDLE;
@ -473,15 +472,18 @@ private:
std::string m_tfx_source;
GSTexture* CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) override;
GSTexture* CreateSurface(
GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) override;
void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE,
const GSRegEXTBUF& EXTBUF, u32 c, const bool linear) final;
void DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderInterlace shader, bool linear, const InterlaceConstantBuffer& cb) final;
void DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect,
ShaderInterlace shader, bool linear, const InterlaceConstantBuffer& cb) final;
void DoShadeBoost(GSTexture* sTex, GSTexture* dTex, const float params[4]) final;
void DoFXAA(GSTexture* sTex, GSTexture* dTex) final;
bool DoCAS(GSTexture* sTex, GSTexture* dTex, bool sharpen_only, const std::array<u32, NUM_CAS_CONSTANTS>& constants) final;
bool DoCAS(
GSTexture* sTex, GSTexture* dTex, bool sharpen_only, const std::array<u32, NUM_CAS_CONSTANTS>& constants) final;
VkSampler GetSampler(GSHWDrawConfig::SamplerSelector ss);
void ClearSamplerCache() final;
@ -520,7 +522,8 @@ public:
__fi static GSDeviceVK* GetInstance() { return static_cast<GSDeviceVK*>(g_gs_device.get()); }
static void GetAdaptersAndFullscreenModes(std::vector<std::string>* adapters, std::vector<std::string>* fullscreen_modes);
static void GetAdaptersAndFullscreenModes(
std::vector<std::string>* adapters, std::vector<std::string>* fullscreen_modes);
/// Returns true if Vulkan is suitable as a default for the devices in the system.
static bool IsSuitableDefaultRenderer();
@ -571,7 +574,8 @@ public:
bool green, bool blue, bool alpha) override;
void PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect,
PresentShader shader, float shaderTime, bool linear) override;
void DrawMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvert shader) override;
void DrawMultiStretchRects(
const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvert shader) override;
void DoMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, GSTextureVK* dTex, ShaderConvert shader);
void BeginRenderPassForStretchRect(
@ -583,8 +587,10 @@ public:
void BlitRect(GSTexture* sTex, const GSVector4i& sRect, u32 sLevel, GSTexture* dTex, const GSVector4i& dRect,
u32 dLevel, bool linear);
void UpdateCLUTTexture(GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, GSTexture* dTex, u32 dOffset, u32 dSize) override;
void ConvertToIndexedTexture(GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, u32 SBW, u32 SPSM, GSTexture* dTex, u32 DBW, u32 DPSM) override;
void UpdateCLUTTexture(
GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, GSTexture* dTex, u32 dOffset, u32 dSize) override;
void ConvertToIndexedTexture(GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, u32 SBW, u32 SPSM,
GSTexture* dTex, u32 DBW, u32 DPSM) override;
void SetupDATE(GSTexture* rt, GSTexture* ds, bool datm, const GSVector4i& bbox);
GSTextureVK* SetupPrimitiveTrackingDATE(GSHWDrawConfig& config);
@ -657,25 +663,34 @@ public:
private:
enum DIRTY_FLAG : u32
{
DIRTY_FLAG_TFX_SAMPLERS_DS = (1 << 0),
DIRTY_FLAG_TFX_RT_TEXTURE_DS = (1 << 1),
DIRTY_FLAG_TFX_DYNAMIC_OFFSETS = (1 << 2),
DIRTY_FLAG_UTILITY_TEXTURE = (1 << 3),
DIRTY_FLAG_BLEND_CONSTANTS = (1 << 4),
DIRTY_FLAG_LINE_WIDTH = (1 << 5),
DIRTY_FLAG_VERTEX_BUFFER = (1 << 6),
DIRTY_FLAG_INDEX_BUFFER = (1 << 7),
DIRTY_FLAG_VIEWPORT = (1 << 8),
DIRTY_FLAG_SCISSOR = (1 << 9),
DIRTY_FLAG_PIPELINE = (1 << 10),
DIRTY_FLAG_VS_CONSTANT_BUFFER = (1 << 11),
DIRTY_FLAG_PS_CONSTANT_BUFFER = (1 << 12),
DIRTY_FLAG_TFX_TEXTURE_0 = (1 << 0), // 0, 1, 2, 3
DIRTY_FLAG_TFX_UBO = (1 << 4),
DIRTY_FLAG_UTILITY_TEXTURE = (1 << 5),
DIRTY_FLAG_BLEND_CONSTANTS = (1 << 6),
DIRTY_FLAG_LINE_WIDTH = (1 << 7),
DIRTY_FLAG_VERTEX_BUFFER = (1 << 8),
DIRTY_FLAG_INDEX_BUFFER = (1 << 9),
DIRTY_FLAG_VIEWPORT = (1 << 10),
DIRTY_FLAG_SCISSOR = (1 << 11),
DIRTY_FLAG_PIPELINE = (1 << 12),
DIRTY_FLAG_VS_CONSTANT_BUFFER = (1 << 13),
DIRTY_FLAG_PS_CONSTANT_BUFFER = (1 << 14),
DIRTY_FLAG_TFX_TEXTURE_TEX = (DIRTY_FLAG_TFX_TEXTURE_0 << 0),
DIRTY_FLAG_TFX_TEXTURE_PALETTE = (DIRTY_FLAG_TFX_TEXTURE_0 << 1),
DIRTY_FLAG_TFX_TEXTURE_RT = (DIRTY_FLAG_TFX_TEXTURE_0 << 2),
DIRTY_FLAG_TFX_TEXTURE_PRIMID = (DIRTY_FLAG_TFX_TEXTURE_0 << 3),
DIRTY_FLAG_TFX_TEXTURES = DIRTY_FLAG_TFX_TEXTURE_TEX | DIRTY_FLAG_TFX_TEXTURE_PALETTE |
DIRTY_FLAG_TFX_TEXTURE_RT | DIRTY_FLAG_TFX_TEXTURE_PRIMID,
DIRTY_BASE_STATE = DIRTY_FLAG_VERTEX_BUFFER | DIRTY_FLAG_INDEX_BUFFER | DIRTY_FLAG_PIPELINE |
DIRTY_FLAG_VIEWPORT | DIRTY_FLAG_SCISSOR | DIRTY_FLAG_BLEND_CONSTANTS | DIRTY_FLAG_LINE_WIDTH,
DIRTY_TFX_STATE = DIRTY_BASE_STATE | DIRTY_FLAG_TFX_SAMPLERS_DS | DIRTY_FLAG_TFX_RT_TEXTURE_DS,
DIRTY_FLAG_VIEWPORT | DIRTY_FLAG_SCISSOR | DIRTY_FLAG_BLEND_CONSTANTS |
DIRTY_FLAG_LINE_WIDTH,
DIRTY_TFX_STATE = DIRTY_BASE_STATE | DIRTY_FLAG_TFX_TEXTURES,
DIRTY_UTILITY_STATE = DIRTY_BASE_STATE | DIRTY_FLAG_UTILITY_TEXTURE,
DIRTY_CONSTANT_BUFFER_STATE = DIRTY_FLAG_VS_CONSTANT_BUFFER | DIRTY_FLAG_PS_CONSTANT_BUFFER,
ALL_DIRTY_STATE = DIRTY_BASE_STATE | DIRTY_TFX_STATE | DIRTY_UTILITY_STATE | DIRTY_CONSTANT_BUFFER_STATE,
};
enum class PipelineLayout

View File

@ -141,6 +141,11 @@ void Vulkan::DescriptorSetLayoutBuilder::Clear()
m_ci.bindingCount = 0;
}
void Vulkan::DescriptorSetLayoutBuilder::SetPushFlag()
{
m_ci.flags |= VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR;
}
VkDescriptorSetLayout Vulkan::DescriptorSetLayoutBuilder::Create(VkDevice device)
{
VkDescriptorSetLayout layout;
@ -724,6 +729,17 @@ void Vulkan::DescriptorSetUpdateBuilder::Update(VkDevice device, bool clear /*=
Clear();
}
void Vulkan::DescriptorSetUpdateBuilder::PushUpdate(
VkCommandBuffer cmdbuf, VkPipelineBindPoint bind_point, VkPipelineLayout layout, u32 set, bool clear /*= true*/)
{
pxAssert(m_num_writes > 0);
vkCmdPushDescriptorSetKHR(cmdbuf, bind_point, layout, set, m_num_writes, m_writes.data());
if (clear)
Clear();
}
void Vulkan::DescriptorSetUpdateBuilder::AddImageDescriptorWrite(VkDescriptorSet set, u32 binding, VkImageView view,
VkImageLayout layout /*= VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL*/)
{

View File

@ -48,6 +48,7 @@ namespace Vulkan
DescriptorSetLayoutBuilder();
void Clear();
void SetPushFlag();
VkDescriptorSetLayout Create(VkDevice device);
@ -248,6 +249,8 @@ namespace Vulkan
void Clear();
void Update(VkDevice device, bool clear = true);
void PushUpdate(VkCommandBuffer cmdbuf, VkPipelineBindPoint bind_point, VkPipelineLayout layout, u32 set,
bool clear = true);
void AddImageDescriptorWrite(VkDescriptorSet set, u32 binding, VkImageView view,
VkImageLayout layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);

View File

@ -243,4 +243,7 @@ VULKAN_DEVICE_ENTRY_POINT(vkReleaseFullScreenExclusiveModeEXT, false)
// VK_EXT_calibrated_timestamps
VULKAN_DEVICE_ENTRY_POINT(vkGetCalibratedTimestampsEXT, false)
// VK_KHR_push_descriptor
VULKAN_DEVICE_ENTRY_POINT(vkCmdPushDescriptorSetKHR, false)
#endif // VULKAN_DEVICE_ENTRY_POINT

View File

@ -15,4 +15,4 @@
/// Version number for GS and other shaders. Increment whenever any of the contents of the
/// shaders change, to invalidate the cache.
static constexpr u32 SHADER_CACHE_VERSION = 29;
static constexpr u32 SHADER_CACHE_VERSION = 30;