diff --git a/src/dxbc/dxbc_compiler.cpp b/src/dxbc/dxbc_compiler.cpp index 2d5b60df0..e2b97430b 100644 --- a/src/dxbc/dxbc_compiler.cpp +++ b/src/dxbc/dxbc_compiler.cpp @@ -25,12 +25,10 @@ namespace dxvk { case DxbcOpcode::DclInputPs: case DxbcOpcode::DclInputPsSiv: case DxbcOpcode::DclInputPsSgv: - return this->dclInput(ins); - case DxbcOpcode::DclOutput: case DxbcOpcode::DclOutputSiv: case DxbcOpcode::DclOutputSgv: - return this->dclOutput(ins); + return this->dclInterfaceVar(ins); case DxbcOpcode::DclTemps: return this->dclTemps(ins); @@ -53,12 +51,7 @@ namespace dxvk { } - void DxbcCompiler::dclInput(const DxbcInstruction& ins) { - - } - - - void DxbcCompiler::dclOutput(const DxbcInstruction& ins) { + void DxbcCompiler::dclInterfaceVar(const DxbcInstruction& ins) { } diff --git a/src/dxbc/dxbc_compiler.h b/src/dxbc/dxbc_compiler.h index a3533e4a3..cb67bcb73 100644 --- a/src/dxbc/dxbc_compiler.h +++ b/src/dxbc/dxbc_compiler.h @@ -30,10 +30,7 @@ namespace dxvk { void dclGlobalFlags( const DxbcInstruction& ins); - void dclInput( - const DxbcInstruction& ins); - - void dclOutput( + void dclInterfaceVar( const DxbcInstruction& ins); void dclTemps( diff --git a/src/dxbc/gen/dxbc_gen_common.cpp b/src/dxbc/gen/dxbc_gen_common.cpp index 9ddf9aae0..a88660cd2 100644 --- a/src/dxbc/gen/dxbc_gen_common.cpp +++ b/src/dxbc/gen/dxbc_gen_common.cpp @@ -41,6 +41,84 @@ namespace dxvk { } + DxbcPointer DxbcCodeGen::ptrTempReg(uint32_t regId) { + return m_rRegs.at(regId); + } + + + DxbcValue DxbcCodeGen::vecStore( + const DxbcValue& dst, + const DxbcValue& src, + DxbcComponentMask mask) { + DxbcValue result; + result.type = dst.type; + + if (dst.type.componentCount == 1) { + // Both values are scalar, so the first component + // of the write mask decides which one to take. + result.valueId = mask.test(0) + ? src.valueId : dst.valueId; + } else if (src.type.componentCount == 1) { + // The source value is scalar. Since OpVectorShuffle + // requires both arguments to be vectors, we have to + // use OpCompositeInsert to modify the vector instead. + const uint32_t componentId = mask.firstComponent(); + + result.valueId = m_module.opCompositeInsert( + this->defValueType(result.type), + src.valueId, dst.valueId, + 1, &componentId); + } else { + // Both arguments are vectors. We can determine which + // components to take from which vector and use the + // OpVectorShuffle instruction. + std::array components; + uint32_t srcComponentId = dst.type.componentCount; + + for (uint32_t i = 0; i < dst.type.componentCount; i++) + components[i] = mask.test(i) ? srcComponentId++ : i; + + result.valueId = m_module.opVectorShuffle( + this->defValueType(result.type), + dst.valueId, src.valueId, + dst.type.componentCount, + components.data()); + } + + return result; + } + + + DxbcValue DxbcCodeGen::regLoad(const DxbcPointer& ptr) { + DxbcValue result; + result.type = ptr.type.valueType; + result.valueId = m_module.opLoad( + this->defValueType(result.type), + ptr.valueId); + return result; + } + + + void DxbcCodeGen::regStore( + const DxbcPointer& ptr, + const DxbcValue& val, + DxbcComponentMask mask) { + if (ptr.type.valueType.componentCount != val.type.componentCount) { + // In case we write to only a part of the destination + // register, we need to load the previous value first + // and then update the given components. + DxbcValue tmp = this->regLoad(ptr); + tmp = this->vecStore(tmp, val, mask); + + m_module.opStore(ptr.valueId, tmp.valueId); + } else { + // All destination components get written, so we don't + // need to load and modify the target register first. + m_module.opStore(ptr.valueId, val.valueId); + } + } + + Rc DxbcCodeGen::create( const DxbcProgramVersion& version) { switch (version.type()) { diff --git a/src/dxbc/gen/dxbc_gen_common.h b/src/dxbc/gen/dxbc_gen_common.h index 807cf9eda..e7a099d4e 100644 --- a/src/dxbc/gen/dxbc_gen_common.h +++ b/src/dxbc/gen/dxbc_gen_common.h @@ -37,12 +37,6 @@ namespace dxvk { virtual ~DxbcCodeGen(); - /** - * \brief Declares temporary registers - * \param [in] n Number of temp registers - */ - void dclTemps(uint32_t n); - /** * \brief Declares an interface variable * @@ -59,6 +53,86 @@ namespace dxvk { DxbcComponentMask regMask, DxbcSystemValue sv) = 0; + /** + * \brief Declares temporary registers + * \param [in] n Number of temp registers + */ + void dclTemps(uint32_t n); + + /** + * \brief Retrieves temporary register pointer + * + * Provides access to a temporary register. + * \param [in] regId Register index + * \returns Register pointer + */ + DxbcPointer ptrTempReg( + uint32_t regId); + + /** + * \brief Writes to parts of a vector register + * + * Note that the source value must not have the + * same number of components as the write mask. + * \param [in] dst Destination value ID + * \param [in] src Source value ID + * \param [in] mask Write mask + * \returns New destination value ID + */ + DxbcValue vecStore( + const DxbcValue& dst, + const DxbcValue& src, + DxbcComponentMask mask); + + /** + * \brief Loads register + * + * \param [in] ptr Register pointer + * \returns The register value ID + */ + DxbcValue regLoad( + const DxbcPointer& ptr); + + /** + * \brief Stores register + * + * \param [in] ptr Register pointer + * \param [in] val Value ID to store + * \param [in] mask Write mask + */ + void regStore( + const DxbcPointer& ptr, + const DxbcValue& val, + DxbcComponentMask mask); + + /** + * \brief Pointer to an interface variable + * + * Provides access to an interface variable. + * \param [in] regType Register type + * \param [in] regId Register index + * \returns Register pointer + */ + virtual void ptrInterfaceVar( + DxbcOperandType regType, + uint32_t regId) = 0; + + /** + * \brief Pointer to an interface variable + * + * Provides access to an indexed interface variable. + * Some shader types may have indexed input or output + * variables that can be accesswed via an array index. + * \param [in] regType Register type + * \param [in] regId Register index + * \param [in] index Array index + * \returns Register pointer + */ + virtual void ptrInterfaceVarIndexed( + DxbcOperandType regType, + uint32_t regId, + const DxbcValue& index) = 0; + /** * \brief Finalizes shader * diff --git a/src/dxbc/gen/dxbc_gen_vertex.cpp b/src/dxbc/gen/dxbc_gen_vertex.cpp index 330f29bd4..e40731131 100644 --- a/src/dxbc/gen/dxbc_gen_vertex.cpp +++ b/src/dxbc/gen/dxbc_gen_vertex.cpp @@ -6,6 +6,7 @@ namespace dxvk { m_outPerVertex = m_module.newVar( m_module.defPointerType(this->defPerVertexBlock(), spv::StorageClassOutput), spv::StorageClassOutput); + m_module.setDebugName(m_outPerVertex, "vs_out"); } @@ -24,6 +25,23 @@ namespace dxvk { } + void DxbcVsCodeGen::ptrInterfaceVar( + DxbcOperandType regType, + uint32_t regId) { + + } + + + void DxbcVsCodeGen::ptrInterfaceVarIndexed( + DxbcOperandType regType, + uint32_t regId, + const DxbcValue& index) { + throw DxvkError(str::format( + "DxbcVsCodeGen::ptrInterfaceVarIndexed:\n", + "Vertex shaders do not support indexed interface variables")); + } + + Rc DxbcVsCodeGen::finalize() { m_module.addEntryPoint(m_entryPointId, spv::ExecutionModelVertex, "main", diff --git a/src/dxbc/gen/dxbc_gen_vertex.h b/src/dxbc/gen/dxbc_gen_vertex.h index e798ac21a..2422be05b 100644 --- a/src/dxbc/gen/dxbc_gen_vertex.h +++ b/src/dxbc/gen/dxbc_gen_vertex.h @@ -21,6 +21,15 @@ namespace dxvk { DxbcComponentMask regMask, DxbcSystemValue sv); + void ptrInterfaceVar( + DxbcOperandType regType, + uint32_t regId); + + void ptrInterfaceVarIndexed( + DxbcOperandType regType, + uint32_t regId, + const DxbcValue& index); + Rc finalize() final; private: diff --git a/src/spirv/spirv_module.cpp b/src/spirv/spirv_module.cpp index 3150b5e8b..6a18fe1dd 100644 --- a/src/spirv/spirv_module.cpp +++ b/src/spirv/spirv_module.cpp @@ -444,6 +444,26 @@ namespace dxvk { } + uint32_t SpirvModule::opCompositeInsert( + uint32_t resultType, + uint32_t object, + uint32_t composite, + uint32_t indexCount, + const uint32_t* indexArray) { + uint32_t resultId = this->allocateId(); + + m_code.putIns (spv::OpCompositeInsert, 5 + indexCount); + m_code.putWord(resultType); + m_code.putWord(resultId); + m_code.putWord(object); + m_code.putWord(composite); + + for (uint32_t i = 0; i < indexCount; i++) + m_code.putInt32(indexArray[i]); + return resultId; + } + + uint32_t SpirvModule::opVectorShuffle( uint32_t resultType, uint32_t vectorLeft, diff --git a/src/spirv/spirv_module.h b/src/spirv/spirv_module.h index 97c39c181..2284395e7 100644 --- a/src/spirv/spirv_module.h +++ b/src/spirv/spirv_module.h @@ -165,6 +165,13 @@ namespace dxvk { uint32_t indexCount, const uint32_t* indexArray); + uint32_t opCompositeInsert( + uint32_t resultType, + uint32_t object, + uint32_t composite, + uint32_t indexCount, + const uint32_t* indexArray); + uint32_t opVectorShuffle( uint32_t resultType, uint32_t vectorLeft,