1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-01-31 05:52:11 +01:00

[dxbc] Instruction decoder work

This commit is contained in:
Philip Rebohle 2017-10-25 13:49:13 +02:00
parent 79e2236958
commit 294586eeb3
4 changed files with 248 additions and 161 deletions

View File

@ -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<uint32_t>(token.opcode())));
return false;
}
} }
@ -26,7 +41,11 @@ namespace dxvk {
codeBuffer.putHeader(m_counter.numIds()); codeBuffer.putHeader(m_counter.numIds());
codeBuffer.append(m_spvCapabilities.code()); codeBuffer.append(m_spvCapabilities.code());
codeBuffer.append(m_spvEntryPoints.code()); codeBuffer.append(m_spvEntryPoints.code());
codeBuffer.append(m_spvDebugInfo.code());
codeBuffer.append(m_spvDecorations.code());
codeBuffer.append(m_spvTypeInfo.code()); codeBuffer.append(m_spvTypeInfo.code());
codeBuffer.append(m_spvConstants.code());
codeBuffer.append(m_spvVariables.code());
codeBuffer.append(m_spvCode); codeBuffer.append(m_spvCode);
return new DxvkShader(m_version.shaderStage(), return new DxvkShader(m_version.shaderStage(),

View File

@ -33,7 +33,8 @@ namespace dxvk {
* \param [in] ins The instruction * \param [in] ins The instruction
* \returns \c true on success * \returns \c true on success
*/ */
bool processInstruction(DxbcInstruction ins); bool processInstruction(
const DxbcInstruction& ins);
/** /**
* \brief Creates actual shader object * \brief Creates actual shader object

View File

@ -2,36 +2,15 @@
namespace dxvk { namespace dxvk {
DxbcInstruction::DxbcInstruction( DxbcCodeReader& DxbcCodeReader::operator ++ () {
const uint32_t* code, return this->operator += (1);
uint32_t size)
: m_code(code), m_size(size) {
} }
uint32_t DxbcInstruction::getWord(uint32_t id) const { DxbcCodeReader& DxbcCodeReader::operator += (uint32_t n) {
return id < m_size ? m_code[id] : 0; if (n < m_size) {
} m_code += n;
m_size -= n;
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;
} else { } else {
m_code = nullptr; m_code = nullptr;
m_size = 0; m_size = 0;
@ -40,8 +19,106 @@ namespace dxvk {
} }
DxbcInstruction DxbcDecoder::operator * () const { DxbcCodeReader DxbcCodeReader::operator + (uint32_t n) const {
return DxbcInstruction(m_code, m_size); 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<DxbcOperandTokenExt> 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<DxbcOpcodeTokenExt> 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 { };
} }
} }

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <cstring> #include <cstring>
#include <optional>
#include "dxbc_enums.h" #include "dxbc_enums.h"
@ -281,37 +282,34 @@ namespace dxvk {
/** /**
* \brief DXBC instruction * \brief DXBC code DxbcCodeReader
* *
* Provides convenience methods to extract the * Helper class that can read DWORDs from a sized slice.
* opcode, instruction length, and instruction * Returns undefined numbers on out-of-bounds access, but
* arguments from an instruction. * makes sure not to access memory locations outside the
* original code array.
*/ */
class DxbcInstruction { class DxbcCodeReader {
public: public:
DxbcInstruction() { } DxbcCodeReader() { }
DxbcInstruction( DxbcCodeReader(
const uint32_t* code, const uint32_t* code,
uint32_t size); uint32_t size)
: m_code(size != 0 ? code : nullptr),
m_size(size) { }
/** uint32_t getWord(uint32_t id) const {
* \brief Retrieves instruction word return id < m_size ? m_code[id] : 0;
* }
* \param [in] Instruction word ID
* \returns The instruction word
*/
uint32_t getWord(uint32_t id) const;
/** DxbcCodeReader& operator ++ ();
* \brief Instruction length DxbcCodeReader& operator += (uint32_t n);
* DxbcCodeReader operator + (uint32_t n) const;
* Number of DWORDs for this instruction,
* including the initial opcode token. bool operator == (const DxbcCodeReader& other) const;
* \returns Instruction length bool operator != (const DxbcCodeReader& other) const;
*/
uint32_t length() const;
private: 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 Instruction decoder * \brief DXBC operand
* *
* Helper class that provides methods to read typed * Provides methods to query the operand token
* tokens and immediate values from the instruction * including extended operand tokens, which may
* stream. This will read instructions word by word. * modify the operand's return value.
*/ */
class DxbcInstructionDecoder { class DxbcOperand {
public: public:
DxbcInstructionDecoder() { } DxbcOperand() { }
DxbcInstructionDecoder( DxbcOperand(const DxbcCodeReader& code);
const DxbcInstruction& inst)
: m_inst(inst) { }
/** /**
* \brief Reads opcode token * \brief Operand token
* * \returns Operand token
* Must be the very first call.
* \returns The opcode token
*/ */
DxbcOpcodeToken readOpcode() { DxbcOperandToken token() const {
return DxbcOpcodeToken(m_inst.getWord(m_word++)); return DxbcOperandToken(m_info.getWord(0));
} }
/** /**
* \brief Reads extended opcode token * \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<DxbcOperandTokenExt> 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 DXBC instruction
*
* Provides methods to query the opcode token
* including extended opcode tokens, as well
* as convenience methods to read operands.
*/
class DxbcInstruction {
public:
DxbcInstruction() { }
DxbcInstruction(const DxbcCodeReader& code);
/**
* \brief Opcode token
* \returns Opcode token
*/
DxbcOpcodeToken token() const {
return DxbcOpcodeToken(m_op.getWord(0));
}
/**
* \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 * \returns Extended opcode token
*/ */
DxbcOpcodeTokenExt readOpcodeExt() { std::optional<DxbcOpcodeTokenExt> queryOpcodeExt(
return DxbcOpcodeTokenExt(m_inst.getWord(m_word++)); 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 * \brief Retrieves an operand
* \returns Next operand token *
* \param [in] idx Argument word index
* \returns The operand object
*/ */
DxbcOperandToken readOperand() { DxbcOperand getOperand(uint32_t idx) const {
return DxbcOperandToken(m_inst.getWord(m_word++)); return DxbcOperand(m_args + idx);
}
/**
* \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;
} }
private: private:
DxbcInstruction m_inst = { nullptr, 0u }; DxbcCodeReader m_op;
uint32_t m_word = 0; DxbcCodeReader m_args;
}; };
@ -465,19 +450,24 @@ namespace dxvk {
public: public:
DxbcDecoder() { } 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; }
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: private:
const uint32_t* m_code = nullptr; DxbcCodeReader m_code;
uint32_t m_size = 0;
}; };