1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2024-11-29 10:24:10 +01:00

[dxbc] Separate code generator classed for each shader type

This commit is contained in:
Philip Rebohle 2017-11-13 00:22:52 +01:00
parent 403ab75aeb
commit 43dfba2287
15 changed files with 489 additions and 110 deletions

View File

@ -1,13 +1,10 @@
#include "dxbc_compiler.h"
#include "dxbc_names.h"
namespace dxvk {
DxbcCompiler::DxbcCompiler(
DxbcProgramVersion version)
: m_version(version) {
}
const DxbcProgramVersion& version)
: m_gen(DxbcCodeGen::create(version)) { }
DxbcCompiler::~DxbcCompiler() {
@ -16,13 +13,58 @@ namespace dxvk {
void DxbcCompiler::processInstruction(const DxbcInstruction& ins) {
const DxbcOpcodeToken token = ins.token();
switch (token.opcode()) {
case DxbcOpcode::DclGlobalFlags:
return this->dclGlobalFlags(ins);
case DxbcOpcode::DclInput:
case DxbcOpcode::DclInputSiv:
case DxbcOpcode::DclInputSgv:
case DxbcOpcode::DclInputPs:
case DxbcOpcode::DclInputPsSiv:
case DxbcOpcode::DclInputPsSgv:
return this->dclInput(ins);
case DxbcOpcode::DclOutput:
case DxbcOpcode::DclOutputSiv:
case DxbcOpcode::DclOutputSgv:
return this->dclOutput(ins);
case DxbcOpcode::DclTemps:
return this->dclTemps(ins);
default:
Logger::err(str::format(
"DxbcCompiler::processInstruction: Unhandled opcode: ",
token.opcode()));
}
}
Rc<DxvkShader> DxbcCompiler::finalize() {
return new DxvkShader(m_version.shaderStage(),
m_module.compile(), 0, nullptr);
return m_gen->finalize();
}
void DxbcCompiler::dclGlobalFlags(const DxbcInstruction& ins) {
}
void DxbcCompiler::dclInput(const DxbcInstruction& ins) {
}
void DxbcCompiler::dclOutput(const DxbcInstruction& ins) {
}
void DxbcCompiler::dclTemps(const DxbcInstruction& ins) {
m_gen->dclTemps(ins.arg(0));
}
}

View File

@ -1,49 +1,43 @@
#pragma once
#include "dxbc_chunk_isgn.h"
#include "dxbc_chunk_shex.h"
#include "dxbc_names.h"
#include "dxbc_type.h"
#include "../spirv/spirv_module.h"
#include "./gen/dxbc_gen_common.h"
namespace dxvk {
/**
* \brief DXBC to SPIR-V compiler
* \brief DXBC compiler
*
* Interprets DXBC instructions and generates
* SPIR-V code for the appropriate shader type.
*/
class DxbcCompiler {
public:
DxbcCompiler(
DxbcProgramVersion version);
const DxbcProgramVersion& version);
~DxbcCompiler();
DxbcCompiler (DxbcCompiler&&) = delete;
DxbcCompiler& operator = (DxbcCompiler&&) = delete;
/**
* \brief Processes a single instruction
*
* \param [in] ins The instruction
* \returns \c true on success
*/
void processInstruction(
const DxbcInstruction& ins);
const DxbcInstruction& ins);
/**
* \brief Creates actual shader object
*
* Combines all information gatherd during the
* shader compilation into one shader object.
*/
Rc<DxvkShader> finalize();
private:
DxbcProgramVersion m_version;
SpirvModule m_module;
Rc<DxbcCodeGen> m_gen;
void dclGlobalFlags(
const DxbcInstruction& ins);
void dclInput(
const DxbcInstruction& ins);
void dclOutput(
const DxbcInstruction& ins);
void dclTemps(
const DxbcInstruction& ins);
};

View File

