diff --git a/src/d3d11/d3d11_context.cpp b/src/d3d11/d3d11_context.cpp index a331f4ccc..e03d35bab 100644 --- a/src/d3d11/d3d11_context.cpp +++ b/src/d3d11/d3d11_context.cpp @@ -3,6 +3,8 @@ #include "d3d11_context.h" #include "d3d11_device.h" +#include "../dxbc/dxbc_util.h" + namespace dxvk { D3D11DeviceContext::D3D11DeviceContext( @@ -638,6 +640,7 @@ namespace dxvk { switch (binding.format) { case DXGI_FORMAT_R16_UINT: indexType = VK_INDEX_TYPE_UINT16; break; case DXGI_FORMAT_R32_UINT: indexType = VK_INDEX_TYPE_UINT32; break; + default: Logger::err(str::format("D3D11: Invalid index format: ", binding.format)); } m_context->bindIndexBuffer( @@ -696,7 +699,7 @@ namespace dxvk { UINT NumBuffers, ID3D11Buffer* const* ppConstantBuffers) { this->BindConstantBuffers( - D3D11ShaderStage::VertexShader, + DxbcProgramType::VertexShader, &m_state.vs.constantBuffers, StartSlot, NumBuffers, ppConstantBuffers); @@ -966,7 +969,7 @@ namespace dxvk { UINT NumBuffers, ID3D11Buffer* const* ppConstantBuffers) { this->BindConstantBuffers( - D3D11ShaderStage::PixelShader, + DxbcProgramType::PixelShader, &m_state.vs.constantBuffers, StartSlot, NumBuffers, ppConstantBuffers); @@ -1329,7 +1332,7 @@ namespace dxvk { void D3D11DeviceContext::BindConstantBuffers( - D3D11ShaderStage ShaderStage, + DxbcProgramType ShaderStage, D3D11ConstantBufferBindings* pBindings, UINT StartSlot, UINT NumBuffers, @@ -1343,18 +1346,25 @@ namespace dxvk { if (pBindings->at(StartSlot + i) != buffer) { pBindings->at(StartSlot + i) = buffer; - DxvkBufferBinding dxvkBinding; + DxvkBufferBinding bindingInfo; if (buffer != nullptr) { - dxvkBinding = DxvkBufferBinding( + bindingInfo = DxvkBufferBinding( buffer->GetDXVKBuffer(), 0, VK_WHOLE_SIZE); } - // TODO compute actual slot index + VkPipelineBindPoint bindPoint + = ShaderStage == DxbcProgramType::ComputeShader + ? VK_PIPELINE_BIND_POINT_COMPUTE + : VK_PIPELINE_BIND_POINT_GRAPHICS; + + uint32_t slotId = computeResourceSlotId( + ShaderStage, DxbcBindingType::ConstantBuffer, + StartSlot + i); + m_context->bindResourceBuffer( - VK_PIPELINE_BIND_POINT_GRAPHICS, 0, - dxvkBinding); + bindPoint, slotId, bindingInfo); } } } @@ -1369,8 +1379,9 @@ namespace dxvk { std::array viewports; std::array scissors; - // FIXME compute proper viewport coordinates (vertical origin). - // D3D11's coordinate system has its origin in the bottom left. + // D3D11's coordinate system has its origin in the bottom left, + // but the viewport coordinates are aligned to the top-left + // corner so we can get away with flipping the viewport. for (uint32_t i = 0; i < m_state.rs.numViewports; i++) { const D3D11_VIEWPORT& vp = m_state.rs.viewports.at(i); @@ -1396,7 +1407,6 @@ namespace dxvk { // TODO D3D11 docs aren't clear about what should happen // when there are undefined scissor rects for a viewport. // Figure out what it does on Windows. - // FIXME Compute correct vertical position if (enableScissorTest && (i < m_state.rs.numScissors)) { const D3D11_RECT& sr = m_state.rs.scissors.at(i); diff --git a/src/d3d11/d3d11_context.h b/src/d3d11/d3d11_context.h index b86dd7bc7..1672821b9 100644 --- a/src/d3d11/d3d11_context.h +++ b/src/d3d11/d3d11_context.h @@ -555,7 +555,7 @@ namespace dxvk { D3D11ContextState m_state; void BindConstantBuffers( - D3D11ShaderStage ShaderStage, + DxbcProgramType ShaderStage, D3D11ConstantBufferBindings* pBindings, UINT StartSlot, UINT NumBuffers, diff --git a/src/d3d11/d3d11_context_state.h b/src/d3d11/d3d11_context_state.h index 31bc28967..71baa0638 100644 --- a/src/d3d11/d3d11_context_state.h +++ b/src/d3d11/d3d11_context_state.h @@ -10,15 +10,6 @@ namespace dxvk { - enum class D3D11ShaderStage { - VertexShader = 0, - HullShader = 1, - DomainShader = 2, - GeometryShader = 3, - PixelShader = 4, - ComputeShader = 5, - }; - using D3D11ConstantBufferBindings = std::array< Com, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT>; diff --git a/src/dxbc/dxbc_util.cpp b/src/dxbc/dxbc_util.cpp new file mode 100644 index 000000000..067e28944 --- /dev/null +++ b/src/dxbc/dxbc_util.cpp @@ -0,0 +1,44 @@ +#include "dxbc_util.h" + +namespace dxvk { + + uint32_t computeResourceSlotId( + DxbcProgramType shaderStage, + DxbcBindingType bindingType, + uint32_t bindingIndex) { + if (shaderStage == DxbcProgramType::ComputeShader) { + // 0 - 13: Constant buffers + // 14 - 29: Samplers + // 30 - 157: Shader resources + // 158 - 221: Uniform access views + switch (bindingType) { + case DxbcBindingType::ConstantBuffer: return bindingIndex + 0; + case DxbcBindingType::ImageSampler: return bindingIndex + 14; + case DxbcBindingType::ShaderResource: return bindingIndex + 30; + case DxbcBindingType::UnorderedAccessView:return bindingIndex + 158; + default: Logger::err("computeResourceSlotId: Invalid resource type"); + } + } else { + // Global resource slots + // 0 - 7: Uniform access views + // 8 - 11: Stream output buffers + // Per-stage resource slots: + // 0 - 13: Constant buffers + // 14 - 29: Samplers + // 30 - 157: Shader resources + const uint32_t stageOffset = 12 + 158 * static_cast(shaderStage); + + switch (bindingType) { + case DxbcBindingType::UnorderedAccessView:return bindingIndex + 0; + case DxbcBindingType::StreamOutputBuffer: return bindingIndex + 8; + case DxbcBindingType::ConstantBuffer: return bindingIndex + stageOffset + 0; + case DxbcBindingType::ImageSampler: return bindingIndex + stageOffset + 14; + case DxbcBindingType::ShaderResource: return bindingIndex + stageOffset + 30; + default: Logger::err("computeResourceSlotId: Invalid resource type"); + } + } + + return 0; + } + +} \ No newline at end of file diff --git a/src/dxbc/dxbc_util.h b/src/dxbc/dxbc_util.h new file mode 100644 index 000000000..64f2c0554 --- /dev/null +++ b/src/dxbc/dxbc_util.h @@ -0,0 +1,35 @@ +#pragma once + +#include "dxbc_common.h" + +namespace dxvk { + + /** + * \brief Resource type + * + * The type of a shader resource. Used + * to determine the DXVK resource slot. + */ + enum DxbcBindingType : uint32_t { + ConstantBuffer = 0, + ShaderResource = 1, + ImageSampler = 2, + UnorderedAccessView = 3, + StreamOutputBuffer = 4, + }; + + + /** + * \brief Computes the DXVK resource slot for a binding + * + * \param [in] shaderStage The target shader stage + * \param [in] bindingType Type of the resource + * \param [in] bindingIndex Resource binding index + * \returns DXVK resource slot index + */ + uint32_t computeResourceSlotId( + DxbcProgramType shaderStage, + DxbcBindingType bindingType, + uint32_t bindingIndex); + +} \ No newline at end of file diff --git a/src/dxbc/gen/dxbc_gen_common.cpp b/src/dxbc/gen/dxbc_gen_common.cpp index b5150871c..c5d5e65ba 100644 --- a/src/dxbc/gen/dxbc_gen_common.cpp +++ b/src/dxbc/gen/dxbc_gen_common.cpp @@ -6,7 +6,8 @@ namespace dxvk { - DxbcCodeGen::DxbcCodeGen() { + DxbcCodeGen::DxbcCodeGen(DxbcProgramType shaderStage) + : m_shaderStage(shaderStage) { m_module.setMemoryModel( spv::AddressingModelLogical, spv::MemoryModelGLSL450); @@ -52,14 +53,20 @@ namespace dxvk { m_module.defPointerType(structType, spv::StorageClassUniform), spv::StorageClassUniform); + uint32_t bindingId = computeResourceSlotId(m_shaderStage, + DxbcBindingType::ConstantBuffer, bufferId); + m_module.setDebugName(varIndex, str::format("cb", bufferId).c_str()); m_module.decorateDescriptorSet(varIndex, 0); - m_module.decorateBinding(varIndex, 0); + m_module.decorateBinding(varIndex, bindingId); m_constantBuffers.at(bufferId).varId = varIndex; m_constantBuffers.at(bufferId).size = elementCount; // TODO compute resource slot index - m_resourceSlots.push_back({ 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER }); + DxvkResourceSlot resource; + resource.slot = bindingId; + resource.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + m_resourceSlots.push_back(resource); } diff --git a/src/dxbc/gen/dxbc_gen_common.h b/src/dxbc/gen/dxbc_gen_common.h index 4bf7c08ae..c222f1bb1 100644 --- a/src/dxbc/gen/dxbc_gen_common.h +++ b/src/dxbc/gen/dxbc_gen_common.h @@ -4,6 +4,7 @@ #include "../dxbc_common.h" #include "../dxbc_decoder.h" #include "../dxbc_type.h" +#include "../dxbc_util.h" #include "../../spirv/spirv_module.h" @@ -46,7 +47,7 @@ namespace dxvk { public: - DxbcCodeGen(); + DxbcCodeGen(DxbcProgramType shaderStage); virtual ~DxbcCodeGen(); @@ -149,6 +150,8 @@ namespace dxvk { constexpr static uint32_t PerVertex_CullDist = 2; constexpr static uint32_t PerVertex_ClipDist = 3; + const DxbcProgramType m_shaderStage; + SpirvModule m_module; std::vector m_entryPointInterfaces; diff --git a/src/dxbc/gen/dxbc_gen_pixel.cpp b/src/dxbc/gen/dxbc_gen_pixel.cpp index 86bcf3556..d8411ac07 100644 --- a/src/dxbc/gen/dxbc_gen_pixel.cpp +++ b/src/dxbc/gen/dxbc_gen_pixel.cpp @@ -2,8 +2,8 @@ namespace dxvk { - DxbcPsCodeGen::DxbcPsCodeGen( - const Rc& osgn) { + DxbcPsCodeGen::DxbcPsCodeGen(const Rc& osgn) + : DxbcCodeGen(DxbcProgramType::PixelShader) { m_module.enableCapability(spv::CapabilityShader); m_module.enableCapability(spv::CapabilityCullDistance); m_module.enableCapability(spv::CapabilityClipDistance); diff --git a/src/dxbc/gen/dxbc_gen_vertex.cpp b/src/dxbc/gen/dxbc_gen_vertex.cpp index 1c8dfdcb8..5d0fbcd8f 100644 --- a/src/dxbc/gen/dxbc_gen_vertex.cpp +++ b/src/dxbc/gen/dxbc_gen_vertex.cpp @@ -2,7 +2,8 @@ namespace dxvk { - DxbcVsCodeGen::DxbcVsCodeGen(const Rc& isgn) { + DxbcVsCodeGen::DxbcVsCodeGen(const Rc& isgn) + : DxbcCodeGen(DxbcProgramType::VertexShader) { m_module.enableCapability(spv::CapabilityShader); m_module.enableCapability(spv::CapabilityCullDistance); m_module.enableCapability(spv::CapabilityClipDistance); diff --git a/src/dxbc/meson.build b/src/dxbc/meson.build index f94cf64f2..3fb7dda84 100644 --- a/src/dxbc/meson.build +++ b/src/dxbc/meson.build @@ -9,6 +9,7 @@ dxbc_src = files([ 'dxbc_names.cpp', 'dxbc_reader.cpp', 'dxbc_type.cpp', + 'dxbc_util.cpp', 'gen/dxbc_gen_common.cpp', 'gen/dxbc_gen_pixel.cpp', diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h index 6831cc2e3..dce1c60e8 100644 --- a/src/dxvk/dxvk_context.h +++ b/src/dxvk/dxvk_context.h @@ -330,8 +330,8 @@ namespace dxvk { DxvkContextState m_state; DxvkBarrierSet m_barriers; - DxvkShaderResourceSlots m_cResources = { 1024 }; - DxvkShaderResourceSlots m_gResources = { 4096 }; + DxvkShaderResourceSlots m_cResources = { 256 }; + DxvkShaderResourceSlots m_gResources = { 1024 }; void renderPassBegin(); void renderPassEnd(); diff --git a/src/dxvk/dxvk_pipelayout.cpp b/src/dxvk/dxvk_pipelayout.cpp index 77c25160e..19efc17df 100644 --- a/src/dxvk/dxvk_pipelayout.cpp +++ b/src/dxvk/dxvk_pipelayout.cpp @@ -26,7 +26,7 @@ namespace dxvk { } - uint32_t DxvkDescriptorSlotMapping::getBindingId(uint32_t slot) { + uint32_t DxvkDescriptorSlotMapping::getBindingId(uint32_t slot) const { // This won't win a performance competition, but the number // of bindings used by a shader is usually much smaller than // the number of resource slots available to the system. diff --git a/src/dxvk/dxvk_pipelayout.h b/src/dxvk/dxvk_pipelayout.h index d12eae021..5419df58d 100644 --- a/src/dxvk/dxvk_pipelayout.h +++ b/src/dxvk/dxvk_pipelayout.h @@ -74,7 +74,7 @@ namespace dxvk { * \returns Binding index, or \c InvalidBinding */ uint32_t getBindingId( - uint32_t slot); + uint32_t slot) const; private: diff --git a/src/dxvk/dxvk_shader.cpp b/src/dxvk/dxvk_shader.cpp index 25ec379c2..2f90dbdaa 100644 --- a/src/dxvk/dxvk_shader.cpp +++ b/src/dxvk/dxvk_shader.cpp @@ -66,8 +66,21 @@ namespace dxvk { Rc DxvkShader::createShaderModule( const Rc& vkd, const DxvkDescriptorSlotMapping& mapping) const { - // TODO apply mapping - return new DxvkShaderModule(vkd, m_stage, m_code); + // Iterate over the code and replace every resource slot + // index with the corresponding mapped binding index. + SpirvCodeBuffer spirvCode = m_code; + + for (auto ins : spirvCode) { + if (ins.opCode() == spv::OpDecorate + && ins.arg(2) == spv::DecorationBinding) { + + const uint32_t oldBinding = ins.arg(3); + const uint32_t newBinding = mapping.getBindingId(oldBinding); + ins.setArg(3, newBinding); + } + } + + return new DxvkShaderModule(vkd, m_stage, spirvCode); } diff --git a/src/spirv/spirv_code_buffer.h b/src/spirv/spirv_code_buffer.h index 5bfc681bb..53234f676 100644 --- a/src/spirv/spirv_code_buffer.h +++ b/src/spirv/spirv_code_buffer.h @@ -48,7 +48,7 @@ namespace dxvk { * block. The header, if any, will be skipped over. * \returns Instruction iterator */ - SpirvInstructionIterator begin() const { + SpirvInstructionIterator begin() { return SpirvInstructionIterator(m_code.data(), m_code.size()); } @@ -58,7 +58,7 @@ namespace dxvk { * Points to the end of the instruction block. * \returns Instruction iterator */ - SpirvInstructionIterator end() const { + SpirvInstructionIterator end() { return SpirvInstructionIterator(nullptr, 0); } diff --git a/src/spirv/spirv_instruction.h b/src/spirv/spirv_instruction.h index b1e448de6..6ed9504cc 100644 --- a/src/spirv/spirv_instruction.h +++ b/src/spirv/spirv_instruction.h @@ -19,8 +19,7 @@ namespace dxvk { public: SpirvInstruction() { } - SpirvInstruction( - const uint32_t* code, uint32_t size) + SpirvInstruction(uint32_t* code, uint32_t size) : m_code(code), m_size(size) { } /** @@ -54,10 +53,21 @@ namespace dxvk { return id < m_size ? m_code[id] : 0; } + /** + * \brief Changes the value of an argument + * + * \param [in] id Argument index, starting at 1 + * \param [in] word New argument word + */ + void setArg(uint32_t id, uint32_t word) const { + if (id < m_size) + m_code[id] = word; + } + private: - uint32_t const* m_code = nullptr; - uint32_t m_size = 0; + uint32_t* m_code = nullptr; + uint32_t m_size = 0; }; @@ -73,7 +83,7 @@ namespace dxvk { public: SpirvInstructionIterator() { } - SpirvInstructionIterator(const uint32_t* code, uint32_t size) + SpirvInstructionIterator(uint32_t* code, uint32_t size) : m_code(size != 0 ? code : nullptr), m_size(size) { if ((size >= 5) && (m_code[0] == spv::MagicNumber)) this->advance(5); @@ -100,8 +110,8 @@ namespace dxvk { private: - uint32_t const* m_code = nullptr; - uint32_t m_size = 0; + uint32_t* m_code = nullptr; + uint32_t m_size = 0; void advance(uint32_t n) { if (n < m_size) {