From 6f7a4681740e7656cd734d39fd1e63cab63885ff Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Mon, 17 Feb 2025 04:35:23 +0100 Subject: [PATCH] [dxvk] Fix global render pass barrier Only need to deal with common write-after-read scenarios, we can ignore writes since those will add extra barriers anyway. Also move this work out of the somewhat hot pipeline bind function. --- src/dxvk/dxvk_context.cpp | 79 ++++++++++++++------------------------ src/dxvk/dxvk_context.h | 8 ++-- src/dxvk/dxvk_graphics.cpp | 3 +- 3 files changed, 33 insertions(+), 57 deletions(-) diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 2cbc83a13..f35ea2fbf 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -21,32 +21,17 @@ namespace dxvk { m_state.om.framebufferInfo = makeFramebufferInfo(m_state.om.renderTargets); m_descriptorManager = new DxvkDescriptorManager(device.ptr()); - // Default destination barriers for graphics pipelines - m_globalRoGraphicsBarrier.stages = m_device->getShaderPipelineStages() - | VK_PIPELINE_STAGE_TRANSFER_BIT - | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT - | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT - | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; - m_globalRoGraphicsBarrier.access = 0; + // Global barrier for graphics pipelines. This is only used to + // avoid write-after-read hazards after a render pass, so the + // access mask here can be zero. + m_renderPassBarrierDst.stages = m_device->getShaderPipelineStages() + | VK_PIPELINE_STAGE_TRANSFER_BIT + | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT + | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT + | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; if (m_device->features().extTransformFeedback.transformFeedback) - m_globalRoGraphicsBarrier.stages |= VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT; - - m_globalRwGraphicsBarrier = m_globalRoGraphicsBarrier; - m_globalRwGraphicsBarrier.stages |= VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT - | VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; - - m_globalRwGraphicsBarrier.access |= VK_ACCESS_INDIRECT_COMMAND_READ_BIT - | VK_ACCESS_INDEX_READ_BIT - | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT - | VK_ACCESS_UNIFORM_READ_BIT - | VK_ACCESS_SHADER_READ_BIT - | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT - | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT - | VK_ACCESS_TRANSFER_READ_BIT; - - if (m_device->features().extTransformFeedback.transformFeedback) - m_globalRwGraphicsBarrier.access |= VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT; + m_renderPassBarrierDst.stages |= VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT; // Store the lifetime tracking bit as a context feature so // that we don't have to scan device features at draw time @@ -5230,6 +5215,14 @@ namespace dxvk { else this->transitionRenderTargetLayouts(false); + if (m_renderPassBarrierSrc.stages) { + accessMemory(DxvkCmdBuffer::ExecBuffer, + m_renderPassBarrierSrc.stages, m_renderPassBarrierSrc.access, + m_renderPassBarrierDst.stages, m_renderPassBarrierDst.access); + + m_renderPassBarrierSrc = DxvkGlobalPipelineBarrier(); + } + flushBarriers(); flushResolves(); @@ -5733,7 +5726,7 @@ namespace dxvk { } - bool DxvkContext::updateGraphicsPipelineState(DxvkGlobalPipelineBarrier srcBarrier) { + bool DxvkContext::updateGraphicsPipelineState() { bool oldIndependentSets = m_flags.test(DxvkContextFlag::GpIndependentSets); // Check which dynamic states need to be active. States that @@ -5808,19 +5801,9 @@ namespace dxvk { // Emit barrier based on pipeline properties, in order to avoid // accidental write-after-read hazards after the render pass. - DxvkGlobalPipelineBarrier pipelineBarrier = m_state.gp.pipeline->getGlobalBarrier(m_state.gp.state); - srcBarrier.stages |= pipelineBarrier.stages; - srcBarrier.access |= pipelineBarrier.access; - - if (srcBarrier.stages) { - DxvkGlobalPipelineBarrier dstBarrier = (srcBarrier.access & vk::AccessWriteMask) - ? m_globalRwGraphicsBarrier - : m_globalRoGraphicsBarrier; - - accessMemory(DxvkCmdBuffer::ExecBuffer, - srcBarrier.stages, srcBarrier.access, - dstBarrier.stages, dstBarrier.access); - } + DxvkGlobalPipelineBarrier srcBarrier = m_state.gp.pipeline->getGlobalBarrier(m_state.gp.state); + m_renderPassBarrierSrc.stages |= srcBarrier.stages; + m_renderPassBarrierSrc.access |= srcBarrier.access; if (unlikely(m_features.test(DxvkContextFeature::DebugUtils))) { uint32_t color = getGraphicsPipelineDebugColor(); @@ -6392,6 +6375,9 @@ namespace dxvk { VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_ACCESS_INDEX_READ_BIT, DxvkAccessOp::None); } + m_renderPassBarrierSrc.stages |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; + m_renderPassBarrierSrc.access |= VK_ACCESS_INDEX_READ_BIT; + m_cmd->track(m_state.vi.indexBuffer.buffer(), DxvkAccess::Read); return true; } @@ -6758,19 +6744,7 @@ namespace dxvk { this->updateSpecConstants(); if (m_flags.test(DxvkContextFlag::GpDirtyPipelineState)) { - DxvkGlobalPipelineBarrier barrier = { }; - - if (Indexed) { - barrier.stages |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; - barrier.access |= VK_ACCESS_INDEX_READ_BIT; - } - - if (Indirect) { - barrier.stages |= VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT; - barrier.access |= VK_ACCESS_INDIRECT_COMMAND_READ_BIT; - } - - if (unlikely(!this->updateGraphicsPipelineState(barrier))) + if (unlikely(!this->updateGraphicsPipelineState())) return false; } @@ -7031,6 +7005,9 @@ namespace dxvk { if (m_flags.test(DxvkContextFlag::DirtyDrawBuffer)) { m_flags.clr(DxvkContextFlag::DirtyDrawBuffer); + m_renderPassBarrierSrc.stages |= VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT; + m_renderPassBarrierSrc.access |= VK_ACCESS_INDIRECT_COMMAND_READ_BIT; + if (m_state.id.argBuffer.length()) m_cmd->track(m_state.id.argBuffer.buffer(), DxvkAccess::Read); diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h index d975545a6..4b836d763 100644 --- a/src/dxvk/dxvk_context.h +++ b/src/dxvk/dxvk_context.h @@ -1434,9 +1434,9 @@ namespace dxvk { DxvkBarrierControlFlags m_barrierControl; DxvkGpuQueryManager m_queryManager; - - DxvkGlobalPipelineBarrier m_globalRoGraphicsBarrier; - DxvkGlobalPipelineBarrier m_globalRwGraphicsBarrier; + + DxvkGlobalPipelineBarrier m_renderPassBarrierSrc = { }; + DxvkGlobalPipelineBarrier m_renderPassBarrierDst = { }; DxvkRenderTargetLayouts m_rtLayouts = { }; @@ -1690,7 +1690,7 @@ namespace dxvk { void unbindGraphicsPipeline(); bool updateGraphicsPipeline(); - bool updateGraphicsPipelineState(DxvkGlobalPipelineBarrier srcBarrier); + bool updateGraphicsPipelineState(); uint32_t getGraphicsPipelineDebugColor() const; diff --git a/src/dxvk/dxvk_graphics.cpp b/src/dxvk/dxvk_graphics.cpp index 7a8ed26a0..9ac5211de 100644 --- a/src/dxvk/dxvk_graphics.cpp +++ b/src/dxvk/dxvk_graphics.cpp @@ -955,8 +955,7 @@ namespace dxvk { if (m_shaders.gs->flags().test(DxvkShaderFlag::HasTransformFeedback)) { m_flags.set(DxvkGraphicsPipelineFlag::HasTransformFeedback); - m_barrier.stages |= VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT - | VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT; + m_barrier.stages |= VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT; m_barrier.access |= VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT | VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT | VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT;