diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index b5097c463..19b7fea94 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -3032,8 +3032,15 @@ namespace dxvk { void DxvkContext::commitGraphicsPostBarriers() { - if (m_state.gp.flags.test(DxvkGraphicsPipelineFlag::HasStorageDescriptors)) { - // FIXME support vertex stage SSBO synchronization + bool fs = m_state.gp.flags.test(DxvkGraphicsPipelineFlag::HasFsStorageDescriptors); + bool vs = m_state.gp.flags.test(DxvkGraphicsPipelineFlag::HasVsStorageDescriptors); + + if (vs) { + // External subpass dependencies serve as full memory + // and execution barriers, so we can use this to allow + // inter-stage synchronization. + this->spillRenderPass(); + } else if (fs) { this->emitMemoryBarrier( VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_SHADER_WRITE_BIT, diff --git a/src/dxvk/dxvk_graphics.cpp b/src/dxvk/dxvk_graphics.cpp index 63afdb51f..9dee8cf4a 100644 --- a/src/dxvk/dxvk_graphics.cpp +++ b/src/dxvk/dxvk_graphics.cpp @@ -73,8 +73,13 @@ namespace dxvk { if (gs != nullptr && gs->hasCapability(spv::CapabilityTransformFeedback)) m_flags.set(DxvkGraphicsPipelineFlag::HasTransformFeedback); - if (m_layout->hasStorageDescriptors()) - m_flags.set(DxvkGraphicsPipelineFlag::HasStorageDescriptors); + VkShaderStageFlags stoStages = m_layout->getStorageDescriptorStages(); + + if (stoStages & VK_SHADER_STAGE_FRAGMENT_BIT) + m_flags.set(DxvkGraphicsPipelineFlag::HasFsStorageDescriptors); + + if (stoStages & ~VK_SHADER_STAGE_FRAGMENT_BIT) + m_flags.set(DxvkGraphicsPipelineFlag::HasVsStorageDescriptors); m_common.msSampleShadingEnable = fs != nullptr && fs->hasCapability(spv::CapabilitySampleRateShading); m_common.msSampleShadingFactor = 1.0f; diff --git a/src/dxvk/dxvk_graphics.h b/src/dxvk/dxvk_graphics.h index 445c942d1..f0d7d9a55 100644 --- a/src/dxvk/dxvk_graphics.h +++ b/src/dxvk/dxvk_graphics.h @@ -21,7 +21,8 @@ namespace dxvk { */ enum class DxvkGraphicsPipelineFlag { HasTransformFeedback, - HasStorageDescriptors, + HasFsStorageDescriptors, + HasVsStorageDescriptors, }; using DxvkGraphicsPipelineFlags = Flags; diff --git a/src/dxvk/dxvk_pipelayout.h b/src/dxvk/dxvk_pipelayout.h index 185f0829f..ddea8a6f9 100644 --- a/src/dxvk/dxvk_pipelayout.h +++ b/src/dxvk/dxvk_pipelayout.h @@ -224,13 +224,23 @@ namespace dxvk { * It is assumed that storage images and buffers * will be written to if they are present. Used * for synchronization purposes. + * \param [in] stages Shader stages to check */ - bool hasStorageDescriptors() const { - return m_descriptorTypes.any( - VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, - VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, - VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, - VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER); + VkShaderStageFlags getStorageDescriptorStages() const { + VkShaderStageFlags stages = 0; + + for (const auto& slot : m_bindingSlots) { + bool isStorageDescriptor = + slot.type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER || + slot.type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC || + slot.type == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER || + slot.type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + + if (isStorageDescriptor) + stages |= slot.stages; + } + + return stages; } private: