Home

Awesome

SpvGenTwo

SpvGenTwo is a SPIR-V building and parsing library written in C++17, no other dependencies! No STL or other 3rd-Party library needed. The library comes with its own set of SPIR-V definitions generated from the machine readable grammar and therefore does not require any vulkan or spirv-headers includes. The generator can be found here: rustspvgen.

I built this library as a 'slim' backend for runtime material/shader-editors (like Proto) to avoid introducing enormous libraries like DXC (including LLVM and Frontend) or SPIRV-Tools to the codebase.

SpvGenTwo is still under development, many parts are still missing, but all the building blocks are there. SpvGenTwo is designed to be extensible and customizable, it is fairly easy to implement new SPIR-V instructions and extensions, use custom allocators and define own type inference rules. Note that it is still possible to generate invalid SPIR-V modules because not all inputs are checked yet. Use the SPIR-V validator spirv-val from the SDK and have the specification at hand while using this library.

I mainly focused on Shader capabilities, so the Kernel and OpenCL side is a bit under-developed. Any community contributions in that regard are very welcome!

Overview:

Examples

ConsoleLogger log;
HeapAllocator alloc; // custom user allocator

// create a new spir-v module
Module module(&alloc, &log);

// configure capabilities and extensions
module.addCapability(spv::Capability::Shader);
module.addCapability(spv::Capability::VulkanMemoryModelKHR);
module.addExtension(spv::Extension::SPV_KHR_vulkan_memory_model);
Instruction* ext = module.getExtensionInstructionImport(u8"GLSL.std.450");
module.setMemoryModel(spv::AddressingModel::Logical, spv::MemoryModel::VulkanKHR);

// global variables
Instruction* uniformVar = module.uniform<vector_t<float, 3>>(u8"u_Position");

// float add(float x, float y)
Function& funcAdd = module.addFunction<float, float, float>(u8"add", spv::FunctionControlMask::Const);
{
    BasicBlock& bb = *funcAdd; // get entry block to this function

    Instruction* x = funcAdd.getParameter(0);
    Instruction* y = funcAdd.getParameter(1);

    Instruction* z = bb.Add(x, y);
    bb.returnValue(z);
}

// void entryPoint();
{
    EntryPoint& entry = module.addEntryPoint(spv::ExecutionModel::Fragment, u8"main");
    entry.addExecutionMode(spv::ExecutionMode::OriginUpperLeft);
    BasicBlock& bb = *entry; // get entry block to this function

    Instruction* uniVec = bb->opLoad(uniformVar);
    Instruction* cross = bb.ext<GLSL>()->opCross(uniVec, uniVec); // use GLSL.std.450 extension
    Instruction* s = bb->opDot(cross, uniVec);
    entry->call(&funcAdd, s, s); // call add(s, s)
    entry->opReturn();
}

// custom spir-v binary serializer:
BinaryFileWriter writer("test.spv");
module.finalizeAndWrite(writer);

The resulting SPIR-V binary when disassembled using spirv-dis:

; SPIR-V
; Version: 1.0
; Generator: SpvGenTwo SPIR-V IR Tools(30); 0
; Bound: 20
; Schema: 0
               OpCapability Shader
               OpCapability VulkanMemoryModelKHR
               OpExtension "SPV_KHR_vulkan_memory_model"
          %1 = OpExtInstImport "GLSL.std.450"
               OpMemoryModel Logical VulkanKHR
               OpEntryPoint Fragment %main "main" %u_Position
               OpExecutionMode %main OriginUpperLeft
               OpName %u_Position "u_Position"
               OpName %add "add"
               OpName %main "main"
      %float = OpTypeFloat 32
    %v3float = OpTypeVector %float 3
%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
          %9 = OpTypeFunction %float %float %float
       %void = OpTypeVoid
          %3 = OpTypeFunction %void
 %u_Position = OpVariable %_ptr_Uniform_v3float Uniform
        %add = OpFunction %float Const %9
         %11 = OpFunctionParameter %float
         %12 = OpFunctionParameter %float
         %13 = OpLabel
         %14 = OpFAdd %float %11 %12
               OpReturnValue %14
               OpFunctionEnd
       %main = OpFunction %void None %3
         %15 = OpLabel
         %16 = OpLoad %v3float %u_Position None
         %17 = OpExtInst %v3float %1 Cross %16 %16
         %18 = OpDot %float %17 %16
         %19 = OpFunctionCall %float %add %18 %18
               OpReturn
               OpFunctionEnd

Test Project

Set CMake option SPVGENTWO_BUILD_TESTS to TRUE to build included examples:

Project Structure

SpvGenTwo is split into 5 folders:

