diff --git a/src/dxbc/dxbc_chunk_isgn.cpp b/src/dxbc/dxbc_chunk_isgn.cpp index b47dcf165..e0d1f5b0b 100644 --- a/src/dxbc/dxbc_chunk_isgn.cpp +++ b/src/dxbc/dxbc_chunk_isgn.cpp @@ -29,14 +29,4 @@ namespace dxvk { } - - uint32_t DxbcIsgn::entryCount() const { - return m_entries.size(); - } - - - const DxbcSgnEntry& DxbcIsgn::entry(uint32_t id) const { - return m_entries.at(id); - } - } \ No newline at end of file diff --git a/src/dxbc/dxbc_chunk_isgn.h b/src/dxbc/dxbc_chunk_isgn.h index 31b70caab..349dd0eef 100644 --- a/src/dxbc/dxbc_chunk_isgn.h +++ b/src/dxbc/dxbc_chunk_isgn.h @@ -36,9 +36,8 @@ namespace dxvk { DxbcIsgn(DxbcReader reader); ~DxbcIsgn(); - uint32_t entryCount() const; - - const DxbcSgnEntry& entry(uint32_t id) const; + auto begin() const { return m_entries.cbegin(); } + auto end () const { return m_entries.cend(); } private: diff --git a/src/dxbc/dxbc_compiler.cpp b/src/dxbc/dxbc_compiler.cpp index bddcba291..274ee7c9c 100644 --- a/src/dxbc/dxbc_compiler.cpp +++ b/src/dxbc/dxbc_compiler.cpp @@ -1,28 +1,12 @@ #include "dxbc_compiler.h" +#include "dxbc_names.h" namespace dxvk { DxbcCompiler::DxbcCompiler( - DxbcProgramVersion version, - const Rc& inputSig, - const Rc& outputSig) - : m_version (version), - m_inputSig (inputSig), - m_outputSig (outputSig) { - m_entryPointId = m_module.allocateId(); + DxbcProgramVersion version) + : m_version(version) { - this->declareCapabilities(); - this->declareMemoryModel(); - - m_typeVoid = m_module.defVoidType(); - m_typeFunction = m_module.defFunctionType(m_typeVoid, 0, nullptr); - - m_module.functionBegin(m_typeVoid, - m_entryPointId, m_typeFunction, - spv::FunctionControlMaskNone); - - // TODO implement proper control flow - m_module.opLabel(m_module.allocateId()); } @@ -32,240 +16,13 @@ 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: - return this->dclInput(ins); - - case DxbcOpcode::DclOutputSiv: - return this->dclOutputSiv(ins); - - case DxbcOpcode::DclTemps: - return this->dclTemps(ins); - - case DxbcOpcode::DclThreadGroup: - return this->dclThreadGroup(ins); - - case DxbcOpcode::Mov: - return this->opMov(ins); - - case DxbcOpcode::Ret: - return this->opRet(ins); - - default: - throw DxvkError(str::format("DXBC: Unhandled instruction: ", ins.token().opcode())); - } } Rc DxbcCompiler::finalize() { - m_module.functionEnd(); - - m_module.addEntryPoint(m_entryPointId, - m_version.executionModel(), "main", - m_interfaces.size(), - m_interfaces.data()); - return new DxvkShader(m_version.shaderStage(), m_module.compile(), 0, nullptr); } - - void DxbcCompiler::declareCapabilities() { - m_module.enableCapability(spv::CapabilityShader); - - switch (m_version.type()) { - case DxbcProgramType::GeometryShader: - m_module.enableCapability(spv::CapabilityGeometry); - break; - - case DxbcProgramType::HullShader: - case DxbcProgramType::DomainShader: - m_module.enableCapability(spv::CapabilityTessellation); - break; - - default: - break; - } - } - - - void DxbcCompiler::declareMemoryModel() { - m_module.setMemoryModel( - spv::AddressingModelLogical, - spv::MemoryModelGLSL450); - } - - - void DxbcCompiler::dclGlobalFlags(const DxbcInstruction& ins) { - const DxbcGlobalFlags flags(ins.token().control()); - - if (!flags.test(DxbcGlobalFlag::RefactoringAllowed)) - m_useRestrictedMath = true; - - if (flags.test(DxbcGlobalFlag::DoublePrecision)) - m_module.enableCapability(spv::CapabilityFloat64); - - if (flags.test(DxbcGlobalFlag::EarlyFragmentTests)) - m_module.enableEarlyFragmentTests(m_entryPointId); - - // Raw and structured buffers are supported regardless - // of whether the corresponding flag is set or not. - } - - - void DxbcCompiler::dclInput(const DxbcInstruction& ins) { - const DxbcOperand operand = ins.operand(0); - const DxbcOperandToken token = operand.token(); - - } - - - void DxbcCompiler::dclOutputSiv(const DxbcInstruction& ins) { - Logger::err("DXBC: dclOutputSiv: Not implemented yet"); - } - - - void DxbcCompiler::dclTemps(const DxbcInstruction& ins) { - // Temporaries are treated as untyped 4x32-bit vectors. - const DxbcValueType regType(DxbcScalarType::Uint32, 4); - const DxbcPointerType ptrType(regType, spv::StorageClassPrivate); - const uint32_t ptrTypeId = this->getPointerTypeId(ptrType); - - for (uint32_t i = 0; i < ins.arg(0); i++) { - DxbcPointer reg; - reg.type = ptrType; - reg.typeId = ptrTypeId; - reg.valueId = m_module.newVar(ptrTypeId, spv::StorageClassPrivate); - m_rRegs.push_back(reg); - - m_module.setDebugName(reg.valueId, - str::format("r", i).c_str()); - } - } - - - void DxbcCompiler::dclThreadGroup(const DxbcInstruction& ins) { - m_module.setLocalSize(m_entryPointId, - ins.arg(0), ins.arg(1), ins.arg(2)); - } - - - void DxbcCompiler::opMov(const DxbcInstruction& ins) { - const DxbcOperand dstOp = ins.operand(0); - const DxbcOperand srcOp = ins.operand(dstOp.length()); - - DxbcValueType dstType(DxbcScalarType::Uint32, 1); - this->loadOperand(srcOp, dstType); - - Logger::err("DXBC: mov: Not implemented yet"); - } - - - void DxbcCompiler::opRet(const DxbcInstruction& ins) { - // TODO implement proper control flow - m_module.opReturn(); - } - - - uint32_t DxbcCompiler::getScalarTypeId(const 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); - } - - throw DxvkError("DXBC: Invalid scalar type"); - } - - - uint32_t DxbcCompiler::getValueTypeId(const DxbcValueType& type) { - const uint32_t scalarTypeId = this->getScalarTypeId(type.componentType); - - return type.componentCount > 1 - ? m_module.defVectorType(scalarTypeId, type.componentCount) - : scalarTypeId; - } - - - uint32_t DxbcCompiler::getPointerTypeId(const DxbcPointerType& type) { - return m_module.defPointerType( - this->getValueTypeId(type.valueType), - type.storageClass); - } - - - DxbcValue DxbcCompiler::loadPointer(const DxbcPointer& pointer) { - DxbcValue result; - result.type = pointer.type.valueType; - result.typeId = this->getValueTypeId(result.type); - result.valueId = m_module.opLoad(result.typeId, pointer.valueId); - return result; - } - - - DxbcValue DxbcCompiler::loadOperand( - const DxbcOperand& operand, - const DxbcValueType& type) { - const DxbcOperandToken token = operand.token(); - - DxbcValue result; - - switch (token.type()) { - - case DxbcOperandType::Imm32: { - const uint32_t componentCount = token.numComponents(); - - result.type = DxbcValueType(DxbcScalarType::Uint32, componentCount); - result.typeId = this->getValueTypeId(result.type); - - if (componentCount == 1) { - result.valueId = m_module.constu32(operand.imm32(0)); - } else { - std::array constIds; - - for (uint32_t i = 0; i < componentCount; i++) - constIds.at(i) = m_module.constu32(operand.imm32(i)); - - result.valueId = m_module.constComposite( - result.typeId, componentCount, constIds.data()); - } - } break; - - case DxbcOperandType::Temp: { - const DxbcOperandIndex index = operand.index(0); - result = this->loadPointer(m_rRegs.at(index.immPart())); - } break; - - default: - throw DxvkError(str::format( - "DxbcCompiler::loadOperandRegister: Unhandled operand type: ", - token.type())); - } - - return result; - } - - - void DxbcCompiler::storePointer( - const DxbcPointer& pointer, - const DxbcValue& value) { - m_module.opStore(pointer.valueId, value.valueId); - } - - - void DxbcCompiler::storeOperand( - const DxbcOperand& operand, - const DxbcValueType& srcType, - uint32_t srcValue) { - - } - } \ No newline at end of file diff --git a/src/dxbc/dxbc_compiler.h b/src/dxbc/dxbc_compiler.h index e74c3b1a5..1702c7a87 100644 --- a/src/dxbc/dxbc_compiler.h +++ b/src/dxbc/dxbc_compiler.h @@ -17,9 +17,7 @@ namespace dxvk { public: DxbcCompiler( - DxbcProgramVersion version, - const Rc& inputSig, - const Rc& outputSig); + DxbcProgramVersion version); ~DxbcCompiler(); DxbcCompiler (DxbcCompiler&&) = delete; @@ -32,7 +30,7 @@ namespace dxvk { * \returns \c true on success */ void processInstruction( - const DxbcInstruction& ins); + const DxbcInstruction& ins); /** * \brief Creates actual shader object @@ -47,77 +45,6 @@ namespace dxvk { DxbcProgramVersion m_version; SpirvModule m_module; - Rc m_inputSig; - Rc m_outputSig; - - std::vector m_interfaces; - std::vector m_rRegs; // Temps - - DxbcPointer m_svPosition; - std::vector m_svClipDistance; - std::vector m_svCullDistance; - - uint32_t m_entryPointId = 0; - - uint32_t m_typeVoid = 0; - uint32_t m_typeFunction = 0; - - bool m_useRestrictedMath = false; - - - - void declareCapabilities(); - void declareMemoryModel(); - - void dclGlobalFlags( - const DxbcInstruction& ins); - - void dclInput( - const DxbcInstruction& ins); - - void dclOutputSiv( - const DxbcInstruction& ins); - - void dclTemps( - const DxbcInstruction& ins); - - void dclThreadGroup( - const DxbcInstruction& ins); - - - void opMov( - const DxbcInstruction& ins); - - void opRet( - const DxbcInstruction& ins); - - uint32_t getScalarTypeId( - const DxbcScalarType& type); - - uint32_t getValueTypeId( - const DxbcValueType& type); - - uint32_t getPointerTypeId( - const DxbcPointerType& type); - - - DxbcValue loadPointer( - const DxbcPointer& pointer); - - DxbcValue loadOperand( - const DxbcOperand& operand, - const DxbcValueType& type); - - - void storePointer( - const DxbcPointer& pointer, - const DxbcValue& value); - - void storeOperand( - const DxbcOperand& operand, - const DxbcValueType& srcType, - uint32_t srcValue); - }; } \ No newline at end of file diff --git a/src/dxbc/dxbc_decoder.h b/src/dxbc/dxbc_decoder.h index 21b1e019d..90006fb9b 100644 --- a/src/dxbc/dxbc_decoder.h +++ b/src/dxbc/dxbc_decoder.h @@ -5,26 +5,12 @@ #include "dxbc_enums.h" #include "dxbc_names.h" +#include "dxbc_type.h" namespace dxvk { class DxbcOperand; - /** - * \brief Component swizzle - */ - struct DxbcComponentSwizzle { - DxbcComponentName x; - DxbcComponentName y; - DxbcComponentName z; - DxbcComponentName w; - }; - - /** - * \brief Component mask - */ - using DxbcComponentMask = Flags; - /** * \brief DXBC instruction token * @@ -213,11 +199,11 @@ namespace dxvk { * \returns The component swizzle */ DxbcComponentSwizzle componentSwizzle() const { - return DxbcComponentSwizzle { - static_cast(bit::extract(m_token, 4, 5)), - static_cast(bit::extract(m_token, 6, 7)), - static_cast(bit::extract(m_token, 8, 9)), - static_cast(bit::extract(m_token, 10, 11)) }; + return DxbcComponentSwizzle( + bit::extract(m_token, 4, 5), + bit::extract(m_token, 6, 7), + bit::extract(m_token, 8, 9), + bit::extract(m_token, 10, 11)); } /** @@ -226,9 +212,8 @@ namespace dxvk { * Used when the component selection mode is * \c DxbcComponentSelectionMode::Select1. */ - DxbcComponentName componentSelection() const { - return static_cast( - bit::extract(m_token, 4, 5)); + DxbcComponentMask componentSelection() const { + return DxbcComponentMask(bit::extract(m_token, 4, 5)); } /** diff --git a/src/dxbc/dxbc_enums.h b/src/dxbc/dxbc_enums.h index 7db82b37a..f57ccbd12 100644 --- a/src/dxbc/dxbc_enums.h +++ b/src/dxbc/dxbc_enums.h @@ -307,15 +307,6 @@ namespace dxvk { }; - /** - * \brief Component name - * Used for component selection. - */ - enum class DxbcComponentName : uint32_t { - X = 0, Y = 1, Z = 2, W = 3, - }; - - /** * \brief Index representation * diff --git a/src/dxbc/dxbc_module.cpp b/src/dxbc/dxbc_module.cpp index 256cebc18..09a43ad82 100644 --- a/src/dxbc/dxbc_module.cpp +++ b/src/dxbc/dxbc_module.cpp @@ -44,7 +44,13 @@ namespace dxvk { if (m_shexChunk == nullptr) throw DxvkError("DxbcModule::compile: No SHDR/SHEX chunk"); - DxbcCompiler compiler(m_shexChunk->version(), m_isgnChunk, m_osgnChunk); + 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); diff --git a/src/dxbc/dxbc_names.cpp b/src/dxbc/dxbc_names.cpp index 45ece7770..624246b7a 100644 --- a/src/dxbc/dxbc_names.cpp +++ b/src/dxbc/dxbc_names.cpp @@ -295,17 +295,6 @@ std::ostream& operator << (std::ostream& os, DxbcComponentSelectionMode e) { } -std::ostream& operator << (std::ostream& os, DxbcComponentName e) { - switch (e) { - ENUM_NAME(DxbcComponentName::X); - ENUM_NAME(DxbcComponentName::Y); - ENUM_NAME(DxbcComponentName::Z); - ENUM_NAME(DxbcComponentName::W); - ENUM_DEFAULT(e); - } -} - - std::ostream& operator << (std::ostream& os, DxbcOperandIndexRepresentation e) { switch (e) { ENUM_NAME(DxbcOperandIndexRepresentation::Imm32); diff --git a/src/dxbc/dxbc_names.h b/src/dxbc/dxbc_names.h index cc3bb8000..4b4195568 100644 --- a/src/dxbc/dxbc_names.h +++ b/src/dxbc/dxbc_names.h @@ -9,7 +9,6 @@ std::ostream& operator << (std::ostream& os, dxvk::DxbcExtOpcode e); std::ostream& operator << (std::ostream& os, dxvk::DxbcOperandType e); std::ostream& operator << (std::ostream& os, dxvk::DxbcComponentCount e); std::ostream& operator << (std::ostream& os, dxvk::DxbcComponentSelectionMode e); -std::ostream& operator << (std::ostream& os, dxvk::DxbcComponentName e); std::ostream& operator << (std::ostream& os, dxvk::DxbcOperandIndexRepresentation e); std::ostream& operator << (std::ostream& os, dxvk::DxbcResourceDim e); std::ostream& operator << (std::ostream& os, dxvk::DxbcResourceReturnType e); diff --git a/src/dxbc/dxbc_type.h b/src/dxbc/dxbc_type.h index c799c2244..f820de7e6 100644 --- a/src/dxbc/dxbc_type.h +++ b/src/dxbc/dxbc_type.h @@ -101,4 +101,83 @@ namespace dxvk { uint32_t valueId = 0; }; + /** + * \brief Component mask + */ + class DxbcComponentMask { + + public: + + DxbcComponentMask() { } + DxbcComponentMask(uint32_t mask) + : m_mask(mask) { } + DxbcComponentMask(bool x, bool y, bool z, bool w) + : m_mask((x ? 1 : 0) | (y ? 2 : 0) | (z ? 4 : 0) | (w ? 8 : 0)) { } + + void set(uint32_t id) { m_mask |= bit(id); } + void clr(uint32_t id) { m_mask &= ~bit(id); } + + bool test(uint32_t id) const { + return !!(m_mask & bit(id)); + } + + uint32_t componentCount() const { + return bit::popcnt(m_mask); + } + + uint32_t firstComponent() const { + return bit::tzcnt(m_mask); + } + + DxbcComponentMask operator ~ () const { return (~m_mask) & 0xF; } + + DxbcComponentMask operator & (const DxbcComponentMask& other) const { return m_mask & other.m_mask; } + DxbcComponentMask operator | (const DxbcComponentMask& other) const { return m_mask | other.m_mask; } + + bool operator == (const DxbcComponentMask& other) const { return m_mask == other.m_mask; } + bool operator != (const DxbcComponentMask& other) const { return m_mask != other.m_mask; } + + operator bool () const { + return m_mask != 0; + } + + private: + + uint32_t m_mask = 0; + + uint32_t bit(uint32_t id) const { + return 1u << id; + } + + }; + + /** + * \brief Component swizzle + */ + class DxbcComponentSwizzle { + + public: + + DxbcComponentSwizzle() + : DxbcComponentSwizzle(0, 1, 2, 3) { } + DxbcComponentSwizzle(uint32_t x, uint32_t y, uint32_t z, uint32_t w) + : m_components {{ x, y, z, w }} { } + + uint32_t operator [] (uint32_t id) const { return m_components.at(id); } + uint32_t& operator [] (uint32_t id) { return m_components.at(id); } + + const uint32_t* operator & () const { + return m_components.data(); + } + + DxbcComponentSwizzle extract(DxbcComponentMask mask) const; + + DxbcComponentMask mask(uint32_t n) const; + + private: + + std::array m_components; + + }; + } \ No newline at end of file diff --git a/src/dxbc/meson.build b/src/dxbc/meson.build index 633685c95..04dcfbd6e 100644 --- a/src/dxbc/meson.build +++ b/src/dxbc/meson.build @@ -8,6 +8,7 @@ dxbc_src = files([ 'dxbc_module.cpp', 'dxbc_names.cpp', 'dxbc_reader.cpp', + 'dxbc_type.cpp', ]) dxbc_lib = static_library('dxbc', dxbc_src, diff --git a/src/spirv/spirv_module.cpp b/src/spirv/spirv_module.cpp index ab930bf7c..ec4aba44e 100644 --- a/src/spirv/spirv_module.cpp +++ b/src/spirv/spirv_module.cpp @@ -204,6 +204,36 @@ namespace dxvk { } + void SpirvModule::decorateBuiltIn( + uint32_t object, + spv::BuiltIn builtIn) { + m_annotations.putIns (spv::OpDecorate, 4); + m_annotations.putWord (object); + m_annotations.putWord (spv::DecorationBuiltIn); + m_annotations.putWord (builtIn); + } + + + void SpirvModule::decorateComponent( + uint32_t object, + uint32_t location) { + m_annotations.putIns (spv::OpDecorate, 4); + m_annotations.putWord (object); + m_annotations.putWord (spv::DecorationComponent); + m_annotations.putInt32(location); + } + + + void SpirvModule::decorateLocation( + uint32_t object, + uint32_t location) { + m_annotations.putIns (spv::OpDecorate, 4); + m_annotations.putWord (object); + m_annotations.putWord (spv::DecorationLocation); + m_annotations.putInt32(location); + } + + uint32_t SpirvModule::defVoidType() { return this->defType(spv::OpTypeVoid, 0, nullptr); } @@ -354,6 +384,57 @@ namespace dxvk { } + uint32_t SpirvModule::opBitcast( + uint32_t resultType, + uint32_t operand) { + uint32_t resultId = this->allocateId(); + + m_code.putIns (spv::OpBitcast, 4); + m_code.putWord(resultType); + m_code.putWord(resultId); + m_code.putWord(operand); + return resultId; + } + + + uint32_t SpirvModule::opCompositeExtract( + uint32_t resultType, + uint32_t composite, + uint32_t indexCount, + const uint32_t* indexArray) { + uint32_t resultId = this->allocateId(); + + m_code.putIns (spv::OpCompositeExtract, 4 + indexCount); + m_code.putWord(resultType); + m_code.putWord(resultId); + m_code.putWord(composite); + + for (uint32_t i = 0; i < indexCount; i++) + m_code.putInt32(indexArray[i]); + return resultId; + } + + + uint32_t SpirvModule::opVectorShuffle( + uint32_t resultType, + uint32_t vectorLeft, + uint32_t vectorRight, + uint32_t indexCount, + const uint32_t* indexArray) { + uint32_t resultId = this->allocateId(); + + m_code.putIns (spv::OpVectorShuffle, 5 + indexCount); + m_code.putWord(resultType); + m_code.putWord(resultId); + m_code.putWord(vectorLeft); + m_code.putWord(vectorRight); + + for (uint32_t i = 0; i < indexCount; i++) + m_code.putInt32(indexArray[i]); + return resultId; + } + + uint32_t SpirvModule::opFunctionCall( uint32_t resultType, uint32_t functionId, @@ -373,7 +454,7 @@ namespace dxvk { void SpirvModule::opLabel(uint32_t labelId) { - m_code.putIns (spv::OpReturn, 2); + m_code.putIns (spv::OpLabel, 2); m_code.putWord(labelId); } diff --git a/src/spirv/spirv_module.h b/src/spirv/spirv_module.h index dc6f21b19..a685878d5 100644 --- a/src/spirv/spirv_module.h +++ b/src/spirv/spirv_module.h @@ -76,6 +76,18 @@ namespace dxvk { uint32_t constCount, const uint32_t* constIds); + void decorateBuiltIn( + uint32_t object, + spv::BuiltIn builtIn); + + void decorateComponent( + uint32_t object, + uint32_t location); + + void decorateLocation( + uint32_t object, + uint32_t location); + uint32_t defVoidType(); uint32_t defBoolType(); @@ -130,6 +142,23 @@ namespace dxvk { void functionEnd(); + uint32_t opBitcast( + uint32_t resultType, + uint32_t operand); + + uint32_t opCompositeExtract( + uint32_t resultType, + uint32_t composite, + uint32_t indexCount, + const uint32_t* indexArray); + + uint32_t opVectorShuffle( + uint32_t resultType, + uint32_t vectorLeft, + uint32_t vectorRight, + uint32_t indexCount, + const uint32_t* indexArray); + uint32_t opFunctionCall( uint32_t resultType, uint32_t functionId, diff --git a/src/util/util_bit.h b/src/util/util_bit.h index ce9762c9b..a946c6c95 100644 --- a/src/util/util_bit.h +++ b/src/util/util_bit.h @@ -3,8 +3,24 @@ namespace dxvk::bit { template - inline T extract(T value, uint32_t fst, uint32_t lst) { + T extract(T value, uint32_t fst, uint32_t lst) { return (value >> fst) & ~(~T(0) << (lst - fst + 1)); } + template + T popcnt(T value) { + return value != 0 + ? (value & 1) + popcnt(value >> 1) + : 0; + } + + template + T tzcnt(T value) { + uint32_t result = 0; + while ((result < sizeof(T) * 8) + && (((value >> result) & 1) == 0)) + result += 1; + return result; + } + } \ No newline at end of file diff --git a/src/util/util_flags.h b/src/util/util_flags.h index 530c59e5f..1d176779d 100644 --- a/src/util/util_flags.h +++ b/src/util/util_flags.h @@ -2,6 +2,8 @@ #include +#include "util_bit.h" + namespace dxvk { template @@ -54,6 +56,10 @@ namespace dxvk { m_bits = 0; } + uint32_t raw() const { + return m_bits; + } + private: IntType m_bits = 0;