[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.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(),

View File

@ -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

View File

@ -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 { };
}
}

View File

@ -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;
};