Building

Use the supplied CMakeLists.txt to generate project files for your build system. SpvGenTwo allows the user to use standard library headers (<type_traits>, <new> etc) instead of my hand-made replacements (see stdreplament.h).

Note that I mainly develop on Windows using Clang and MSVC but I'll also try to support GCC/linux. I don't have any Apple hardware so I can't debug any issues there, but you are welcome to contribute fixes for this platform.

Tools

SpvGenTwo includes a couple of CLI tools to explore and test the libraries capabilities.

SPIR-V Disassembler

SpvGenTwoDisassembler

SpvGenTwoDisassembler source can be found at dis/source/dis.cpp, it is just a single source file demonstrating the basic parsing and IR walking capabilities of SpvGenTwo.

CLI: SpvGenTwoDisassembler [file] <option> <option> ...

Options

SPIR-V Reflector

SpvGenTwoReflect

SpvGenTwoReflect source can be found at refl/source/refl.cpp

CLI: SpvGenTwoReflect [file] <option> <option> ...

Options

SPIR-V Linker

SpvGenTwoLinker

SPIR-V Shader library linker and patcher. See SpvGenTwoLinker for detailed description. Source can be found at link/source/link.cpp.

Documentation

Please read the documentation for more detailed information on how to use SpvGenTwo and some reasoning about my design choices.

Contributing

Please follow the "fork-and-pull" Git workflow:

Make sure to merge the latest from "upstream" before making a pull request.

Copyright and Licensing

The SpvGenTwo open source project is licensed under MIT license. Any contribution you make to this original repository shall be licensed under same license. You are still free to distribute your contributions (in your own fork) under the license you desire.

Roadmap

A list of short and long term goals for this library:

Gallery

SpvGenTwo is used in:

Leave PR with your software if you want it to be added here :)

Coverage

SPIR-V IR generation progress, parsing is independent and auto generated. This table indicates whether the operation is already implemented in the Instruction class or can be generated by other facilities. This is not a complete list, if an entry is missing, assume it has not been implemented yet. You can file an Issue to request its implementation or just use Instruction::makeOp(...) directly.

Core