@ -527,6 +527,19 @@ namespace dxvk {
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
*

View File

@ -45,13 +45,6 @@ namespace dxvk {
throw DxvkError("DxbcModule::compile: No SHDR/SHEX chunk");
DxbcCompiler compiler(m_shexChunk->version());
// if (m_isgnChunk != nullptr)
// compiler.declareInputSignature(*m_isgnChunk);
// if (m_osgnChunk != nullptr)
// compiler.declareOutputSignature(*m_osgnChunk);
for (auto ins : *m_shexChunk)
compiler.processInstruction(ins);
return compiler.finalize();

View File

@ -390,3 +390,16 @@ std::ostream& operator << (std::ostream& os, DxbcSystemValue e) {
ENUM_DEFAULT(e);
}
}
std::ostream& operator << (std::ostream& os, dxvk::DxbcProgramType e) {
switch (e) {
ENUM_NAME(DxbcProgramType::PixelShader);
ENUM_NAME(DxbcProgramType::VertexShader);
ENUM_NAME(DxbcProgramType::GeometryShader);
ENUM_NAME(DxbcProgramType::HullShader);
ENUM_NAME(DxbcProgramType::DomainShader);
ENUM_NAME(DxbcProgramType::ComputeShader);
ENUM_DEFAULT(e);
}
}

View File

@ -2,6 +2,7 @@
#include <ostream>
#include "dxbc_common.h"
#include "dxbc_enums.h"
std::ostream& operator << (std::ostream& os, dxvk::DxbcOpcode e);
@ -15,3 +16,4 @@ std::ostream& operator << (std::ostream& os, dxvk::DxbcResourceReturnType e);
std::ostream& operator << (std::ostream& os, dxvk::DxbcRegisterComponentType e);
std::ostream& operator << (std::ostream& os, dxvk::DxbcInstructionReturnType e);
std::ostream& operator << (std::ostream& os, dxvk::DxbcSystemValue e);
std::ostream& operator << (std::ostream& os, dxvk::DxbcProgramType e);

View File

@ -14,12 +14,4 @@ namespace dxvk {
return result;
}
DxbcComponentMask DxbcComponentSwizzle::mask(uint32_t n) const {
DxbcComponentMask mask;
for (uint32_t i = 0; i < n; i++)
mask.set(m_components.at(i));
return mask;
}
}

View File

