mirror of
https://github.com/EduApps-CDG/OpenDX
synced 2024-12-30 09:45:37 +01:00
[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:
parent
47347e38da
commit
858913ec0c
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
#include "dxbc_common.h"
|
#include "dxbc_common.h"
|
||||||
#include "dxbc_decoder.h"
|
#include "dxbc_decoder.h"
|
||||||
#include "dxbc_decoder_2.h"
|
|
||||||
#include "dxbc_reader.h"
|
#include "dxbc_reader.h"
|
||||||
|
|
||||||
namespace dxvk {
|
namespace dxvk {
|
||||||
@ -30,14 +29,6 @@ namespace dxvk {
|
|||||||
m_code.data() + m_code.size());
|
m_code.data() + m_code.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
DxbcDecoder begin() const {
|
|
||||||
return DxbcDecoder(m_code.data(), m_code.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
DxbcDecoder end() const {
|
|
||||||
return DxbcDecoder();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
DxbcProgramVersion m_version;
|
DxbcProgramVersion m_version;
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,133 +1,84 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "../spirv/spirv_module.h"
|
#include "../spirv/spirv_module.h"
|
||||||
|
|
||||||
#include "dxbc_chunk_isgn.h"
|
#include "dxbc_chunk_isgn.h"
|
||||||
#include "dxbc_decoder.h"
|
#include "dxbc_decoder.h"
|
||||||
#include "dxbc_defs.h"
|
#include "dxbc_defs.h"
|
||||||
|
#include "dxbc_names.h"
|
||||||
|
#include "dxbc_util.h"
|
||||||
|
|
||||||
namespace dxvk {
|
namespace dxvk {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Expression value
|
* \brief Vector type
|
||||||
*
|
*
|
||||||
* Tracks the type and the SPIR-V variable
|
* Convenience struct that stores a scalar
|
||||||
* ID when evaluating DXBC instructions.
|
* type and a component count. The compiler
|
||||||
|
* can use this to generate SPIR-V types.
|
||||||
*/
|
*/
|
||||||
struct DxbcValue {
|
struct DxbcVectorType {
|
||||||
DxbcScalarType componentType = DxbcScalarType::Float32;
|
DxbcScalarType ctype;
|
||||||
uint32_t componentCount = 0;
|
uint32_t ccount;
|
||||||
uint32_t valueId = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Variable pointer
|
* \brief Register info
|
||||||
*
|
*
|
||||||
* Stores the SPIR-V pointer ID and the
|
* Stores the vector type of a register and
|
||||||
* type of the referenced variable. Used
|
* its storage class. The compiler can use
|
||||||
* to access variables and resources.
|
* this to generate SPIR-V pointer types.
|
||||||
*/
|
*/
|
||||||
struct DxbcPointer {
|
struct DxbcRegisterInfo {
|
||||||
DxbcScalarType componentType = DxbcScalarType::Float32;
|
DxbcVectorType type;
|
||||||
uint32_t componentCount = 0;
|
spv::StorageClass sclass;
|
||||||
uint32_t pointerId = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Compiler error code
|
* \brief Register value
|
||||||
*
|
*
|
||||||
* Helps identify the type of error
|
* Stores a vector type and a SPIR-V ID that
|
||||||
* that may occur during compilation.
|
* represents an intermediate value. This is
|
||||||
|
* used to track the type of such values.
|
||||||
*/
|
*/
|
||||||
enum class DxbcError {
|
struct DxbcRegisterValue {
|
||||||
sOk,
|
DxbcVectorType type;
|
||||||
eInternal,
|
uint32_t id;
|
||||||
eInstructionFormat,
|
|
||||||
eInvalidOperand,
|
|
||||||
eInvalidOperandIndex,
|
|
||||||
eTypeMismatch,
|
|
||||||
eUnhandledOpcode,
|
|
||||||
eUnsupported,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Operand index type
|
* \brief Register pointer
|
||||||
*
|
*
|
||||||
* Defines whether a register index
|
* Stores a vector type and a SPIR-V ID that
|
||||||
* is relative or constant.
|
* represents a pointer to such a vector. This
|
||||||
|
* can be used to load registers conveniently.
|
||||||
*/
|
*/
|
||||||
enum class DxbcIndexType {
|
struct DxbcRegisterPointer {
|
||||||
Immediate, ///< Index is a constant value
|
DxbcVectorType type;
|
||||||
Relative, ///< Index depends on a r# register
|
uint32_t id;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Instruction operand index
|
* \brief Vertex shader-specific structure
|
||||||
*
|
|
||||||
* Stores the type of the index as well as the
|
|
||||||
* register (if relative) and the constant offset.
|
|
||||||
*/
|
*/
|
||||||
struct DxbcInstOpIndex {
|
struct DxbcCompilerVsPart {
|
||||||
DxbcIndexType type = DxbcIndexType::Immediate;
|
uint32_t functionId;
|
||||||
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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Decoded instruction
|
* \brief Pixel shader-specific structure
|
||||||
*
|
|
||||||
* Stores all information about a single
|
|
||||||
* instruction, including its operands.
|
|
||||||
*/
|
*/
|
||||||
struct DxbcInst {
|
struct DxbcCompilerPsPart {
|
||||||
DxbcOpcode opcode = DxbcOpcode::Nop;
|
uint32_t functionId;
|
||||||
DxbcOpcodeControl control = 0;
|
std::array<DxbcVectorType, DxbcMaxInterfaceRegs> oTypes;
|
||||||
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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -150,12 +101,10 @@ namespace dxvk {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Processes a single instruction
|
* \brief Processes a single instruction
|
||||||
*
|
|
||||||
* \param [in] ins The instruction
|
* \param [in] ins The instruction
|
||||||
* \returns An error code, or \c sOK
|
|
||||||
*/
|
*/
|
||||||
DxbcError processInstruction(
|
void processInstruction(
|
||||||
const DxbcInstruction& ins);
|
const DxbcShaderInstruction& ins);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Finalizes the shader
|
* \brief Finalizes the shader
|
||||||
@ -184,12 +133,14 @@ namespace dxvk {
|
|||||||
// v# registers as defined by the shader. The type of each
|
// v# registers as defined by the shader. The type of each
|
||||||
// of these inputs is either float4 or an array of float4.
|
// of these inputs is either float4 or an array of float4.
|
||||||
std::array<uint32_t, DxbcMaxInterfaceRegs> m_vRegs;
|
std::array<uint32_t, DxbcMaxInterfaceRegs> m_vRegs;
|
||||||
|
std::vector<DxbcSvMapping> m_vMappings;
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////
|
||||||
// o# registers as defined by the shader. In the fragment
|
// o# registers as defined by the shader. In the fragment
|
||||||
// shader stage, these registers are typed by the signature,
|
// shader stage, these registers are typed by the signature,
|
||||||
// in all other stages, they are float4 registers or arrays.
|
// in all other stages, they are float4 registers or arrays.
|
||||||
std::array<uint32_t, DxbcMaxInterfaceRegs> m_oRegs;
|
std::array<uint32_t, DxbcMaxInterfaceRegs> m_oRegs;
|
||||||
|
std::vector<DxbcSvMapping> m_oMappings;
|
||||||
|
|
||||||
//////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////
|
||||||
// Shader resource variables. These provide access to
|
// Shader resource variables. These provide access to
|
||||||
@ -198,12 +149,6 @@ namespace dxvk {
|
|||||||
std::array<DxbcSampler, 16> m_samplers;
|
std::array<DxbcSampler, 16> m_samplers;
|
||||||
std::array<DxbcShaderResource, 128> m_textures;
|
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
|
// Array of input values. Since v# registers are indexable
|
||||||
// in DXBC, we need to copy them into an array first.
|
// in DXBC, we need to copy them into an array first.
|
||||||
@ -221,190 +166,185 @@ namespace dxvk {
|
|||||||
std::vector<uint32_t> m_entryPointInterfaces;
|
std::vector<uint32_t> m_entryPointInterfaces;
|
||||||
uint32_t m_entryPointId = 0;
|
uint32_t m_entryPointId = 0;
|
||||||
|
|
||||||
////////////////////////////////////////
|
///////////////////////////////////
|
||||||
// Data structures for each shader type
|
// Shader-specific data structures
|
||||||
DxbcVsSpecifics m_vs;
|
DxbcCompilerVsPart m_vs;
|
||||||
DxbcPsSpecifics m_ps;
|
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
|
// Instruction class handlers
|
||||||
DxbcError handleDeclaration(
|
void emitVectorAlu(
|
||||||
const DxbcInst& ins);
|
const DxbcShaderInstruction& ins);
|
||||||
|
|
||||||
DxbcError handleControlFlow(
|
void emitVectorCmov(
|
||||||
const DxbcInst& ins);
|
const DxbcShaderInstruction& ins);
|
||||||
|
|
||||||
DxbcError handleTextureSample(
|
void emitVectorCmp(
|
||||||
const DxbcInst& ins);
|
const DxbcShaderInstruction& ins);
|
||||||
|
|
||||||
DxbcError handleVectorAlu(
|
void emitVectorDot(
|
||||||
const DxbcInst& ins);
|
const DxbcShaderInstruction& ins);
|
||||||
|
|
||||||
DxbcError handleVectorCmov(
|
void emitVectorImul(
|
||||||
const DxbcInst& ins);
|
const DxbcShaderInstruction& ins);
|
||||||
|
|
||||||
DxbcError handleVectorCmp(
|
void emitVectorSinCos(
|
||||||
const DxbcInst& ins);
|
const DxbcShaderInstruction& ins);
|
||||||
|
|
||||||
DxbcError handleVectorDot(
|
void emitSample(
|
||||||
const DxbcInst& ins);
|
const DxbcShaderInstruction& ins);
|
||||||
|
|
||||||
DxbcError handleVectorSinCos(
|
void emitRet(
|
||||||
const DxbcInst& ins);
|
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(
|
DxbcRegisterValue emitRegisterSwizzle(
|
||||||
const DxbcInst& ins);
|
DxbcRegisterValue value,
|
||||||
|
DxbcRegSwizzle swizzle,
|
||||||
|
DxbcRegMask writeMask);
|
||||||
|
|
||||||
DxbcError declareConstantBuffer(
|
DxbcRegisterValue emitRegisterExtract(
|
||||||
const DxbcInst& ins);
|
DxbcRegisterValue value,
|
||||||
|
DxbcRegMask mask);
|
||||||
|
|
||||||
DxbcError declareSampler(
|
DxbcRegisterValue emitRegisterInsert(
|
||||||
const DxbcInst& ins);
|
DxbcRegisterValue dstValue,
|
||||||
|
DxbcRegisterValue srcValue,
|
||||||
|
DxbcRegMask srcMask);
|
||||||
|
|
||||||
DxbcError declareResource(
|
DxbcRegisterValue emitRegisterExtend(
|
||||||
const DxbcInst& ins);
|
DxbcRegisterValue value,
|
||||||
|
uint32_t size);
|
||||||
|
|
||||||
DxbcError declareInputVar(
|
DxbcRegisterValue emitRegisterAbsolute(
|
||||||
uint32_t regId,
|
DxbcRegisterValue value);
|
||||||
uint32_t regDim,
|
|
||||||
DxbcRegMask regMask,
|
|
||||||
DxbcSystemValue sv,
|
|
||||||
DxbcInterpolationMode im);
|
|
||||||
|
|
||||||
DxbcError declareOutputVar(
|
DxbcRegisterValue emitRegisterNegate(
|
||||||
uint32_t regId,
|
DxbcRegisterValue value);
|
||||||
uint32_t regDim,
|
|
||||||
DxbcRegMask regMask,
|
|
||||||
DxbcSystemValue sv,
|
|
||||||
DxbcInterpolationMode im);
|
|
||||||
|
|
||||||
////////////////////////////////////
|
DxbcRegisterValue emitSrcOperandModifiers(
|
||||||
// Register manipulation operations
|
DxbcRegisterValue value,
|
||||||
DxbcValue bitcastReg(
|
DxbcRegModifiers modifiers);
|
||||||
const DxbcValue& src,
|
|
||||||
DxbcScalarType type);
|
|
||||||
|
|
||||||
DxbcValue insertReg(
|
DxbcRegisterValue emitDstOperandModifiers(
|
||||||
const DxbcValue& dst,
|
DxbcRegisterValue value,
|
||||||
const DxbcValue& src,
|
DxbcOpModifiers modifiers);
|
||||||
DxbcRegMask mask);
|
|
||||||
|
|
||||||
DxbcValue extractReg(
|
////////////////////////
|
||||||
const DxbcValue& src,
|
// Address load methods
|
||||||
DxbcRegMask mask);
|
DxbcRegisterPointer emitGetTempPtr(
|
||||||
|
const DxbcRegister& operand);
|
||||||
|
|
||||||
DxbcValue swizzleReg(
|
DxbcRegisterPointer emitGetInputPtr(
|
||||||
const DxbcValue& src,
|
const DxbcRegister& operand);
|
||||||
const DxbcRegSwizzle& swizzle,
|
|
||||||
DxbcRegMask mask);
|
|
||||||
|
|
||||||
DxbcValue regVector(
|
DxbcRegisterPointer emitGetOutputPtr(
|
||||||
const DxbcValue& src,
|
const DxbcRegister& operand);
|
||||||
uint32_t size);
|
|
||||||
|
|
||||||
DxbcValue extendReg(
|
DxbcRegisterPointer emitGetConstBufPtr(
|
||||||
const DxbcValue& src,
|
const DxbcRegister& operand);
|
||||||
uint32_t size);
|
|
||||||
|
|
||||||
////////////////////////////
|
DxbcRegisterPointer emitGetOperandPtr(
|
||||||
// Operand modifier methods
|
const DxbcRegister& operand);
|
||||||
DxbcValue applyOperandModifiers(
|
|
||||||
DxbcValue value,
|
|
||||||
DxbcOperandModifiers modifiers);
|
|
||||||
|
|
||||||
DxbcValue applyResultModifiers(
|
//////////////////////////////
|
||||||
DxbcValue value,
|
// Operand load/store methods
|
||||||
DxbcOpcodeControl control);
|
DxbcRegisterValue emitIndexLoad(
|
||||||
|
DxbcRegIndex index);
|
||||||
|
|
||||||
/////////////////////////
|
DxbcRegisterValue emitValueLoad(
|
||||||
// Load/Store operations
|
DxbcRegisterPointer ptr);
|
||||||
DxbcValue loadOp(
|
|
||||||
const DxbcInstOp& srcOp,
|
|
||||||
DxbcRegMask srcMask,
|
|
||||||
DxbcScalarType dstType);
|
|
||||||
|
|
||||||
DxbcValue loadImm32(
|
void emitValueStore(
|
||||||
const DxbcInstOp& srcOp,
|
DxbcRegisterPointer ptr,
|
||||||
DxbcRegMask srcMask,
|
DxbcRegisterValue value,
|
||||||
DxbcScalarType dstType);
|
DxbcRegMask writeMask);
|
||||||
|
|
||||||
DxbcValue loadRegister(
|
DxbcRegisterValue emitRegisterLoad(
|
||||||
const DxbcInstOp& srcOp,
|
const DxbcRegister& reg,
|
||||||
DxbcRegMask srcMask,
|
DxbcRegMask writeMask);
|
||||||
DxbcScalarType dstType);
|
|
||||||
|
|
||||||
void storeOp(
|
void emitRegisterStore(
|
||||||
const DxbcInstOp& dstOp,
|
const DxbcRegister& reg,
|
||||||
const DxbcValue& srcValue);
|
DxbcRegisterValue value);
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
/////////////////////////////
|
/////////////////////////////
|
||||||
// Input preparation methods
|
// Input preparation methods
|
||||||
void prepareVertexInputs();
|
void emitVsInputSetup();
|
||||||
void preparePixelInputs();
|
void emitPsInputSetup();
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
// Output preparation methods
|
// Output preparation methods
|
||||||
void prepareVertexOutputs();
|
void emitVsOutputSetup();
|
||||||
void preparePixelOutputs();
|
void emitPsOutputSetup();
|
||||||
|
|
||||||
|
/////////////////////////////////
|
||||||
|
// Shader initialization methods
|
||||||
|
void emitVsInit();
|
||||||
|
void emitPsInit();
|
||||||
|
|
||||||
///////////////////////////////
|
///////////////////////////////
|
||||||
// Shader finalization methods
|
// Shader finalization methods
|
||||||
void endVertexShader();
|
void emitVsFinalize();
|
||||||
void endPixelShader();
|
void emitPsFinalize();
|
||||||
|
|
||||||
|
///////////////////////////////
|
||||||
|
// Variable definition methods
|
||||||
|
uint32_t emitNewVariable(
|
||||||
|
const DxbcRegisterInfo& info);
|
||||||
|
|
||||||
///////////////////////////
|
///////////////////////////
|
||||||
// Type definition methods
|
// Type definition methods
|
||||||
uint32_t definePerVertexBlock();
|
uint32_t getScalarTypeId(
|
||||||
|
DxbcScalarType type);
|
||||||
|
|
||||||
uint32_t defineScalarType(
|
uint32_t getVectorTypeId(
|
||||||
DxbcScalarType componentType);
|
const DxbcVectorType& type);
|
||||||
|
|
||||||
uint32_t defineVectorType(
|
uint32_t getPointerTypeId(
|
||||||
DxbcScalarType componentType,
|
const DxbcRegisterInfo& type);
|
||||||
uint32_t componentCount);
|
|
||||||
|
|
||||||
uint32_t definePointerType(
|
uint32_t getPerVertexBlockId();
|
||||||
DxbcScalarType componentType,
|
|
||||||
uint32_t componentCount,
|
|
||||||
spv::StorageClass storageClass);
|
|
||||||
|
|
||||||
/////////////////////////
|
|
||||||
// DXBC decoding methods
|
|
||||||
DxbcError parseInstruction(
|
|
||||||
const DxbcInstruction& ins,
|
|
||||||
DxbcInst& out);
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -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();
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
@ -2,208 +2,332 @@
|
|||||||
|
|
||||||
namespace dxvk {
|
namespace dxvk {
|
||||||
|
|
||||||
DxbcCodeReader& DxbcCodeReader::operator ++ () {
|
uint32_t DxbcCodeSlice::at(uint32_t id) const {
|
||||||
return this->operator += (1);
|
if (m_ptr + id >= m_end)
|
||||||
|
throw DxvkError("DxbcCodeSlice: End of stream");
|
||||||
|
return m_ptr[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DxbcCodeReader& DxbcCodeReader::operator += (uint32_t n) {
|
uint32_t DxbcCodeSlice::read() {
|
||||||
if (n < m_size) {
|
if (m_ptr >= m_end)
|
||||||
m_code += n;
|
throw DxvkError("DxbcCodeSlice: End of stream");
|
||||||
m_size -= n;
|
return *(m_ptr++);
|
||||||
} else {
|
|
||||||
m_code = nullptr;
|
|
||||||
m_size = 0;
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DxbcCodeReader DxbcCodeReader::operator + (uint32_t n) const {
|
DxbcCodeSlice DxbcCodeSlice::take(uint32_t n) const {
|
||||||
return n < m_size
|
if (m_ptr + n > m_end)
|
||||||
? DxbcCodeReader(m_code + n, m_size - n)
|
throw DxvkError("DxbcCodeSlice: End of stream");
|
||||||
: DxbcCodeReader();
|
return DxbcCodeSlice(m_ptr, m_ptr + n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool DxbcCodeReader::operator == (const DxbcCodeReader& other) const {
|
DxbcCodeSlice DxbcCodeSlice::skip(uint32_t n) const {
|
||||||
return m_code == other.m_code && m_size == other.m_size;
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
void DxbcDecodeContext::decodeInstruction(DxbcCodeSlice& code) {
|
||||||
uint32_t DxbcOperandIndex::length() const {
|
const uint32_t token0 = code.at(0);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw DxvkError(str::format("DXBC: Unknown index representation: ", m_rep));
|
// 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 };
|
||||||
bool DxbcOperandIndex::hasImmPart() const {
|
m_instruction.dstCount = 0;
|
||||||
return m_rep == DxbcOperandIndexRepresentation::Imm32
|
m_instruction.srcCount = 0;
|
||||||
|| m_rep == DxbcOperandIndexRepresentation::Imm64
|
m_instruction.immCount = 0;
|
||||||
|| m_rep == DxbcOperandIndexRepresentation::Imm32Relative
|
m_instruction.dst = m_dstOperands.data();
|
||||||
|| m_rep == DxbcOperandIndexRepresentation::Imm64Relative;
|
m_instruction.src = m_srcOperands.data();
|
||||||
}
|
m_instruction.imm = m_immOperands.data();
|
||||||
|
|
||||||
|
|
||||||
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));
|
|
||||||
|
|
||||||
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
|
// Instruction length, in DWORDs. This includes the token
|
||||||
if (token.isExtended()) {
|
// itself and any other prefix that an instruction may have.
|
||||||
while (DxbcOperandTokenExt(m_info.getWord(numTokens++)).isExtended())
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_data = m_info + numTokens;
|
|
||||||
|
|
||||||
// Immediate operands
|
|
||||||
uint32_t length = 0;
|
uint32_t length = 0;
|
||||||
|
|
||||||
if (token.type() == DxbcOperandType::Imm32
|
if (m_instruction.op == DxbcOpcode::CustomData) {
|
||||||
|| token.type() == DxbcOperandType::Imm64)
|
length = code.at(1);
|
||||||
length += token.numComponents();
|
this->decodeCustomData(code.take(length));
|
||||||
|
|
||||||
// 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;
|
|
||||||
} else {
|
} else {
|
||||||
// For normal instructions, we just count
|
length = bit::extract(token0, 24, 30);
|
||||||
// the number of extended opcode tokens.
|
this->decodeOperation(code.take(length));
|
||||||
uint32_t numOpcodeTokens = 1;
|
}
|
||||||
|
|
||||||
|
// 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()) {
|
const DxbcExtOpcode extOpcode
|
||||||
numOpcodeTokens += 1;
|
= static_cast<DxbcExtOpcode>(bit::extract(token, 0, 5));
|
||||||
while (DxbcOpcodeTokenExt(m_op.getWord(numOpcodeTokens)).isExtended())
|
|
||||||
numOpcodeTokens += 1;
|
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 {
|
void DxbcDecodeContext::decodeOperandExtensions(DxbcCodeSlice& code, DxbcRegister& reg, uint32_t token) {
|
||||||
auto token = this->token();
|
while (bit::extract(token, 31, 31)) {
|
||||||
return token.opcode() != DxbcOpcode::CustomData
|
token = code.read();
|
||||||
? token.length() : m_op.getWord(1);
|
|
||||||
|
// 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 {
|
void DxbcDecodeContext::decodeOperandImmediates(DxbcCodeSlice& code, DxbcRegister& reg) {
|
||||||
if (!this->token().isExtended())
|
if (reg.type == DxbcOperandType::Imm32) {
|
||||||
return false;
|
switch (reg.componentCount) {
|
||||||
|
// This is commonly used if only one vector
|
||||||
uint32_t extTokenId = 1;
|
// component is involved in an operation
|
||||||
DxbcOpcodeTokenExt extToken;
|
case DxbcComponentCount::Component1: {
|
||||||
|
reg.imm.u32_1 = code.read();
|
||||||
do {
|
} break;
|
||||||
extToken = m_op.getWord(extTokenId++);
|
|
||||||
|
// Typical four-component vector
|
||||||
if (extToken.opcode() == extOpcode) {
|
case DxbcComponentCount::Component4: {
|
||||||
token = extToken;
|
reg.imm.u32_4[0] = code.read();
|
||||||
return true;
|
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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,13 +1,32 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstring>
|
#include <array>
|
||||||
|
|
||||||
|
#include "dxbc_common.h"
|
||||||
|
#include "dxbc_decoder.h"
|
||||||
|
#include "dxbc_defs.h"
|
||||||
#include "dxbc_enums.h"
|
#include "dxbc_enums.h"
|
||||||
#include "dxbc_names.h"
|
#include "dxbc_names.h"
|
||||||
|
|
||||||
namespace dxvk {
|
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
|
* \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:
|
public:
|
||||||
|
|
||||||
DxbcOpcodeControl() { }
|
DxbcCodeSlice(
|
||||||
DxbcOpcodeControl(uint32_t control)
|
const uint32_t* ptr,
|
||||||
: m_control(control) { }
|
const uint32_t* end)
|
||||||
|
: m_ptr(ptr), m_end(end) { }
|
||||||
|
|
||||||
/**
|
uint32_t at(uint32_t id) const;
|
||||||
* \brief Saturation hint
|
uint32_t read();
|
||||||
*
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
DxbcCodeSlice take(uint32_t n) const;
|
||||||
* \brief Precision hint
|
DxbcCodeSlice skip(uint32_t n) const;
|
||||||
*/
|
|
||||||
bool preciseBit() const {
|
|
||||||
return bit::extract(m_control, 8, 11) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
bool atEnd() const {
|
||||||
* \brief Zero test
|
return m_ptr == m_end;
|
||||||
*
|
|
||||||
* 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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
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.
|
* Stores data that is required to decode a single
|
||||||
* This encodes the actual op code, the length of the
|
* instruction. This data is not persistent, so it
|
||||||
* entire instruction in DWORDs, as well as some flags
|
* should be forwarded to the compiler right away.
|
||||||
* controlling the specific instruction.
|
|
||||||
*/
|
*/
|
||||||
class DxbcOpcodeToken {
|
class DxbcDecodeContext {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
DxbcOpcodeToken() { }
|
|
||||||
DxbcOpcodeToken(uint32_t token)
|
|
||||||
: m_token(token) { }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Opcode
|
* \brief Retrieves current instruction
|
||||||
* \returns Opcode
|
|
||||||
*/
|
|
||||||
DxbcOpcode opcode() const {
|
|
||||||
return static_cast<DxbcOpcode>(
|
|
||||||
bit::extract(m_token, 0, 10));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Control info
|
|
||||||
*
|
*
|
||||||
* Instruction-specific control info. Undefined
|
* This is only valid after a call to \ref decode.
|
||||||
* if the opcode is \c DxbcOpcode::CustomData.
|
* \returns Reference to last decoded instruction
|
||||||
* \returns Control info
|
|
||||||
*/
|
*/
|
||||||
uint32_t control() const {
|
const DxbcShaderInstruction& getInstruction() const {
|
||||||
return bit::extract(m_token, 11, 23);
|
return m_instruction;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Instruction length
|
* \brief Decodes an instruction
|
||||||
*
|
*
|
||||||
* Undefind if the opcode is \c DxbcOpcode::CustomData.
|
* This also advances the given code slice by the
|
||||||
* In that case, the instruction length will be stored
|
* number of dwords consumed by the instruction.
|
||||||
* in the DWORD immediately following the opcode token.
|
* \param [in] code Code slice
|
||||||
* \returns Instruction length, in DWORDs
|
|
||||||
*/
|
*/
|
||||||
uint32_t length() const {
|
void decodeInstruction(DxbcCodeSlice& code);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
uint32_t m_token = 0;
|
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;
|
||||||
* \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 {
|
|
||||||
|
|
||||||
public:
|
// Index into the indices array. Used when decoding
|
||||||
|
// instruction operands with relative indexing.
|
||||||
|
uint32_t m_indexId = 0;
|
||||||
|
|
||||||
DxbcOpcodeTokenExt() { }
|
void decodeCustomData(DxbcCodeSlice code);
|
||||||
DxbcOpcodeTokenExt(uint32_t token)
|
void decodeOperation(DxbcCodeSlice code);
|
||||||
: m_token(token) { }
|
|
||||||
|
|
||||||
/**
|
void decodeComponentSelection(DxbcRegister& reg, uint32_t token);
|
||||||
* \brief Extended opcode
|
void decodeOperandExtensions(DxbcCodeSlice& code, DxbcRegister& reg, uint32_t token);
|
||||||
* \returns Extended opcode
|
void decodeOperandImmediates(DxbcCodeSlice& code, DxbcRegister& reg);
|
||||||
*/
|
void decodeOperandIndex(DxbcCodeSlice& code, DxbcRegister& reg, uint32_t token);
|
||||||
DxbcExtOpcode opcode() const {
|
|
||||||
return static_cast<DxbcExtOpcode>(
|
|
||||||
bit::extract(m_token, 0, 5));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
void decodeRegister(DxbcCodeSlice& code, DxbcRegister& reg, DxbcScalarType type);
|
||||||
* \brief Control info
|
void decodeImm32(DxbcCodeSlice& code, DxbcImmediate& imm, DxbcScalarType type);
|
||||||
*
|
|
||||||
* 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 decodeOperand(DxbcCodeSlice& code, const DxbcInstOperandFormat& format);
|
||||||
* \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;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -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);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
@ -436,14 +436,6 @@ namespace dxvk {
|
|||||||
|
|
||||||
using DxbcGlobalFlags = Flags<DxbcGlobalFlag>;
|
using DxbcGlobalFlags = Flags<DxbcGlobalFlag>;
|
||||||
|
|
||||||
|
|
||||||
enum class DxbcOperandModifier : uint32_t {
|
|
||||||
Neg = 0,
|
|
||||||
Abs = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
using DxbcOperandModifiers = Flags<DxbcOperandModifier>;
|
|
||||||
|
|
||||||
enum class DxbcZeroTest : uint32_t {
|
enum class DxbcZeroTest : uint32_t {
|
||||||
TestZ = 0,
|
TestZ = 0,
|
||||||
TestNz = 1,
|
TestNz = 1,
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
#include "dxbc_compiler.h"
|
#include "dxbc_compiler.h"
|
||||||
#include "dxbc_compiler_2.h"
|
|
||||||
#include "dxbc_module.h"
|
#include "dxbc_module.h"
|
||||||
|
|
||||||
namespace dxvk {
|
namespace dxvk {
|
||||||
@ -47,7 +46,7 @@ namespace dxvk {
|
|||||||
|
|
||||||
DxbcCodeSlice slice = m_shexChunk->slice();
|
DxbcCodeSlice slice = m_shexChunk->slice();
|
||||||
|
|
||||||
DxbcCompiler2 compiler(
|
DxbcCompiler compiler(
|
||||||
m_shexChunk->version(),
|
m_shexChunk->version(),
|
||||||
m_isgnChunk, m_osgnChunk);
|
m_isgnChunk, m_osgnChunk);
|
||||||
|
|
||||||
|
@ -3,10 +3,8 @@ dxbc_src = files([
|
|||||||
'dxbc_chunk_shex.cpp',
|
'dxbc_chunk_shex.cpp',
|
||||||
'dxbc_common.cpp',
|
'dxbc_common.cpp',
|
||||||
'dxbc_compiler.cpp',
|
'dxbc_compiler.cpp',
|
||||||
'dxbc_compiler_2.cpp',
|
|
||||||
'dxbc_defs.cpp',
|
'dxbc_defs.cpp',
|
||||||
'dxbc_decoder.cpp',
|
'dxbc_decoder.cpp',
|
||||||
'dxbc_decoder_2.cpp',
|
|
||||||
'dxbc_header.cpp',
|
'dxbc_header.cpp',
|
||||||
'dxbc_module.cpp',
|
'dxbc_module.cpp',
|
||||||
'dxbc_names.cpp',
|
'dxbc_names.cpp',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user