diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 87ce23cb..90b55594 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -1733,6 +1733,16 @@ namespace dxvk { } } } + + + void DxvkContext::pushConstants( + uint32_t offset, + uint32_t size, + const void* data) { + std::memcpy(&m_state.pc.data[offset], data, size); + + m_flags.set(DxvkContextFlag::DirtyPushConstants); + } void DxvkContext::resolveImage( @@ -3232,8 +3242,12 @@ namespace dxvk { m_state.cp.state.bsBindingMask.clear(); m_state.cp.pipeline = m_pipeMgr->createComputePipeline(m_state.cp.cs.shader); - if (m_state.cp.pipeline != nullptr) + if (m_state.cp.pipeline != nullptr) { m_cmd->trackResource(m_state.cp.pipeline); + + if (m_state.cp.pipeline->layout()->pushConstRange().size) + m_flags.set(DxvkContextFlag::DirtyPushConstants); + } } } @@ -3288,6 +3302,9 @@ namespace dxvk { if (m_state.gp.pipeline != nullptr) { m_state.gp.flags = m_state.gp.pipeline->flags(); m_cmd->trackResource(m_state.gp.pipeline); + + if (m_state.gp.pipeline->layout()->pushConstRange().size) + m_flags.set(DxvkContextFlag::DirtyPushConstants); } } } @@ -3813,6 +3830,31 @@ namespace dxvk { m_state.dyn.depthBounds.maxDepthBounds); } } + + + void DxvkContext::updatePushConstants(VkPipelineBindPoint bindPoint) { + if (m_flags.test(DxvkContextFlag::DirtyPushConstants)) { + m_flags.clr(DxvkContextFlag::DirtyPushConstants); + + auto layout = bindPoint == VK_PIPELINE_BIND_POINT_GRAPHICS + ? (m_state.gp.pipeline != nullptr ? m_state.gp.pipeline->layout() : nullptr) + : (m_state.cp.pipeline != nullptr ? m_state.cp.pipeline->layout() : nullptr); + + if (!layout) + return; + + VkPushConstantRange pushConstRange = layout->pushConstRange(); + if (!pushConstRange.size) + return; + + m_cmd->cmdPushConstants( + layout->pipelineLayout(), + pushConstRange.stageFlags, + pushConstRange.offset, + pushConstRange.size, + &m_state.pc.data[pushConstRange.offset]); + } + } bool DxvkContext::validateComputeState() { @@ -3848,6 +3890,9 @@ namespace dxvk { DxvkContextFlag::CpDirtyDescriptorSet, DxvkContextFlag::CpDirtyDescriptorOffsets)) this->updateComputeShaderDescriptors(); + + if (m_flags.test(DxvkContextFlag::DirtyPushConstants)) + this->updatePushConstants(VK_PIPELINE_BIND_POINT_COMPUTE); } @@ -3893,6 +3938,9 @@ namespace dxvk { DxvkContextFlag::GpDirtyDepthBias, DxvkContextFlag::GpDirtyDepthBounds)) this->updateDynamicState(); + + if (m_flags.test(DxvkContextFlag::DirtyPushConstants)) + this->updatePushConstants(VK_PIPELINE_BIND_POINT_GRAPHICS); } diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h index b5636f7b..68aa5542 100644 --- a/src/dxvk/dxvk_context.h +++ b/src/dxvk/dxvk_context.h @@ -653,6 +653,19 @@ namespace dxvk { const Rc& buffer, const DxvkBufferSliceHandle& slice); + /** + * \brief Updates push constants + * + * Updates the given push constant range. + * \param [in] offset Byte offset of data to update + * \param [in] size Number of bytes to update + * \param [in] data Pointer to raw data + */ + void pushConstants( + uint32_t offset, + uint32_t size, + const void* data); + /** * \brief Resolves a multisampled image resource * @@ -1074,6 +1087,9 @@ namespace dxvk { void updateConditionalRendering(); void updateDynamicState(); + + void updatePushConstants( + VkPipelineBindPoint bindPoint); bool validateComputeState(); bool validateGraphicsState(); diff --git a/src/dxvk/dxvk_context_state.h b/src/dxvk/dxvk_context_state.h index f7dca11b..9d9ba56e 100644 --- a/src/dxvk/dxvk_context_state.h +++ b/src/dxvk/dxvk_context_state.h @@ -53,6 +53,7 @@ namespace dxvk { CpDirtyDescriptorSet, ///< Compute descriptor set needs to be updated DirtyDrawBuffer, ///< Indirect argument buffer is dirty + DirtyPushConstants, ///< Push constant data has changed }; using DxvkContextFlags = Flags; @@ -102,6 +103,11 @@ namespace dxvk { }; + struct DxvkPushConstantState { + alignas(64) char data[MaxPushConstantSize]; + }; + + struct DxvkXfbState { std::array buffers; std::array counters; @@ -159,6 +165,7 @@ namespace dxvk { DxvkVertexInputState vi; DxvkViewportState vp; DxvkOutputMergerState om; + DxvkPushConstantState pc; DxvkXfbState xfb; DxvkDynamicState dyn; DxvkCondRenderState cond;