From 7c03495d74642b501710b9dcd8ebd950fe558125 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Sun, 10 Dec 2017 10:34:18 +0100 Subject: [PATCH] [dxbc] Implemented shader resource declaration for images --- src/d3d11/d3d11_context.cpp | 2 +- src/dxbc/dxbc_compiler.cpp | 52 +++++++++++++++++- src/dxbc/dxbc_compiler.h | 3 ++ src/dxbc/gen/dxbc_gen_common.cpp | 93 ++++++++++++++++++++++++++++++++ src/dxbc/gen/dxbc_gen_common.h | 26 +++++++-- 5 files changed, 169 insertions(+), 7 deletions(-) diff --git a/src/d3d11/d3d11_context.cpp b/src/d3d11/d3d11_context.cpp index 3bbccd029..95248cdef 100644 --- a/src/d3d11/d3d11_context.cpp +++ b/src/d3d11/d3d11_context.cpp @@ -1438,7 +1438,7 @@ namespace dxvk { : VK_PIPELINE_BIND_POINT_GRAPHICS; const uint32_t slotId = computeResourceSlotId( - ShaderStage, DxbcBindingType::ImageSampler, + ShaderStage, DxbcBindingType::ShaderResource, StartSlot + i); if (resView != nullptr) { diff --git a/src/dxbc/dxbc_compiler.cpp b/src/dxbc/dxbc_compiler.cpp index 9cdf98aba..9e9161179 100644 --- a/src/dxbc/dxbc_compiler.cpp +++ b/src/dxbc/dxbc_compiler.cpp @@ -24,6 +24,9 @@ namespace dxvk { case DxbcOpcode::DclConstantBuffer: return this->dclConstantBuffer(ins); + case DxbcOpcode::DclResource: + return this->dclResource(ins); + case DxbcOpcode::DclSampler: return this->dclSampler(ins); @@ -39,7 +42,7 @@ namespace dxvk { return this->dclInterfaceVar(ins); case DxbcOpcode::DclTemps: - return this->dclTemps(ins); + return this->dclTemps(ins); case DxbcOpcode::Add: return this->opAdd(ins); @@ -81,6 +84,9 @@ namespace dxvk { void DxbcCompiler::dclConstantBuffer(const DxbcInstruction& ins) { + // dclConstantBuffer takes two operands: + // 1. The buffer register ID + // 2. The number of 4x32-bit constants auto op = ins.operand(0); if (op.token().indexDimension() != 2) @@ -93,7 +99,46 @@ namespace dxvk { } - void DxbcCompiler::dclSampler(const DxbcInstruction& ins) { + void DxbcCompiler::dclResource(const DxbcInstruction& ins) { + // dclResource takes two operands: + // 1. The resource register ID + // 2. The resource return type + auto op = ins.operand(0); + + if (op.token().indexDimension() != 1) + throw DxvkError("DXBC: dclResource: Invalid index dimension"); + + const uint32_t index = op.index(0).immPart(); + + // Defines the type of the resource (texture2D, ...) + auto resourceDim = static_cast( + bit::extract(ins.token().control(), 0, 4)); + + // Defines the type of a read operation. DXBC has the ability + // to define four different types whereas SPIR-V only allows + // one, but in practice this should not be much of a problem. + const uint32_t ofs = op.length(); + + auto xType = static_cast( + bit::extract(ins.arg(ofs), 0, 3)); + auto yType = static_cast( + bit::extract(ins.arg(ofs), 4, 7)); + auto zType = static_cast( + bit::extract(ins.arg(ofs), 8, 11)); + auto wType = static_cast( + bit::extract(ins.arg(ofs), 12, 15)); + + if ((xType != yType) || (xType != zType) || (xType != wType)) + Logger::warn("DXBC: dclResource: Ignoring resource return types"); + + m_gen->dclResource(index, resourceDim, xType); + } + + + void DxbcCompiler::dclSampler(const DxbcInstruction& ins) { + // dclSampler takes one operand: + // 1. The sampler register ID + // TODO implement sampler mode (default / comparison / mono) auto op = ins.operand(0); if (op.token().indexDimension() != 1) @@ -163,6 +208,9 @@ namespace dxvk { void DxbcCompiler::dclTemps(const DxbcInstruction& ins) { + // dclTemps takes one operand: + // 1. The number of temporary registers to + // declare, as an immediate 32-bit integer. m_gen->dclTemps(ins.arg(0)); } diff --git a/src/dxbc/dxbc_compiler.h b/src/dxbc/dxbc_compiler.h index 708393371..0612d1fa5 100644 --- a/src/dxbc/dxbc_compiler.h +++ b/src/dxbc/dxbc_compiler.h @@ -35,6 +35,9 @@ namespace dxvk { void dclConstantBuffer( const DxbcInstruction& ins); + void dclResource( + const DxbcInstruction& ins); + void dclSampler( const DxbcInstruction& ins); diff --git a/src/dxbc/gen/dxbc_gen_common.cpp b/src/dxbc/gen/dxbc_gen_common.cpp index 41ebe8e1a..acbbd3c1c 100644 --- a/src/dxbc/gen/dxbc_gen_common.cpp +++ b/src/dxbc/gen/dxbc_gen_common.cpp @@ -80,6 +80,99 @@ namespace dxvk { } + void DxbcCodeGen::dclResource( + uint32_t registerId, + DxbcResourceDim resourceType, + DxbcResourceReturnType returnType) { + uint32_t sampledTypeId = 0; + + switch (returnType) { + default: Logger::err(str::format("DXBC: Invalid sampled type: ", returnType)); + case DxbcResourceReturnType::Float: sampledTypeId = m_module.defFloatType(32); break; + case DxbcResourceReturnType::Sint: sampledTypeId = m_module.defIntType (32, 1); break; + case DxbcResourceReturnType::Uint: sampledTypeId = m_module.defIntType (32, 0); break; + } + + uint32_t resourceTypeId = 0; + + switch (resourceType) { + default: + Logger::err(str::format( + "DXBC: Invalid resource type: ", + resourceType)); + + case DxbcResourceDim::Texture1D: + resourceTypeId = m_module.defImageType( + sampledTypeId, spv::Dim1D, 2, 0, 0, 1, + spv::ImageFormatUnknown); + break; + + case DxbcResourceDim::Texture1DArr: + resourceTypeId = m_module.defImageType( + sampledTypeId, spv::Dim1D, 2, 1, 0, 1, + spv::ImageFormatUnknown); + break; + + case DxbcResourceDim::Texture2D: + resourceTypeId = m_module.defImageType( + sampledTypeId, spv::Dim2D, 2, 0, 0, 1, + spv::ImageFormatUnknown); + break; + + case DxbcResourceDim::Texture2DArr: + resourceTypeId = m_module.defImageType( + sampledTypeId, spv::Dim2D, 2, 1, 0, 1, + spv::ImageFormatUnknown); + break; + + case DxbcResourceDim::Texture3D: + resourceTypeId = m_module.defImageType( + sampledTypeId, spv::Dim3D, 2, 0, 0, 1, + spv::ImageFormatUnknown); + break; + + case DxbcResourceDim::TextureCube: + resourceTypeId = m_module.defImageType( + sampledTypeId, spv::DimCube, 2, 0, 0, 1, + spv::ImageFormatUnknown); + break; + + case DxbcResourceDim::TextureCubeArr: + resourceTypeId = m_module.defImageType( + sampledTypeId, spv::DimCube, 2, 1, 0, 1, + spv::ImageFormatUnknown); + break; + } + + uint32_t resourcePtrType = m_module.defPointerType( + resourceTypeId, spv::StorageClassUniformConstant); + + uint32_t varId = m_module.newVar(resourcePtrType, + spv::StorageClassUniformConstant); + + m_module.setDebugName(varId, + str::format("t", registerId).c_str()); + + m_resources.at(registerId).varId = varId; + m_resources.at(registerId).sampledTypeId = sampledTypeId; + m_resources.at(registerId).resourceTypeId = resourceTypeId; + + // Compute the DXVK binding slot index for the resource. + // D3D11 needs to bind the actual resource to this slot. + uint32_t bindingId = computeResourceSlotId(m_shaderStage, + DxbcBindingType::ShaderResource, registerId); + + m_module.decorateDescriptorSet(varId, 0); + m_module.decorateBinding(varId, bindingId); + + // Store descriptor info for the shader interface + DxvkResourceSlot resource; + resource.slot = bindingId; + resource.type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + m_resourceSlots.push_back(resource); + } + + void DxbcCodeGen::dclSampler(uint32_t samplerId) { // The sampler type is opaque, but we still have to // define a pointer and a variable in oder to use it diff --git a/src/dxbc/gen/dxbc_gen_common.h b/src/dxbc/gen/dxbc_gen_common.h index 3a7db3d46..ece6201f1 100644 --- a/src/dxbc/gen/dxbc_gen_common.h +++ b/src/dxbc/gen/dxbc_gen_common.h @@ -45,6 +45,18 @@ namespace dxvk { }; + /** + * \brief Shader resource binding + * + * Stores the sampler variable as well as + */ + struct DxbcShaderResource { + uint32_t varId = 0; + uint32_t sampledTypeId = 0; + uint32_t resourceTypeId = 0; + }; + + /** * \brief DXBC code generator * @@ -64,11 +76,16 @@ namespace dxvk { void dclTemps(uint32_t n); void dclConstantBuffer( - uint32_t bufferId, + uint32_t registerId, uint32_t elementCount); + void dclResource( + uint32_t registerId, + DxbcResourceDim resourceType, + DxbcResourceReturnType returnType); + void dclSampler( - uint32_t samplerId); + uint32_t registerId); DxbcValue defConstScalar(uint32_t v); @@ -172,8 +189,9 @@ namespace dxvk { std::vector m_rRegs; - std::array m_constantBuffers; - std::array m_samplers; + std::array m_constantBuffers; + std::array m_samplers; + std::array m_resources; std::vector m_resourceSlots;