InstructionImplemented
OpNop
OpUndef
OpSourceContinued
OpSource
OpSourceExtension
OpName
OpMemberName
OpString
OpLine
OpExtension
OpExtInstImport
OpExtInst
OpMemoryModel
OpEntryPoint
opExecutionMode
OpCapability
OpExecutionModeId
OpTypeXXXvia Module::addType()/type<T>
OpConstantXXXvia Module::addConstant()/constant<T>(T t)
OpSpecConstantXXXvia Module::addConstant()/constant<T>(T t)
OpSpecConstantOp
OpFunction
OpFunctionParameter
OpFunctionEnd
OpFunctionCall
OpVariable
OpImageTexelPointer
OpLoad
OpStore
OpCopyMemory
OpCopyMemorySized
OpAccessChain
OpInBoundsAccessChain
OpPtrAccessChain
OpArrayLength
OpGenericPtrMemSemantics
OpInBoundsPtrAccessChain
OpDecorate
OpMemberDecorate
OpDecorationGroupDeprecated
OpGroupDecorateDeprecated
OpGroupMemberDecorateDeprecated
OpVectorExtractDynamic
OpVectorInsertDynamic
OpVectorShuffle
OpCompositeConstruct
OpCompositeExtract
OpCompositeInsert
OpCopyObject
OpTranspose
OpSampledImage
OpImageSampleImplicitLod
OpImageSampleExplicitLod
OpImageSampleDrefImplicitLod
OpImageSampleDrefExplicitLod
OpImageSampleProjImplicitLod
OpImageSampleProjExplicitLod
OpImageSampleProjDrefImplicitLod
OpImageSampleProjDrefExplicitLod
OpImageFetch
OpImageGather
OpImageDrefGather
OpImageRead
OpImageWrite
OpImage
OpImageQueryFormat
OpImageQueryOrder
OpImageQuerySizeLod
OpImageQuerySize
OpImageQueryLod
OpImageQueryLevels
OpImageQuerySamples
OpConvertFToU
OpConvertFToS
OpConvertSToF
OpConvertUToF
OpUConvert
OpSConvert
OpFConvert
OpQuantizeToF16
OpConvertPtrToU
OpSatConvertSToU
OpSatConvertUToS
OpConvertUToPtr
OpPtrCastToGeneric
OpGenericCastToPtr
OpGenericCastToPtrExplicit
OpBitcast
OpSNegate
OpFNegate
OpIAdd
OpFAdd
OpISub
OpFSub
OpIMul
OpFMul
OpUDiv
OpSDiv
OpFDiv
OpUMod
OpSRem
OpSMod
OpFRem
OpFMod
OpVectorTimesScalar
OpMatrixTimesScalar
OpVectorTimesMatrix
OpMatrixTimesVector
OpMatrixTimesMatrix
OpOuterProduct
OpDot
OpIAddCarry
OpISubBorrow
OpUMulExtended
OpSMulExtended
OpAny
OpAll
OpIsNan
OpIsInf
OpIsFinite
OpIsNormal
OpSignBitSet
OpLessOrGreaterDeprecated
OpOrdered
OpUnordered
OpLogicalEqual
OpLogicalNotEqual
OpLogicalOr
OpLogicalAnd
OpLogicalNot
OpSelect
OpIEqual
OpINotEqual
OpUGreaterThan
OpSGreaterThan
OpUGreaterThanEqual
OpSGreaterThanEqual
OpULessThan
OpSLessThan
OpULessThanEqual
OpSLessThanEqual
OpFOrdEqual
OpFUnordEqual
OpFOrdNotEqual
OpFUnordNotEqual
OpFOrdLessThan
OpFUnordLessThan
OpFOrdGreaterThan
OpFUnordGreaterThan
OpFOrdLessThanEqual
OpFUnordLessThanEqual
OpFOrdGreaterThanEqual
OpFUnordGreaterThanEqual
OpShiftRightLogical
OpShiftRightArithmetic
OpShiftLeftLogical
OpBitwiseOr
OpBitwiseXor
OpBitwiseAnd
OpNot
OpBitFieldInsert
OpBitFieldSExtract
OpBitFieldUExtract
OpBitReverse
OpBitCount
OpDPdx
OpDPdy
OpFwidth
OpDPdxFine
OpDPdyFine
OpFwidthFine
OpDPdxCoarse
OpDPdyCoarse
OpFwidthCoarse
OpEmitVertex
OpEndPrimitive
OpEmitStreamVertex
OpEndStreamPrimitive
OpControlBarrier
OpMemoryBarrier
OpAtomicLoad
OpAtomicStore
OpAtomicExchange
OpAtomicCompareExchange
OpAtomicCompareExchangeWeak
OpAtomicIIncrement
OpAtomicIDecrement
OpAtomicIAdd
OpAtomicISub
OpAtomicSMin
OpAtomicUMin
OpAtomicSMax
OpAtomicUMax
OpAtomicAnd
OpAtomicOr
OpAtomicXor
OpPhi
OpLoopMerge
OpSelectionMerge
OpLabel
OpBranch
OpBranchConditional
OpSwitch
OpKill
OpReturn
OpReturnValue
OpUnreachable
OpNoLine
OpAtomicFlagTestAndSet
OpAtomicFlagClear
OpImageSparseRead
OpSizeOf
OpTypePipeStoragevia Module::addType()
OpConstantPipeStoragevia Module::addConstant()
OpCreatePipeFromPipeStorage
OpGetKernelLocalSizeForSubgroupCount
OpGetKernelMaxNumSubgroups
OpTypeNamedBarriervia Module::addType()
OpNamedBarrierInitialize
OpModuleProcessed
OpExecutionModeId
OpDecorateId
OpPtrEqual
OpPtrNotEqual
......

GLSL.std.450

InstructionImplemented
Round
RoundEven
Trunc
FAbs
SAbs
FSign
SSign
Floor
Ceil
Fract
Radians
Degrees
Sin
Cos
Tan
Asin
Acos
Atan
Sinh
Cosh
Tanh
Asinh
Acosh
Atanh
Atan2
Pow
Exp
Log
Exp2
Log2
Sqrt
InverseSqrt
Determinant
MatrixInverse
ModfDeprecated
ModfStruct
FMin
UMin
SMin
FMax
UMax
SMax
FClamp
UClamp
SClamp
FMix
IMixRemoved in v0.99, Revision 3
Step
SmoothStep
Fma
FrexpDeprecated
FrexpStruct
Ldexp
PackSnorm4x8
PackUnorm4x8
PackSnorm2x16
PackUnorm2x16
PackHalf2x16
PackDouble2x32
UnpackSnorm2x16
UnpackUnorm2x16
UnpackHalf2x16
UnpackSnorm4x8
UnpackUnorm4x8
UnpackDouble2x32
Length
Distance
Cross
Normalize
FaceForward
Reflect
Refract
FindILsb
FindSMsb
FindUMsb
InterpolateAtCentroid
InterpolateAtSample
InterpolateAtOffset
NMin
NMax
NClamp

OpenCl.std.100

Not implemented yet