[dxbc] Shader decoder and compiler overhaul (2/2)

Removed the old decoder and the old shader compiler
and added documentation to the new structures.
This commit is contained in:
Philip Rebohle 2017-12-18 00:46:44 +01:00
parent 47347e38da
commit 858913ec0c
12 changed files with 1653 additions and 4607 deletions

View File

@ -2,7 +2,6 @@
#include "dxbc_common.h"
#include "dxbc_decoder.h"
#include "dxbc_decoder_2.h"
#include "dxbc_reader.h"
namespace dxvk {
@ -30,14 +29,6 @@ namespace dxvk {
m_code.data() + m_code.size());
}
DxbcDecoder begin() const {
return DxbcDecoder(m_code.data(), m_code.size());
}
DxbcDecoder end() const {
return DxbcDecoder();
}
private:
DxbcProgramVersion m_version;

File diff suppressed because it is too large Load Diff

View File

@ -1,133 +1,84 @@
#pragma once
#include <array>
#include <vector>
#include "../spirv/spirv_module.h"
#include "dxbc_chunk_isgn.h"
#include "dxbc_decoder.h"
#include "dxbc_defs.h"
#include "dxbc_names.h"
#include "dxbc_util.h"
namespace dxvk {
/**
* \brief Expression value
* \brief Vector type
*
* Tracks the type and the SPIR-V variable
* ID when evaluating DXBC instructions.
* Convenience struct that stores a scalar
* type and a component count. The compiler
* can use this to generate SPIR-V types.
*/
struct DxbcValue {
DxbcScalarType componentType = DxbcScalarType::Float32;
uint32_t componentCount = 0;
uint32_t valueId = 0;
struct DxbcVectorType {
DxbcScalarType ctype;
uint32_t ccount;
};
/**
* \brief Variable pointer
* \brief Register info
*
* Stores the SPIR-V pointer ID and the
* type of the referenced variable. Used
* to access variables and resources.
* Stores the vector type of a register and
* its storage class. The compiler can use
* this to generate SPIR-V pointer types.
*/
struct DxbcPointer {
DxbcScalarType componentType = DxbcScalarType::Float32;
uint32_t componentCount = 0;
uint32_t pointerId = 0;
struct DxbcRegisterInfo {
DxbcVectorType type;
spv::StorageClass sclass;
};
/**
* \brief Compiler error code
* \brief Register value
*
* Helps identify the type of error
* that may occur during compilation.
* Stores a vector type and a SPIR-V ID that
* represents an intermediate value. This is
* used to track the type of such values.
*/
enum class DxbcError {
sOk,
eInternal,
eInstructionFormat,
eInvalidOperand,
eInvalidOperandIndex,
eTypeMismatch,
eUnhandledOpcode,
eUnsupported,
struct DxbcRegisterValue {
DxbcVectorType type;
uint32_t id;
};
/**
* \brief Operand index type
* \brief Register pointer
*
* Defines whether a register index
* is relative or constant.
* Stores a vector type and a SPIR-V ID that
* represents a pointer to such a vector. This
* can be used to load registers conveniently.
*/
enum class DxbcIndexType {
Immediate, ///< Index is a constant value
Relative, ///< Index depends on a r# register
struct DxbcRegisterPointer {
DxbcVectorType type;
uint32_t id;
};
/**
* \brief Instruction operand index
*
* Stores the type of the index as well as the
* register (if relative) and the constant offset.
* \brief Vertex shader-specific structure
*/
struct DxbcInstOpIndex {
DxbcIndexType type = DxbcIndexType::Immediate;
uint32_t immediate = 0;
uint32_t tempRegId = 0;
uint32_t tempRegComponent = 0;
};
/**
* \brief Instruction operand
*
* Stores all information about a single
* operand, including the register index.
*/
struct DxbcInstOp {
DxbcOperandType type = DxbcOperandType::Temp;
DxbcOperandModifiers modifiers = 0;
uint32_t immediates[4] = { 0u, 0u, 0u, 0u };
uint32_t indexDim = 0;
DxbcInstOpIndex index[3];
uint32_t componentCount = 0;
DxbcRegMode componentMode = DxbcRegMode::Mask;
DxbcRegMask mask = { false, false, false, false };
DxbcRegSwizzle swizzle = { 0, 0, 0, 0 };
uint32_t select1 = 0;
struct DxbcCompilerVsPart {
uint32_t functionId;
};
/**
* \brief Decoded instruction
*
* Stores all information about a single
* instruction, including its operands.
* \brief Pixel shader-specific structure
*/
struct DxbcInst {
DxbcOpcode opcode = DxbcOpcode::Nop;
DxbcOpcodeControl control = 0;
DxbcInstFormat format;
DxbcInstOp operands[DxbcMaxOperandCount];
};
/**
* \brief Vertex shader-specific data
*/
struct DxbcVsSpecifics {
uint32_t functionId = 0;
};
/**
* \brief Pixel shader-specific data
*/
struct DxbcPsSpecifics {
uint32_t functionId = 0;
std::array<DxbcPointer, DxbcMaxInterfaceRegs> oregs;
struct DxbcCompilerPsPart {
uint32_t functionId;
std::array<DxbcVectorType, DxbcMaxInterfaceRegs> oTypes;
};
@ -150,12 +101,10 @@ namespace dxvk {
/**
* \brief Processes a single instruction
*
* \param [in] ins The instruction
* \returns An error code, or \c sOK
*/
DxbcError processInstruction(
const DxbcInstruction& ins);
void processInstruction(
const DxbcShaderInstruction& ins);
/**
* \brief Finalizes the shader
@ -184,12 +133,14 @@ namespace dxvk {
// v# registers as defined by the shader. The type of each
// of these inputs is either float4 or an array of float4.
std::array<uint32_t, DxbcMaxInterfaceRegs> m_vRegs;
std::vector<DxbcSvMapping> m_vMappings;
//////////////////////////////////////////////////////////
// o# registers as defined by the shader. In the fragment
// shader stage, these registers are typed by the signature,
// in all other stages, they are float4 registers or arrays.
std::array<uint32_t, DxbcMaxInterfaceRegs> m_oRegs;
std::vector<DxbcSvMapping> m_oMappings;
//////////////////////////////////////////////////////
// Shader resource variables. These provide access to
@ -198,12 +149,6 @@ namespace dxvk {
std::array<DxbcSampler, 16> m_samplers;
std::array<DxbcShaderResource, 128> m_textures;
////////////////////////////////////////////////////////
// Input/Output system value mappings. These will need
// to be set up before or after the main function runs.
std::vector<DxbcSvMapping> m_vSvs;
std::vector<DxbcSvMapping> m_oSvs;
///////////////////////////////////////////////////////////
// Array of input values. Since v# registers are indexable
// in DXBC, we need to copy them into an array first.
@ -221,190 +166,185 @@ namespace dxvk {
std::vector<uint32_t> m_entryPointInterfaces;
uint32_t m_entryPointId = 0;
////////////////////////////////////////
// Data structures for each shader type
DxbcVsSpecifics m_vs;
DxbcPsSpecifics m_ps;
///////////////////////////////////
// Shader-specific data structures
DxbcCompilerVsPart m_vs;
DxbcCompilerPsPart m_ps;
/////////////////////////////////////////////////////
// Shader interface and metadata declaration methods
void emitDclGlobalFlags(
const DxbcShaderInstruction& ins);
void emitDclTemps(
const DxbcShaderInstruction& ins);
void emitDclInterfaceReg(
const DxbcShaderInstruction& ins);
void emitDclInput(
uint32_t regIdx,
uint32_t regDim,
DxbcRegMask regMask,
DxbcSystemValue sv,
DxbcInterpolationMode im);
void emitDclOutput(
uint32_t regIdx,
uint32_t regDim,
DxbcRegMask regMask,
DxbcSystemValue sv,
DxbcInterpolationMode im);
void emitDclConstantBuffer(
const DxbcShaderInstruction& ins);
void emitDclSampler(
const DxbcShaderInstruction& ins);
void emitDclResource(
const DxbcShaderInstruction& ins);
//////////////////////////////
// Instruction class handlers
DxbcError handleDeclaration(
const DxbcInst& ins);
void emitVectorAlu(
const DxbcShaderInstruction& ins);
DxbcError handleControlFlow(
const DxbcInst& ins);
void emitVectorCmov(
const DxbcShaderInstruction& ins);
DxbcError handleTextureSample(
const DxbcInst& ins);
void emitVectorCmp(
const DxbcShaderInstruction& ins);
DxbcError handleVectorAlu(
const DxbcInst& ins);
void emitVectorDot(
const DxbcShaderInstruction& ins);
DxbcError handleVectorCmov(
const DxbcInst& ins);
void emitVectorImul(
const DxbcShaderInstruction& ins);
DxbcError handleVectorCmp(
const DxbcInst& ins);
void emitVectorSinCos(
const DxbcShaderInstruction& ins);
DxbcError handleVectorDot(
const DxbcInst& ins);
void emitSample(
const DxbcShaderInstruction& ins);
DxbcError handleVectorSinCos(
const DxbcInst& ins);
void emitRet(
const DxbcShaderInstruction& ins);
///////////////////////
// Declaration methods
DxbcError declareGlobalFlags(
const DxbcInst& ins);
DxbcError declareTemps(
const DxbcInst& ins);
/////////////////////////////////////////
// Generic register manipulation methods
DxbcRegisterValue emitRegisterBitcast(
DxbcRegisterValue srcValue,
DxbcScalarType dstType);
DxbcError declareInterfaceVar(
const DxbcInst& ins);
DxbcRegisterValue emitRegisterSwizzle(
DxbcRegisterValue value,
DxbcRegSwizzle swizzle,
DxbcRegMask writeMask);
DxbcError declareConstantBuffer(
const DxbcInst& ins);
DxbcRegisterValue emitRegisterExtract(
DxbcRegisterValue value,
DxbcRegMask mask);
DxbcError declareSampler(
const DxbcInst& ins);
DxbcRegisterValue emitRegisterInsert(
DxbcRegisterValue dstValue,
DxbcRegisterValue srcValue,
DxbcRegMask srcMask);
DxbcError declareResource(
const DxbcInst& ins);
DxbcRegisterValue emitRegisterExtend(
DxbcRegisterValue value,
uint32_t size);
DxbcError declareInputVar(
uint32_t regId,
uint32_t regDim,
DxbcRegMask regMask,
DxbcSystemValue sv,
DxbcInterpolationMode im);
DxbcRegisterValue emitRegisterAbsolute(
DxbcRegisterValue value);
DxbcError declareOutputVar(
uint32_t regId,
uint32_t regDim,
DxbcRegMask regMask,
DxbcSystemValue sv,
DxbcInterpolationMode im);
DxbcRegisterValue emitRegisterNegate(
DxbcRegisterValue value);
////////////////////////////////////
// Register manipulation operations
DxbcValue bitcastReg(
const DxbcValue& src,
DxbcScalarType type);
DxbcRegisterValue emitSrcOperandModifiers(
DxbcRegisterValue value,
DxbcRegModifiers modifiers);
DxbcValue insertReg(
const DxbcValue& dst,
const DxbcValue& src,
DxbcRegMask mask);
DxbcRegisterValue emitDstOperandModifiers(
DxbcRegisterValue value,
DxbcOpModifiers modifiers);
DxbcValue extractReg(
const DxbcValue& src,
DxbcRegMask mask);
////////////////////////
// Address load methods
DxbcRegisterPointer emitGetTempPtr(
const DxbcRegister& operand);
DxbcValue swizzleReg(
const DxbcValue& src,
const DxbcRegSwizzle& swizzle,
DxbcRegMask mask);
DxbcRegisterPointer emitGetInputPtr(
const DxbcRegister& operand);
DxbcValue regVector(
const DxbcValue& src,
uint32_t size);
DxbcRegisterPointer emitGetOutputPtr(
const DxbcRegister& operand);
DxbcValue extendReg(
const DxbcValue& src,
uint32_t size);
DxbcRegisterPointer emitGetConstBufPtr(
const DxbcRegister& operand);
////////////////////////////
// Operand modifier methods
DxbcValue applyOperandModifiers(
DxbcValue value,
DxbcOperandModifiers modifiers);
DxbcRegisterPointer emitGetOperandPtr(
const DxbcRegister& operand);
DxbcValue applyResultModifiers(
DxbcValue value,
DxbcOpcodeControl control);
//////////////////////////////
// Operand load/store methods
DxbcRegisterValue emitIndexLoad(
DxbcRegIndex index);
/////////////////////////
// Load/Store operations
DxbcValue loadOp(
const DxbcInstOp& srcOp,
DxbcRegMask srcMask,
DxbcScalarType dstType);
DxbcRegisterValue emitValueLoad(
DxbcRegisterPointer ptr);
DxbcValue loadImm32(
const DxbcInstOp& srcOp,
DxbcRegMask srcMask,
DxbcScalarType dstType);
void emitValueStore(
DxbcRegisterPointer ptr,
DxbcRegisterValue value,
DxbcRegMask writeMask);
DxbcValue loadRegister(
const DxbcInstOp& srcOp,
DxbcRegMask srcMask,
DxbcScalarType dstType);
DxbcRegisterValue emitRegisterLoad(
const DxbcRegister& reg,
DxbcRegMask writeMask);
void storeOp(
const DxbcInstOp& dstOp,
const DxbcValue& srcValue);
DxbcValue loadPtr(
const DxbcPointer& ptr);
void storePtr(
const DxbcPointer& ptr,
const DxbcValue& value,
DxbcRegMask mask);
DxbcValue loadIndex(
const DxbcInstOpIndex& idx);
///////////////////////////
// Operand pointer methods
DxbcPointer getOperandPtr(
const DxbcInstOp& op);
DxbcPointer getConstantBufferPtr(
const DxbcInstOp& op);
/////////////////////////////////
// Shader initialization methods
void beginVertexShader(const Rc<DxbcIsgn>& isgn);
void beginPixelShader (const Rc<DxbcIsgn>& osgn);
void emitRegisterStore(
const DxbcRegister& reg,
DxbcRegisterValue value);
/////////////////////////////
// Input preparation methods
void prepareVertexInputs();
void preparePixelInputs();
void emitVsInputSetup();
void emitPsInputSetup();
//////////////////////////////
// Output preparation methods
void prepareVertexOutputs();
void preparePixelOutputs();
void emitVsOutputSetup();
void emitPsOutputSetup();
/////////////////////////////////
// Shader initialization methods
void emitVsInit();
void emitPsInit();
///////////////////////////////
// Shader finalization methods
void endVertexShader();
void endPixelShader();
void emitVsFinalize();
void emitPsFinalize();
///////////////////////////////
// Variable definition methods
uint32_t emitNewVariable(
const DxbcRegisterInfo& info);
///////////////////////////
// Type definition methods
uint32_t definePerVertexBlock();
uint32_t getScalarTypeId(
DxbcScalarType type);
uint32_t defineScalarType(
DxbcScalarType componentType);
uint32_t getVectorTypeId(
const DxbcVectorType& type);
uint32_t defineVectorType(
DxbcScalarType componentType,
uint32_t componentCount);
uint32_t getPointerTypeId(
const DxbcRegisterInfo& type);
uint32_t definePointerType(
DxbcScalarType componentType,
uint32_t componentCount,
spv::StorageClass storageClass);
/////////////////////////
// DXBC decoding methods
DxbcError parseInstruction(
const DxbcInstruction& ins,
DxbcInst& out);
uint32_t getPerVertexBlockId();
};

File diff suppressed because it is too large Load Diff

View File

@ -1,311 +0,0 @@
#pragma once
#include <array>
#include <vector>
#include "../spirv/spirv_module.h"
#include "dxbc_chunk_isgn.h"
#include "dxbc_decoder_2.h"
#include "dxbc_defs.h"
#include "dxbc_names.h"
#include "dxbc_util.h"
namespace dxvk {
struct DxbcVectorType {
DxbcScalarType ctype;
uint32_t ccount;
};
struct DxbcRegisterInfo {
DxbcVectorType type;
spv::StorageClass sclass;
};
struct DxbcRegisterValue {
DxbcVectorType type;
uint32_t id;
};
struct DxbcRegisterPointer {
DxbcVectorType type;
uint32_t id;
};
struct DxbcCompilerVsPart {
uint32_t functionId;
};
struct DxbcCompilerPsPart {
uint32_t functionId;
std::array<DxbcVectorType, DxbcMaxInterfaceRegs> oTypes;
};
/**
* \brief DXBC to SPIR-V shader compiler
*
* Processes instructions from a DXBC shader and creates
* a DXVK shader object, which contains the SPIR-V module
* and information about the shader resource bindings.
*/
class DxbcCompiler2 {
public:
DxbcCompiler2(
const DxbcProgramVersion& version,
const Rc<DxbcIsgn>& isgn,
const Rc<DxbcIsgn>& osgn);
~DxbcCompiler2();
/**
* \brief Processes a single instruction
* \param [in] ins The instruction
*/
void processInstruction(
const DxbcShaderInstruction& ins);
/**
* \brief Finalizes the shader
* \returns The final shader object
*/
Rc<DxvkShader> finalize();
private:
DxbcProgramVersion m_version;
SpirvModule m_module;
Rc<DxbcIsgn> m_isgn;
Rc<DxbcIsgn> m_osgn;
///////////////////////////////////////////////////////
// Resource slot description for the shader. This will
// be used to map D3D11 bindings to DXVK bindings.
std::vector<DxvkResourceSlot> m_resourceSlots;
///////////////////////////////
// r# registers of type float4
std::vector<uint32_t> m_rRegs;
///////////////////////////////////////////////////////////
// v# registers as defined by the shader. The type of each
// of these inputs is either float4 or an array of float4.
std::array<uint32_t, DxbcMaxInterfaceRegs> m_vRegs;
std::vector<DxbcSvMapping> m_vMappings;
//////////////////////////////////////////////////////////
// o# registers as defined by the shader. In the fragment
// shader stage, these registers are typed by the signature,
// in all other stages, they are float4 registers or arrays.
std::array<uint32_t, DxbcMaxInterfaceRegs> m_oRegs;
std::vector<DxbcSvMapping> m_oMappings;
//////////////////////////////////////////////////////
// Shader resource variables. These provide access to
// constant buffers, samplers, textures, and UAVs.
std::array<DxbcConstantBuffer, 16> m_constantBuffers;
std::array<DxbcSampler, 16> m_samplers;
std::array<DxbcShaderResource, 128> m_textures;
///////////////////////////////////////////////////////////
// Array of input values. Since v# registers are indexable
// in DXBC, we need to copy them into an array first.
uint32_t m_vArray = 0;
////////////////////////////////////////////////////
// Per-vertex input and output blocks. Depending on
// the shader stage, these may be declared as arrays.
uint32_t m_perVertexIn = 0;
uint32_t m_perVertexOut = 0;
///////////////////////////////////////////////////
// Entry point description - we'll need to declare
// the function ID and all input/output variables.
std::vector<uint32_t> m_entryPointInterfaces;
uint32_t m_entryPointId = 0;
///////////////////////////////////
// Shader-specific data structures
DxbcCompilerVsPart m_vs;
DxbcCompilerPsPart m_ps;
/////////////////////////////////////////////////////
// Shader interface and metadata declaration methods
void emitDclGlobalFlags(
const DxbcShaderInstruction& ins);
void emitDclTemps(
const DxbcShaderInstruction& ins);
void emitDclInterfaceReg(
const DxbcShaderInstruction& ins);
void emitDclInput(
uint32_t regIdx,
uint32_t regDim,
DxbcRegMask regMask,
DxbcSystemValue sv,
DxbcInterpolationMode im);
void emitDclOutput(
uint32_t regIdx,
uint32_t regDim,
DxbcRegMask regMask,
DxbcSystemValue sv,
DxbcInterpolationMode im);
void emitDclConstantBuffer(
const DxbcShaderInstruction& ins);
void emitDclSampler(
const DxbcShaderInstruction& ins);
void emitDclResource(
const DxbcShaderInstruction& ins);
//////////////////////////////
// Instruction class handlers
void emitVectorAlu(
const DxbcShaderInstruction& ins);
void emitVectorCmov(
const DxbcShaderInstruction& ins);
void emitVectorCmp(
const DxbcShaderInstruction& ins);
void emitVectorDot(
const DxbcShaderInstruction& ins);
void emitVectorImul(
const DxbcShaderInstruction& ins);
void emitVectorSinCos(
const DxbcShaderInstruction& ins);
void emitSample(
const DxbcShaderInstruction& ins);
void emitRet(
const DxbcShaderInstruction& ins);
/////////////////////////////////////////
// Generic register manipulation methods
DxbcRegisterValue emitRegisterBitcast(
DxbcRegisterValue srcValue,
DxbcScalarType dstType);
DxbcRegisterValue emitRegisterSwizzle(
DxbcRegisterValue value,
DxbcRegSwizzle swizzle,
DxbcRegMask writeMask);
DxbcRegisterValue emitRegisterExtract(
DxbcRegisterValue value,
DxbcRegMask mask);
DxbcRegisterValue emitRegisterInsert(
DxbcRegisterValue dstValue,
DxbcRegisterValue srcValue,
DxbcRegMask srcMask);
DxbcRegisterValue emitRegisterExtend(
DxbcRegisterValue value,
uint32_t size);
DxbcRegisterValue emitRegisterAbsolute(
DxbcRegisterValue value);
DxbcRegisterValue emitRegisterNegate(
DxbcRegisterValue value);
DxbcRegisterValue emitSrcOperandModifiers(
DxbcRegisterValue value,
DxbcRegModifiers modifiers);
DxbcRegisterValue emitDstOperandModifiers(
DxbcRegisterValue value,
DxbcOpModifiers modifiers);
////////////////////////
// Address load methods
DxbcRegisterPointer emitGetTempPtr(
const DxbcRegister& operand);
DxbcRegisterPointer emitGetInputPtr(
const DxbcRegister& operand);
DxbcRegisterPointer emitGetOutputPtr(
const DxbcRegister& operand);
DxbcRegisterPointer emitGetConstBufPtr(
const DxbcRegister& operand);
DxbcRegisterPointer emitGetOperandPtr(
const DxbcRegister& operand);
//////////////////////////////
// Operand load/store methods
DxbcRegisterValue emitIndexLoad(
DxbcRegIndex index);
DxbcRegisterValue emitValueLoad(
DxbcRegisterPointer ptr);
void emitValueStore(
DxbcRegisterPointer ptr,
DxbcRegisterValue value,
DxbcRegMask writeMask);
DxbcRegisterValue emitRegisterLoad(
const DxbcRegister& reg,
DxbcRegMask writeMask);
void emitRegisterStore(
const DxbcRegister& reg,
DxbcRegisterValue value);
/////////////////////////////
// Input preparation methods
void emitVsInputSetup();
void emitPsInputSetup();
//////////////////////////////
// Output preparation methods
void emitVsOutputSetup();
void emitPsOutputSetup();
/////////////////////////////////
// Shader initialization methods
void emitVsInit();
void emitPsInit();
///////////////////////////////
// Shader finalization methods
void emitVsFinalize();
void emitPsFinalize();
///////////////////////////////
// Variable definition methods
uint32_t emitNewVariable(
const DxbcRegisterInfo& info);
///////////////////////////
// Type definition methods
uint32_t getScalarTypeId(
DxbcScalarType type);
uint32_t getVectorTypeId(
const DxbcVectorType& type);
uint32_t getPointerTypeId(
const DxbcRegisterInfo& type);
uint32_t getPerVertexBlockId();
};
}

View File

@ -2,208 +2,332 @@
namespace dxvk {
DxbcCodeReader& DxbcCodeReader::operator ++ () {
return this->operator += (1);
uint32_t DxbcCodeSlice::at(uint32_t id) const {
if (m_ptr + id >= m_end)
throw DxvkError("DxbcCodeSlice: End of stream");
return m_ptr[id];
}
DxbcCodeReader& DxbcCodeReader::operator += (uint32_t n) {
if (n < m_size) {
m_code += n;
m_size -= n;
} else {
m_code = nullptr;
m_size = 0;
}
return *this;
uint32_t DxbcCodeSlice::read() {
if (m_ptr >= m_end)
throw DxvkError("DxbcCodeSlice: End of stream");
return *(m_ptr++);
}
DxbcCodeReader DxbcCodeReader::operator + (uint32_t n) const {
return n < m_size
? DxbcCodeReader(m_code + n, m_size - n)
: DxbcCodeReader();
DxbcCodeSlice DxbcCodeSlice::take(uint32_t n) const {
if (m_ptr + n > m_end)
throw DxvkError("DxbcCodeSlice: End of stream");
return DxbcCodeSlice(m_ptr, m_ptr + n);
}
bool DxbcCodeReader::operator == (const DxbcCodeReader& other) const {
return m_code == other.m_code && m_size == other.m_size;
DxbcCodeSlice DxbcCodeSlice::skip(uint32_t n) const {
if (m_ptr + n > m_end)
throw DxvkError("DxbcCodeSlice: End of stream");
return DxbcCodeSlice(m_ptr + n, m_end);
}
bool DxbcCodeReader::operator != (const DxbcCodeReader& other) const {
return !this->operator == (other);
}
uint32_t DxbcOperandIndex::length() const {
switch (m_rep) {
case DxbcOperandIndexRepresentation::Imm32: return 1;
case DxbcOperandIndexRepresentation::Imm64: return 2;
case DxbcOperandIndexRepresentation::Relative: return this->relPart().length();
case DxbcOperandIndexRepresentation::Imm32Relative: return this->relPart().length() + 1;
case DxbcOperandIndexRepresentation::Imm64Relative: return this->relPart().length() + 2;
}
void DxbcDecodeContext::decodeInstruction(DxbcCodeSlice& code) {
const uint32_t token0 = code.at(0);
throw DxvkError(str::format("DXBC: Unknown index representation: ", m_rep));
}
bool DxbcOperandIndex::hasImmPart() const {
return m_rep == DxbcOperandIndexRepresentation::Imm32
|| m_rep == DxbcOperandIndexRepresentation::Imm64
|| m_rep == DxbcOperandIndexRepresentation::Imm32Relative
|| m_rep == DxbcOperandIndexRepresentation::Imm64Relative;
}
bool DxbcOperandIndex::hasRelPart() const {
return m_rep == DxbcOperandIndexRepresentation::Relative
|| m_rep == DxbcOperandIndexRepresentation::Imm32Relative
|| m_rep == DxbcOperandIndexRepresentation::Imm64Relative;
}
uint64_t DxbcOperandIndex::immPart() const {
switch (m_rep) {
case DxbcOperandIndexRepresentation::Imm32:
case DxbcOperandIndexRepresentation::Imm32Relative:
return m_code.getWord(0);
case DxbcOperandIndexRepresentation::Imm64:
case DxbcOperandIndexRepresentation::Imm64Relative:
return (static_cast<uint64_t>(m_code.getWord(0)) << 32)
| (static_cast<uint64_t>(m_code.getWord(1)));
default:
return 0;
}
}
DxbcOperand DxbcOperandIndex::relPart() const {
switch (m_rep) {
case DxbcOperandIndexRepresentation::Relative:
return DxbcOperand(m_code);
case DxbcOperandIndexRepresentation::Imm32Relative:
return DxbcOperand(m_code + 1);
case DxbcOperandIndexRepresentation::Imm64Relative:
return DxbcOperand(m_code + 2);
default:
throw DxvkError("DXBC: Operand index is not relative");
}
}
DxbcOperand::DxbcOperand(const DxbcCodeReader& code)
: m_info(code) {
const DxbcOperandToken token(m_info.getWord(0));
// Initialize the instruction structure. Some of these values
// may not get written otherwise while decoding the instruction.
m_instruction.op = static_cast<DxbcOpcode>(bit::extract(token0, 0, 10));
m_instruction.sampleControls = { 0, 0, 0 };
m_instruction.dstCount = 0;
m_instruction.srcCount = 0;
m_instruction.immCount = 0;
m_instruction.dst = m_dstOperands.data();
m_instruction.src = m_srcOperands.data();
m_instruction.imm = m_immOperands.data();
uint32_t numTokens = 1;
// Reset the index pointer, which may still contain
// a non-zero value from the previous iteration
m_indexId = 0;
// Count extended operand tokens
if (token.isExtended()) {
while (DxbcOperandTokenExt(m_info.getWord(numTokens++)).isExtended())
continue;
}
m_data = m_info + numTokens;
// Immediate operands
// Instruction length, in DWORDs. This includes the token
// itself and any other prefix that an instruction may have.
uint32_t length = 0;
if (token.type() == DxbcOperandType::Imm32
|| token.type() == DxbcOperandType::Imm64)
length += token.numComponents();
// Indices into the register file, may contain additional operands
for (uint32_t i = 0; i < token.indexDimension(); i++) {
m_indexOffsets[i] = length;
length += this->index(i).length();
}
m_length = length + numTokens;
}
DxbcOperandIndex DxbcOperand::index(uint32_t dim) const {
return DxbcOperandIndex(
m_data + m_indexOffsets.at(dim),
this->token().indexRepresentation(dim));
}
bool DxbcOperand::queryOperandExt(DxbcOperandExt ext, DxbcOperandTokenExt& token) const {
if (!this->token().isExtended())
return false;
uint32_t extTokenId = 1;
DxbcOperandTokenExt extToken;
do {
extToken = m_info.getWord(extTokenId++);
if (extToken.type() == ext) {
token = extToken;
return true;
}
} while (extToken.isExtended());
return false;
}
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;
if (m_instruction.op == DxbcOpcode::CustomData) {
length = code.at(1);
this->decodeCustomData(code.take(length));
} else {
// For normal instructions, we just count
// the number of extended opcode tokens.
uint32_t numOpcodeTokens = 1;
length = bit::extract(token0, 24, 30);
this->decodeOperation(code.take(length));
}
// Advance the caller's slice to the next token so that
// they can make consecutive calls to decodeInstruction()
code = code.skip(length);
}
void DxbcDecodeContext::decodeCustomData(DxbcCodeSlice code) {
Logger::warn("DxbcDecodeContext::decodeCustomData: Not implemented");
}
void DxbcDecodeContext::decodeOperation(DxbcCodeSlice code) {
uint32_t token = code.read();
// Result modifiers, which are applied to common ALU ops
m_instruction.modifiers.saturate = !!bit::extract(token, 13, 13);
m_instruction.modifiers.precise = !!bit::extract(token, 19, 22);
// Opcode controls. It will depend on the opcode itself which ones are valid.
m_instruction.controls.zeroTest = static_cast<DxbcZeroTest> (bit::extract(token, 18, 18));
m_instruction.controls.syncFlags = static_cast<DxbcSyncFlags> (bit::extract(token, 11, 14));
m_instruction.controls.resourceDim = static_cast<DxbcResourceDim> (bit::extract(token, 11, 15));
m_instruction.controls.resinfoType = static_cast<DxbcResinfoType> (bit::extract(token, 11, 12));
m_instruction.controls.interpolation = static_cast<DxbcInterpolationMode>(bit::extract(token, 11, 14));
// Process extended opcode tokens
while (bit::extract(token, 31, 31)) {
token = code.read();
if (token.isExtended()) {
numOpcodeTokens += 1;
while (DxbcOpcodeTokenExt(m_op.getWord(numOpcodeTokens)).isExtended())
numOpcodeTokens += 1;
const DxbcExtOpcode extOpcode
= static_cast<DxbcExtOpcode>(bit::extract(token, 0, 5));
switch (extOpcode) {
case DxbcExtOpcode::SampleControls: {
struct {
int u : 4;
int v : 4;
int w : 4;
} aoffimmi;
aoffimmi.u = bit::extract(token, 9, 12);
aoffimmi.v = bit::extract(token, 13, 16);
aoffimmi.w = bit::extract(token, 17, 20);
// Four-bit signed numbers, sign-extend them
m_instruction.sampleControls.u = aoffimmi.u;
m_instruction.sampleControls.v = aoffimmi.v;
m_instruction.sampleControls.w = aoffimmi.w;
} break;
default:
Logger::warn(str::format(
"DxbcDecodeContext: Unhandled extended opcode: ",
extOpcode));
}
}
// Retrieve the instruction format in order to parse the
// operands. Doing this mostly automatically means that
// the compiler can rely on the operands being valid.
const DxbcInstFormat format = dxbcInstructionFormat(m_instruction.op);
for (uint32_t i = 0; i < format.operandCount; i++)
this->decodeOperand(code, format.operands[i]);
}
void DxbcDecodeContext::decodeComponentSelection(DxbcRegister& reg, uint32_t token) {
// Pick the correct component selection mode based on the
// component count. We'll simplify this here so that the
// compiler can assume that everything is a 4D vector.
reg.componentCount = static_cast<DxbcComponentCount>(bit::extract(token, 0, 1));
switch (reg.componentCount) {
// No components - used for samplers etc.
case DxbcComponentCount::Component0:
reg.mask = DxbcRegMask(false, false, false, false);
reg.swizzle = DxbcRegSwizzle(0, 0, 0, 0);
break;
m_args = m_op + numOpcodeTokens;
// One component - used for immediates
// and a few built-in registers.
case DxbcComponentCount::Component1:
reg.mask = DxbcRegMask(true, false, false, false);
reg.swizzle = DxbcRegSwizzle(0, 0, 0, 0);
break;
// Four components - everything else. This requires us
// to actually parse the component selection mode.
case DxbcComponentCount::Component4: {
const DxbcRegMode componentMode =
static_cast<DxbcRegMode>(bit::extract(token, 2, 3));
switch (componentMode) {
// Write mask for destination operands
case DxbcRegMode::Mask:
reg.mask = bit::extract(token, 4, 7);
reg.swizzle = DxbcRegSwizzle(0, 1, 2, 3);
break;
// Swizzle for source operands (including resources)
case DxbcRegMode::Swizzle:
reg.mask = DxbcRegMask(true, true, true, true);
reg.swizzle = DxbcRegSwizzle(
bit::extract(token, 4, 5),
bit::extract(token, 6, 7),
bit::extract(token, 8, 9),
bit::extract(token, 10, 11));
break;
// Selection of one component. We can generate both a
// mask and a swizzle for this so that the compiler
// won't have to deal with this case specifically.
case DxbcRegMode::Select1: {
const uint32_t n = bit::extract(token, 4, 5);
reg.mask = DxbcRegMask(n == 0, n == 1, n == 2, n == 3);
reg.swizzle = DxbcRegSwizzle(n, n, n, n);
} break;
default:
Logger::warn("DxbcDecodeContext: Invalid component selection mode");
}
} break;
default:
Logger::warn("DxbcDecodeContext: Invalid component count");
}
}
uint32_t DxbcInstruction::length() const {
auto token = this->token();
return token.opcode() != DxbcOpcode::CustomData
? token.length() : m_op.getWord(1);
void DxbcDecodeContext::decodeOperandExtensions(DxbcCodeSlice& code, DxbcRegister& reg, uint32_t token) {
while (bit::extract(token, 31, 31)) {
token = code.read();
// Type of the extended operand token
const DxbcOperandExt extTokenType =
static_cast<DxbcOperandExt>(bit::extract(token, 0, 5));
switch (extTokenType) {
// Operand modifiers, which are used to manipulate the
// value of a source operand during the load operation
case DxbcOperandExt::OperandModifier:
reg.modifiers = bit::extract(token, 6, 13);
break;
default:
Logger::warn(str::format(
"DxbcDecodeContext: Unhandled extended operand token: ",
extTokenType));
}
}
}
bool DxbcInstruction::queryOpcodeExt(DxbcExtOpcode extOpcode, DxbcOpcodeTokenExt& token) const {
if (!this->token().isExtended())
return false;
uint32_t extTokenId = 1;
DxbcOpcodeTokenExt extToken;
do {
extToken = m_op.getWord(extTokenId++);
if (extToken.opcode() == extOpcode) {
token = extToken;
return true;
void DxbcDecodeContext::decodeOperandImmediates(DxbcCodeSlice& code, DxbcRegister& reg) {
if (reg.type == DxbcOperandType::Imm32) {
switch (reg.componentCount) {
// This is commonly used if only one vector
// component is involved in an operation
case DxbcComponentCount::Component1: {
reg.imm.u32_1 = code.read();
} break;
// Typical four-component vector
case DxbcComponentCount::Component4: {
reg.imm.u32_4[0] = code.read();
reg.imm.u32_4[1] = code.read();
reg.imm.u32_4[2] = code.read();
reg.imm.u32_4[3] = code.read();
} break;
default:
Logger::warn("DxbcDecodeContext: Invalid component count for immediate operand");
}
} while (extToken.isExtended());
} else if (reg.type == DxbcOperandType::Imm64) {
Logger::warn("DxbcDecodeContext: 64-bit immediates not supported");
}
}
void DxbcDecodeContext::decodeOperandIndex(DxbcCodeSlice& code, DxbcRegister& reg, uint32_t token) {
reg.idxDim = bit::extract(token, 20, 21);
return false;
for (uint32_t i = 0; i < reg.idxDim; i++) {
// An index can be encoded in various different ways
const DxbcOperandIndexRepresentation repr =
static_cast<DxbcOperandIndexRepresentation>(
bit::extract(token, 22 + 3 * i, 24 + 3 * i));
switch (repr) {
case DxbcOperandIndexRepresentation::Imm32:
reg.idx[i].offset = static_cast<int32_t>(code.read());
reg.idx[i].relReg = nullptr;
break;
case DxbcOperandIndexRepresentation::Relative:
reg.idx[i].offset = 0;
reg.idx[i].relReg = &m_indices.at(m_indexId);
this->decodeRegister(code,
m_indices.at(m_indexId++),
DxbcScalarType::Sint32);
break;
case DxbcOperandIndexRepresentation::Imm32Relative:
reg.idx[i].offset = static_cast<int32_t>(code.read());
reg.idx[i].relReg = &m_indices.at(m_indexId);
this->decodeRegister(code,
m_indices.at(m_indexId++),
DxbcScalarType::Sint32);
break;
default:
Logger::warn(str::format(
"DxbcDecodeContext: Unhandled index representation: ",
repr));
}
}
}
void DxbcDecodeContext::decodeRegister(DxbcCodeSlice& code, DxbcRegister& reg, DxbcScalarType type) {
const uint32_t token = code.read();
reg.type = static_cast<DxbcOperandType>(bit::extract(token, 12, 19));
reg.dataType = type;
reg.modifiers = 0;
reg.idxDim = 0;
for (uint32_t i = 0; i < DxbcMaxRegIndexDim; i++) {
reg.idx[i].relReg = nullptr;
reg.idx[i].offset = 0;
}
this->decodeComponentSelection(reg, token);
this->decodeOperandExtensions(code, reg, token);
this->decodeOperandImmediates(code, reg);
this->decodeOperandIndex(code, reg, token);
}
void DxbcDecodeContext::decodeImm32(DxbcCodeSlice& code, DxbcImmediate& imm, DxbcScalarType type) {
imm.u32 = code.read();
}
void DxbcDecodeContext::decodeOperand(DxbcCodeSlice& code, const DxbcInstOperandFormat& format) {
switch (format.kind) {
case DxbcOperandKind::DstReg: {
const uint32_t operandId = m_instruction.dstCount++;
this->decodeRegister(code, m_dstOperands.at(operandId), format.type);
} break;
case DxbcOperandKind::SrcReg: {
const uint32_t operandId = m_instruction.srcCount++;
this->decodeRegister(code, m_srcOperands.at(operandId), format.type);
} break;
case DxbcOperandKind::Imm32: {
const uint32_t operandId = m_instruction.immCount++;
this->decodeImm32(code, m_immOperands.at(operandId), format.type);
} break;
default:
throw DxvkError("DxbcDecodeContext: Invalid operand format");
}
}
}

View File

@ -1,13 +1,32 @@
#pragma once
#include <cstring>
#include <array>
#include "dxbc_common.h"
#include "dxbc_decoder.h"
#include "dxbc_defs.h"
#include "dxbc_enums.h"
#include "dxbc_names.h"
namespace dxvk {
class DxbcOperand;
constexpr size_t DxbcMaxRegIndexDim = 3;
struct DxbcRegister;
/**
* \brief Source operand modifiers
*
* These are applied after loading
* an operand register.
*/
enum class DxbcRegModifier : uint32_t {
Neg = 0,
Abs = 1,
};
using DxbcRegModifiers = Flags<DxbcRegModifier>;
/**
* \brief Constant buffer binding
@ -121,671 +140,193 @@ namespace dxvk {
};
struct DxbcRegIndex {
DxbcRegister* relReg;
int32_t offset;
};
/**
* \brief Basic control info
* \brief Instruction operand
*
*
* Parses instruction-specific control bits. Whether
* these are well defined depends on the instruction.
*/
class DxbcOpcodeControl {
struct DxbcRegister {
DxbcOperandType type;
DxbcScalarType dataType;
DxbcComponentCount componentCount;
uint32_t idxDim;
DxbcRegIndex idx[DxbcMaxRegIndexDim];
DxbcRegMask mask;
DxbcRegSwizzle swizzle;
DxbcRegModifiers modifiers;
union {
uint32_t u32_4[4];
uint32_t u32_1;
} imm;
};
/**
* \brief Instruction result modifiers
*
* Modifiers that are applied
* to all destination operands.
*/
struct DxbcOpModifiers {
bool saturate;
bool precise;
};
/**
* \brief Opcode controls
*
* Instruction-specific controls. Usually,
* only one of the members will be valid.
*/
struct DxbcShaderOpcodeControls {
DxbcZeroTest zeroTest;
DxbcSyncFlags syncFlags;
DxbcResourceDim resourceDim;
DxbcResinfoType resinfoType;
DxbcInterpolationMode interpolation;
};
/**
* \brief Sample controls
*
* Constant texel offset with
* values raning from -8 to 7.
*/
struct DxbcShaderSampleControls {
int u, v, w;
};
/**
* \brief Immediate value
*
* Immediate argument represented either
* as a 32-bit or 64-bit unsigned integer.
*/
union DxbcImmediate {
uint32_t u32;
uint64_t u64;
};
/**
* \brief Shader instruction
*/
struct DxbcShaderInstruction {
DxbcOpcode op;
DxbcOpModifiers modifiers;
DxbcShaderOpcodeControls controls;
DxbcShaderSampleControls sampleControls;
uint32_t dstCount;
uint32_t srcCount;
uint32_t immCount;
const DxbcRegister* dst;
const DxbcRegister* src;
const DxbcImmediate* imm;
};
/**
* \brief DXBC code slice
*
* Convenient pointer pair that allows
* reading the code word stream safely.
*/
class DxbcCodeSlice {
public:
DxbcOpcodeControl() { }
DxbcOpcodeControl(uint32_t control)
: m_control(control) { }
DxbcCodeSlice(
const uint32_t* ptr,
const uint32_t* end)
: m_ptr(ptr), m_end(end) { }
/**
* \brief Saturation hint
*
* If set, the result of the given instruction
* is clamped to the [0..1] range.
*/
bool saturateBit() const {
return bit::extract(m_control, 2, 2) != 0;
}
uint32_t at(uint32_t id) const;
uint32_t read();
/**
* \brief Precision hint
*/
bool preciseBit() const {
return bit::extract(m_control, 8, 11) != 0;
}
DxbcCodeSlice take(uint32_t n) const;
DxbcCodeSlice skip(uint32_t n) const;
/**
* \brief Zero test
*
* For conditional instructions, this defines
* whether the test shall pass when the given
* operand is zero or non-zero.
*/
DxbcZeroTest zeroTest() const {
return static_cast<DxbcZeroTest>(
bit::extract(m_control, 7, 7));
}
/**
* \brief Resinfo return type
*
* Control bits specifically for
* the \c resinfo instruction.
*/
DxbcResinfoType resinfoType() const {
return static_cast<DxbcResinfoType>(
bit::extract(m_control, 0, 1));
}
/**
* \brief Sync flags
*
* Defines the exact operation of sync
* instructions in compute shaders.
*/
DxbcSyncFlags syncFlags() const {
return bit::extract(m_control, 0, 3);
}
/**
* \brief Resource dimension
*
* Defines the type of a resource.
* Only valid for dcl_resource etc.
*/
DxbcResourceDim resourceDim() const {
return static_cast<DxbcResourceDim>(
bit::extract(m_control, 0, 4));
bool atEnd() const {
return m_ptr == m_end;
}
private:
uint32_t m_control = 0;
const uint32_t* m_ptr = nullptr;
const uint32_t* m_end = nullptr;
};
/**
* \brief DXBC instruction token
* \brief Decode context
*
* Initial token at the beginning of each instruction.
* This encodes the actual op code, the length of the
* entire instruction in DWORDs, as well as some flags
* controlling the specific instruction.
* Stores data that is required to decode a single
* instruction. This data is not persistent, so it
* should be forwarded to the compiler right away.
*/
class DxbcOpcodeToken {
class DxbcDecodeContext {
public:
DxbcOpcodeToken() { }
DxbcOpcodeToken(uint32_t token)
: m_token(token) { }
/**
* \brief Opcode
* \returns Opcode
*/
DxbcOpcode opcode() const {
return static_cast<DxbcOpcode>(
bit::extract(m_token, 0, 10));
}
/**
* \brief Control info
* \brief Retrieves current instruction
*
* Instruction-specific control info. Undefined
* if the opcode is \c DxbcOpcode::CustomData.
* \returns Control info
* This is only valid after a call to \ref decode.
* \returns Reference to last decoded instruction
*/
uint32_t control() const {
return bit::extract(m_token, 11, 23);
const DxbcShaderInstruction& getInstruction() const {
return m_instruction;
}
/**
* \brief Instruction length
* \brief Decodes an instruction
*
* Undefind if the opcode is \c DxbcOpcode::CustomData.
* In that case, the instruction length will be stored
* in the DWORD immediately following the opcode token.
* \returns Instruction length, in DWORDs
* This also advances the given code slice by the
* number of dwords consumed by the instruction.
* \param [in] code Code slice
*/
uint32_t length() const {
return bit::extract(m_token, 24, 30);
}
/**
* \brief Checks whether the opcode is extended
*
* Additional information is encoded in extended
* opcode tokens if this flag is set. Note that
* multiple extended opcode tokens may be chained.
* \returns \c true if the opcode is extended.
*/
bool isExtended() const {
return !!bit::extract(m_token, 31, 31);
}
void decodeInstruction(DxbcCodeSlice& code);
private:
uint32_t m_token = 0;
DxbcShaderInstruction m_instruction;
};
/**
* \brief DXBC extended instruction token
*
* Some instruction may encode additional control
* modifiers in extended opcode tokens. The format
* of these tokens differs from that of the the
* initial opcode tokens.
*/
class DxbcOpcodeTokenExt {
std::array<DxbcRegister, 4> m_dstOperands;
std::array<DxbcRegister, 4> m_srcOperands;
std::array<DxbcImmediate, 4> m_immOperands;
std::array<DxbcRegister, 12> m_indices;
public:
// Index into the indices array. Used when decoding
// instruction operands with relative indexing.
uint32_t m_indexId = 0;
DxbcOpcodeTokenExt() { }
DxbcOpcodeTokenExt(uint32_t token)
: m_token(token) { }
void decodeCustomData(DxbcCodeSlice code);
void decodeOperation(DxbcCodeSlice code);
/**
* \brief Extended opcode
* \returns Extended opcode
*/
DxbcExtOpcode opcode() const {
return static_cast<DxbcExtOpcode>(
bit::extract(m_token, 0, 5));
}
void decodeComponentSelection(DxbcRegister& reg, uint32_t token);
void decodeOperandExtensions(DxbcCodeSlice& code, DxbcRegister& reg, uint32_t token);
void decodeOperandImmediates(DxbcCodeSlice& code, DxbcRegister& reg);
void decodeOperandIndex(DxbcCodeSlice& code, DxbcRegister& reg, uint32_t token);
/**
* \brief Control info
*
* Instruction-specific control info. Undefined
* if the opcode is \c DxbcOpcode::CustomData.
* \returns Control info
*/
uint32_t control() const {
return bit::extract(m_token, 6, 30);
}
void decodeRegister(DxbcCodeSlice& code, DxbcRegister& reg, DxbcScalarType type);
void decodeImm32(DxbcCodeSlice& code, DxbcImmediate& imm, DxbcScalarType type);
/**
* \brief Extended opcode length
*
* Number of DWORDs that belong to this extended
* opcode information. Currently, there are no
* extended opcodes with a length greater than 1.
* \returns Exteded opcode length, in DWORDs
*/
uint32_t length() const {
return 1;
}
/**
* \brief Checks whether there are additional modifiers
* \returns \c true if the extended opcode is extended
*/
bool isExtended() const {
return !!bit::extract(m_token, 31, 31);
}
private:
uint32_t m_token = 0;
};
/**
* \brief Operand token
*
* Stores general information about one operand of an
* instruction. Like opcode tokens, operand tokens may
* be extended.
*/
class DxbcOperandToken {
public:
DxbcOperandToken(uint32_t token)
: m_token(token) { }
/**
* \brief Number of operand components
*
* The number of components that the operand
* has. Can be zero, one, or four.
* \returns Number of components
*/
uint32_t numComponents() const {
std::array<uint32_t, 4> count = { 0, 1, 4, 0 };
return count.at(bit::extract(m_token, 0, 1));
}
/**
* \brief Component selection mode
*
* Operands can be either masked so that some components
* will not be used, or they can be swizzled so that only
* a given set of components is used.
* \returns Component selection mode
*/
DxbcRegMode selectionMode() const {
return static_cast<DxbcRegMode>(
bit::extract(m_token, 2, 3));
}
/**
* \brief Component mask
*
* Used when the component selection
* mode is \c DxbcRegMode::Mask.
* \returns The component mask
*/
DxbcRegMask mask() const {
return DxbcRegMask(bit::extract(m_token, 4, 7));
}
/**
* \brief Component swizzle
*
* Used when the component selection
* mode is \c DxbcRegMode::Swizzle.
* \returns The component swizzle
*/
DxbcRegSwizzle swizzle() const {
return DxbcRegSwizzle(
bit::extract(m_token, 4, 5),
bit::extract(m_token, 6, 7),
bit::extract(m_token, 8, 9),
bit::extract(m_token, 10, 11));
}
/**
* \brief Single component selection
*
* Used when the component selection
* mode is \c DxbcRegMode::Select1.
* \returns The component index
*/
uint32_t select1() const {
return bit::extract(m_token, 4, 5);
}
/**
* \brief Operand type
*
* Selects the type of the operand, i.e. whether the
* operand is a temporary register, a shader resource
* or a builtin interface variable.
* \returns Operand type
*/
DxbcOperandType type() const {
return static_cast<DxbcOperandType>(
bit::extract(m_token, 12, 19));
}
/**
* \brief Index dimension
*
* Number of indices. In DXBC, each register file has
* a dimensionality, e.g. the temporary registers are
* one-dimensional and therefore require one index.
* \returns Number of index dimensions
*/
uint32_t indexDimension() const {
return bit::extract(m_token, 20, 21);
}
/**
* \brief Index representation
*
* Stores whether an index is stored as an
* immediate value or as a relative value
* which requires another operand token.
* \param [in] dim Index dimension to query
* \returns Representation of that index
*/
DxbcOperandIndexRepresentation indexRepresentation(uint32_t dim) const {
return static_cast<DxbcOperandIndexRepresentation>(
bit::extract(m_token, 22 + 3 * dim, 24 + 3 * dim));
}
/**
* \brief Checks whether the operand is extended
*
* Operands can be modified with extended tokens.
* \returns \c true if the operand is extended
*/
bool isExtended() const {
return !!bit::extract(m_token, 31, 31);
}
private:
uint32_t m_token = 0;
};
/**
* \brief Extended operand token
*
* Stores additional properties for an operand that
* cannot be stored in the initial operand token.
*/
class DxbcOperandTokenExt {
public:
DxbcOperandTokenExt() { }
DxbcOperandTokenExt(uint32_t token)
: m_token(token) { }
/**
* \brief Operand extension type
* \returns Operand extension type
*/
DxbcOperandExt type() const {
return static_cast<DxbcOperandExt>(
bit::extract(m_token, 0, 5));
}
/**
* \brief Data flags
* \returns Data flags
*/
uint32_t data() const {
return bit::extract(m_token, 6, 30);
}
/**
* \brief Checks whether the operand is extended
*
* Like extended opcode tokens, extended
* operand tokens can be chained.
* \returns \c true if extended
*/
bool isExtended() const {
return !!bit::extract(m_token, 31, 31);
}
private:
uint32_t m_token = 0;
};
/**
* \brief DXBC code DxbcCodeReader
*
* 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 DxbcCodeReader {
public:
DxbcCodeReader() { }
DxbcCodeReader(
const uint32_t* code,
uint32_t size)
: m_code(size != 0 ? code : nullptr),
m_size(size) { }
uint32_t getWord(uint32_t id) const {
return id < m_size ? m_code[id] : 0;
}
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:
const uint32_t* m_code = nullptr;
uint32_t m_size = 0;
};
/**
* \brief DXBC operand index
*
* Represents an index into an indexable register file.
* For each register file dimension, one operand index
* must be read from the encoded instruction.
*/
class DxbcOperandIndex {
public:
DxbcOperandIndex() { }
DxbcOperandIndex(
const DxbcCodeReader& code,
DxbcOperandIndexRepresentation rep)
: m_code(code), m_rep(rep) { }
uint32_t length() const;
bool hasImmPart() const;
bool hasRelPart() const;
uint64_t immPart() const;
DxbcOperand relPart() const;
private:
DxbcCodeReader m_code;
DxbcOperandIndexRepresentation m_rep;
};
/**
* \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 Operand length, in DWORDs
* \returns Number of DWORDs
*/
uint32_t length() const {
return m_length;
}
/**
* \brief Operand index for a single dimension
*
* \param [in] dim Dimension to query
* \returns Operand index
*/
DxbcOperandIndex index(uint32_t dim) const;
/**
* \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
* \param [out] token The extended token
* \returns \c true if the token was defined
*/
bool queryOperandExt(
DxbcOperandExt ext,
DxbcOperandTokenExt& token) const;
/**
* \brief Reads 32-bit immediate integer
*
* \param [in] idx Component index
* \returns The immediate operand
*/
uint32_t imm32(uint32_t idx) const {
return m_data.getWord(idx);
}
/**
* \brief Reads 64-bit immediate integer
*
* \param [in] idx Component index
* \returns The immediate operand
*/
uint64_t imm64(uint32_t idx) const {
uint64_t hi = m_data.getWord(2 * idx + 0);
uint64_t lo = m_data.getWord(2 * idx + 1);
return (hi << 32) | (lo);
}
private:
DxbcCodeReader m_info;
DxbcCodeReader m_data;
uint32_t m_length = 0;
std::array<uint32_t, 3> m_indexOffsets = { 0, 0, 0 };
};
/**
* \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 [in] extOpcode Extended opcode
* \param [out] token The extended token
* \returns \c true if the token was defined
*/
bool queryOpcodeExt(
DxbcExtOpcode extOpcode,
DxbcOpcodeTokenExt& token) 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 arg(uint32_t idx) const {
return m_args.getWord(idx);
}
/**
* \brief Reads an argument enum
*
* Casts the word at the given location to an enum.
* Some instructions take name tokens as operands.
* \param [in] idx Argument word index
* \returns The enum value of the given word
*/
template<typename T>
T readEnum(uint32_t idx) const {
return static_cast<T>(arg(idx));
}
/**
* \brief Retrieves an operand
*
* \param [in] idx Argument word index
* \returns The operand object
*/
DxbcOperand operand(uint32_t idx) const {
return DxbcOperand(m_args + idx);
}
private:
DxbcCodeReader m_op;
DxbcCodeReader m_args;
};
/**
* \brief DXBC instruction decoder
*
* Iterator that walks over DXBC instructions.
* Instruction boundaries are easy to find as
* the length of each instruction is encoded
* in the opcode token, much like in SPIR-V.
*/
class DxbcDecoder {
public:
DxbcDecoder() { }
DxbcDecoder(const uint32_t* code, uint32_t size)
: m_code(code, size) { }
DxbcDecoder& operator ++ () {
m_code += DxbcInstruction(m_code).length();
return *this;
}
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:
DxbcCodeReader m_code;
void decodeOperand(DxbcCodeSlice& code, const DxbcInstOperandFormat& format);
};

View File

@ -1,333 +0,0 @@
#include "dxbc_decoder_2.h"
namespace dxvk {
uint32_t DxbcCodeSlice::at(uint32_t id) const {
if (m_ptr + id >= m_end)
throw DxvkError("DxbcCodeSlice: End of stream");
return m_ptr[id];
}
uint32_t DxbcCodeSlice::read() {
if (m_ptr >= m_end)
throw DxvkError("DxbcCodeSlice: End of stream");
return *(m_ptr++);
}
DxbcCodeSlice DxbcCodeSlice::take(uint32_t n) const {
if (m_ptr + n > m_end)
throw DxvkError("DxbcCodeSlice: End of stream");
return DxbcCodeSlice(m_ptr, m_ptr + n);
}
DxbcCodeSlice DxbcCodeSlice::skip(uint32_t n) const {
if (m_ptr + n > m_end)
throw DxvkError("DxbcCodeSlice: End of stream");
return DxbcCodeSlice(m_ptr + n, m_end);
}
void DxbcDecodeContext::decodeInstruction(DxbcCodeSlice& code) {
const uint32_t token0 = code.at(0);
// Initialize the instruction structure. Some of these values
// may not get written otherwise while decoding the instruction.
m_instruction.op = static_cast<DxbcOpcode>(bit::extract(token0, 0, 10));
m_instruction.sampleControls = { 0, 0, 0 };
m_instruction.dstCount = 0;
m_instruction.srcCount = 0;
m_instruction.immCount = 0;
m_instruction.dst = m_dstOperands.data();
m_instruction.src = m_srcOperands.data();
m_instruction.imm = m_immOperands.data();
// Reset the index pointer, which may still contain
// a non-zero value from the previous iteration
m_indexId = 0;
// Instruction length, in DWORDs. This includes the token
// itself and any other prefix that an instruction may have.
uint32_t length = 0;
if (m_instruction.op == DxbcOpcode::CustomData) {
length = code.at(1);
this->decodeCustomData(code.take(length));
} else {
length = bit::extract(token0, 24, 30);
this->decodeOperation(code.take(length));
}
// Advance the caller's slice to the next token so that
// they can make consecutive calls to decodeInstruction()
code = code.skip(length);
}
void DxbcDecodeContext::decodeCustomData(DxbcCodeSlice code) {
Logger::warn("DxbcDecodeContext::decodeCustomData: Not implemented");
}
void DxbcDecodeContext::decodeOperation(DxbcCodeSlice code) {
uint32_t token = code.read();
// Result modifiers, which are applied to common ALU ops
m_instruction.modifiers.saturate = !!bit::extract(token, 13, 13);
m_instruction.modifiers.precise = !!bit::extract(token, 19, 22);
// Opcode controls. It will depend on the opcode itself which ones are valid.
m_instruction.controls.zeroTest = static_cast<DxbcZeroTest> (bit::extract(token, 18, 18));
m_instruction.controls.syncFlags = static_cast<DxbcSyncFlags> (bit::extract(token, 11, 14));
m_instruction.controls.resourceDim = static_cast<DxbcResourceDim> (bit::extract(token, 11, 15));
m_instruction.controls.resinfoType = static_cast<DxbcResinfoType> (bit::extract(token, 11, 12));
m_instruction.controls.interpolation = static_cast<DxbcInterpolationMode>(bit::extract(token, 11, 14));
// Process extended opcode tokens
while (bit::extract(token, 31, 31)) {
token = code.read();
const DxbcExtOpcode extOpcode
= static_cast<DxbcExtOpcode>(bit::extract(token, 0, 5));
switch (extOpcode) {
case DxbcExtOpcode::SampleControls: {
struct {
int u : 4;
int v : 4;
int w : 4;
} aoffimmi;
aoffimmi.u = bit::extract(token, 9, 12);
aoffimmi.v = bit::extract(token, 13, 16);
aoffimmi.w = bit::extract(token, 17, 20);
// Four-bit signed numbers, sign-extend them
m_instruction.sampleControls.u = aoffimmi.u;
m_instruction.sampleControls.v = aoffimmi.v;
m_instruction.sampleControls.w = aoffimmi.w;
} break;
default:
Logger::warn(str::format(
"DxbcDecodeContext: Unhandled extended opcode: ",
extOpcode));
}
}
// Retrieve the instruction format in order to parse the
// operands. Doing this mostly automatically means that
// the compiler can rely on the operands being valid.
const DxbcInstFormat format = dxbcInstructionFormat(m_instruction.op);
for (uint32_t i = 0; i < format.operandCount; i++)
this->decodeOperand(code, format.operands[i]);
}
void DxbcDecodeContext::decodeComponentSelection(DxbcRegister& reg, uint32_t token) {
// Pick the correct component selection mode based on the
// component count. We'll simplify this here so that the
// compiler can assume that everything is a 4D vector.
reg.componentCount = static_cast<DxbcRegComponentCount>(bit::extract(token, 0, 1));
switch (reg.componentCount) {
// No components - used for samplers etc.
case DxbcRegComponentCount::c0:
reg.mask = DxbcRegMask(false, false, false, false);
reg.swizzle = DxbcRegSwizzle(0, 0, 0, 0);
break;
// One component - used for immediates
// and a few built-in registers.
case DxbcRegComponentCount::c1:
reg.mask = DxbcRegMask(true, false, false, false);
reg.swizzle = DxbcRegSwizzle(0, 0, 0, 0);
break;
// Four components - everything else. This requires us
// to actually parse the component selection mode.
case DxbcRegComponentCount::c4: {
const DxbcRegMode componentMode =
static_cast<DxbcRegMode>(bit::extract(token, 2, 3));
switch (componentMode) {
// Write mask for destination operands
case DxbcRegMode::Mask:
reg.mask = bit::extract(token, 4, 7);
reg.swizzle = DxbcRegSwizzle(0, 1, 2, 3);
break;
// Swizzle for source operands (including resources)
case DxbcRegMode::Swizzle:
reg.mask = DxbcRegMask(true, true, true, true);
reg.swizzle = DxbcRegSwizzle(
bit::extract(token, 4, 5),
bit::extract(token, 6, 7),
bit::extract(token, 8, 9),
bit::extract(token, 10, 11));
break;
// Selection of one component. We can generate both a
// mask and a swizzle for this so that the compiler
// won't have to deal with this case specifically.
case DxbcRegMode::Select1: {
const uint32_t n = bit::extract(token, 4, 5);
reg.mask = DxbcRegMask(n == 0, n == 1, n == 2, n == 3);
reg.swizzle = DxbcRegSwizzle(n, n, n, n);
} break;
default:
Logger::warn("DxbcDecodeContext: Invalid component selection mode");
}
} break;
default:
Logger::warn("DxbcDecodeContext: Invalid component count");
}
}
void DxbcDecodeContext::decodeOperandExtensions(DxbcCodeSlice& code, DxbcRegister& reg, uint32_t token) {
while (bit::extract(token, 31, 31)) {
token = code.read();
// Type of the extended operand token
const DxbcOperandExt extTokenType =
static_cast<DxbcOperandExt>(bit::extract(token, 0, 5));
switch (extTokenType) {
// Operand modifiers, which are used to manipulate the
// value of a source operand during the load operation
case DxbcOperandExt::OperandModifier:
reg.modifiers = bit::extract(token, 6, 13);
break;
default:
Logger::warn(str::format(
"DxbcDecodeContext: Unhandled extended operand token: ",
extTokenType));
}
}
}
void DxbcDecodeContext::decodeOperandImmediates(DxbcCodeSlice& code, DxbcRegister& reg) {
if (reg.type == DxbcOperandType::Imm32) {
switch (reg.componentCount) {
// This is commonly used if only one vector
// component is involved in an operation
case DxbcRegComponentCount::c1: {
reg.imm.u32_1 = code.read();
} break;
// Typical four-component vector
case DxbcRegComponentCount::c4: {
reg.imm.u32_4[0] = code.read();
reg.imm.u32_4[1] = code.read();
reg.imm.u32_4[2] = code.read();
reg.imm.u32_4[3] = code.read();
} break;
default:
Logger::warn("DxbcDecodeContext: Invalid component count for immediate operand");
}
} else if (reg.type == DxbcOperandType::Imm64) {
Logger::warn("DxbcDecodeContext: 64-bit immediates not supported");
}
}
void DxbcDecodeContext::decodeOperandIndex(DxbcCodeSlice& code, DxbcRegister& reg, uint32_t token) {
reg.idxDim = bit::extract(token, 20, 21);
for (uint32_t i = 0; i < reg.idxDim; i++) {
// An index can be encoded in various different ways
const DxbcOperandIndexRepresentation repr =
static_cast<DxbcOperandIndexRepresentation>(
bit::extract(token, 22 + 3 * i, 24 + 3 * i));
switch (repr) {
case DxbcOperandIndexRepresentation::Imm32:
reg.idx[i].offset = static_cast<int32_t>(code.read());
reg.idx[i].relReg = nullptr;
break;
case DxbcOperandIndexRepresentation::Relative:
reg.idx[i].offset = 0;
reg.idx[i].relReg = &m_indices.at(m_indexId);
this->decodeRegister(code,
m_indices.at(m_indexId++),
DxbcScalarType::Sint32);
break;
case DxbcOperandIndexRepresentation::Imm32Relative:
reg.idx[i].offset = static_cast<int32_t>(code.read());
reg.idx[i].relReg = &m_indices.at(m_indexId);
this->decodeRegister(code,
m_indices.at(m_indexId++),
DxbcScalarType::Sint32);
break;
default:
Logger::warn(str::format(
"DxbcDecodeContext: Unhandled index representation: ",
repr));
}
}
}
void DxbcDecodeContext::decodeRegister(DxbcCodeSlice& code, DxbcRegister& reg, DxbcScalarType type) {
const uint32_t token = code.read();
reg.type = static_cast<DxbcOperandType>(bit::extract(token, 12, 19));
reg.dataType = type;
reg.modifiers = 0;
reg.idxDim = 0;
for (uint32_t i = 0; i < DxbcMaxRegIndexDim; i++) {
reg.idx[i].relReg = nullptr;
reg.idx[i].offset = 0;
}
this->decodeComponentSelection(reg, token);
this->decodeOperandExtensions(code, reg, token);
this->decodeOperandImmediates(code, reg);
this->decodeOperandIndex(code, reg, token);
}
void DxbcDecodeContext::decodeImm32(DxbcCodeSlice& code, DxbcImmediate& imm, DxbcScalarType type) {
imm.u32 = code.read();
}
void DxbcDecodeContext::decodeOperand(DxbcCodeSlice& code, const DxbcInstOperandFormat& format) {
switch (format.kind) {
case DxbcOperandKind::DstReg: {
const uint32_t operandId = m_instruction.dstCount++;
this->decodeRegister(code, m_dstOperands.at(operandId), format.type);
} break;
case DxbcOperandKind::SrcReg: {
const uint32_t operandId = m_instruction.srcCount++;
this->decodeRegister(code, m_srcOperands.at(operandId), format.type);
} break;
case DxbcOperandKind::Imm32: {
const uint32_t operandId = m_instruction.immCount++;
this->decodeImm32(code, m_immOperands.at(operandId), format.type);
} break;
default:
throw DxvkError("DxbcDecodeContext: Invalid operand format");
}
}
}

View File

@ -1,192 +0,0 @@
#pragma once
#include <array>
#include "dxbc_common.h"
#include "dxbc_decoder.h"
#include "dxbc_defs.h"
#include "dxbc_enums.h"
#include "dxbc_names.h"
namespace dxvk {
constexpr size_t DxbcMaxRegIndexDim = 3;
struct DxbcRegister;
enum class DxbcRegComponentCount : uint32_t {
c0 = 0,
c1 = 1,
c4 = 2,
};
enum class DxbcRegModifier : uint32_t {
Neg = 0,
Abs = 1,
};
using DxbcRegModifiers = Flags<DxbcRegModifier>;
struct DxbcRegIndex {
DxbcRegister* relReg;
int32_t offset;
};
struct DxbcRegister {
DxbcOperandType type;
DxbcScalarType dataType;
DxbcRegComponentCount componentCount;
uint32_t idxDim;
DxbcRegIndex idx[DxbcMaxRegIndexDim];
DxbcRegMask mask;
DxbcRegSwizzle swizzle;
DxbcRegModifiers modifiers;
union {
uint32_t u32_4[4];
uint32_t u32_1;
} imm;
};
struct DxbcOpModifiers {
bool saturate;
bool precise;
};
struct DxbcShaderOpcodeControls {
DxbcZeroTest zeroTest;
DxbcSyncFlags syncFlags;
DxbcResourceDim resourceDim;
DxbcResinfoType resinfoType;
DxbcInterpolationMode interpolation;
};
struct DxbcShaderSampleControls {
int u, v, w;
};
union DxbcImmediate {
uint32_t u32;
uint64_t u64;
};
/**
* \brief Shader instruction
*/
struct DxbcShaderInstruction {
DxbcOpcode op;
DxbcOpModifiers modifiers;
DxbcShaderOpcodeControls controls;
DxbcShaderSampleControls sampleControls;
uint32_t dstCount;
uint32_t srcCount;
uint32_t immCount;
const DxbcRegister* dst;
const DxbcRegister* src;
const DxbcImmediate* imm;
};
/**
* \brief DXBC code slice
*
* Convenient pointer pair that allows
* reading the code word stream safely.
*/
class DxbcCodeSlice {
public:
DxbcCodeSlice(
const uint32_t* ptr,
const uint32_t* end)
: m_ptr(ptr), m_end(end) { }
uint32_t at(uint32_t id) const;
uint32_t read();
DxbcCodeSlice take(uint32_t n) const;
DxbcCodeSlice skip(uint32_t n) const;
bool atEnd() const {
return m_ptr == m_end;
}
private:
const uint32_t* m_ptr = nullptr;
const uint32_t* m_end = nullptr;
};
/**
* \brief Decode context
*
* Stores data that is required to decode a single
* instruction. This data is not persistent, so it
* should be forwarded to the compiler right away.
*/
class DxbcDecodeContext {
public:
/**
* \brief Retrieves current instruction
*
* This is only valid after a call to \ref decode.
* \returns Reference to last decoded instruction
*/
const DxbcShaderInstruction& getInstruction() const {
return m_instruction;
}
/**
* \brief Decodes an instruction
*
* This also advances the given code slice by the
* number of dwords consumed by the instruction.
* \param [in] code Code slice
*/
void decodeInstruction(DxbcCodeSlice& code);
private:
DxbcShaderInstruction m_instruction;
std::array<DxbcRegister, 4> m_dstOperands;
std::array<DxbcRegister, 4> m_srcOperands;
std::array<DxbcImmediate, 4> m_immOperands;
std::array<DxbcRegister, 12> m_indices;
// Index into the indices array. Used when decoding
// instruction operands with relative indexing.
uint32_t m_indexId = 0;
void decodeCustomData(DxbcCodeSlice code);
void decodeOperation(DxbcCodeSlice code);
void decodeComponentSelection(DxbcRegister& reg, uint32_t token);
void decodeOperandExtensions(DxbcCodeSlice& code, DxbcRegister& reg, uint32_t token);
void decodeOperandImmediates(DxbcCodeSlice& code, DxbcRegister& reg);
void decodeOperandIndex(DxbcCodeSlice& code, DxbcRegister& reg, uint32_t token);
void decodeRegister(DxbcCodeSlice& code, DxbcRegister& reg, DxbcScalarType type);
void decodeImm32(DxbcCodeSlice& code, DxbcImmediate& imm, DxbcScalarType type);
void decodeOperand(DxbcCodeSlice& code, const DxbcInstOperandFormat& format);
};
}

View File

@ -436,14 +436,6 @@ namespace dxvk {
using DxbcGlobalFlags = Flags<DxbcGlobalFlag>;
enum class DxbcOperandModifier : uint32_t {
Neg = 0,
Abs = 1,
};
using DxbcOperandModifiers = Flags<DxbcOperandModifier>;
enum class DxbcZeroTest : uint32_t {
TestZ = 0,
TestNz = 1,

View File

@ -1,5 +1,4 @@
#include "dxbc_compiler.h"
#include "dxbc_compiler_2.h"
#include "dxbc_module.h"
namespace dxvk {
@ -47,7 +46,7 @@ namespace dxvk {
DxbcCodeSlice slice = m_shexChunk->slice();
DxbcCompiler2 compiler(
DxbcCompiler compiler(
m_shexChunk->version(),
m_isgnChunk, m_osgnChunk);

View File

@ -3,10 +3,8 @@ dxbc_src = files([
'dxbc_chunk_shex.cpp',
'dxbc_common.cpp',
'dxbc_compiler.cpp',
'dxbc_compiler_2.cpp',
'dxbc_defs.cpp',
'dxbc_decoder.cpp',
'dxbc_decoder_2.cpp',
'dxbc_header.cpp',
'dxbc_module.cpp',
'dxbc_names.cpp',