mirror of
https://github.com/EduApps-CDG/OpenDX
synced 2024-12-30 09:45:37 +01:00
[dxbc] Shader compiler rewrite (1/2)
Rewrote most parts of the shader compiler and removed the old one. The next step is to improve documentation and remove the remaining traces of the old shader compiler.
This commit is contained in:
parent
a0db9198e3
commit
464a3e7d4e
File diff suppressed because it is too large
Load Diff
@ -1,117 +1,438 @@
|
||||
#pragma once
|
||||
|
||||
#include "./gen/dxbc_gen_common.h"
|
||||
#include "../spirv/spirv_module.h"
|
||||
|
||||
#include "dxbc_chunk_isgn.h"
|
||||
#include "dxbc_decoder.h"
|
||||
#include "dxbc_defs.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
// TODO deprecate DxbcComponentSelectionMode
|
||||
using DxbcRegMode = DxbcComponentSelectionMode;
|
||||
|
||||
struct DxbcValue2 {
|
||||
DxbcScalarType componentType = DxbcScalarType::Float32;
|
||||
uint32_t componentCount = 0;
|
||||
uint32_t valueId = 0;
|
||||
};
|
||||
|
||||
struct DxbcPointer2 {
|
||||
DxbcScalarType componentType = DxbcScalarType::Float32;
|
||||
uint32_t componentCount = 0;
|
||||
uint32_t pointerId = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief DXBC compiler
|
||||
* \brief Constant buffer binding
|
||||
*
|
||||
* Interprets DXBC instructions and generates
|
||||
* SPIR-V code for the appropriate shader type.
|
||||
* Stores information required to
|
||||
* access a constant buffer.
|
||||
*/
|
||||
class DxbcCompiler {
|
||||
struct DxbcConstantBuffer2 {
|
||||
uint32_t varId = 0;
|
||||
uint32_t size = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Sampler binding
|
||||
*
|
||||
* Stores a sampler variable that can be
|
||||
* used together with a texture resource.
|
||||
*/
|
||||
struct DxbcSampler2 {
|
||||
uint32_t varId = 0;
|
||||
uint32_t typeId = 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Shader resource binding
|
||||
*
|
||||
* Stores a resource variable
|
||||
* and associated type IDs.
|
||||
*/
|
||||
struct DxbcShaderResource2 {
|
||||
uint32_t varId = 0;
|
||||
uint32_t sampledTypeId = 0;
|
||||
uint32_t textureTypeId = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief System value mapping
|
||||
*
|
||||
* Maps a system value to a given set of
|
||||
* components of an input or output register.
|
||||
*/
|
||||
struct DxbcSvMapping2 {
|
||||
uint32_t regId;
|
||||
DxbcRegMask regMask;
|
||||
DxbcSystemValue sv;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Compiler error code
|
||||
*
|
||||
* Helps identify the type of error
|
||||
* that may occur during compilation.
|
||||
*/
|
||||
enum class DxbcError {
|
||||
sOk,
|
||||
eInternal,
|
||||
eInstructionFormat,
|
||||
eInvalidOperand,
|
||||
eInvalidOperandIndex,
|
||||
eTypeMismatch,
|
||||
eUnhandledOpcode,
|
||||
eUnsupported,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Operand index type
|
||||
*
|
||||
* Defines whether a register index
|
||||
* is relative or constant.
|
||||
*/
|
||||
enum class DxbcIndexType {
|
||||
Immediate, ///< Index is a constant value
|
||||
Relative, ///< Index depends on a r# register
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Instruction operand index
|
||||
*
|
||||
* Stores the type of the index as well as the
|
||||
* register (if relative) and the constant offset.
|
||||
*/
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Decoded instruction
|
||||
*
|
||||
* Stores all information about a single
|
||||
* instruction, including its operands.
|
||||
*/
|
||||
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<DxbcPointer2, DxbcMaxInterfaceRegs> oregs;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \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:
|
||||
|
||||
DxbcCompiler(
|
||||
DxbcCompiler2(
|
||||
const DxbcProgramVersion& version,
|
||||
const Rc<DxbcIsgn>& isgn,
|
||||
const Rc<DxbcIsgn>& osgn);
|
||||
~DxbcCompiler();
|
||||
~DxbcCompiler2();
|
||||
|
||||
void processInstruction(
|
||||
/**
|
||||
* \brief Processes a single instruction
|
||||
*
|
||||
* \param [in] ins The instruction
|
||||
* \returns An error code, or \c sOK
|
||||
*/
|
||||
DxbcError processInstruction(
|
||||
const DxbcInstruction& ins);
|
||||
|
||||
/**
|
||||
* \brief Finalizes the shader
|
||||
* \returns The final shader object
|
||||
*/
|
||||
Rc<DxvkShader> finalize();
|
||||
|
||||
private:
|
||||
|
||||
Rc<DxbcCodeGen> m_gen;
|
||||
DxbcProgramVersion m_version;
|
||||
SpirvModule m_module;
|
||||
|
||||
void dclGlobalFlags(
|
||||
const DxbcInstruction& ins);
|
||||
Rc<DxbcIsgn> m_isgn;
|
||||
Rc<DxbcIsgn> m_osgn;
|
||||
|
||||
void dclConstantBuffer(
|
||||
const DxbcInstruction& ins);
|
||||
///////////////////////////////////////////////////////
|
||||
// Resource slot description for the shader. This will
|
||||
// be used to map D3D11 bindings to DXVK bindings.
|
||||
std::vector<DxvkResourceSlot> m_resourceSlots;
|
||||
|
||||
void dclResource(
|
||||
const DxbcInstruction& ins);
|
||||
///////////////////////////////
|
||||
// r# registers of type float4
|
||||
std::vector<uint32_t> m_rRegs;
|
||||
|
||||
void dclSampler(
|
||||
const DxbcInstruction& ins);
|
||||
///////////////////////////////////////////////////////////
|
||||
// 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;
|
||||
|
||||
void dclInterfaceVar(
|
||||
const DxbcInstruction& ins);
|
||||
//////////////////////////////////////////////////////////
|
||||
// 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;
|
||||
|
||||
void dclTemps(
|
||||
const DxbcInstruction& ins);
|
||||
//////////////////////////////////////////////////////
|
||||
// Shader resource variables. These provide access to
|
||||
// constant buffers, samplers, textures, and UAVs.
|
||||
std::array<DxbcConstantBuffer2, 16> m_constantBuffers;
|
||||
std::array<DxbcSampler2, 16> m_samplers;
|
||||
std::array<DxbcShaderResource2, 128> m_textures;
|
||||
|
||||
void opAdd(
|
||||
const DxbcInstruction& ins);
|
||||
////////////////////////////////////////////////////////
|
||||
// Input/Output system value mappings. These will need
|
||||
// to be set up before or after the main function runs.
|
||||
std::vector<DxbcSvMapping2> m_vSvs;
|
||||
std::vector<DxbcSvMapping2> m_oSvs;
|
||||
|
||||
void opMad(
|
||||
const DxbcInstruction& ins);
|
||||
///////////////////////////////////////////////////////////
|
||||
// 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;
|
||||
|
||||
void opMul(
|
||||
const DxbcInstruction& ins);
|
||||
////////////////////////////////////////////////////
|
||||
// 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;
|
||||
|
||||
void opDpx(
|
||||
const DxbcInstruction& ins,
|
||||
uint32_t n);
|
||||
///////////////////////////////////////////////////
|
||||
// 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;
|
||||
|
||||
void opRsq(
|
||||
const DxbcInstruction& ins);
|
||||
////////////////////////////////////////
|
||||
// Data structures for each shader type
|
||||
DxbcVsSpecifics m_vs;
|
||||
DxbcPsSpecifics m_ps;
|
||||
|
||||
void opMov(
|
||||
const DxbcInstruction& ins);
|
||||
//////////////////////////////
|
||||
// Instruction class handlers
|
||||
DxbcError handleDeclaration(
|
||||
const DxbcInst& ins);
|
||||
|
||||
void opRet(
|
||||
const DxbcInstruction& ins);
|
||||
DxbcError handleControlFlow(
|
||||
const DxbcInst& ins);
|
||||
|
||||
void opSample(
|
||||
const DxbcInstruction& ins);
|
||||
DxbcError handleTextureSample(
|
||||
const DxbcInst& ins);
|
||||
|
||||
DxbcValue getDynamicIndexValue(
|
||||
const DxbcOperandIndex& index);
|
||||
DxbcError handleVectorAlu(
|
||||
const DxbcInst& ins);
|
||||
|
||||
DxbcComponentMask getDstOperandMask(
|
||||
const DxbcOperand& operand);
|
||||
DxbcError handleVectorDot(
|
||||
const DxbcInst& ins);
|
||||
|
||||
DxbcPointer getTempOperandPtr(
|
||||
const DxbcOperand& operand);
|
||||
///////////////////////
|
||||
// Declaration methods
|
||||
DxbcError declareGlobalFlags(
|
||||
const DxbcInst& ins);
|
||||
|
||||
DxbcPointer getInterfaceOperandPtr(
|
||||
const DxbcOperand& operand);
|
||||
DxbcError declareTemps(
|
||||
const DxbcInst& ins);
|
||||
|
||||
DxbcPointer getConstantBufferPtr(
|
||||
const DxbcOperand& operand);
|
||||
DxbcError declareInterfaceVar(
|
||||
const DxbcInst& ins);
|
||||
|
||||
DxbcPointer getOperandPtr(
|
||||
const DxbcOperand& operand);
|
||||
DxbcError declareConstantBuffer(
|
||||
const DxbcInst& ins);
|
||||
|
||||
DxbcValue selectOperandComponents(
|
||||
const DxbcOperandToken& opToken,
|
||||
const DxbcValue& opValue,
|
||||
DxbcComponentMask dstMask);
|
||||
DxbcError declareSampler(
|
||||
const DxbcInst& ins);
|
||||
|
||||
DxbcValue applyOperandModifiers(
|
||||
DxbcValue value,
|
||||
DxbcOperandModifiers modifiers);
|
||||
DxbcError declareResource(
|
||||
const DxbcInst& ins);
|
||||
|
||||
DxbcValue applyResultModifiers(
|
||||
DxbcValue value,
|
||||
DxbcOpcodeControl control);
|
||||
|
||||
DxbcValue loadOperand(
|
||||
const DxbcOperand& operand,
|
||||
DxbcComponentMask dstMask,
|
||||
DxbcScalarType dstType);
|
||||
DxbcError declareInputVar(
|
||||
uint32_t regId,
|
||||
uint32_t regDim,
|
||||
DxbcRegMask regMask,
|
||||
DxbcSystemValue sv,
|
||||
DxbcInterpolationMode im);
|
||||
|
||||
void storeOperand(
|
||||
const DxbcOperand& operand,
|
||||
DxbcValue value,
|
||||
DxbcComponentMask mask);
|
||||
DxbcError declareOutputVar(
|
||||
uint32_t regId,
|
||||
uint32_t regDim,
|
||||
DxbcRegMask regMask,
|
||||
DxbcSystemValue sv,
|
||||
DxbcInterpolationMode im);
|
||||
|
||||
////////////////////////////////////
|
||||
// Register manipulation operations
|
||||
DxbcValue2 bitcastReg(
|
||||
const DxbcValue2& src,
|
||||
DxbcScalarType type);
|
||||
|
||||
DxbcValue2 insertReg(
|
||||
const DxbcValue2& dst,
|
||||
const DxbcValue2& src,
|
||||
DxbcRegMask mask);
|
||||
|
||||
DxbcValue2 extractReg(
|
||||
const DxbcValue2& src,
|
||||
DxbcRegMask mask);
|
||||
|
||||
DxbcValue2 swizzleReg(
|
||||
const DxbcValue2& src,
|
||||
const DxbcRegSwizzle& swizzle,
|
||||
DxbcRegMask mask);
|
||||
|
||||
DxbcValue2 regVector(
|
||||
const DxbcValue2& src,
|
||||
uint32_t size);
|
||||
|
||||
DxbcValue2 extendReg(
|
||||
const DxbcValue2& src,
|
||||
uint32_t size);
|
||||
|
||||
////////////////////////////
|
||||
// Operand modifier methods
|
||||
DxbcValue2 applyOperandModifiers(
|
||||
DxbcValue2 value,
|
||||
DxbcOperandModifiers modifiers);
|
||||
|
||||
DxbcValue2 applyResultModifiers(
|
||||
DxbcValue2 value,
|
||||
DxbcOpcodeControl control);
|
||||
|
||||
/////////////////////////
|
||||
// Load/Store operations
|
||||
DxbcValue2 loadOp(
|
||||
const DxbcInstOp& srcOp,
|
||||
DxbcRegMask srcMask,
|
||||
DxbcScalarType dstType);
|
||||
|
||||
DxbcValue2 loadImm32(
|
||||
const DxbcInstOp& srcOp,
|
||||
DxbcRegMask srcMask,
|
||||
DxbcScalarType dstType);
|
||||
|
||||
DxbcValue2 loadRegister(
|
||||
const DxbcInstOp& srcOp,
|
||||
DxbcRegMask srcMask,
|
||||
DxbcScalarType dstType);
|
||||
|
||||
void storeOp(
|
||||
const DxbcInstOp& dstOp,
|
||||
const DxbcValue2& srcValue);
|
||||
|
||||
DxbcValue2 loadPtr(
|
||||
const DxbcPointer2& ptr);
|
||||
|
||||
void storePtr(
|
||||
const DxbcPointer2& ptr,
|
||||
const DxbcValue2& value,
|
||||
DxbcRegMask mask);
|
||||
|
||||
DxbcValue2 loadIndex(
|
||||
const DxbcInstOpIndex& idx);
|
||||
|
||||
///////////////////////////
|
||||
// Operand pointer methods
|
||||
DxbcPointer2 getOperandPtr(
|
||||
const DxbcInstOp& op);
|
||||
|
||||
DxbcPointer2 getConstantBufferPtr(
|
||||
const DxbcInstOp& op);
|
||||
|
||||
/////////////////////////////////
|
||||
// Shader initialization methods
|
||||
void beginVertexShader(const Rc<DxbcIsgn>& isgn);
|
||||
void beginPixelShader (const Rc<DxbcIsgn>& osgn);
|
||||
|
||||
/////////////////////////////
|
||||
// Input preparation methods
|
||||
void prepareVertexInputs();
|
||||
void preparePixelInputs();
|
||||
|
||||
//////////////////////////////
|
||||
// Output preparation methods
|
||||
void prepareVertexOutputs();
|
||||
void preparePixelOutputs();
|
||||
|
||||
///////////////////////////////
|
||||
// Shader finalization methods
|
||||
void endVertexShader();
|
||||
void endPixelShader();
|
||||
|
||||
///////////////////////////
|
||||
// Type definition methods
|
||||
uint32_t definePerVertexBlock();
|
||||
|
||||
uint32_t defineScalarType(
|
||||
DxbcScalarType componentType);
|
||||
|
||||
uint32_t defineVectorType(
|
||||
DxbcScalarType componentType,
|
||||
uint32_t componentCount);
|
||||
|
||||
uint32_t definePointerType(
|
||||
DxbcScalarType componentType,
|
||||
uint32_t componentCount,
|
||||
spv::StorageClass storageClass);
|
||||
|
||||
/////////////////////////
|
||||
// DXBC decoding methods
|
||||
DxbcError parseInstruction(
|
||||
const DxbcInstruction& ins,
|
||||
DxbcInst& out);
|
||||
|
||||
};
|
||||
|
||||
|
@ -10,6 +10,72 @@ namespace dxvk {
|
||||
|
||||
class DxbcOperand;
|
||||
|
||||
/**
|
||||
* \brief Component swizzle
|
||||
*
|
||||
* Maps vector components to
|
||||
* other vector components.
|
||||
* TODO remove old class
|
||||
*/
|
||||
class DxbcRegSwizzle {
|
||||
|
||||
public:
|
||||
|
||||
DxbcRegSwizzle() { }
|
||||
DxbcRegSwizzle(uint32_t x, uint32_t y, uint32_t z, uint32_t w)
|
||||
: m_data((x << 0) | (y << 2) | (z << 4) | (w << 6)) { }
|
||||
|
||||
uint32_t operator [] (uint32_t id) const {
|
||||
return (m_data >> (id + id)) & 0x3;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
uint8_t m_data = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Component mask
|
||||
*
|
||||
* Enables access to certain
|
||||
* subset of vector components.
|
||||
* TODO remove old class
|
||||
*/
|
||||
class DxbcRegMask {
|
||||
|
||||
public:
|
||||
|
||||
DxbcRegMask() { }
|
||||
DxbcRegMask(uint32_t mask) : m_data(mask) { }
|
||||
DxbcRegMask(bool x, bool y, bool z, bool w)
|
||||
: m_data((x ? 0x1 : 0) | (y ? 0x2 : 0)
|
||||
| (z ? 0x4 : 0) | (w ? 0x8 : 0)) { }
|
||||
|
||||
bool operator [] (uint32_t id) const {
|
||||
return (m_data >> id) & 1;
|
||||
}
|
||||
|
||||
uint32_t setCount() const {
|
||||
const uint8_t n[16] = { 0, 1, 1, 2, 1, 2, 2, 3,
|
||||
1, 2, 2, 3, 2, 3, 3, 4 };
|
||||
return n[m_data & 0xF];
|
||||
}
|
||||
|
||||
uint32_t firstSet() const {
|
||||
const uint8_t n[16] = { 4, 0, 1, 0, 2, 0, 1, 0,
|
||||
3, 0, 1, 0, 2, 0, 1, 0 };
|
||||
return n[m_data & 0xF];
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
uint8_t m_data = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Basic control info
|
||||
*
|
||||
@ -74,6 +140,17 @@ namespace dxvk {
|
||||
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:
|
||||
|
||||
uint32_t m_control = 0;
|
||||
@ -233,7 +310,7 @@ namespace dxvk {
|
||||
* \returns Number of components
|
||||
*/
|
||||
uint32_t numComponents() const {
|
||||
std::array<uint32_t, 3> count = { 0, 1, 4 };
|
||||
std::array<uint32_t, 4> count = { 0, 1, 4, 0 };
|
||||
return count.at(bit::extract(m_token, 0, 1));
|
||||
}
|
||||
|
||||
@ -261,6 +338,17 @@ namespace dxvk {
|
||||
return DxbcComponentMask(bit::extract(m_token, 4, 7));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Component mask
|
||||
*
|
||||
* Used when the component selection mode is
|
||||
* \c DxbcComponentSelectionMode::Mask.
|
||||
* \returns The component mask
|
||||
*/
|
||||
DxbcRegMask mask() const {
|
||||
return DxbcRegMask(bit::extract(m_token, 4, 7));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Component swizzle
|
||||
*
|
||||
@ -276,6 +364,29 @@ namespace dxvk {
|
||||
bit::extract(m_token, 10, 11));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Component swizzle
|
||||
*
|
||||
* Used when the component selection mode is
|
||||
* \c DxbcComponentSelectionMode::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
|
||||
* \returns The component index
|
||||
*/
|
||||
uint32_t select1() const {
|
||||
return bit::extract(m_token, 4, 5);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Component selection
|
||||
*
|
||||
|
500
src/dxbc/dxbc_defs.cpp
Normal file
500
src/dxbc/dxbc_defs.cpp
Normal file
@ -0,0 +1,500 @@
|
||||
#include "dxbc_defs.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
const std::array<DxbcInstFormat, 207> g_instructionFormats = {{
|
||||
/* Add */
|
||||
{ 3, DxbcInstClass::VectorAlu, {
|
||||
{ DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
|
||||
{ DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
|
||||
{ DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
|
||||
} },
|
||||
/* And */
|
||||
{ },
|
||||
/* Break */
|
||||
{ },
|
||||
/* Breakc */
|
||||
{ },
|
||||
/* Call */
|
||||
{ },
|
||||
/* Callc */
|
||||
{ },
|
||||
/* Case */
|
||||
{ },
|
||||
/* Continue */
|
||||
{ },
|
||||
/* Continuec */
|
||||
{ },
|
||||
/* Cut */
|
||||
{ },
|
||||
/* Default */
|
||||
{ },
|
||||
/* DerivRtx */
|
||||
{ },
|
||||
/* DerivRty */
|
||||
{ },
|
||||
/* Discard */
|
||||
{ },
|
||||
/* Div */
|
||||
{ },
|
||||
/* Dp2 */
|
||||
{ 3, DxbcInstClass::VectorDot, {
|
||||
{ DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
|
||||
{ DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
|
||||
{ DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
|
||||
} },
|
||||
/* Dp3 */
|
||||
{ 3, DxbcInstClass::VectorDot, {
|
||||
{ DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
|
||||
{ DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
|
||||
{ DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
|
||||
} },
|
||||
/* Dp4 */
|
||||
{ 3, DxbcInstClass::VectorDot, {
|
||||
{ DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
|
||||
{ DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
|
||||
{ DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
|
||||
} },
|
||||
/* Else */
|
||||
{ },
|
||||
/* Emit */
|
||||
{ },
|
||||
/* EmitThenCut */
|
||||
{ },
|
||||
/* EndIf */
|
||||
{ },
|
||||
/* EndLoop */
|
||||
{ },
|
||||
/* EndSwitch */
|
||||
{ },
|
||||
/* Eq */
|
||||
{ },
|
||||
/* Exp */
|
||||
{ },
|
||||
/* Frc */
|
||||
{ },
|
||||
/* FtoI */
|
||||
{ },
|
||||
/* FtoU */
|
||||
{ },
|
||||
/* Ge */
|
||||
{ },
|
||||
/* IAdd */
|
||||
{ },
|
||||
/* If */
|
||||
{ },
|
||||
/* IEq */
|
||||
{ },
|
||||
/* IGe */
|
||||
{ },
|
||||
/* ILt */
|
||||
{ },
|
||||
/* IMad */
|
||||
{ },
|
||||
/* IMax */
|
||||
{ },
|
||||
/* IMin */
|
||||
{ },
|
||||
/* IMul */
|
||||
{ },
|
||||
/* INe */
|
||||
{ },
|
||||
/* INeg */
|
||||
{ },
|
||||
/* IShl */
|
||||
{ },
|
||||
/* IShr */
|
||||
{ },
|
||||
/* ItoF */
|
||||
{ },
|
||||
/* Label */
|
||||
{ },
|
||||
/* Ld */
|
||||
{ },
|
||||
/* LdMs */
|
||||
{ },
|
||||
/* Log */
|
||||
{ },
|
||||
/* Loop */
|
||||
{ },
|
||||
/* Lt */
|
||||
{ },
|
||||
/* Mad */
|
||||
{ 4, DxbcInstClass::VectorAlu, {
|
||||
{ DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
|
||||
{ DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
|
||||
{ DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
|
||||
{ DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
|
||||
} },
|
||||
/* Min */
|
||||
{ },
|
||||
/* Max */
|
||||
{ },
|
||||
/* CustomData */
|
||||
{ },
|
||||
/* Mov */
|
||||
{ 2, DxbcInstClass::VectorAlu, {
|
||||
{ DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
|
||||
{ DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
|
||||
} },
|
||||
/* Movc */
|
||||
{ },
|
||||
/* Mul */
|
||||
{ 3, DxbcInstClass::VectorAlu, {
|
||||
{ DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
|
||||
{ DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
|
||||
{ DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
|
||||
} },
|
||||
/* Ne */
|
||||
{ },
|
||||
/* Nop */
|
||||
{ },
|
||||
/* Not */
|
||||
{ },
|
||||
/* Or */
|
||||
{ },
|
||||
/* ResInfo */
|
||||
{ },
|
||||
/* Ret */
|
||||
{ 0, DxbcInstClass::ControlFlow },
|
||||
/* Retc */
|
||||
{ },
|
||||
/* RoundNe */
|
||||
{ },
|
||||
/* RoundNi */
|
||||
{ },
|
||||
/* RoundPi */
|
||||
{ },
|
||||
/* RoundZ */
|
||||
{ },
|
||||
/* Rsq */
|
||||
{ 2, DxbcInstClass::VectorAlu, {
|
||||
{ DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
|
||||
{ DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
|
||||
} },
|
||||
/* Sample */
|
||||
{ 4, DxbcInstClass::TextureSample, {
|
||||
{ DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
|
||||
{ DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
|
||||
{ DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
|
||||
{ DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
|
||||
} },
|
||||
/* SampleC */
|
||||
{ },
|
||||
/* SampleClz */
|
||||
{ },
|
||||
/* SampleL */
|
||||
{ },
|
||||
/* SampleD */
|
||||
{ },
|
||||
/* SampleB */
|
||||
{ },
|
||||
/* Sqrt */
|
||||
{ },
|
||||
/* Switch */
|
||||
{ },
|
||||
/* SinCos */
|
||||
{ },
|
||||
/* UDiv */
|
||||
{ },
|
||||
/* ULt */
|
||||
{ },
|
||||
/* UGe */
|
||||
{ },
|
||||
/* UMul */
|
||||
{ },
|
||||
/* UMad */
|
||||
{ },
|
||||
/* UMax */
|
||||
{ },
|
||||
/* UMin */
|
||||
{ },
|
||||
/* UShr */
|
||||
{ },
|
||||
/* UtoF */
|
||||
{ },
|
||||
/* Xor */
|
||||
{ },
|
||||
/* DclResource */
|
||||
{ 2, DxbcInstClass::Declaration, {
|
||||
{ DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
|
||||
{ DxbcOperandKind::Imm32, DxbcScalarType::Uint32 },
|
||||
} },
|
||||
/* DclConstantBuffer */
|
||||
{ 1, DxbcInstClass::Declaration, {
|
||||
{ DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
|
||||
} },
|
||||
/* DclSampler */
|
||||
{ 1, DxbcInstClass::Declaration, {
|
||||
{ DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
|
||||
} },
|
||||
/* DclIndexRange */
|
||||
{ },
|
||||
/* DclGsOutputPrimitiveTopology */
|
||||
{ },
|
||||
/* DclGsInputPrimitive */
|
||||
{ },
|
||||
/* DclMaxOutputVertexCount */
|
||||
{ },
|
||||
/* DclInput */
|
||||
{ 1, DxbcInstClass::Declaration, {
|
||||
{ DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
|
||||
} },
|
||||
/* DclInputSgv */
|
||||
{ 2, DxbcInstClass::Declaration, {
|
||||
{ DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
|
||||
{ DxbcOperandKind::Imm32, DxbcScalarType::Uint32 },
|
||||
} },
|
||||
/* DclInputSiv */
|
||||
{ 2, DxbcInstClass::Declaration, {
|
||||
{ DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
|
||||
{ DxbcOperandKind::Imm32, DxbcScalarType::Uint32 },
|
||||
} },
|
||||
/* DclInputPs */
|
||||
{ 1, DxbcInstClass::Declaration, {
|
||||
{ DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
|
||||
} },
|
||||
/* DclInputPsSgv */
|
||||
{ 2, DxbcInstClass::Declaration, {
|
||||
{ DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
|
||||
{ DxbcOperandKind::Imm32, DxbcScalarType::Uint32 },
|
||||
} },
|
||||
/* DclInputPsSiv */
|
||||
{ 2, DxbcInstClass::Declaration, {
|
||||
{ DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
|
||||
{ DxbcOperandKind::Imm32, DxbcScalarType::Uint32 },
|
||||
} },
|
||||
/* DclOutput */
|
||||
{ 1, DxbcInstClass::Declaration, {
|
||||
{ DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
|
||||
} },
|
||||
/* DclOutputSgv */
|
||||
{ 2, DxbcInstClass::Declaration, {
|
||||
{ DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
|
||||
{ DxbcOperandKind::Imm32, DxbcScalarType::Uint32 },
|
||||
} },
|
||||
/* DclOutputSiv */
|
||||
{ 2, DxbcInstClass::Declaration, {
|
||||
{ DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
|
||||
{ DxbcOperandKind::Imm32, DxbcScalarType::Uint32 },
|
||||
} },
|
||||
/* DclTemps */
|
||||
{ 1, DxbcInstClass::Declaration, {
|
||||
{ DxbcOperandKind::Imm32, DxbcScalarType::Uint32 },
|
||||
} },
|
||||
/* DclIndexableTemp */
|
||||
{ },
|
||||
/* DclGlobalFlags */
|
||||
{ 0, DxbcInstClass::Declaration },
|
||||
/* Reserved0 */
|
||||
{ 0, DxbcInstClass::Undefined },
|
||||
/* Lod */
|
||||
{ },
|
||||
/* Gather4 */
|
||||
{ },
|
||||
/* SamplePos */
|
||||
{ },
|
||||
/* SampleInfo */
|
||||
{ },
|
||||
/* Reserved1 */
|
||||
{ },
|
||||
/* HsDecls */
|
||||
{ },
|
||||
/* HsControlPointPhase */
|
||||
{ },
|
||||
/* HsForkPhase */
|
||||
{ },
|
||||
/* HsJoinPhase */
|
||||
{ },
|
||||
/* EmitStream */
|
||||
{ },
|
||||
/* CutStream */
|
||||
{ },
|
||||
/* EmitThenCutStream */
|
||||
{ },
|
||||
/* InterfaceCall */
|
||||
{ },
|
||||
/* BufInfo */
|
||||
{ },
|
||||
/* DerivRtxCoarse */
|
||||
{ },
|
||||
/* DerivRtxFine */
|
||||
{ },
|
||||
/* DerivRtyCoarse */
|
||||
{ },
|
||||
/* DerivRtyFine */
|
||||
{ },
|
||||
/* Gather4C */
|
||||
{ },
|
||||
/* Gather4Po */
|
||||
{ },
|
||||
/* Gather4PoC */
|
||||
{ },
|
||||
/* Rcp */
|
||||
{ },
|
||||
/* F32toF16 */
|
||||
{ },
|
||||
/* F16toF32 */
|
||||
{ },
|
||||
/* UAddc */
|
||||
{ },
|
||||
/* USubb */
|
||||
{ },
|
||||
/* CountBits */
|
||||
{ },
|
||||
/* FirstBitHi */
|
||||
{ },
|
||||
/* FirstBitLo */
|
||||
{ },
|
||||
/* FirstBitShi */
|
||||
{ },
|
||||
/* UBfe */
|
||||
{ },
|
||||
/* IBfe */
|
||||
{ },
|
||||
/* Bfi */
|
||||
{ },
|
||||
/* BfRev */
|
||||
{ },
|
||||
/* Swapc */
|
||||
{ },
|
||||
/* DclStream */
|
||||
{ },
|
||||
/* DclFunctionBody */
|
||||
{ },
|
||||
/* DclFunctionTable */
|
||||
{ },
|
||||
/* DclInterface */
|
||||
{ },
|
||||
/* DclInputControlPointCount */
|
||||
{ },
|
||||
/* DclOutputControlPointCount */
|
||||
{ },
|
||||
/* DclTessDomain */
|
||||
{ },
|
||||
/* DclTessPartitioning */
|
||||
{ },
|
||||
/* DclTessOutputPrimitive */
|
||||
{ },
|
||||
/* DclHsMaxTessFactor */
|
||||
{ },
|
||||
/* DclHsForkPhaseInstanceCount */
|
||||
{ },
|
||||
/* DclHsJoinPhaseInstanceCount */
|
||||
{ },
|
||||
/* DclThreadGroup */
|
||||
{ },
|
||||
/* DclUavTyped */
|
||||
{ },
|
||||
/* DclUavRaw */
|
||||
{ },
|
||||
/* DclUavStructured */
|
||||
{ },
|
||||
/* DclThreadGroupSharedMemoryRaw */
|
||||
{ },
|
||||
/* DclThreadGroupSharedMemoryStructured */
|
||||
{ },
|
||||
/* DclResourceRaw */
|
||||
{ },
|
||||
/* DclResourceStructured */
|
||||
{ },
|
||||
/* LdUavTyped */
|
||||
{ },
|
||||
/* StoreUavTyped */
|
||||
{ },
|
||||
/* LdRaw */
|
||||
{ },
|
||||
/* StoreRaw */
|
||||
{ },
|
||||
/* LdStructured */
|
||||
{ },
|
||||
/* StoreStructured */
|
||||
{ },
|
||||
/* AtomicAnd */
|
||||
{ },
|
||||
/* AtomicOr */
|
||||
{ },
|
||||
/* AtomicXor */
|
||||
{ },
|
||||
/* AtomicCmpStore */
|
||||
{ },
|
||||
/* AtomicIAdd */
|
||||
{ },
|
||||
/* AtomicIMax */
|
||||
{ },
|
||||
/* AtomicIMin */
|
||||
{ },
|
||||
/* AtomicUMax */
|
||||
{ },
|
||||
/* AtomicUMin */
|
||||
{ },
|
||||
/* ImmAtomicAlloc */
|
||||
{ },
|
||||
/* ImmAtomicConsume */
|
||||
{ },
|
||||
/* ImmAtomicIAdd */
|
||||
{ },
|
||||
/* ImmAtomicAnd */
|
||||
{ },
|
||||
/* ImmAtomicOr */
|
||||
{ },
|
||||
/* ImmAtomicXor */
|
||||
{ },
|
||||
/* ImmAtomicExch */
|
||||
{ },
|
||||
/* ImmAtomicCmpExch */
|
||||
{ },
|
||||
/* ImmAtomicImax */
|
||||
{ },
|
||||
/* ImmAtomicImin */
|
||||
{ },
|
||||
/* ImmAtomicUmax */
|
||||
{ },
|
||||
/* ImmAtomicUmin */
|
||||
{ },
|
||||
/* Sync */
|
||||
{ },
|
||||
/* DAdd */
|
||||
{ },
|
||||
/* DMax */
|
||||
{ },
|
||||
/* DMin */
|
||||
{ },
|
||||
/* DMul */
|
||||
{ },
|
||||
/* DEq */
|
||||
{ },
|
||||
/* DGe */
|
||||
{ },
|
||||
/* DLt */
|
||||
{ },
|
||||
/* DNe */
|
||||
{ },
|
||||
/* DMov */
|
||||
{ },
|
||||
/* DMovc */
|
||||
{ },
|
||||
/* DtoF */
|
||||
{ },
|
||||
/* FtoD */
|
||||
{ },
|
||||
/* EvalSnapped */
|
||||
{ },
|
||||
/* EvalSampleIndex */
|
||||
{ },
|
||||
/* EvalCentroid */
|
||||
{ },
|
||||
/* DclGsInstanceCount */
|
||||
{ },
|
||||
}};
|
||||
|
||||
|
||||
DxbcInstFormat dxbcInstructionFormat(DxbcOpcode opcode) {
|
||||
const uint32_t idx = static_cast<uint32_t>(opcode);
|
||||
|
||||
return (idx < g_instructionFormats.size())
|
||||
? g_instructionFormats.at(idx)
|
||||
: DxbcInstFormat();
|
||||
}
|
||||
|
||||
}
|
40
src/dxbc/dxbc_defs.h
Normal file
40
src/dxbc/dxbc_defs.h
Normal file
@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include "dxbc_enums.h"
|
||||
#include "dxbc_type.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
constexpr size_t DxbcMaxInterfaceRegs = 32;
|
||||
constexpr size_t DxbcMaxOperandCount = 8;
|
||||
|
||||
enum class DxbcOperandKind {
|
||||
DstReg, ///< Destination register
|
||||
SrcReg, ///< Source register
|
||||
Imm32, ///< Constant number
|
||||
};
|
||||
|
||||
enum class DxbcInstClass {
|
||||
Declaration, ///< Interface or resource declaration
|
||||
TextureSample, ///< Texture sampling instruction
|
||||
VectorAlu, ///< Component-wise vector instructions
|
||||
VectorCmp, ///< Component-wise vector comparison
|
||||
VectorDot, ///< Dot product instruction
|
||||
ControlFlow, ///< Control flow instructions
|
||||
Undefined, ///< Instruction code not defined
|
||||
};
|
||||
|
||||
struct DxbcInstOperandFormat {
|
||||
DxbcOperandKind kind;
|
||||
DxbcScalarType type;
|
||||
};
|
||||
|
||||
struct DxbcInstFormat {
|
||||
uint32_t operandCount = 0;
|
||||
DxbcInstClass instructionClass = DxbcInstClass::Undefined;
|
||||
DxbcInstOperandFormat operands[DxbcMaxOperandCount];
|
||||
};
|
||||
|
||||
DxbcInstFormat dxbcInstructionFormat(DxbcOpcode opcode);
|
||||
|
||||
}
|
@ -44,12 +44,20 @@ namespace dxvk {
|
||||
if (m_shexChunk == nullptr)
|
||||
throw DxvkError("DxbcModule::compile: No SHDR/SHEX chunk");
|
||||
|
||||
DxbcCompiler compiler(
|
||||
DxbcCompiler2 compiler(
|
||||
m_shexChunk->version(),
|
||||
m_isgnChunk, m_osgnChunk);
|
||||
|
||||
for (auto ins : *m_shexChunk)
|
||||
compiler.processInstruction(ins);
|
||||
for (auto ins : *m_shexChunk) {
|
||||
const DxbcError error = compiler.processInstruction(ins);
|
||||
|
||||
if (error != DxbcError::sOk) {
|
||||
Logger::err(str::format(
|
||||
"dxbc: Error while processing ",
|
||||
ins.token().opcode(), ": Error ",
|
||||
static_cast<uint32_t>(error)));
|
||||
}
|
||||
}
|
||||
|
||||
return compiler.finalize();
|
||||
}
|
||||
|
@ -1,707 +0,0 @@
|
||||
#include "dxbc_gen_common.h"
|
||||
#include "dxbc_gen_pixel.h"
|
||||
#include "dxbc_gen_vertex.h"
|
||||
|
||||
#include "../dxbc_names.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
DxbcCodeGen::DxbcCodeGen(DxbcProgramType shaderStage)
|
||||
: m_shaderStage(shaderStage) {
|
||||
m_module.setMemoryModel(
|
||||
spv::AddressingModelLogical,
|
||||
spv::MemoryModelGLSL450);
|
||||
m_entryPointId = m_module.allocateId();
|
||||
}
|
||||
|
||||
|
||||
DxbcCodeGen::~DxbcCodeGen() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
void DxbcCodeGen::dclTemps(uint32_t n) {
|
||||
const uint32_t oldSize = m_rRegs.size();
|
||||
|
||||
if (n > oldSize) {
|
||||
m_rRegs.resize(n);
|
||||
|
||||
for (uint32_t i = oldSize; i < n; i++) {
|
||||
m_rRegs.at(i) = this->defVar(
|
||||
DxbcValueType(DxbcScalarType::Float32, 4),
|
||||
spv::StorageClassPrivate);
|
||||
m_module.setDebugName(m_rRegs.at(i).valueId,
|
||||
str::format("r", i).c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DxbcCodeGen::dclConstantBuffer(
|
||||
uint32_t bufferId,
|
||||
uint32_t elementCount) {
|
||||
// Uniform buffer data is stored as a fixed-size array
|
||||
// of 4x32-bit vectors. SPIR-V requires explicit strides.
|
||||
uint32_t arrayType = m_module.defArrayTypeUnique(
|
||||
this->defValueType(DxbcValueType(DxbcScalarType::Float32, 4)),
|
||||
m_module.constu32(elementCount));
|
||||
m_module.decorateArrayStride(arrayType, 16);
|
||||
|
||||
// SPIR-V requires us to put that array into a
|
||||
// struct and decorate that struct as a block.
|
||||
uint32_t structType = m_module.defStructTypeUnique(1, &arrayType);
|
||||
m_module.memberDecorateOffset(structType, 0, 0);
|
||||
m_module.decorateBlock(structType);
|
||||
|
||||
// Variable that we'll use to access the buffer
|
||||
uint32_t varId = m_module.newVar(
|
||||
m_module.defPointerType(structType, spv::StorageClassUniform),
|
||||
spv::StorageClassUniform);
|
||||
|
||||
m_module.setDebugName(varId,
|
||||
str::format("cb", bufferId).c_str());
|
||||
|
||||
m_constantBuffers.at(bufferId).varId = varId;
|
||||
m_constantBuffers.at(bufferId).size = elementCount;
|
||||
|
||||
// Compute the DXVK binding slot index for the buffer.
|
||||
// D3D11 needs to bind the actual buffers to this slot.
|
||||
uint32_t bindingId = computeResourceSlotId(m_shaderStage,
|
||||
DxbcBindingType::ConstantBuffer, bufferId);
|
||||
|
||||
m_module.decorateDescriptorSet(varId, 0);
|
||||
m_module.decorateBinding(varId, bindingId);
|
||||
|
||||
// Store descriptor info for the shader interface
|
||||
DxvkResourceSlot resource;
|
||||
resource.slot = bindingId;
|
||||
resource.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
m_resourceSlots.push_back(resource);
|
||||
}
|
||||
|
||||
|
||||
void DxbcCodeGen::dclResource(
|
||||
uint32_t registerId,
|
||||
DxbcResourceDim resourceType,
|
||||
DxbcResourceReturnType returnType) {
|
||||
uint32_t sampledTypeId = 0;
|
||||
|
||||
switch (returnType) {
|
||||
default: Logger::err(str::format("DXBC: Invalid sampled type: ", returnType));
|
||||
case DxbcResourceReturnType::Float: sampledTypeId = m_module.defFloatType(32); break;
|
||||
case DxbcResourceReturnType::Sint: sampledTypeId = m_module.defIntType (32, 1); break;
|
||||
case DxbcResourceReturnType::Uint: sampledTypeId = m_module.defIntType (32, 0); break;
|
||||
}
|
||||
|
||||
uint32_t textureTypeId = 0;
|
||||
|
||||
switch (resourceType) {
|
||||
default:
|
||||
Logger::err(str::format(
|
||||
"DXBC: Invalid resource type: ",
|
||||
resourceType));
|
||||
|
||||
case DxbcResourceDim::Texture1D:
|
||||
textureTypeId = m_module.defImageType(
|
||||
sampledTypeId, spv::Dim1D, 0, 0, 0, 1,
|
||||
spv::ImageFormatUnknown);
|
||||
break;
|
||||
|
||||
case DxbcResourceDim::Texture1DArr:
|
||||
textureTypeId = m_module.defImageType(
|
||||
sampledTypeId, spv::Dim1D, 0, 1, 0, 1,
|
||||
spv::ImageFormatUnknown);
|
||||
break;
|
||||
|
||||
case DxbcResourceDim::Texture2D:
|
||||
textureTypeId = m_module.defImageType(
|
||||
sampledTypeId, spv::Dim2D, 0, 0, 0, 1,
|
||||
spv::ImageFormatUnknown);
|
||||
break;
|
||||
|
||||
case DxbcResourceDim::Texture2DArr:
|
||||
textureTypeId = m_module.defImageType(
|
||||
sampledTypeId, spv::Dim2D, 0, 1, 0, 1,
|
||||
spv::ImageFormatUnknown);
|
||||
break;
|
||||
|
||||
case DxbcResourceDim::Texture3D:
|
||||
textureTypeId = m_module.defImageType(
|
||||
sampledTypeId, spv::Dim3D, 0, 0, 0, 1,
|
||||
spv::ImageFormatUnknown);
|
||||
break;
|
||||
|
||||
case DxbcResourceDim::TextureCube:
|
||||
textureTypeId = m_module.defImageType(
|
||||
sampledTypeId, spv::DimCube, 0, 0, 0, 1,
|
||||
spv::ImageFormatUnknown);
|
||||
break;
|
||||
|
||||
case DxbcResourceDim::TextureCubeArr:
|
||||
textureTypeId = m_module.defImageType(
|
||||
sampledTypeId, spv::DimCube, 0, 1, 0, 1,
|
||||
spv::ImageFormatUnknown);
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t resourcePtrType = m_module.defPointerType(
|
||||
textureTypeId, spv::StorageClassUniformConstant);
|
||||
|
||||
uint32_t varId = m_module.newVar(resourcePtrType,
|
||||
spv::StorageClassUniformConstant);
|
||||
|
||||
m_module.setDebugName(varId,
|
||||
str::format("t", registerId).c_str());
|
||||
|
||||
m_textures.at(registerId).varId = varId;
|
||||
m_textures.at(registerId).sampledTypeId = sampledTypeId;
|
||||
m_textures.at(registerId).textureTypeId = textureTypeId;
|
||||
|
||||
// Compute the DXVK binding slot index for the resource.
|
||||
// D3D11 needs to bind the actual resource to this slot.
|
||||
uint32_t bindingId = computeResourceSlotId(m_shaderStage,
|
||||
DxbcBindingType::ShaderResource, registerId);
|
||||
|
||||
m_module.decorateDescriptorSet(varId, 0);
|
||||
m_module.decorateBinding(varId, bindingId);
|
||||
|
||||
// Store descriptor info for the shader interface
|
||||
DxvkResourceSlot resource;
|
||||
resource.slot = bindingId;
|
||||
resource.type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
|
||||
m_resourceSlots.push_back(resource);
|
||||
}
|
||||
|
||||
|
||||
void DxbcCodeGen::dclSampler(uint32_t samplerId) {
|
||||
// The sampler type is opaque, but we still have to
|
||||
// define a pointer and a variable in oder to use it
|
||||
uint32_t samplerType = m_module.defSamplerType();
|
||||
uint32_t samplerPtrType = m_module.defPointerType(
|
||||
samplerType, spv::StorageClassUniformConstant);
|
||||
|
||||
// Define the sampler variable
|
||||
uint32_t varId = m_module.newVar(samplerPtrType,
|
||||
spv::StorageClassUniformConstant);
|
||||
|
||||
m_module.setDebugName(varId,
|
||||
str::format("s", samplerId).c_str());
|
||||
|
||||
m_samplers.at(samplerId).varId = varId;
|
||||
m_samplers.at(samplerId).typeId = samplerType;
|
||||
|
||||
// Compute binding slot index for the sampler
|
||||
uint32_t bindingId = computeResourceSlotId(m_shaderStage,
|
||||
DxbcBindingType::ImageSampler, samplerId);
|
||||
|
||||
m_module.decorateDescriptorSet(varId, 0);
|
||||
m_module.decorateBinding(varId, bindingId);
|
||||
|
||||
// Store descriptor info for the shader interface
|
||||
DxvkResourceSlot resource;
|
||||
resource.slot = bindingId;
|
||||
resource.type = VK_DESCRIPTOR_TYPE_SAMPLER;
|
||||
m_resourceSlots.push_back(resource);
|
||||
}
|
||||
|
||||
|
||||
DxbcValue DxbcCodeGen::defConstScalar(uint32_t v) {
|
||||
DxbcValue result;
|
||||
result.type = DxbcValueType(DxbcScalarType::Uint32, 1);
|
||||
result.valueId = m_module.constu32(v);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
DxbcValue DxbcCodeGen::defConstVector(
|
||||
uint32_t x, uint32_t y,
|
||||
uint32_t z, uint32_t w) {
|
||||
std::array<uint32_t, 4> ids = {
|
||||
m_module.constu32(x),
|
||||
m_module.constu32(y),
|
||||
m_module.constu32(z),
|
||||
m_module.constu32(w) };
|
||||
|
||||
DxbcValue result;
|
||||
result.type = DxbcValueType(DxbcScalarType::Uint32, 4);
|
||||
result.valueId = m_module.constComposite(
|
||||
this->defValueType(result.type),
|
||||
ids.size(), ids.data());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void DxbcCodeGen::fnReturn() {
|
||||
// TODO implement control flow
|
||||
m_module.opReturn();
|
||||
m_module.functionEnd();
|
||||
}
|
||||
|
||||
|
||||
DxbcPointer DxbcCodeGen::ptrTempReg(uint32_t regId) {
|
||||
return m_rRegs.at(regId);
|
||||
}
|
||||
|
||||
|
||||
DxbcPointer DxbcCodeGen::ptrConstantBuffer(
|
||||
uint32_t regId,
|
||||
const DxbcValue& index) {
|
||||
// The first index selects the struct member,
|
||||
// the second one selects the array element.
|
||||
std::array<uint32_t, 2> indices = {
|
||||
m_module.constu32(0), index.valueId };
|
||||
|
||||
DxbcPointer result;
|
||||
result.type = DxbcPointerType(
|
||||
DxbcValueType(DxbcScalarType::Float32, 4),
|
||||
spv::StorageClassUniform);
|
||||
result.valueId = m_module.opAccessChain(
|
||||
this->defPointerType(result.type),
|
||||
m_constantBuffers.at(regId).varId,
|
||||
2, indices.data());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
DxbcValue DxbcCodeGen::opAbs(const DxbcValue& src) {
|
||||
DxbcValue result;
|
||||
result.type = src.type;
|
||||
|
||||
switch (src.type.componentType) {
|
||||
case DxbcScalarType::Sint32:
|
||||
case DxbcScalarType::Sint64:
|
||||
result.valueId = m_module.opSAbs(
|
||||
this->defValueType(result.type),
|
||||
src.valueId);
|
||||
break;
|
||||
|
||||
case DxbcScalarType::Uint32:
|
||||
case DxbcScalarType::Uint64:
|
||||
result.valueId = src.valueId;
|
||||
break;
|
||||
|
||||
case DxbcScalarType::Float32:
|
||||
case DxbcScalarType::Float64:
|
||||
result.valueId = m_module.opFAbs(
|
||||
this->defValueType(result.type),
|
||||
src.valueId);
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
DxbcValue DxbcCodeGen::opAdd(const DxbcValue& a, const DxbcValue& b) {
|
||||
DxbcValue result;
|
||||
result.type = a.type;
|
||||
|
||||
switch (result.type.componentType) {
|
||||
case DxbcScalarType::Sint32:
|
||||
case DxbcScalarType::Sint64:
|
||||
case DxbcScalarType::Uint32:
|
||||
case DxbcScalarType::Uint64:
|
||||
result.valueId = m_module.opIAdd(
|
||||
this->defValueType(result.type),
|
||||
a.valueId, b.valueId);
|
||||
break;
|
||||
|
||||
case DxbcScalarType::Float32:
|
||||
case DxbcScalarType::Float64:
|
||||
result.valueId = m_module.opFAdd(
|
||||
this->defValueType(result.type),
|
||||
a.valueId, b.valueId);
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
DxbcValue DxbcCodeGen::opMul(const DxbcValue& a, const DxbcValue& b) {
|
||||
DxbcValue result;
|
||||
result.type = a.type;
|
||||
|
||||
switch (result.type.componentType) {
|
||||
case DxbcScalarType::Sint32:
|
||||
case DxbcScalarType::Sint64:
|
||||
case DxbcScalarType::Uint32:
|
||||
case DxbcScalarType::Uint64:
|
||||
result.valueId = m_module.opIMul(
|
||||
this->defValueType(result.type),
|
||||
a.valueId, b.valueId);
|
||||
break;
|
||||
|
||||
case DxbcScalarType::Float32:
|
||||
case DxbcScalarType::Float64:
|
||||
result.valueId = m_module.opFMul(
|
||||
this->defValueType(result.type),
|
||||
a.valueId, b.valueId);
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
DxbcValue DxbcCodeGen::opDot(const DxbcValue& a, const DxbcValue& b) {
|
||||
DxbcValue result;
|
||||
result.type = DxbcValueType(a.type.componentType, 1);
|
||||
result.valueId = m_module.opDot(
|
||||
this->defValueType(result.type),
|
||||
a.valueId, b.valueId);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
DxbcValue DxbcCodeGen::opRsqrt(const DxbcValue& src) {
|
||||
DxbcValue result;
|
||||
result.type = src.type;
|
||||
result.valueId = m_module.opInverseSqrt(
|
||||
this->defValueType(result.type),
|
||||
src.valueId);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
DxbcValue DxbcCodeGen::opNeg(const DxbcValue& src) {
|
||||
DxbcValue result;
|
||||
result.type = src.type;
|
||||
|
||||
switch (src.type.componentType) {
|
||||
case DxbcScalarType::Sint32:
|
||||
case DxbcScalarType::Sint64:
|
||||
case DxbcScalarType::Uint32:
|
||||
case DxbcScalarType::Uint64:
|
||||
result.valueId = m_module.opSNegate(
|
||||
this->defValueType(result.type),
|
||||
src.valueId);
|
||||
break;
|
||||
|
||||
case DxbcScalarType::Float32:
|
||||
case DxbcScalarType::Float64:
|
||||
result.valueId = m_module.opFNegate(
|
||||
this->defValueType(result.type),
|
||||
src.valueId);
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
DxbcValue DxbcCodeGen::opSaturate(const DxbcValue& src) {
|
||||
const uint32_t typeId = this->defValueType(src.type);
|
||||
|
||||
std::array<uint32_t, 4> const0;
|
||||
std::array<uint32_t, 4> const1;
|
||||
|
||||
uint32_t const0Id = 0;
|
||||
uint32_t const1Id = 0;
|
||||
|
||||
if (src.type.componentType == DxbcScalarType::Float32) {
|
||||
const0Id = m_module.constf32(0.0f);
|
||||
const1Id = m_module.constf32(1.0f);
|
||||
} else if (src.type.componentType == DxbcScalarType::Float64) {
|
||||
const0Id = m_module.constf64(0.0);
|
||||
const1Id = m_module.constf64(1.0);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < src.type.componentCount; i++) {
|
||||
const0.at(i) = const0Id;
|
||||
const1.at(i) = const1Id;
|
||||
}
|
||||
|
||||
if (src.type.componentCount > 1) {
|
||||
const0Id = m_module.constComposite(typeId, src.type.componentCount, const0.data());
|
||||
const1Id = m_module.constComposite(typeId, src.type.componentCount, const1.data());
|
||||
}
|
||||
|
||||
DxbcValue result;
|
||||
result.type = src.type;
|
||||
result.valueId = m_module.opFClamp(
|
||||
typeId, src.valueId, const0Id, const1Id);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
DxbcValue DxbcCodeGen::regCast(
|
||||
const DxbcValue& src,
|
||||
const DxbcValueType& type) {
|
||||
if (src.type.componentType == type.componentType)
|
||||
return src;
|
||||
|
||||
DxbcValue result;
|
||||
result.type = type;
|
||||
result.valueId = m_module.opBitcast(
|
||||
this->defValueType(result.type),
|
||||
src.valueId);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
DxbcValue DxbcCodeGen::regExtract(
|
||||
const DxbcValue& src,
|
||||
DxbcComponentMask mask) {
|
||||
return this->regSwizzle(src,
|
||||
DxbcComponentSwizzle(), mask);
|
||||
}
|
||||
|
||||
|
||||
DxbcValue DxbcCodeGen::regSwizzle(
|
||||
const DxbcValue& src,
|
||||
const DxbcComponentSwizzle& swizzle,
|
||||
DxbcComponentMask mask) {
|
||||
std::array<uint32_t, 4> indices;
|
||||
|
||||
uint32_t dstIndex = 0;
|
||||
for (uint32_t i = 0; i < src.type.componentCount; i++) {
|
||||
if (mask.test(i))
|
||||
indices[dstIndex++] = swizzle[i];
|
||||
}
|
||||
|
||||
// If the swizzle combined with the mask can be reduced
|
||||
// to a no-op, we don't need to insert any instructions.
|
||||
bool isIdentitySwizzle = dstIndex == src.type.componentCount;
|
||||
|
||||
for (uint32_t i = 0; i < dstIndex && isIdentitySwizzle; i++)
|
||||
isIdentitySwizzle &= indices[i] == i;
|
||||
|
||||
if (isIdentitySwizzle)
|
||||
return src;
|
||||
|
||||
// Use OpCompositeExtract if the resulting vector contains
|
||||
// only one component, and OpVectorShuffle if it is a vector.
|
||||
DxbcValue result;
|
||||
result.type = DxbcValueType(src.type.componentType, dstIndex);
|
||||
|
||||
if (dstIndex == 1) {
|
||||
result.valueId = m_module.opCompositeExtract(
|
||||
this->defValueType(result.type),
|
||||
src.valueId, 1, indices.data());
|
||||
} else {
|
||||
result.valueId = m_module.opVectorShuffle(
|
||||
this->defValueType(result.type),
|
||||
src.valueId, src.valueId,
|
||||
dstIndex, indices.data());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
DxbcValue DxbcCodeGen::regInsert(
|
||||
const DxbcValue& dst,
|
||||
const DxbcValue& src,
|
||||
DxbcComponentMask mask) {
|
||||
DxbcValue result;
|
||||
result.type = dst.type;
|
||||
|
||||
if (dst.type.componentCount == 1) {
|
||||
// Both values are scalar, so the first component
|
||||
// of the write mask decides which one to take.
|
||||
result.valueId = mask.test(0)
|
||||
? src.valueId : dst.valueId;
|
||||
} else if (src.type.componentCount == 1) {
|
||||
// The source value is scalar. Since OpVectorShuffle
|
||||
// requires both arguments to be vectors, we have to
|
||||
// use OpCompositeInsert to modify the vector instead.
|
||||
const uint32_t componentId = mask.firstComponent();
|
||||
|
||||
result.valueId = m_module.opCompositeInsert(
|
||||
this->defValueType(result.type),
|
||||
src.valueId, dst.valueId,
|
||||
1, &componentId);
|
||||
} else {
|
||||
// Both arguments are vectors. We can determine which
|
||||
// components to take from which vector and use the
|
||||
// OpVectorShuffle instruction.
|
||||
std::array<uint32_t, 4> components;
|
||||
uint32_t srcComponentId = dst.type.componentCount;
|
||||
|
||||
for (uint32_t i = 0; i < dst.type.componentCount; i++)
|
||||
components[i] = mask.test(i) ? srcComponentId++ : i;
|
||||
|
||||
result.valueId = m_module.opVectorShuffle(
|
||||
this->defValueType(result.type),
|
||||
dst.valueId, src.valueId,
|
||||
dst.type.componentCount,
|
||||
components.data());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
DxbcValue DxbcCodeGen::regVector(
|
||||
const DxbcValue& src,
|
||||
uint32_t size) {
|
||||
if (size == 1)
|
||||
return src;
|
||||
|
||||
std::array<uint32_t, 4> ids = {
|
||||
src.valueId, src.valueId, src.valueId, src.valueId,
|
||||
};
|
||||
|
||||
DxbcValue result;
|
||||
result.type = DxbcValueType(src.type.componentType, size);
|
||||
result.valueId = m_module.opCompositeConstruct(
|
||||
this->defValueType(result.type), size, ids.data());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
DxbcValue DxbcCodeGen::regLoad(const DxbcPointer& ptr) {
|
||||
DxbcValue result;
|
||||
result.type = ptr.type.valueType;
|
||||
result.valueId = m_module.opLoad(
|
||||
this->defValueType(result.type),
|
||||
ptr.valueId);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void DxbcCodeGen::regStore(
|
||||
const DxbcPointer& ptr,
|
||||
const DxbcValue& val,
|
||||
DxbcComponentMask mask) {
|
||||
if (ptr.type.valueType.componentCount != val.type.componentCount) {
|
||||
// In case we write to only a part of the destination
|
||||
// register, we need to load the previous value first
|
||||
// and then update the given components.
|
||||
DxbcValue tmp = this->regLoad(ptr);
|
||||
tmp = this->regInsert(tmp, val, mask);
|
||||
|
||||
m_module.opStore(ptr.valueId, tmp.valueId);
|
||||
} else {
|
||||
// All destination components get written, so we don't
|
||||
// need to load and modify the target register first.
|
||||
m_module.opStore(ptr.valueId, val.valueId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DxbcValue DxbcCodeGen::texSample(
|
||||
const uint32_t textureId,
|
||||
const uint32_t samplerId,
|
||||
const DxbcValue& coordinates) {
|
||||
// Combine the texture and the sampler into a sampled image
|
||||
uint32_t sampledImageType = m_module.defSampledImageType(
|
||||
m_textures.at(textureId).textureTypeId);
|
||||
|
||||
uint32_t sampledImageId = m_module.opSampledImage(
|
||||
sampledImageType,
|
||||
m_module.opLoad(
|
||||
m_textures.at(textureId).textureTypeId,
|
||||
m_textures.at(textureId).varId),
|
||||
m_module.opLoad(
|
||||
m_samplers.at(samplerId).typeId,
|
||||
m_samplers.at(samplerId).varId));
|
||||
|
||||
// Sampling an image in SPIR-V always returns a four-component
|
||||
// vector, so we need to declare the corresponding type here
|
||||
// TODO infer sampled type properly
|
||||
DxbcValue result;
|
||||
result.type = DxbcValueType(DxbcScalarType::Float32, 4);
|
||||
result.valueId = m_module.opImageSampleImplicitLod(
|
||||
this->defValueType(result.type),
|
||||
sampledImageId,
|
||||
this->regExtract(coordinates, DxbcComponentMask(true, true, false, false)).valueId);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
Rc<DxbcCodeGen> DxbcCodeGen::create(
|
||||
const DxbcProgramVersion& version,
|
||||
const Rc<DxbcIsgn>& isgn,
|
||||
const Rc<DxbcIsgn>& osgn) {
|
||||
switch (version.type()) {
|
||||
case DxbcProgramType::PixelShader:
|
||||
return new DxbcPsCodeGen(osgn);
|
||||
|
||||
case DxbcProgramType::VertexShader:
|
||||
return new DxbcVsCodeGen(isgn);
|
||||
|
||||
default:
|
||||
throw DxvkError(str::format(
|
||||
"DxbcCodeGen::create: Unsupported program type: ",
|
||||
version.type()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t DxbcCodeGen::defScalarType(DxbcScalarType type) {
|
||||
switch (type) {
|
||||
case DxbcScalarType::Uint32 : return m_module.defIntType(32, 0);
|
||||
case DxbcScalarType::Uint64 : return m_module.defIntType(64, 0);
|
||||
case DxbcScalarType::Sint32 : return m_module.defIntType(32, 1);
|
||||
case DxbcScalarType::Sint64 : return m_module.defIntType(64, 1);
|
||||
case DxbcScalarType::Float32: return m_module.defFloatType(32);
|
||||
case DxbcScalarType::Float64: return m_module.defFloatType(64);
|
||||
|
||||
default:
|
||||
throw DxvkError("DxbcCodeGen::defScalarType: Invalid scalar type");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t DxbcCodeGen::defValueType(const DxbcValueType& type) {
|
||||
uint32_t typeId = this->defScalarType(type.componentType);
|
||||
|
||||
if (type.componentCount > 1)
|
||||
typeId = m_module.defVectorType(typeId, type.componentCount);
|
||||
|
||||
if (type.elementCount > 0)
|
||||
typeId = m_module.defArrayType(typeId, m_module.constu32(type.elementCount));
|
||||
|
||||
return typeId;
|
||||
}
|
||||
|
||||
|
||||
uint32_t DxbcCodeGen::defPointerType(const DxbcPointerType& type) {
|
||||
uint32_t valueTypeId = this->defValueType(type.valueType);
|
||||
return m_module.defPointerType(valueTypeId, type.storageClass);
|
||||
}
|
||||
|
||||
|
||||
uint32_t DxbcCodeGen::defPerVertexBlock() {
|
||||
uint32_t s1f32 = this->defScalarType(DxbcScalarType::Float32);
|
||||
uint32_t v4f32 = this->defValueType(DxbcValueType(DxbcScalarType::Float32, 4, 0));
|
||||
uint32_t a2f32 = this->defValueType(DxbcValueType(DxbcScalarType::Float32, 1, 2));
|
||||
|
||||
std::array<uint32_t, 4> members;
|
||||
members[PerVertex_Position] = v4f32;
|
||||
members[PerVertex_PointSize] = s1f32;
|
||||
members[PerVertex_CullDist] = a2f32;
|
||||
members[PerVertex_ClipDist] = a2f32;
|
||||
|
||||
uint32_t typeId = m_module.defStructTypeUnique(
|
||||
members.size(), members.data());
|
||||
|
||||
m_module.memberDecorateBuiltIn(typeId, PerVertex_Position, spv::BuiltInPosition);
|
||||
m_module.memberDecorateBuiltIn(typeId, PerVertex_PointSize, spv::BuiltInPointSize);
|
||||
m_module.memberDecorateBuiltIn(typeId, PerVertex_CullDist, spv::BuiltInCullDistance);
|
||||
m_module.memberDecorateBuiltIn(typeId, PerVertex_ClipDist, spv::BuiltInClipDistance);
|
||||
m_module.decorateBlock(typeId);
|
||||
|
||||
m_module.setDebugName(typeId, "per_vertex");
|
||||
m_module.setDebugMemberName(typeId, PerVertex_Position, "position");
|
||||
m_module.setDebugMemberName(typeId, PerVertex_PointSize, "point_size");
|
||||
m_module.setDebugMemberName(typeId, PerVertex_CullDist, "cull_dist");
|
||||
m_module.setDebugMemberName(typeId, PerVertex_ClipDist, "clip_dist");
|
||||
return typeId;
|
||||
}
|
||||
|
||||
|
||||
DxbcPointer DxbcCodeGen::defVar(
|
||||
const DxbcValueType& type,
|
||||
spv::StorageClass storageClass) {
|
||||
DxbcPointer result;
|
||||
result.type = DxbcPointerType(type, storageClass);
|
||||
result.valueId = m_module.newVar(
|
||||
this->defPointerType(result.type),
|
||||
storageClass);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
@ -1,228 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "../dxbc_chunk_isgn.h"
|
||||
#include "../dxbc_common.h"
|
||||
#include "../dxbc_decoder.h"
|
||||
#include "../dxbc_type.h"
|
||||
#include "../dxbc_util.h"
|
||||
|
||||
#include "../../spirv/spirv_module.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief System value mapping
|
||||
*
|
||||
* Maps a system value to a given set of
|
||||
* components of an input or output register.
|
||||
*/
|
||||
struct DxbcSvMapping {
|
||||
uint32_t regId;
|
||||
DxbcComponentMask regMask;
|
||||
DxbcSystemValue sv;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Constant buffer binding
|
||||
*
|
||||
* Stores information required to
|
||||
* access a constant buffer.
|
||||
*/
|
||||
struct DxbcConstantBuffer {
|
||||
uint32_t varId = 0;
|
||||
uint32_t size = 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Sampler binding
|
||||
*
|
||||
* Stores a sampler variable.
|
||||
*/
|
||||
struct DxbcSampler {
|
||||
uint32_t varId = 0;
|
||||
uint32_t typeId = 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Shader resource binding
|
||||
*
|
||||
* Stores the sampler variable as well as
|
||||
*/
|
||||
struct DxbcShaderResource {
|
||||
uint32_t varId = 0;
|
||||
uint32_t sampledTypeId = 0;
|
||||
uint32_t textureTypeId = 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief DXBC code generator
|
||||
*
|
||||
* SPIR-V code generator. Implements simple micro ops that are
|
||||
* generated when parsing the DXBC shader code. Some of these
|
||||
* may require different implementations for each shader stage
|
||||
* and are therefore implemented in a sub class.
|
||||
*/
|
||||
class DxbcCodeGen : public RcObject {
|
||||
|
||||
public:
|
||||
|
||||
DxbcCodeGen(DxbcProgramType shaderStage);
|
||||
|
||||
virtual ~DxbcCodeGen();
|
||||
|
||||
void dclTemps(uint32_t n);
|
||||
|
||||
void dclConstantBuffer(
|
||||
uint32_t registerId,
|
||||
uint32_t elementCount);
|
||||
|
||||
void dclResource(
|
||||
uint32_t registerId,
|
||||
DxbcResourceDim resourceType,
|
||||
DxbcResourceReturnType returnType);
|
||||
|
||||
void dclSampler(
|
||||
uint32_t registerId);
|
||||
|
||||
DxbcValue defConstScalar(uint32_t v);
|
||||
|
||||
DxbcValue defConstVector(
|
||||
uint32_t x, uint32_t y,
|
||||
uint32_t z, uint32_t w);
|
||||
|
||||
void fnReturn();
|
||||
|
||||
DxbcPointer ptrTempReg(
|
||||
uint32_t regId);
|
||||
|
||||
DxbcPointer ptrConstantBuffer(
|
||||
uint32_t regId,
|
||||
const DxbcValue& index);
|
||||
|
||||
DxbcValue opAbs(
|
||||
const DxbcValue& src);
|
||||
|
||||
DxbcValue opAdd(
|
||||
const DxbcValue& a,
|
||||
const DxbcValue& b);
|
||||
|
||||
DxbcValue opMul(
|
||||
const DxbcValue& a,
|
||||
const DxbcValue& b);
|
||||
|
||||
DxbcValue opDot(
|
||||
const DxbcValue& a,
|
||||
const DxbcValue& b);
|
||||
|
||||
DxbcValue opRsqrt(
|
||||
const DxbcValue& src);
|
||||
|
||||
DxbcValue opNeg(
|
||||
const DxbcValue& src);
|
||||
|
||||
DxbcValue opSaturate(
|
||||
const DxbcValue& src);
|
||||
|
||||
DxbcValue regCast(
|
||||
const DxbcValue& src,
|
||||
const DxbcValueType& type);
|
||||
|
||||
DxbcValue regExtract(
|
||||
const DxbcValue& src,
|
||||
DxbcComponentMask mask);
|
||||
|
||||
DxbcValue regSwizzle(
|
||||
const DxbcValue& src,
|
||||
const DxbcComponentSwizzle& swizzle,
|
||||
DxbcComponentMask mask);
|
||||
|
||||
DxbcValue regInsert(
|
||||
const DxbcValue& dst,
|
||||
const DxbcValue& src,
|
||||
DxbcComponentMask mask);
|
||||
|
||||
DxbcValue regVector(
|
||||
const DxbcValue& src,
|
||||
uint32_t size);
|
||||
|
||||
DxbcValue regLoad(
|
||||
const DxbcPointer& ptr);
|
||||
|
||||
void regStore(
|
||||
const DxbcPointer& ptr,
|
||||
const DxbcValue& val,
|
||||
DxbcComponentMask mask);
|
||||
|
||||
DxbcValue texSample(
|
||||
const uint32_t textureId,
|
||||
const uint32_t samplerId,
|
||||
const DxbcValue& coordinates);
|
||||
|
||||
virtual void dclInterfaceVar(
|
||||
DxbcOperandType regType,
|
||||
uint32_t regId,
|
||||
uint32_t regDim,
|
||||
DxbcComponentMask regMask,
|
||||
DxbcSystemValue sv,
|
||||
DxbcInterpolationMode im) = 0;
|
||||
|
||||
virtual DxbcPointer ptrInterfaceVar(
|
||||
DxbcOperandType regType,
|
||||
uint32_t regId) = 0;
|
||||
|
||||
virtual DxbcPointer ptrInterfaceVarIndexed(
|
||||
DxbcOperandType regType,
|
||||
uint32_t regId,
|
||||
const DxbcValue& index) = 0;
|
||||
|
||||
virtual Rc<DxvkShader> finalize() = 0;
|
||||
|
||||
static Rc<DxbcCodeGen> create(
|
||||
const DxbcProgramVersion& version,
|
||||
const Rc<DxbcIsgn>& isgn,
|
||||
const Rc<DxbcIsgn>& osgn);
|
||||
|
||||
protected:
|
||||
|
||||
constexpr static uint32_t PerVertex_Position = 0;
|
||||
constexpr static uint32_t PerVertex_PointSize = 1;
|
||||
constexpr static uint32_t PerVertex_CullDist = 2;
|
||||
constexpr static uint32_t PerVertex_ClipDist = 3;
|
||||
|
||||
const DxbcProgramType m_shaderStage;
|
||||
|
||||
SpirvModule m_module;
|
||||
|
||||
std::vector<uint32_t> m_entryPointInterfaces;
|
||||
uint32_t m_entryPointId = 0;
|
||||
|
||||
std::vector<DxbcPointer> m_rRegs;
|
||||
|
||||
std::array<DxbcConstantBuffer, 16> m_constantBuffers;
|
||||
std::array<DxbcSampler, 16> m_samplers;
|
||||
std::array<DxbcShaderResource, 128> m_textures;
|
||||
|
||||
std::vector<DxvkResourceSlot> m_resourceSlots;
|
||||
|
||||
uint32_t defScalarType(
|
||||
DxbcScalarType type);
|
||||
|
||||
uint32_t defValueType(
|
||||
const DxbcValueType& type);
|
||||
|
||||
uint32_t defPointerType(
|
||||
const DxbcPointerType& type);
|
||||
|
||||
uint32_t defPerVertexBlock();
|
||||
|
||||
DxbcPointer defVar(
|
||||
const DxbcValueType& type,
|
||||
spv::StorageClass storageClass);
|
||||
|
||||
};
|
||||
|
||||
}
|
@ -1,217 +0,0 @@
|
||||
#include "dxbc_gen_pixel.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
DxbcPsCodeGen::DxbcPsCodeGen(const Rc<DxbcIsgn>& osgn)
|
||||
: DxbcCodeGen(DxbcProgramType::PixelShader) {
|
||||
m_module.enableCapability(spv::CapabilityShader);
|
||||
m_module.enableCapability(spv::CapabilityCullDistance);
|
||||
m_module.enableCapability(spv::CapabilityClipDistance);
|
||||
|
||||
m_function = m_module.allocateId();
|
||||
m_module.setDebugName(m_function, "ps_main");
|
||||
|
||||
m_module.functionBegin(
|
||||
m_module.defVoidType(),
|
||||
m_function,
|
||||
m_module.defFunctionType(
|
||||
m_module.defVoidType(), 0, nullptr),
|
||||
spv::FunctionControlMaskNone);
|
||||
m_module.opLabel(m_module.allocateId());
|
||||
|
||||
// Declare outputs based on the input signature
|
||||
for (auto e = osgn->begin(); e != osgn->end(); e++) {
|
||||
if (e->systemValue == DxbcSystemValue::None) {
|
||||
const DxbcPointer var = this->defVar(
|
||||
DxbcValueType(e->componentType, e->componentMask.componentCount()),
|
||||
spv::StorageClassOutput);
|
||||
|
||||
m_psOut.at(e->registerId) = var;
|
||||
|
||||
m_module.decorateLocation(var.valueId, e->registerId);
|
||||
m_module.setDebugName(var.valueId,
|
||||
str::format("ps_out", e->registerId).c_str());
|
||||
m_entryPointInterfaces.push_back(var.valueId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DxbcPsCodeGen::~DxbcPsCodeGen() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
void DxbcPsCodeGen::dclInterfaceVar(
|
||||
DxbcOperandType regType,
|
||||
uint32_t regId,
|
||||
uint32_t regDim,
|
||||
DxbcComponentMask regMask,
|
||||
DxbcSystemValue sv,
|
||||
DxbcInterpolationMode im) {
|
||||
switch (regType) {
|
||||
case DxbcOperandType::Input: {
|
||||
if (m_vRegs.at(regId).valueId == 0) {
|
||||
const DxbcPointer var = this->defVar(
|
||||
DxbcValueType(DxbcScalarType::Float32, 4),
|
||||
spv::StorageClassInput);
|
||||
|
||||
m_vRegs.at(regId) = var;
|
||||
m_module.decorateLocation(var.valueId, regId);
|
||||
m_module.setDebugName(var.valueId,
|
||||
str::format("v", regId).c_str());
|
||||
m_entryPointInterfaces.push_back(var.valueId);
|
||||
|
||||
switch (im) {
|
||||
case DxbcInterpolationMode::Undefined:
|
||||
case DxbcInterpolationMode::Linear:
|
||||
break;
|
||||
|
||||
case DxbcInterpolationMode::Constant:
|
||||
m_module.decorate(var.valueId, spv::DecorationFlat);
|
||||
break;
|
||||
|
||||
case DxbcInterpolationMode::LinearCentroid:
|
||||
m_module.decorate(var.valueId, spv::DecorationCentroid);
|
||||
break;
|
||||
|
||||
case DxbcInterpolationMode::LinearNoPerspective:
|
||||
m_module.decorate(var.valueId, spv::DecorationNoPerspective);
|
||||
break;
|
||||
|
||||
case DxbcInterpolationMode::LinearNoPerspectiveCentroid:
|
||||
m_module.decorate(var.valueId, spv::DecorationNoPerspective);
|
||||
m_module.decorate(var.valueId, spv::DecorationCentroid);
|
||||
break;
|
||||
|
||||
case DxbcInterpolationMode::LinearSample:
|
||||
m_module.decorate(var.valueId, spv::DecorationSample);
|
||||
break;
|
||||
|
||||
case DxbcInterpolationMode::LinearNoPerspectiveSample:
|
||||
m_module.decorate(var.valueId, spv::DecorationNoPerspective);
|
||||
m_module.decorate(var.valueId, spv::DecorationSample);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case DxbcOperandType::Output: {
|
||||
if (m_oRegs.at(regId).valueId == 0) {
|
||||
m_oRegs.at(regId) = this->defVar(
|
||||
DxbcValueType(DxbcScalarType::Float32, 4),
|
||||
spv::StorageClassPrivate);
|
||||
m_module.setDebugName(m_oRegs.at(regId).valueId,
|
||||
str::format("o", regId).c_str());
|
||||
}
|
||||
} break;
|
||||
|
||||
default:
|
||||
throw DxvkError(str::format(
|
||||
"DxbcPsCodeGen::dclInterfaceVar: Unhandled operand type: ",
|
||||
regType));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DxbcPointer DxbcPsCodeGen::ptrInterfaceVar(
|
||||
DxbcOperandType regType,
|
||||
uint32_t regId) {
|
||||
switch (regType) {
|
||||
case DxbcOperandType::Input:
|
||||
return m_vRegs.at(regId);
|
||||
|
||||
case DxbcOperandType::Output:
|
||||
return m_oRegs.at(regId);
|
||||
|
||||
default:
|
||||
throw DxvkError(str::format(
|
||||
"DxbcPsCodeGen::ptrInterfaceVar: Unhandled operand type: ",
|
||||
regType));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DxbcPointer DxbcPsCodeGen::ptrInterfaceVarIndexed(
|
||||
DxbcOperandType regType,
|
||||
uint32_t regId,
|
||||
const DxbcValue& index) {
|
||||
throw DxvkError(str::format(
|
||||
"DxbcPsCodeGen::ptrInterfaceVarIndexed:\n",
|
||||
"Pixel shaders do not support indexed interface variables"));
|
||||
}
|
||||
|
||||
|
||||
Rc<DxvkShader> DxbcPsCodeGen::finalize() {
|
||||
m_module.functionBegin(
|
||||
m_module.defVoidType(),
|
||||
m_entryPointId,
|
||||
m_module.defFunctionType(
|
||||
m_module.defVoidType(), 0, nullptr),
|
||||
spv::FunctionControlMaskNone);
|
||||
m_module.opLabel(m_module.allocateId());
|
||||
|
||||
this->prepareSvInputs();
|
||||
m_module.opFunctionCall(
|
||||
m_module.defVoidType(),
|
||||
m_function, 0, nullptr);
|
||||
this->prepareSvOutputs();
|
||||
|
||||
m_module.opReturn();
|
||||
m_module.functionEnd();
|
||||
|
||||
m_module.addEntryPoint(m_entryPointId,
|
||||
spv::ExecutionModelFragment, "main",
|
||||
m_entryPointInterfaces.size(),
|
||||
m_entryPointInterfaces.data());
|
||||
m_module.setOriginUpperLeft(m_entryPointId);
|
||||
m_module.setDebugName(m_entryPointId, "main");
|
||||
|
||||
return new DxvkShader(
|
||||
VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
m_resourceSlots.size(),
|
||||
m_resourceSlots.data(),
|
||||
m_module.compile());
|
||||
}
|
||||
|
||||
|
||||
void DxbcPsCodeGen::dclSvInputReg(DxbcSystemValue sv) {
|
||||
switch (sv) {
|
||||
case DxbcSystemValue::Position: {
|
||||
m_svPosition = this->defVar(
|
||||
DxbcValueType(DxbcScalarType::Float32, 4),
|
||||
spv::StorageClassInput);
|
||||
m_entryPointInterfaces.push_back(
|
||||
m_svPosition.valueId);
|
||||
|
||||
m_module.setDebugName(m_svPosition.valueId, "sv_position");
|
||||
m_module.decorateBuiltIn(m_svPosition.valueId, spv::BuiltInFragCoord);
|
||||
} break;
|
||||
|
||||
default:
|
||||
throw DxvkError(str::format(
|
||||
"DxbcPsCodeGen::dclSvInputReg: Unhandled SV: ", sv));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DxbcPsCodeGen::prepareSvInputs() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
void DxbcPsCodeGen::prepareSvOutputs() {
|
||||
// TODO properly re-implement this
|
||||
std::array<uint32_t, 5> masks = { 0x0, 0x1, 0x3, 0x7, 0xF };
|
||||
|
||||
for (uint32_t i = 0; i < m_psOut.size(); i++) {
|
||||
if ((m_psOut.at(i).valueId != 0) && (m_oRegs.at(i).valueId != 0)) {
|
||||
DxbcValue srcValue = this->regLoad(m_oRegs.at(i));
|
||||
srcValue = this->regCast(srcValue, m_psOut.at(i).type.valueType);
|
||||
this->regStore(m_psOut.at(i), srcValue, DxbcComponentMask(
|
||||
masks.at(m_psOut.at(i).type.valueType.componentCount)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "dxbc_gen_common.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief Pixel shader code generator
|
||||
*/
|
||||
class DxbcPsCodeGen : public DxbcCodeGen {
|
||||
|
||||
public:
|
||||
|
||||
DxbcPsCodeGen(
|
||||
const Rc<DxbcIsgn>& osgn);
|
||||
~DxbcPsCodeGen();
|
||||
|
||||
void dclInterfaceVar(
|
||||
DxbcOperandType regType,
|
||||
uint32_t regId,
|
||||
uint32_t regDim,
|
||||
DxbcComponentMask regMask,
|
||||
DxbcSystemValue sv,
|
||||
DxbcInterpolationMode im);
|
||||
|
||||
DxbcPointer ptrInterfaceVar(
|
||||
DxbcOperandType regType,
|
||||
uint32_t regId);
|
||||
|
||||
DxbcPointer ptrInterfaceVarIndexed(
|
||||
DxbcOperandType regType,
|
||||
uint32_t regId,
|
||||
const DxbcValue& index);
|
||||
|
||||
Rc<DxvkShader> finalize() final;
|
||||
|
||||
private:
|
||||
|
||||
uint32_t m_function = 0;
|
||||
uint32_t m_psIn = 0;
|
||||
|
||||
DxbcPointer m_svPosition;
|
||||
|
||||
std::array<DxbcPointer, 32> m_vRegs;
|
||||
std::array<DxbcPointer, 8> m_oRegs;
|
||||
std::array<DxbcPointer, 8> m_psOut;
|
||||
|
||||
void dclSvInputReg(DxbcSystemValue sv);
|
||||
|
||||
void prepareSvInputs();
|
||||
void prepareSvOutputs();
|
||||
|
||||
};
|
||||
|
||||
}
|
@ -1,186 +0,0 @@
|
||||
#include "dxbc_gen_vertex.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
DxbcVsCodeGen::DxbcVsCodeGen(const Rc<DxbcIsgn>& isgn)
|
||||
: DxbcCodeGen(DxbcProgramType::VertexShader) {
|
||||
m_module.enableCapability(spv::CapabilityShader);
|
||||
m_module.enableCapability(spv::CapabilityCullDistance);
|
||||
m_module.enableCapability(spv::CapabilityClipDistance);
|
||||
|
||||
m_function = m_module.allocateId();
|
||||
m_module.setDebugName(m_function, "vs_main");
|
||||
|
||||
m_module.functionBegin(
|
||||
m_module.defVoidType(),
|
||||
m_function,
|
||||
m_module.defFunctionType(
|
||||
m_module.defVoidType(), 0, nullptr),
|
||||
spv::FunctionControlMaskNone);
|
||||
m_module.opLabel(m_module.allocateId());
|
||||
|
||||
// Declare per-vertex builtin output block
|
||||
m_vsPerVertex = m_module.newVar(
|
||||
m_module.defPointerType(this->defPerVertexBlock(), spv::StorageClassOutput),
|
||||
spv::StorageClassOutput);
|
||||
m_entryPointInterfaces.push_back(m_vsPerVertex);
|
||||
m_module.setDebugName(m_vsPerVertex, "vs_per_vertex");
|
||||
}
|
||||
|
||||
|
||||
DxbcVsCodeGen::~DxbcVsCodeGen() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
void DxbcVsCodeGen::dclInterfaceVar(
|
||||
DxbcOperandType regType,
|
||||
uint32_t regId,
|
||||
uint32_t regDim,
|
||||
DxbcComponentMask regMask,
|
||||
DxbcSystemValue sv,
|
||||
DxbcInterpolationMode im) {
|
||||
switch (regType) {
|
||||
case DxbcOperandType::Input: {
|
||||
if (m_vRegs.at(regId).valueId == 0) {
|
||||
m_vRegs.at(regId) = this->defVar(
|
||||
DxbcValueType(DxbcScalarType::Float32, 4),
|
||||
spv::StorageClassInput);
|
||||
m_module.decorateLocation(m_vRegs.at(regId).valueId, regId);
|
||||
m_module.setDebugName(m_vRegs.at(regId).valueId,
|
||||
str::format("v", regId).c_str());
|
||||
m_entryPointInterfaces.push_back(m_vRegs.at(regId).valueId);
|
||||
}
|
||||
|
||||
if (sv != DxbcSystemValue::None) {
|
||||
m_svIn.push_back(DxbcSvMapping {
|
||||
regId, regMask, sv });
|
||||
}
|
||||
} break;
|
||||
|
||||
case DxbcOperandType::Output: {
|
||||
if (m_oRegs.at(regId).valueId == 0) {
|
||||
m_oRegs.at(regId) = this->defVar(
|
||||
DxbcValueType(DxbcScalarType::Float32, 4),
|
||||
spv::StorageClassOutput);
|
||||
m_module.decorateLocation(m_oRegs.at(regId).valueId, regId);
|
||||
m_module.setDebugName(m_oRegs.at(regId).valueId,
|
||||
str::format("o", regId).c_str());
|
||||
m_entryPointInterfaces.push_back(m_oRegs.at(regId).valueId);
|
||||
}
|
||||
|
||||
if (sv != DxbcSystemValue::None) {
|
||||
m_svOut.push_back(DxbcSvMapping {
|
||||
regId, regMask, sv });
|
||||
}
|
||||
} break;
|
||||
|
||||
default:
|
||||
throw DxvkError(str::format(
|
||||
"DxbcVsCodeGen::dclInterfaceVar: Unhandled operand type: ",
|
||||
regType));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DxbcPointer DxbcVsCodeGen::ptrInterfaceVar(
|
||||
DxbcOperandType regType,
|
||||
uint32_t regId) {
|
||||
switch (regType) {
|
||||
case DxbcOperandType::Input:
|
||||
return m_vRegs.at(regId);
|
||||
|
||||
case DxbcOperandType::Output:
|
||||
return m_oRegs.at(regId);
|
||||
|
||||
default:
|
||||
throw DxvkError(str::format(
|
||||
"DxbcVsCodeGen::ptrInterfaceVar: Unhandled operand type: ",
|
||||
regType));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DxbcPointer DxbcVsCodeGen::ptrInterfaceVarIndexed(
|
||||
DxbcOperandType regType,
|
||||
uint32_t regId,
|
||||
const DxbcValue& index) {
|
||||
throw DxvkError(str::format(
|
||||
"DxbcVsCodeGen::ptrInterfaceVarIndexed:\n",
|
||||
"Vertex shaders do not support indexed interface variables"));
|
||||
}
|
||||
|
||||
|
||||
Rc<DxvkShader> DxbcVsCodeGen::finalize() {
|
||||
m_module.functionBegin(
|
||||
m_module.defVoidType(),
|
||||
m_entryPointId,
|
||||
m_module.defFunctionType(
|
||||
m_module.defVoidType(), 0, nullptr),
|
||||
spv::FunctionControlMaskNone);
|
||||
m_module.opLabel(m_module.allocateId());
|
||||
|
||||
this->prepareSvInputs();
|
||||
m_module.opFunctionCall(
|
||||
m_module.defVoidType(),
|
||||
m_function, 0, nullptr);
|
||||
this->prepareSvOutputs();
|
||||
|
||||
m_module.opReturn();
|
||||
m_module.functionEnd();
|
||||
|
||||
m_module.addEntryPoint(m_entryPointId,
|
||||
spv::ExecutionModelVertex, "main",
|
||||
m_entryPointInterfaces.size(),
|
||||
m_entryPointInterfaces.data());
|
||||
m_module.setDebugName(m_entryPointId, "main");
|
||||
|
||||
return new DxvkShader(
|
||||
VK_SHADER_STAGE_VERTEX_BIT,
|
||||
m_resourceSlots.size(),
|
||||
m_resourceSlots.data(),
|
||||
m_module.compile());
|
||||
}
|
||||
|
||||
|
||||
void DxbcVsCodeGen::dclSvInputReg(DxbcSystemValue sv) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
void DxbcVsCodeGen::prepareSvInputs() {
|
||||
DxbcValueType targetType(DxbcScalarType::Float32, 4);
|
||||
|
||||
// TODO system values
|
||||
}
|
||||
|
||||
|
||||
void DxbcVsCodeGen::prepareSvOutputs() {
|
||||
for (const auto& mapping : m_svOut) {
|
||||
DxbcValue srcValue = this->regLoad(m_oRegs.at(mapping.regId));
|
||||
|
||||
switch (mapping.sv) {
|
||||
case DxbcSystemValue::Position: {
|
||||
this->regStore(this->ptrBuiltInPosition(), srcValue,
|
||||
DxbcComponentMask(true, true, true, true));
|
||||
} break;
|
||||
default: ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DxbcPointer DxbcVsCodeGen::ptrBuiltInPosition() {
|
||||
const uint32_t memberId = m_module.constu32(PerVertex_Position);
|
||||
|
||||
DxbcPointer result;
|
||||
result.type = DxbcPointerType(
|
||||
DxbcValueType(DxbcScalarType::Float32, 4),
|
||||
spv::StorageClassOutput);
|
||||
result.valueId = m_module.opAccessChain(
|
||||
this->defPointerType(result.type),
|
||||
m_vsPerVertex, 1, &memberId);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "dxbc_gen_common.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief Vertex shader code generator
|
||||
*/
|
||||
class DxbcVsCodeGen : public DxbcCodeGen {
|
||||
|
||||
public:
|
||||
|
||||
DxbcVsCodeGen(
|
||||
const Rc<DxbcIsgn>& isgn);
|
||||
~DxbcVsCodeGen();
|
||||
|
||||
void dclInterfaceVar(
|
||||
DxbcOperandType regType,
|
||||
uint32_t regId,
|
||||
uint32_t regDim,
|
||||
DxbcComponentMask regMask,
|
||||
DxbcSystemValue sv,
|
||||
DxbcInterpolationMode im);
|
||||
|
||||
DxbcPointer ptrInterfaceVar(
|
||||
DxbcOperandType regType,
|
||||
uint32_t regId);
|
||||
|
||||
DxbcPointer ptrInterfaceVarIndexed(
|
||||
DxbcOperandType regType,
|
||||
uint32_t regId,
|
||||
const DxbcValue& index);
|
||||
|
||||
Rc<DxvkShader> finalize() final;
|
||||
|
||||
private:
|
||||
|
||||
uint32_t m_function = 0;
|
||||
uint32_t m_vsPerVertex = 0;
|
||||
|
||||
std::array<DxbcPointer, 32> m_vRegs;
|
||||
std::array<DxbcPointer, 32> m_oRegs;
|
||||
|
||||
std::vector<DxbcSvMapping> m_svIn;
|
||||
std::vector<DxbcSvMapping> m_svOut;
|
||||
|
||||
void dclSvInputReg(DxbcSystemValue sv);
|
||||
|
||||
void prepareSvInputs();
|
||||
void prepareSvOutputs();
|
||||
|
||||
DxbcPointer ptrBuiltInPosition();
|
||||
|
||||
DxbcPointer getVsOutPtr(uint32_t id);
|
||||
|
||||
};
|
||||
|
||||
}
|
@ -3,6 +3,7 @@ dxbc_src = files([
|
||||
'dxbc_chunk_shex.cpp',
|
||||
'dxbc_common.cpp',
|
||||
'dxbc_compiler.cpp',
|
||||
'dxbc_defs.cpp',
|
||||
'dxbc_decoder.cpp',
|
||||
'dxbc_header.cpp',
|
||||
'dxbc_module.cpp',
|
||||
@ -10,10 +11,6 @@ dxbc_src = files([
|
||||
'dxbc_reader.cpp',
|
||||
'dxbc_type.cpp',
|
||||
'dxbc_util.cpp',
|
||||
|
||||
'gen/dxbc_gen_common.cpp',
|
||||
'gen/dxbc_gen_pixel.cpp',
|
||||
'gen/dxbc_gen_vertex.cpp',
|
||||
])
|
||||
|
||||
dxbc_lib = static_library('dxbc', dxbc_src,
|
||||
|
@ -768,6 +768,25 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
uint32_t SpirvModule::opFFma(
|
||||
uint32_t resultType,
|
||||
uint32_t a,
|
||||
uint32_t b,
|
||||
uint32_t c) {
|
||||
uint32_t resultId = this->allocateId();
|
||||
|
||||
m_code.putIns (spv::OpExtInst, 8);
|
||||
m_code.putWord(resultType);
|
||||
m_code.putWord(resultId);
|
||||
m_code.putWord(m_instExtGlsl450);
|
||||
m_code.putWord(spv::GLSLstd450Fma);
|
||||
m_code.putWord(a);
|
||||
m_code.putWord(b);
|
||||
m_code.putWord(c);
|
||||
return resultId;
|
||||
}
|
||||
|
||||
|
||||
uint32_t SpirvModule::opFClamp(
|
||||
uint32_t resultType,
|
||||
uint32_t x,
|
||||
|
@ -275,6 +275,12 @@ namespace dxvk {
|
||||
uint32_t a,
|
||||
uint32_t b);
|
||||
|
||||
uint32_t opFFma(
|
||||
uint32_t resultType,
|
||||
uint32_t a,
|
||||
uint32_t b,
|
||||
uint32_t c);
|
||||
|
||||
uint32_t opFClamp(
|
||||
uint32_t resultType,
|
||||
uint32_t x,
|
||||
|
Loading…
x
Reference in New Issue
Block a user