diff --git a/src/dxbc/dxbc_compiler.cpp b/src/dxbc/dxbc_compiler.cpp index 0d2830fff..9e48f048a 100644 --- a/src/dxbc/dxbc_compiler.cpp +++ b/src/dxbc/dxbc_compiler.cpp @@ -4,7 +4,7 @@ namespace dxvk { DxbcCompiler::DxbcCompiler(DxbcProgramVersion version) : m_version(version) { - m_entryPointId = m_counter.nextId(); + m_entryPointId = m_module.allocateId(); this->declareCapabilities(); this->declareMemoryModel(); @@ -21,7 +21,7 @@ namespace dxvk { switch (token.opcode()) { case DxbcOpcode::DclThreadGroup: { - m_spvEntryPoints.setLocalSize( + m_module.setLocalSize( m_entryPointId, ins.getArgWord(0), ins.getArgWord(1), @@ -37,33 +37,22 @@ namespace dxvk { Rc DxbcCompiler::finalize() { - SpirvCodeBuffer codeBuffer; - codeBuffer.putHeader(m_counter.numIds()); - codeBuffer.append(m_spvCapabilities.code()); - codeBuffer.append(m_spvEntryPoints.code()); - codeBuffer.append(m_spvDebugInfo.code()); - codeBuffer.append(m_spvDecorations.code()); - codeBuffer.append(m_spvTypeInfo.code()); - codeBuffer.append(m_spvConstants.code()); - codeBuffer.append(m_spvVariables.code()); - codeBuffer.append(m_spvCode); - return new DxvkShader(m_version.shaderStage(), - std::move(codeBuffer), 0, nullptr); + m_module.compile(), 0, nullptr); } void DxbcCompiler::declareCapabilities() { - m_spvCapabilities.enable(spv::CapabilityShader); + m_module.enableCapability(spv::CapabilityShader); switch (m_version.type()) { case DxbcProgramType::GeometryShader: - m_spvCapabilities.enable(spv::CapabilityGeometry); + m_module.enableCapability(spv::CapabilityGeometry); break; case DxbcProgramType::HullShader: case DxbcProgramType::DomainShader: - m_spvCapabilities.enable(spv::CapabilityTessellation); + m_module.enableCapability(spv::CapabilityTessellation); break; default: @@ -73,7 +62,7 @@ namespace dxvk { void DxbcCompiler::declareMemoryModel() { - m_spvEntryPoints.setMemoryModel( + m_module.setMemoryModel( spv::AddressingModelLogical, spv::MemoryModelGLSL450); } diff --git a/src/dxbc/dxbc_compiler.h b/src/dxbc/dxbc_compiler.h index 785665d97..91d39e810 100644 --- a/src/dxbc/dxbc_compiler.h +++ b/src/dxbc/dxbc_compiler.h @@ -2,13 +2,7 @@ #include "dxbc_chunk_shex.h" -#include "../spirv/gen/spirv_gen_capability.h" -#include "../spirv/gen/spirv_gen_constant.h" -#include "../spirv/gen/spirv_gen_debuginfo.h" -#include "../spirv/gen/spirv_gen_decoration.h" -#include "../spirv/gen/spirv_gen_entrypoint.h" -#include "../spirv/gen/spirv_gen_typeinfo.h" -#include "../spirv/gen/spirv_gen_variable.h" +#include "../spirv/spirv_module.h" namespace dxvk { @@ -47,16 +41,7 @@ namespace dxvk { private: DxbcProgramVersion m_version; - SpirvIdCounter m_counter; - - SpirvCapabilities m_spvCapabilities; - SpirvEntryPoint m_spvEntryPoints; - SpirvDebugInfo m_spvDebugInfo; - SpirvDecorations m_spvDecorations; - SpirvTypeInfo m_spvTypeInfo; - SpirvConstants m_spvConstants; - SpirvVariables m_spvVariables; - SpirvCodeBuffer m_spvCode; + SpirvModule m_module; uint32_t m_entryPointId = 0; diff --git a/src/spirv/gen/spirv_gen_capability.cpp b/src/spirv/gen/spirv_gen_capability.cpp deleted file mode 100644 index 487205adc..000000000 --- a/src/spirv/gen/spirv_gen_capability.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "spirv_gen_capability.h" - -namespace dxvk { - - SpirvCapabilities:: SpirvCapabilities() { } - SpirvCapabilities::~SpirvCapabilities() { } - - - void SpirvCapabilities::enable(spv::Capability cap) { - // Scan the generated instructions to check - // whether we already enabled the capability. - for (auto ins : m_code) { - if (ins.opCode() == spv::OpCapability && ins.arg(1) == cap) - return; - } - - m_code.putIns (spv::OpCapability, 2); - m_code.putWord(cap); - } - -} \ No newline at end of file diff --git a/src/spirv/gen/spirv_gen_capability.h b/src/spirv/gen/spirv_gen_capability.h deleted file mode 100644 index f47cecdd8..000000000 --- a/src/spirv/gen/spirv_gen_capability.h +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once - -#include "../spirv_code_buffer.h" - -namespace dxvk { - - /** - * \brief SPIR-V capability set - * - * Holds a code buffer solely for the \c OpCapability - * instructions in the generated SPIR-V shader module. - */ - class SpirvCapabilities { - - public: - - SpirvCapabilities(); - ~SpirvCapabilities(); - - /** - * \brief Code buffer - * - * Code buffer that contains the - * \c OpCapability instructions. - * \returns Code buffer - */ - const SpirvCodeBuffer& code() const { - return m_code; - } - - /** - * \brief Enables a capability - * - * If the given capability has not been explicitly - * enabled yet, this will generate an \c OpCapability - * instruction for the given capability. - * \param [in] cap The capability - */ - void enable(spv::Capability cap); - - private: - - SpirvCodeBuffer m_code; - - }; - -} \ No newline at end of file diff --git a/src/spirv/gen/spirv_gen_constant.cpp b/src/spirv/gen/spirv_gen_constant.cpp deleted file mode 100644 index cf41273f4..000000000 --- a/src/spirv/gen/spirv_gen_constant.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "spirv_gen_constant.h" - -namespace dxvk { - - SpirvConstants:: SpirvConstants() { } - SpirvConstants::~SpirvConstants() { } - - - SpirvCodeBuffer SpirvConstants::code() const { - return m_code; - } - -} \ No newline at end of file diff --git a/src/spirv/gen/spirv_gen_constant.h b/src/spirv/gen/spirv_gen_constant.h deleted file mode 100644 index 2981254a1..000000000 --- a/src/spirv/gen/spirv_gen_constant.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include "../spirv_code_buffer.h" - -#include "spirv_gen_id.h" - -namespace dxvk { - - /** - * \brief SPIR-V constant generator - * - * Provides convenient methods to - * generate SPIR-V constants. - */ - class SpirvConstants { - - public: - - SpirvConstants(); - ~SpirvConstants(); - - SpirvCodeBuffer code() const; - - private: - - SpirvCodeBuffer m_code; - - }; - -} \ No newline at end of file diff --git a/src/spirv/gen/spirv_gen_debuginfo.cpp b/src/spirv/gen/spirv_gen_debuginfo.cpp deleted file mode 100644 index a8f383386..000000000 --- a/src/spirv/gen/spirv_gen_debuginfo.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "spirv_gen_debuginfo.h" - -namespace dxvk { - - SpirvDebugInfo:: SpirvDebugInfo() { } - SpirvDebugInfo::~SpirvDebugInfo() { } - - - void SpirvDebugInfo::assignName( - uint32_t id, - const char* name) { - m_code.putIns (spv::OpName, 2 + m_code.strLen(name)); - m_code.putWord(id); - m_code.putStr (name); - } - -} \ No newline at end of file diff --git a/src/spirv/gen/spirv_gen_debuginfo.h b/src/spirv/gen/spirv_gen_debuginfo.h deleted file mode 100644 index b3fbfb7a3..000000000 --- a/src/spirv/gen/spirv_gen_debuginfo.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -#include "../spirv_code_buffer.h" - -namespace dxvk { - - /** - * \brief SPIR-V debug info generator - * - * Can be used to assign names to result IDs, - * such as variables, for debugging purposes. - */ - class SpirvDebugInfo { - - public: - - SpirvDebugInfo(); - ~SpirvDebugInfo(); - - const SpirvCodeBuffer& code() const { - return m_code; - } - - void assignName( - uint32_t id, - const char* name); - - private: - - SpirvCodeBuffer m_code; - - }; - -} \ No newline at end of file diff --git a/src/spirv/gen/spirv_gen_decoration.cpp b/src/spirv/gen/spirv_gen_decoration.cpp deleted file mode 100644 index 3c5406a29..000000000 --- a/src/spirv/gen/spirv_gen_decoration.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include "spirv_gen_decoration.h" - -namespace dxvk { - - SpirvDecorations:: SpirvDecorations() { } - SpirvDecorations::~SpirvDecorations() { } - -} \ No newline at end of file diff --git a/src/spirv/gen/spirv_gen_decoration.h b/src/spirv/gen/spirv_gen_decoration.h deleted file mode 100644 index c82d91509..000000000 --- a/src/spirv/gen/spirv_gen_decoration.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include "../spirv_code_buffer.h" - -#include "spirv_gen_id.h" - -namespace dxvk { - - /** - * \brief SPIR-V decoration generator - * - * Generates instructions for descriptor - * bindings and builtin variable decorations. - */ - class SpirvDecorations { - - public: - - SpirvDecorations(); - ~SpirvDecorations(); - - const SpirvCodeBuffer& code() const { - return m_code; - } - - private: - - SpirvCodeBuffer m_code; - - }; - -} \ No newline at end of file diff --git a/src/spirv/gen/spirv_gen_entrypoint.cpp b/src/spirv/gen/spirv_gen_entrypoint.cpp deleted file mode 100644 index fc99d837b..000000000 --- a/src/spirv/gen/spirv_gen_entrypoint.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include "spirv_gen_entrypoint.h" - -namespace dxvk { - - SpirvEntryPoint:: SpirvEntryPoint() { } - SpirvEntryPoint::~SpirvEntryPoint() { } - - - SpirvCodeBuffer SpirvEntryPoint::code() const { - SpirvCodeBuffer code; - code.append(m_memoryModel); - code.append(m_entryPoints); - code.append(m_execModeInfo); - return code; - } - - - void SpirvEntryPoint::setMemoryModel( - spv::AddressingModel addressModel, - spv::MemoryModel memoryModel) { - m_memoryModel.putIns (spv::OpMemoryModel, 3); - m_memoryModel.putWord (addressModel); - m_memoryModel.putWord (memoryModel); - } - - - void SpirvEntryPoint::addEntryPoint( - uint32_t functionId, - spv::ExecutionModel execModel, - const char* name, - uint32_t interfaceCount, - const uint32_t* interfaceIds) { - m_entryPoints.putIns (spv::OpEntryPoint, 3 + m_entryPoints.strLen(name) + interfaceCount); - m_entryPoints.putWord (execModel); - m_entryPoints.putWord (functionId); - m_entryPoints.putStr (name); - - for (uint32_t i = 0; i < interfaceCount; i++) - m_entryPoints.putWord(interfaceIds[i]); - } - - - void SpirvEntryPoint::setLocalSize( - uint32_t functionId, - uint32_t x, - uint32_t y, - uint32_t z) { - m_execModeInfo.putIns (spv::OpExecutionMode, 6); - m_execModeInfo.putWord(functionId); - m_execModeInfo.putWord(spv::ExecutionModeLocalSize); - m_execModeInfo.putWord(x); - m_execModeInfo.putWord(y); - m_execModeInfo.putWord(z); - } - -} \ No newline at end of file diff --git a/src/spirv/gen/spirv_gen_entrypoint.h b/src/spirv/gen/spirv_gen_entrypoint.h deleted file mode 100644 index 492c184c7..000000000 --- a/src/spirv/gen/spirv_gen_entrypoint.h +++ /dev/null @@ -1,88 +0,0 @@ -#pragma once - -#include "../spirv_code_buffer.h" - -namespace dxvk { - - /** - * \brief SPIR-V entry point info - * - * Accumulates information about the entry - * point of the generated shader module, - * including execution mode info. - */ - class SpirvEntryPoint { - - public: - - SpirvEntryPoint(); - ~SpirvEntryPoint(); - - /** - * \brief Generates SPIR-V code - * \returns SPIR-V code buffer - */ - SpirvCodeBuffer code() const; - - /** - * \brief Sets memory model - * - * Generates an \c OpMemoryModel instruction. - * Only ever call this once, or otherwise the - * resulting shader will become undefined. - * \param [in] addressModel Address model - * \param [in] memoryModel Memory model - */ - void setMemoryModel( - spv::AddressingModel addressModel, - spv::MemoryModel memoryModel); - - /** - * \brief Adds an entry point - * - * Currently, DXVK expects there to be a single entry point - * with the name \c main. Do not create additional entry points. - * \param [in] functionId Entry point function ID - * \param [in] execModel Execution model for the function - * \param [in] name Entry point name that is used by Vulkan - * \param [in] interfaceCount Number of additional interface IDs - * \param [in] interfaceIds List of additional interface IDs - */ - void addEntryPoint( - uint32_t functionId, - spv::ExecutionModel execModel, - const char* name, - uint32_t interfaceCount, - const uint32_t* interfaceIds); - - /** - * \brief Enables early fragment tests - */ - void enableEarlyFragmentTests( - uint32_t functionId); - - /** - * \brief Sets local work group size for a compute shader - * - * Adds a \c OpExecutionMode instruction that sets - * the local work group size for a compute shader. - * \param [in] functionId Entry point ID - * \param [in] x Number of threads in X direction - * \param [in] y Number of threads in Y direction - * \param [in] z Number of threads in Z direction - */ - void setLocalSize( - uint32_t functionId, - uint32_t x, - uint32_t y, - uint32_t z); - - private: - - SpirvCodeBuffer m_memoryModel; - SpirvCodeBuffer m_entryPoints; - SpirvCodeBuffer m_execModeInfo; - - }; - -} \ No newline at end of file diff --git a/src/spirv/gen/spirv_gen_id.h b/src/spirv/gen/spirv_gen_id.h deleted file mode 100644 index f0f108b62..000000000 --- a/src/spirv/gen/spirv_gen_id.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include "../spirv_include.h" - -namespace dxvk { - - /** - * \brief SPIR-V ID counter - * - * Allocates IDs, starting at zero. This is meant - * to be used to allocate unique IDs during code - * generation. - */ - class SpirvIdCounter { - - public: - - uint32_t nextId() { - return ++m_id; - } - - uint32_t numIds() const { - return m_id; - } - - private: - - uint32_t m_id = 0; - - }; - -} \ No newline at end of file diff --git a/src/spirv/gen/spirv_gen_typeinfo.cpp b/src/spirv/gen/spirv_gen_typeinfo.cpp deleted file mode 100644 index b78d1085c..000000000 --- a/src/spirv/gen/spirv_gen_typeinfo.cpp +++ /dev/null @@ -1,146 +0,0 @@ -#include - -#include "spirv_gen_typeinfo.h" - -namespace dxvk { - - SpirvTypeInfo:: SpirvTypeInfo() { } - SpirvTypeInfo::~SpirvTypeInfo() { } - - - uint32_t SpirvTypeInfo::typeVoid(SpirvIdCounter& ids) { - return this->getTypeId(ids, - spv::OpTypeVoid, 0, nullptr); - } - - - uint32_t SpirvTypeInfo::typeBool(SpirvIdCounter& ids) { - return this->getTypeId(ids, - spv::OpTypeBool, 0, nullptr); - } - - - uint32_t SpirvTypeInfo::typeInt( - SpirvIdCounter& ids, - uint32_t width, - uint32_t isSigned) { - std::array args = {{ width, isSigned }}; - return this->getTypeId(ids, - spv::OpTypeInt, args.size(), args.data()); - } - - - uint32_t SpirvTypeInfo::typeFloat( - SpirvIdCounter& ids, - uint32_t width) { - return this->getTypeId(ids, - spv::OpTypeFloat, 1, &width); - } - - - uint32_t SpirvTypeInfo::typeVector( - SpirvIdCounter& ids, - uint32_t componentType, - uint32_t componentCount) { - std::array args = {{ componentType, componentCount }}; - return this->getTypeId(ids, - spv::OpTypeVector, args.size(), args.data()); - } - - - uint32_t SpirvTypeInfo::typeMatrix( - SpirvIdCounter& ids, - uint32_t colType, - uint32_t colCount) { - std::array args = {{ colType, colCount }}; - return this->getTypeId(ids, - spv::OpTypeMatrix, args.size(), args.data()); - } - - - uint32_t SpirvTypeInfo::typeArray( - SpirvIdCounter& ids, - uint32_t elementType, - uint32_t elementCount) { - std::array args = {{ elementType, elementCount }}; - return this->getTypeId(ids, - spv::OpTypeArray, args.size(), args.data()); - } - - - uint32_t SpirvTypeInfo::typeRuntimeArray( - SpirvIdCounter& ids, - uint32_t elementType) { - return this->getTypeId(ids, - spv::OpTypeRuntimeArray, 1, &elementType); - } - - - uint32_t SpirvTypeInfo::typePointer( - SpirvIdCounter& ids, - spv::StorageClass storageClass, - uint32_t type) { - std::array args = {{ storageClass, type }}; - return this->getTypeId(ids, - spv::OpTypePointer, args.size(), args.data()); - } - - - uint32_t SpirvTypeInfo::typeFunction( - SpirvIdCounter& ids, - uint32_t returnType, - uint32_t argCount, - const uint32_t* argTypes) { - std::vector args(argCount + 1); - args.at(0) = returnType; - - for (uint32_t i = 0; i < argCount; i++) - args.at(i + 1) = argTypes[i]; - - return this->getTypeId(ids, - spv::OpTypeFunction, - args.size(), args.data()); - } - - - uint32_t SpirvTypeInfo::typeStruct( - SpirvIdCounter& ids, - uint32_t memberCount, - const uint32_t* memberTypes) { - return this->getTypeId(ids, - spv::OpTypeStruct, - memberCount, - memberTypes); - } - - - uint32_t SpirvTypeInfo::getTypeId( - SpirvIdCounter& ids, - spv::Op op, - uint32_t argCount, - const uint32_t* args) { - // 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_code) { - bool match = ins.opCode() == op; - - for (uint32_t i = 0; i < argCount && match; i++) - match &= ins.arg(2 + i) == args[i]; - - if (match) - return ins.arg(1); - } - - // Type not yet declared, create a new one. - uint32_t result = ids.nextId(); - m_code.putIns (op, 2 + argCount); - m_code.putWord(result); - - for (uint32_t i = 0; i < argCount; i++) - m_code.putWord(args[i]); - return result; - } - - -} \ No newline at end of file diff --git a/src/spirv/gen/spirv_gen_typeinfo.h b/src/spirv/gen/spirv_gen_typeinfo.h deleted file mode 100644 index 637f32fba..000000000 --- a/src/spirv/gen/spirv_gen_typeinfo.h +++ /dev/null @@ -1,88 +0,0 @@ -#pragma once - -#include "../spirv_code_buffer.h" - -#include "spirv_gen_id.h" - -namespace dxvk { - - /** - * \brief SPIR-V type set - * - * Stores SPIR-V type definition so that - * each type will only be declared once. - */ - class SpirvTypeInfo { - - public: - - SpirvTypeInfo(); - ~SpirvTypeInfo(); - - const SpirvCodeBuffer& code() const { - return m_code; - } - - uint32_t typeVoid( - SpirvIdCounter& ids); - - uint32_t typeBool( - SpirvIdCounter& ids); - - uint32_t typeInt( - SpirvIdCounter& ids, - uint32_t width, - uint32_t isSigned); - - uint32_t typeFloat( - SpirvIdCounter& ids, - uint32_t width); - - uint32_t typeVector( - SpirvIdCounter& ids, - uint32_t componentType, - uint32_t componentCount); - - uint32_t typeMatrix( - SpirvIdCounter& ids, - uint32_t colType, - uint32_t colCount); - - uint32_t typeArray( - SpirvIdCounter& ids, - uint32_t elementType, - uint32_t elementCount); - - uint32_t typeRuntimeArray( - SpirvIdCounter& ids, - uint32_t elementType); - - uint32_t typePointer( - SpirvIdCounter& ids, - spv::StorageClass storageClass, - uint32_t type); - - uint32_t typeFunction( - SpirvIdCounter& ids, - uint32_t returnType, - uint32_t argCount, - const uint32_t* argTypes); - - uint32_t typeStruct( - SpirvIdCounter& ids, - uint32_t memberCount, - const uint32_t* memberTypes); - - private: - - SpirvCodeBuffer m_code; - - uint32_t getTypeId( - SpirvIdCounter& ids, - spv::Op op, - uint32_t argCount, - const uint32_t* args); - - }; - -} \ No newline at end of file diff --git a/src/spirv/gen/spirv_gen_variable.cpp b/src/spirv/gen/spirv_gen_variable.cpp deleted file mode 100644 index e41a33369..000000000 --- a/src/spirv/gen/spirv_gen_variable.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include "spirv_gen_variable.h" - -namespace dxvk { - - SpirvVariables:: SpirvVariables() { } - SpirvVariables::~SpirvVariables() { } - -} \ No newline at end of file diff --git a/src/spirv/gen/spirv_gen_variable.h b/src/spirv/gen/spirv_gen_variable.h deleted file mode 100644 index a695ab9fd..000000000 --- a/src/spirv/gen/spirv_gen_variable.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include "../spirv_code_buffer.h" - -#include "spirv_gen_id.h" - -namespace dxvk { - - /** - * \brief SPIR-V variable generator - * - * Generates global variable declarations. - */ - class SpirvVariables { - - public: - - SpirvVariables(); - ~SpirvVariables(); - - const SpirvCodeBuffer& code() const { - return m_code; - } - - private: - - SpirvCodeBuffer m_code; - - }; - -} \ No newline at end of file diff --git a/src/spirv/meson.build b/src/spirv/meson.build index c31b799d8..dd1452f3d 100644 --- a/src/spirv/meson.build +++ b/src/spirv/meson.build @@ -1,13 +1,6 @@ spirv_src = files([ 'spirv_code_buffer.cpp', - - 'gen/spirv_gen_capability.cpp', - 'gen/spirv_gen_constant.cpp', - 'gen/spirv_gen_debuginfo.cpp', - 'gen/spirv_gen_decoration.cpp', - 'gen/spirv_gen_entrypoint.cpp', - 'gen/spirv_gen_typeinfo.cpp', - 'gen/spirv_gen_variable.cpp', + 'spirv_module.cpp', ]) spirv_lib = static_library('spirv', spirv_src, diff --git a/src/spirv/spirv_module.cpp b/src/spirv/spirv_module.cpp new file mode 100644 index 000000000..388eaae07 --- /dev/null +++ b/src/spirv/spirv_module.cpp @@ -0,0 +1,372 @@ +#include "spirv_module.h" + +namespace dxvk { + + SpirvModule:: SpirvModule() { } + SpirvModule::~SpirvModule() { } + + + SpirvCodeBuffer SpirvModule::compile() const { + SpirvCodeBuffer result; + result.putHeader(m_id); + result.append(m_capabilities); + result.append(m_memoryModel); + result.append(m_entryPoints); + result.append(m_execModeInfo); + result.append(m_debugNames); + result.append(m_annotations); + result.append(m_typeDefs); + result.append(m_constDefs); + result.append(m_variables); + result.append(m_code); + return result; + } + + + uint32_t SpirvModule::allocateId() { + return ++m_id; + } + + + void SpirvModule::enableCapability( + spv::Capability capability) { + // Scan the generated instructions to check + // whether we already enabled the capability. + for (auto ins : m_capabilities) { + if (ins.opCode() == spv::OpCapability && ins.arg(1) == capability) + return; + } + + m_capabilities.putIns (spv::OpCapability, 2); + m_capabilities.putWord(capability); + } + + + void SpirvModule::addEntryPoint( + uint32_t entryPointId, + spv::ExecutionModel executionModel, + const char* name, + uint32_t interfaceCount, + const uint32_t* interfaceIds) { + + } + + + void SpirvModule::setMemoryModel( + spv::AddressingModel addressModel, + spv::MemoryModel memoryModel) { + + } + + + void SpirvModule::enableEarlyFragmentTests( + uint32_t entryPointId) { + + } + + + void SpirvModule::setLocalSize( + uint32_t entryPointId, + uint32_t x, + uint32_t y, + uint32_t z) { + + } + + + void SpirvModule::setDebugName( + uint32_t expressionId, + const char* 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); + return resultId; + } + + + uint32_t SpirvModule::consti32( + int32_t v) { + 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); + return resultId; + } + + + uint32_t SpirvModule::consti64( + int64_t v) { + 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); + return resultId; + } + + + uint32_t SpirvModule::constu32( + uint32_t v) { + 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); + return resultId; + } + + + uint32_t SpirvModule::constu64( + uint64_t v) { + 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); + return resultId; + } + + + uint32_t SpirvModule::constf32( + float v) { + 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); + return resultId; + } + + + uint32_t SpirvModule::constf64( + double v) { + 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); + return resultId; + } + + + uint32_t SpirvModule::constComposite( + uint32_t typeId, + uint32_t constCount, + const uint32_t* constIds) { + uint32_t resultId = this->allocateId(); + + m_constDefs.putIns (spv::OpConstantComposite, 3 + constCount); + m_constDefs.putWord (typeId); + m_constDefs.putWord (resultId); + + for (uint32_t i = 0; i < constCount; i++) + m_constDefs.putWord(constIds[i]); + return resultId; + } + + + uint32_t SpirvModule::defVoidType() { + return this->defType(spv::OpTypeVoid, 0, nullptr); + } + + + uint32_t SpirvModule::defBoolType() { + return this->defType(spv::OpTypeBool, 0, nullptr); + } + + + uint32_t SpirvModule::defIntType( + uint32_t width, + uint32_t isSigned) { + std::array args = { width, isSigned }; + return this->defType(spv::OpTypeInt, + args.size(), args.data()); + } + + + uint32_t SpirvModule::defFloatType( + uint32_t width) { + std::array args = { width }; + return this->defType(spv::OpTypeFloat, + args.size(), args.data()); + } + + + uint32_t SpirvModule::defVectorType( + uint32_t elementType, + uint32_t elementCount) { + std::array args = { + elementType, + elementCount + }; + + return this->defType(spv::OpTypeVector, + args.size(), args.data()); + } + + + uint32_t SpirvModule::defMatrixType( + uint32_t columnType, + uint32_t columnCount) { + std::array args = { + columnType, + columnCount + }; + + return this->defType(spv::OpTypeMatrix, + args.size(), args.data()); + } + + + uint32_t SpirvModule::defArrayType( + uint32_t typeId, + uint32_t length) { + std::array args = { typeId, length }; + + return this->defType(spv::OpTypeArray, + args.size(), args.data()); + } + + + uint32_t SpirvModule::defRuntimeArrayType( + uint32_t typeId) { + std::array args = { typeId }; + + return this->defType(spv::OpTypeRuntimeArray, + args.size(), args.data()); + } + + + uint32_t SpirvModule::defFunctionType( + uint32_t returnType, + uint32_t argCount, + const uint32_t* argTypes) { + std::vector args; + args.push_back(returnType); + + for (uint32_t i = 0; i < argCount; i++) + args.push_back(argTypes[i]); + + return this->defType(spv::OpTypeFunction, + args.size(), args.data()); + } + + + uint32_t SpirvModule::defStructType( + uint32_t memberCount, + const uint32_t* memberTypes) { + return this->defType(spv::OpTypeStruct, + memberCount, memberTypes); + } + + + uint32_t SpirvModule::defPointerType( + uint32_t variableType, + spv::StorageClass storageClass) { + std::array args = { + variableType, + storageClass, + }; + + return this->defType(spv::OpTypePointer, + args.size(), args.data()); + } + + + void SpirvModule::functionBegin( + uint32_t returnType, + uint32_t functionId, + uint32_t functionType, + spv::FunctionControlMask functionControl) { + m_code.putIns (spv::OpFunction, 5); + m_code.putWord(returnType); + m_code.putWord(functionId); + m_code.putWord(functionControl); + m_code.putWord(functionType); + } + + + uint32_t SpirvModule::functionParameter( + uint32_t parameterType) { + uint32_t parameterId = this->allocateId(); + + m_code.putIns (spv::OpFunctionParameter, 3); + m_code.putWord(parameterType); + m_code.putWord(parameterId); + return parameterId; + } + + + void SpirvModule::functionEnd() { + m_code.putIns (spv::OpFunctionEnd, 1); + } + + + uint32_t SpirvModule::opFunctionCall( + uint32_t resultType, + uint32_t functionId, + uint32_t argCount, + const uint32_t* argIds) { + uint32_t resultId = this->allocateId(); + + m_code.putIns (spv::OpFunctionCall, 4 + argCount); + m_code.putWord(resultType); + m_code.putWord(resultId); + m_code.putWord(functionId); + + for (uint32_t i = 0; i < argCount; i++) + m_code.putWord(argIds[i]); + return resultId; + } + + + uint32_t SpirvModule::defType( + spv::Op op, + uint32_t argCount, + const uint32_t* argIds) { + // 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) { + bool match = ins.opCode() == op; + + for (uint32_t i = 0; i < argCount && match; i++) + match &= ins.arg(2 + i) == argIds[i]; + + if (match) + return ins.arg(1); + } + + // Type not yet declared, create a new one. + uint32_t resultId = this->allocateId(); + m_typeDefs.putIns (op, 2 + argCount); + m_typeDefs.putWord(resultId); + + for (uint32_t i = 0; i < argCount; i++) + m_typeDefs.putWord(argIds[i]); + return resultId; + } + +} \ No newline at end of file diff --git a/src/spirv/spirv_module.h b/src/spirv/spirv_module.h new file mode 100644 index 000000000..4a3376332 --- /dev/null +++ b/src/spirv/spirv_module.h @@ -0,0 +1,157 @@ +#pragma once + +#include "spirv_code_buffer.h" + +namespace dxvk { + + /** + * \brief SPIR-V module + * + * This class generates a code buffer containing a full + * SPIR-V shader module. Ensures that the module layout + * is valid, as defined in the SPIR-V 1.0 specification, + * section 2.4 "Logical Layout of a Module". + */ + class SpirvModule { + + public: + + SpirvModule(); + ~SpirvModule(); + + SpirvCodeBuffer compile() const; + + uint32_t allocateId(); + + void enableCapability( + spv::Capability capability); + + void addEntryPoint( + uint32_t entryPointId, + spv::ExecutionModel executionModel, + const char* name, + uint32_t interfaceCount, + const uint32_t* interfaceIds); + + void setMemoryModel( + spv::AddressingModel addressModel, + spv::MemoryModel memoryModel); + + void enableEarlyFragmentTests( + uint32_t entryPointId); + + void setLocalSize( + uint32_t entryPointId, + uint32_t x, + uint32_t y, + uint32_t z); + + void setDebugName( + uint32_t expressionId, + const char* debugName); + + uint32_t constBool( + bool v); + + uint32_t consti32( + int32_t v); + + uint32_t consti64( + int64_t v); + + uint32_t constu32( + uint32_t v); + + uint32_t constu64( + uint64_t v); + + uint32_t constf32( + float v); + + uint32_t constf64( + double v); + + uint32_t constComposite( + uint32_t typeId, + uint32_t constCount, + const uint32_t* constIds); + + uint32_t defVoidType(); + + uint32_t defBoolType(); + + uint32_t defIntType( + uint32_t width, + uint32_t isSigned); + + uint32_t defFloatType( + uint32_t width); + + uint32_t defVectorType( + uint32_t elementType, + uint32_t elementCount); + + uint32_t defMatrixType( + uint32_t columnType, + uint32_t columnCount); + + uint32_t defArrayType( + uint32_t typeId, + uint32_t length); + + uint32_t defRuntimeArrayType( + uint32_t typeId); + + uint32_t defFunctionType( + uint32_t returnType, + uint32_t argCount, + const uint32_t* argTypes); + + uint32_t defStructType( + uint32_t memberCount, + const uint32_t* memberTypes); + + uint32_t defPointerType( + uint32_t variableType, + spv::StorageClass storageClass); + + void functionBegin( + uint32_t returnType, + uint32_t functionId, + uint32_t functionType, + spv::FunctionControlMask functionControl); + + uint32_t functionParameter( + uint32_t parameterType); + + void functionEnd(); + + uint32_t opFunctionCall( + uint32_t resultType, + uint32_t functionId, + uint32_t argCount, + const uint32_t* argIds); + + private: + + uint32_t m_id = 0; + + SpirvCodeBuffer m_capabilities; + SpirvCodeBuffer m_memoryModel; + SpirvCodeBuffer m_entryPoints; + SpirvCodeBuffer m_execModeInfo; + SpirvCodeBuffer m_debugNames; + SpirvCodeBuffer m_annotations; + SpirvCodeBuffer m_typeDefs; + SpirvCodeBuffer m_constDefs; + SpirvCodeBuffer m_variables; + SpirvCodeBuffer m_code; + + uint32_t defType( + spv::Op op, + uint32_t argCount, + const uint32_t* argIds); + + }; + +} \ No newline at end of file