diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 71e4b17ab..8a3b8ced3 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -2032,6 +2032,28 @@ namespace dxvk { } + void DxvkContext::setPredicate( + const DxvkBufferSlice& predicate, + VkConditionalRenderingFlagsEXT flags) { + if (!m_state.cond.predicate.matches(predicate)) { + m_state.cond.predicate = predicate; + + if (m_predicateWrites.find(predicate.getSliceHandle()) + != m_predicateWrites.end()) { + spillRenderPass(); + commitPredicateUpdates(); + } + + m_flags.set(DxvkContextFlag::GpDirtyPredicate); + } + + if (m_state.cond.flags != flags) { + m_state.cond.flags = flags; + m_flags.set(DxvkContextFlag::GpDirtyPredicate); + } + } + + void DxvkContext::setBarrierControl(DxvkBarrierControlFlags control) { m_barrierControl = control; } @@ -2055,6 +2077,21 @@ namespace dxvk { } + void DxvkContext::writePredicate( + const DxvkBufferSlice& predicate, + const Rc& query) { + DxvkBufferSliceHandle predicateHandle = predicate.getSliceHandle(); + DxvkGpuQueryHandle queryHandle = query->handle(); + + if (m_flags.test(DxvkContextFlag::GpRenderPassBound)) + m_predicateWrites.insert({ predicateHandle, queryHandle }); + else + updatePredicate(predicateHandle, queryHandle); + + m_cmd->trackResource(predicate.buffer()); + } + + void DxvkContext::writeTimestamp(const Rc& query) { m_queryManager.writeTimestamp(m_cmd, query); } @@ -2669,6 +2706,30 @@ namespace dxvk { } + void DxvkContext::updatePredicate( + const DxvkBufferSliceHandle& predicate, + const DxvkGpuQueryHandle& query) { + m_cmd->cmdCopyQueryPoolResults( + query.queryPool, query.queryId, 1, + predicate.handle, predicate.offset, sizeof(uint32_t), + VK_QUERY_RESULT_WAIT_BIT); + + m_barriers.accessBuffer(predicate, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_ACCESS_TRANSFER_WRITE_BIT, + VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT, + VK_ACCESS_CONDITIONAL_RENDERING_READ_BIT_EXT); + } + + + void DxvkContext::commitPredicateUpdates() { + for (const auto& update : m_predicateWrites) + updatePredicate(update.first, update.second); + + m_predicateWrites.clear(); + } + + void DxvkContext::startRenderPass() { if (!m_flags.test(DxvkContextFlag::GpRenderPassBound) && (m_state.om.framebuffer != nullptr)) { @@ -2710,6 +2771,7 @@ namespace dxvk { this->renderPassUnbindFramebuffer(); this->unbindGraphicsPipeline(); + this->commitPredicateUpdates(); m_flags.clr(DxvkContextFlag::GpDirtyXfbCounters); } @@ -2865,6 +2927,33 @@ namespace dxvk { } + void DxvkContext::startConditionalRendering() { + if (!m_flags.test(DxvkContextFlag::GpCondActive)) { + m_flags.set(DxvkContextFlag::GpCondActive); + + auto predicateSlice = m_state.cond.predicate.getSliceHandle(); + + VkConditionalRenderingBeginInfoEXT info; + info.sType = VK_STRUCTURE_TYPE_CONDITIONAL_RENDERING_BEGIN_INFO_EXT; + info.pNext = nullptr; + info.buffer = predicateSlice.handle; + info.offset = predicateSlice.offset; + info.flags = m_state.cond.flags; + + m_cmd->cmdBeginConditionalRendering(&info); + } + } + + + void DxvkContext::pauseConditionalRendering() { + if (m_flags.test(DxvkContextFlag::GpCondActive)) { + m_flags.clr(DxvkContextFlag::GpCondActive); + + m_cmd->cmdEndConditionalRendering(); + } + } + + void DxvkContext::startTransformFeedback() { if (!m_flags.test(DxvkContextFlag::GpXfbActive)) { m_flags.set(DxvkContextFlag::GpXfbActive); @@ -2980,7 +3069,8 @@ namespace dxvk { DxvkContextFlag::GpDirtyBlendConstants, DxvkContextFlag::GpDirtyStencilRef, DxvkContextFlag::GpDirtyViewport, - DxvkContextFlag::GpDirtyDepthBias); + DxvkContextFlag::GpDirtyDepthBias, + DxvkContextFlag::GpDirtyPredicate); m_gpActivePipeline = VK_NULL_HANDLE; } @@ -3442,6 +3532,18 @@ namespace dxvk { } + void DxvkContext::updateConditionalRendering() { + if (m_flags.test(DxvkContextFlag::GpDirtyPredicate)) { + m_flags.clr(DxvkContextFlag::GpDirtyPredicate); + + pauseConditionalRendering(); + + if (m_state.cond.predicate.defined()) + startConditionalRendering(); + } + } + + void DxvkContext::updateDynamicState() { if (m_gpActivePipeline == VK_NULL_HANDLE) return; @@ -3548,6 +3650,9 @@ namespace dxvk { if (m_state.gp.flags.test(DxvkGraphicsPipelineFlag::HasTransformFeedback)) this->updateTransformFeedbackState(); + + if (m_flags.test(DxvkContextFlag::GpDirtyPredicate)) + this->updateConditionalRendering(); if (m_flags.any( DxvkContextFlag::GpDirtyDescriptorSet, diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h index 653a5b74b..c374e9f2f 100644 --- a/src/dxvk/dxvk_context.h +++ b/src/dxvk/dxvk_context.h @@ -813,6 +813,21 @@ namespace dxvk { uint32_t attachment, const DxvkBlendMode& blendMode); + /** + * \brief Sets predicate + * + * Enables or disables conditional rendering, + * depending on whether the given buffer slice + * is defined or not. Draw calls and render + * target clear commands will get discarded if + * the predicate value is either zero or non-zero. + * \param [in] predicate The predicate buffer + * \param [in] flags Conditional rendering mode + */ + void setPredicate( + const DxvkBufferSlice& predicate, + VkConditionalRenderingFlagsEXT flags); + /** * \brief Sets barrier control flags * @@ -837,6 +852,18 @@ namespace dxvk { void signalGpuEvent( const Rc& event); + /** + * \brief Copies query data to predicate buffer + * + * The given buffer slice can then be passed + * to \c setPredicate to enable predication. + * \param [in] predicate Predicate buffer + * \param [in] query Source query + */ + void writePredicate( + const DxvkBufferSlice& predicate, + const Rc& query); + /** * \brief Writes to a timestamp query * \param [in] query The timestamp query @@ -876,6 +903,11 @@ namespace dxvk { std::array m_descInfos; std::array m_descOffsets; + std::unordered_map< + DxvkBufferSliceHandle, + DxvkGpuQueryHandle, + DxvkHash, DxvkEq> m_predicateWrites; + void clearImageViewFb( const Rc& imageView, VkOffset3D offset, @@ -919,6 +951,12 @@ namespace dxvk { const VkImageSubresourceLayers& srcSubresources, VkFormat format); + void updatePredicate( + const DxvkBufferSliceHandle& predicate, + const DxvkGpuQueryHandle& query); + + void commitPredicateUpdates(); + void startRenderPass(); void spillRenderPass(); void clearRenderPass(); @@ -935,6 +973,9 @@ namespace dxvk { const DxvkRenderTargets& renderTargets, DxvkRenderPassOps& renderPassOps); + void startConditionalRendering(); + void pauseConditionalRendering(); + void startTransformFeedback(); void pauseTransformFeedback(); @@ -970,10 +1011,12 @@ namespace dxvk { void updateIndexBufferBinding(); void updateVertexBufferBindings(); - + void updateTransformFeedbackBuffers(); void updateTransformFeedbackState(); + void updateConditionalRendering(); + void updateDynamicState(); bool validateComputeState(); diff --git a/src/dxvk/dxvk_context_state.h b/src/dxvk/dxvk_context_state.h index 0343f3437..69ec26bba 100644 --- a/src/dxvk/dxvk_context_state.h +++ b/src/dxvk/dxvk_context_state.h @@ -22,6 +22,7 @@ namespace dxvk { */ enum class DxvkContextFlag : uint64_t { GpRenderPassBound, ///< Render pass is currently bound + GpCondActive, ///< Conditional rendering is enabled GpXfbActive, ///< Transform feedback is enabled GpClearRenderTargets, ///< Render targets need to be cleared GpDirtyFramebuffer, ///< Framebuffer binding is out of date @@ -38,6 +39,7 @@ namespace dxvk { GpDirtyDepthBias, ///< Depth bias has changed GpDirtyStencilRef, ///< Stencil reference has changed GpDirtyViewport, ///< Viewport state has changed + GpDirtyPredicate, ///< Predicate has changed GpDynamicBlendConstants, ///< Blend constants are dynamic GpDynamicDepthBias, ///< Depth bias is dynamic GpDynamicStencilRef, ///< Stencil reference is dynamic @@ -134,6 +136,12 @@ namespace dxvk { DxvkDepthBias depthBias = { 0.0f, 0.0f, 0.0f }; uint32_t stencilReference = 0; }; + + + struct DxvkCondRenderState { + DxvkBufferSlice predicate; + VkConditionalRenderingFlagsEXT flags; + }; /** @@ -149,6 +157,7 @@ namespace dxvk { DxvkOutputMergerState om; DxvkXfbState xfb; DxvkDynamicState dyn; + DxvkCondRenderState cond; DxvkGraphicsPipelineState gp; DxvkComputePipelineState cp;