diff --git a/src/dxbc/dxbc_compiler.cpp b/src/dxbc/dxbc_compiler.cpp index 805e1e59e..0d2830fff 100644 --- a/src/dxbc/dxbc_compiler.cpp +++ b/src/dxbc/dxbc_compiler.cpp @@ -16,8 +16,23 @@ namespace dxvk { } - bool DxbcCompiler::processInstruction(DxbcInstruction ins) { + bool DxbcCompiler::processInstruction(const DxbcInstruction& ins) { + const DxbcOpcodeToken token = ins.token(); + switch (token.opcode()) { + case DxbcOpcode::DclThreadGroup: { + m_spvEntryPoints.setLocalSize( + m_entryPointId, + ins.getArgWord(0), + ins.getArgWord(1), + ins.getArgWord(2)); + } return true; + + default: + Logger::err(str::format("DXBC: unhandled instruction: ", + static_cast(token.opcode()))); + return false; + } } @@ -26,7 +41,11 @@ namespace dxvk { codeBuffer.putHeader(m_counter.numIds()); codeBuffer.append(m_spvCapabilities.code()); codeBuffer.append(m_spvEntryPoints.code()); + codeBuffer.append(m_spvDebugInfo.code()); + codeBuffer.append(m_spvDecorations.code()); codeBuffer.append(m_spvTypeInfo.code()); + codeBuffer.append(m_spvConstants.code()); + codeBuffer.append(m_spvVariables.code()); codeBuffer.append(m_spvCode); return new DxvkShader(m_version.shaderStage(), diff --git a/src/dxbc/dxbc_compiler.h b/src/dxbc/dxbc_compiler.h index 70b5fba22..785665d97 100644 --- a/src/dxbc/dxbc_compiler.h +++ b/src/dxbc/dxbc_compiler.h @@ -33,7 +33,8 @@ namespace dxvk { * \param [in] ins The instruction * \returns \c true on success */ - bool processInstruction(DxbcInstruction ins); + bool processInstruction( + const DxbcInstruction& ins); /** * \brief Creates actual shader object diff --git a/src/dxbc/dxbc_decoder.cpp b/src/dxbc/dxbc_decoder.cpp index 0bc185d85..50fe221a3 100644 --- a/src/dxbc/dxbc_decoder.cpp +++ b/src/dxbc/dxbc_decoder.cpp @@ -2,36 +2,15 @@ namespace dxvk { - DxbcInstruction::DxbcInstruction( - const uint32_t* code, - uint32_t size) - : m_code(code), m_size(size) { - + DxbcCodeReader& DxbcCodeReader::operator ++ () { + return this->operator += (1); } - uint32_t DxbcInstruction::getWord(uint32_t id) const { - return id < m_size ? m_code[id] : 0; - } - - - uint32_t DxbcInstruction::length() const { - const DxbcOpcodeToken token(getWord(0)); - return token.opcode() != DxbcOpcode::CustomData - ? token.length() - : getWord(1); - } - - - DxbcDecoder::DxbcDecoder(const uint32_t* code, uint32_t size) - : m_code(size != 0 ? code : nullptr), m_size(size) { } - - - DxbcDecoder& DxbcDecoder::operator ++ () { - auto len = DxbcInstruction(m_code, m_size).length(); - if (len < m_size) { - m_code += len; - m_size -= len; + DxbcCodeReader& DxbcCodeReader::operator += (uint32_t n) { + if (n < m_size) { + m_code += n; + m_size -= n; } else { m_code = nullptr; m_size = 0; @@ -40,8 +19,106 @@ namespace dxvk { } - DxbcInstruction DxbcDecoder::operator * () const { - return DxbcInstruction(m_code, m_size); + DxbcCodeReader DxbcCodeReader::operator + (uint32_t n) const { + return n < m_size + ? DxbcCodeReader(m_code + n, m_size - n) + : DxbcCodeReader(); + } + + + bool DxbcCodeReader::operator == (const DxbcCodeReader& other) const { + return m_code == other.m_code && m_size == other.m_size; + } + + + bool DxbcCodeReader::operator != (const DxbcCodeReader& other) const { + return !this->operator == (other); + } + + + DxbcOperand::DxbcOperand(const DxbcCodeReader& code) + : m_info(code) { + DxbcOperandToken token(m_info.getWord(0)); + + uint32_t numOperandTokens = 1; + + if (token.isExtended()) { + while (DxbcOperandTokenExt(m_info.getWord(numOperandTokens++)).isExtended()) + continue; + } + + m_data = m_info + numOperandTokens; + } + + + std::optional DxbcOperand::queryOperandExt(DxbcOperandExt ext) const { + if (!this->token().isExtended()) + return { }; + + uint32_t extTokenId = 1; + DxbcOperandTokenExt extToken; + + do { + extToken = m_info.getWord(extTokenId++); + + if (extToken.type() == ext) + return extToken; + } while (extToken.isExtended()); + + return { }; + } + + + uint32_t DxbcOperand::length() const { + + } + + + DxbcInstruction::DxbcInstruction(const DxbcCodeReader& code) + : m_op(code) { + DxbcOpcodeToken token(m_op.getWord(0)); + + if (token.opcode() == DxbcOpcode::CustomData) { + // Custom data blocks have a special format, + // the length is stored in a separate DWORD + m_args = m_op + 2; + } else { + // For normal instructions, we just count + // the number of extended opcode tokens. + uint32_t numOpcodeTokens = 1; + + if (token.isExtended()) { + while (DxbcOpcodeTokenExt(m_op.getWord(numOpcodeTokens++)).isExtended()) + continue; + } + + m_args = m_op + numOpcodeTokens; + } + } + + + uint32_t DxbcInstruction::length() const { + auto token = this->token(); + return token.opcode() != DxbcOpcode::CustomData + ? token.length() : m_op.getWord(1); + } + + + std::optional DxbcInstruction::queryOpcodeExt(DxbcExtOpcode extOpcode) const { + if (!this->token().isExtended()) + return { }; + + uint32_t extTokenId = 1; + DxbcOpcodeTokenExt extToken; + + do { + extToken = m_op.getWord(extTokenId++); + + if (extToken.opcode() == extOpcode) + return extToken; + } while (extToken.isExtended()); + + return { }; } } \ No newline at end of file diff --git a/src/dxbc/dxbc_decoder.h b/src/dxbc/dxbc_decoder.h index ef6cb83d0..762019065 100644 --- a/src/dxbc/dxbc_decoder.h +++ b/src/dxbc/dxbc_decoder.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include "dxbc_enums.h" @@ -281,37 +282,34 @@ namespace dxvk { /** - * \brief DXBC instruction + * \brief DXBC code DxbcCodeReader * - * Provides convenience methods to extract the - * opcode, instruction length, and instruction - * arguments from an instruction. + * Helper class that can read DWORDs from a sized slice. + * Returns undefined numbers on out-of-bounds access, but + * makes sure not to access memory locations outside the + * original code array. */ - class DxbcInstruction { + class DxbcCodeReader { public: - DxbcInstruction() { } - DxbcInstruction( + DxbcCodeReader() { } + DxbcCodeReader( const uint32_t* code, - uint32_t size); + uint32_t size) + : m_code(size != 0 ? code : nullptr), + m_size(size) { } - /** - * \brief Retrieves instruction word - * - * \param [in] Instruction word ID - * \returns The instruction word - */ - uint32_t getWord(uint32_t id) const; + uint32_t getWord(uint32_t id) const { + return id < m_size ? m_code[id] : 0; + } - /** - * \brief Instruction length - * - * Number of DWORDs for this instruction, - * including the initial opcode token. - * \returns Instruction length - */ - uint32_t length() const; + DxbcCodeReader& operator ++ (); + DxbcCodeReader& operator += (uint32_t n); + DxbcCodeReader operator + (uint32_t n) const; + + bool operator == (const DxbcCodeReader& other) const; + bool operator != (const DxbcCodeReader& other) const; private: @@ -321,133 +319,120 @@ namespace dxvk { }; - struct DxbcInstructionSampleControls { - int32_t uoffset; - int32_t voffset; - int32_t woffset; - }; - - - struct DxbcInstructionResourceDim { - DxbcResourceDim dim; - }; - - - struct DxbcInstructionResourceRet { - DxbcResourceReturnType x; - DxbcResourceReturnType y; - DxbcResourceReturnType z; - DxbcResourceReturnType w; - }; - - - union DxbcInstructionModifierInfo { - DxbcInstructionSampleControls sampleControls; - DxbcInstructionResourceDim resourceDim; - DxbcInstructionResourceRet resourceRet; - }; - - - struct DxbcInstructionModifier { - DxbcExtOpcode code; - DxbcInstructionModifierInfo info; + /** + * \brief DXBC operand + * + * Provides methods to query the operand token + * including extended operand tokens, which may + * modify the operand's return value. + */ + class DxbcOperand { + + public: + + DxbcOperand() { } + DxbcOperand(const DxbcCodeReader& code); + + /** + * \brief Operand token + * \returns Operand token + */ + DxbcOperandToken token() const { + return DxbcOperandToken(m_info.getWord(0)); + } + + /** + * \brief Queries an operand extension + * + * If an extended operand token with the given + * operand extension exists, return that token. + * \param [in] ext The operand extension + * \returns The extended operand token + */ + std::optional queryOperandExt( + DxbcOperandExt ext) const; + + /** + * \brief Operand length, in DWORDs + * \returns Number of DWORDs + */ + uint32_t length() const; + + private: + + DxbcCodeReader m_info; + DxbcCodeReader m_data; + }; /** - * \brief Instruction decoder + * \brief DXBC instruction * - * Helper class that provides methods to read typed - * tokens and immediate values from the instruction - * stream. This will read instructions word by word. + * Provides methods to query the opcode token + * including extended opcode tokens, as well + * as convenience methods to read operands. */ - class DxbcInstructionDecoder { + class DxbcInstruction { public: - DxbcInstructionDecoder() { } - DxbcInstructionDecoder( - const DxbcInstruction& inst) - : m_inst(inst) { } + DxbcInstruction() { } + DxbcInstruction(const DxbcCodeReader& code); /** - * \brief Reads opcode token - * - * Must be the very first call. - * \returns The opcode token + * \brief Opcode token + * \returns Opcode token */ - DxbcOpcodeToken readOpcode() { - return DxbcOpcodeToken(m_inst.getWord(m_word++)); + DxbcOpcodeToken token() const { + return DxbcOpcodeToken(m_op.getWord(0)); } /** - * \brief Reads extended opcode token + * \brief Instruction length, in DWORDs + * \returns Instruction length, in DWORDs + */ + uint32_t length() const; + + /** + * \brief Queries an opcode extension + * + * If an extended opcode token with the given + * opcode exists, the token will be returned. + * \param extOpcode Extended opcode * \returns Extended opcode token */ - DxbcOpcodeTokenExt readOpcodeExt() { - return DxbcOpcodeTokenExt(m_inst.getWord(m_word++)); + std::optional queryOpcodeExt( + DxbcExtOpcode extOpcode) const; + + /** + * \brief Retrieves argument word + * + * Instruction arguments immediately follow the opcode + * tokens, including the extended opcodes. Argument 0 + * will therefore be the first DWORD that is part of + * an instruction operand or an immediate number. + * \param [in] idx Argument word index + * \returns The word at the given index + */ + uint32_t getArgWord(uint32_t idx) const { + return m_args.getWord(idx); } /** - * \brief Reads operand token - * \returns Next operand token + * \brief Retrieves an operand + * + * \param [in] idx Argument word index + * \returns The operand object */ - DxbcOperandToken readOperand() { - return DxbcOperandToken(m_inst.getWord(m_word++)); - } - - /** - * \brief Reads extended operand token - * \returns Extended operand token - */ - DxbcOperandTokenExt readOperandExt() { - return DxbcOperandTokenExt(m_inst.getWord(m_word++)); - } - - /** - * \brief Reads immediate 32-bit integer - * \returns The 32-bit integer constant - */ - uint32_t readu32() { - return m_inst.getWord(m_word++); - } - - /** - * \brief Reads immediate 64-bit integer - * \returns The 64-bit integer constant - */ - uint64_t readu64() { - uint64_t hi = readu32(); - uint64_t lo = readu32(); - return (hi << 32) | lo; - } - - /** - * \brief Reads immediate 32-bit float - * \returns The 32-bit float constant - */ - float readf32() { - float result; - uint32_t integer = readu32(); - std::memcpy(&result, &integer, sizeof(float)); - return result; - } - - /** - * \brief Reads immediate 64-bit float - * \returns The 64-bit float constant - */ - double readf64() { - double result; - uint64_t integer = readu64(); - std::memcpy(&result, &integer, sizeof(double)); - return result; + DxbcOperand getOperand(uint32_t idx) const { + return DxbcOperand(m_args + idx); } private: - DxbcInstruction m_inst = { nullptr, 0u }; - uint32_t m_word = 0; + DxbcCodeReader m_op; + DxbcCodeReader m_args; }; @@ -465,19 +450,24 @@ namespace dxvk { public: DxbcDecoder() { } - DxbcDecoder(const uint32_t* code, uint32_t size); + DxbcDecoder(const uint32_t* code, uint32_t size) + : m_code(code, size) { } - DxbcDecoder& operator ++ (); + DxbcDecoder& operator ++ () { + m_code += DxbcInstruction(m_code).length(); + return *this; + } - DxbcInstruction operator * () const; + DxbcInstruction operator * () const { + return DxbcInstruction(m_code); + } bool operator == (const DxbcDecoder& other) const { return m_code == other.m_code; } bool operator != (const DxbcDecoder& other) const { return m_code != other.m_code; } private: - const uint32_t* m_code = nullptr; - uint32_t m_size = 0; + DxbcCodeReader m_code; };