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_decoder.h"
|
||||
#include "dxbc_decoder_2.h"
|
||||
#include "dxbc_reader.h"
|
||||
|
||||
namespace dxvk {
|
||||
@ -30,14 +29,6 @@ namespace dxvk {
|
||||
m_code.data() + m_code.size());
|
||||
}
|
||||
|
||||
DxbcDecoder begin() const {
|
||||
return DxbcDecoder(m_code.data(), m_code.size());
|
||||
}
|
||||
|
||||
DxbcDecoder end() const {
|
||||
return DxbcDecoder();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
DxbcProgramVersion m_version;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,133 +1,84 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
#include "../spirv/spirv_module.h"
|
||||
|
||||
#include "dxbc_chunk_isgn.h"
|
||||
#include "dxbc_decoder.h"
|
||||
#include "dxbc_defs.h"
|
||||
#include "dxbc_names.h"
|
||||
#include "dxbc_util.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief Expression value
|
||||
* \brief Vector type
|
||||
*
|
||||
* Tracks the type and the SPIR-V variable
|
||||
* ID when evaluating DXBC instructions.
|
||||
* Convenience struct that stores a scalar
|
||||
* type and a component count. The compiler
|
||||
* can use this to generate SPIR-V types.
|
||||
*/
|
||||
struct DxbcValue {
|
||||
DxbcScalarType componentType = DxbcScalarType::Float32;
|
||||
uint32_t componentCount = 0;
|
||||
uint32_t valueId = 0;
|
||||
struct DxbcVectorType {
|
||||
DxbcScalarType ctype;
|
||||
uint32_t ccount;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Variable pointer
|
||||
* \brief Register info
|
||||
*
|
||||
* Stores the SPIR-V pointer ID and the
|
||||
* type of the referenced variable. Used
|
||||
* to access variables and resources.
|
||||
* Stores the vector type of a register and
|
||||
* its storage class. The compiler can use
|
||||
* this to generate SPIR-V pointer types.
|
||||
*/
|
||||
struct DxbcPointer {
|
||||
DxbcScalarType componentType = DxbcScalarType::Float32;
|
||||
uint32_t componentCount = 0;
|
||||
uint32_t pointerId = 0;
|
||||
struct DxbcRegisterInfo {
|
||||
DxbcVectorType type;
|
||||
spv::StorageClass sclass;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Compiler error code
|
||||
* \brief Register value
|
||||
*
|
||||
* Helps identify the type of error
|
||||
* that may occur during compilation.
|
||||
* Stores a vector type and a SPIR-V ID that
|
||||
* represents an intermediate value. This is
|
||||
* used to track the type of such values.
|
||||
*/
|
||||
enum class DxbcError {
|
||||
sOk,
|
||||
eInternal,
|
||||
eInstructionFormat,
|
||||
eInvalidOperand,
|
||||
eInvalidOperandIndex,
|
||||
eTypeMismatch,
|
||||
eUnhandledOpcode,
|
||||
eUnsupported,
|
||||
struct DxbcRegisterValue {
|
||||
DxbcVectorType type;
|
||||
uint32_t id;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Operand index type
|
||||
* \brief Register pointer
|
||||
*
|
||||
* Defines whether a register index
|
||||
* is relative or constant.
|
||||
* Stores a vector type and a SPIR-V ID that
|
||||
* represents a pointer to such a vector. This
|
||||
* can be used to load registers conveniently.
|
||||
*/
|
||||
enum class DxbcIndexType {
|
||||
Immediate, ///< Index is a constant value
|
||||
Relative, ///< Index depends on a r# register
|
||||
struct DxbcRegisterPointer {
|
||||
DxbcVectorType type;
|
||||
uint32_t id;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Instruction operand index
|
||||
*
|
||||
* Stores the type of the index as well as the
|
||||
* register (if relative) and the constant offset.
|
||||
* \brief Vertex shader-specific structure
|
||||
*/
|
||||
struct DxbcInstOpIndex {
|
||||
DxbcIndexType type = DxbcIndexType::Immediate;
|
||||
uint32_t immediate = 0;
|
||||
uint32_t tempRegId = 0;
|
||||
uint32_t tempRegComponent = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Instruction operand
|
||||
*
|
||||
* Stores all information about a single
|
||||
* operand, including the register index.
|
||||
*/
|
||||
struct DxbcInstOp {
|
||||
DxbcOperandType type = DxbcOperandType::Temp;
|
||||
DxbcOperandModifiers modifiers = 0;
|
||||
uint32_t immediates[4] = { 0u, 0u, 0u, 0u };
|
||||
|
||||
uint32_t indexDim = 0;
|
||||
DxbcInstOpIndex index[3];
|
||||
|
||||
uint32_t componentCount = 0;
|
||||
DxbcRegMode componentMode = DxbcRegMode::Mask;
|
||||
|
||||
DxbcRegMask mask = { false, false, false, false };
|
||||
DxbcRegSwizzle swizzle = { 0, 0, 0, 0 };
|
||||
uint32_t select1 = 0;
|
||||
struct DxbcCompilerVsPart {
|
||||
uint32_t functionId;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Decoded instruction
|
||||
*
|
||||
* Stores all information about a single
|
||||
* instruction, including its operands.
|
||||
* \brief Pixel shader-specific structure
|
||||
*/
|
||||
struct DxbcInst {
|
||||
DxbcOpcode opcode = DxbcOpcode::Nop;
|
||||
DxbcOpcodeControl control = 0;
|
||||
DxbcInstFormat format;
|
||||
DxbcInstOp operands[DxbcMaxOperandCount];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Vertex shader-specific data
|
||||
*/
|
||||
struct DxbcVsSpecifics {
|
||||
uint32_t functionId = 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Pixel shader-specific data
|
||||
*/
|
||||
struct DxbcPsSpecifics {
|
||||
uint32_t functionId = 0;
|
||||
|
||||
std::array<DxbcPointer, DxbcMaxInterfaceRegs> oregs;
|
||||
struct DxbcCompilerPsPart {
|
||||
uint32_t functionId;
|
||||
std::array<DxbcVectorType, DxbcMaxInterfaceRegs> oTypes;
|
||||
};
|
||||
|
||||
|
||||
@ -150,12 +101,10 @@ namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief Processes a single instruction
|
||||
*
|
||||
* \param [in] ins The instruction
|
||||
* \returns An error code, or \c sOK
|
||||
*/
|
||||
DxbcError processInstruction(
|
||||
const DxbcInstruction& ins);
|
||||
void processInstruction(
|
||||
const DxbcShaderInstruction& ins);
|
||||
|
||||
/**
|
||||
* \brief Finalizes the shader
|
||||
@ -184,12 +133,14 @@ namespace dxvk {
|
||||
// v# registers as defined by the shader. The type of each
|
||||
// of these inputs is either float4 or an array of float4.
|
||||
std::array<uint32_t, DxbcMaxInterfaceRegs> m_vRegs;
|
||||
std::vector<DxbcSvMapping> m_vMappings;
|
||||
|
||||
//////////////////////////////////////////////////////////
|
||||
// o# registers as defined by the shader. In the fragment
|
||||
// shader stage, these registers are typed by the signature,
|
||||
// in all other stages, they are float4 registers or arrays.
|
||||
std::array<uint32_t, DxbcMaxInterfaceRegs> m_oRegs;
|
||||
std::vector<DxbcSvMapping> m_oMappings;
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// Shader resource variables. These provide access to
|
||||
@ -198,12 +149,6 @@ namespace dxvk {
|
||||
std::array<DxbcSampler, 16> m_samplers;
|
||||
std::array<DxbcShaderResource, 128> m_textures;
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
// Input/Output system value mappings. These will need
|
||||
// to be set up before or after the main function runs.
|
||||
std::vector<DxbcSvMapping> m_vSvs;
|
||||
std::vector<DxbcSvMapping> m_oSvs;
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// Array of input values. Since v# registers are indexable
|
||||
// in DXBC, we need to copy them into an array first.
|
||||
@ -221,190 +166,185 @@ namespace dxvk {
|
||||
std::vector<uint32_t> m_entryPointInterfaces;
|
||||
uint32_t m_entryPointId = 0;
|
||||
|
||||
////////////////////////////////////////
|
||||
// Data structures for each shader type
|
||||
DxbcVsSpecifics m_vs;
|
||||
DxbcPsSpecifics m_ps;
|
||||
///////////////////////////////////
|
||||
// Shader-specific data structures
|
||||
DxbcCompilerVsPart m_vs;
|
||||
DxbcCompilerPsPart m_ps;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
// Shader interface and metadata declaration methods
|
||||
void emitDclGlobalFlags(
|
||||
const DxbcShaderInstruction& ins);
|
||||
|
||||
void emitDclTemps(
|
||||
const DxbcShaderInstruction& ins);
|
||||
|
||||
void emitDclInterfaceReg(
|
||||
const DxbcShaderInstruction& ins);
|
||||
|
||||
void emitDclInput(
|
||||
uint32_t regIdx,
|
||||
uint32_t regDim,
|
||||
DxbcRegMask regMask,
|
||||
DxbcSystemValue sv,
|
||||
DxbcInterpolationMode im);
|
||||
|
||||
void emitDclOutput(
|
||||
uint32_t regIdx,
|
||||
uint32_t regDim,
|
||||
DxbcRegMask regMask,
|
||||
DxbcSystemValue sv,
|
||||
DxbcInterpolationMode im);
|
||||
|
||||
void emitDclConstantBuffer(
|
||||
const DxbcShaderInstruction& ins);
|
||||
|
||||
void emitDclSampler(
|
||||
const DxbcShaderInstruction& ins);
|
||||
|
||||
void emitDclResource(
|
||||
const DxbcShaderInstruction& ins);
|
||||
|
||||
//////////////////////////////
|
||||
// Instruction class handlers
|
||||
DxbcError handleDeclaration(
|
||||
const DxbcInst& ins);
|
||||
void emitVectorAlu(
|
||||
const DxbcShaderInstruction& ins);
|
||||
|
||||
DxbcError handleControlFlow(
|
||||
const DxbcInst& ins);
|
||||
void emitVectorCmov(
|
||||
const DxbcShaderInstruction& ins);
|
||||
|
||||
DxbcError handleTextureSample(
|
||||
const DxbcInst& ins);
|
||||
void emitVectorCmp(
|
||||
const DxbcShaderInstruction& ins);
|
||||
|
||||
DxbcError handleVectorAlu(
|
||||
const DxbcInst& ins);
|
||||
void emitVectorDot(
|
||||
const DxbcShaderInstruction& ins);
|
||||
|
||||
DxbcError handleVectorCmov(
|
||||
const DxbcInst& ins);
|
||||
void emitVectorImul(
|
||||
const DxbcShaderInstruction& ins);
|
||||
|
||||
DxbcError handleVectorCmp(
|
||||
const DxbcInst& ins);
|
||||
void emitVectorSinCos(
|
||||
const DxbcShaderInstruction& ins);
|
||||
|
||||
DxbcError handleVectorDot(
|
||||
const DxbcInst& ins);
|
||||
void emitSample(
|
||||
const DxbcShaderInstruction& ins);
|
||||
|
||||
DxbcError handleVectorSinCos(
|
||||
const DxbcInst& ins);
|
||||
void emitRet(
|
||||
const DxbcShaderInstruction& ins);
|
||||
|
||||
///////////////////////
|
||||
// Declaration methods
|
||||
DxbcError declareGlobalFlags(
|
||||
const DxbcInst& ins);
|
||||
|
||||
DxbcError declareTemps(
|
||||
const DxbcInst& ins);
|
||||
/////////////////////////////////////////
|
||||
// Generic register manipulation methods
|
||||
DxbcRegisterValue emitRegisterBitcast(
|
||||
DxbcRegisterValue srcValue,
|
||||
DxbcScalarType dstType);
|
||||
|
||||
DxbcError declareInterfaceVar(
|
||||
const DxbcInst& ins);
|
||||
DxbcRegisterValue emitRegisterSwizzle(
|
||||
DxbcRegisterValue value,
|
||||
DxbcRegSwizzle swizzle,
|
||||
DxbcRegMask writeMask);
|
||||
|
||||
DxbcError declareConstantBuffer(
|
||||
const DxbcInst& ins);
|
||||
DxbcRegisterValue emitRegisterExtract(
|
||||
DxbcRegisterValue value,
|
||||
DxbcRegMask mask);
|
||||
|
||||
DxbcError declareSampler(
|
||||
const DxbcInst& ins);
|
||||
DxbcRegisterValue emitRegisterInsert(
|
||||
DxbcRegisterValue dstValue,
|
||||
DxbcRegisterValue srcValue,
|
||||
DxbcRegMask srcMask);
|
||||
|
||||
DxbcError declareResource(
|
||||
const DxbcInst& ins);
|
||||
DxbcRegisterValue emitRegisterExtend(
|
||||
DxbcRegisterValue value,
|
||||
uint32_t size);
|
||||
|
||||
DxbcError declareInputVar(
|
||||
uint32_t regId,
|
||||
uint32_t regDim,
|
||||
DxbcRegMask regMask,
|
||||
DxbcSystemValue sv,
|
||||
DxbcInterpolationMode im);
|
||||
DxbcRegisterValue emitRegisterAbsolute(
|
||||
DxbcRegisterValue value);
|
||||
|
||||
DxbcError declareOutputVar(
|
||||
uint32_t regId,
|
||||
uint32_t regDim,
|
||||
DxbcRegMask regMask,
|
||||
DxbcSystemValue sv,
|
||||
DxbcInterpolationMode im);
|
||||
DxbcRegisterValue emitRegisterNegate(
|
||||
DxbcRegisterValue value);
|
||||
|
||||
////////////////////////////////////
|
||||
// Register manipulation operations
|
||||
DxbcValue bitcastReg(
|
||||
const DxbcValue& src,
|
||||
DxbcScalarType type);
|
||||
DxbcRegisterValue emitSrcOperandModifiers(
|
||||
DxbcRegisterValue value,
|
||||
DxbcRegModifiers modifiers);
|
||||
|
||||
DxbcValue insertReg(
|
||||
const DxbcValue& dst,
|
||||
const DxbcValue& src,
|
||||
DxbcRegMask mask);
|
||||
DxbcRegisterValue emitDstOperandModifiers(
|
||||
DxbcRegisterValue value,
|
||||
DxbcOpModifiers modifiers);
|
||||
|
||||
DxbcValue extractReg(
|
||||
const DxbcValue& src,
|
||||
DxbcRegMask mask);
|
||||
////////////////////////
|
||||
// Address load methods
|
||||
DxbcRegisterPointer emitGetTempPtr(
|
||||
const DxbcRegister& operand);
|
||||
|
||||
DxbcValue swizzleReg(
|
||||
const DxbcValue& src,
|
||||
const DxbcRegSwizzle& swizzle,
|
||||
DxbcRegMask mask);
|
||||
DxbcRegisterPointer emitGetInputPtr(
|
||||
const DxbcRegister& operand);
|
||||
|
||||
DxbcValue regVector(
|
||||
const DxbcValue& src,
|
||||
uint32_t size);
|
||||
DxbcRegisterPointer emitGetOutputPtr(
|
||||
const DxbcRegister& operand);
|
||||
|
||||
DxbcValue extendReg(
|
||||
const DxbcValue& src,
|
||||
uint32_t size);
|
||||
DxbcRegisterPointer emitGetConstBufPtr(
|
||||
const DxbcRegister& operand);
|
||||
|
||||
////////////////////////////
|
||||
// Operand modifier methods
|
||||
DxbcValue applyOperandModifiers(
|
||||
DxbcValue value,
|
||||
DxbcOperandModifiers modifiers);
|
||||
DxbcRegisterPointer emitGetOperandPtr(
|
||||
const DxbcRegister& operand);
|
||||
|
||||
DxbcValue applyResultModifiers(
|
||||
DxbcValue value,
|
||||
DxbcOpcodeControl control);
|
||||
//////////////////////////////
|
||||
// Operand load/store methods
|
||||
DxbcRegisterValue emitIndexLoad(
|
||||
DxbcRegIndex index);
|
||||
|
||||
/////////////////////////
|
||||
// Load/Store operations
|
||||
DxbcValue loadOp(
|
||||
const DxbcInstOp& srcOp,
|
||||
DxbcRegMask srcMask,
|
||||
DxbcScalarType dstType);
|
||||
DxbcRegisterValue emitValueLoad(
|
||||
DxbcRegisterPointer ptr);
|
||||
|
||||
DxbcValue loadImm32(
|
||||
const DxbcInstOp& srcOp,
|
||||
DxbcRegMask srcMask,
|
||||
DxbcScalarType dstType);
|
||||
void emitValueStore(
|
||||
DxbcRegisterPointer ptr,
|
||||
DxbcRegisterValue value,
|
||||
DxbcRegMask writeMask);
|
||||
|
||||
DxbcValue loadRegister(
|
||||
const DxbcInstOp& srcOp,
|
||||
DxbcRegMask srcMask,
|
||||
DxbcScalarType dstType);
|
||||
DxbcRegisterValue emitRegisterLoad(
|
||||
const DxbcRegister& reg,
|
||||
DxbcRegMask writeMask);
|
||||
|
||||
void storeOp(
|
||||
const DxbcInstOp& dstOp,
|
||||
const DxbcValue& srcValue);
|
||||
|
||||
DxbcValue loadPtr(
|
||||
const DxbcPointer& ptr);
|
||||
|
||||
void storePtr(
|
||||
const DxbcPointer& ptr,
|
||||
const DxbcValue& value,
|
||||
DxbcRegMask mask);
|
||||
|
||||
DxbcValue loadIndex(
|
||||
const DxbcInstOpIndex& idx);
|
||||
|
||||
///////////////////////////
|
||||
// Operand pointer methods
|
||||
DxbcPointer getOperandPtr(
|
||||
const DxbcInstOp& op);
|
||||
|
||||
DxbcPointer getConstantBufferPtr(
|
||||
const DxbcInstOp& op);
|
||||
|
||||
/////////////////////////////////
|
||||
// Shader initialization methods
|
||||
void beginVertexShader(const Rc<DxbcIsgn>& isgn);
|
||||
void beginPixelShader (const Rc<DxbcIsgn>& osgn);
|
||||
void emitRegisterStore(
|
||||
const DxbcRegister& reg,
|
||||
DxbcRegisterValue value);
|
||||
|
||||
/////////////////////////////
|
||||
// Input preparation methods
|
||||
void prepareVertexInputs();
|
||||
void preparePixelInputs();
|
||||
void emitVsInputSetup();
|
||||
void emitPsInputSetup();
|
||||
|
||||
//////////////////////////////
|
||||
// Output preparation methods
|
||||
void prepareVertexOutputs();
|
||||
void preparePixelOutputs();
|
||||
void emitVsOutputSetup();
|
||||
void emitPsOutputSetup();
|
||||
|
||||
/////////////////////////////////
|
||||
// Shader initialization methods
|
||||
void emitVsInit();
|
||||
void emitPsInit();
|
||||
|
||||
///////////////////////////////
|
||||
// Shader finalization methods
|
||||
void endVertexShader();
|
||||
void endPixelShader();
|
||||
void emitVsFinalize();
|
||||
void emitPsFinalize();
|
||||
|
||||
///////////////////////////////
|
||||
// Variable definition methods
|
||||
uint32_t emitNewVariable(
|
||||
const DxbcRegisterInfo& info);
|
||||
|
||||
///////////////////////////
|
||||
// Type definition methods
|
||||
uint32_t definePerVertexBlock();
|
||||
uint32_t getScalarTypeId(
|
||||
DxbcScalarType type);
|
||||
|
||||
uint32_t defineScalarType(
|
||||
DxbcScalarType componentType);
|
||||
uint32_t getVectorTypeId(
|
||||
const DxbcVectorType& type);
|
||||
|
||||
uint32_t defineVectorType(
|
||||
DxbcScalarType componentType,
|
||||
uint32_t componentCount);
|
||||
uint32_t getPointerTypeId(
|
||||
const DxbcRegisterInfo& type);
|
||||
|
||||
uint32_t definePointerType(
|
||||
DxbcScalarType componentType,
|
||||
uint32_t componentCount,
|
||||
spv::StorageClass storageClass);
|
||||
|
||||
/////////////////////////
|
||||
// DXBC decoding methods
|
||||
DxbcError parseInstruction(
|
||||
const DxbcInstruction& ins,
|
||||
DxbcInst& out);
|
||||
uint32_t getPerVertexBlockId();
|
||||
|
||||
};
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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 {
|
||||
|
||||
DxbcCodeReader& DxbcCodeReader::operator ++ () {
|
||||
return this->operator += (1);
|
||||
uint32_t DxbcCodeSlice::at(uint32_t id) const {
|
||||
if (m_ptr + id >= m_end)
|
||||
throw DxvkError("DxbcCodeSlice: End of stream");
|
||||
return m_ptr[id];
|
||||
}
|
||||
|
||||
|
||||
DxbcCodeReader& DxbcCodeReader::operator += (uint32_t n) {
|
||||
if (n < m_size) {
|
||||
m_code += n;
|
||||
m_size -= n;
|
||||
} else {
|
||||
m_code = nullptr;
|
||||
m_size = 0;
|
||||
}
|
||||
return *this;
|
||||
uint32_t DxbcCodeSlice::read() {
|
||||
if (m_ptr >= m_end)
|
||||
throw DxvkError("DxbcCodeSlice: End of stream");
|
||||
return *(m_ptr++);
|
||||
}
|
||||
|
||||
|
||||
DxbcCodeReader DxbcCodeReader::operator + (uint32_t n) const {
|
||||
return n < m_size
|
||||
? DxbcCodeReader(m_code + n, m_size - n)
|
||||
: DxbcCodeReader();
|
||||
DxbcCodeSlice DxbcCodeSlice::take(uint32_t n) const {
|
||||
if (m_ptr + n > m_end)
|
||||
throw DxvkError("DxbcCodeSlice: End of stream");
|
||||
return DxbcCodeSlice(m_ptr, m_ptr + n);
|
||||
}
|
||||
|
||||
|
||||
bool DxbcCodeReader::operator == (const DxbcCodeReader& other) const {
|
||||
return m_code == other.m_code && m_size == other.m_size;
|
||||
DxbcCodeSlice DxbcCodeSlice::skip(uint32_t n) const {
|
||||
if (m_ptr + n > m_end)
|
||||
throw DxvkError("DxbcCodeSlice: End of stream");
|
||||
return DxbcCodeSlice(m_ptr + n, m_end);
|
||||
}
|
||||
|
||||
|
||||
bool DxbcCodeReader::operator != (const DxbcCodeReader& other) const {
|
||||
return !this->operator == (other);
|
||||
}
|
||||
|
||||
|
||||
uint32_t DxbcOperandIndex::length() const {
|
||||
switch (m_rep) {
|
||||
case DxbcOperandIndexRepresentation::Imm32: return 1;
|
||||
case DxbcOperandIndexRepresentation::Imm64: return 2;
|
||||
case DxbcOperandIndexRepresentation::Relative: return this->relPart().length();
|
||||
case DxbcOperandIndexRepresentation::Imm32Relative: return this->relPart().length() + 1;
|
||||
case DxbcOperandIndexRepresentation::Imm64Relative: return this->relPart().length() + 2;
|
||||
}
|
||||
void DxbcDecodeContext::decodeInstruction(DxbcCodeSlice& code) {
|
||||
const uint32_t token0 = code.at(0);
|
||||
|
||||
throw DxvkError(str::format("DXBC: Unknown index representation: ", m_rep));
|
||||
}
|
||||
|
||||
|
||||
bool DxbcOperandIndex::hasImmPart() const {
|
||||
return m_rep == DxbcOperandIndexRepresentation::Imm32
|
||||
|| m_rep == DxbcOperandIndexRepresentation::Imm64
|
||||
|| m_rep == DxbcOperandIndexRepresentation::Imm32Relative
|
||||
|| m_rep == DxbcOperandIndexRepresentation::Imm64Relative;
|
||||
}
|
||||
|
||||
|
||||
bool DxbcOperandIndex::hasRelPart() const {
|
||||
return m_rep == DxbcOperandIndexRepresentation::Relative
|
||||
|| m_rep == DxbcOperandIndexRepresentation::Imm32Relative
|
||||
|| m_rep == DxbcOperandIndexRepresentation::Imm64Relative;
|
||||
}
|
||||
|
||||
|
||||
uint64_t DxbcOperandIndex::immPart() const {
|
||||
switch (m_rep) {
|
||||
case DxbcOperandIndexRepresentation::Imm32:
|
||||
case DxbcOperandIndexRepresentation::Imm32Relative:
|
||||
return m_code.getWord(0);
|
||||
|
||||
case DxbcOperandIndexRepresentation::Imm64:
|
||||
case DxbcOperandIndexRepresentation::Imm64Relative:
|
||||
return (static_cast<uint64_t>(m_code.getWord(0)) << 32)
|
||||
| (static_cast<uint64_t>(m_code.getWord(1)));
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DxbcOperand DxbcOperandIndex::relPart() const {
|
||||
switch (m_rep) {
|
||||
case DxbcOperandIndexRepresentation::Relative:
|
||||
return DxbcOperand(m_code);
|
||||
|
||||
case DxbcOperandIndexRepresentation::Imm32Relative:
|
||||
return DxbcOperand(m_code + 1);
|
||||
|
||||
case DxbcOperandIndexRepresentation::Imm64Relative:
|
||||
return DxbcOperand(m_code + 2);
|
||||
|
||||
default:
|
||||
throw DxvkError("DXBC: Operand index is not relative");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DxbcOperand::DxbcOperand(const DxbcCodeReader& code)
|
||||
: m_info(code) {
|
||||
const DxbcOperandToken token(m_info.getWord(0));
|
||||
// Initialize the instruction structure. Some of these values
|
||||
// may not get written otherwise while decoding the instruction.
|
||||
m_instruction.op = static_cast<DxbcOpcode>(bit::extract(token0, 0, 10));
|
||||
m_instruction.sampleControls = { 0, 0, 0 };
|
||||
m_instruction.dstCount = 0;
|
||||
m_instruction.srcCount = 0;
|
||||
m_instruction.immCount = 0;
|
||||
m_instruction.dst = m_dstOperands.data();
|
||||
m_instruction.src = m_srcOperands.data();
|
||||
m_instruction.imm = m_immOperands.data();
|
||||
|
||||
uint32_t numTokens = 1;
|
||||
// Reset the index pointer, which may still contain
|
||||
// a non-zero value from the previous iteration
|
||||
m_indexId = 0;
|
||||
|
||||
// Count extended operand tokens
|
||||
if (token.isExtended()) {
|
||||
while (DxbcOperandTokenExt(m_info.getWord(numTokens++)).isExtended())
|
||||
continue;
|
||||
}
|
||||
|
||||
m_data = m_info + numTokens;
|
||||
|
||||
// Immediate operands
|
||||
// Instruction length, in DWORDs. This includes the token
|
||||
// itself and any other prefix that an instruction may have.
|
||||
uint32_t length = 0;
|
||||
|
||||
if (token.type() == DxbcOperandType::Imm32
|
||||
|| token.type() == DxbcOperandType::Imm64)
|
||||
length += token.numComponents();
|
||||
|
||||
// Indices into the register file, may contain additional operands
|
||||
for (uint32_t i = 0; i < token.indexDimension(); i++) {
|
||||
m_indexOffsets[i] = length;
|
||||
length += this->index(i).length();
|
||||
}
|
||||
|
||||
m_length = length + numTokens;
|
||||
}
|
||||
|
||||
|
||||
DxbcOperandIndex DxbcOperand::index(uint32_t dim) const {
|
||||
return DxbcOperandIndex(
|
||||
m_data + m_indexOffsets.at(dim),
|
||||
this->token().indexRepresentation(dim));
|
||||
}
|
||||
|
||||
|
||||
bool DxbcOperand::queryOperandExt(DxbcOperandExt ext, DxbcOperandTokenExt& token) const {
|
||||
if (!this->token().isExtended())
|
||||
return false;
|
||||
|
||||
uint32_t extTokenId = 1;
|
||||
DxbcOperandTokenExt extToken;
|
||||
|
||||
do {
|
||||
extToken = m_info.getWord(extTokenId++);
|
||||
|
||||
if (extToken.type() == ext) {
|
||||
token = extToken;
|
||||
return true;
|
||||
}
|
||||
} while (extToken.isExtended());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
DxbcInstruction::DxbcInstruction(const DxbcCodeReader& code)
|
||||
: m_op(code) {
|
||||
DxbcOpcodeToken token(m_op.getWord(0));
|
||||
|
||||
if (token.opcode() == DxbcOpcode::CustomData) {
|
||||
// Custom data blocks have a special format,
|
||||
// the length is stored in a separate DWORD
|
||||
m_args = m_op + 2;
|
||||
if (m_instruction.op == DxbcOpcode::CustomData) {
|
||||
length = code.at(1);
|
||||
this->decodeCustomData(code.take(length));
|
||||
} else {
|
||||
// For normal instructions, we just count
|
||||
// the number of extended opcode tokens.
|
||||
uint32_t numOpcodeTokens = 1;
|
||||
length = bit::extract(token0, 24, 30);
|
||||
this->decodeOperation(code.take(length));
|
||||
}
|
||||
|
||||
// Advance the caller's slice to the next token so that
|
||||
// they can make consecutive calls to decodeInstruction()
|
||||
code = code.skip(length);
|
||||
}
|
||||
|
||||
|
||||
void DxbcDecodeContext::decodeCustomData(DxbcCodeSlice code) {
|
||||
Logger::warn("DxbcDecodeContext::decodeCustomData: Not implemented");
|
||||
}
|
||||
|
||||
|
||||
void DxbcDecodeContext::decodeOperation(DxbcCodeSlice code) {
|
||||
uint32_t token = code.read();
|
||||
|
||||
// Result modifiers, which are applied to common ALU ops
|
||||
m_instruction.modifiers.saturate = !!bit::extract(token, 13, 13);
|
||||
m_instruction.modifiers.precise = !!bit::extract(token, 19, 22);
|
||||
|
||||
// Opcode controls. It will depend on the opcode itself which ones are valid.
|
||||
m_instruction.controls.zeroTest = static_cast<DxbcZeroTest> (bit::extract(token, 18, 18));
|
||||
m_instruction.controls.syncFlags = static_cast<DxbcSyncFlags> (bit::extract(token, 11, 14));
|
||||
m_instruction.controls.resourceDim = static_cast<DxbcResourceDim> (bit::extract(token, 11, 15));
|
||||
m_instruction.controls.resinfoType = static_cast<DxbcResinfoType> (bit::extract(token, 11, 12));
|
||||
m_instruction.controls.interpolation = static_cast<DxbcInterpolationMode>(bit::extract(token, 11, 14));
|
||||
|
||||
// Process extended opcode tokens
|
||||
while (bit::extract(token, 31, 31)) {
|
||||
token = code.read();
|
||||
|
||||
if (token.isExtended()) {
|
||||
numOpcodeTokens += 1;
|
||||
while (DxbcOpcodeTokenExt(m_op.getWord(numOpcodeTokens)).isExtended())
|
||||
numOpcodeTokens += 1;
|
||||
const DxbcExtOpcode extOpcode
|
||||
= static_cast<DxbcExtOpcode>(bit::extract(token, 0, 5));
|
||||
|
||||
switch (extOpcode) {
|
||||
case DxbcExtOpcode::SampleControls: {
|
||||
struct {
|
||||
int u : 4;
|
||||
int v : 4;
|
||||
int w : 4;
|
||||
} aoffimmi;
|
||||
|
||||
aoffimmi.u = bit::extract(token, 9, 12);
|
||||
aoffimmi.v = bit::extract(token, 13, 16);
|
||||
aoffimmi.w = bit::extract(token, 17, 20);
|
||||
|
||||
// Four-bit signed numbers, sign-extend them
|
||||
m_instruction.sampleControls.u = aoffimmi.u;
|
||||
m_instruction.sampleControls.v = aoffimmi.v;
|
||||
m_instruction.sampleControls.w = aoffimmi.w;
|
||||
} break;
|
||||
|
||||
default:
|
||||
Logger::warn(str::format(
|
||||
"DxbcDecodeContext: Unhandled extended opcode: ",
|
||||
extOpcode));
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve the instruction format in order to parse the
|
||||
// operands. Doing this mostly automatically means that
|
||||
// the compiler can rely on the operands being valid.
|
||||
const DxbcInstFormat format = dxbcInstructionFormat(m_instruction.op);
|
||||
|
||||
for (uint32_t i = 0; i < format.operandCount; i++)
|
||||
this->decodeOperand(code, format.operands[i]);
|
||||
}
|
||||
|
||||
|
||||
void DxbcDecodeContext::decodeComponentSelection(DxbcRegister& reg, uint32_t token) {
|
||||
// Pick the correct component selection mode based on the
|
||||
// component count. We'll simplify this here so that the
|
||||
// compiler can assume that everything is a 4D vector.
|
||||
reg.componentCount = static_cast<DxbcComponentCount>(bit::extract(token, 0, 1));
|
||||
|
||||
switch (reg.componentCount) {
|
||||
// No components - used for samplers etc.
|
||||
case DxbcComponentCount::Component0:
|
||||
reg.mask = DxbcRegMask(false, false, false, false);
|
||||
reg.swizzle = DxbcRegSwizzle(0, 0, 0, 0);
|
||||
break;
|
||||
|
||||
m_args = m_op + numOpcodeTokens;
|
||||
// One component - used for immediates
|
||||
// and a few built-in registers.
|
||||
case DxbcComponentCount::Component1:
|
||||
reg.mask = DxbcRegMask(true, false, false, false);
|
||||
reg.swizzle = DxbcRegSwizzle(0, 0, 0, 0);
|
||||
break;
|
||||
|
||||
// Four components - everything else. This requires us
|
||||
// to actually parse the component selection mode.
|
||||
case DxbcComponentCount::Component4: {
|
||||
const DxbcRegMode componentMode =
|
||||
static_cast<DxbcRegMode>(bit::extract(token, 2, 3));
|
||||
|
||||
switch (componentMode) {
|
||||
// Write mask for destination operands
|
||||
case DxbcRegMode::Mask:
|
||||
reg.mask = bit::extract(token, 4, 7);
|
||||
reg.swizzle = DxbcRegSwizzle(0, 1, 2, 3);
|
||||
break;
|
||||
|
||||
// Swizzle for source operands (including resources)
|
||||
case DxbcRegMode::Swizzle:
|
||||
reg.mask = DxbcRegMask(true, true, true, true);
|
||||
reg.swizzle = DxbcRegSwizzle(
|
||||
bit::extract(token, 4, 5),
|
||||
bit::extract(token, 6, 7),
|
||||
bit::extract(token, 8, 9),
|
||||
bit::extract(token, 10, 11));
|
||||
break;
|
||||
|
||||
// Selection of one component. We can generate both a
|
||||
// mask and a swizzle for this so that the compiler
|
||||
// won't have to deal with this case specifically.
|
||||
case DxbcRegMode::Select1: {
|
||||
const uint32_t n = bit::extract(token, 4, 5);
|
||||
reg.mask = DxbcRegMask(n == 0, n == 1, n == 2, n == 3);
|
||||
reg.swizzle = DxbcRegSwizzle(n, n, n, n);
|
||||
} break;
|
||||
|
||||
default:
|
||||
Logger::warn("DxbcDecodeContext: Invalid component selection mode");
|
||||
}
|
||||
} break;
|
||||
|
||||
default:
|
||||
Logger::warn("DxbcDecodeContext: Invalid component count");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t DxbcInstruction::length() const {
|
||||
auto token = this->token();
|
||||
return token.opcode() != DxbcOpcode::CustomData
|
||||
? token.length() : m_op.getWord(1);
|
||||
void DxbcDecodeContext::decodeOperandExtensions(DxbcCodeSlice& code, DxbcRegister& reg, uint32_t token) {
|
||||
while (bit::extract(token, 31, 31)) {
|
||||
token = code.read();
|
||||
|
||||
// Type of the extended operand token
|
||||
const DxbcOperandExt extTokenType =
|
||||
static_cast<DxbcOperandExt>(bit::extract(token, 0, 5));
|
||||
|
||||
switch (extTokenType) {
|
||||
// Operand modifiers, which are used to manipulate the
|
||||
// value of a source operand during the load operation
|
||||
case DxbcOperandExt::OperandModifier:
|
||||
reg.modifiers = bit::extract(token, 6, 13);
|
||||
break;
|
||||
|
||||
default:
|
||||
Logger::warn(str::format(
|
||||
"DxbcDecodeContext: Unhandled extended operand token: ",
|
||||
extTokenType));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool DxbcInstruction::queryOpcodeExt(DxbcExtOpcode extOpcode, DxbcOpcodeTokenExt& token) const {
|
||||
if (!this->token().isExtended())
|
||||
return false;
|
||||
|
||||
uint32_t extTokenId = 1;
|
||||
DxbcOpcodeTokenExt extToken;
|
||||
|
||||
do {
|
||||
extToken = m_op.getWord(extTokenId++);
|
||||
|
||||
if (extToken.opcode() == extOpcode) {
|
||||
token = extToken;
|
||||
return true;
|
||||
void DxbcDecodeContext::decodeOperandImmediates(DxbcCodeSlice& code, DxbcRegister& reg) {
|
||||
if (reg.type == DxbcOperandType::Imm32) {
|
||||
switch (reg.componentCount) {
|
||||
// This is commonly used if only one vector
|
||||
// component is involved in an operation
|
||||
case DxbcComponentCount::Component1: {
|
||||
reg.imm.u32_1 = code.read();
|
||||
} break;
|
||||
|
||||
// Typical four-component vector
|
||||
case DxbcComponentCount::Component4: {
|
||||
reg.imm.u32_4[0] = code.read();
|
||||
reg.imm.u32_4[1] = code.read();
|
||||
reg.imm.u32_4[2] = code.read();
|
||||
reg.imm.u32_4[3] = code.read();
|
||||
} break;
|
||||
|
||||
default:
|
||||
Logger::warn("DxbcDecodeContext: Invalid component count for immediate operand");
|
||||
}
|
||||
} while (extToken.isExtended());
|
||||
} else if (reg.type == DxbcOperandType::Imm64) {
|
||||
Logger::warn("DxbcDecodeContext: 64-bit immediates not supported");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DxbcDecodeContext::decodeOperandIndex(DxbcCodeSlice& code, DxbcRegister& reg, uint32_t token) {
|
||||
reg.idxDim = bit::extract(token, 20, 21);
|
||||
|
||||
return false;
|
||||
for (uint32_t i = 0; i < reg.idxDim; i++) {
|
||||
// An index can be encoded in various different ways
|
||||
const DxbcOperandIndexRepresentation repr =
|
||||
static_cast<DxbcOperandIndexRepresentation>(
|
||||
bit::extract(token, 22 + 3 * i, 24 + 3 * i));
|
||||
|
||||
switch (repr) {
|
||||
case DxbcOperandIndexRepresentation::Imm32:
|
||||
reg.idx[i].offset = static_cast<int32_t>(code.read());
|
||||
reg.idx[i].relReg = nullptr;
|
||||
break;
|
||||
|
||||
case DxbcOperandIndexRepresentation::Relative:
|
||||
reg.idx[i].offset = 0;
|
||||
reg.idx[i].relReg = &m_indices.at(m_indexId);
|
||||
|
||||
this->decodeRegister(code,
|
||||
m_indices.at(m_indexId++),
|
||||
DxbcScalarType::Sint32);
|
||||
break;
|
||||
|
||||
case DxbcOperandIndexRepresentation::Imm32Relative:
|
||||
reg.idx[i].offset = static_cast<int32_t>(code.read());
|
||||
reg.idx[i].relReg = &m_indices.at(m_indexId);
|
||||
|
||||
this->decodeRegister(code,
|
||||
m_indices.at(m_indexId++),
|
||||
DxbcScalarType::Sint32);
|
||||
break;
|
||||
|
||||
default:
|
||||
Logger::warn(str::format(
|
||||
"DxbcDecodeContext: Unhandled index representation: ",
|
||||
repr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DxbcDecodeContext::decodeRegister(DxbcCodeSlice& code, DxbcRegister& reg, DxbcScalarType type) {
|
||||
const uint32_t token = code.read();
|
||||
|
||||
reg.type = static_cast<DxbcOperandType>(bit::extract(token, 12, 19));
|
||||
reg.dataType = type;
|
||||
reg.modifiers = 0;
|
||||
reg.idxDim = 0;
|
||||
|
||||
for (uint32_t i = 0; i < DxbcMaxRegIndexDim; i++) {
|
||||
reg.idx[i].relReg = nullptr;
|
||||
reg.idx[i].offset = 0;
|
||||
}
|
||||
|
||||
this->decodeComponentSelection(reg, token);
|
||||
this->decodeOperandExtensions(code, reg, token);
|
||||
this->decodeOperandImmediates(code, reg);
|
||||
this->decodeOperandIndex(code, reg, token);
|
||||
}
|
||||
|
||||
|
||||
void DxbcDecodeContext::decodeImm32(DxbcCodeSlice& code, DxbcImmediate& imm, DxbcScalarType type) {
|
||||
imm.u32 = code.read();
|
||||
}
|
||||
|
||||
|
||||
void DxbcDecodeContext::decodeOperand(DxbcCodeSlice& code, const DxbcInstOperandFormat& format) {
|
||||
switch (format.kind) {
|
||||
case DxbcOperandKind::DstReg: {
|
||||
const uint32_t operandId = m_instruction.dstCount++;
|
||||
this->decodeRegister(code, m_dstOperands.at(operandId), format.type);
|
||||
} break;
|
||||
|
||||
case DxbcOperandKind::SrcReg: {
|
||||
const uint32_t operandId = m_instruction.srcCount++;
|
||||
this->decodeRegister(code, m_srcOperands.at(operandId), format.type);
|
||||
} break;
|
||||
|
||||
case DxbcOperandKind::Imm32: {
|
||||
const uint32_t operandId = m_instruction.immCount++;
|
||||
this->decodeImm32(code, m_immOperands.at(operandId), format.type);
|
||||
} break;
|
||||
|
||||
default:
|
||||
throw DxvkError("DxbcDecodeContext: Invalid operand format");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,13 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstring>
|
||||
#include <array>
|
||||
|
||||
#include "dxbc_common.h"
|
||||
#include "dxbc_decoder.h"
|
||||
#include "dxbc_defs.h"
|
||||
#include "dxbc_enums.h"
|
||||
#include "dxbc_names.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
class DxbcOperand;
|
||||
constexpr size_t DxbcMaxRegIndexDim = 3;
|
||||
|
||||
struct DxbcRegister;
|
||||
|
||||
/**
|
||||
* \brief Source operand modifiers
|
||||
*
|
||||
* These are applied after loading
|
||||
* an operand register.
|
||||
*/
|
||||
enum class DxbcRegModifier : uint32_t {
|
||||
Neg = 0,
|
||||
Abs = 1,
|
||||
};
|
||||
|
||||
using DxbcRegModifiers = Flags<DxbcRegModifier>;
|
||||
|
||||
|
||||
/**
|
||||
* \brief Constant buffer binding
|
||||
@ -121,671 +140,193 @@ namespace dxvk {
|
||||
};
|
||||
|
||||
|
||||
struct DxbcRegIndex {
|
||||
DxbcRegister* relReg;
|
||||
int32_t offset;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Basic control info
|
||||
* \brief Instruction operand
|
||||
*
|
||||
*
|
||||
* Parses instruction-specific control bits. Whether
|
||||
* these are well defined depends on the instruction.
|
||||
*/
|
||||
class DxbcOpcodeControl {
|
||||
struct DxbcRegister {
|
||||
DxbcOperandType type;
|
||||
DxbcScalarType dataType;
|
||||
DxbcComponentCount componentCount;
|
||||
|
||||
uint32_t idxDim;
|
||||
DxbcRegIndex idx[DxbcMaxRegIndexDim];
|
||||
|
||||
DxbcRegMask mask;
|
||||
DxbcRegSwizzle swizzle;
|
||||
DxbcRegModifiers modifiers;
|
||||
|
||||
union {
|
||||
uint32_t u32_4[4];
|
||||
uint32_t u32_1;
|
||||
} imm;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Instruction result modifiers
|
||||
*
|
||||
* Modifiers that are applied
|
||||
* to all destination operands.
|
||||
*/
|
||||
struct DxbcOpModifiers {
|
||||
bool saturate;
|
||||
bool precise;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Opcode controls
|
||||
*
|
||||
* Instruction-specific controls. Usually,
|
||||
* only one of the members will be valid.
|
||||
*/
|
||||
struct DxbcShaderOpcodeControls {
|
||||
DxbcZeroTest zeroTest;
|
||||
DxbcSyncFlags syncFlags;
|
||||
DxbcResourceDim resourceDim;
|
||||
DxbcResinfoType resinfoType;
|
||||
DxbcInterpolationMode interpolation;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Sample controls
|
||||
*
|
||||
* Constant texel offset with
|
||||
* values raning from -8 to 7.
|
||||
*/
|
||||
struct DxbcShaderSampleControls {
|
||||
int u, v, w;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Immediate value
|
||||
*
|
||||
* Immediate argument represented either
|
||||
* as a 32-bit or 64-bit unsigned integer.
|
||||
*/
|
||||
union DxbcImmediate {
|
||||
uint32_t u32;
|
||||
uint64_t u64;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Shader instruction
|
||||
*/
|
||||
struct DxbcShaderInstruction {
|
||||
DxbcOpcode op;
|
||||
DxbcOpModifiers modifiers;
|
||||
DxbcShaderOpcodeControls controls;
|
||||
DxbcShaderSampleControls sampleControls;
|
||||
|
||||
uint32_t dstCount;
|
||||
uint32_t srcCount;
|
||||
uint32_t immCount;
|
||||
|
||||
const DxbcRegister* dst;
|
||||
const DxbcRegister* src;
|
||||
const DxbcImmediate* imm;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief DXBC code slice
|
||||
*
|
||||
* Convenient pointer pair that allows
|
||||
* reading the code word stream safely.
|
||||
*/
|
||||
class DxbcCodeSlice {
|
||||
|
||||
public:
|
||||
|
||||
DxbcOpcodeControl() { }
|
||||
DxbcOpcodeControl(uint32_t control)
|
||||
: m_control(control) { }
|
||||
DxbcCodeSlice(
|
||||
const uint32_t* ptr,
|
||||
const uint32_t* end)
|
||||
: m_ptr(ptr), m_end(end) { }
|
||||
|
||||
/**
|
||||
* \brief Saturation hint
|
||||
*
|
||||
* If set, the result of the given instruction
|
||||
* is clamped to the [0..1] range.
|
||||
*/
|
||||
bool saturateBit() const {
|
||||
return bit::extract(m_control, 2, 2) != 0;
|
||||
}
|
||||
uint32_t at(uint32_t id) const;
|
||||
uint32_t read();
|
||||
|
||||
/**
|
||||
* \brief Precision hint
|
||||
*/
|
||||
bool preciseBit() const {
|
||||
return bit::extract(m_control, 8, 11) != 0;
|
||||
}
|
||||
DxbcCodeSlice take(uint32_t n) const;
|
||||
DxbcCodeSlice skip(uint32_t n) const;
|
||||
|
||||
/**
|
||||
* \brief Zero test
|
||||
*
|
||||
* For conditional instructions, this defines
|
||||
* whether the test shall pass when the given
|
||||
* operand is zero or non-zero.
|
||||
*/
|
||||
DxbcZeroTest zeroTest() const {
|
||||
return static_cast<DxbcZeroTest>(
|
||||
bit::extract(m_control, 7, 7));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Resinfo return type
|
||||
*
|
||||
* Control bits specifically for
|
||||
* the \c resinfo instruction.
|
||||
*/
|
||||
DxbcResinfoType resinfoType() const {
|
||||
return static_cast<DxbcResinfoType>(
|
||||
bit::extract(m_control, 0, 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Sync flags
|
||||
*
|
||||
* Defines the exact operation of sync
|
||||
* instructions in compute shaders.
|
||||
*/
|
||||
DxbcSyncFlags syncFlags() const {
|
||||
return bit::extract(m_control, 0, 3);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Resource dimension
|
||||
*
|
||||
* Defines the type of a resource.
|
||||
* Only valid for dcl_resource etc.
|
||||
*/
|
||||
DxbcResourceDim resourceDim() const {
|
||||
return static_cast<DxbcResourceDim>(
|
||||
bit::extract(m_control, 0, 4));
|
||||
bool atEnd() const {
|
||||
return m_ptr == m_end;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
uint32_t m_control = 0;
|
||||
const uint32_t* m_ptr = nullptr;
|
||||
const uint32_t* m_end = nullptr;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief DXBC instruction token
|
||||
* \brief Decode context
|
||||
*
|
||||
* Initial token at the beginning of each instruction.
|
||||
* This encodes the actual op code, the length of the
|
||||
* entire instruction in DWORDs, as well as some flags
|
||||
* controlling the specific instruction.
|
||||
* Stores data that is required to decode a single
|
||||
* instruction. This data is not persistent, so it
|
||||
* should be forwarded to the compiler right away.
|
||||
*/
|
||||
class DxbcOpcodeToken {
|
||||
class DxbcDecodeContext {
|
||||
|
||||
public:
|
||||
|
||||
DxbcOpcodeToken() { }
|
||||
DxbcOpcodeToken(uint32_t token)
|
||||
: m_token(token) { }
|
||||
|
||||
/**
|
||||
* \brief Opcode
|
||||
* \returns Opcode
|
||||
*/
|
||||
DxbcOpcode opcode() const {
|
||||
return static_cast<DxbcOpcode>(
|
||||
bit::extract(m_token, 0, 10));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Control info
|
||||
* \brief Retrieves current instruction
|
||||
*
|
||||
* Instruction-specific control info. Undefined
|
||||
* if the opcode is \c DxbcOpcode::CustomData.
|
||||
* \returns Control info
|
||||
* This is only valid after a call to \ref decode.
|
||||
* \returns Reference to last decoded instruction
|
||||
*/
|
||||
uint32_t control() const {
|
||||
return bit::extract(m_token, 11, 23);
|
||||
const DxbcShaderInstruction& getInstruction() const {
|
||||
return m_instruction;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Instruction length
|
||||
* \brief Decodes an instruction
|
||||
*
|
||||
* Undefind if the opcode is \c DxbcOpcode::CustomData.
|
||||
* In that case, the instruction length will be stored
|
||||
* in the DWORD immediately following the opcode token.
|
||||
* \returns Instruction length, in DWORDs
|
||||
* This also advances the given code slice by the
|
||||
* number of dwords consumed by the instruction.
|
||||
* \param [in] code Code slice
|
||||
*/
|
||||
uint32_t length() const {
|
||||
return bit::extract(m_token, 24, 30);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Checks whether the opcode is extended
|
||||
*
|
||||
* Additional information is encoded in extended
|
||||
* opcode tokens if this flag is set. Note that
|
||||
* multiple extended opcode tokens may be chained.
|
||||
* \returns \c true if the opcode is extended.
|
||||
*/
|
||||
bool isExtended() const {
|
||||
return !!bit::extract(m_token, 31, 31);
|
||||
}
|
||||
void decodeInstruction(DxbcCodeSlice& code);
|
||||
|
||||
private:
|
||||
|
||||
uint32_t m_token = 0;
|
||||
DxbcShaderInstruction m_instruction;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief DXBC extended instruction token
|
||||
*
|
||||
* Some instruction may encode additional control
|
||||
* modifiers in extended opcode tokens. The format
|
||||
* of these tokens differs from that of the the
|
||||
* initial opcode tokens.
|
||||
*/
|
||||
class DxbcOpcodeTokenExt {
|
||||
std::array<DxbcRegister, 4> m_dstOperands;
|
||||
std::array<DxbcRegister, 4> m_srcOperands;
|
||||
std::array<DxbcImmediate, 4> m_immOperands;
|
||||
std::array<DxbcRegister, 12> m_indices;
|
||||
|
||||
public:
|
||||
// Index into the indices array. Used when decoding
|
||||
// instruction operands with relative indexing.
|
||||
uint32_t m_indexId = 0;
|
||||
|
||||
DxbcOpcodeTokenExt() { }
|
||||
DxbcOpcodeTokenExt(uint32_t token)
|
||||
: m_token(token) { }
|
||||
void decodeCustomData(DxbcCodeSlice code);
|
||||
void decodeOperation(DxbcCodeSlice code);
|
||||
|
||||
/**
|
||||
* \brief Extended opcode
|
||||
* \returns Extended opcode
|
||||
*/
|
||||
DxbcExtOpcode opcode() const {
|
||||
return static_cast<DxbcExtOpcode>(
|
||||
bit::extract(m_token, 0, 5));
|
||||
}
|
||||
void decodeComponentSelection(DxbcRegister& reg, uint32_t token);
|
||||
void decodeOperandExtensions(DxbcCodeSlice& code, DxbcRegister& reg, uint32_t token);
|
||||
void decodeOperandImmediates(DxbcCodeSlice& code, DxbcRegister& reg);
|
||||
void decodeOperandIndex(DxbcCodeSlice& code, DxbcRegister& reg, uint32_t token);
|
||||
|
||||
/**
|
||||
* \brief Control info
|
||||
*
|
||||
* Instruction-specific control info. Undefined
|
||||
* if the opcode is \c DxbcOpcode::CustomData.
|
||||
* \returns Control info
|
||||
*/
|
||||
uint32_t control() const {
|
||||
return bit::extract(m_token, 6, 30);
|
||||
}
|
||||
void decodeRegister(DxbcCodeSlice& code, DxbcRegister& reg, DxbcScalarType type);
|
||||
void decodeImm32(DxbcCodeSlice& code, DxbcImmediate& imm, DxbcScalarType type);
|
||||
|
||||
/**
|
||||
* \brief Extended opcode length
|
||||
*
|
||||
* Number of DWORDs that belong to this extended
|
||||
* opcode information. Currently, there are no
|
||||
* extended opcodes with a length greater than 1.
|
||||
* \returns Exteded opcode length, in DWORDs
|
||||
*/
|
||||
uint32_t length() const {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Checks whether there are additional modifiers
|
||||
* \returns \c true if the extended opcode is extended
|
||||
*/
|
||||
bool isExtended() const {
|
||||
return !!bit::extract(m_token, 31, 31);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
uint32_t m_token = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Operand token
|
||||
*
|
||||
* Stores general information about one operand of an
|
||||
* instruction. Like opcode tokens, operand tokens may
|
||||
* be extended.
|
||||
*/
|
||||
class DxbcOperandToken {
|
||||
|
||||
public:
|
||||
|
||||
DxbcOperandToken(uint32_t token)
|
||||
: m_token(token) { }
|
||||
|
||||
/**
|
||||
* \brief Number of operand components
|
||||
*
|
||||
* The number of components that the operand
|
||||
* has. Can be zero, one, or four.
|
||||
* \returns Number of components
|
||||
*/
|
||||
uint32_t numComponents() const {
|
||||
std::array<uint32_t, 4> count = { 0, 1, 4, 0 };
|
||||
return count.at(bit::extract(m_token, 0, 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Component selection mode
|
||||
*
|
||||
* Operands can be either masked so that some components
|
||||
* will not be used, or they can be swizzled so that only
|
||||
* a given set of components is used.
|
||||
* \returns Component selection mode
|
||||
*/
|
||||
DxbcRegMode selectionMode() const {
|
||||
return static_cast<DxbcRegMode>(
|
||||
bit::extract(m_token, 2, 3));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Component mask
|
||||
*
|
||||
* Used when the component selection
|
||||
* mode is \c DxbcRegMode::Mask.
|
||||
* \returns The component mask
|
||||
*/
|
||||
DxbcRegMask mask() const {
|
||||
return DxbcRegMask(bit::extract(m_token, 4, 7));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Component swizzle
|
||||
*
|
||||
* Used when the component selection
|
||||
* mode is \c DxbcRegMode::Swizzle.
|
||||
* \returns The component swizzle
|
||||
*/
|
||||
DxbcRegSwizzle swizzle() const {
|
||||
return DxbcRegSwizzle(
|
||||
bit::extract(m_token, 4, 5),
|
||||
bit::extract(m_token, 6, 7),
|
||||
bit::extract(m_token, 8, 9),
|
||||
bit::extract(m_token, 10, 11));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Single component selection
|
||||
*
|
||||
* Used when the component selection
|
||||
* mode is \c DxbcRegMode::Select1.
|
||||
* \returns The component index
|
||||
*/
|
||||
uint32_t select1() const {
|
||||
return bit::extract(m_token, 4, 5);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Operand type
|
||||
*
|
||||
* Selects the type of the operand, i.e. whether the
|
||||
* operand is a temporary register, a shader resource
|
||||
* or a builtin interface variable.
|
||||
* \returns Operand type
|
||||
*/
|
||||
DxbcOperandType type() const {
|
||||
return static_cast<DxbcOperandType>(
|
||||
bit::extract(m_token, 12, 19));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Index dimension
|
||||
*
|
||||
* Number of indices. In DXBC, each register file has
|
||||
* a dimensionality, e.g. the temporary registers are
|
||||
* one-dimensional and therefore require one index.
|
||||
* \returns Number of index dimensions
|
||||
*/
|
||||
uint32_t indexDimension() const {
|
||||
return bit::extract(m_token, 20, 21);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Index representation
|
||||
*
|
||||
* Stores whether an index is stored as an
|
||||
* immediate value or as a relative value
|
||||
* which requires another operand token.
|
||||
* \param [in] dim Index dimension to query
|
||||
* \returns Representation of that index
|
||||
*/
|
||||
DxbcOperandIndexRepresentation indexRepresentation(uint32_t dim) const {
|
||||
return static_cast<DxbcOperandIndexRepresentation>(
|
||||
bit::extract(m_token, 22 + 3 * dim, 24 + 3 * dim));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Checks whether the operand is extended
|
||||
*
|
||||
* Operands can be modified with extended tokens.
|
||||
* \returns \c true if the operand is extended
|
||||
*/
|
||||
bool isExtended() const {
|
||||
return !!bit::extract(m_token, 31, 31);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
uint32_t m_token = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Extended operand token
|
||||
*
|
||||
* Stores additional properties for an operand that
|
||||
* cannot be stored in the initial operand token.
|
||||
*/
|
||||
class DxbcOperandTokenExt {
|
||||
|
||||
public:
|
||||
|
||||
DxbcOperandTokenExt() { }
|
||||
DxbcOperandTokenExt(uint32_t token)
|
||||
: m_token(token) { }
|
||||
|
||||
/**
|
||||
* \brief Operand extension type
|
||||
* \returns Operand extension type
|
||||
*/
|
||||
DxbcOperandExt type() const {
|
||||
return static_cast<DxbcOperandExt>(
|
||||
bit::extract(m_token, 0, 5));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Data flags
|
||||
* \returns Data flags
|
||||
*/
|
||||
uint32_t data() const {
|
||||
return bit::extract(m_token, 6, 30);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Checks whether the operand is extended
|
||||
*
|
||||
* Like extended opcode tokens, extended
|
||||
* operand tokens can be chained.
|
||||
* \returns \c true if extended
|
||||
*/
|
||||
bool isExtended() const {
|
||||
return !!bit::extract(m_token, 31, 31);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
uint32_t m_token = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief DXBC code DxbcCodeReader
|
||||
*
|
||||
* Helper class that can read DWORDs from a sized slice.
|
||||
* Returns undefined numbers on out-of-bounds access, but
|
||||
* makes sure not to access memory locations outside the
|
||||
* original code array.
|
||||
*/
|
||||
class DxbcCodeReader {
|
||||
|
||||
public:
|
||||
|
||||
DxbcCodeReader() { }
|
||||
DxbcCodeReader(
|
||||
const uint32_t* code,
|
||||
uint32_t size)
|
||||
: m_code(size != 0 ? code : nullptr),
|
||||
m_size(size) { }
|
||||
|
||||
uint32_t getWord(uint32_t id) const {
|
||||
return id < m_size ? m_code[id] : 0;
|
||||
}
|
||||
|
||||
DxbcCodeReader& operator ++ ();
|
||||
DxbcCodeReader& operator += (uint32_t n);
|
||||
DxbcCodeReader operator + (uint32_t n) const;
|
||||
|
||||
bool operator == (const DxbcCodeReader& other) const;
|
||||
bool operator != (const DxbcCodeReader& other) const;
|
||||
|
||||
private:
|
||||
|
||||
const uint32_t* m_code = nullptr;
|
||||
uint32_t m_size = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief DXBC operand index
|
||||
*
|
||||
* Represents an index into an indexable register file.
|
||||
* For each register file dimension, one operand index
|
||||
* must be read from the encoded instruction.
|
||||
*/
|
||||
class DxbcOperandIndex {
|
||||
|
||||
public:
|
||||
|
||||
DxbcOperandIndex() { }
|
||||
DxbcOperandIndex(
|
||||
const DxbcCodeReader& code,
|
||||
DxbcOperandIndexRepresentation rep)
|
||||
: m_code(code), m_rep(rep) { }
|
||||
|
||||
uint32_t length() const;
|
||||
|
||||
bool hasImmPart() const;
|
||||
bool hasRelPart() const;
|
||||
|
||||
uint64_t immPart() const;
|
||||
DxbcOperand relPart() const;
|
||||
|
||||
private:
|
||||
|
||||
DxbcCodeReader m_code;
|
||||
DxbcOperandIndexRepresentation m_rep;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief DXBC operand
|
||||
*
|
||||
* Provides methods to query the operand token
|
||||
* including extended operand tokens, which may
|
||||
* modify the operand's return value.
|
||||
*/
|
||||
class DxbcOperand {
|
||||
|
||||
public:
|
||||
|
||||
DxbcOperand() { }
|
||||
DxbcOperand(const DxbcCodeReader& code);
|
||||
|
||||
/**
|
||||
* \brief Operand token
|
||||
* \returns Operand token
|
||||
*/
|
||||
DxbcOperandToken token() const {
|
||||
return DxbcOperandToken(m_info.getWord(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Operand length, in DWORDs
|
||||
* \returns Number of DWORDs
|
||||
*/
|
||||
uint32_t length() const {
|
||||
return m_length;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Operand index for a single dimension
|
||||
*
|
||||
* \param [in] dim Dimension to query
|
||||
* \returns Operand index
|
||||
*/
|
||||
DxbcOperandIndex index(uint32_t dim) const;
|
||||
|
||||
/**
|
||||
* \brief Queries an operand extension
|
||||
*
|
||||
* If an extended operand token with the given
|
||||
* operand extension exists, return that token.
|
||||
* \param [in] ext The operand extension
|
||||
* \param [out] token The extended token
|
||||
* \returns \c true if the token was defined
|
||||
*/
|
||||
bool queryOperandExt(
|
||||
DxbcOperandExt ext,
|
||||
DxbcOperandTokenExt& token) const;
|
||||
|
||||
/**
|
||||
* \brief Reads 32-bit immediate integer
|
||||
*
|
||||
* \param [in] idx Component index
|
||||
* \returns The immediate operand
|
||||
*/
|
||||
uint32_t imm32(uint32_t idx) const {
|
||||
return m_data.getWord(idx);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Reads 64-bit immediate integer
|
||||
*
|
||||
* \param [in] idx Component index
|
||||
* \returns The immediate operand
|
||||
*/
|
||||
uint64_t imm64(uint32_t idx) const {
|
||||
uint64_t hi = m_data.getWord(2 * idx + 0);
|
||||
uint64_t lo = m_data.getWord(2 * idx + 1);
|
||||
return (hi << 32) | (lo);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
DxbcCodeReader m_info;
|
||||
DxbcCodeReader m_data;
|
||||
|
||||
uint32_t m_length = 0;
|
||||
std::array<uint32_t, 3> m_indexOffsets = { 0, 0, 0 };
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief DXBC instruction
|
||||
*
|
||||
* Provides methods to query the opcode token
|
||||
* including extended opcode tokens, as well
|
||||
* as convenience methods to read operands.
|
||||
*/
|
||||
class DxbcInstruction {
|
||||
|
||||
public:
|
||||
|
||||
DxbcInstruction() { }
|
||||
DxbcInstruction(const DxbcCodeReader& code);
|
||||
|
||||
/**
|
||||
* \brief Opcode token
|
||||
* \returns Opcode token
|
||||
*/
|
||||
DxbcOpcodeToken token() const {
|
||||
return DxbcOpcodeToken(m_op.getWord(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Instruction length, in DWORDs
|
||||
* \returns Instruction length, in DWORDs
|
||||
*/
|
||||
uint32_t length() const;
|
||||
|
||||
/**
|
||||
* \brief Queries an opcode extension
|
||||
*
|
||||
* If an extended opcode token with the given
|
||||
* opcode exists, the token will be returned.
|
||||
* \param [in] extOpcode Extended opcode
|
||||
* \param [out] token The extended token
|
||||
* \returns \c true if the token was defined
|
||||
*/
|
||||
bool queryOpcodeExt(
|
||||
DxbcExtOpcode extOpcode,
|
||||
DxbcOpcodeTokenExt& token) const;
|
||||
|
||||
/**
|
||||
* \brief Retrieves argument word
|
||||
*
|
||||
* Instruction arguments immediately follow the opcode
|
||||
* tokens, including the extended opcodes. Argument 0
|
||||
* will therefore be the first DWORD that is part of
|
||||
* an instruction operand or an immediate number.
|
||||
* \param [in] idx Argument word index
|
||||
* \returns The word at the given index
|
||||
*/
|
||||
uint32_t arg(uint32_t idx) const {
|
||||
return m_args.getWord(idx);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Reads an argument enum
|
||||
*
|
||||
* Casts the word at the given location to an enum.
|
||||
* Some instructions take name tokens as operands.
|
||||
* \param [in] idx Argument word index
|
||||
* \returns The enum value of the given word
|
||||
*/
|
||||
template<typename T>
|
||||
T readEnum(uint32_t idx) const {
|
||||
return static_cast<T>(arg(idx));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Retrieves an operand
|
||||
*
|
||||
* \param [in] idx Argument word index
|
||||
* \returns The operand object
|
||||
*/
|
||||
DxbcOperand operand(uint32_t idx) const {
|
||||
return DxbcOperand(m_args + idx);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
DxbcCodeReader m_op;
|
||||
DxbcCodeReader m_args;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief DXBC instruction decoder
|
||||
*
|
||||
* Iterator that walks over DXBC instructions.
|
||||
* Instruction boundaries are easy to find as
|
||||
* the length of each instruction is encoded
|
||||
* in the opcode token, much like in SPIR-V.
|
||||
*/
|
||||
class DxbcDecoder {
|
||||
|
||||
public:
|
||||
|
||||
DxbcDecoder() { }
|
||||
DxbcDecoder(const uint32_t* code, uint32_t size)
|
||||
: m_code(code, size) { }
|
||||
|
||||
DxbcDecoder& operator ++ () {
|
||||
m_code += DxbcInstruction(m_code).length();
|
||||
return *this;
|
||||
}
|
||||
|
||||
DxbcInstruction operator * () const {
|
||||
return DxbcInstruction(m_code);
|
||||
}
|
||||
|
||||
bool operator == (const DxbcDecoder& other) const { return m_code == other.m_code; }
|
||||
bool operator != (const DxbcDecoder& other) const { return m_code != other.m_code; }
|
||||
|
||||
private:
|
||||
|
||||
DxbcCodeReader m_code;
|
||||
void decodeOperand(DxbcCodeSlice& code, const DxbcInstOperandFormat& format);
|
||||
|
||||
};
|
||||
|
||||
|
@ -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>;
|
||||
|
||||
|
||||
enum class DxbcOperandModifier : uint32_t {
|
||||
Neg = 0,
|
||||
Abs = 1,
|
||||
};
|
||||
|
||||
using DxbcOperandModifiers = Flags<DxbcOperandModifier>;
|
||||
|
||||
enum class DxbcZeroTest : uint32_t {
|
||||
TestZ = 0,
|
||||
TestNz = 1,
|
||||
|
@ -1,5 +1,4 @@
|
||||
#include "dxbc_compiler.h"
|
||||
#include "dxbc_compiler_2.h"
|
||||
#include "dxbc_module.h"
|
||||
|
||||
namespace dxvk {
|
||||
@ -47,7 +46,7 @@ namespace dxvk {
|
||||
|
||||
DxbcCodeSlice slice = m_shexChunk->slice();
|
||||
|
||||
DxbcCompiler2 compiler(
|
||||
DxbcCompiler compiler(
|
||||
m_shexChunk->version(),
|
||||
m_isgnChunk, m_osgnChunk);
|
||||
|
||||
|
@ -3,10 +3,8 @@ dxbc_src = files([
|
||||
'dxbc_chunk_shex.cpp',
|
||||
'dxbc_common.cpp',
|
||||
'dxbc_compiler.cpp',
|
||||
'dxbc_compiler_2.cpp',
|
||||
'dxbc_defs.cpp',
|
||||
'dxbc_decoder.cpp',
|
||||
'dxbc_decoder_2.cpp',
|
||||
'dxbc_header.cpp',
|
||||
'dxbc_module.cpp',
|
||||
'dxbc_names.cpp',
|
||||
|
Loading…
x
Reference in New Issue
Block a user