diff --git a/src/d3d11/d3d11_device.cpp b/src/d3d11/d3d11_device.cpp index ac2cf257..831cd2bc 100644 --- a/src/d3d11/d3d11_device.cpp +++ b/src/d3d11/d3d11_device.cpp @@ -731,17 +731,10 @@ namespace dxvk { // set by D3D11DeviceContext::IASetVertexBuffers. DxvkVertexBinding binding; binding.binding = pInputElementDescs[i].InputSlot; - binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; - - if (pInputElementDescs[i].InputSlotClass == D3D11_INPUT_PER_INSTANCE_DATA) { - binding.inputRate = VK_VERTEX_INPUT_RATE_INSTANCE; - - if (pInputElementDescs[i].InstanceDataStepRate != 1) { - Logger::warn(str::format( - "D3D11Device: Unsupported instance data step rate: ", - pInputElementDescs[i].InstanceDataStepRate)); - } - } + binding.fetchRate = pInputElementDescs[i].InstanceDataStepRate; + binding.inputRate = pInputElementDescs[i].InputSlotClass == D3D11_INPUT_PER_INSTANCE_DATA + ? VK_VERTEX_INPUT_RATE_INSTANCE + : VK_VERTEX_INPUT_RATE_VERTEX; // Check if the binding was already defined. If so, the // parameters must be identical (namely, the input rate). diff --git a/src/dxbc/dxbc_compiler.cpp b/src/dxbc/dxbc_compiler.cpp index 1c2dcc8e..694623ab 100644 --- a/src/dxbc/dxbc_compiler.cpp +++ b/src/dxbc/dxbc_compiler.cpp @@ -4930,6 +4930,8 @@ namespace dxvk { m_module.setDebugName(typeId, "s_push_constant"); m_module.setDebugMemberName(typeId, PerVertex_Position, "instance_id"); + // There's only ever going to be one single push constant + // block per shader, so we'll declare the variable here uint32_t ptrTypeId = m_module.defPointerType( typeId, spv::StorageClassPushConstant); diff --git a/src/dxvk/dxvk_cmdlist.h b/src/dxvk/dxvk_cmdlist.h index b54361c3..c961719d 100644 --- a/src/dxvk/dxvk_cmdlist.h +++ b/src/dxvk/dxvk_cmdlist.h @@ -333,6 +333,17 @@ namespace dxvk { } + void cmdPushConstants( + VkPipelineLayout layout, + VkShaderStageFlags stageFlags, + uint32_t offset, + uint32_t size, + const void* pValues) { + m_vkd->vkCmdPushConstants(m_buffer, + layout, stageFlags, offset, size, pValues); + } + + void cmdResolveImage( VkImage srcImage, VkImageLayout srcImageLayout, diff --git a/src/dxvk/dxvk_constant_state.h b/src/dxvk/dxvk_constant_state.h index b748100c..c8903093 100644 --- a/src/dxvk/dxvk_constant_state.h +++ b/src/dxvk/dxvk_constant_state.h @@ -136,6 +136,7 @@ namespace dxvk { */ struct DxvkVertexBinding { uint32_t binding; + uint32_t fetchRate; VkVertexInputRate inputRate; }; diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 73d0b1a5..591ba948 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -572,9 +572,16 @@ namespace dxvk { this->commitGraphicsState(); if (m_gpActivePipeline != VK_NULL_HANDLE) { - m_cmd->cmdDraw( - vertexCount, instanceCount, - firstVertex, firstInstance); + if (!m_flags.test(DxvkContextFlag::GpEmulateInstanceFetchRate)) { + m_cmd->cmdDraw( + vertexCount, instanceCount, + firstVertex, firstInstance); + } else { + static bool errorShown = false; + + if (!std::exchange(errorShown, true)) + Logger::warn("Dxvk: GpEmulateInstanceFetchRate not supported for direct draws"); + } } } @@ -588,10 +595,17 @@ namespace dxvk { if (m_gpActivePipeline != VK_NULL_HANDLE) { auto physicalSlice = buffer.physicalSlice(); - m_cmd->cmdDrawIndirect( - physicalSlice.handle(), - physicalSlice.offset(), - count, stride); + if (!m_flags.test(DxvkContextFlag::GpEmulateInstanceFetchRate)) { + m_cmd->cmdDrawIndirect( + physicalSlice.handle(), + physicalSlice.offset(), + count, stride); + } else { + static bool errorShown = false; + + if (!std::exchange(errorShown, true)) + Logger::warn("Dxvk: GpEmulateInstanceFetchRate not supported for indirect draws"); + } } } @@ -1042,6 +1056,8 @@ namespace dxvk { m_flags.set( DxvkContextFlag::GpDirtyPipelineState, DxvkContextFlag::GpDirtyVertexBuffers); + m_flags.clr( + DxvkContextFlag::GpEmulateInstanceFetchRate); for (uint32_t i = 0; i < attributeCount; i++) { m_state.gp.state.ilAttributes[i].location = attributes[i].location; @@ -1056,6 +1072,10 @@ namespace dxvk { for (uint32_t i = 0; i < bindingCount; i++) { m_state.gp.state.ilBindings[i].binding = bindings[i].binding; m_state.gp.state.ilBindings[i].inputRate = bindings[i].inputRate; + m_state.vi.vertexFetchRates[bindings[i].binding] = bindings[i].fetchRate; + + if (bindings[i].inputRate == VK_VERTEX_INPUT_RATE_INSTANCE && bindings[i].fetchRate != 1) + m_flags.set(DxvkContextFlag::GpEmulateInstanceFetchRate); } for (uint32_t i = bindingCount; i < m_state.gp.state.ilBindingCount; i++) diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h index 67e9757e..928fd41a 100644 --- a/src/dxvk/dxvk_context.h +++ b/src/dxvk/dxvk_context.h @@ -558,12 +558,12 @@ namespace dxvk { void updateShaderResources( VkPipelineBindPoint bindPoint, - const Rc& layout); + const Rc& layout); void updateShaderDescriptors( VkPipelineBindPoint bindPoint, const DxvkBindingState& bindingState, - const Rc& layout); + const Rc& layout); void updateViewports(); void updateBlendConstants(); diff --git a/src/dxvk/dxvk_context_state.h b/src/dxvk/dxvk_context_state.h index 4ff5c793..b0b9e7d2 100644 --- a/src/dxvk/dxvk_context_state.h +++ b/src/dxvk/dxvk_context_state.h @@ -21,16 +21,17 @@ namespace dxvk { * be updated. */ enum class DxvkContextFlag : uint64_t { - GpRenderPassBound, ///< Render pass is currently bound - GpDirtyPipeline, ///< Graphics pipeline binding is out of date - GpDirtyPipelineState, ///< Graphics pipeline needs to be recompiled - GpDirtyResources, ///< Graphics pipeline resource bindings are out of date - GpDirtyVertexBuffers, ///< Vertex buffer bindings are out of date - GpDirtyIndexBuffer, ///< Index buffer binding are out of date + GpRenderPassBound, ///< Render pass is currently bound + GpDirtyPipeline, ///< Graphics pipeline binding is out of date + GpDirtyPipelineState, ///< Graphics pipeline needs to be recompiled + GpDirtyResources, ///< Graphics pipeline resource bindings are out of date + GpDirtyVertexBuffers, ///< Vertex buffer bindings are out of date + GpDirtyIndexBuffer, ///< Index buffer binding are out of date + GpEmulateInstanceFetchRate, ///< The current input layout uses fetch rates != 1 - CpDirtyPipeline, ///< Compute pipeline binding are out of date - CpDirtyPipelineState, ///< Compute pipeline needs to be recompiled - CpDirtyResources, ///< Compute pipeline resource bindings are out of date + CpDirtyPipeline, ///< Compute pipeline binding are out of date + CpDirtyPipelineState, ///< Compute pipeline needs to be recompiled + CpDirtyResources, ///< Compute pipeline resource bindings are out of date }; using DxvkContextFlags = Flags; @@ -42,23 +43,25 @@ namespace dxvk { uint32_t bindingMask = 0; std::array vertexBuffers; + DxvkLimits::MaxNumVertexBindings> vertexBuffers = { }; std::array vertexStrides; + DxvkLimits::MaxNumVertexBindings> vertexStrides = { }; + std::array vertexFetchRates = { }; }; struct DxvkViewportState { - std::array viewports; - std::array scissorRects; + std::array viewports = { }; + std::array scissorRects = { }; }; struct DxvkOutputMergerState { Rc framebuffer; - DxvkBlendConstants blendConstants; - uint32_t stencilReference; + DxvkBlendConstants blendConstants = { 0.0f, 0.0f, 0.0f, 0.0f }; + uint32_t stencilReference = 0; }; @@ -73,9 +76,9 @@ namespace dxvk { DxvkShaderStage tes; DxvkShaderStage gs; DxvkShaderStage fs; - + DxvkGraphicsPipelineStateInfo state; - Rc pipeline; + Rc pipeline; }; diff --git a/src/dxvk/dxvk_limits.h b/src/dxvk/dxvk_limits.h index 0769ea48..db58ea68 100644 --- a/src/dxvk/dxvk_limits.h +++ b/src/dxvk/dxvk_limits.h @@ -14,6 +14,7 @@ namespace dxvk { MaxNumActiveBindings = 128, MaxNumQueuedCommandBuffers = 8, MaxVertexBindingStride = 2048, + MaxPushConstantSize = 128, }; } \ No newline at end of file