mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-01-18 11:52:12 +01:00
[dxbc] Instruction decoder work
This commit is contained in:
parent
79e2236958
commit
294586eeb3
@ -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.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(),
|
||||
|
@ -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
|
||||
|
@ -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<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 { };
|
||||
}
|
||||
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstring>
|
||||
#include <optional>
|
||||
|
||||
#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<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 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<DxbcOpcodeTokenExt> 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;
|
||||
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user