├── .clang-format ├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── LICENSE.txt ├── README.md ├── include └── sirit │ └── sirit.h ├── src ├── .gitignore ├── CMakeLists.txt ├── common_types.h ├── instructions │ ├── annotation.cpp │ ├── arithmetic.cpp │ ├── atomic.cpp │ ├── barrier.cpp │ ├── bit.cpp │ ├── constant.cpp │ ├── conversion.cpp │ ├── debug.cpp │ ├── derivatives.cpp │ ├── extension.cpp │ ├── flow.cpp │ ├── function.cpp │ ├── group.cpp │ ├── image.cpp │ ├── logical.cpp │ ├── memory.cpp │ ├── misc.cpp │ └── type.cpp ├── sirit.cpp ├── stream.cpp └── stream.h └── tests ├── CMakeLists.txt └── main.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: LLVM 4 | AccessModifierOffset: -4 5 | AlignAfterOpenBracket: Align 6 | AlignConsecutiveAssignments: false 7 | AlignConsecutiveDeclarations: false 8 | AlignEscapedNewlinesLeft: false 9 | AlignOperands: true 10 | AlignTrailingComments: true 11 | AllowAllParametersOfDeclarationOnNextLine: true 12 | AllowShortBlocksOnASingleLine: false 13 | AllowShortCaseLabelsOnASingleLine: false 14 | AllowShortFunctionsOnASingleLine: Empty 15 | AllowShortIfStatementsOnASingleLine: false 16 | AllowShortLoopsOnASingleLine: false 17 | AlwaysBreakAfterDefinitionReturnType: None 18 | AlwaysBreakAfterReturnType: None 19 | AlwaysBreakBeforeMultilineStrings: false 20 | AlwaysBreakTemplateDeclarations: true 21 | BinPackArguments: true 22 | BinPackParameters: true 23 | BraceWrapping: 24 | AfterClass: false 25 | AfterControlStatement: false 26 | AfterEnum: false 27 | AfterFunction: false 28 | AfterNamespace: false 29 | AfterObjCDeclaration: false 30 | AfterStruct: false 31 | AfterUnion: false 32 | BeforeCatch: false 33 | BeforeElse: false 34 | IndentBraces: false 35 | BreakBeforeBinaryOperators: None 36 | BreakBeforeBraces: Attach 37 | BreakBeforeTernaryOperators: true 38 | BreakConstructorInitializersBeforeComma: false 39 | ColumnLimit: 100 40 | CommentPragmas: '^ IWYU pragma:' 41 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 42 | ConstructorInitializerIndentWidth: 4 43 | ContinuationIndentWidth: 4 44 | Cpp11BracedListStyle: true 45 | DerivePointerAlignment: false 46 | DisableFormat: false 47 | ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] 48 | IncludeCategories: 49 | - Regex: '^\<[^Q][^/.>]*\>' 50 | Priority: -2 51 | - Regex: '^\<' 52 | Priority: -1 53 | - Regex: '^\"' 54 | Priority: 0 55 | IndentCaseLabels: false 56 | IndentWidth: 4 57 | IndentWrappedFunctionNames: false 58 | KeepEmptyLinesAtTheStartOfBlocks: true 59 | MacroBlockBegin: '' 60 | MacroBlockEnd: '' 61 | MaxEmptyLinesToKeep: 1 62 | NamespaceIndentation: None 63 | ObjCBlockIndentWidth: 2 64 | ObjCSpaceAfterProperty: false 65 | ObjCSpaceBeforeProtocolList: true 66 | PenaltyBreakBeforeFirstCallParameter: 19 67 | PenaltyBreakComment: 300 68 | PenaltyBreakFirstLessLess: 120 69 | PenaltyBreakString: 1000 70 | PenaltyExcessCharacter: 1000000 71 | PenaltyReturnTypeOnItsOwnLine: 150 72 | PointerAlignment: Left 73 | ReflowComments: true 74 | SortIncludes: true 75 | SpaceAfterCStyleCast: false 76 | SpaceBeforeAssignmentOperators: true 77 | SpaceBeforeParens: ControlStatements 78 | SpaceInEmptyParentheses: false 79 | SpacesBeforeTrailingComments: 1 80 | SpacesInAngles: false 81 | SpacesInContainerLiterals: true 82 | SpacesInCStyleCastParentheses: false 83 | SpacesInParentheses: false 84 | SpacesInSquareBrackets: false 85 | Standard: Cpp11 86 | TabWidth: 4 87 | UseTab: Never 88 | ... 89 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | *.o 3 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "externals/SPIRV-Headers"] 2 | path = externals/SPIRV-Headers 3 | url = https://github.com/KhronosGroup/SPIRV-Headers 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # This file has been adapted from dynarmic 2 | 3 | cmake_minimum_required(VERSION 3.8) 4 | project(sirit CXX) 5 | 6 | # Determine if we're built as a subproject (using add_subdirectory) 7 | # or if this is the master project. 8 | set(MASTER_PROJECT OFF) 9 | if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) 10 | set(MASTER_PROJECT ON) 11 | endif() 12 | 13 | # Sirit project options 14 | option(SIRIT_TESTS "Build tests" OFF) 15 | option(SIRIT_USE_SYSTEM_SPIRV_HEADERS "Use system SPIR-V headers" OFF) 16 | 17 | # Default to a Release build 18 | if (NOT CMAKE_BUILD_TYPE) 19 | set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE) 20 | message(STATUS "Defaulting to a Release build") 21 | endif() 22 | 23 | # Set hard requirements for C++ 24 | set(CMAKE_CXX_STANDARD 20) 25 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 26 | set(CMAKE_CXX_EXTENSIONS OFF) 27 | 28 | # Warn on CMake API deprecations 29 | set(CMAKE_WARN_DEPRECATED ON) 30 | 31 | # Disable in-source builds 32 | set(CMAKE_DISABLE_SOURCE_CHANGES ON) 33 | set(CMAKE_DISABLE_IN_SOURCE_BUILD ON) 34 | if ("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}") 35 | message(SEND_ERROR "In-source builds are not allowed.") 36 | endif() 37 | 38 | # Add the module directory to the list of paths 39 | list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/CMakeModules") 40 | 41 | # Compiler flags 42 | if (MSVC) 43 | set(SIRIT_CXX_FLAGS 44 | /std:c++latest # CMAKE_CXX_STANDARD as no effect on MSVC until CMake 3.10. 45 | /W4 46 | /w34263 # Non-virtual member function hides base class virtual function 47 | /w44265 # Class has virtual functions, but destructor is not virtual 48 | /w34456 # Declaration of 'var' hides previous local declaration 49 | /w34457 # Declaration of 'var' hides function parameter 50 | /w34458 # Declaration of 'var' hides class member 51 | /w34459 # Declaration of 'var' hides global definition 52 | /w34946 # Reinterpret-cast between related types 53 | /wd4592 # Symbol will be dynamically initialized (implementation limitation) 54 | /permissive- # Stricter C++ standards conformance 55 | /MP 56 | /Zi 57 | /Zo 58 | /EHsc 59 | /Zc:throwingNew # Assumes new never returns null 60 | /Zc:inline # Omits inline functions from object-file output 61 | /DNOMINMAX 62 | /WX) 63 | 64 | if (CMAKE_VS_PLATFORM_TOOLSET MATCHES "LLVM-vs[0-9]+") 65 | list(APPEND SIRIT_CXX_FLAGS 66 | -Qunused-arguments 67 | -Wno-missing-braces) 68 | endif() 69 | else() 70 | set(SIRIT_CXX_FLAGS 71 | -Wall 72 | -Wextra 73 | -Wcast-qual 74 | -pedantic 75 | -pedantic-errors 76 | -Wfatal-errors 77 | -Wno-missing-braces 78 | -Wconversion 79 | -Wsign-conversion 80 | -Wshadow 81 | -Werror) 82 | endif() 83 | 84 | # Enable unit-testing. 85 | enable_testing(true) 86 | 87 | # SPIR-V headers 88 | if (SIRIT_USE_SYSTEM_SPIRV_HEADERS) 89 | find_package(SPIRV-Headers REQUIRED) 90 | else() 91 | add_subdirectory(externals/SPIRV-Headers EXCLUDE_FROM_ALL) 92 | add_library(SPIRV-Headers::SPIRV-Headers ALIAS SPIRV-Headers) 93 | endif() 94 | 95 | # Sirit project files 96 | add_subdirectory(src) 97 | if (SIRIT_TESTS) 98 | add_subdirectory(tests) 99 | endif() 100 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019, sirit 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of the nor the 12 | names of its contributors may be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Sirit 2 | ===== 3 | A runtime SPIR-V assembler. It aims to ease dynamic SPIR-V code generation 4 | without calling external applications (like Khronos' `spirv-as`) 5 | 6 | Its design aims to move code that does not belong in the application to the 7 | library, without limiting its functionality. 8 | 9 | What Sirit does for you: 10 | * Sort declaration opcodes 11 | * Handle types and constant duplicates 12 | * Emit SPIR-V opcodes 13 | 14 | What Sirit won't do for you: 15 | * Avoid ID duplicates (e.g. emitting the same label twice) 16 | * Dump code to disk 17 | * Handle control flow 18 | * Compile from a higher level language 19 | 20 | 21 | It's in early stages of development, many instructions are missing since 22 | they are written manually instead of being generated from a file. 23 | 24 | Example 25 | ------- 26 | 27 | ```cpp 28 | class MyModule : public Sirit::Module { 29 | public: 30 | MyModule() {} 31 | ~MyModule() = default; 32 | 33 | void Generate() { 34 | AddCapability(spv::Capability::Shader); 35 | SetMemoryModel(spv::AddressingModel::Logical, spv::MemoryModel::GLSL450); 36 | 37 | auto main_type{TypeFunction(TypeVoid())}; 38 | auto main_func{OpFunction(TypeVoid(), spv::FunctionControlMask::MaskNone, main_type)}; 39 | AddLabel(OpLabel()); 40 | OpReturn(); 41 | OpFunctionEnd(); 42 | 43 | AddEntryPoint(spv::ExecutionModel::Vertex, main_func, "main"); 44 | } 45 | }; 46 | 47 | // Then... 48 | 49 | MyModule module; 50 | module.Generate(); 51 | 52 | std::vector code{module.Assemble()}; 53 | ``` 54 | -------------------------------------------------------------------------------- /include/sirit/sirit.h: -------------------------------------------------------------------------------- 1 | /* This file is part of the sirit project. 2 | * Copyright (c) 2019 sirit 3 | * This software may be used and distributed according to the terms of the 4 | * 3-Clause BSD License 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | 24 | namespace Sirit { 25 | 26 | constexpr std::uint32_t GENERATOR_MAGIC_NUMBER = 0; 27 | 28 | class Declarations; 29 | class Operand; 30 | class Stream; 31 | 32 | using Literal = 33 | std::variant; 34 | 35 | struct Id { 36 | std::uint32_t value; 37 | }; 38 | 39 | [[nodiscard]] inline bool ValidId(Id id) noexcept { 40 | return id.value != 0; 41 | } 42 | 43 | class Module { 44 | public: 45 | explicit Module(std::uint32_t version = spv::Version); 46 | ~Module(); 47 | 48 | /** 49 | * Assembles current module into a SPIR-V stream. 50 | * It can be called multiple times but it's recommended to copy code 51 | * externally. 52 | * @return A stream of bytes representing a SPIR-V module. 53 | */ 54 | std::vector Assemble() const; 55 | 56 | /// Patches deferred phi nodes calling the passed function on each phi argument 57 | void PatchDeferredPhi(const std::function& func); 58 | 59 | /// Adds a SPIR-V extension. 60 | void AddExtension(std::string extension_name); 61 | 62 | /// Adds a module capability. 63 | void AddCapability(spv::Capability capability); 64 | 65 | /// Sets module memory model. 66 | void SetMemoryModel(spv::AddressingModel addressing_model_, spv::MemoryModel memory_model_); 67 | 68 | /// Adds an entry point. 69 | void AddEntryPoint(spv::ExecutionModel execution_model, Id entry_point, std::string_view name, 70 | std::span interfaces = {}); 71 | 72 | /// Adds an entry point. 73 | // TODO: Change std::is_convertible_v to std::convertible_to when compilers 74 | // support it; same elsewhere. 75 | template 76 | requires(...&& std::is_convertible_v) void AddEntryPoint( 77 | spv::ExecutionModel execution_model, Id entry_point, std::string_view name, 78 | Ts&&... interfaces) { 79 | AddEntryPoint(execution_model, std::move(entry_point), name, 80 | std::span({interfaces...})); 81 | } 82 | 83 | /// Declare an execution mode for an entry point. 84 | void AddExecutionMode(Id entry_point, spv::ExecutionMode mode, 85 | std::span literals = {}); 86 | 87 | /// Declare an execution mode for an entry point. 88 | template 89 | requires(...&& std::is_convertible_v) void AddExecutionMode( 90 | Id entry_point, spv::ExecutionMode mode, Ts&&... literals) { 91 | AddExecutionMode(entry_point, mode, std::span({literals...})); 92 | } 93 | 94 | /** 95 | * Adds an existing label to the code 96 | * @param label Label to insert into code. 97 | * @return Returns label. 98 | */ 99 | Id AddLabel(Id label); 100 | 101 | /** 102 | * Adds a label to the code 103 | * @return Returns the created label. 104 | */ 105 | Id AddLabel() { 106 | return AddLabel(OpLabel()); 107 | } 108 | 109 | /// Adds a local variable to the code 110 | Id AddLocalVariable(Id result_type, spv::StorageClass storage_class, 111 | std::optional initializer = std::nullopt); 112 | 113 | /// Adds a global variable 114 | Id AddGlobalVariable(Id result_type, spv::StorageClass storage_class, 115 | std::optional initializer = std::nullopt); 116 | 117 | // Types 118 | 119 | /// Returns type void. 120 | Id TypeVoid(); 121 | 122 | /// Returns type bool. 123 | Id TypeBool(); 124 | 125 | /// Returns type integer. 126 | Id TypeInt(int width, bool is_signed); 127 | 128 | /// Returns type signed integer. 129 | Id TypeSInt(int width); 130 | 131 | /// Returns type unsigned integer. 132 | Id TypeUInt(int width); 133 | 134 | /// Returns type float. 135 | Id TypeFloat(int width); 136 | 137 | /// Returns type vector. 138 | Id TypeVector(Id component_type, int component_count); 139 | 140 | /// Returns type matrix. 141 | Id TypeMatrix(Id column_type, int column_count); 142 | 143 | /// Returns type image. 144 | Id TypeImage(Id sampled_type, spv::Dim dim, int depth, bool arrayed, bool ms, int sampled, 145 | spv::ImageFormat image_format, 146 | std::optional access_qualifier = std::nullopt); 147 | 148 | /// Returns type sampler. 149 | Id TypeSampler(); 150 | 151 | /// Returns type sampled image. 152 | Id TypeSampledImage(Id image_type); 153 | 154 | /// Returns type array. 155 | Id TypeArray(Id element_type, Id length); 156 | 157 | /// Returns type runtime array. 158 | Id TypeRuntimeArray(Id element_type); 159 | 160 | /// Returns type struct. 161 | Id TypeStruct(std::span members = {}); 162 | 163 | /// Returns type struct. 164 | template 165 | requires(...&& std::is_convertible_v) Id TypeStruct(Ts&&... members) { 166 | return TypeStruct(std::span({members...})); 167 | } 168 | 169 | /// Returns type opaque. 170 | Id TypeOpaque(std::string_view name); 171 | 172 | /// Returns type pointer. 173 | Id TypePointer(spv::StorageClass storage_class, Id type); 174 | 175 | /// Returns type function. 176 | Id TypeFunction(Id return_type, std::span arguments = {}); 177 | 178 | /// Returns type function. 179 | template 180 | requires(...&& std::is_convertible_v) Id 181 | TypeFunction(Id return_type, Ts&&... arguments) { 182 | return TypeFunction(return_type, std::span({arguments...})); 183 | } 184 | 185 | /// Returns type event. 186 | Id TypeEvent(); 187 | 188 | /// Returns type device event. 189 | Id TypeDeviceEvent(); 190 | 191 | /// Returns type reserve id. 192 | Id TypeReserveId(); 193 | 194 | /// Returns type queue. 195 | Id TypeQueue(); 196 | 197 | /// Returns type pipe. 198 | Id TypePipe(spv::AccessQualifier access_qualifier); 199 | 200 | // Constant 201 | 202 | /// Returns a true scalar constant. 203 | Id ConstantTrue(Id result_type); 204 | 205 | /// Returns a false scalar constant. 206 | Id ConstantFalse(Id result_type); 207 | 208 | /// Returns a numeric scalar constant. 209 | Id Constant(Id result_type, const Literal& literal); 210 | 211 | /// Returns a numeric scalar constant. 212 | Id ConstantComposite(Id result_type, std::span constituents); 213 | 214 | /// Returns a numeric scalar constant. 215 | template 216 | requires(...&& std::is_convertible_v) Id 217 | ConstantComposite(Id result_type, Ts&&... constituents) { 218 | return ConstantComposite(result_type, std::span({constituents...})); 219 | } 220 | 221 | /// Returns a sampler constant. 222 | Id ConstantSampler(Id result_type, spv::SamplerAddressingMode addressing_mode, bool normalized, 223 | spv::SamplerFilterMode filter_mode); 224 | 225 | /// Returns a null constant value. 226 | Id ConstantNull(Id result_type); 227 | 228 | // Function 229 | 230 | /// Declares a function. 231 | Id OpFunction(Id result_type, spv::FunctionControlMask function_control, Id function_type); 232 | 233 | /// Ends a function. 234 | void OpFunctionEnd(); 235 | 236 | /// Call a function. 237 | Id OpFunctionCall(Id result_type, Id function, std::span arguments = {}); 238 | 239 | /// Call a function. 240 | template 241 | requires(...&& std::is_convertible_v) Id 242 | OpFunctionCall(Id result_type, Id function, Ts&&... arguments) { 243 | return OpFunctionCall(result_type, function, std::span({arguments...})); 244 | } 245 | 246 | /// Declare a formal parameter of the current function. 247 | Id OpFunctionParameter(Id result_type); 248 | 249 | // Flow 250 | 251 | /** 252 | * The SSA phi function. 253 | * 254 | * @param result_type The result type. 255 | * @param operands An immutable span of variable, parent block pairs 256 | */ 257 | Id OpPhi(Id result_type, std::span operands); 258 | 259 | /** 260 | * The SSA phi function. This instruction will be revisited when patching phi nodes. 261 | * 262 | * @param result_type The result type. 263 | * @param blocks An immutable span of block pairs. 264 | */ 265 | Id DeferredOpPhi(Id result_type, std::span blocks); 266 | 267 | /// Declare a structured loop. 268 | Id OpLoopMerge(Id merge_block, Id continue_target, spv::LoopControlMask loop_control, 269 | std::span literals = {}); 270 | 271 | /// Declare a structured loop. 272 | template 273 | requires(...&& std::is_convertible_v) Id 274 | OpLoopMerge(Id merge_block, Id continue_target, spv::LoopControlMask loop_control, 275 | Ts&&... literals) { 276 | return OpLoopMerge(merge_block, continue_target, loop_control, 277 | std::span({literals...})); 278 | } 279 | 280 | /// Declare a structured selection. 281 | Id OpSelectionMerge(Id merge_block, spv::SelectionControlMask selection_control); 282 | 283 | /// The block label instruction: Any reference to a block is through this ref. 284 | Id OpLabel(); 285 | 286 | /// The block label instruction: Any reference to a block is through this ref. 287 | Id OpLabel(std::string_view label_name) { 288 | return Name(OpLabel(), label_name); 289 | } 290 | 291 | /// Unconditional jump to label. 292 | Id OpBranch(Id target_label); 293 | 294 | /// If condition is true branch to true_label, otherwise branch to 295 | /// false_label. 296 | Id OpBranchConditional(Id condition, Id true_label, Id false_label, 297 | std::uint32_t true_weight = 0, std::uint32_t false_weight = 0); 298 | 299 | /// Multi-way branch to one of the operand label. 300 | Id OpSwitch(Id selector, Id default_label, std::span literals, 301 | std::span labels); 302 | 303 | /// Returns with no value from a function with void return type. 304 | void OpReturn(); 305 | 306 | /// Behavior is undefined if this instruction is executed. 307 | void OpUnreachable(); 308 | 309 | /// Return a value from a function. 310 | Id OpReturnValue(Id value); 311 | 312 | /// Deprecated fragment-shader discard. 313 | void OpKill(); 314 | 315 | /// Demote fragment shader invocation to a helper invocation 316 | void OpDemoteToHelperInvocation(); 317 | void OpDemoteToHelperInvocationEXT(); 318 | 319 | /// Fragment-shader discard. 320 | void OpTerminateInvocation(); 321 | 322 | // Debug 323 | 324 | /// Assign a name string to a reference. 325 | /// @return target 326 | Id Name(Id target, std::string_view name); 327 | 328 | /// Assign a name string to a member of a structure type. 329 | /// @return type 330 | Id MemberName(Id type, std::uint32_t member, std::string_view name); 331 | 332 | /// Assign a Result to a string for use by other debug instructions. 333 | Id String(std::string_view string); 334 | 335 | /// Add source-level location information 336 | Id OpLine(Id file, Literal line, Literal column); 337 | 338 | // Memory 339 | 340 | /// Form a pointer to a texel of an image. Use of such a pointer is limited to atomic 341 | /// operations. 342 | Id OpImageTexelPointer(Id result_type, Id image, Id coordinate, Id sample); 343 | 344 | /// Load through a pointer. 345 | Id OpLoad(Id result_type, Id pointer, 346 | std::optional memory_access = std::nullopt); 347 | 348 | /// Store through a pointer. 349 | Id OpStore(Id pointer, Id object, 350 | std::optional memory_access = std::nullopt); 351 | 352 | /// Create a pointer into a composite object that can be used with OpLoad and OpStore. 353 | Id OpAccessChain(Id result_type, Id base, std::span indexes = {}); 354 | 355 | /// Create a pointer into a composite object that can be used with OpLoad and OpStore. 356 | template 357 | requires(...&& std::is_convertible_v) Id 358 | OpAccessChain(Id result_type, Id base, Ts&&... indexes) { 359 | return OpAccessChain(result_type, base, std::span({indexes...})); 360 | } 361 | 362 | /// Extract a single, dynamically selected, component of a vector. 363 | Id OpVectorExtractDynamic(Id result_type, Id vector, Id index); 364 | 365 | /// Make a copy of a vector, with a single, variably selected, component modified. 366 | Id OpVectorInsertDynamic(Id result_type, Id vector, Id component, Id index); 367 | 368 | /// Make a copy of a composite object, while modifying one part of it. 369 | Id OpCompositeInsert(Id result_type, Id object, Id composite, 370 | std::span indexes = {}); 371 | 372 | /// Make a copy of a composite object, while modifying one part of it. 373 | template 374 | requires(...&& std::is_convertible_v) Id 375 | OpCompositeInsert(Id result_type, Id object, Id composite, Ts&&... indexes) { 376 | const Literal stack_indexes[] = {std::forward(indexes)...}; 377 | return OpCompositeInsert(result_type, object, composite, 378 | std::span{stack_indexes}); 379 | } 380 | 381 | /// Extract a part of a composite object. 382 | Id OpCompositeExtract(Id result_type, Id composite, std::span indexes = {}); 383 | 384 | /// Extract a part of a composite object. 385 | template 386 | requires(...&& std::is_convertible_v) Id 387 | OpCompositeExtract(Id result_type, Id composite, Ts&&... indexes) { 388 | const Literal stack_indexes[] = {std::forward(indexes)...}; 389 | return OpCompositeExtract(result_type, composite, std::span{stack_indexes}); 390 | } 391 | 392 | /// Construct a new composite object from a set of constituent objects that will fully form it. 393 | Id OpCompositeConstruct(Id result_type, std::span ids); 394 | 395 | /// Construct a new composite object from a set of constituent objects that will fully form it. 396 | template 397 | requires(...&& std::is_convertible_v) Id 398 | OpCompositeConstruct(Id result_type, Ts&&... ids) { 399 | return OpCompositeConstruct(result_type, std::span({ids...})); 400 | } 401 | 402 | // Annotation 403 | 404 | /// Add a decoration to target. 405 | Id Decorate(Id target, spv::Decoration decoration, std::span literals = {}); 406 | 407 | /// Add a decoration to target. 408 | template 409 | requires(...&& std::is_convertible_v) Id 410 | Decorate(Id target, spv::Decoration decoration, Ts&&... literals) { 411 | const Literal stack_literals[] = {std::forward(literals)...}; 412 | return Decorate(target, decoration, std::span{stack_literals}); 413 | } 414 | 415 | /// Add a decoration to target. 416 | template 417 | requires std::is_enum_v Id Decorate(Id target, spv::Decoration decoration, T literal) { 418 | return Decorate(target, decoration, static_cast(literal)); 419 | } 420 | 421 | Id MemberDecorate(Id structure_type, Literal member, spv::Decoration decoration, 422 | std::span literals = {}); 423 | 424 | template 425 | requires(...&& std::is_convertible_v) Id 426 | MemberDecorate(Id structure_type, Literal member, spv::Decoration decoration, 427 | Ts&&... literals) { 428 | const Literal stack_literals[] = {std::forward(literals)...}; 429 | return MemberDecorate(structure_type, member, decoration, 430 | std::span{stack_literals}); 431 | } 432 | 433 | // Misc 434 | 435 | /// Make an intermediate object whose value is undefined. 436 | Id OpUndef(Id result_type); 437 | 438 | /// Emits the current values of all output variables to the current output primitive. 439 | void OpEmitVertex(); 440 | 441 | /// Finish the current primitive and start a new one. No vertex is emitted. 442 | void OpEndPrimitive(); 443 | 444 | /// Emits the current values of all output variables to the current output primitive. After 445 | /// execution, the values of all output variables are undefined. 446 | void OpEmitStreamVertex(Id stream); 447 | 448 | /// Finish the current primitive and start a new one. No vertex is emitted. 449 | void OpEndStreamPrimitive(Id stream); 450 | 451 | // Barrier 452 | 453 | /// Wait for other invocations of this module to reach the current point of execution. 454 | Id OpControlBarrier(Id execution, Id memory, Id semantics); 455 | 456 | /// Control the order that memory accesses are observed. 457 | Id OpMemoryBarrier(Id scope, Id semantics); 458 | 459 | // Logical 460 | 461 | /// Result is true if any component of Vector is true, otherwise result is false. 462 | Id OpAny(Id result_type, Id vector); 463 | 464 | /// Result is true if all components of Vector are true, otherwise result is false. 465 | Id OpAll(Id result_type, Id vector); 466 | 467 | /// Result is true if x is an IEEE NaN, otherwise result is false. 468 | Id OpIsNan(Id result_type, Id operand); 469 | 470 | /// Result is true if x is an IEEE Inf, otherwise result is false. 471 | Id OpIsInf(Id result_type, Id operand); 472 | 473 | /// Result is true if Operand 1 and Operand 2 have the same value. Result is false if Operand 1 474 | /// and Operand 2 have different values. 475 | Id OpLogicalEqual(Id result_type, Id operand_1, Id operand_2); 476 | 477 | /// Result is true if Operand 1 and Operand 2 have different values. Result is false if Operand 478 | /// 1 and Operand 2 have the same value. 479 | Id OpLogicalNotEqual(Id result_type, Id operand_1, Id operand_2); 480 | 481 | /// Result is true if either Operand 1 or Operand 2 is true. Result is false if both Operand 1 482 | /// and Operand 2 are false. 483 | Id OpLogicalOr(Id result_type, Id operand_1, Id operand_2); 484 | 485 | /// Result is true if both Operand 1 and Operand 2 are true. Result is false if either Operand 1 486 | /// or Operand 2 are false. 487 | Id OpLogicalAnd(Id result_type, Id operand_1, Id operand_2); 488 | 489 | /// Result is true if Operand is false. Result is false if Operand is true. 490 | Id OpLogicalNot(Id result_type, Id operand); 491 | 492 | /// Select components from two objects. 493 | Id OpSelect(Id result_type, Id condition, Id operand_1, Id operand_2); 494 | 495 | /// Integer comparison for equality. 496 | Id OpIEqual(Id result_type, Id operand_1, Id operand_2); 497 | 498 | /// Integer comparison for inequality. 499 | Id OpINotEqual(Id result_type, Id operand_1, Id operand_2); 500 | 501 | /// Unsigned-integer comparison if Operand 1 is greater than Operand 2. 502 | Id OpUGreaterThan(Id result_type, Id operand_1, Id operand_2); 503 | 504 | /// Signed-integer comparison if Operand 1 is greater than Operand 2. 505 | Id OpSGreaterThan(Id result_type, Id operand_1, Id operand_2); 506 | 507 | /// Unsigned-integer comparison if Operand 1 is greater than or equal to Operand 2. 508 | Id OpUGreaterThanEqual(Id result_type, Id operand_1, Id operand_2); 509 | 510 | /// Signed-integer comparison if Operand 1 is greater than or equal to Operand 2. 511 | Id OpSGreaterThanEqual(Id result_type, Id operand_1, Id operand_2); 512 | 513 | /// Unsigned-integer comparison if Operand 1 is less than Operand 2. 514 | Id OpULessThan(Id result_type, Id operand_1, Id operand_2); 515 | 516 | /// Signed-integer comparison if Operand 1 is less than Operand 2. 517 | Id OpSLessThan(Id result_type, Id operand_1, Id operand_2); 518 | 519 | /// Unsigned-integer comparison if Operand 1 is less than or equal to Operand 2. 520 | Id OpULessThanEqual(Id result_type, Id operand_1, Id operand_2); 521 | 522 | /// Signed-integer comparison if Operand 1 is less than or equal to Operand 2. 523 | Id OpSLessThanEqual(Id result_type, Id operand_1, Id operand_2); 524 | 525 | /// Floating-point comparison for being ordered and equal. 526 | Id OpFOrdEqual(Id result_type, Id operand_1, Id operand_2); 527 | 528 | /// Floating-point comparison for being unordered or equal. 529 | Id OpFUnordEqual(Id result_type, Id operand_1, Id operand_2); 530 | 531 | /// Floating-point comparison for being ordered and not equal. 532 | Id OpFOrdNotEqual(Id result_type, Id operand_1, Id operand_2); 533 | 534 | /// Floating-point comparison for being unordered or not equal. 535 | Id OpFUnordNotEqual(Id result_type, Id operand_1, Id operand_2); 536 | 537 | /// Floating-point comparison if operands are ordered and Operand 1 is less than Operand 2. 538 | Id OpFOrdLessThan(Id result_type, Id operand_1, Id operand_2); 539 | 540 | /// Floating-point comparison if operands are unordered or Operand 1 is less than Operand 2. 541 | Id OpFUnordLessThan(Id result_type, Id operand_1, Id operand_2); 542 | 543 | /// Floating-point comparison if operands are ordered and Operand 1 is greater than Operand 2. 544 | Id OpFOrdGreaterThan(Id result_type, Id operand_1, Id operand_2); 545 | 546 | /// Floating-point comparison if operands are unordered or Operand 1 is greater than Operand 2. 547 | Id OpFUnordGreaterThan(Id result_type, Id operand_1, Id operand_2); 548 | 549 | /// Floating-point comparison if operands are ordered and Operand 1 is less than or equal to 550 | /// Operand 2. 551 | Id OpFOrdLessThanEqual(Id result_type, Id operand_1, Id operand_2); 552 | 553 | /// Floating-point comparison if operands are unordered or Operand 1 is less than or equal to 554 | /// Operand 2. 555 | Id OpFUnordLessThanEqual(Id result_type, Id operand_1, Id operand_2); 556 | 557 | /// Floating-point comparison if operands are ordered and Operand 1 is greater than or equal to 558 | /// Operand 2. 559 | Id OpFOrdGreaterThanEqual(Id result_type, Id operand_1, Id operand_2); 560 | 561 | /// Floating-point comparison if operands are unordered or Operand 1 is greater than or equal to 562 | /// Operand 2. 563 | Id OpFUnordGreaterThanEqual(Id result_type, Id operand_1, Id operand_2); 564 | 565 | // Conversion 566 | 567 | /// Convert (value preserving) from floating point to unsigned integer, with round toward 0.0. 568 | Id OpConvertFToU(Id result_type, Id operand); 569 | 570 | /// Convert (value preserving) from floating point to signed integer, with round toward 0.0. 571 | Id OpConvertFToS(Id result_type, Id operand); 572 | 573 | /// Convert (value preserving) from signed integer to floating point. 574 | Id OpConvertSToF(Id result_type, Id operand); 575 | 576 | /// Convert (value preserving) from unsigned integer to floating point. 577 | Id OpConvertUToF(Id result_type, Id operand); 578 | 579 | /// Convert (value preserving) unsigned width. This is either a truncate or a zero extend. 580 | Id OpUConvert(Id result_type, Id operand); 581 | 582 | /// Convert (value preserving) signed width. This is either a truncate or a sign extend. 583 | Id OpSConvert(Id result_type, Id operand); 584 | 585 | /// Convert (value preserving) floating-point width. 586 | Id OpFConvert(Id result_type, Id operand); 587 | 588 | /// Quantize a floating-point value to what is expressible by a 16-bit floating-point value. 589 | Id OpQuantizeToF16(Id result_type, Id operand); 590 | 591 | /// Bit pattern-preserving type conversion. 592 | Id OpBitcast(Id result_type, Id operand); 593 | 594 | // Bit 595 | 596 | /// Shift the bits in Base right by the number of bits specified in Shift. 597 | /// The most-significant bits will be zero filled. 598 | Id OpShiftRightLogical(Id result_type, Id base, Id shift); 599 | 600 | /// Shift the bits in Base right by the number of bits specified in Shift. 601 | /// The most-significant bits will be filled with the sign bit from Base. 602 | Id OpShiftRightArithmetic(Id result_type, Id base, Id shift); 603 | 604 | /// Shift the bits in Base left by the number of bits specified in Shift. 605 | /// The least-significant bits will be zero filled. 606 | Id OpShiftLeftLogical(Id result_type, Id base, Id shift); 607 | 608 | /// Does a bitwise Or between operands 1 and 2. 609 | Id OpBitwiseOr(Id result_type, Id operand_1, Id operand_2); 610 | 611 | /// Does a bitwise Xor between operands 1 and 2. 612 | Id OpBitwiseXor(Id result_type, Id operand_1, Id operand_2); 613 | 614 | /// Result is 1 if both Operand 1 and Operand 2 are 1. Result is 0 if either 615 | /// Operand 1 or Operand 2 are 0. 616 | Id OpBitwiseAnd(Id result_type, Id operand_1, Id operand_2); 617 | 618 | /// Does a bitwise Not on the operand. 619 | Id OpNot(Id result_type, Id operand); 620 | 621 | /// Make a copy of an object, with a modified bit field that comes from another object. 622 | Id OpBitFieldInsert(Id result_type, Id base, Id insert, Id offset, Id count); 623 | 624 | /// Extract a bit field from an object, with sign extension. 625 | Id OpBitFieldSExtract(Id result_type, Id base, Id offset, Id count); 626 | 627 | /// Extract a bit field from an object, without sign extension. 628 | Id OpBitFieldUExtract(Id result_type, Id base, Id offset, Id count); 629 | 630 | /// Reverse the bits in an object. 631 | Id OpBitReverse(Id result_type, Id base); 632 | 633 | /// Count the number of set bits in an object. 634 | Id OpBitCount(Id result_type, Id base); 635 | 636 | // Arithmetic 637 | 638 | /// Floating-point subtract of Operand from zero. 639 | Id OpSNegate(Id result_type, Id operand); 640 | 641 | /// Floating-point subtract of Operand from zero. 642 | Id OpFNegate(Id result_type, Id operand); 643 | 644 | /// Integer addition of Operand 1 and Operand 2. 645 | Id OpIAdd(Id result_type, Id operand_1, Id operand_2); 646 | 647 | /// Floating-point addition of Operand 1 and Operand 2. 648 | Id OpFAdd(Id result_type, Id operand_1, Id operand_2); 649 | 650 | /// Integer substraction of Operand 1 and Operand 2. 651 | Id OpISub(Id result_type, Id operand_1, Id operand_2); 652 | 653 | /// Floating-point subtraction of Operand 1 and Operand 2. 654 | Id OpFSub(Id result_type, Id operand_1, Id operand_2); 655 | 656 | /// Integer multiplication of Operand 1 and Operand 2. 657 | Id OpIMul(Id result_type, Id operand_1, Id operand_2); 658 | 659 | /// Floating-point multiplication of Operand 1 and Operand 2. 660 | Id OpFMul(Id result_type, Id operand_1, Id operand_2); 661 | 662 | /// Unsigned-integer division of Operand 1 divided by Operand 2. 663 | Id OpUDiv(Id result_type, Id operand_1, Id operand_2); 664 | 665 | /// signed-integer division of Operand 1 divided by Operand 2. 666 | Id OpSDiv(Id result_type, Id operand_1, Id operand_2); 667 | 668 | /// Floating-point division of Operand 1 divided by Operand 2. 669 | Id OpFDiv(Id result_type, Id operand_1, Id operand_2); 670 | 671 | /// Unsigned modulo operation of Operand 1 modulo Operand 2. 672 | Id OpUMod(Id result_type, Id operand_1, Id operand_2); 673 | 674 | /// Signed modulo operation of Operand 1 modulo Operand 2. 675 | Id OpSMod(Id result_type, Id operand_1, Id operand_2); 676 | 677 | /// Floating-point modulo operation of Operand 1 modulo Operand 2. 678 | Id OpFMod(Id result_type, Id operand_1, Id operand_2); 679 | 680 | /// Signed reminder operation of Operand 1 modulo Operand 2. 681 | Id OpSRem(Id result_type, Id operand_1, Id operand_2); 682 | 683 | /// Floating-point reminder operation of Operand 1 modulo Operand 2. 684 | Id OpFRem(Id result_type, Id operand_1, Id operand_2); 685 | 686 | /// Result is the unsigned integer addition of Operand 1 and Operand 2, including its carry. 687 | Id OpIAddCarry(Id result_type, Id operand_1, Id operand_2); 688 | 689 | // Extensions 690 | 691 | /// Execute an instruction in an imported set of extended instructions. 692 | Id OpExtInst(Id result_type, Id set, std::uint32_t instruction, std::span operands); 693 | 694 | /// Execute an instruction in an imported set of extended instructions. 695 | template 696 | requires(...&& std::is_convertible_v) Id 697 | OpExtInst(Id result_type, Id set, std::uint32_t instruction, Ts&&... operands) { 698 | return OpExtInst(result_type, set, instruction, std::span({operands...})); 699 | } 700 | 701 | /// Result is x if x >= 0; otherwise result is -x. 702 | Id OpFAbs(Id result_type, Id x); 703 | 704 | /// Result is x if x >= 0; otherwise result is -x. 705 | Id OpSAbs(Id result_type, Id x); 706 | 707 | /// Result is the value equal to the nearest whole number to x. The fraction 0.5 will round in a 708 | /// direction chosen by the implementation, presumably the direction that is fastest. 709 | Id OpRound(Id result_type, Id x); 710 | 711 | /// Result is the value equal to the nearest whole number to x. A fractional part of 0.5 will 712 | /// round toward the nearest even whole number. 713 | Id OpRoundEven(Id result_type, Id x); 714 | 715 | /// Result is the value equal to the nearest whole number to x whose absolute value is not 716 | /// larger than the absolute value of x. 717 | Id OpTrunc(Id result_type, Id x); 718 | 719 | /// Result is 1.0 if x > 0, 0.0 if x = 0, or -1.0 if x < 0. 720 | Id OpFSign(Id result_type, Id x); 721 | 722 | /// Result is 1 if x > 0, 0 if x = 0, or -1 if x < 0, where x is interpreted as a signed 723 | /// integer. 724 | Id OpSSign(Id result_type, Id x); 725 | 726 | /// Result is the value equal to the nearest whole number that is less than or equal to x. 727 | Id OpFloor(Id result_type, Id x); 728 | 729 | /// Result is the value equal to the nearest whole number that is greater than or equal to x. 730 | Id OpCeil(Id result_type, Id x); 731 | 732 | /// Result is x - floor x. 733 | Id OpFract(Id result_type, Id x); 734 | 735 | /// The standard trigonometric sine of x radians. 736 | Id OpSin(Id result_type, Id x); 737 | 738 | /// The standard trigonometric cosine of x radians. 739 | Id OpCos(Id result_type, Id x); 740 | 741 | /// Arc sine. Result is an angle, in radians, whose sine is x. The range of result values is 742 | /// [-pi / 2, pi / 2]. Result is undefined if abs x > 1. 743 | Id OpAsin(Id result_type, Id x); 744 | 745 | /// Arc cosine. Result is an angle, in radians, whose cosine is x. The range of result values is 746 | /// [0, pi]. Result is undefined if abs x > 1. 747 | Id OpAcos(Id result_type, Id x); 748 | 749 | /// Result is x raised to the y power. Result is undefined if x < 0. Result is undefined if x = 750 | /// 0 and y <= 0. 751 | Id OpPow(Id result_type, Id x, Id y); 752 | 753 | /// Result is the natural exponentiation of x. 754 | Id OpExp(Id result_type, Id x); 755 | 756 | /// Result is the natural logarithm of x. Result is undefined if x <= 0. 757 | Id OpLog(Id result_type, Id x); 758 | 759 | /// Result is 2 raised to the x power. 760 | Id OpExp2(Id result_type, Id x); 761 | 762 | /// Result is the base-2 logarithm of x. Result is undefined if x <= 0. 763 | Id OpLog2(Id result_type, Id x); 764 | 765 | /// Result is the square root of x. Result is undefined if x < 0. 766 | Id OpSqrt(Id result_type, Id x); 767 | 768 | /// Result is the reciprocal of sqrt x. Result is undefined if x <= 0. 769 | Id OpInverseSqrt(Id result_type, Id x); 770 | 771 | /// Result is y if y < x; otherwise result is x. Which operand is the result is undefined if one 772 | /// of the operands is a NaN. 773 | Id OpFMin(Id result_type, Id x, Id y); 774 | 775 | /// Result is y if y < x; otherwise result is x, where x and y are interpreted as unsigned 776 | /// integers. 777 | Id OpUMin(Id result_type, Id x, Id y); 778 | 779 | /// Result is y if y < x; otherwise result is x, where x and y are interpreted as signed 780 | /// integers. 781 | Id OpSMin(Id result_type, Id x, Id y); 782 | 783 | /// Result is y if x < y; otherwise result is x. Which operand is the result is undefined if one 784 | /// of the operands is a NaN. 785 | Id OpFMax(Id result_type, Id x, Id y); 786 | 787 | /// Result is y if x < y; otherwise result is x, where x and y are interpreted as unsigned 788 | /// integers. 789 | Id OpUMax(Id result_type, Id x, Id y); 790 | 791 | /// Result is y if x < y; otherwise result is x, where x and y are interpreted as signed 792 | /// integers. 793 | Id OpSMax(Id result_type, Id x, Id y); 794 | 795 | /// Result is min(max(x, minVal), maxVal). Result is undefined if minVal > maxVal.The semantics 796 | /// used by min() and max() are those of FMin and FMax. 797 | Id OpFClamp(Id result_type, Id x, Id min_val, Id max_val); 798 | 799 | /// Result is min(max(x, minVal), maxVal), where x, minVal and maxVal are interpreted as 800 | /// unsigned integers. Result is undefined if minVal > maxVal. 801 | Id OpUClamp(Id result_type, Id x, Id min_val, Id max_val); 802 | 803 | /// Result is min(max(x, minVal), maxVal), where x, minVal and maxVal are interpreted as signed 804 | /// integers. Result is undefined if minVal > maxVal. 805 | Id OpSClamp(Id result_type, Id x, Id min_val, Id max_val); 806 | 807 | /// Computes a * b + c. 808 | Id OpFma(Id result_type, Id a, Id b, Id c); 809 | 810 | /// Result is the unsigned integer obtained by converting the components of a two-component 811 | /// floating-point vector to the 16-bit OpTypeFloat, and then packing these two 16-bit integers 812 | /// into a 32-bit unsigned integer. 813 | Id OpPackHalf2x16(Id result_type, Id v); 814 | 815 | /// Result is the two-component floating-point vector with components obtained by unpacking a 816 | /// 32-bit unsigned integer into a pair of 16-bit values. 817 | Id OpUnpackHalf2x16(Id result_type, Id v); 818 | 819 | /// Integer least-significant bit. 820 | Id OpFindILsb(Id result_type, Id value); 821 | 822 | /// Signed-integer most-significant bit, with value interpreted as a signed integer. 823 | Id OpFindSMsb(Id result_type, Id value); 824 | 825 | /// Unsigned-integer most-significant bit. 826 | Id OpFindUMsb(Id result_type, Id value); 827 | 828 | /// Result is the value of the input interpolant sampled at a location inside both the pixel and 829 | /// the primitive being processed. 830 | Id OpInterpolateAtCentroid(Id result_type, Id interpolant); 831 | 832 | /// Result is the value of the input interpolant variable at the location of sample number 833 | /// sample. 834 | Id OpInterpolateAtSample(Id result_type, Id interpolant, Id sample); 835 | 836 | /// Result is the value of the input interpolant variable sampled at an offset from the center 837 | /// of the pixel specified by offset. 838 | Id OpInterpolateAtOffset(Id result_type, Id interpolant, Id offset); 839 | 840 | // Derivatives 841 | 842 | /// Same result as either OpDPdxFine or OpDPdxCoarse on the input. 843 | /// Selection of which one is based on external factors. 844 | Id OpDPdx(Id result_type, Id operand); 845 | 846 | /// Same result as either OpDPdyFine or OpDPdyCoarse on the input. 847 | /// Selection of which one is based on external factors. 848 | Id OpDPdy(Id result_type, Id operand); 849 | 850 | /// Result is the same as computing the sum of the absolute values of OpDPdx and OpDPdy 851 | /// on the input. 852 | Id OpFwidth(Id result_type, Id operand); 853 | 854 | /// Result is the partial derivative of the input with respect to the window x coordinate. 855 | /// Uses local differencing based on the value of the input for the current fragment and 856 | /// its immediate neighbor(s). 857 | Id OpDPdxFine(Id result_type, Id operand); 858 | 859 | /// Result is the partial derivative of the input with respect to the window y coordinate. 860 | /// Uses local differencing based on the value of the input for the current fragment and 861 | /// its immediate neighbor(s). 862 | Id OpDPdyFine(Id result_type, Id operand); 863 | 864 | /// Result is the same as computing the sum of the absolute values of OpDPdxFine and OpDPdyFine 865 | /// on the input. 866 | Id OpFwidthFine(Id result_type, Id operand); 867 | 868 | /// Result is the partial derivative of the input with respect to the window x coordinate. 869 | /// Uses local differencing based on the value of the input for the current fragment's 870 | /// neighbors, and possibly, but not necessarily, includes the value of the input for the 871 | /// current fragment. That is, over a given area, the implementation can compute x derivatives 872 | /// in fewer unique locations than would be allowed for OpDPdxFine. 873 | Id OpDPdxCoarse(Id result_type, Id operand); 874 | 875 | /// Result is the partial derivative of the input with respect to the window y coordinate. 876 | /// Uses local differencing based on the value of the input for the current fragment's 877 | /// neighbors, and possibly, but not necessarily, includes the value of the input for the 878 | /// current fragment. That is, over a given area, the implementation can compute y derivatives 879 | /// in fewer unique locations than would be allowed for OpDPdyFine. 880 | Id OpDPdyCoarse(Id result_type, Id operand); 881 | 882 | /// Result is the same as computing the sum of the absolute values of OpDPdxCoarse and 883 | /// OpDPdyCoarse on the input. 884 | Id OpFwidthCoarse(Id result_type, Id operand); 885 | 886 | // Image 887 | 888 | /// Create a sampled image, containing both a sampler and an image. 889 | Id OpSampledImage(Id result_type, Id image, Id sampler); 890 | 891 | /// Sample an image with an implicit level of detail. 892 | Id OpImageSampleImplicitLod(Id result_type, Id sampled_image, Id coordinate, 893 | std::optional image_operands = std::nullopt, 894 | std::span operands = {}); 895 | 896 | /// Sample an image with an implicit level of detail. 897 | template 898 | requires(...&& std::is_convertible_v) Id 899 | OpImageSampleImplicitLod(Id result_type, Id sampled_image, Id coordinate, 900 | spv::ImageOperandsMask image_operands, Ts&&... operands) { 901 | return OpImageSampleImplicitLod(result_type, sampled_image, coordinate, image_operands, 902 | std::span({operands...})); 903 | } 904 | 905 | /// Sample an image using an explicit level of detail. 906 | Id OpImageSampleExplicitLod(Id result_type, Id sampled_image, Id coordinate, 907 | spv::ImageOperandsMask image_operands, 908 | std::span operands = {}); 909 | 910 | /// Sample an image using an explicit level of detail. 911 | template 912 | requires(...&& std::is_convertible_v) Id 913 | OpImageSampleExplicitLod(Id result_type, Id sampled_image, Id coordinate, 914 | spv::ImageOperandsMask image_operands, Ts&&... operands) { 915 | return OpImageSampleExplicitLod(result_type, sampled_image, coordinate, image_operands, 916 | std::span({operands...})); 917 | } 918 | 919 | /// Sample an image doing depth-comparison with an implicit level of detail. 920 | Id OpImageSampleDrefImplicitLod( 921 | Id result_type, Id sampled_image, Id coordinate, Id dref, 922 | std::optional image_operands = std::nullopt, 923 | std::span operands = {}); 924 | 925 | /// Sample an image doing depth-comparison with an implicit level of detail. 926 | template 927 | requires(...&& std::is_convertible_v) Id 928 | OpImageSampleDrefImplicitLod(Id result_type, Id sampled_image, Id coordinate, Id dref, 929 | spv::ImageOperandsMask image_operands, Ts&&... operands) { 930 | return OpImageSampleDrefImplicitLod(result_type, sampled_image, coordinate, dref, 931 | image_operands, std::span({operands...})); 932 | } 933 | 934 | /// Sample an image doing depth-comparison using an explicit level of detail. 935 | Id OpImageSampleDrefExplicitLod(Id result_type, Id sampled_image, Id coordinate, Id dref, 936 | spv::ImageOperandsMask image_operands, 937 | std::span operands = {}); 938 | 939 | /// Sample an image doing depth-comparison using an explicit level of detail. 940 | template 941 | requires(...&& std::is_convertible_v) Id 942 | OpImageSampleDrefExplicitLod(Id result_type, Id sampled_image, Id coordinate, Id dref, 943 | spv::ImageOperandsMask image_operands, Ts&&... operands) { 944 | return OpImageSampleDrefExplicitLod(result_type, sampled_image, coordinate, dref, 945 | image_operands, std::span({operands...})); 946 | } 947 | 948 | /// Sample an image with with a project coordinate and an implicit level of detail. 949 | Id OpImageSampleProjImplicitLod( 950 | Id result_type, Id sampled_image, Id coordinate, 951 | std::optional image_operands = std::nullopt, 952 | std::span operands = {}); 953 | 954 | /// Sample an image with with a project coordinate and an implicit level of detail. 955 | template 956 | requires(...&& std::is_convertible_v) Id 957 | OpImageSampleProjImplicitLod(Id result_type, Id sampled_image, Id coordinate, 958 | spv::ImageOperandsMask image_operands, Ts&&... operands) { 959 | return OpImageSampleProjImplicitLod(result_type, sampled_image, coordinate, image_operands, 960 | std::span({operands...})); 961 | } 962 | 963 | /// Sample an image with a project coordinate using an explicit level of detail. 964 | Id OpImageSampleProjExplicitLod(Id result_type, Id sampled_image, Id coordinate, 965 | spv::ImageOperandsMask image_operands, 966 | std::span operands = {}); 967 | 968 | /// Sample an image with a project coordinate using an explicit level of detail. 969 | template 970 | requires(...&& std::is_convertible_v) Id 971 | OpImageSampleProjExplicitLod(Id result_type, Id sampled_image, Id coordinate, 972 | spv::ImageOperandsMask image_operands, Ts&&... operands) { 973 | return OpImageSampleProjExplicitLod(result_type, sampled_image, coordinate, image_operands, 974 | std::span({operands...})); 975 | } 976 | 977 | /// Sample an image with a project coordinate, doing depth-comparison, with an implicit level of 978 | /// detail. 979 | Id OpImageSampleProjDrefImplicitLod( 980 | Id result_type, Id sampled_image, Id coordinate, Id dref, 981 | std::optional image_operands = std::nullopt, 982 | std::span operands = {}); 983 | 984 | /// Sample an image with a project coordinate, doing depth-comparison, with an implicit level of 985 | /// detail. 986 | template 987 | requires(...&& std::is_convertible_v) Id 988 | OpImageSampleProjDrefImplicitLod(Id result_type, Id sampled_image, Id coordinate, Id dref, 989 | spv::ImageOperandsMask image_operands, Ts&&... operands) { 990 | return OpImageSampleProjDrefImplicitLod(result_type, sampled_image, coordinate, dref, 991 | image_operands, std::span({operands...})); 992 | } 993 | 994 | /// Sample an image with a project coordinate, doing depth-comparison, using an explicit level 995 | /// of detail. 996 | Id OpImageSampleProjDrefExplicitLod(Id result_type, Id sampled_image, Id coordinate, Id dref, 997 | spv::ImageOperandsMask image_operands, 998 | std::span operands = {}); 999 | 1000 | /// Sample an image with a project coordinate, doing depth-comparison, using an explicit level 1001 | /// of detail. 1002 | template 1003 | requires(...&& std::is_convertible_v) Id 1004 | OpImageSampleProjDrefExplicitLod(Id result_type, Id sampled_image, Id coordinate, Id dref, 1005 | spv::ImageOperandsMask image_operands, Ts&&... operands) { 1006 | return OpImageSampleProjDrefExplicitLod(result_type, sampled_image, coordinate, dref, 1007 | image_operands, std::span({operands...})); 1008 | } 1009 | 1010 | /// Fetch a single texel from an image whose Sampled operand is 1. 1011 | Id OpImageFetch(Id result_type, Id sampled_image, Id coordinate, 1012 | std::optional image_operands = std::nullopt, 1013 | std::span operands = {}); 1014 | 1015 | /// Fetch a single texel from an image whose Sampled operand is 1. 1016 | template 1017 | requires(...&& std::is_convertible_v) Id 1018 | OpImageFetch(Id result_type, Id sampled_image, Id coordinate, 1019 | spv::ImageOperandsMask image_operands, Ts&&... operands) { 1020 | return OpImageFetch(result_type, sampled_image, coordinate, image_operands, 1021 | std::span({operands...})); 1022 | } 1023 | 1024 | /// Gathers the requested component from four texels. 1025 | Id OpImageGather(Id result_type, Id sampled_image, Id coordinate, Id component, 1026 | std::optional image_operands = std::nullopt, 1027 | std::span operands = {}); 1028 | 1029 | /// Gathers the requested component from four texels. 1030 | template 1031 | requires(...&& std::is_convertible_v) Id 1032 | OpImageGather(Id result_type, Id sampled_image, Id coordinate, Id component, 1033 | spv::ImageOperandsMask image_operands, Ts&&... operands) { 1034 | return OpImageGather(result_type, sampled_image, coordinate, component, image_operands, 1035 | std::span({operands...})); 1036 | } 1037 | 1038 | /// Gathers the requested depth-comparison from four texels. 1039 | Id OpImageDrefGather(Id result_type, Id sampled_image, Id coordinate, Id dref, 1040 | std::optional image_operands = std::nullopt, 1041 | std::span operands = {}); 1042 | 1043 | /// Gathers the requested depth-comparison from four texels. 1044 | template 1045 | requires(...&& std::is_convertible_v) Id 1046 | OpImageDrefGather(Id result_type, Id sampled_image, Id coordinate, Id dref, 1047 | spv::ImageOperandsMask image_operands, Ts&&... operands) { 1048 | return OpImageDrefGather(result_type, sampled_image, coordinate, dref, image_operands, 1049 | std::span({operands...})); 1050 | } 1051 | 1052 | /// Read a texel from an image without a sampler. 1053 | Id OpImageRead(Id result_type, Id sampled_image, Id coordinate, 1054 | std::optional image_operands = std::nullopt, 1055 | std::span operands = {}); 1056 | 1057 | /// Read a texel from an image without a sampler. 1058 | template 1059 | requires(...&& std::is_convertible_v) Id 1060 | OpImageRead(Id result_type, Id sampled_image, Id coordinate, 1061 | spv::ImageOperandsMask image_operands, Ts&&... operands) { 1062 | return OpImageRead(result_type, sampled_image, coordinate, image_operands, 1063 | std::span({operands...})); 1064 | } 1065 | 1066 | /// Write a texel to an image without a sampler. 1067 | Id OpImageWrite(Id image, Id coordinate, Id texel, 1068 | std::optional image_operands = std::nullopt, 1069 | std::span operands = {}); 1070 | 1071 | /// Write a texel to an image without a sampler. 1072 | template 1073 | requires(...&& std::is_convertible_v) Id 1074 | OpImageWrite(Id image, Id coordinate, Id texel, spv::ImageOperandsMask image_operands, 1075 | Ts&&... operands) { 1076 | return OpImageWrite(image, coordinate, texel, image_operands, 1077 | std::span({operands...})); 1078 | } 1079 | 1080 | /// Extract the image from a sampled image. 1081 | Id OpImage(Id result_type, Id sampled_image); 1082 | 1083 | /// Query the dimensions of Image for mipmap level for Level of Detail. 1084 | Id OpImageQuerySizeLod(Id result_type, Id image, Id level_of_detail); 1085 | 1086 | /// Query the dimensions of Image, with no level of detail. 1087 | Id OpImageQuerySize(Id result_type, Id image); 1088 | 1089 | /// Query the mipmap level and the level of detail for a hypothetical sampling of Image at 1090 | /// Coordinate using an implicit level of detail. 1091 | Id OpImageQueryLod(Id result_type, Id image, Id coordinate); 1092 | 1093 | /// Query the number of mipmap levels accessible through Image. 1094 | Id OpImageQueryLevels(Id result_type, Id image); 1095 | 1096 | /// Query the number of samples available per texel fetch in a multisample image. 1097 | Id OpImageQuerySamples(Id result_type, Id image); 1098 | 1099 | /// Sample a sparse image with an implicit level of detail. 1100 | Id OpImageSparseSampleImplicitLod(Id result_type, Id sampled_image, Id coordinate, 1101 | std::optional image_operands, 1102 | std::span operands); 1103 | 1104 | /// Sample a sparse image using an explicit level of detail. 1105 | Id OpImageSparseSampleExplicitLod(Id result_type, Id sampled_image, Id coordinate, 1106 | spv::ImageOperandsMask image_operands, 1107 | std::span operands); 1108 | 1109 | /// Sample a sparse image doing depth-comparison with an implicit level of detail. 1110 | Id OpImageSparseSampleDrefImplicitLod(Id result_type, Id sampled_image, Id coordinate, Id dref, 1111 | std::optional image_operands, 1112 | std::span operands); 1113 | 1114 | /// Sample a sparse image doing depth-comparison using an explicit level of detail. 1115 | Id OpImageSparseSampleDrefExplicitLod(Id result_type, Id sampled_image, Id coordinate, Id dref, 1116 | spv::ImageOperandsMask image_operands, 1117 | std::span operands); 1118 | 1119 | /// Fetch a single texel from a sampled sparse image. 1120 | Id OpImageSparseFetch(Id result_type, Id image, Id coordinate, 1121 | std::optional image_operands, 1122 | std::span operands); 1123 | 1124 | /// Gathers the requested component from four texels of a sparse image. 1125 | Id OpImageSparseGather(Id result_type, Id sampled_image, Id coordinate, Id component, 1126 | std::optional image_operands, 1127 | std::span operands); 1128 | 1129 | /// Gathers the requested depth-comparison from four texels of a sparse image. 1130 | Id OpImageSparseDrefGather(Id result_type, Id sampled_image, Id coordinate, Id dref, 1131 | std::optional image_operands, 1132 | std::span operands); 1133 | 1134 | /// Translates a Resident Code into a Boolean. Result is false if any of the texels were in 1135 | /// uncommitted texture memory, and true otherwise. 1136 | Id OpImageSparseTexelsResident(Id result_type, Id resident_code); 1137 | 1138 | /// Read a texel from a sparse image without a sampler. 1139 | Id OpImageSparseRead(Id result_type, Id image, Id coordinate, 1140 | std::optional image_operands, 1141 | std::span operands); 1142 | 1143 | // Group 1144 | 1145 | /// Computes a bitfield value combining the Predicate value from all invocations in the current 1146 | /// Subgroup that execute the same dynamic instance of this instruction. 1147 | Id OpSubgroupBallotKHR(Id result_type, Id predicate); 1148 | 1149 | /// Return the value from the invocation in the subgroup with an invocation ID equal to index. 1150 | /// The index must be the same for all active invocations in the subgroup, otherwise the results 1151 | /// are undefined. 1152 | Id OpSubgroupReadInvocationKHR(Id result_type, Id value, Id index); 1153 | 1154 | /// TBD 1155 | Id OpSubgroupAllKHR(Id result_type, Id predicate); 1156 | 1157 | /// TBD 1158 | Id OpSubgroupAnyKHR(Id result_type, Id predicate); 1159 | 1160 | /// TBD 1161 | Id OpSubgroupAllEqualKHR(Id result_type, Id predicate); 1162 | 1163 | // Result is the Value of the invocation identified by the id Id to all active invocations in 1164 | // the group. 1165 | Id OpGroupNonUniformBroadcast(Id result_type, Id scope, Id value, Id id); 1166 | 1167 | // Result is the Value of the invocation identified by the id Id. 1168 | Id OpGroupNonUniformShuffle(Id result_type, Id scope, Id value, Id id); 1169 | 1170 | /// Return the value of the invocation identified by the current invocation's id within the 1171 | /// group xor'ed with mask. 1172 | Id OpGroupNonUniformShuffleXor(Id result_type, Id scope, Id value, Id mask); 1173 | 1174 | /// Evaluates a predicate for all active invocations in the group, resulting in 1175 | /// true if predicate evaluates to true for all active invocations in the 1176 | /// group, otherwise the result is false. 1177 | Id OpGroupNonUniformAll(Id result_type, Id scope, Id predicate); 1178 | 1179 | /// Evaluates a predicate for all active invocations in the group, 1180 | /// resulting in true if predicate evaluates to true for any active 1181 | /// invocation in the group, otherwise the result is false. 1182 | Id OpGroupNonUniformAny(Id result_type, Id scope, Id predicate); 1183 | 1184 | /// Evaluates a value for all active invocations in the group. The result 1185 | /// is true if Value is equal for all active invocations in the group. 1186 | /// Otherwise, the result is false. 1187 | Id OpGroupNonUniformAllEqual(Id result_type, Id scope, Id value); 1188 | 1189 | /// Result is a bitfield value combining the Predicate value from all 1190 | /// invocations in the group that execute the same dynamic instance of this 1191 | /// instruction. The bit is set to one if the corresponding invocation is 1192 | /// active and the Predicate for that invocation evaluated to true; 1193 | /// otherwise, it is set to zero. 1194 | Id OpGroupNonUniformBallot(Id result_type, Id scope, Id predicate); 1195 | 1196 | // Atomic 1197 | 1198 | /// Atomically load through Pointer using the given Semantics. All subparts of the value that is 1199 | /// loaded will be read atomically with respect to all other atomic accesses to it within Scope. 1200 | Id OpAtomicLoad(Id result_type, Id pointer, Id memory, Id semantics); 1201 | 1202 | /// Atomically store through Pointer using the given Semantics. All subparts of Value will be 1203 | /// written atomically with respect to all other atomic accesses to it within Scope. 1204 | Id OpAtomicStore(Id pointer, Id memory, Id semantics, Id value); 1205 | 1206 | /// Perform the following steps atomically with respect to any other atomic accesses within 1207 | /// Scope to the same location: 1208 | /// 1) load through Pointer to get an Original Value, 1209 | /// 2) get a New Value from copying Value, and 1210 | /// 3) store the New Value back through Pointer. 1211 | Id OpAtomicExchange(Id result_type, Id pointer, Id memory, Id semantics, Id value); 1212 | 1213 | /// Perform the following steps atomically with respect to any other atomic accesses within 1214 | /// Scope to the same location: 1215 | /// 1) load through Pointer to get an Original Value, 1216 | /// 2) get a New Value from Value only if Original Value equals Comparator, and 1217 | /// 3) store the New Value back through Pointer only if 'Original Value equaled Comparator. 1218 | Id OpAtomicCompareExchange(Id result_type, Id pointer, Id memory, Id equal, Id unequal, 1219 | Id value, Id comparator); 1220 | 1221 | /// Perform the following steps atomically with respect to any other atomic accesses within 1222 | /// Scope to the same location: 1223 | /// 1) load through Pointer to get an Original Value, 1224 | /// 2) get a New Value through integer addition of 1 to Original Value, and 1225 | /// 3) store the New Value back through Pointer. 1226 | Id OpAtomicIIncrement(Id result_type, Id pointer, Id memory, Id semantics); 1227 | 1228 | /// Perform the following steps atomically with respect to any other atomic accesses within 1229 | /// Scope to the same location: 1230 | /// 1) load through Pointer to get an Original Value, 1231 | /// 2) get a New Value through integer subtraction of 1 from Original Value, and 1232 | /// 3) store the New Value back through Pointer. 1233 | Id OpAtomicIDecrement(Id result_type, Id pointer, Id memory, Id semantics); 1234 | 1235 | /// Perform the following steps atomically with respect to any other atomic accesses within 1236 | /// Scope to the same location: 1237 | /// 1) load through Pointer to get an Original Value, 1238 | /// 2) get a New Value by integer addition of Original Value and Value, and 1239 | /// 3) store the New Value back through Pointer. 1240 | Id OpAtomicIAdd(Id result_type, Id pointer, Id memory, Id semantics, Id value); 1241 | 1242 | /// Perform the following steps atomically with respect to any other atomic accesses within 1243 | /// Scope to the same location: 1244 | /// 1) load through Pointer to get an Original Value, 1245 | /// 2) get a New Value by integer subtraction of Value from Original Value, and 1246 | /// 3) store the New Value back through Pointer. 1247 | Id OpAtomicISub(Id result_type, Id pointer, Id memory, Id semantics, Id value); 1248 | 1249 | /// Perform the following steps atomically with respect to any other atomic accesses within 1250 | /// Scope to the same location: 1251 | /// 1) load through Pointer to get an Original Value, 1252 | /// 2) get a New Value by finding the smallest signed integer of Original Value and Value, and 1253 | /// 3) store the New Value back through Pointer. 1254 | Id OpAtomicSMin(Id result_type, Id pointer, Id memory, Id semantics, Id value); 1255 | 1256 | /// Perform the following steps atomically with respect to any other atomic accesses within 1257 | /// Scope to the same location: 1258 | /// 1) load through Pointer to get an Original Value, 1259 | /// 2) get a New Value by finding the smallest unsigned integer of Original Value and Value, and 1260 | /// 3) store the New Value back through Pointer. 1261 | Id OpAtomicUMin(Id result_type, Id pointer, Id memory, Id semantics, Id value); 1262 | 1263 | /// Perform the following steps atomically with respect to any other atomic accesses within 1264 | /// Scope to the same location: 1265 | /// 1) load through Pointer to get an Original Value, 1266 | /// 2) get a New Value by finding the largest signed integer of Original Value and Value, and 1267 | /// 3) store the New Value back through Pointer. 1268 | Id OpAtomicSMax(Id result_type, Id pointer, Id memory, Id semantics, Id value); 1269 | 1270 | /// Perform the following steps atomically with respect to any other atomic accesses within 1271 | /// Scope to the same location: 1272 | /// 1) load through Pointer to get an Original Value, 1273 | /// 2) get a New Value by finding the largest unsigned integer of Original Value and Value, and 1274 | /// 3) store the New Value back through Pointer. 1275 | Id OpAtomicUMax(Id result_type, Id pointer, Id memory, Id semantics, Id value); 1276 | 1277 | /// Perform the following steps atomically with respect to any other atomic accesses within 1278 | /// Scope to the same location: 1279 | /// 1) load through Pointer to get an Original Value, 1280 | /// 2) get a New Value by the bitwise AND of Original Value and Value, and 1281 | /// 3) store the New Value back through Pointer. 1282 | Id OpAtomicAnd(Id result_type, Id pointer, Id memory, Id semantics, Id value); 1283 | 1284 | /// Perform the following steps atomically with respect to any other atomic accesses within 1285 | /// Scope to the same location: 1286 | /// 1) load through Pointer to get an Original Value, 1287 | /// 2) get a New Value by the bitwise OR of Original Value and Value, and 1288 | /// 3) store the New Value back through Pointer. 1289 | Id OpAtomicOr(Id result_type, Id pointer, Id memory, Id semantics, Id value); 1290 | 1291 | /// Perform the following steps atomically with respect to any other atomic accesses within 1292 | /// Scope to the same location: 1293 | /// 1) load through Pointer to get an Original Value, 1294 | /// 2) get a New Value by the bitwise exclusive OR of Original Value and Value, and 1295 | /// 3) store the New Value back through Pointer. 1296 | Id OpAtomicXor(Id result_type, Id pointer, Id memory, Id semantics, Id value); 1297 | 1298 | private: 1299 | Id GetGLSLstd450(); 1300 | 1301 | std::uint32_t version{}; 1302 | std::uint32_t bound{}; 1303 | 1304 | std::unordered_set extensions; 1305 | std::unordered_set capabilities; 1306 | std::optional glsl_std_450; 1307 | 1308 | spv::AddressingModel addressing_model{spv::AddressingModel::Logical}; 1309 | spv::MemoryModel memory_model{spv::MemoryModel::GLSL450}; 1310 | 1311 | std::unique_ptr ext_inst_imports; 1312 | std::unique_ptr entry_points; 1313 | std::unique_ptr execution_modes; 1314 | std::unique_ptr debug; 1315 | std::unique_ptr annotations; 1316 | std::unique_ptr declarations; 1317 | std::unique_ptr global_variables; 1318 | std::unique_ptr code; 1319 | std::vector deferred_phi_nodes; 1320 | }; 1321 | 1322 | } // namespace Sirit 1323 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | sirit.h 2 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(sirit 2 | ../include/sirit/sirit.h 3 | sirit.cpp 4 | stream.h 5 | common_types.h 6 | instructions/type.cpp 7 | instructions/constant.cpp 8 | instructions/function.cpp 9 | instructions/flow.cpp 10 | instructions/debug.cpp 11 | instructions/derivatives.cpp 12 | instructions/memory.cpp 13 | instructions/annotation.cpp 14 | instructions/misc.cpp 15 | instructions/logical.cpp 16 | instructions/conversion.cpp 17 | instructions/bit.cpp 18 | instructions/arithmetic.cpp 19 | instructions/extension.cpp 20 | instructions/image.cpp 21 | instructions/group.cpp 22 | instructions/barrier.cpp 23 | instructions/atomic.cpp 24 | ) 25 | 26 | target_compile_options(sirit PRIVATE ${SIRIT_CXX_FLAGS}) 27 | 28 | target_include_directories(sirit 29 | PUBLIC ../include 30 | PRIVATE .) 31 | 32 | target_link_libraries(sirit PUBLIC SPIRV-Headers::SPIRV-Headers) 33 | -------------------------------------------------------------------------------- /src/common_types.h: -------------------------------------------------------------------------------- 1 | /* This file is part of the sirit project. 2 | * Copyright (c) 2019 sirit 3 | * This software may be used and distributed according to the terms of the 4 | * 3-Clause BSD License 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | namespace Sirit { 13 | 14 | using u8 = std::uint8_t; 15 | using u16 = std::uint16_t; 16 | using u32 = std::uint32_t; 17 | using u64 = std::uint64_t; 18 | using uptr = std::uintptr_t; 19 | 20 | using s8 = std::int8_t; 21 | using s16 = std::int16_t; 22 | using s32 = std::int32_t; 23 | using s64 = std::int64_t; 24 | using sptr = std::intptr_t; 25 | 26 | using f32 = float; 27 | using f64 = double; 28 | static_assert(sizeof(f32) == sizeof(u32), "f32 must be 32 bits wide"); 29 | static_assert(sizeof(f64) == sizeof(u64), "f64 must be 64 bits wide"); 30 | 31 | } // namespace Sirit 32 | -------------------------------------------------------------------------------- /src/instructions/annotation.cpp: -------------------------------------------------------------------------------- 1 | /* This file is part of the sirit project. 2 | * Copyright (c) 2019 sirit 3 | * This software may be used and distributed according to the terms of the 4 | * 3-Clause BSD License 5 | */ 6 | 7 | #include 8 | 9 | #include "sirit/sirit.h" 10 | 11 | #include "stream.h" 12 | 13 | namespace Sirit { 14 | 15 | Id Module::Decorate(Id target, spv::Decoration decoration, std::span literals) { 16 | annotations->Reserve(3 + literals.size()); 17 | return *annotations << spv::Op::OpDecorate << target << decoration << literals << EndOp{}; 18 | } 19 | 20 | Id Module::MemberDecorate(Id structure_type, Literal member, spv::Decoration decoration, 21 | std::span literals) { 22 | annotations->Reserve(4 + literals.size()); 23 | return *annotations << spv::Op::OpMemberDecorate << structure_type << member << decoration 24 | << literals << EndOp{}; 25 | } 26 | 27 | } // namespace Sirit 28 | -------------------------------------------------------------------------------- /src/instructions/arithmetic.cpp: -------------------------------------------------------------------------------- 1 | /* This file is part of the sirit project. 2 | * Copyright (c) 2019 sirit 3 | * This software may be used and distributed according to the terms of the 4 | * 3-Clause BSD License 5 | */ 6 | 7 | #include "sirit/sirit.h" 8 | 9 | #include "stream.h" 10 | 11 | namespace Sirit { 12 | 13 | #define DEFINE_UNARY(funcname, opcode) \ 14 | Id Module::funcname(Id result_type, Id operand) { \ 15 | code->Reserve(4); \ 16 | return *code << OpId{opcode, result_type} << operand << EndOp{}; \ 17 | } 18 | 19 | #define DEFINE_BINARY(funcname, opcode) \ 20 | Id Module::funcname(Id result_type, Id operand_1, Id operand_2) { \ 21 | code->Reserve(5); \ 22 | return *code << OpId{opcode, result_type} << operand_1 << operand_2 << EndOp{}; \ 23 | } 24 | 25 | DEFINE_UNARY(OpSNegate, spv::Op::OpSNegate) 26 | DEFINE_UNARY(OpFNegate, spv::Op::OpFNegate) 27 | 28 | DEFINE_BINARY(OpIAdd, spv::Op::OpIAdd) 29 | DEFINE_BINARY(OpFAdd, spv::Op::OpFAdd) 30 | DEFINE_BINARY(OpISub, spv::Op::OpISub) 31 | DEFINE_BINARY(OpFSub, spv::Op::OpFSub) 32 | DEFINE_BINARY(OpIMul, spv::Op::OpIMul) 33 | DEFINE_BINARY(OpFMul, spv::Op::OpFMul) 34 | DEFINE_BINARY(OpUDiv, spv::Op::OpUDiv) 35 | DEFINE_BINARY(OpSDiv, spv::Op::OpSDiv) 36 | DEFINE_BINARY(OpFDiv, spv::Op::OpFDiv) 37 | DEFINE_BINARY(OpUMod, spv::Op::OpUMod) 38 | DEFINE_BINARY(OpSMod, spv::Op::OpSMod) 39 | DEFINE_BINARY(OpFMod, spv::Op::OpFMod) 40 | DEFINE_BINARY(OpSRem, spv::Op::OpSRem) 41 | DEFINE_BINARY(OpFRem, spv::Op::OpFRem) 42 | DEFINE_BINARY(OpIAddCarry, spv::Op::OpIAddCarry) 43 | 44 | } // namespace Sirit 45 | -------------------------------------------------------------------------------- /src/instructions/atomic.cpp: -------------------------------------------------------------------------------- 1 | /* This file is part of the sirit project. 2 | * Copyright (c) 2019 sirit 3 | * This software may be used and distributed according to the terms of the 4 | * 3-Clause BSD License 5 | */ 6 | 7 | #include "sirit/sirit.h" 8 | 9 | #include "stream.h" 10 | 11 | namespace Sirit { 12 | 13 | Id Module::OpAtomicLoad(Id result_type, Id pointer, Id memory, Id semantics) { 14 | code->Reserve(6); 15 | return *code << OpId{spv::Op::OpAtomicLoad, result_type} << pointer << memory << semantics 16 | << EndOp{}; 17 | } 18 | 19 | Id Module::OpAtomicStore(Id pointer, Id memory, Id semantics, Id value) { 20 | code->Reserve(5); 21 | return *code << OpId{spv::Op::OpAtomicStore} << pointer << memory << semantics << value 22 | << EndOp{}; 23 | } 24 | 25 | Id Module::OpAtomicExchange(Id result_type, Id pointer, Id memory, Id semantics, Id value) { 26 | code->Reserve(7); 27 | return *code << OpId{spv::Op::OpAtomicExchange, result_type} << pointer << memory << semantics 28 | << value << EndOp{}; 29 | } 30 | 31 | Id Module::OpAtomicCompareExchange(Id result_type, Id pointer, Id memory, Id equal, Id unequal, 32 | Id value, Id comparator) { 33 | code->Reserve(9); 34 | return *code << OpId{spv::Op::OpAtomicCompareExchange, result_type} << pointer << memory 35 | << equal << unequal << value << comparator << EndOp{}; 36 | } 37 | 38 | Id Module::OpAtomicIIncrement(Id result_type, Id pointer, Id memory, Id semantics) { 39 | code->Reserve(6); 40 | return *code << OpId{spv::Op::OpAtomicIIncrement, result_type} << pointer << memory << semantics 41 | << EndOp{}; 42 | } 43 | 44 | Id Module::OpAtomicIDecrement(Id result_type, Id pointer, Id memory, Id semantics) { 45 | code->Reserve(6); 46 | return *code << OpId{spv::Op::OpAtomicIDecrement, result_type} << pointer << memory << semantics 47 | << EndOp{}; 48 | } 49 | 50 | Id Module::OpAtomicIAdd(Id result_type, Id pointer, Id memory, Id semantics, Id value) { 51 | code->Reserve(7); 52 | return *code << OpId{spv::Op::OpAtomicIAdd, result_type} << pointer << memory << semantics 53 | << value << EndOp{}; 54 | } 55 | 56 | Id Module::OpAtomicISub(Id result_type, Id pointer, Id memory, Id semantics, Id value) { 57 | code->Reserve(7); 58 | return *code << OpId{spv::Op::OpAtomicISub, result_type} << pointer << memory << semantics 59 | << value << EndOp{}; 60 | } 61 | 62 | Id Module::OpAtomicSMin(Id result_type, Id pointer, Id memory, Id semantics, Id value) { 63 | code->Reserve(7); 64 | return *code << OpId{spv::Op::OpAtomicSMin, result_type} << pointer << memory << semantics 65 | << value << EndOp{}; 66 | } 67 | 68 | Id Module::OpAtomicUMin(Id result_type, Id pointer, Id memory, Id semantics, Id value) { 69 | code->Reserve(7); 70 | return *code << OpId{spv::Op::OpAtomicUMin, result_type} << pointer << memory << semantics 71 | << value << EndOp{}; 72 | } 73 | 74 | Id Module::OpAtomicSMax(Id result_type, Id pointer, Id memory, Id semantics, Id value) { 75 | code->Reserve(7); 76 | return *code << OpId{spv::Op::OpAtomicSMax, result_type} << pointer << memory << semantics 77 | << value << EndOp{}; 78 | } 79 | 80 | Id Module::OpAtomicUMax(Id result_type, Id pointer, Id memory, Id semantics, Id value) { 81 | code->Reserve(7); 82 | return *code << OpId{spv::Op::OpAtomicUMax, result_type} << pointer << memory << semantics 83 | << value << EndOp{}; 84 | } 85 | 86 | Id Module::OpAtomicAnd(Id result_type, Id pointer, Id memory, Id semantics, Id value) { 87 | code->Reserve(7); 88 | return *code << OpId{spv::Op::OpAtomicAnd, result_type} << pointer << memory << semantics 89 | << value << EndOp{}; 90 | } 91 | 92 | Id Module::OpAtomicOr(Id result_type, Id pointer, Id memory, Id semantics, Id value) { 93 | code->Reserve(7); 94 | return *code << OpId{spv::Op::OpAtomicOr, result_type} << pointer << memory << semantics 95 | << value << EndOp{}; 96 | } 97 | 98 | Id Module::OpAtomicXor(Id result_type, Id pointer, Id memory, Id semantics, Id value) { 99 | code->Reserve(7); 100 | return *code << OpId{spv::Op::OpAtomicXor, result_type} << pointer << memory << semantics 101 | << value << EndOp{}; 102 | } 103 | 104 | } // namespace Sirit 105 | -------------------------------------------------------------------------------- /src/instructions/barrier.cpp: -------------------------------------------------------------------------------- 1 | /* This file is part of the sirit project. 2 | * Copyright (c) 2019 sirit 3 | * This software may be used and distributed according to the terms of the 4 | * 3-Clause BSD License 5 | */ 6 | 7 | #include "sirit/sirit.h" 8 | 9 | #include "stream.h" 10 | 11 | namespace Sirit { 12 | 13 | Id Module::OpControlBarrier(Id execution, Id memory, Id semantics) { 14 | code->Reserve(4); 15 | return *code << spv::Op::OpControlBarrier << execution << memory << semantics << EndOp{}; 16 | } 17 | 18 | Id Module::OpMemoryBarrier(Id scope, Id semantics) { 19 | code->Reserve(3); 20 | return *code << spv::Op::OpMemoryBarrier << scope << semantics << EndOp{}; 21 | } 22 | 23 | } // namespace Sirit 24 | -------------------------------------------------------------------------------- /src/instructions/bit.cpp: -------------------------------------------------------------------------------- 1 | /* This file is part of the sirit project. 2 | * Copyright (c) 2019 sirit 3 | * This software may be used and distributed according to the terms of the 4 | * 3-Clause BSD License 5 | */ 6 | 7 | #include "sirit/sirit.h" 8 | 9 | #include "stream.h" 10 | 11 | namespace Sirit { 12 | 13 | Id Module::OpShiftRightLogical(Id result_type, Id base, Id shift) { 14 | code->Reserve(5); 15 | return *code << OpId{spv::Op::OpShiftRightLogical, result_type} << base << shift << EndOp{}; 16 | } 17 | 18 | Id Module::OpShiftRightArithmetic(Id result_type, Id base, Id shift) { 19 | code->Reserve(5); 20 | return *code << OpId{spv::Op::OpShiftRightArithmetic, result_type} << base << shift << EndOp{}; 21 | } 22 | 23 | Id Module::OpShiftLeftLogical(Id result_type, Id base, Id shift) { 24 | code->Reserve(5); 25 | return *code << OpId{spv::Op::OpShiftLeftLogical, result_type} << base << shift << EndOp{}; 26 | } 27 | 28 | Id Module::OpBitwiseOr(Id result_type, Id operand_1, Id operand_2) { 29 | code->Reserve(5); 30 | return *code << OpId{spv::Op::OpBitwiseOr, result_type} << operand_1 << operand_2 << EndOp{}; 31 | } 32 | 33 | Id Module::OpBitwiseXor(Id result_type, Id operand_1, Id operand_2) { 34 | code->Reserve(5); 35 | return *code << OpId{spv::Op::OpBitwiseXor, result_type} << operand_1 << operand_2 << EndOp{}; 36 | } 37 | 38 | Id Module::OpBitwiseAnd(Id result_type, Id operand_1, Id operand_2) { 39 | code->Reserve(5); 40 | return *code << OpId{spv::Op::OpBitwiseAnd, result_type} << operand_1 << operand_2 << EndOp{}; 41 | } 42 | 43 | Id Module::OpNot(Id result_type, Id operand) { 44 | code->Reserve(4); 45 | return *code << OpId{spv::Op::OpNot, result_type} << operand << EndOp{}; 46 | } 47 | 48 | Id Module::OpBitFieldInsert(Id result_type, Id base, Id insert, Id offset, Id count) { 49 | code->Reserve(7); 50 | return *code << OpId{spv::Op::OpBitFieldInsert, result_type} << base << insert << offset 51 | << count << EndOp{}; 52 | } 53 | 54 | Id Module::OpBitFieldSExtract(Id result_type, Id base, Id offset, Id count) { 55 | code->Reserve(6); 56 | return *code << OpId{spv::Op::OpBitFieldSExtract, result_type} << base << offset << count 57 | << EndOp{}; 58 | } 59 | 60 | Id Module::OpBitFieldUExtract(Id result_type, Id base, Id offset, Id count) { 61 | code->Reserve(6); 62 | return *code << OpId{spv::Op::OpBitFieldUExtract, result_type} << base << offset << count 63 | << EndOp{}; 64 | } 65 | 66 | Id Module::OpBitReverse(Id result_type, Id base) { 67 | code->Reserve(4); 68 | return *code << OpId{spv::Op::OpBitReverse, result_type} << base << EndOp{}; 69 | } 70 | 71 | Id Module::OpBitCount(Id result_type, Id base) { 72 | code->Reserve(4); 73 | return *code << OpId{spv::Op::OpBitCount, result_type} << base << EndOp{}; 74 | } 75 | 76 | } // namespace Sirit 77 | -------------------------------------------------------------------------------- /src/instructions/constant.cpp: -------------------------------------------------------------------------------- 1 | /* This file is part of the sirit project. 2 | * Copyright (c) 2019 sirit 3 | * This software may be used and distributed according to the terms of the 4 | * 3-Clause BSD License 5 | */ 6 | 7 | #include 8 | 9 | #include "sirit/sirit.h" 10 | 11 | #include "stream.h" 12 | 13 | namespace Sirit { 14 | 15 | Id Module::ConstantTrue(Id result_type) { 16 | declarations->Reserve(3); 17 | return *declarations << OpId{spv::Op::OpConstantTrue, result_type} << EndOp{}; 18 | } 19 | 20 | Id Module::ConstantFalse(Id result_type) { 21 | declarations->Reserve(3); 22 | return *declarations << OpId{spv::Op::OpConstantFalse, result_type} << EndOp{}; 23 | } 24 | 25 | Id Module::Constant(Id result_type, const Literal& literal) { 26 | declarations->Reserve(3 + 2); 27 | return *declarations << OpId{spv::Op::OpConstant, result_type} << literal << EndOp{}; 28 | } 29 | 30 | Id Module::ConstantComposite(Id result_type, std::span constituents) { 31 | declarations->Reserve(3 + constituents.size()); 32 | return *declarations << OpId{spv::Op::OpConstantComposite, result_type} << constituents 33 | << EndOp{}; 34 | } 35 | 36 | Id Module::ConstantSampler(Id result_type, spv::SamplerAddressingMode addressing_mode, 37 | bool normalized, spv::SamplerFilterMode filter_mode) { 38 | declarations->Reserve(6); 39 | return *declarations << OpId{spv::Op::OpConstantSampler, result_type} << addressing_mode 40 | << normalized << filter_mode << EndOp{}; 41 | } 42 | 43 | Id Module::ConstantNull(Id result_type) { 44 | declarations->Reserve(3); 45 | return *declarations << OpId{spv::Op::OpConstantNull, result_type} << EndOp{}; 46 | } 47 | 48 | } // namespace Sirit 49 | -------------------------------------------------------------------------------- /src/instructions/conversion.cpp: -------------------------------------------------------------------------------- 1 | /* This file is part of the sirit project. 2 | * Copyright (c) 2019 sirit 3 | * This software may be used and distributed according to the terms of the 4 | * 3-Clause BSD License 5 | */ 6 | 7 | #include "sirit/sirit.h" 8 | 9 | #include "stream.h" 10 | 11 | namespace Sirit { 12 | 13 | #define DEFINE_UNARY(opcode) \ 14 | Id Module::opcode(Id result_type, Id operand) { \ 15 | code->Reserve(4); \ 16 | return *code << OpId{spv::Op::opcode, result_type} << operand << EndOp{}; \ 17 | } 18 | 19 | DEFINE_UNARY(OpConvertFToU) 20 | DEFINE_UNARY(OpConvertFToS) 21 | DEFINE_UNARY(OpConvertSToF) 22 | DEFINE_UNARY(OpConvertUToF) 23 | DEFINE_UNARY(OpUConvert) 24 | DEFINE_UNARY(OpSConvert) 25 | DEFINE_UNARY(OpFConvert) 26 | DEFINE_UNARY(OpQuantizeToF16) 27 | DEFINE_UNARY(OpBitcast) 28 | 29 | } // namespace Sirit 30 | -------------------------------------------------------------------------------- /src/instructions/debug.cpp: -------------------------------------------------------------------------------- 1 | /* This file is part of the sirit project. 2 | * Copyright (c) 2019 sirit 3 | * This software may be used and distributed according to the terms of the 4 | * 3-Clause BSD License 5 | */ 6 | 7 | #include "sirit/sirit.h" 8 | 9 | #include "common_types.h" 10 | #include "stream.h" 11 | 12 | namespace Sirit { 13 | 14 | Id Module::Name(Id target, std::string_view name) { 15 | debug->Reserve(3 + WordsInString(name)); 16 | *debug << spv::Op::OpName << target << name << EndOp{}; 17 | return target; 18 | } 19 | 20 | Id Module::MemberName(Id type, u32 member, std::string_view name) { 21 | debug->Reserve(4 + WordsInString(name)); 22 | *debug << spv::Op::OpMemberName << type << member << name << EndOp{}; 23 | return type; 24 | } 25 | 26 | Id Module::String(std::string_view string) { 27 | debug->Reserve(3 + WordsInString(string)); 28 | return *debug << OpId{spv::Op::OpString} << string << EndOp{}; 29 | } 30 | 31 | Id Module::OpLine(Id file, Literal line, Literal column) { 32 | debug->Reserve(4); 33 | return *debug << spv::Op::OpLine << file << line << column << EndOp{}; 34 | } 35 | 36 | } // namespace Sirit 37 | -------------------------------------------------------------------------------- /src/instructions/derivatives.cpp: -------------------------------------------------------------------------------- 1 | /* This file is part of the sirit project. 2 | * Copyright (c) 2021 sirit 3 | * This software may be used and distributed according to the terms of the 4 | * 3-Clause BSD License 5 | */ 6 | 7 | #include "sirit/sirit.h" 8 | 9 | #include "stream.h" 10 | 11 | namespace Sirit { 12 | 13 | #define DEFINE_UNARY(funcname, opcode) \ 14 | Id Module::funcname(Id result_type, Id operand) { \ 15 | code->Reserve(4); \ 16 | return *code << OpId{opcode, result_type} << operand << EndOp{}; \ 17 | } 18 | 19 | DEFINE_UNARY(OpDPdx, spv::Op::OpDPdx) 20 | DEFINE_UNARY(OpDPdy, spv::Op::OpDPdy) 21 | DEFINE_UNARY(OpFwidth, spv::Op::OpFwidth) 22 | DEFINE_UNARY(OpDPdxFine, spv::Op::OpDPdxFine) 23 | DEFINE_UNARY(OpDPdyFine, spv::Op::OpDPdyFine) 24 | DEFINE_UNARY(OpFwidthFine, spv::Op::OpFwidthFine) 25 | DEFINE_UNARY(OpDPdxCoarse, spv::Op::OpDPdxCoarse) 26 | DEFINE_UNARY(OpDPdyCoarse, spv::Op::OpDPdyCoarse) 27 | DEFINE_UNARY(OpFwidthCoarse, spv::Op::OpFwidthCoarse) 28 | 29 | } // namespace Sirit 30 | -------------------------------------------------------------------------------- /src/instructions/extension.cpp: -------------------------------------------------------------------------------- 1 | /* This file is part of the sirit project. 2 | * Copyright (c) 2019 sirit 3 | * This software may be used and distributed according to the terms of the 4 | * 3-Clause BSD License 5 | */ 6 | 7 | #include 8 | 9 | #include "sirit/sirit.h" 10 | 11 | #include "stream.h" 12 | 13 | namespace Sirit { 14 | 15 | Id Module::OpExtInst(Id result_type, Id set, u32 instruction, std::span operands) { 16 | code->Reserve(5 + operands.size()); 17 | return *code << OpId{spv::Op::OpExtInst, result_type} << set << instruction << operands 18 | << EndOp{}; 19 | } 20 | 21 | #define DEFINE_UNARY(funcname, opcode) \ 22 | Id Module::funcname(Id result_type, Id operand) { \ 23 | return OpExtInst(result_type, GetGLSLstd450(), opcode, operand); \ 24 | } 25 | 26 | #define DEFINE_BINARY(funcname, opcode) \ 27 | Id Module::funcname(Id result_type, Id operand_1, Id operand_2) { \ 28 | return OpExtInst(result_type, GetGLSLstd450(), opcode, operand_1, operand_2); \ 29 | } 30 | 31 | #define DEFINE_TRINARY(funcname, opcode) \ 32 | Id Module::funcname(Id result_type, Id operand_1, Id operand_2, Id operand_3) { \ 33 | return OpExtInst(result_type, GetGLSLstd450(), opcode, operand_1, operand_2, operand_3); \ 34 | } 35 | 36 | DEFINE_UNARY(OpFAbs, GLSLstd450FAbs) 37 | DEFINE_UNARY(OpSAbs, GLSLstd450SAbs) 38 | DEFINE_UNARY(OpRound, GLSLstd450Round) 39 | DEFINE_UNARY(OpRoundEven, GLSLstd450RoundEven) 40 | DEFINE_UNARY(OpTrunc, GLSLstd450Trunc) 41 | DEFINE_UNARY(OpFSign, GLSLstd450FSign) 42 | DEFINE_UNARY(OpSSign, GLSLstd450SSign) 43 | DEFINE_UNARY(OpFloor, GLSLstd450Floor) 44 | DEFINE_UNARY(OpCeil, GLSLstd450Ceil) 45 | DEFINE_UNARY(OpFract, GLSLstd450Fract) 46 | DEFINE_UNARY(OpSin, GLSLstd450Sin) 47 | DEFINE_UNARY(OpCos, GLSLstd450Cos) 48 | DEFINE_UNARY(OpAsin, GLSLstd450Asin) 49 | DEFINE_UNARY(OpAcos, GLSLstd450Acos) 50 | DEFINE_BINARY(OpPow, GLSLstd450Pow) 51 | DEFINE_UNARY(OpExp, GLSLstd450Exp) 52 | DEFINE_UNARY(OpLog, GLSLstd450Log) 53 | DEFINE_UNARY(OpExp2, GLSLstd450Exp2) 54 | DEFINE_UNARY(OpLog2, GLSLstd450Log2) 55 | DEFINE_UNARY(OpSqrt, GLSLstd450Sqrt) 56 | DEFINE_UNARY(OpInverseSqrt, GLSLstd450InverseSqrt) 57 | DEFINE_BINARY(OpFMin, GLSLstd450FMin) 58 | DEFINE_BINARY(OpUMin, GLSLstd450UMin) 59 | DEFINE_BINARY(OpSMin, GLSLstd450SMin) 60 | DEFINE_BINARY(OpFMax, GLSLstd450FMax) 61 | DEFINE_BINARY(OpUMax, GLSLstd450UMax) 62 | DEFINE_BINARY(OpSMax, GLSLstd450SMax) 63 | DEFINE_TRINARY(OpFClamp, GLSLstd450FClamp) 64 | DEFINE_TRINARY(OpUClamp, GLSLstd450UClamp) 65 | DEFINE_TRINARY(OpSClamp, GLSLstd450SClamp) 66 | DEFINE_TRINARY(OpFma, GLSLstd450Fma) 67 | DEFINE_UNARY(OpPackHalf2x16, GLSLstd450PackHalf2x16) 68 | DEFINE_UNARY(OpUnpackHalf2x16, GLSLstd450UnpackHalf2x16) 69 | DEFINE_UNARY(OpFindILsb, GLSLstd450FindILsb) 70 | DEFINE_UNARY(OpFindSMsb, GLSLstd450FindSMsb) 71 | DEFINE_UNARY(OpFindUMsb, GLSLstd450FindUMsb) 72 | DEFINE_UNARY(OpInterpolateAtCentroid, GLSLstd450InterpolateAtCentroid) 73 | DEFINE_BINARY(OpInterpolateAtSample, GLSLstd450InterpolateAtSample) 74 | DEFINE_BINARY(OpInterpolateAtOffset, GLSLstd450InterpolateAtOffset) 75 | 76 | } // namespace Sirit 77 | -------------------------------------------------------------------------------- /src/instructions/flow.cpp: -------------------------------------------------------------------------------- 1 | /* This file is part of the sirit project. 2 | * Copyright (c) 2019 sirit 3 | * This software may be used and distributed according to the terms of the 4 | * 3-Clause BSD License 5 | */ 6 | 7 | #include 8 | 9 | #include "sirit/sirit.h" 10 | 11 | #include "stream.h" 12 | 13 | namespace Sirit { 14 | 15 | Id Module::OpPhi(Id result_type, std::span operands) { 16 | assert(operands.size() % 2 == 0); 17 | code->Reserve(3 + operands.size()); 18 | return *code << OpId{spv::Op::OpPhi, result_type} << operands << EndOp{}; 19 | } 20 | 21 | Id Module::DeferredOpPhi(Id result_type, std::span blocks) { 22 | deferred_phi_nodes.push_back(code->LocalAddress()); 23 | code->Reserve(3 + blocks.size() * 2); 24 | *code << OpId{spv::Op::OpPhi, result_type}; 25 | for (const Id block : blocks) { 26 | *code << u32{0} << block; 27 | } 28 | return *code << EndOp{}; 29 | } 30 | 31 | Id Module::OpLoopMerge(Id merge_block, Id continue_target, spv::LoopControlMask loop_control, 32 | std::span literals) { 33 | code->Reserve(4 + literals.size()); 34 | return *code << spv::Op::OpLoopMerge << merge_block << continue_target << loop_control 35 | << literals << EndOp{}; 36 | } 37 | 38 | Id Module::OpSelectionMerge(Id merge_block, spv::SelectionControlMask selection_control) { 39 | code->Reserve(3); 40 | return *code << spv::Op::OpSelectionMerge << merge_block << selection_control << EndOp{}; 41 | } 42 | 43 | Id Module::OpLabel() { 44 | return Id{++bound}; 45 | } 46 | 47 | Id Module::OpBranch(Id target_label) { 48 | code->Reserve(2); 49 | return *code << spv::Op::OpBranch << target_label << EndOp{}; 50 | } 51 | 52 | Id Module::OpBranchConditional(Id condition, Id true_label, Id false_label, u32 true_weight, 53 | u32 false_weight) { 54 | code->Reserve(6); 55 | *code << spv::Op::OpBranchConditional << condition << true_label << false_label; 56 | if (true_weight != 0 || false_weight != 0) { 57 | *code << true_weight << false_weight; 58 | } 59 | return *code << EndOp{}; 60 | } 61 | 62 | Id Module::OpSwitch(Id selector, Id default_label, std::span literals, 63 | std::span labels) { 64 | assert(literals.size() == labels.size()); 65 | const size_t size = literals.size(); 66 | code->Reserve(3 + size * 2); 67 | 68 | *code << spv::Op::OpSwitch << selector << default_label; 69 | for (std::size_t i = 0; i < size; ++i) { 70 | *code << literals[i] << labels[i]; 71 | } 72 | return *code << EndOp{}; 73 | } 74 | 75 | void Module::OpReturn() { 76 | code->Reserve(1); 77 | *code << spv::Op::OpReturn << EndOp{}; 78 | } 79 | 80 | void Module::OpUnreachable() { 81 | code->Reserve(1); 82 | *code << spv::Op::OpUnreachable << EndOp{}; 83 | } 84 | 85 | Id Module::OpReturnValue(Id value) { 86 | code->Reserve(2); 87 | return *code << spv::Op::OpReturnValue << value << EndOp{}; 88 | } 89 | 90 | void Module::OpKill() { 91 | code->Reserve(1); 92 | *code << spv::Op::OpKill << EndOp{}; 93 | } 94 | 95 | void Module::OpDemoteToHelperInvocation() { 96 | code->Reserve(1); 97 | *code << spv::Op::OpDemoteToHelperInvocation << EndOp{}; 98 | } 99 | 100 | void Module::OpDemoteToHelperInvocationEXT() { 101 | OpDemoteToHelperInvocation(); 102 | } 103 | 104 | void Module::OpTerminateInvocation() { 105 | code->Reserve(1); 106 | *code << spv::Op::OpTerminateInvocation << EndOp{}; 107 | } 108 | 109 | } // namespace Sirit 110 | -------------------------------------------------------------------------------- /src/instructions/function.cpp: -------------------------------------------------------------------------------- 1 | /* This file is part of the sirit project. 2 | * Copyright (c) 2019 sirit 3 | * This software may be used and distributed according to the terms of the 4 | * 3-Clause BSD License 5 | */ 6 | 7 | #include "sirit/sirit.h" 8 | 9 | #include "stream.h" 10 | 11 | namespace Sirit { 12 | 13 | Id Module::OpFunction(Id result_type, spv::FunctionControlMask function_control, Id function_type) { 14 | code->Reserve(5); 15 | return *code << OpId{spv::Op::OpFunction, result_type} << function_control << function_type 16 | << EndOp{}; 17 | } 18 | 19 | void Module::OpFunctionEnd() { 20 | code->Reserve(1); 21 | *code << spv::Op::OpFunctionEnd << EndOp{}; 22 | } 23 | 24 | Id Module::OpFunctionCall(Id result_type, Id function, std::span arguments) { 25 | code->Reserve(4 + arguments.size()); 26 | return *code << OpId{spv::Op::OpFunctionCall, result_type} << function << arguments << EndOp{}; 27 | } 28 | 29 | Id Module::OpFunctionParameter(Id result_type) { 30 | code->Reserve(3); 31 | return *code << OpId{spv::Op::OpFunctionParameter, result_type} << EndOp{}; 32 | } 33 | 34 | } // namespace Sirit 35 | -------------------------------------------------------------------------------- /src/instructions/group.cpp: -------------------------------------------------------------------------------- 1 | /* This file is part of the sirit project. 2 | * Copyright (c) 2019 sirit 3 | * This software may be used and distributed according to the terms of the 4 | * 3-Clause BSD License 5 | */ 6 | 7 | #include "sirit/sirit.h" 8 | 9 | #include "stream.h" 10 | 11 | namespace Sirit { 12 | 13 | Id Module::OpSubgroupBallotKHR(Id result_type, Id predicate) { 14 | code->Reserve(4); 15 | return *code << OpId{spv::Op::OpSubgroupBallotKHR, result_type} << predicate << EndOp{}; 16 | } 17 | 18 | Id Module::OpSubgroupReadInvocationKHR(Id result_type, Id value, Id index) { 19 | code->Reserve(5); 20 | return *code << OpId{spv::Op::OpSubgroupReadInvocationKHR, result_type} << value << index 21 | << EndOp{}; 22 | } 23 | 24 | Id Module::OpSubgroupAllKHR(Id result_type, Id predicate) { 25 | code->Reserve(4); 26 | return *code << OpId{spv::Op::OpSubgroupAllKHR, result_type} << predicate << EndOp{}; 27 | } 28 | 29 | Id Module::OpSubgroupAnyKHR(Id result_type, Id predicate) { 30 | code->Reserve(4); 31 | return *code << OpId{spv::Op::OpSubgroupAnyKHR, result_type} << predicate << EndOp{}; 32 | } 33 | 34 | Id Module::OpSubgroupAllEqualKHR(Id result_type, Id predicate) { 35 | code->Reserve(4); 36 | return *code << OpId{spv::Op::OpSubgroupAllEqualKHR, result_type} << predicate << EndOp{}; 37 | } 38 | 39 | Id Module::OpGroupNonUniformBroadcast(Id result_type, Id scope, Id value, Id id) { 40 | code->Reserve(6); 41 | return *code << OpId{spv::Op::OpGroupNonUniformBroadcast, result_type} << scope << value 42 | << id << EndOp{}; 43 | } 44 | 45 | Id Module::OpGroupNonUniformShuffle(Id result_type, Id scope, Id value, Id id) { 46 | code->Reserve(6); 47 | return *code << OpId{spv::Op::OpGroupNonUniformShuffle, result_type} << scope << value << id 48 | << EndOp{}; 49 | } 50 | 51 | Id Module::OpGroupNonUniformShuffleXor(Id result_type, Id scope, Id value, Id mask) { 52 | code->Reserve(6); 53 | return *code << OpId{spv::Op::OpGroupNonUniformShuffleXor, result_type} << scope << value 54 | << mask << EndOp{}; 55 | } 56 | 57 | Id Module::OpGroupNonUniformAll(Id result_type, Id scope, Id predicate) { 58 | code->Reserve(5); 59 | return *code << OpId{spv::Op::OpGroupNonUniformAll, result_type} << scope << predicate << EndOp{}; 60 | } 61 | 62 | Id Module::OpGroupNonUniformAny(Id result_type, Id scope, Id predicate) { 63 | code->Reserve(5); 64 | return *code << OpId{spv::Op::OpGroupNonUniformAny, result_type} << scope << predicate << EndOp{}; 65 | } 66 | 67 | Id Module::OpGroupNonUniformAllEqual(Id result_type, Id scope, Id value) { 68 | code->Reserve(5); 69 | return *code << OpId{spv::Op::OpGroupNonUniformAllEqual, result_type} << scope << value << EndOp{}; 70 | } 71 | 72 | Id Module::OpGroupNonUniformBallot(Id result_type, Id scope, Id predicate) { 73 | code->Reserve(5); 74 | return *code << OpId{spv::Op::OpGroupNonUniformBallot, result_type} << scope << predicate << EndOp{}; 75 | } 76 | 77 | } // namespace Sirit 78 | -------------------------------------------------------------------------------- /src/instructions/image.cpp: -------------------------------------------------------------------------------- 1 | /* This file is part of the sirit project. 2 | * Copyright (c) 2019 sirit 3 | * This software may be used and distributed according to the terms of the 4 | * 3-Clause BSD License 5 | */ 6 | 7 | #include 8 | 9 | #include "sirit/sirit.h" 10 | 11 | #include "stream.h" 12 | 13 | namespace Sirit { 14 | 15 | #define DEFINE_IMAGE_OP(opcode) \ 16 | Id Module::opcode(Id result_type, Id sampled_image, Id coordinate, \ 17 | std::optional image_operands, \ 18 | std::span operands) { \ 19 | code->Reserve(6 + operands.size()); \ 20 | return *code << OpId{spv::Op::opcode, result_type} << sampled_image << coordinate \ 21 | << image_operands << operands << EndOp{}; \ 22 | } 23 | 24 | #define DEFINE_IMAGE_EXP_OP(opcode) \ 25 | Id Module::opcode(Id result_type, Id sampled_image, Id coordinate, \ 26 | spv::ImageOperandsMask image_operands, std::span operands) { \ 27 | code->Reserve(6 + operands.size()); \ 28 | return *code << OpId{spv::Op::opcode, result_type} << sampled_image << coordinate \ 29 | << image_operands << operands << EndOp{}; \ 30 | } 31 | 32 | #define DEFINE_IMAGE_EXTRA_OP(opcode) \ 33 | Id Module::opcode(Id result_type, Id sampled_image, Id coordinate, Id extra, \ 34 | std::optional image_operands, \ 35 | std::span operands) { \ 36 | code->Reserve(7 + operands.size()); \ 37 | return *code << OpId{spv::Op::opcode, result_type} << sampled_image << coordinate << extra \ 38 | << image_operands << operands << EndOp{}; \ 39 | } 40 | 41 | #define DEFINE_IMAGE_EXTRA_EXP_OP(opcode) \ 42 | Id Module::opcode(Id result_type, Id sampled_image, Id coordinate, Id extra, \ 43 | spv::ImageOperandsMask image_operands, std::span operands) { \ 44 | code->Reserve(8 + operands.size()); \ 45 | return *code << OpId{spv::Op::opcode, result_type} << sampled_image << coordinate << extra \ 46 | << image_operands << operands << EndOp{}; \ 47 | } 48 | 49 | #define DEFINE_IMAGE_QUERY_OP(opcode) \ 50 | Id Module::opcode(Id result_type, Id image) { \ 51 | code->Reserve(5); \ 52 | return *code << OpId{spv::Op::opcode, result_type} << image << EndOp{}; \ 53 | } 54 | 55 | #define DEFINE_IMAGE_QUERY_BIN_OP(opcode) \ 56 | Id Module::opcode(Id result_type, Id image, Id extra) { \ 57 | code->Reserve(5); \ 58 | return *code << OpId{spv::Op::opcode, result_type} << image << extra << EndOp{}; \ 59 | } 60 | 61 | DEFINE_IMAGE_OP(OpImageSampleImplicitLod) 62 | DEFINE_IMAGE_EXP_OP(OpImageSampleExplicitLod) 63 | DEFINE_IMAGE_EXTRA_OP(OpImageSampleDrefImplicitLod) 64 | DEFINE_IMAGE_EXTRA_EXP_OP(OpImageSampleDrefExplicitLod) 65 | DEFINE_IMAGE_OP(OpImageSampleProjImplicitLod) 66 | DEFINE_IMAGE_EXP_OP(OpImageSampleProjExplicitLod) 67 | DEFINE_IMAGE_EXTRA_OP(OpImageSampleProjDrefImplicitLod) 68 | DEFINE_IMAGE_EXTRA_EXP_OP(OpImageSampleProjDrefExplicitLod) 69 | DEFINE_IMAGE_OP(OpImageFetch) 70 | DEFINE_IMAGE_EXTRA_OP(OpImageGather) 71 | DEFINE_IMAGE_EXTRA_OP(OpImageDrefGather) 72 | DEFINE_IMAGE_OP(OpImageRead) 73 | DEFINE_IMAGE_QUERY_BIN_OP(OpImageQuerySizeLod) 74 | DEFINE_IMAGE_QUERY_OP(OpImageQuerySize) 75 | DEFINE_IMAGE_QUERY_BIN_OP(OpImageQueryLod) 76 | DEFINE_IMAGE_QUERY_OP(OpImageQueryLevels) 77 | DEFINE_IMAGE_QUERY_OP(OpImageQuerySamples) 78 | 79 | Id Module::OpSampledImage(Id result_type, Id image, Id sampler) { 80 | code->Reserve(5); 81 | return *code << OpId{spv::Op::OpSampledImage, result_type} << image << sampler << EndOp{}; 82 | } 83 | 84 | Id Module::OpImageWrite(Id image, Id coordinate, Id texel, 85 | std::optional image_operands, 86 | std::span operands) { 87 | assert(image_operands.has_value() != operands.empty()); 88 | code->Reserve(5 + operands.size()); 89 | return *code << spv::Op::OpImageWrite << image << coordinate << texel << image_operands 90 | << operands << EndOp{}; 91 | } 92 | 93 | Id Module::OpImage(Id result_type, Id sampled_image) { 94 | code->Reserve(4); 95 | return *code << OpId{spv::Op::OpImage, result_type} << sampled_image << EndOp{}; 96 | } 97 | 98 | Id Module::OpImageSparseSampleImplicitLod(Id result_type, Id sampled_image, Id coordinate, 99 | std::optional image_operands, 100 | std::span operands) { 101 | code->Reserve(5 + (image_operands.has_value() ? 1 : 0) + operands.size()); 102 | return *code << OpId{spv::Op::OpImageSparseSampleImplicitLod, result_type} << sampled_image 103 | << coordinate << image_operands << operands << EndOp{}; 104 | } 105 | 106 | Id Module::OpImageSparseSampleExplicitLod(Id result_type, Id sampled_image, Id coordinate, 107 | spv::ImageOperandsMask image_operands, 108 | std::span operands) { 109 | code->Reserve(6 + operands.size()); 110 | return *code << OpId{spv::Op::OpImageSparseSampleExplicitLod, result_type} << sampled_image 111 | << coordinate << image_operands << operands << EndOp{}; 112 | } 113 | 114 | Id Module::OpImageSparseSampleDrefImplicitLod(Id result_type, Id sampled_image, Id coordinate, 115 | Id dref, 116 | std::optional image_operands, 117 | std::span operands) { 118 | code->Reserve(6 + (image_operands.has_value() ? 1 : 0) + operands.size()); 119 | return *code << OpId{spv::Op::OpImageSparseSampleDrefImplicitLod, result_type} << sampled_image 120 | << coordinate << dref << image_operands << operands << EndOp{}; 121 | } 122 | 123 | Id Module::OpImageSparseSampleDrefExplicitLod(Id result_type, Id sampled_image, Id coordinate, 124 | Id dref, spv::ImageOperandsMask image_operands, 125 | std::span operands) { 126 | code->Reserve(7 + operands.size()); 127 | return *code << OpId{spv::Op::OpImageSparseSampleDrefExplicitLod, result_type} << sampled_image 128 | << coordinate << dref << image_operands << operands << EndOp{}; 129 | } 130 | 131 | Id Module::OpImageSparseFetch(Id result_type, Id image, Id coordinate, 132 | std::optional image_operands, 133 | std::span operands) { 134 | code->Reserve(5 + (image_operands.has_value() ? 1 : 0) + operands.size()); 135 | return *code << OpId{spv::Op::OpImageSparseFetch, result_type} << image << coordinate 136 | << image_operands << operands << EndOp{}; 137 | } 138 | 139 | Id Module::OpImageSparseGather(Id result_type, Id sampled_image, Id coordinate, Id component, 140 | std::optional image_operands, 141 | std::span operands) { 142 | code->Reserve(6 + operands.size()); 143 | return *code << OpId{spv::Op::OpImageSparseGather, result_type} << sampled_image << coordinate 144 | << component << image_operands << operands << EndOp{}; 145 | } 146 | 147 | Id Module::OpImageSparseDrefGather(Id result_type, Id sampled_image, Id coordinate, Id dref, 148 | std::optional image_operands, 149 | std::span operands) { 150 | code->Reserve(6 + operands.size()); 151 | return *code << OpId{spv::Op::OpImageSparseDrefGather, result_type} << sampled_image 152 | << coordinate << dref << image_operands << operands << EndOp{}; 153 | } 154 | 155 | Id Module::OpImageSparseTexelsResident(Id result_type, Id resident_code) { 156 | code->Reserve(4); 157 | return *code << OpId{spv::Op::OpImageSparseTexelsResident, result_type} << resident_code 158 | << EndOp{}; 159 | } 160 | 161 | Id Module::OpImageSparseRead(Id result_type, Id image, Id coordinate, 162 | std::optional image_operands, 163 | std::span operands) { 164 | code->Reserve(5 + (image_operands.has_value() ? 1 : 0) + operands.size()); 165 | return *code << OpId{spv::Op::OpImageSparseTexelsResident, result_type} << image << coordinate 166 | << image_operands << operands << EndOp{}; 167 | } 168 | 169 | } // namespace Sirit 170 | -------------------------------------------------------------------------------- /src/instructions/logical.cpp: -------------------------------------------------------------------------------- 1 | /* This file is part of the sirit project. 2 | * Copyright (c) 2019 sirit 3 | * This software may be used and distributed according to the terms of the 4 | * 3-Clause BSD License 5 | */ 6 | 7 | #include "sirit/sirit.h" 8 | 9 | #include "stream.h" 10 | 11 | namespace Sirit { 12 | 13 | #define DEFINE_UNARY(opcode) \ 14 | Id Module::opcode(Id result_type, Id operand) { \ 15 | code->Reserve(4); \ 16 | return *code << OpId{spv::Op::opcode, result_type} << operand << EndOp{}; \ 17 | } 18 | 19 | #define DEFINE_BINARY(opcode) \ 20 | Id Module::opcode(Id result_type, Id operand_1, Id operand_2) { \ 21 | code->Reserve(5); \ 22 | return *code << OpId{spv::Op::opcode, result_type} << operand_1 << operand_2 << EndOp{}; \ 23 | } 24 | 25 | #define DEFINE_TRINARY(opcode) \ 26 | Id Module::opcode(Id result_type, Id operand_1, Id operand_2, Id operand_3) { \ 27 | code->Reserve(6); \ 28 | return *code << OpId{spv::Op::opcode, result_type} << operand_1 << operand_2 << operand_3 \ 29 | << EndOp{}; \ 30 | } 31 | 32 | DEFINE_UNARY(OpAny) 33 | DEFINE_UNARY(OpAll) 34 | DEFINE_UNARY(OpIsNan) 35 | DEFINE_UNARY(OpIsInf) 36 | DEFINE_BINARY(OpLogicalEqual) 37 | DEFINE_BINARY(OpLogicalNotEqual) 38 | DEFINE_BINARY(OpLogicalOr) 39 | DEFINE_BINARY(OpLogicalAnd) 40 | DEFINE_UNARY(OpLogicalNot) 41 | DEFINE_TRINARY(OpSelect) 42 | DEFINE_BINARY(OpIEqual) 43 | DEFINE_BINARY(OpINotEqual) 44 | DEFINE_BINARY(OpUGreaterThan) 45 | DEFINE_BINARY(OpSGreaterThan) 46 | DEFINE_BINARY(OpUGreaterThanEqual) 47 | DEFINE_BINARY(OpSGreaterThanEqual) 48 | DEFINE_BINARY(OpULessThan) 49 | DEFINE_BINARY(OpSLessThan) 50 | DEFINE_BINARY(OpULessThanEqual) 51 | DEFINE_BINARY(OpSLessThanEqual) 52 | DEFINE_BINARY(OpFOrdEqual) 53 | DEFINE_BINARY(OpFUnordEqual) 54 | DEFINE_BINARY(OpFOrdNotEqual) 55 | DEFINE_BINARY(OpFUnordNotEqual) 56 | DEFINE_BINARY(OpFOrdLessThan) 57 | DEFINE_BINARY(OpFUnordLessThan) 58 | DEFINE_BINARY(OpFOrdGreaterThan) 59 | DEFINE_BINARY(OpFUnordGreaterThan) 60 | DEFINE_BINARY(OpFOrdLessThanEqual) 61 | DEFINE_BINARY(OpFUnordLessThanEqual) 62 | DEFINE_BINARY(OpFOrdGreaterThanEqual) 63 | DEFINE_BINARY(OpFUnordGreaterThanEqual) 64 | 65 | } // namespace Sirit 66 | -------------------------------------------------------------------------------- /src/instructions/memory.cpp: -------------------------------------------------------------------------------- 1 | /* This file is part of the sirit project. 2 | * Copyright (c) 2019 sirit 3 | * This software may be used and distributed according to the terms of the 4 | * 3-Clause BSD License 5 | */ 6 | 7 | #include 8 | 9 | #include "sirit/sirit.h" 10 | 11 | #include "stream.h" 12 | 13 | namespace Sirit { 14 | 15 | Id Module::OpImageTexelPointer(Id result_type, Id image, Id coordinate, Id sample) { 16 | code->Reserve(6); 17 | return *code << OpId{spv::Op::OpImageTexelPointer, result_type} << image << coordinate << sample 18 | << EndOp{}; 19 | } 20 | 21 | Id Module::OpLoad(Id result_type, Id pointer, std::optional memory_access) { 22 | code->Reserve(5); 23 | return *code << OpId{spv::Op::OpLoad, result_type} << pointer << memory_access << EndOp{}; 24 | } 25 | 26 | Id Module::OpStore(Id pointer, Id object, std::optional memory_access) { 27 | code->Reserve(4); 28 | return *code << spv::Op::OpStore << pointer << object << memory_access << EndOp{}; 29 | } 30 | 31 | Id Module::OpAccessChain(Id result_type, Id base, std::span indexes) { 32 | assert(!indexes.empty()); 33 | code->Reserve(4 + indexes.size()); 34 | return *code << OpId{spv::Op::OpAccessChain, result_type} << base << indexes << EndOp{}; 35 | } 36 | 37 | Id Module::OpVectorExtractDynamic(Id result_type, Id vector, Id index) { 38 | code->Reserve(5); 39 | return *code << OpId{spv::Op::OpVectorExtractDynamic, result_type} << vector << index 40 | << EndOp{}; 41 | } 42 | 43 | Id Module::OpVectorInsertDynamic(Id result_type, Id vector, Id component, Id index) { 44 | code->Reserve(6); 45 | return *code << OpId{spv::Op::OpVectorInsertDynamic, result_type} << vector << component 46 | << index << EndOp{}; 47 | } 48 | 49 | Id Module::OpCompositeInsert(Id result_type, Id object, Id composite, 50 | std::span indexes) { 51 | code->Reserve(5 + indexes.size()); 52 | return *code << OpId{spv::Op::OpCompositeInsert, result_type} << object << composite << indexes 53 | << EndOp{}; 54 | } 55 | 56 | Id Module::OpCompositeExtract(Id result_type, Id composite, std::span indexes) { 57 | code->Reserve(4 + indexes.size()); 58 | return *code << OpId{spv::Op::OpCompositeExtract, result_type} << composite << indexes 59 | << EndOp{}; 60 | } 61 | 62 | Id Module::OpCompositeConstruct(Id result_type, std::span ids) { 63 | assert(ids.size() >= 1); 64 | code->Reserve(3 + ids.size()); 65 | return *code << OpId{spv::Op::OpCompositeConstruct, result_type} << ids << EndOp{}; 66 | } 67 | 68 | } // namespace Sirit 69 | -------------------------------------------------------------------------------- /src/instructions/misc.cpp: -------------------------------------------------------------------------------- 1 | /* This file is part of the sirit project. 2 | * Copyright (c) 2019 sirit 3 | * This software may be used and distributed according to the terms of the 4 | * 3-Clause BSD License 5 | */ 6 | 7 | #include "sirit/sirit.h" 8 | 9 | #include "stream.h" 10 | 11 | namespace Sirit { 12 | 13 | Id Module::OpUndef(Id result_type) { 14 | code->Reserve(3); 15 | return *code << OpId{spv::Op::OpUndef, result_type} << EndOp{}; 16 | } 17 | 18 | void Module::OpEmitVertex() { 19 | code->Reserve(1); 20 | *code << spv::Op::OpEmitVertex << EndOp{}; 21 | } 22 | 23 | void Module::OpEndPrimitive() { 24 | code->Reserve(1); 25 | *code << spv::Op::OpEndPrimitive << EndOp{}; 26 | } 27 | 28 | void Module::OpEmitStreamVertex(Id stream) { 29 | code->Reserve(2); 30 | *code << spv::Op::OpEmitStreamVertex << stream << EndOp{}; 31 | } 32 | 33 | void Module::OpEndStreamPrimitive(Id stream) { 34 | code->Reserve(2); 35 | *code << spv::Op::OpEndStreamPrimitive << stream << EndOp{}; 36 | } 37 | 38 | } // namespace Sirit 39 | -------------------------------------------------------------------------------- /src/instructions/type.cpp: -------------------------------------------------------------------------------- 1 | /* This file is part of the sirit project. 2 | * Copyright (c) 2019 sirit 3 | * This software may be used and distributed according to the terms of the 4 | * 3-Clause BSD License 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #include "sirit/sirit.h" 11 | 12 | #include "stream.h" 13 | 14 | namespace Sirit { 15 | 16 | Id Module::TypeVoid() { 17 | declarations->Reserve(2); 18 | return *declarations << OpId{spv::Op::OpTypeVoid} << EndOp{}; 19 | } 20 | 21 | Id Module::TypeBool() { 22 | declarations->Reserve(2); 23 | return *declarations << OpId{spv::Op::OpTypeBool} << EndOp{}; 24 | } 25 | 26 | Id Module::TypeInt(int width, bool is_signed) { 27 | declarations->Reserve(4); 28 | return *declarations << OpId{spv::Op::OpTypeInt} << width << is_signed << EndOp{}; 29 | } 30 | 31 | Id Module::TypeSInt(int width) { 32 | return TypeInt(width, true); 33 | } 34 | 35 | Id Module::TypeUInt(int width) { 36 | return TypeInt(width, false); 37 | } 38 | 39 | Id Module::TypeFloat(int width) { 40 | declarations->Reserve(3); 41 | return *declarations << OpId{spv::Op::OpTypeFloat} << width << EndOp{}; 42 | } 43 | 44 | Id Module::TypeVector(Id component_type, int component_count) { 45 | assert(component_count >= 2); 46 | declarations->Reserve(4); 47 | return *declarations << OpId{spv::Op::OpTypeVector} << component_type << component_count 48 | << EndOp{}; 49 | } 50 | 51 | Id Module::TypeMatrix(Id column_type, int column_count) { 52 | assert(column_count >= 2); 53 | declarations->Reserve(4); 54 | return *declarations << OpId{spv::Op::OpTypeMatrix} << column_type << column_count << EndOp{}; 55 | } 56 | 57 | Id Module::TypeImage(Id sampled_type, spv::Dim dim, int depth, bool arrayed, bool ms, int sampled, 58 | spv::ImageFormat image_format, 59 | std::optional access_qualifier) { 60 | declarations->Reserve(10); 61 | return *declarations << OpId{spv::Op::OpTypeImage} << sampled_type << dim << depth << arrayed 62 | << ms << sampled << image_format << access_qualifier << EndOp{}; 63 | } 64 | 65 | Id Module::TypeSampler() { 66 | declarations->Reserve(2); 67 | return *declarations << OpId{spv::Op::OpTypeSampler} << EndOp{}; 68 | } 69 | 70 | Id Module::TypeSampledImage(Id image_type) { 71 | declarations->Reserve(3); 72 | return *declarations << OpId{spv::Op::OpTypeSampledImage} << image_type << EndOp{}; 73 | } 74 | 75 | Id Module::TypeArray(Id element_type, Id length) { 76 | declarations->Reserve(4); 77 | return *declarations << OpId{spv::Op::OpTypeArray} << element_type << length << EndOp{}; 78 | } 79 | 80 | Id Module::TypeRuntimeArray(Id element_type) { 81 | declarations->Reserve(3); 82 | return *declarations << OpId{spv::Op::OpTypeRuntimeArray} << element_type << EndOp{}; 83 | } 84 | 85 | Id Module::TypeStruct(std::span members) { 86 | declarations->Reserve(2 + members.size()); 87 | return *declarations << OpId{spv::Op::OpTypeStruct} << members << EndOp{}; 88 | } 89 | 90 | Id Module::TypeOpaque(std::string_view name) { 91 | declarations->Reserve(3 + WordsInString(name)); 92 | return *declarations << OpId{spv::Op::OpTypeOpaque} << name << EndOp{}; 93 | } 94 | 95 | Id Module::TypePointer(spv::StorageClass storage_class, Id type) { 96 | declarations->Reserve(4); 97 | return *declarations << OpId{spv::Op::OpTypePointer} << storage_class << type << EndOp{}; 98 | } 99 | 100 | Id Module::TypeFunction(Id return_type, std::span arguments) { 101 | declarations->Reserve(3 + arguments.size()); 102 | return *declarations << OpId{spv::Op::OpTypeFunction} << return_type << arguments << EndOp{}; 103 | } 104 | 105 | Id Module::TypeEvent() { 106 | declarations->Reserve(2); 107 | return *declarations << OpId{spv::Op::OpTypeEvent} << EndOp{}; 108 | } 109 | 110 | Id Module::TypeDeviceEvent() { 111 | declarations->Reserve(2); 112 | return *declarations << OpId{spv::Op::OpTypeDeviceEvent} << EndOp{}; 113 | } 114 | 115 | Id Module::TypeReserveId() { 116 | declarations->Reserve(2); 117 | return *declarations << OpId{spv::Op::OpTypeReserveId} << EndOp{}; 118 | } 119 | 120 | Id Module::TypeQueue() { 121 | declarations->Reserve(2); 122 | return *declarations << OpId{spv::Op::OpTypeQueue} << EndOp{}; 123 | } 124 | 125 | Id Module::TypePipe(spv::AccessQualifier access_qualifier) { 126 | declarations->Reserve(2); 127 | return *declarations << OpId{spv::Op::OpTypePipe} << access_qualifier << EndOp{}; 128 | } 129 | 130 | } // namespace Sirit 131 | -------------------------------------------------------------------------------- /src/sirit.cpp: -------------------------------------------------------------------------------- 1 | /* This file is part of the sirit project. 2 | * Copyright (c) 2019 sirit 3 | * This software may be used and distributed according to the terms of the 4 | * 3-Clause BSD License 5 | */ 6 | 7 | #include 8 | 9 | #include "sirit/sirit.h" 10 | 11 | #include "common_types.h" 12 | #include "stream.h" 13 | 14 | namespace Sirit { 15 | 16 | constexpr u32 MakeWord0(spv::Op op, size_t word_count) { 17 | return static_cast(op) | static_cast(word_count) << 16; 18 | } 19 | 20 | Module::Module(u32 version_) 21 | : version{version_}, ext_inst_imports{std::make_unique(&bound)}, 22 | entry_points{std::make_unique(&bound)}, 23 | execution_modes{std::make_unique(&bound)}, debug{std::make_unique(&bound)}, 24 | annotations{std::make_unique(&bound)}, declarations{std::make_unique( 25 | &bound)}, 26 | global_variables{std::make_unique(&bound)}, code{std::make_unique(&bound)} {} 27 | 28 | Module::~Module() = default; 29 | 30 | std::vector Module::Assemble() const { 31 | std::vector words = {spv::MagicNumber, version, GENERATOR_MAGIC_NUMBER, bound + 1, 0}; 32 | const auto insert = [&words](std::span input) { 33 | words.insert(words.end(), input.begin(), input.end()); 34 | }; 35 | 36 | words.reserve(words.size() + capabilities.size() * 2); 37 | for (const spv::Capability capability : capabilities) { 38 | insert(std::array{ 39 | MakeWord0(spv::Op::OpCapability, 2), 40 | static_cast(capability), 41 | }); 42 | } 43 | 44 | for (const std::string_view extension_name : extensions) { 45 | size_t string_words = WordsInString(extension_name); 46 | words.push_back(MakeWord0(spv::Op::OpExtension, string_words + 1)); 47 | size_t insert_index = words.size(); 48 | words.resize(words.size() + string_words); 49 | InsertStringView(words, insert_index, extension_name); 50 | } 51 | 52 | insert(ext_inst_imports->Words()); 53 | 54 | insert(std::array{ 55 | MakeWord0(spv::Op::OpMemoryModel, 3), 56 | static_cast(addressing_model), 57 | static_cast(memory_model), 58 | }); 59 | 60 | insert(entry_points->Words()); 61 | insert(execution_modes->Words()); 62 | insert(debug->Words()); 63 | insert(annotations->Words()); 64 | insert(declarations->Words()); 65 | insert(global_variables->Words()); 66 | insert(code->Words()); 67 | 68 | return words; 69 | } 70 | 71 | void Module::PatchDeferredPhi(const std::function& func) { 72 | for (const u32 phi_index : deferred_phi_nodes) { 73 | const u32 first_word = code->Value(phi_index); 74 | [[maybe_unused]] const spv::Op op = static_cast(first_word & 0xffff); 75 | assert(op == spv::Op::OpPhi); 76 | const u32 num_words = first_word >> 16; 77 | const u32 num_args = (num_words - 3) / 2; 78 | u32 cursor = phi_index + 3; 79 | for (u32 arg = 0; arg < num_args; ++arg, cursor += 2) { 80 | code->SetValue(cursor, func(arg).value); 81 | } 82 | } 83 | } 84 | 85 | void Module::AddExtension(std::string extension_name) { 86 | extensions.insert(std::move(extension_name)); 87 | } 88 | 89 | void Module::AddCapability(spv::Capability capability) { 90 | capabilities.insert(capability); 91 | } 92 | 93 | void Module::SetMemoryModel(spv::AddressingModel addressing_model_, 94 | spv::MemoryModel memory_model_) { 95 | addressing_model = addressing_model_; 96 | memory_model = memory_model_; 97 | } 98 | 99 | void Module::AddEntryPoint(spv::ExecutionModel execution_model, Id entry_point, 100 | std::string_view name, std::span interfaces) { 101 | entry_points->Reserve(4 + WordsInString(name) + interfaces.size()); 102 | *entry_points << spv::Op::OpEntryPoint << execution_model << entry_point << name << interfaces 103 | << EndOp{}; 104 | } 105 | 106 | void Module::AddExecutionMode(Id entry_point, spv::ExecutionMode mode, 107 | std::span literals) { 108 | execution_modes->Reserve(3 + literals.size()); 109 | *execution_modes << spv::Op::OpExecutionMode << entry_point << mode << literals << EndOp{}; 110 | } 111 | 112 | Id Module::AddLabel(Id label) { 113 | assert(label.value != 0); 114 | code->Reserve(2); 115 | *code << MakeWord0(spv::Op::OpLabel, 2) << label.value; 116 | return label; 117 | } 118 | 119 | Id Module::AddLocalVariable(Id result_type, spv::StorageClass storage_class, 120 | std::optional initializer) { 121 | code->Reserve(5); 122 | return *code << OpId{spv::Op::OpVariable, result_type} << storage_class << initializer 123 | << EndOp{}; 124 | } 125 | 126 | Id Module::AddGlobalVariable(Id result_type, spv::StorageClass storage_class, 127 | std::optional initializer) { 128 | global_variables->Reserve(5); 129 | return *global_variables << OpId{spv::Op::OpVariable, result_type} << storage_class 130 | << initializer << EndOp{}; 131 | } 132 | 133 | Id Module::GetGLSLstd450() { 134 | if (!glsl_std_450) { 135 | ext_inst_imports->Reserve(3 + 4); 136 | glsl_std_450 = *ext_inst_imports << OpId{spv::Op::OpExtInstImport} << "GLSL.std.450" 137 | << EndOp{}; 138 | } 139 | return *glsl_std_450; 140 | } 141 | 142 | } // namespace Sirit 143 | -------------------------------------------------------------------------------- /src/stream.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReinUsesLisp/sirit/d7ad93a88864bda94e282e95028f90b5784e4d20/src/stream.cpp -------------------------------------------------------------------------------- /src/stream.h: -------------------------------------------------------------------------------- 1 | /* This file is part of the sirit project. 2 | * Copyright (c) 2019 sirit 3 | * This software may be used and distributed according to the terms of the 4 | * 3-Clause BSD License 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #ifndef __cpp_lib_bit_cast 21 | #include 22 | #endif 23 | 24 | #include 25 | 26 | #include "common_types.h" 27 | 28 | namespace Sirit { 29 | 30 | class Declarations; 31 | 32 | struct OpId { 33 | OpId(spv::Op opcode_) : opcode{opcode_} {} 34 | OpId(spv::Op opcode_, Id result_type_) : opcode{opcode_}, result_type{result_type_} { 35 | assert(result_type.value != 0); 36 | } 37 | 38 | spv::Op opcode{}; 39 | Id result_type{}; 40 | }; 41 | 42 | struct EndOp {}; 43 | 44 | inline size_t WordsInString(std::string_view string) { 45 | return string.size() / sizeof(u32) + 1; 46 | } 47 | 48 | inline void InsertStringView(std::vector& words, size_t& insert_index, 49 | std::string_view string) { 50 | const size_t size = string.size(); 51 | const auto read = [string, size](size_t offset) { 52 | return offset < size ? static_cast(string[offset]) : 0u; 53 | }; 54 | 55 | for (size_t i = 0; i < size; i += sizeof(u32)) { 56 | words[insert_index++] = read(i) | read(i + 1) << 8 | read(i + 2) << 16 | read(i + 3) << 24; 57 | } 58 | if (size % sizeof(u32) == 0) { 59 | words[insert_index++] = 0; 60 | } 61 | } 62 | 63 | class Stream { 64 | friend Declarations; 65 | 66 | public: 67 | explicit Stream(u32* bound_) : bound{bound_} {} 68 | 69 | void Reserve(size_t num_words) { 70 | if (insert_index + num_words <= words.size()) { 71 | return; 72 | } 73 | words.resize(insert_index + num_words); 74 | } 75 | 76 | std::span Words() const noexcept { 77 | return std::span(words.data(), insert_index); 78 | } 79 | 80 | u32 LocalAddress() const noexcept { 81 | return static_cast(words.size()); 82 | } 83 | 84 | u32 Value(u32 index) const noexcept { 85 | return words[index]; 86 | } 87 | 88 | void SetValue(u32 index, u32 value) noexcept { 89 | words[index] = value; 90 | } 91 | 92 | Stream& operator<<(spv::Op op) { 93 | op_index = insert_index; 94 | words[insert_index++] = static_cast(op); 95 | return *this; 96 | } 97 | 98 | Stream& operator<<(OpId op) { 99 | op_index = insert_index; 100 | words[insert_index++] = static_cast(op.opcode); 101 | if (op.result_type.value != 0) { 102 | words[insert_index++] = op.result_type.value; 103 | } 104 | words[insert_index++] = ++*bound; 105 | return *this; 106 | } 107 | 108 | Id operator<<(EndOp) { 109 | const size_t num_words = insert_index - op_index; 110 | words[op_index] |= static_cast(num_words) << 16; 111 | return Id{*bound}; 112 | } 113 | 114 | Stream& operator<<(u32 value) { 115 | words[insert_index++] = value; 116 | return *this; 117 | } 118 | 119 | Stream& operator<<(s32 value) { 120 | return *this << static_cast(value); 121 | } 122 | 123 | Stream& operator<<(u64 value) { 124 | return *this << static_cast(value) << static_cast(value >> 32); 125 | } 126 | 127 | Stream& operator<<(s64 value) { 128 | return *this << static_cast(value); 129 | } 130 | 131 | Stream& operator<<(float value) { 132 | #ifdef __cpp_lib_bit_cast 133 | return *this << std::bit_cast(value); 134 | #else 135 | static_assert(sizeof(float) == sizeof(u32)); 136 | u32 int_value; 137 | std::memcpy(&int_value, &value, sizeof(int_value)); 138 | return *this << int_value; 139 | #endif 140 | } 141 | 142 | Stream& operator<<(double value) { 143 | #ifdef __cpp_lib_bit_cast 144 | return *this << std::bit_cast(value); 145 | #else 146 | static_assert(sizeof(double) == sizeof(u64)); 147 | u64 int_value; 148 | std::memcpy(&int_value, &value, sizeof(int_value)); 149 | return *this << int_value; 150 | #endif 151 | } 152 | 153 | Stream& operator<<(bool value) { 154 | return *this << static_cast(value ? 1 : 0); 155 | } 156 | 157 | Stream& operator<<(Id value) { 158 | assert(value.value != 0); 159 | return *this << value.value; 160 | } 161 | 162 | Stream& operator<<(const Literal& literal) { 163 | std::visit([this](auto value) { *this << value; }, literal); 164 | return *this; 165 | } 166 | 167 | Stream& operator<<(std::string_view string) { 168 | InsertStringView(words, insert_index, string); 169 | return *this; 170 | } 171 | 172 | Stream& operator<<(const char* string) { 173 | return *this << std::string_view{string}; 174 | } 175 | 176 | template 177 | requires std::is_enum_v Stream& operator<<(T value) { 178 | static_assert(sizeof(T) == sizeof(u32)); 179 | return *this << static_cast(value); 180 | } 181 | 182 | template 183 | Stream& operator<<(std::optional value) { 184 | if (value) { 185 | *this << *value; 186 | } 187 | return *this; 188 | } 189 | 190 | template 191 | Stream& operator<<(std::span values) { 192 | for (const auto& value : values) { 193 | *this << value; 194 | } 195 | return *this; 196 | } 197 | 198 | private: 199 | u32* bound = nullptr; 200 | std::vector words; 201 | size_t insert_index = 0; 202 | size_t op_index = 0; 203 | }; 204 | 205 | class Declarations { 206 | public: 207 | explicit Declarations(u32* bound) : stream{bound} {} 208 | 209 | void Reserve(size_t num_words) { 210 | return stream.Reserve(num_words); 211 | } 212 | 213 | std::span Words() const noexcept { 214 | return stream.Words(); 215 | } 216 | 217 | template 218 | Declarations& operator<<(const T& value) { 219 | stream << value; 220 | return *this; 221 | } 222 | 223 | // Declarations without an id don't exist 224 | Declarations& operator<<(spv::Op) = delete; 225 | 226 | Declarations& operator<<(OpId op) { 227 | id_index = op.result_type.value != 0 ? 2 : 1; 228 | stream << op; 229 | return *this; 230 | } 231 | 232 | Id operator<<(EndOp) { 233 | const auto begin = stream.words.data(); 234 | std::vector declarations(begin + stream.op_index, begin + stream.insert_index); 235 | 236 | // Normalize result id for lookups 237 | const u32 id = std::exchange(declarations[id_index], 0); 238 | 239 | const auto [entry, inserted] = existing_declarations.emplace(declarations, id); 240 | if (inserted) { 241 | return stream << EndOp{}; 242 | } 243 | // If the declaration already exists, undo the operation 244 | stream.insert_index = stream.op_index; 245 | --*stream.bound; 246 | 247 | return Id{entry->second}; 248 | } 249 | 250 | private: 251 | struct HashVector { 252 | size_t operator()(const std::vector& vector) const noexcept { 253 | size_t hash = std::hash{}(vector.size()); 254 | for (const u32 value : vector) { 255 | hash ^= std::hash{}(value); 256 | } 257 | return hash; 258 | } 259 | }; 260 | 261 | Stream stream; 262 | std::unordered_map, u32, HashVector> existing_declarations; 263 | size_t id_index = 0; 264 | }; 265 | 266 | } // namespace Sirit 267 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(sirit_tests 2 | main.cpp) 3 | target_link_libraries(sirit_tests PRIVATE sirit) 4 | target_include_directories(sirit_tests PRIVATE . ../include) 5 | 6 | add_test(sirit_tests sirit_tests) 7 | -------------------------------------------------------------------------------- /tests/main.cpp: -------------------------------------------------------------------------------- 1 | /* This file is part of the sirit project. 2 | * Copyright (c) 2019 sirit 3 | * This software may be used and distributed according to the terms of the 4 | * 3-Clause BSD License 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | class MyModule : public Sirit::Module { 14 | public: 15 | MyModule() : Sirit::Module{0x00010300} {} 16 | ~MyModule() = default; 17 | 18 | void Generate() { 19 | AddCapability(spv::Capability::Shader); 20 | SetMemoryModel(spv::AddressingModel::Logical, spv::MemoryModel::GLSL450); 21 | 22 | const auto t_void = Name(TypeVoid(), "void"); 23 | const auto t_uint = Name(TypeInt(32, false), "uint"); 24 | const auto t_float = Name(TypeFloat(32), "float"); 25 | 26 | const auto float4 = Name(TypeVector(t_float, 4), "float4"); 27 | const auto in_float = Name(TypePointer(spv::StorageClass::Input, t_float), "in_float"); 28 | const auto in_float4 = Name(TypePointer(spv::StorageClass::Input, float4), "in_float4"); 29 | const auto out_float4 = Name(TypePointer(spv::StorageClass::Output, float4), "out_float4"); 30 | 31 | const auto gl_per_vertex = Name(TypeStruct(float4), "gl_PerVertex"); 32 | const auto gl_per_vertex_ptr = 33 | Name(TypePointer(spv::StorageClass::Output, gl_per_vertex), "out_gl_PerVertex"); 34 | 35 | const auto in_pos = Name(AddGlobalVariable(in_float4, spv::StorageClass::Input), "in_pos"); 36 | const auto per_vertex = 37 | Name(AddGlobalVariable(gl_per_vertex_ptr, spv::StorageClass::Output), "per_vertex"); 38 | 39 | Decorate(in_pos, spv::Decoration::Location, 0); 40 | Decorate(gl_per_vertex, spv::Decoration::Block); 41 | Decorate(gl_per_vertex, spv::Decoration::Block); 42 | MemberDecorate(gl_per_vertex, 0, spv::Decoration::BuiltIn, 43 | static_cast(spv::BuiltIn::Position)); 44 | 45 | const auto main_func = Name( 46 | OpFunction(t_void, spv::FunctionControlMask::MaskNone, TypeFunction(t_void)), "main"); 47 | AddLabel(); 48 | 49 | const auto ptr_pos_x = OpAccessChain(in_float, in_pos, Constant(t_uint, 0u)); 50 | const auto ptr_pos_y = OpAccessChain(in_float, in_pos, Constant(t_uint, 1u)); 51 | 52 | const auto pos_x = OpLoad(t_float, ptr_pos_x); 53 | const auto pos_y = OpLoad(t_float, ptr_pos_y); 54 | 55 | auto tmp_position = OpUndef(float4); 56 | tmp_position = OpCompositeInsert(float4, pos_x, tmp_position, 0); 57 | tmp_position = OpCompositeInsert(float4, pos_y, tmp_position, 1); 58 | tmp_position = OpCompositeInsert(float4, Constant(t_float, 0.0f), tmp_position, 2); 59 | tmp_position = OpCompositeInsert(float4, Constant(t_float, 1.0f), tmp_position, 3); 60 | 61 | const auto gl_position = OpAccessChain(out_float4, per_vertex, Constant(t_uint, 0u)); 62 | OpStore(gl_position, tmp_position); 63 | 64 | OpReturn(); 65 | OpFunctionEnd(); 66 | 67 | AddEntryPoint(spv::ExecutionModel::Vertex, main_func, "main", in_pos, per_vertex); 68 | } 69 | }; 70 | 71 | static constexpr std::uint8_t expected_binary[] = { 72 | 0x03, 0x02, 0x23, 0x07, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 73 | 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 74 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 75 | 0x0d, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 76 | 0x0b, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x76, 0x6f, 0x69, 0x64, 77 | 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x75, 0x69, 0x6e, 0x74, 78 | 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x03, 0x00, 0x00, 0x00, 0x66, 0x6c, 0x6f, 0x61, 79 | 0x74, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x66, 0x6c, 0x6f, 0x61, 80 | 0x74, 0x34, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x5f, 0x66, 81 | 0x6c, 0x6f, 0x61, 0x74, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 82 | 0x69, 0x6e, 0x5f, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x34, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 83 | 0x07, 0x00, 0x00, 0x00, 0x6f, 0x75, 0x74, 0x5f, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x34, 0x00, 0x00, 84 | 0x05, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00, 0x67, 0x6c, 0x5f, 0x50, 0x65, 0x72, 0x56, 0x65, 85 | 0x72, 0x74, 0x65, 0x78, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x07, 0x00, 0x09, 0x00, 0x00, 0x00, 86 | 0x6f, 0x75, 0x74, 0x5f, 0x67, 0x6c, 0x5f, 0x50, 0x65, 0x72, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 87 | 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x5f, 0x70, 88 | 0x6f, 0x73, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x70, 0x65, 0x72, 0x5f, 89 | 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 90 | 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, 91 | 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00, 92 | 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 93 | 0x48, 0x00, 0x05, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 94 | 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 95 | 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, 96 | 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 97 | 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x05, 0x00, 0x00, 0x00, 98 | 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 99 | 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 100 | 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00, 101 | 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 102 | 0x08, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 103 | 0x2b, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 104 | 0x2b, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 105 | 0x2b, 0x00, 0x04, 0x00, 0x03, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 106 | 0x2b, 0x00, 0x04, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 107 | 0x3b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 108 | 0x3b, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 109 | 0x36, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 110 | 0x0c, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 111 | 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 112 | 0x41, 0x00, 0x05, 0x00, 0x05, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 113 | 0x11, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x03, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 114 | 0x10, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x03, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 115 | 0x12, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 116 | 0x52, 0x00, 0x06, 0x00, 0x04, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 117 | 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x00, 0x06, 0x00, 0x04, 0x00, 0x00, 0x00, 118 | 0x17, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 119 | 0x52, 0x00, 0x06, 0x00, 0x04, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 120 | 0x17, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x52, 0x00, 0x06, 0x00, 0x04, 0x00, 0x00, 0x00, 121 | 0x1b, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 122 | 0x41, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 123 | 0x0f, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 124 | 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00, 125 | }; 126 | 127 | int main(int argc, char** argv) { 128 | MyModule module; 129 | module.Generate(); 130 | 131 | std::vector code = module.Assemble(); 132 | if (std::size(code) * sizeof(std::uint32_t) != std::size(expected_binary)) { 133 | return EXIT_FAILURE; 134 | } 135 | if (std::memcmp(std::data(code), std::data(expected_binary), std::size(expected_binary)) != 0) { 136 | return EXIT_FAILURE; 137 | } 138 | return EXIT_SUCCESS; 139 | } 140 | --------------------------------------------------------------------------------