@ -30,10 +30,13 @@ namespace dxvk {
struct DxbcValueType {
DxbcValueType() { }
DxbcValueType(DxbcScalarType s, uint32_t c)
: componentType(s), componentCount(c) { }
: DxbcValueType(s, c, 0) { }
DxbcValueType(DxbcScalarType s, uint32_t c, uint32_t e)
: componentType(s), componentCount(c), elementCount(e) { }
DxbcScalarType componentType = DxbcScalarType::Uint32;
uint32_t componentCount = 0;
uint32_t elementCount = 0;
};
@ -44,17 +47,7 @@ namespace dxvk {
* result that can be used as an operand value.
*/
struct DxbcValue {
DxbcValue() { }
DxbcValue(
DxbcValueType p_type,
uint32_t p_typeId,
uint32_t p_valueId)
: type (p_type),
typeId (p_typeId),
valueId (p_valueId) { }
DxbcValueType type;
uint32_t typeId = 0;
uint32_t valueId = 0;
};
@ -87,20 +80,11 @@ namespace dxvk {
* class. Can be used as a memory operand.
*/
struct DxbcPointer {
DxbcPointer() { }
DxbcPointer(
DxbcPointerType p_type,
uint32_t p_typeId,
uint32_t p_valueId)
: type (p_type),
typeId (p_typeId),
valueId (p_valueId) { }
DxbcPointerType type;
uint32_t typeId = 0;
uint32_t valueId = 0;
};
/**
* \brief Component mask
*/
@ -172,8 +156,6 @@ namespace dxvk {
DxbcComponentSwizzle extract(DxbcComponentMask mask) const;
DxbcComponentMask mask(uint32_t n) const;
private:
std::array<uint32_t, 4> m_components;

View File

@ -0,0 +1,120 @@
#include "dxbc_gen_common.h"
#include "dxbc_gen_vertex.h"
#include "../dxbc_names.h"
namespace dxvk {
DxbcCodeGen::DxbcCodeGen() {
m_module.enableCapability(spv::CapabilityShader);
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);
DxbcPointer reg;
reg.type = DxbcPointerType(
DxbcValueType(DxbcScalarType::Float32, 4),
spv::StorageClassPrivate);
const uint32_t typeId = this->defPointerType(reg.type);
for (uint32_t i = oldSize; i < n; i++) {
reg.valueId = m_module.newVar(typeId, spv::StorageClassPrivate);
m_module.setDebugName(reg.valueId, str::format("r", i).c_str());
m_rRegs.at(i) = reg;
}
}
}
Rc<DxbcCodeGen> DxbcCodeGen::create(
const DxbcProgramVersion& version) {
switch (version.type()) {
case DxbcProgramType::VertexShader:
return new DxbcVsCodeGen();
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.defStructType(
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;
}
}

View File

@ -0,0 +1,108 @@
#pragma once
#include "../dxbc_common.h"
#include "../dxbc_decoder.h"
#include "../dxbc_type.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 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();
virtual ~DxbcCodeGen();
/**
* \brief Declares temporary registers
* \param [in] n Number of temp registers
*/
void dclTemps(uint32_t n);
/**
* \brief Declares an interface variable
*
* \param [in] regType Register type
* \param [in] regId Interface register index
* \param [in] regDim Array dimension of interface variable
* \param [in] regMask Component mask for this declaration
* \param [in] sv System value to map to the given components
*/
virtual void dclInterfaceVar(
DxbcOperandType regType,
uint32_t regId,
uint32_t regDim,
DxbcComponentMask regMask,
DxbcSystemValue sv) = 0;
/**
* \brief Finalizes shader
*
* Depending on the shader stage, this may generate
* additional code to set up input variables, output
* variables, and execute shader phases.
* \returns DXVK shader module
*/
virtual Rc<DxvkShader> finalize() = 0;
/**
* \brief Creates code generator for a given program type
*
* \param [in] version Program version
* \returns The code generator
*/
static Rc<DxbcCodeGen> create(
const DxbcProgramVersion& version);
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;
SpirvModule m_module;
std::vector<uint32_t> m_entryPointInterfaces;
uint32_t m_entryPointId = 0;
std::vector<DxbcPointer> m_rRegs;
uint32_t defScalarType(
DxbcScalarType type);
uint32_t defValueType(
const DxbcValueType& type);
uint32_t defPointerType(
const DxbcPointerType& type);
uint32_t defPerVertexBlock();
};
}

View File

@ -0,0 +1,38 @@
#include "dxbc_gen_vertex.h"
namespace dxvk {
DxbcVsCodeGen::DxbcVsCodeGen() {
m_outPerVertex = m_module.newVar(
m_module.defPointerType(this->defPerVertexBlock(), spv::StorageClassOutput),
spv::StorageClassOutput);
}
DxbcVsCodeGen::~DxbcVsCodeGen() {
}
void DxbcVsCodeGen::dclInterfaceVar(
DxbcOperandType regType,
uint32_t regId,
uint32_t regDim,
DxbcComponentMask regMask,
DxbcSystemValue sv) {
}
Rc<DxvkShader> DxbcVsCodeGen::finalize() {
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_module.compile(), 0, nullptr);
}
}

View File

@ -0,0 +1,38 @@
#pragma once
#include "dxbc_gen_common.h"
namespace dxvk {
/**
* \brief Vertex shader code generator
*/
class DxbcVsCodeGen : public DxbcCodeGen {
public:
DxbcVsCodeGen();
~DxbcVsCodeGen();
void dclInterfaceVar(
DxbcOperandType regType,
uint32_t regId,
uint32_t regDim,
DxbcComponentMask regMask,
DxbcSystemValue sv);
Rc<DxvkShader> finalize() final;
private:
uint32_t m_outPerVertex = 0;
std::array<DxbcPointer, 32> m_vRegs;
std::array<DxbcPointer, 32> m_oRegs;
std::vector<DxbcSvMapping> m_svInputs;
std::vector<DxbcSvMapping> m_svOutputs;
};
}

View File

@ -9,6 +9,9 @@ dxbc_src = files([
'dxbc_names.cpp',
'dxbc_reader.cpp',
'dxbc_type.cpp',
'gen/dxbc_gen_common.cpp',
'gen/dxbc_gen_vertex.cpp',
])
dxbc_lib = static_library('dxbc', dxbc_src,

View File

@ -15,8 +15,7 @@ namespace dxvk {
result.append(m_execModeInfo);
result.append(m_debugNames);
result.append(m_annotations);
result.append(m_typeDefs);
result.append(m_constDefs);
result.append(m_typeConstDefs);
result.append(m_variables);
result.append(m_code);
return result;
@ -98,14 +97,25 @@ namespace dxvk {
}
void SpirvModule::setDebugMemberName(
uint32_t structId,
uint32_t memberId,
const char* debugName) {
m_debugNames.putIns (spv::OpMemberName, 3 + m_debugNames.strLen(debugName));
m_debugNames.putWord(structId);
m_debugNames.putWord(memberId);
m_debugNames.putStr (debugName);
}
uint32_t SpirvModule::constBool(
bool v) {
uint32_t typeId = this->defBoolType();
uint32_t resultId = this->allocateId();
m_constDefs.putIns (v ? spv::OpConstantTrue : spv::OpConstantFalse, 3);
m_constDefs.putWord (typeId);
m_constDefs.putWord (resultId);
m_typeConstDefs.putIns (v ? spv::OpConstantTrue : spv::OpConstantFalse, 3);
m_typeConstDefs.putWord (typeId);
m_typeConstDefs.putWord (resultId);
return resultId;
}
@ -115,10 +125,10 @@ namespace dxvk {
uint32_t typeId = this->defIntType(32, 1);
uint32_t resultId = this->allocateId();
m_constDefs.putIns (spv::OpConstant, 4);
m_constDefs.putWord (typeId);
m_constDefs.putWord (resultId);
m_constDefs.putInt32(v);
m_typeConstDefs.putIns (spv::OpConstant, 4);
m_typeConstDefs.putWord (typeId);
m_typeConstDefs.putWord (resultId);
m_typeConstDefs.putInt32(v);
return resultId;
}
@ -128,10 +138,10 @@ namespace dxvk {
uint32_t typeId = this->defIntType(64, 1);
uint32_t resultId = this->allocateId();
m_constDefs.putIns (spv::OpConstant, 5);
m_constDefs.putWord (typeId);
m_constDefs.putWord (resultId);
m_constDefs.putInt64(v);
m_typeConstDefs.putIns (spv::OpConstant, 5);
m_typeConstDefs.putWord (typeId);
m_typeConstDefs.putWord (resultId);
m_typeConstDefs.putInt64(v);
return resultId;
}
@ -141,10 +151,10 @@ namespace dxvk {
uint32_t typeId = this->defIntType(32, 0);
uint32_t resultId = this->allocateId();
m_constDefs.putIns (spv::OpConstant, 4);
m_constDefs.putWord (typeId);
m_constDefs.putWord (resultId);
m_constDefs.putInt32(v);
m_typeConstDefs.putIns (spv::OpConstant, 4);
m_typeConstDefs.putWord (typeId);
m_typeConstDefs.putWord (resultId);
m_typeConstDefs.putInt32(v);
return resultId;
}
@ -154,10 +164,10 @@ namespace dxvk {
uint32_t typeId = this->defIntType(64, 0);
uint32_t resultId = this->allocateId();
m_constDefs.putIns (spv::OpConstant, 5);
m_constDefs.putWord (typeId);
m_constDefs.putWord (resultId);
m_constDefs.putInt64(v);
m_typeConstDefs.putIns (spv::OpConstant, 5);
m_typeConstDefs.putWord (typeId);
m_typeConstDefs.putWord (resultId);
m_typeConstDefs.putInt64(v);
return resultId;
}
@ -167,10 +177,10 @@ namespace dxvk {
uint32_t typeId = this->defFloatType(32);
uint32_t resultId = this->allocateId();
m_constDefs.putIns (spv::OpConstant, 4);
m_constDefs.putWord (typeId);
m_constDefs.putWord (resultId);
m_constDefs.putFloat32(v);
m_typeConstDefs.putIns (spv::OpConstant, 4);
m_typeConstDefs.putWord (typeId);
m_typeConstDefs.putWord (resultId);
m_typeConstDefs.putFloat32(v);
return resultId;
}
@ -180,10 +190,10 @@ namespace dxvk {
uint32_t typeId = this->defFloatType(64);
uint32_t resultId = this->allocateId();
m_constDefs.putIns (spv::OpConstant, 5);
m_constDefs.putWord (typeId);
m_constDefs.putWord (resultId);
m_constDefs.putFloat64(v);
m_typeConstDefs.putIns (spv::OpConstant, 5);
m_typeConstDefs.putWord (typeId);
m_typeConstDefs.putWord (resultId);
m_typeConstDefs.putFloat64(v);
return resultId;
}
@ -194,16 +204,23 @@ namespace dxvk {
const uint32_t* constIds) {
uint32_t resultId = this->allocateId();
m_constDefs.putIns (spv::OpConstantComposite, 3 + constCount);
m_constDefs.putWord (typeId);
m_constDefs.putWord (resultId);
m_typeConstDefs.putIns (spv::OpConstantComposite, 3 + constCount);
m_typeConstDefs.putWord (typeId);
m_typeConstDefs.putWord (resultId);
for (uint32_t i = 0; i < constCount; i++)
m_constDefs.putWord(constIds[i]);
m_typeConstDefs.putWord(constIds[i]);
return resultId;
}
void SpirvModule::decorateBlock(uint32_t object) {
m_annotations.putIns (spv::OpDecorate, 3);
m_annotations.putWord (object);
m_annotations.putWord (spv::DecorationBlock);
}
void SpirvModule::decorateBuiltIn(
uint32_t object,
spv::BuiltIn builtIn) {
@ -234,6 +251,18 @@ namespace dxvk {
}
void SpirvModule::memberDecorateBuiltIn(
uint32_t structId,
uint32_t memberId,
spv::BuiltIn builtIn) {
m_annotations.putIns (spv::OpMemberDecorate, 5);
m_annotations.putWord (structId);
m_annotations.putWord (memberId);
m_annotations.putWord (spv::DecorationBuiltIn);
m_annotations.putWord (builtIn);
}
uint32_t SpirvModule::defVoidType() {
return this->defType(spv::OpTypeVoid, 0, nullptr);
}
@ -493,7 +522,7 @@ namespace dxvk {
// Since the type info is stored in the code buffer,
// we can use the code buffer to look up type IDs as
// well. Result IDs are always stored as argument 1.
for (auto ins : m_typeDefs) {
for (auto ins : m_typeConstDefs) {
bool match = ins.opCode() == op;
for (uint32_t i = 0; i < argCount && match; i++)
@ -505,11 +534,11 @@ namespace dxvk {
// Type not yet declared, create a new one.
uint32_t resultId = this->allocateId();
m_typeDefs.putIns (op, 2 + argCount);
m_typeDefs.putWord(resultId);
m_typeConstDefs.putIns (op, 2 + argCount);
m_typeConstDefs.putWord(resultId);
for (uint32_t i = 0; i < argCount; i++)
m_typeDefs.putWord(argIds[i]);
m_typeConstDefs.putWord(argIds[i]);
return resultId;
}

View File

@ -50,6 +50,11 @@ namespace dxvk {
uint32_t expressionId,
const char* debugName);
void setDebugMemberName(
uint32_t structId,
uint32_t memberId,
const char* debugName);
uint32_t constBool(
bool v);
@ -76,6 +81,9 @@ namespace dxvk {
uint32_t constCount,
const uint32_t* constIds);
void decorateBlock(
uint32_t object);
void decorateBuiltIn(
uint32_t object,
spv::BuiltIn builtIn);
@ -88,6 +96,11 @@ namespace dxvk {
uint32_t object,
uint32_t location);
void memberDecorateBuiltIn(
uint32_t structId,
uint32_t memberId,
spv::BuiltIn builtIn);
uint32_t defVoidType();
uint32_t defBoolType();
@ -188,8 +201,7 @@ namespace dxvk {
SpirvCodeBuffer m_execModeInfo;
SpirvCodeBuffer m_debugNames;
SpirvCodeBuffer m_annotations;
SpirvCodeBuffer m_typeDefs;
SpirvCodeBuffer m_constDefs;
SpirvCodeBuffer m_typeConstDefs;
SpirvCodeBuffer m_variables;
SpirvCodeBuffer m_code;