├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── LICENSE.txt ├── README.md ├── SPIRVGen ├── SPIRVAssembler.cpp ├── SPIRVAssembler.h ├── SPIRVBinaryDefines.h ├── SPIRVBranchOperations.h ├── SPIRVComplex.h ├── SPIRVConstant.cpp ├── SPIRVConstant.h ├── SPIRVDecoration.cpp ├── SPIRVDecoration.h ├── SPIRVExtensionAMD.h ├── SPIRVInlineAssembler.h ├── SPIRVInstruction.cpp ├── SPIRVInstruction.h ├── SPIRVInterop.h ├── SPIRVModule.cpp ├── SPIRVModule.h ├── SPIRVOperation.cpp ├── SPIRVOperation.h ├── SPIRVOperatorImpl.h ├── SPIRVProgram.h ├── SPIRVQuaternion.h ├── SPIRVType.cpp ├── SPIRVType.h ├── SPIRVVariable.cpp ├── SPIRVVariable.h ├── SPIRVVariableTypeDefs.h ├── SPIRVVariableTypes.h └── SPIRVVectorComponentAccess.h ├── SPIRVGenTest ├── DeferredLightingExample.h ├── ExampleProg.h ├── GenerateSwizzleHeader.h └── main.cpp ├── SPIRVShaderFactory ├── CSGExampleShader.h ├── CSGObject.h ├── CameraFunctions.h ├── ClearColor.h ├── CommonBufferSourceNames.h ├── DefaultShaderFactory.cpp ├── DefaultShaderFactory.h ├── DefaultShaderIdentifiers.h ├── IShaderFactory.h ├── LightingFunctions.h ├── Mandelbrot.h ├── MaterialInterface.h ├── MathFunctions.h ├── MicrofacetReflection.h ├── PhongMaterial.h ├── SDFObject.h ├── ScreenSpaceTriangle.h ├── ShaderID.h └── SimpleCSGRayMarching.h └── misc ├── Paper.pdf ├── Slides.pdf ├── fractal.png └── vs_shader_dbg.png /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | libs/boost 3 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "libs/hlx"] 2 | path = libs/hlx 3 | url = https://github.com/rAzoR8/hlx 4 | [submodule "libs/glm"] 5 | path = libs/glm 6 | url = https://github.com/g-truc/glm.git 7 | [submodule "libs/spirv-tools"] 8 | path = libs/spirv-tools 9 | url = https://github.com/KhronosGroup/SPIRV-Tools.git 10 | [submodule "libs/spirv-headers"] 11 | path = libs/spirv-headers 12 | url = https://github.com/KhronosGroup/SPIRV-Headers.git 13 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPEAR: C++/SPIR-V Shader Runtime 2 | # https://github.com/razor8/SPEAR/ 3 | # 4 | # Building: create an out-of-source build directory, e.g. `build`, and go to it. 5 | # Call `cmake ..` and provide any extra configuration settings you might need to 6 | # make it work. All configs that can be given are shown below and in the README: 7 | # 8 | # SPEAR_ENABLE_PROPERTIES = ON | OFF (default: ON) 9 | # Many convenience facilities are based on __declspec(property), and are not 10 | # available on e.g. gcc. However, the library can be used without them fine. 11 | # 12 | # SPEAR_BUILD_TESTBED = ON | OFF (default: ON) 13 | # Also build the accompanying example project, depending on the libSPEARGen. 14 | # This gets you an executable e.g SPEARGenTest that you can (hopefully) run. 15 | # 16 | # SPEAR_BUILD_SHADER_FACTORY = ON | OFF (default: ON) 17 | # Also build the dynamic shader library project and links it to libSPEARGen, 18 | # which will be a shared library called libSPEARShaderFactory.so on Unix-es. 19 | # 20 | # After this CMake should have generated target-specific build files in `build`. 21 | # If the target was GNU Make you should call `make` (and probably give -j8 too), 22 | # and if your target is a Visual Studio solution, just open it and compile this. 23 | # 24 | # Acknowledgements: heavily inspired by the Vulkan/CMakeLists & glfw/CMakeLists. 25 | # Note: this script was written by Erik S. V. Jansson 26 | # and is neither general or pretty, if you can, consider contributing. This file 27 | # is released under the same license as the rest of the SPEAR project, as below: 28 | # 29 | # Permission is hereby granted, free of charge, to any person obtaining a copy 30 | # of this software and associated documentation files (the "Software"), to deal 31 | # in the Software without restriction, including without limitation the rights 32 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 33 | # copies of the Software, and to permit persons to whom the Software is 34 | # furnished to do so, subject to the following conditions: 35 | # 36 | # The above copyright notice and this permission notice shall be included in all 37 | # copies or substantial portions of the Software. Naming the author(s) of this 38 | # software in any of the following locations: About page, README file, credits. 39 | # 40 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 41 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 42 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 43 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 44 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 45 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 46 | # SOFTWARE. 47 | 48 | cmake_minimum_required(VERSION 3.8) 49 | 50 | project(SPEAR VERSION 1.0 LANGUAGES CXX DESCRIPTION "C++/SPIR-V Shader Runtime") 51 | set(CMAKE_CXX_STANDARD 17) 52 | 53 | include(GNUInstallDirs) 54 | 55 | set(SPEAR_VERSION_MAJOR "1") 56 | set(SPEAR_VERSION_MINOR "0") 57 | set(SPEAR_VERSION "${SPEAR_VERSION_MAJOR}.${SPEAR_VERSION_MINOR}") 58 | 59 | #set(ENV{SPEAR_SDK} ${CMAKE_CURRENT_SOURCE_DIR}) 60 | #message("Setting environment variable SPEAR_SDK: $ENV{SPEAR_SDK}") 61 | 62 | option(SPEAR_BUILD_TESTBED "Builds the SPEAR project testbed." ON) 63 | option(SPEAR_BUILD_SHADER_FACTORY "Builds the dynamic shader loader." ON) 64 | option(SPEAR_ENABLE_PROPERTIES "Enable optional property generation." ON) 65 | if(SPEAR_ENABLE_PROPERTIES) # Conditionally removes _declspec(properties)! 66 | add_definitions(-DSPEAR_ENABLE_PROPERTIES) 67 | endif() 68 | 69 | find_package(Vulkan REQUIRED) # Maybe constrain this to 1.0 since we have 1.1. 70 | 71 | if(NOT Vulkan_FOUND) 72 | if (WIN32) 73 | # Shamelessly snatched from Vulkan/CMakeLists, tries to find Vulkan's library elsewhere. 74 | find_library(Vulkan_LIBRARY NAMES vulkan-1 vulkan PATHS ${CMAKE_SOURCE_DIR}/libs/vulkan) 75 | if(Vulkan_LIBRARY) 76 | set(Vulkan_FOUND ON) 77 | MESSAGE("Using local Vulkan library.") 78 | endif() 79 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DVK_USE_PLATFORM_WIN32_KHR") 80 | else() 81 | find_library(Vulkan_LIBRARY NAMES vulkan HINTS "$ENV{VULKAN_SDK}/lib" "${CMAKE_SOURCE_DIR}/libs/vulkan" REQUIRED) 82 | if (Vulkan_LIBRARY) 83 | set(Vulkan_FOUND ON) 84 | MESSAGE("Using local Vulkan library.") 85 | endif() 86 | endif() 87 | endif() 88 | 89 | set(CMAKE_POLICY_DEFAULT_CMP0048 NEW) 90 | 91 | # Hide away any options that were imported together with the add_subdirectory call above. 92 | mark_as_advanced(FORCE SKIP_SPIRV_TOOLS_INSTALL RE2_BUILD_TESTING SPIRV_BUILD_COMPRESSION 93 | SPIRV_CHECK_CONTEXT SPIRV_COLOR_TERMINAL SPIRV_LOG_DEBUG 94 | SPIRV_SKIP_EXECUTABLES SPIRV_SKIP_TESTS 95 | SPIRV_TOOLS_INSTALL_EMACS_HELPERS) 96 | 97 | option(SPIRV_WERROR "Disable the SPIRV warnings that may trigger as errors." OFF) 98 | 99 | add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/libs/spirv-headers EXCLUDE_FROM_ALL) 100 | add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/libs/spirv-tools EXCLUDE_FROM_ALL) 101 | 102 | set(spirv-tools_LIBRARY SPIRV-Tools SPIRV-Tools-opt) # Assume that's how they're called. 103 | 104 | add_library(libSPEARGen STATIC ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVGen/SPIRVAssembler.cpp 105 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVGen/SPIRVConstant.cpp 106 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVGen/SPIRVDecoration.cpp 107 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVGen/SPIRVInstruction.cpp 108 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVGen/SPIRVModule.cpp 109 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVGen/SPIRVOperation.cpp 110 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVGen/SPIRVType.cpp 111 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVGen/SPIRVVariable.cpp) 112 | target_include_directories(libSPEARGen PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVGen 113 | PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/libs/hlx/include 114 | ${CMAKE_CURRENT_SOURCE_DIR}/libs/glm 115 | ${Vulkan_INCLUDE_DIRS} 116 | ${SPIRV-Headers_SOURCE_DIR}/include 117 | ${spirv-tools_SOURCE_DIR}/include) 118 | set_target_properties(libSPEARGen PROPERTIES VERSION ${PROJECT_VERSION}) 119 | set_target_properties(libSPEARGen PROPERTIES SOVERSION ${PROJECT_VERSION}) 120 | set_target_properties(libSPEARGen PROPERTIES FRAMEWORK ON) 121 | target_link_libraries(libSPEARGen ${Vulkan_LIBRARY} ${spirv-tools_LIBRARY}) 122 | 123 | set(SPEAR_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVGen/SPIRVAssembler.h 124 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVGen/SPIRVBinaryDefines.h 125 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVGen/SPIRVBranchOperations.h 126 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVGen/SPIRVComplex.h 127 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVGen/SPIRVConstant.h 128 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVGen/SPIRVDecoration.h 129 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVGen/SPIRVExtensionAMD.h 130 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVGen/SPIRVInlineAssembler.h 131 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVGen/SPIRVInstruction.h 132 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVGen/SPIRVInterop.h 133 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVGen/SPIRVModule.h 134 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVGen/SPIRVOperation.h 135 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVGen/SPIRVOperatorImpl.h 136 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVGen/SPIRVProgram.h 137 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVGen/SPIRVQuaternion.h 138 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVGen/SPIRVType.h 139 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVGen/SPIRVVariable.h 140 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVGen/SPIRVVariableTypeDefs.h 141 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVGen/SPIRVVariableTypes.h 142 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVGen/SPIRVVectorComponentAccess.h) 143 | 144 | # Below we define the headers that will be exported to the platform dep. path. 145 | set_target_properties(libSPEARGen PROPERTIES PUBLIC_HEADER "${SPEAR_INCLUDES}") 146 | 147 | install(TARGETS libSPEARGen ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} 148 | PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) 149 | 150 | if(SPEAR_BUILD_SHADER_FACTORY) 151 | find_package(Boost 1.64) # Maybe bit too recent version, we can probably decrease this if we find it problematic. 152 | 153 | if(NOT Boost_FOUND) # Assume directory is in libs/boost. 154 | message("Using custom Boost libraries at libs/boost!") 155 | set(Boost_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/libs/boost CACHE PATH "Location of the Boost libraries.") 156 | set(Boost_FOUND ON) 157 | endif() 158 | 159 | add_library(libSPEARShaderFactory SHARED ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVShaderFactory/DefaultShaderFactory.cpp) 160 | target_include_directories(libSPEARShaderFactory PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVShaderFactory 161 | PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/libs/hlx/include 162 | ${CMAKE_CURRENT_SOURCE_DIR}/libs/glm 163 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVGen 164 | ${Vulkan_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}) 165 | target_link_libraries(libSPEARShaderFactory libSPEARGen ${Vulkan_LIBRARY}) 166 | set_target_properties(libSPEARShaderFactory PROPERTIES FRAMEWORK ON VERSION ${PROJECT_VERSION}) 167 | set_target_properties(libSPEARShaderFactory PROPERTIES SOVERSION ${PROJECT_VERSION}) 168 | 169 | set(SPEAR_SHADER_FACTORY_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVShaderFactory/CameraFunctions.h 170 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVShaderFactory/ClearColor.h 171 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVShaderFactory/CommonBufferSourceNames.h 172 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVShaderFactory/CSGExampleShader.h 173 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVShaderFactory/CSGObject.h 174 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVShaderFactory/DefaultShaderFactory.h 175 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVShaderFactory/DefaultShaderIdentifiers.h 176 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVShaderFactory/IShaderFactory.h 177 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVShaderFactory/LightingFunctions.h 178 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVShaderFactory/Mandelbrot.h 179 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVShaderFactory/MaterialInterface.h 180 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVShaderFactory/MathFunctions.h 181 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVShaderFactory/MicrofacetReflection.h 182 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVShaderFactory/PhongMaterial.h 183 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVShaderFactory/ScreenSpaceTriangle.h 184 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVShaderFactory/SDFObject.h 185 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVShaderFactory/ShaderID.h 186 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVShaderFactory/SimpleCSGRayMarching.h) 187 | 188 | set_target_properties(libSPEARShaderFactory PROPERTIES PUBLIC_HEADER "${SPEAR_SHADER_FACTORY_INCLUDES}") 189 | 190 | install(TARGETS libSPEARShaderFactory ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} 191 | PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) 192 | 193 | endif() 194 | 195 | if(SPEAR_BUILD_TESTBED) 196 | add_executable(SPEARGenTest ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVGenTest/main.cpp) 197 | target_include_directories(SPEARGenTest PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVGenTest 198 | PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/libs/hlx/include 199 | ${CMAKE_CURRENT_SOURCE_DIR}/SPIRVGen 200 | ${CMAKE_CURRENT_SOURCE_DIR}/libs/glm 201 | ${SPIRV-Headers_SOURCE_DIR}/include 202 | ${Vulkan_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}) 203 | target_link_libraries(SPEARGenTest libSPEARGen ${Vulkan_LIBRARY}) 204 | # Install the testbed as well. This is just for CMakeLists completeness. 205 | install(TARGETS SPEARGenTest RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) 206 | 207 | set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT SPEARGenTest) 208 | endif() 209 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2018 Fabian Wahlster 2 | Contact: f.wahlster@tum.de 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | Naming the author(s) of this software in any of the following locations: About page, README file, credits. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SPEAR: C++/SPIR-V Shader Runtime 2 | 3 | ## Overview 4 | 5 | SPEAR is a integrated domain specific language translating C++17 to SPIR-V at host runtime. 6 | 7 | ```cpp 8 | template 9 | class Mandelbrot : public FragmentProgram 10 | { 11 | public: 12 | Mandelbrot() : FragmentProgram("Mandelbrot"){}; 13 | ~Mandelbrot() {}; 14 | 15 | RenderTarget OutputColor; 16 | inline void operator()() 17 | { 18 | f32 i = 0.f, max = 100.f; 19 | complex c(Lerp(-1.f, 1.f, kFragCoord.x / 1600.f), kFragCoord.y / 900.f); 20 | complex z(0.f, 0.f); 21 | While(z.Conjugate() < 4.f && i < max) 22 | { 23 | z = z * z + c; 24 | ++i; 25 | }); 26 | f32 scale = i / max; 27 | OutputColor = float4(scale, scale, scale, 0.f); 28 | }; 29 | }; 30 | ``` 31 | 32 | SPIR-V shader generated from SPEAR code above, rendered with Vulkan: 33 | ![Mandelbrot rendered from SPEAR shader](misc/fractal.png) 34 | 35 | ## Benefits 36 | 37 | * Modern C++ features like templating & auto type deduction, Polymorphism 38 | * Software design patterns, modularity and reusability 39 | * Adapting cutting edge GPU features using extension 40 | * C++ Profiling and Debugging Tools 41 | * Quite fast for compiling many shader permutations (Makes it possible to compile during runtime for small shaders) 42 | * Interchangeable Shading Libraries (Hot-swapping shader DLLs during rendering) 43 | * Write meta programs / code generators 44 | * Vulkan interoperability: create PSOs from SPIRVModules 45 | 46 | ![Debugging with Visual Studio](misc/vs_shader_dbg.png) 47 | 48 | ## Restrictions 49 | 50 | Please don't use this for production, the codebase is largely untested and not guaranteed to work. See it as a Proof-of-Concept. 51 | 52 | * Variable types are rather long outside the SPIRVProgram context 53 | * Ugly macros for If, While, For etc… 54 | * Mixing regular C++ variables and var_t<> has undesired sideeffects 55 | * C++ variables are interpreted as constants 56 | * Vector components can not be extracted by reference 57 | * Recursion is not supported (will blow up instruction recording) 58 | * Return statements will lead to dead code (not translated) 59 | * Missing keywords switch, continue and break 60 | * Ternary conditional operator? can not be overloaded in C++ (Use Select function instead!) 61 | 62 | Please read to accompanying paper [Development of a C++/SPIR-V Shader-Runtime](misc/Paper.pdf) and presentation [slides](misc/Slides.pdf) from the Khronos Meetup for more information. 63 | 64 | ## Build 65 | 66 | The SPEAR project currently uses CMake to generate build files. In the root of this project is a `CMakeLists.txt`, which should work for generating Visual Studio solutions. There are some issues when generating Makefiles for GNU Make, but it should in theory work with a bit of fiddling. The requirements are: a `C++17` compliant compiler, a Vulkan SDK and runtime somewhere in your system, which are resolved automatically by CMake. You'll also need `boost` somewhere in your include path, or, alternatively, under `libs/boost` (just the headers, which you can get [here](https://dl.bintray.com/boostorg/release/1.67.0/source/)). The rest of the dependencies `glm`, `spirv-headers` and `spirv-tools` are fetched automatically by git submodules, and should in theory work out-of-the-box. 67 | 68 | **Note:** this is a *very* experimental CMake-file! You might need to hack a bit to make it work on your platform, but it should at least work on a target with Visual Studio & LunarG SDK. Also, it isn't nice enough to provide `find_package` in CMake yet, you'll have to do that sort of stuff manually for now. If you have any improvements, feel free to issue a pull request! 69 | 70 | Below is a complete summary of the steps you need to build SPEAR for Visual Studio 2017: 71 | 72 | 1. Clone this repository down to disk: `git clone https://github.com/rAzoR8/SPEAR` 73 | 2. Download `boost` (if it's not in your global include path), and put the headers under `libs/boost` 74 | 3. Fetch the rest of the dependencies with: `git submodule init && git submodule update` 75 | 4. Generate the Visual Studio solution with `cmake-gui`, modify the *build options* as you see fit. 76 | 5. Open the solution in Visual Studio, and set `SPIRVGenTest` as the target project. Build and run. 77 | 78 | ### Build options 79 | 80 | * **SPEAR_ENABLE_PROPERTIES = ON | OFF (default: ON):** Many convenience facilities are based on __declspec(property), and are not available on e.g. gcc. However, the library can be used without them fine. 81 | * **SPEAR_BUILD_TESTBED = ON | OFF (default: ON):** Also build the accompanying example project, depending on the libSPEARGen. This gets you an executable e.g SPEARGenTest that you can (hopefully) run. 82 | * **SPEAR_BUILD_SHADER_FACTORY = ON | OFF (default: ON):** Also build the dynamic shader library project and links it to libSPEARGen, which will be a shared library called libSPEARShaderFactory.so on Unix-es. 83 | 84 | ### Source code organization 85 | 86 | * `SPIRVGen`: Core Spear library 87 | * `SPIRVGenTest`: Simple testbed project 88 | * `SPIRVShaderFactory`: Dynamic shader library example project 89 | * `libs`: Target folder with all submodule dependencies. 90 | * `libs/boost`: Location where boost headers should go. 91 | * `build`: Location of the generated solution. 92 | 93 | `SPIRVGen` library project requires Vulkan-SDK files and HLX (submodule) headers. 94 | `SPIRVGenTest` executable project should link `SPIRVGen`. 95 | `SPIRVShaderFactory` shared library project links `SPIRVGen` and requires boost.DLL libraries for the IPlugin DLL interface. Compile with HDYNAMIC_LINKAGE and HDLL_EXPORT defines to create a dynamic shader library. 96 | 97 | ## Usage 98 | 99 | Please look for the example shaders located at SPIRVShaderFactory folder. 100 | 101 | ## License 102 | ``` 103 | Copyright 2018 Fabian Wahlster 104 | Contact: f.wahlster@tum.de 105 | 106 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 107 | 108 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 109 | Naming the author(s) of this software in any of the following locations: About page, README file, credits. 110 | 111 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 112 | ``` 113 | 114 | ## Contributing 115 | 116 | The SPEAR project is maintained by Fabian Wahlster and hosted at https://github.com/razor8/SPEAR. 117 | 118 | Special thanks go to: 119 | * Mathias Kanzler who supervised this research 120 | * Erik S. V. Jansson [CaffeineViking](https://github.com/CaffeineViking) who provided CMake support 121 | -------------------------------------------------------------------------------- /SPIRVGen/SPIRVAssembler.h: -------------------------------------------------------------------------------- 1 | //Copyright(c) 2018 2 | //Authors: Fabian Wahlster 3 | //Website: https://twitter.com/singul4rity 4 | //Contact: f.wahlster@tum.de 5 | //License: MIT with attribution (see LICENSE.txt) 6 | 7 | #ifndef SPEAR_SPIRVASSEMBLER_H 8 | #define SPEAR_SPIRVASSEMBLER_H 9 | 10 | #include "SPIRVOperation.h" 11 | #include "SPIRVInstruction.h" 12 | #include "SPIRVModule.h" 13 | #include "Flag.h" 14 | #include "Logger.h" 15 | #include 16 | 17 | namespace Spear 18 | { 19 | using namespace hlx; 20 | 21 | inline constexpr bool is_type_op(spv::Op _Op) {return _Op >= spv::OpTypeVoid && _Op <= spv::OpTypeForwardPointer; }; 22 | inline constexpr bool is_const_op (spv::Op _Op) {return _Op >= spv::OpConstantTrue && _Op <= spv::OpSpecConstantOp; }; 23 | inline constexpr bool is_type_or_const_op(spv::Op _Op) { return is_type_op(_Op) || is_const_op(_Op); } 24 | inline constexpr bool is_decorate_op (spv::Op _Op) {return _Op >= spv::OpDecorate && _Op <= spv::OpGroupMemberDecorate; }; 25 | inline constexpr bool is_var_op(spv::Op _Op) {return _Op == spv::OpVariable; }; 26 | inline constexpr bool is_name_op(spv::Op _Op) { return _Op == spv::OpName || _Op == spv::OpMemberName; }; 27 | 28 | // forward decls 29 | template 30 | class SPIRVProgram; 31 | 32 | template 33 | struct var_decoration; 34 | 35 | class SPIRVConstant; 36 | 37 | static const std::string ExtGLSL450 = "GLSL.std.450"; 38 | 39 | enum EOptimizationPassFlag : uint32_t 40 | { 41 | kOptimizationPassFlag_None = 0, 42 | kOptimizationPassFlag_AllPerformance = 1 << 0, 43 | kOptimizationPassFlag_AllSize = 1 << 1, 44 | kOptimizationPassFlag_All = UINT32_MAX 45 | }; 46 | 47 | using TOptimizationPassFlags = hlx::Flag; 48 | 49 | struct OptimizationSettings 50 | { 51 | TOptimizationPassFlags kPasses; 52 | }; 53 | 54 | class SPIRVAssembler 55 | { 56 | public: 57 | using TIdMap = std::unordered_map; 58 | 59 | inline static SPIRVAssembler& Instance() 60 | { 61 | static SPIRVAssembler inst; 62 | return inst; 63 | } 64 | 65 | SPIRVAssembler() noexcept; 66 | virtual ~SPIRVAssembler(); 67 | 68 | template 69 | void InitializeProgram(Ts&& ..._args); 70 | 71 | template 72 | void RecordInstructions(Ts&& ..._args); 73 | 74 | SPIRVModule Assemble(); 75 | 76 | // calls InitializeProgram with Ts args, RecordInstructions without args and Assemble 77 | template 78 | SPIRVModule AssembleSimple(const bool _bUseDefaults = true, Ts&& ..._args); 79 | 80 | uint32_t GetExtensionId(const std::string& _sExt = ExtGLSL450); 81 | 82 | // _pOutInstr gets a pointer to the stored instruction so that i can be modified later (add operands) 83 | //uint32_t AddOperation(const SPIRVOperation& _Instr, SPIRVOperation** _pOutInstr = nullptr); 84 | 85 | // move op 86 | uint32_t AddOperation(SPIRVOperation&& _Instr, SPIRVOperation** _pOutInstr = nullptr); 87 | 88 | template 89 | uint32_t EmplaceOperation(Ts&& ..._args); 90 | 91 | uint32_t AddConstant(const SPIRVConstant& _Const); 92 | uint32_t AddType(const SPIRVType& _Type); 93 | 94 | void AddVariableInfo(const var_decoration& _Var); 95 | 96 | void SetDefaults() noexcept; 97 | void UseDefaultSetLocation(const uint32_t _uDefaultSet = 0u, const uint32_t _uDefaultInputLocation = 0u, const uint32_t _uDefaultOutputLocation = 0u) noexcept; 98 | void UseDefaultSpecConstId(const uint32_t _uStartId = 0u) noexcept; 99 | void UseDefaultInputAttachmentIndex(const uint32_t _uStartIndex = 0u) noexcept; 100 | void ConfigureOptimization(const OptimizationSettings& _Settings); 101 | 102 | void RemoveUnusedOperations(const bool _bEnable = true) noexcept; 103 | bool GetRemoveUnusedOperations() const noexcept; 104 | 105 | void EnterScope(); 106 | void LeaveScope(); 107 | 108 | const uint32_t& GetScopeLevel() const; 109 | const uint32_t& GetScopeID() const; 110 | 111 | const uint32_t& GetDefaultSet() const noexcept; 112 | const uint32_t GetCurrentBinding(const uint32_t _uSet); 113 | 114 | const uint32_t GetCurrentInputLocation() noexcept; 115 | const uint32_t GetCurrentOutputLocation() noexcept; 116 | const uint32_t GetCurrentSpecConstId() noexcept; 117 | const uint32_t GetCurrentInputAttchmentIndex() noexcept; 118 | 119 | static SPIRVModule ExternalOptimize(const SPIRVModule& _Module, const OptimizationSettings& _Settings); 120 | 121 | private: 122 | void Init(const std::unique_ptr>& _pProgram); 123 | 124 | void Resolve(); 125 | 126 | SPIRVInstruction Translate(SPIRVOperation& _Op); 127 | 128 | void AddInstruction(const SPIRVInstruction& _Instr); 129 | 130 | void AssignId(SPIRVOperation& _Op); 131 | 132 | void FlagUnused(); 133 | 134 | spv::StorageClass GetStorageClass(const SPIRVOperation& _Op) const; 135 | 136 | template 137 | void ForEachOp(const Fn& _fn, const Pred& _Pred); 138 | 139 | template 140 | void ForEachOpEx(const Fn& _fn, const Pred& _Pred); 141 | 142 | void AddPreambleId(const uint32_t& _uId); 143 | 144 | private: 145 | std::mutex m_Mutex; 146 | 147 | OptimizationSettings m_OptSettings; 148 | 149 | // remove variables, types, constants 150 | bool m_bRemoveUnused = true; 151 | 152 | std::unique_ptr> m_pAssembleProgram = nullptr; 153 | std::unique_ptr> m_pExecuteProgram = nullptr; 154 | 155 | std::vector m_Extensions; 156 | std::unordered_map m_ExtensionIds; 157 | 158 | uint32_t m_uInstrId = 0u; // internal instruction id 159 | uint32_t m_uResultId = 1u; // actual result ids 160 | 161 | SPIRVOperation* m_pOpEntryPoint = nullptr; 162 | SPIRVOperation* m_pOpExeutionMode = nullptr; 163 | 164 | std::string m_sEntryPoint; 165 | spv::ExecutionModel m_kModel = spv::ExecutionModelMax; 166 | spv::ExecutionMode m_kMode = spv::ExecutionModeMax; 167 | std::vector m_Capabilities; 168 | 169 | std::vector m_Instructions; 170 | 171 | uint32_t m_uScopeLevel = 0; 172 | uint32_t m_uScopeID = 0; 173 | 174 | uint32_t m_uDefaultSet = HUNDEFINED32; 175 | 176 | // set -> binding 177 | std::unordered_map m_Bindings; 178 | 179 | uint32_t m_uCurrentInputLocation = HUNDEFINED32; 180 | uint32_t m_uCurrentOutputLocation = HUNDEFINED32; 181 | uint32_t m_uCurrentSpecConstId = HUNDEFINED32; 182 | uint32_t m_uCurrentInputAttachmentIndex = HUNDEFINED32; 183 | 184 | // type instruction id 185 | TIdMap m_TypeIds; 186 | // constant instruction id 187 | TIdMap m_ConstantIds; 188 | 189 | std::vector m_Operations; // unresolved local instruction stream 190 | 191 | uint32_t m_uFunctionPreambleIndex = 0u; 192 | std::vector m_PreambleOpIds; 193 | 194 | // var id -> VariableInfo 195 | std::unordered_map m_UsedVariables; // info on loaded / stored variables 196 | }; 197 | //--------------------------------------------------------------------------------------------------- 198 | inline void SPIRVAssembler::SetDefaults() noexcept 199 | { 200 | UseDefaultSetLocation(); 201 | UseDefaultSpecConstId(); 202 | UseDefaultInputAttachmentIndex(); 203 | } 204 | 205 | inline void SPIRVAssembler::UseDefaultSetLocation(const uint32_t _uDefaultSet, const uint32_t _uDefaulInputLocation, const uint32_t _uDefaultOutputLocation) noexcept 206 | { 207 | m_uDefaultSet = _uDefaultSet; 208 | m_uCurrentInputLocation = _uDefaulInputLocation; 209 | m_uCurrentOutputLocation = _uDefaultOutputLocation; 210 | } 211 | 212 | inline void SPIRVAssembler::UseDefaultSpecConstId(const uint32_t _uStartId) noexcept 213 | { 214 | m_uCurrentSpecConstId = _uStartId; 215 | } 216 | 217 | inline void SPIRVAssembler::UseDefaultInputAttachmentIndex(const uint32_t _uStartIndex) noexcept 218 | { 219 | m_uCurrentInputAttachmentIndex = _uStartIndex; 220 | } 221 | 222 | inline void SPIRVAssembler::ConfigureOptimization(const OptimizationSettings & _Settings) 223 | { 224 | m_OptSettings = _Settings; 225 | } 226 | 227 | inline void SPIRVAssembler::RemoveUnusedOperations(const bool _bEnable) noexcept 228 | { 229 | m_bRemoveUnused = _bEnable; 230 | } 231 | 232 | inline bool SPIRVAssembler::GetRemoveUnusedOperations() const noexcept 233 | { 234 | return m_bRemoveUnused; 235 | } 236 | 237 | inline void SPIRVAssembler::EnterScope() 238 | { 239 | ++m_uScopeID; 240 | ++m_uScopeLevel; 241 | } 242 | 243 | inline void SPIRVAssembler::LeaveScope() 244 | { 245 | --m_uScopeLevel; 246 | } 247 | 248 | inline const uint32_t& SPIRVAssembler::GetScopeLevel() const 249 | { 250 | return m_uScopeLevel; 251 | } 252 | 253 | inline const uint32_t& SPIRVAssembler::GetScopeID() const 254 | { 255 | return m_uScopeID; 256 | } 257 | 258 | inline const uint32_t& SPIRVAssembler::GetDefaultSet() const noexcept 259 | { 260 | return m_uDefaultSet; 261 | } 262 | 263 | inline const uint32_t SPIRVAssembler::GetCurrentBinding(const uint32_t _uSet) 264 | { 265 | // TODO: assert if to high 266 | auto it = m_Bindings.find(_uSet); 267 | if (it != m_Bindings.end()) 268 | { 269 | return it->second++; 270 | } 271 | else 272 | { 273 | m_Bindings.insert({ _uSet, 1 }); 274 | return 0u; 275 | } 276 | } 277 | 278 | inline const uint32_t SPIRVAssembler::GetCurrentInputLocation() noexcept 279 | { 280 | // TODO: assert if to high 281 | return m_uCurrentInputLocation++; 282 | } 283 | 284 | inline const uint32_t SPIRVAssembler::GetCurrentOutputLocation() noexcept 285 | { 286 | // TODO: assert if to high 287 | return m_uCurrentOutputLocation++; 288 | } 289 | 290 | inline const uint32_t SPIRVAssembler::GetCurrentSpecConstId() noexcept 291 | { 292 | return m_uCurrentSpecConstId++; 293 | } 294 | 295 | inline const uint32_t SPIRVAssembler::GetCurrentInputAttchmentIndex() noexcept 296 | { 297 | return m_uCurrentInputAttachmentIndex++; 298 | } 299 | 300 | #ifndef GlobalAssembler 301 | #define GlobalAssembler (Spear::SPIRVAssembler::Instance()) 302 | #endif 303 | 304 | template 305 | inline void SPIRVAssembler::InitializeProgram(Ts&& ..._args) 306 | { 307 | constexpr bool bAssemble = std::is_base_of_v, TProg>; 308 | constexpr bool bExecute = std::is_base_of_v, TProg>; 309 | 310 | if constexpr(bAssemble) 311 | { 312 | m_Mutex.lock(); 313 | m_pAssembleProgram = std::make_unique(std::forward(_args)...); 314 | Init(m_pAssembleProgram); 315 | } 316 | else if constexpr(bExecute) 317 | { 318 | m_pExecuteProgram = std::make_unique(std::forward(_args)...); 319 | } 320 | } 321 | 322 | template 323 | inline void SPIRVAssembler::RecordInstructions(Ts&& ..._args) 324 | { 325 | HASSERT(m_pAssembleProgram != nullptr || m_pExecuteProgram != nullptr, "Invalid program (InitializeProgram not called)"); 326 | 327 | if (m_pAssembleProgram) 328 | { 329 | m_pAssembleProgram->Execute(std::forward(_args)...); 330 | m_pAssembleProgram.reset(); // destroy prog here to record variable destructors 331 | } 332 | else if (m_pExecuteProgram) 333 | { 334 | m_pExecuteProgram->Execute(std::forward(_args)...); 335 | m_pExecuteProgram.reset(); 336 | } 337 | } 338 | 339 | template 340 | inline SPIRVModule SPIRVAssembler::AssembleSimple(const bool _bUseDefaults, Ts&& ..._args) 341 | { 342 | if (_bUseDefaults) 343 | { 344 | SetDefaults(); 345 | } 346 | 347 | InitializeProgram(std::forward(_args)...); 348 | RecordInstructions(); 349 | 350 | constexpr bool bAssemble = std::is_base_of_v, TProg>; 351 | 352 | if constexpr(bAssemble) 353 | return Assemble(); 354 | else 355 | return SPIRVModule(0); 356 | } 357 | 358 | template 359 | inline uint32_t SPIRVAssembler::EmplaceOperation(Ts&& ..._args) 360 | { 361 | m_Operations.emplace_back(std::forward(_args)...).m_uInstrId = m_uInstrId; 362 | return m_uInstrId++; 363 | } 364 | 365 | template 366 | inline void SPIRVAssembler::ForEachOp(const Fn& _fn, const Pred& _Pred) 367 | { 368 | for (SPIRVOperation& Op : m_Operations) 369 | { 370 | if (_Pred(Op.GetOpCode())) 371 | { 372 | _fn(Op); 373 | } 374 | } 375 | } 376 | 377 | template 378 | inline void SPIRVAssembler::ForEachOpEx(const Fn& _fn, const Pred& _Pred) 379 | { 380 | for (SPIRVOperation& Op : m_Operations) 381 | { 382 | if (_Pred(Op)) 383 | { 384 | _fn(Op); 385 | } 386 | } 387 | } 388 | } // Spear 389 | 390 | #endif // !SPEAR_SPIRVASSEMBLER_H 391 | -------------------------------------------------------------------------------- /SPIRVGen/SPIRVBinaryDefines.h: -------------------------------------------------------------------------------- 1 | //Copyright(c) 2018 2 | //Authors: Fabian Wahlster 3 | //Website: https://twitter.com/singul4rity 4 | //Contact: f.wahlster@tum.de 5 | //License: MIT with attribution (see LICENSE.txt) 6 | 7 | #ifndef SPEAR_SPIRVBINARYDEFINES_H 8 | #define SPEAR_SPIRVBINARYDEFINES_H 9 | 10 | #include 11 | #include 12 | #include 13 | #include "Flag.h" 14 | 15 | namespace Spear 16 | { 17 | enum ESPVOpArgs 18 | { 19 | kSPVOpArgs_None = 0, 20 | kSPVOpArgs_TypeId = 1 << 0, 21 | kSPVOpArgs_ResultId = 1 << 1, 22 | kSPVOpArgs_TypeAndResultId = kSPVOpArgs_TypeId | kSPVOpArgs_ResultId, 23 | kSPVOpArgs_Unknown = 0xff 24 | }; 25 | 26 | using TSPVArgFlag = hlx::Flag; 27 | 28 | // dont use, unfinished 29 | inline static std::string GetOpCodeString(const spv::Op _kOp) 30 | { 31 | static const std::unordered_map OpNames = 32 | { 33 | { spv::OpNop, "OpNop" }, 34 | { spv::OpUndef, "OpUndef" }, 35 | { spv::OpSourceContinued, "OpSourceContinued" }, 36 | { spv::OpSource, "OpSource" }, 37 | { spv::OpSourceExtension, "OpSourceExtension" }, 38 | { spv::OpName, "OpName" }, 39 | { spv::OpMemberName, "OpMemberName" }, 40 | { spv::OpString, "OpString" }, 41 | { spv::OpLine, "OpLine" }, 42 | { spv::OpExtension, "OpExtension" }, 43 | { spv::OpExtInstImport, "OpExtInstImport" }, 44 | { spv::OpMemoryModel, "OpMemoryModel" }, 45 | { spv::OpEntryPoint, "OpEntryPoint" }, 46 | { spv::OpExecutionMode, "OpExecutionMode" }, 47 | { spv::OpCapability, "OpCapability" }, 48 | { spv::OpTypeVoid, "OpTypeVoid" }, 49 | { spv::OpTypeBool, "OpTypeBool" }, 50 | { spv::OpTypeInt, "OpTypeInt" }, 51 | { spv::OpTypeFloat, "OpTypeFloat" }, 52 | { spv::OpTypeVector, "OpTypeVector" }, 53 | { spv::OpTypeMatrix, "OpTypeMatrix" }, 54 | { spv::OpTypeImage, "OpTypeImage" }, 55 | { spv::OpTypeSampler, "OpTypeSampler" }, 56 | { spv::OpTypeSampledImage, "OpTypeSampledImage" }, 57 | { spv::OpTypeArray, "OpTypeArray" }, 58 | { spv::OpTypeRuntimeArray, "OpTypeRuntimeArray" }, 59 | { spv::OpTypeStruct, "OpTypeStruct" }, 60 | { spv::OpTypePointer, "OpTypePointer" }, 61 | { spv::OpTypeFunction, "OpTypeFunction" }, 62 | { spv::OpTypeEvent, "OpTypeEvent" }, 63 | { spv::OpTypeDeviceEvent, "OpTypeDeviceEvent" }, 64 | { spv::OpTypeReserveId, "OpTypeReserveId" }, 65 | { spv::OpTypeQueue, "OpTypeQueue" }, 66 | { spv::OpTypePipe, "OpTypePipe" }, 67 | { spv::OpTypeForwardPointer, "OpTypeForwardPointer" }, 68 | { spv::OpConstantTrue, "OpConstantTrue" }, 69 | { spv::OpConstantFalse, "OpConstantFalse" }, 70 | { spv::OpConstant, "OpConstant" }, 71 | { spv::OpConstantComposite, "OpConstantComposite" }, 72 | { spv::OpConstantSampler, "OpConstantSampler" }, 73 | { spv::OpConstantNull, "OpConstantNull" }, 74 | { spv::OpSpecConstantTrue, "OpSpecConstantTrue" }, 75 | { spv::OpSpecConstantFalse, "OpSpecConstantFalse" }, 76 | { spv::OpSpecConstant, "OpSpecConstant" }, 77 | { spv::OpSpecConstantComposite, "OpSpecConstantComposite" }, 78 | { spv::OpSpecConstantOp, "OpSpecConstantOp" }, 79 | { spv::OpFunction, "OpFunction" }, 80 | { spv::OpFunctionParameter, "OpFunctionParameter" }, 81 | { spv::OpFunctionEnd, "OpFunctionEnd" }, 82 | { spv::OpFunctionCall, "OpFunctionCall" }, 83 | { spv::OpVariable, "OpVariable" }, 84 | { spv::OpImageTexelPointer, "OpImageTexelPointer" }, 85 | { spv::OpLoad, "OpLoad" }, 86 | { spv::OpStore, "OpStore" }, 87 | { spv::OpCopyMemory, "OpCopyMemory" }, 88 | { spv::OpCopyMemorySized, "OpCopyMemorySized" }, 89 | { spv::OpAccessChain, "OpAccessChain" }, 90 | { spv::OpInBoundsAccessChain, "OpInBoundsAccessChain" }, 91 | { spv::OpPtrAccessChain, "OpPtrAccessChain" }, 92 | { spv::OpArrayLength, "OpArrayLength" }, 93 | { spv::OpGenericPtrMemSemantics, "OpGenericPtrMemSemantics" }, 94 | { spv::OpInBoundsPtrAccessChain, "OpInBoundsPtrAccessChain" }, 95 | { spv::OpDecorate, "OpDecorate" }, 96 | { spv::OpMemberDecorate, "OpMemberDecorate" }, 97 | { spv::OpDecorationGroup, "OpDecorationGroup" }, 98 | { spv::OpGroupDecorate, "OpGroupDecorate" }, 99 | { spv::OpGroupMemberDecorate, "OpGroupMemberDecorate" }, 100 | { spv::OpVectorExtractDynamic, "OpVectorExtractDynamic" }, 101 | { spv::OpVectorInsertDynamic, "OpVectorInsertDynamic" }, 102 | { spv::OpVectorShuffle, "OpVectorShuffle" }, 103 | { spv::OpCompositeConstruct, "OpCompositeConstruct" }, 104 | { spv::OpCompositeExtract, "OpCompositeExtract" }, 105 | { spv::OpCopyObject, "OpCopyObject" }, 106 | { spv::OpTranspose, "OpTranspose" }, 107 | { spv::OpSampledImage, "OpSampledImage" }, 108 | { spv::OpImageSampleImplicitLod, "OpImageSampleImplicitLod" }, 109 | { spv::OpImageSampleExplicitLod, "OpImageSampleExplicitLod" }, 110 | { spv::OpImageSampleDrefImplicitLod, "OpImageSampleDrefImplicitLod" }, 111 | { spv::OpImageSampleDrefExplicitLod, "OpImageSampleDrefExplicitLod" }, 112 | { spv::OpImageSampleProjImplicitLod, "OpImageSampleProjImplicitLod" }, 113 | { spv::OpImageSampleProjExplicitLod, "OpImageSampleProjExplicitLod" }, 114 | { spv::OpImageSampleProjDrefImplicitLod, "OpImageSampleProjDrefImplicitLod" }, 115 | { spv::OpImageSampleProjDrefExplicitLod, "OpImageSampleProjDrefExplicitLod" }, 116 | { spv::OpImageFetch, "OpImageFetch" }, 117 | { spv::OpImageGather, "OpImageGather" }, 118 | { spv::OpImageDrefGather, "OpImageDrefGather" }, 119 | { spv::OpImageRead, "OpImageRead" }, 120 | { spv::OpImageWrite, "OpImageWrite" }, 121 | { spv::OpImage, "OpImage" }, 122 | { spv::OpImageQueryFormat, "OpImageQueryFormat" }, 123 | { spv::OpImageQueryOrder, "OpImageQueryOrder" }, 124 | { spv::OpImageQuerySizeLod, "OpImageQuerySizeLod" }, 125 | { spv::OpImageQuerySize, "OpImageQuerySize" }, 126 | { spv::OpImageQueryLod, "OpImageQueryLod" }, 127 | { spv::OpImageQueryLevels, "OpImageQueryLevels" }, 128 | { spv::OpImageQuerySamples, "OpImageQuerySamples" } 129 | 130 | }; 131 | 132 | auto it = OpNames.find(_kOp); 133 | return it != OpNames.end() ? it->second : "Unknown [" + std::to_string(_kOp) + "]"; 134 | } 135 | 136 | // dont use, unfinished 137 | inline static ESPVOpArgs GetOpCodeArgs(const spv::Op _kOp) 138 | { 139 | static const std::unordered_map OpArgs = 140 | { 141 | { spv::OpNop, kSPVOpArgs_None }, 142 | { spv::OpUndef, kSPVOpArgs_TypeAndResultId }, 143 | { spv::OpSourceContinued, kSPVOpArgs_None }, 144 | { spv::OpSource, kSPVOpArgs_None }, 145 | { spv::OpSourceExtension, kSPVOpArgs_None }, 146 | { spv::OpName, kSPVOpArgs_None }, 147 | { spv::OpMemberName, kSPVOpArgs_TypeId }, 148 | { spv::OpString, kSPVOpArgs_ResultId }, 149 | { spv::OpLine, kSPVOpArgs_None }, 150 | { spv::OpExtension, kSPVOpArgs_None }, 151 | { spv::OpExtInstImport, kSPVOpArgs_ResultId }, 152 | { spv::OpExtInst, kSPVOpArgs_TypeAndResultId }, 153 | { spv::OpMemoryModel, kSPVOpArgs_None }, 154 | { spv::OpEntryPoint, kSPVOpArgs_None }, 155 | { spv::OpExecutionMode, kSPVOpArgs_None }, 156 | { spv::OpCapability, kSPVOpArgs_None }, 157 | { spv::OpTypeVoid, kSPVOpArgs_ResultId }, 158 | { spv::OpTypeVoid, kSPVOpArgs_ResultId }, 159 | { spv::OpTypeBool, kSPVOpArgs_ResultId }, 160 | { spv::OpTypeInt, kSPVOpArgs_ResultId }, 161 | { spv::OpTypeFloat, kSPVOpArgs_ResultId }, 162 | { spv::OpTypeVector, kSPVOpArgs_ResultId }, 163 | { spv::OpTypeMatrix, kSPVOpArgs_ResultId }, 164 | { spv::OpTypeImage, kSPVOpArgs_TypeAndResultId }, 165 | { spv::OpTypeSampler, kSPVOpArgs_ResultId }, 166 | { spv::OpTypeSampledImage, kSPVOpArgs_TypeAndResultId }, 167 | { spv::OpTypeArray, kSPVOpArgs_TypeAndResultId }, 168 | { spv::OpTypeRuntimeArray, kSPVOpArgs_TypeAndResultId }, 169 | { spv::OpTypeStruct, kSPVOpArgs_ResultId }, 170 | { spv::OpTypeOpaque, kSPVOpArgs_ResultId }, 171 | { spv::OpTypeOpaque, kSPVOpArgs_ResultId }, 172 | { spv::OpTypePointer, kSPVOpArgs_ResultId }, 173 | { spv::OpTypeFunction, kSPVOpArgs_TypeAndResultId }, 174 | { spv::OpTypeEvent, kSPVOpArgs_ResultId }, 175 | { spv::OpTypeDeviceEvent, kSPVOpArgs_ResultId }, 176 | { spv::OpTypeReserveId, kSPVOpArgs_ResultId }, 177 | { spv::OpTypeQueue, kSPVOpArgs_ResultId }, 178 | { spv::OpTypePipe, kSPVOpArgs_ResultId }, 179 | { spv::OpTypeForwardPointer, kSPVOpArgs_TypeId }, 180 | { spv::OpConstantTrue, kSPVOpArgs_ResultId }, 181 | 182 | }; 183 | 184 | auto it = OpArgs.find(_kOp); 185 | return it != OpArgs.end() ? it->second : kSPVOpArgs_Unknown; 186 | } 187 | 188 | inline static std::string LiteralToString(const uint32_t _uLiteral) 189 | { 190 | std::string sLiteralStr; 191 | const char* c = reinterpret_cast(&_uLiteral); 192 | for (uint32_t i = 0; i < 4 && *c != 0; i++, c++) 193 | { 194 | sLiteralStr += *c; 195 | } 196 | 197 | return sLiteralStr; 198 | } 199 | 200 | inline static bool CreatesResultId(const spv::Op _kOp) 201 | { 202 | switch (_kOp) 203 | { 204 | // instructions that don't create a result id (incomplete list) 205 | case spv::OpNop: 206 | case spv::OpSourceContinued: 207 | case spv::OpSource: 208 | case spv::OpSourceExtension: 209 | case spv::OpName: 210 | case spv::OpMemberName: 211 | case spv::OpLine: 212 | case spv::OpNoLine: 213 | case spv::OpModuleProcessed: 214 | case spv::OpDecorate: 215 | case spv::OpMemberDecorate: 216 | case spv::OpGroupDecorate: 217 | case spv::OpGroupMemberDecorate: 218 | //case spv::OpDecrorateId: // spv v1.2 219 | case spv::OpExtension: 220 | case spv::OpMemoryModel: 221 | case spv::OpEntryPoint: 222 | case spv::OpExecutionMode: 223 | case spv::OpCapability: 224 | //case spv::OpExecutionModeId: // spv v1.2 225 | case spv::OpTypeForwardPointer: 226 | case spv::OpStore: 227 | case spv::OpCopyMemory: 228 | case spv::OpCopyMemorySized: 229 | case spv::OpFunctionEnd: 230 | case spv::OpLoopMerge: 231 | case spv::OpSelectionMerge: 232 | case spv::OpBranch: 233 | case spv::OpBranchConditional: 234 | case spv::OpSwitch: 235 | case spv::OpKill: 236 | case spv::OpReturn: 237 | case spv::OpReturnValue: 238 | case spv::OpUnreachable: 239 | case spv::OpLifetimeStart: 240 | case spv::OpLifetimeStop: 241 | case spv::OpEmitVertex: 242 | case spv::OpEndPrimitive: 243 | case spv::OpEmitStreamVertex: 244 | case spv::OpEndStreamPrimitive: 245 | case spv::OpControlBarrier: 246 | case spv::OpMemoryBarrier: 247 | case spv::OpMemoryNamedBarrier: 248 | case spv::OpGroupWaitEvents: 249 | case spv::OpRetainEvent: 250 | case spv::OpReleaseEvent: 251 | case spv::OpSetUserEventStatus: 252 | case spv::OpCaptureEventProfilingInfo: 253 | case spv::OpGroupCommitReadPipe: 254 | case spv::OpGroupCommitWritePipe: 255 | return false; 256 | break; 257 | default: 258 | return true; 259 | } 260 | } 261 | 262 | } // Spear 263 | 264 | #endif // !SPEAR_SPIRVBINARYDEFINES_H 265 | -------------------------------------------------------------------------------- /SPIRVGen/SPIRVBranchOperations.h: -------------------------------------------------------------------------------- 1 | //Copyright(c) 2018 2 | //Authors: Fabian Wahlster 3 | //Website: https://twitter.com/singul4rity 4 | //Contact: f.wahlster@tum.de 5 | //License: MIT with attribution (see LICENSE.txt) 6 | 7 | #ifndef SPEAR_SPIRVBRANCHNODE_H 8 | #define SPEAR_SPIRVBRANCHNODE_H 9 | 10 | #include "SPIRVAssembler.h" 11 | 12 | namespace Spear 13 | { 14 | #pragma region If 15 | template 16 | struct BranchNodeBase{}; 17 | 18 | template <> 19 | struct BranchNodeBase 20 | { 21 | bool bCondition = false; 22 | }; 23 | 24 | template <> 25 | struct BranchNodeBase 26 | { 27 | SPIRVOperation* pThenBranch = nullptr; 28 | SPIRVOperation* pSelectionMerge = nullptr; 29 | SPIRVOperation* pBranchConditional = nullptr; 30 | }; 31 | 32 | template 33 | struct BranchNode : public BranchNodeBase 34 | { 35 | template 36 | void ElseNode(const LambdaFunc& _Func); 37 | }; 38 | 39 | template 40 | inline BranchNode IfNode(const var_t& _Cond, const LambdaFunc& _Func, const spv::SelectionControlMask _kMask = spv::SelectionControlMaskNone) 41 | { 42 | BranchNode Node; 43 | 44 | if constexpr(Assemble) 45 | { 46 | _Cond.Load(); 47 | 48 | GlobalAssembler.AddOperation(SPIRVOperation(spv::OpSelectionMerge, 49 | { 50 | SPIRVOperand(kOperandType_Intermediate, HUNDEFINED32), // merge id 51 | SPIRVOperand(kOperandType_Literal, (const uint32_t)_kMask) // selection class 52 | }), &Node.pSelectionMerge); 53 | 54 | GlobalAssembler.AddOperation(SPIRVOperation(spv::OpBranchConditional, SPIRVOperand(kOperandType_Intermediate, _Cond.uResultId)), &Node.pBranchConditional); 55 | } 56 | else 57 | { 58 | Node.bCondition = _Cond.Value; 59 | } 60 | 61 | if (_Cond.Value || Assemble) 62 | { 63 | if constexpr(Assemble) 64 | { 65 | Node.pBranchConditional->AddIntermediate(GlobalAssembler.AddOperation(SPIRVOperation(spv::OpLabel))); // add true label 66 | } 67 | 68 | //GlobalAssembler.ForceNextLoads(); 69 | GlobalAssembler.EnterScope(); 70 | _Func(); 71 | GlobalAssembler.LeaveScope(); 72 | //GlobalAssembler.ForceNextLoads(false); 73 | 74 | if constexpr(Assemble) 75 | { 76 | GlobalAssembler.AddOperation(SPIRVOperation(spv::OpBranch), &Node.pThenBranch); // end of then block 77 | 78 | const uint32_t uFalseLableId = GlobalAssembler.AddOperation(SPIRVOperation(spv::OpLabel)); 79 | Node.pThenBranch->AddIntermediate(uFalseLableId); 80 | 81 | std::vector& Operands = Node.pSelectionMerge->GetOperands(); 82 | HASSERT(Operands.size() == 2u, "Invalid number of operands for selection merge"); 83 | Operands.front().uId = uFalseLableId; // use false label as merge label 84 | 85 | Node.pBranchConditional->AddIntermediate(uFalseLableId); 86 | } 87 | } 88 | 89 | return Node; 90 | } 91 | 92 | //--------------------------------------------------------------------------------------------------- 93 | 94 | template 95 | template 96 | inline void BranchNode::ElseNode(const LambdaFunc& _Func) 97 | { 98 | if constexpr (Assemble) 99 | { 100 | GlobalAssembler.EnterScope(); 101 | _Func(); 102 | GlobalAssembler.LeaveScope(); 103 | 104 | HASSERT(pThenBranch != nullptr && pSelectionMerge != nullptr, "Invalid branch node"); 105 | 106 | // end of then block 107 | SPIRVOperation* pElseBranch = nullptr; 108 | GlobalAssembler.AddOperation(SPIRVOperation(spv::OpBranch), &pElseBranch); 109 | 110 | // selection merge 111 | std::vector& SelectionOperands = pSelectionMerge->GetOperands(); 112 | HASSERT(SelectionOperands.size() == 2u, "Invalid number of operands for selection merge"); 113 | const uint32_t uMergeId = GlobalAssembler.AddOperation(SPIRVOperation(spv::OpLabel)); 114 | SelectionOperands.front().uId = uMergeId; 115 | 116 | // then branch update 117 | std::vector& ThenOperands = pThenBranch->GetOperands(); 118 | HASSERT(ThenOperands.size() == 1u, "Invalid number of operands for then branch"); 119 | ThenOperands.front().uId = uMergeId; 120 | 121 | // end of else block 122 | pElseBranch->AddOperand(SPIRVOperand(kOperandType_Intermediate, uMergeId)); 123 | } 124 | else 125 | { 126 | if (bCondition == false) // we are in the not condition branch 127 | { 128 | _Func(); 129 | } 130 | } 131 | } 132 | //--------------------------------------------------------------------------------------------------- 133 | 134 | #pragma endregion 135 | 136 | //--------------------------------------------------------------------------------------------------- 137 | 138 | template > // CondFunc needs to return a var_t 139 | inline void WhileFunc(const CondFunc& _CondFunc, const LoopBody& _LoopBody, const spv::LoopControlMask _kLoopControl = spv::LoopControlMaskNone) 140 | { 141 | static_assert(is_var, "Condition function must return a var_t type SPIR-V Variable"); 142 | 143 | if constexpr(VarT::AssembleMode == false) //Assemble == false 144 | { 145 | while (_CondFunc().Value) 146 | { 147 | _LoopBody(); 148 | } 149 | } 150 | else 151 | { 152 | // merge branch label 153 | SPIRVOperation* pOpBranch = nullptr; 154 | GlobalAssembler.AddOperation(SPIRVOperation(spv::OpBranch), &pOpBranch); // close previous block 155 | const uint32_t uLoopMergeId = GlobalAssembler.AddOperation(SPIRVOperation(spv::OpLabel)); 156 | pOpBranch->AddIntermediate(uLoopMergeId); 157 | 158 | // loop merge 159 | SPIRVOperation* pOpLoopMerge = nullptr; 160 | GlobalAssembler.AddOperation(SPIRVOperation(spv::OpLoopMerge), &pOpLoopMerge); 161 | 162 | // condition branch label 163 | GlobalAssembler.AddOperation(SPIRVOperation(spv::OpBranch), &pOpBranch); 164 | const uint32_t uConditionLabelId = GlobalAssembler.AddOperation(SPIRVOperation(spv::OpLabel)); 165 | pOpBranch->AddIntermediate(uConditionLabelId); 166 | 167 | // tranlate condition var 168 | GlobalAssembler.EnterScope(); 169 | const auto& CondVar = _CondFunc(); 170 | GlobalAssembler.LeaveScope(); 171 | 172 | // branch conditional %cond %loopbody %exit 173 | SPIRVOperation* pOpBranchCond = nullptr; 174 | GlobalAssembler.AddOperation(SPIRVOperation(spv::OpBranchConditional), &pOpBranchCond); 175 | const uint32_t uLoopBodyId = GlobalAssembler.AddOperation(SPIRVOperation(spv::OpLabel)); 176 | pOpBranchCond->AddIntermediate(CondVar.Load()); 177 | pOpBranchCond->AddIntermediate(uLoopBodyId); 178 | 179 | GlobalAssembler.EnterScope(); 180 | _LoopBody(); 181 | GlobalAssembler.LeaveScope(); 182 | 183 | // close block 184 | GlobalAssembler.AddOperation(SPIRVOperation(spv::OpBranch), &pOpBranch); 185 | const uint32_t uBlockExit = GlobalAssembler.AddOperation(SPIRVOperation(spv::OpLabel)); 186 | pOpBranch->AddIntermediate(uBlockExit); 187 | 188 | // exit branch label 189 | GlobalAssembler.AddOperation(SPIRVOperation(spv::OpBranch), &pOpBranch); 190 | const uint32_t uExitId = GlobalAssembler.AddOperation(SPIRVOperation(spv::OpLabel)); 191 | pOpBranch->AddIntermediate(uLoopMergeId); 192 | 193 | pOpLoopMerge->AddIntermediate(uExitId); // merge block 194 | pOpLoopMerge->AddIntermediate(uBlockExit); // continue 195 | pOpLoopMerge->AddLiteral((uint32_t)_kLoopControl); 196 | 197 | pOpBranchCond->AddIntermediate(uExitId); // structured merge 198 | 199 | //GlobalAssembler.ForceNextLoads(false); 200 | } 201 | } 202 | //--------------------------------------------------------------------------------------------------- 203 | 204 | template> // CondFunc needs to return a var_t 205 | inline void ForFunc(const CondFunc& _CondFunc, const IncFunc& _IncFunc, const LoopBody& _LoopBody, const spv::LoopControlMask _kLoopControl = spv::LoopControlMaskNone) 206 | { 207 | static_assert(is_var, "Condition function must return a var_t type SPIR-V Variable"); 208 | 209 | if constexpr(VarT::AssembleMode == false) 210 | { 211 | for (; _CondFunc().Value; _IncFunc()) 212 | { 213 | _LoopBody(); 214 | } 215 | } 216 | else 217 | { 218 | // branch %merge 219 | // label %merge 220 | // loopmerge 221 | // branch %cond 222 | // label %cond 223 | // Condition Code 224 | // branch_conditional 225 | // label %loopbody 226 | // LoopBody code 227 | // branch %increment 228 | // label %increment 229 | // Increment Code 230 | // branch %exit 231 | // label %exit 232 | 233 | // merge branch label 234 | SPIRVOperation* pOpBranch = nullptr; 235 | GlobalAssembler.AddOperation(SPIRVOperation(spv::OpBranch), &pOpBranch); // close previous block 236 | const uint32_t uLoopMergeId = GlobalAssembler.AddOperation(SPIRVOperation(spv::OpLabel)); 237 | pOpBranch->AddIntermediate(uLoopMergeId); 238 | 239 | // loop merge 240 | SPIRVOperation* pOpLoopMerge = nullptr; 241 | GlobalAssembler.AddOperation(SPIRVOperation(spv::OpLoopMerge), &pOpLoopMerge); 242 | 243 | // condition branch label 244 | GlobalAssembler.AddOperation(SPIRVOperation(spv::OpBranch), &pOpBranch); 245 | const uint32_t uConditionLabelId = GlobalAssembler.AddOperation(SPIRVOperation(spv::OpLabel)); 246 | pOpBranch->AddIntermediate(uConditionLabelId); 247 | 248 | //GlobalAssembler.ForceNextLoads(); 249 | 250 | // tranlate condition var 251 | GlobalAssembler.EnterScope(); 252 | const auto& CondVar = _CondFunc(); 253 | GlobalAssembler.LeaveScope(); 254 | 255 | // branch conditional %cond %loopbody %exit 256 | SPIRVOperation* pOpBranchCond = nullptr; 257 | GlobalAssembler.AddOperation(SPIRVOperation(spv::OpBranchConditional), &pOpBranchCond); 258 | const uint32_t uLoopBodyId = GlobalAssembler.AddOperation(SPIRVOperation(spv::OpLabel)); 259 | pOpBranchCond->AddIntermediate(CondVar.Load()); 260 | pOpBranchCond->AddIntermediate(uLoopBodyId); 261 | 262 | GlobalAssembler.EnterScope(); 263 | _LoopBody(); 264 | GlobalAssembler.LeaveScope(); 265 | 266 | // inrement branch label 267 | GlobalAssembler.AddOperation(SPIRVOperation(spv::OpBranch), &pOpBranch); 268 | const uint32_t uIncrementId = GlobalAssembler.AddOperation(SPIRVOperation(spv::OpLabel)); 269 | pOpBranch->AddIntermediate(uIncrementId); 270 | 271 | GlobalAssembler.EnterScope(); 272 | _IncFunc(); 273 | GlobalAssembler.LeaveScope(); 274 | 275 | // exit branch label 276 | GlobalAssembler.AddOperation(SPIRVOperation(spv::OpBranch), &pOpBranch); 277 | const uint32_t uExitId = GlobalAssembler.AddOperation(SPIRVOperation(spv::OpLabel)); 278 | pOpBranch->AddIntermediate(uLoopMergeId); 279 | 280 | pOpLoopMerge->AddIntermediate(uExitId); 281 | pOpLoopMerge->AddIntermediate(uIncrementId); 282 | pOpLoopMerge->AddLiteral((uint32_t)_kLoopControl); 283 | 284 | pOpBranchCond->AddIntermediate(uExitId); // structured merge 285 | 286 | //GlobalAssembler.ForceNextLoads(false); 287 | } 288 | } 289 | //--------------------------------------------------------------------------------------------------- 290 | // helper macros 291 | 292 | #ifndef ExprCaptureRule 293 | #define ExprCaptureRule = 294 | #endif 295 | 296 | #ifndef While 297 | #define While(_cond) WhileFunc([ExprCaptureRule](){return _cond;}, [ExprCaptureRule]() 298 | #endif // !While 299 | 300 | #ifndef For 301 | #define For(_var, _cond, _inc) _var; ForFunc([ExprCaptureRule](){return _cond;}, [ExprCaptureRule](){_inc;}, [ExprCaptureRule]() 302 | #endif // !While 303 | 304 | #pragma region if_else 305 | // renamed If and Else functions so that the macros are not part of the name 306 | #ifndef If 307 | #define If(_cond) IfNode((_cond), [ExprCaptureRule]() 308 | #endif // !If 309 | 310 | #ifndef Endif 311 | #define Endif ); 312 | #endif // !Endif 313 | 314 | #ifndef Else 315 | #define Else ).ElseNode([ExprCaptureRule]() 316 | #endif // !Else 317 | 318 | #ifndef IF 319 | #define IF(_cond) IfNode((_cond), [ExprCaptureRule]() { 320 | #endif // !If 321 | 322 | #ifndef ENDIF 323 | #define ENDIF }); 324 | #endif // !Endif 325 | 326 | #ifndef ELSE 327 | #define ELSE }).ElseNode([ExprCaptureRule]() { 328 | #endif // !Else 329 | //--------------------------------------------------------------------------------------------------- 330 | 331 | } // !Spear 332 | 333 | #endif // !SPEAR_SPIRVBRANCHNODE_H 334 | -------------------------------------------------------------------------------- /SPIRVGen/SPIRVComplex.h: -------------------------------------------------------------------------------- 1 | //Copyright(c) 2018 2 | //Authors: Fabian Wahlster 3 | //Website: https://twitter.com/singul4rity 4 | //Contact: f.wahlster@tum.de 5 | //License: MIT with attribution (see LICENSE.txt) 6 | 7 | #ifndef SPEAR_SPIRVCOMPLEX_H 8 | #define SPEAR_SPIRVCOMPLEX_H 9 | 10 | #include "SPIRVOperatorImpl.h" 11 | 12 | namespace Spear 13 | { 14 | // z = a + bi 15 | // a = real, b = imag 16 | template 17 | struct SPIRVComplex : public var_t 18 | { 19 | using var_t::var_t; 20 | 21 | //template 22 | //SPIRVComplex(const Ts& ... args) : VarType(args...) {} 23 | 24 | template 25 | const SPIRVComplex& operator=(const SPIRVComplex& _Other) const; 26 | 27 | var_t Conjugate() const; 28 | var_t Norm() const; 29 | SPIRVComplex Inverse() const; 30 | 31 | // operators 32 | template 33 | const SPIRVComplex& operator*=(const SPIRVComplex& _Other) const; 34 | 35 | template 36 | const SPIRVComplex& operator/=(const SPIRVComplex& _Other) const; 37 | }; 38 | 39 | //--------------------------------------------------------------------------------------------------- 40 | // assignment 41 | template 42 | template 43 | inline const SPIRVComplex& SPIRVComplex::operator=(const SPIRVComplex& _Other) const 44 | { 45 | var_t::operator=(_Other); 46 | return *this; 47 | } 48 | 49 | //--------------------------------------------------------------------------------------------------- 50 | template 51 | inline var_t SPIRVComplex::Conjugate() const 52 | { 53 | return Dot(*this, *this); 54 | //return x*x + y*y; 55 | } 56 | //--------------------------------------------------------------------------------------------------- 57 | 58 | template 59 | inline var_t SPIRVComplex::Norm() const 60 | { 61 | return Sqrt(Conjugate()); 62 | } 63 | //--------------------------------------------------------------------------------------------------- 64 | // inverse 65 | template 66 | inline SPIRVComplex SPIRVComplex::Inverse() const 67 | { 68 | auto COut = SPIRVComplex(); 69 | const var_t fRcpConj = 1.0f / Conjugate(); 70 | COut.x = x * fRcpConj; 71 | COut.y = -1.0f * (y * fRcpConj); 72 | return COut; 73 | } 74 | 75 | //--------------------------------------------------------------------------------------------------- 76 | // Complex Multiplication 77 | template 78 | inline void CMul(const SPIRVComplex& _c1, const SPIRVComplex& _c2, const SPIRVComplex& _cOut) 79 | { 80 | // z1z2 = (a1 + b1i)(a2 + b2i) = 81 | // = (a1a2 - b1b2)(a1b2 + b1a2)i 82 | const auto A1 = _c1.x; const auto B1 = _c1.y; 83 | const auto A2 = _c2.x; const auto B2 = _c2.y; 84 | _cOut.x = A1 * A2 - B1 * B2; 85 | _cOut.y = A1 * B2 + B1 * A2; 86 | } 87 | 88 | template 89 | template 90 | inline const SPIRVComplex& SPIRVComplex::operator*=(const SPIRVComplex& _Other) const 91 | { 92 | CMul(*this, _Other, *this); 93 | return *this; 94 | } 95 | 96 | template 97 | inline const SPIRVComplex operator*(const SPIRVComplex& _c1, const SPIRVComplex& _c2) 98 | { 99 | auto COut = SPIRVComplex(); 100 | CMul(_c1, _c2, COut); 101 | return COut; 102 | } 103 | 104 | //--------------------------------------------------------------------------------------------------- 105 | // Complex Division 106 | template 107 | inline void CDiv(const SPIRVComplex& _c1, const SPIRVComplex& _c2, SPIRVComplex& _cOut) 108 | { 109 | // z1+z2 = (a1 + b1i)/(a2 + b2i) = 110 | // = (a1a2+b1b2)/(a2^2+b2^2) + (b1a2-a1b2)/(a2^2+b2^2)i 111 | const auto A1 = _c1.x; const auto B1 = _c1.y; 112 | const auto A2 = _c2.x; const auto B2 = _c2.y; 113 | const auto fRcpDenom = 1.0f / (A2 * A2 + B2 * B2); 114 | _cOut.x = (A1*A2 + B1*B2) * fRcpDenom; 115 | _cOut.y = (B1*A2 - A1*B2) * fRcpDenom; 116 | } 117 | 118 | template 119 | template 120 | inline const SPIRVComplex& SPIRVComplex::operator/=(const SPIRVComplex& _Other) const 121 | { 122 | CDiv(*this, _Other, *this); 123 | return *this; 124 | } 125 | 126 | template 127 | inline const SPIRVComplex operator/(const SPIRVComplex& _c1, const SPIRVComplex& _c2) 128 | { 129 | auto COut = SPIRVComplex(); 130 | CDiv(_c1, _c2, COut); 131 | return COut; 132 | } 133 | 134 | //--------------------------------------------------------------------------------------------------- 135 | // global operators from float2 136 | template 137 | inline const SPIRVComplex operator*(const SPIRVComplex& _c1, const var_t& _fScalar) 138 | { 139 | return static_cast&>(_c1) * static_cast&>(_fScalar); 140 | } 141 | 142 | template 143 | inline const SPIRVComplex operator/(const SPIRVComplex& _c1, const var_t& _fScalar) 144 | { 145 | return static_cast&>(_c1) / static_cast&>(_fScalar); 146 | } 147 | 148 | template 149 | inline const SPIRVComplex operator+(const SPIRVComplex& _c1, const SPIRVComplex& _c2) 150 | { 151 | return static_cast&>(_c1) + static_cast&>(_c2); 152 | } 153 | 154 | template 155 | inline const SPIRVComplex operator-(const SPIRVComplex& _c1, const SPIRVComplex& _c2) 156 | { 157 | return static_cast&>(_c1) - static_cast&>(_c2); 158 | } 159 | } 160 | 161 | #endif // !SPEAR_SPIRVCOMPLEX_H -------------------------------------------------------------------------------- /SPIRVGen/SPIRVConstant.cpp: -------------------------------------------------------------------------------- 1 | //Copyright(c) 2018 2 | //Authors: Fabian Wahlster 3 | //Website: https://twitter.com/singul4rity 4 | //Contact: f.wahlster@tum.de 5 | //License: MIT with attribution (see LICENSE.txt) 6 | 7 | #include "SPIRVConstant.h" 8 | #include "HashUtils.h" 9 | #include "Logger.h" 10 | 11 | using namespace Spear; 12 | //--------------------------------------------------------------------------------------------------- 13 | 14 | SPIRVConstant::SPIRVConstant( 15 | const spv::Op _kConstantType, 16 | const SPIRVType& _CompositeType, 17 | const std::vector& _Constants) : 18 | m_kConstantType(_kConstantType), 19 | m_CompositeType(_CompositeType), 20 | m_Constants(_Constants) 21 | { 22 | HASSERT(_kConstantType >= spv::OpConstantTrue && _kConstantType <= spv::OpSpecConstantOp, "Invalid constant type"); 23 | switch (_kConstantType) 24 | { 25 | case spv::OpConstantTrue: 26 | case spv::OpConstantFalse: 27 | case spv::OpSpecConstantTrue: 28 | case spv::OpSpecConstantFalse: 29 | m_CompositeType = SPIRVType::Bool(); 30 | default: 31 | break; 32 | } 33 | } 34 | //--------------------------------------------------------------------------------------------------- 35 | 36 | SPIRVConstant::SPIRVConstant( 37 | const spv::Op _kConstantType, 38 | const SPIRVType& _CompositeType, 39 | const std::vector& _Components) : 40 | m_kConstantType(_kConstantType), 41 | m_CompositeType(_CompositeType), 42 | m_Components(_Components) 43 | { 44 | HASSERT(_kConstantType == spv::OpConstantComposite || _kConstantType == spv::OpSpecConstantComposite, "Invalid constant type"); 45 | } 46 | //--------------------------------------------------------------------------------------------------- 47 | 48 | SPIRVConstant::~SPIRVConstant() 49 | { 50 | } 51 | 52 | //--------------------------------------------------------------------------------------------------- 53 | SPIRVConstant::SPIRVConstant(const SPIRVConstant& _Other) : 54 | m_kConstantType(_Other.m_kConstantType), 55 | m_CompositeType(_Other.m_CompositeType), 56 | m_Constants(_Other.m_Constants), 57 | m_Components(_Other.m_Components) 58 | { 59 | } 60 | //--------------------------------------------------------------------------------------------------- 61 | size_t SPIRVConstant::GetHash(const bool _bParent) const 62 | { 63 | size_t uHash = hlx::CombineHashes(hlx::Hash(m_kConstantType), _bParent ? m_CompositeType.GetHash() : kUndefinedSizeT); 64 | 65 | for (const uint32_t& cval : m_Constants) 66 | { 67 | uHash = hlx::CombineHashes(uHash, cval); 68 | } 69 | 70 | for (const SPIRVConstant& Component : m_Components) 71 | { 72 | uHash = hlx::CombineHashes(uHash, Component.GetHash(false)); 73 | } 74 | 75 | return uHash; 76 | } 77 | //--------------------------------------------------------------------------------------------------- 78 | -------------------------------------------------------------------------------- /SPIRVGen/SPIRVConstant.h: -------------------------------------------------------------------------------- 1 | //Copyright(c) 2018 2 | //Authors: Fabian Wahlster 3 | //Website: https://twitter.com/singul4rity 4 | //Contact: f.wahlster@tum.de 5 | //License: MIT with attribution (see LICENSE.txt) 6 | 7 | #ifndef SPEAR_SPIRVCONSTANT_H 8 | #define SPEAR_SPIRVCONSTANT_H 9 | 10 | #include "SPIRVType.h" 11 | 12 | namespace Spear 13 | { 14 | class SPIRVConstant 15 | { 16 | public: 17 | explicit SPIRVConstant( 18 | const spv::Op _kConstantType = spv::OpConstantNull, 19 | const SPIRVType& _CompositeType = {}, 20 | const std::vector& _Constants = {}); 21 | 22 | explicit SPIRVConstant( 23 | const spv::Op _kConstantType, 24 | const SPIRVType& _CompositeType, 25 | const std::vector& _Components); 26 | 27 | ~SPIRVConstant(); 28 | 29 | template 30 | static SPIRVConstant MakeVec(const Container& _Elements, const bool _bSpec = false); 31 | 32 | // null 33 | inline static SPIRVConstant Make() { return SPIRVConstant(spv::OpConstantNull); }; 34 | 35 | // primitive 36 | template 37 | static SPIRVConstant Make(const T& _const, const bool _bSpec = false); 38 | 39 | SPIRVConstant(const SPIRVConstant& _Other); 40 | 41 | size_t GetHash(const bool _bParent = true) const; 42 | 43 | const spv::Op& GetType() const noexcept; 44 | const SPIRVType& GetCompositeType() const noexcept; 45 | const std::vector& GetLiterals() const noexcept; 46 | const std::vector& GetComponents() const noexcept; 47 | 48 | private: 49 | spv::Op m_kConstantType = spv::OpNop; 50 | 51 | std::vector m_Components; 52 | 53 | SPIRVType m_CompositeType; 54 | std::vector m_Constants; // binary data 55 | }; 56 | 57 | inline bool operator==(const SPIRVConstant& l, const SPIRVConstant& r) 58 | { 59 | return l.GetHash() == r.GetHash(); 60 | } 61 | 62 | inline bool operator!=(const SPIRVConstant& l, const SPIRVConstant& r) 63 | { 64 | return l.GetHash() != r.GetHash(); 65 | } 66 | 67 | inline const spv::Op& SPIRVConstant::GetType() const noexcept 68 | { 69 | return m_kConstantType; 70 | } 71 | inline const SPIRVType& SPIRVConstant::GetCompositeType() const noexcept 72 | { 73 | return m_CompositeType; 74 | } 75 | inline const std::vector& SPIRVConstant::GetLiterals() const noexcept 76 | { 77 | return m_Constants; 78 | } 79 | inline const std::vector& SPIRVConstant::GetComponents() const noexcept 80 | { 81 | return m_Components; 82 | } 83 | 84 | //--------------------------------------------------------------------------------------------------- 85 | 86 | inline size_t LiteralCount(const size_t uSizeInBytes) noexcept 87 | { 88 | if (uSizeInBytes % sizeof(uint32_t) == 0) 89 | { 90 | return uSizeInBytes / sizeof(uint32_t); 91 | } 92 | else 93 | { 94 | return static_cast(std::ceil(uSizeInBytes / static_cast(sizeof(uint32_t)))); 95 | } 96 | } 97 | 98 | inline std::vector MakeLiteralString(const std::string& _sString) 99 | { 100 | struct chars 101 | { 102 | char elem[sizeof(uint32_t)]; 103 | }; 104 | 105 | std::vector Literals(LiteralCount(_sString.size()), 0u); 106 | 107 | uint32_t i = 0u; 108 | for (const char& c : _sString) 109 | { 110 | chars& chunk = reinterpret_cast(Literals[i / sizeof(uint32_t)]); 111 | chunk.elem[i % sizeof(uint32_t)] = c; 112 | ++i; 113 | } 114 | 115 | // add string terminator 116 | if (i % sizeof(uint32_t) == 0u) 117 | { 118 | Literals.push_back(0u); 119 | } 120 | 121 | return Literals; 122 | } 123 | 124 | //--------------------------------------------------------------------------------------------------- 125 | 126 | // Helper 127 | template 128 | inline std::vector MakeLiterals(const T& _Constant, const Ts& ..._args) 129 | { 130 | // TODO: check if T is a std::string and call MakeLiteralString 131 | 132 | // compute number of uint32_t chunks needed to represent the constants 133 | const size_t uCount = std::max(LiteralCount(sizeof(T)), 1ull); 134 | std::vector ConstData(uCount, 0u); 135 | std::memcpy(ConstData.data(), &_Constant, sizeof(T)); 136 | 137 | if constexpr(sizeof...(_args) > 0u) 138 | { 139 | auto&& vec = MakeLiterals(_args...); 140 | ConstData.insert(ConstData.end(), vec.begin(), vec.end()); 141 | } 142 | 143 | return ConstData; 144 | } 145 | 146 | //--------------------------------------------------------------------------------------------------- 147 | 148 | template 149 | inline SPIRVConstant SPIRVConstant::MakeVec(const Container& _Elements, const bool _bSpec) 150 | { 151 | std::vector Components; 152 | for (const T& c : _Elements) 153 | { 154 | Components.emplace_back(Make(c, _bSpec)); 155 | } 156 | 157 | return SPIRVConstant( 158 | _bSpec ? spv::OpSpecConstantComposite : spv::OpConstantComposite, 159 | SPIRVType::Vec(static_cast(_Elements.size())), 160 | Components); 161 | } 162 | 163 | template 164 | inline SPIRVConstant SPIRVConstant::Make(const T& _const, const bool _bSpec) 165 | { 166 | constexpr bool SupportedType = std::is_same_v || is_scalar || is_vector || is_matrix; 167 | static_assert(SupportedType, "Type not supported for spirv constant"); 168 | 169 | // TODO: implement arrays! 170 | 171 | if constexpr(std::is_same_v) 172 | { 173 | if (_bSpec) 174 | return SPIRVConstant(_const ? spv::OpSpecConstantTrue : spv::OpSpecConstantFalse); 175 | else 176 | return SPIRVConstant(_const ? spv::OpConstantTrue : spv::OpConstantFalse); 177 | } 178 | else if constexpr(is_scalar) 179 | { 180 | return SPIRVConstant( 181 | _bSpec ? spv::OpSpecConstant : spv::OpConstant, 182 | SPIRVType::FromType(), 183 | MakeLiterals(_const)); 184 | } 185 | else if constexpr(is_vector) 186 | { 187 | constexpr uint32_t N{ Dimension }; 188 | std::vector Components; // elements 189 | for (uint32_t i = 0; i < N; ++i) 190 | { 191 | Components.emplace_back(Make(_const[i], _bSpec)); // not sure if spec needs to be propagated 192 | } 193 | 194 | return SPIRVConstant( 195 | _bSpec ? spv::OpSpecConstantComposite : spv::OpConstantComposite, 196 | SPIRVType::FromType(), 197 | Components); 198 | } 199 | else if constexpr(is_matrix) 200 | { 201 | constexpr uint32_t N = mat_dim::Rows; 202 | std::vector Components; // cols 203 | for (uint32_t i = 0; i < N; ++i) 204 | { 205 | Components.emplace_back(Make(_const[i], _bSpec)); // not sure if spec needs to be propagated 206 | } 207 | 208 | return SPIRVConstant( 209 | _bSpec ? spv::OpSpecConstantComposite : spv::OpConstantComposite, 210 | SPIRVType::FromType(), 211 | Components); 212 | } 213 | else 214 | { 215 | return SPIRVConstant(spv::OpConstantNull); 216 | } 217 | } 218 | 219 | }; // Spear 220 | 221 | #endif // !SPEAR_SPIRVCONSTANT_H 222 | -------------------------------------------------------------------------------- /SPIRVGen/SPIRVDecoration.cpp: -------------------------------------------------------------------------------- 1 | //Copyright(c) 2018 2 | //Authors: Fabian Wahlster 3 | //Website: https://twitter.com/singul4rity 4 | //Contact: f.wahlster@tum.de 5 | //License: MIT with attribution (see LICENSE.txt) 6 | 7 | #include "SPIRVDecoration.h" 8 | #include "Logger.h" 9 | 10 | using namespace Spear; 11 | 12 | //--------------------------------------------------------------------------------------------------- 13 | 14 | SPIRVOperation SPIRVDecoration::MakeOperation(const uint32_t _uTargetId, const uint32_t _uMemberIndex) const 15 | { 16 | const uint32_t uTargetId = _uTargetId == HUNDEFINED32 ? m_uTargetId : _uTargetId; 17 | const uint32_t uMemberIndex = _uMemberIndex == HUNDEFINED32 ? m_uMemberIndex : _uMemberIndex; 18 | 19 | HASSERT(uTargetId != HUNDEFINED32, "Invalid target id"); 20 | HASSERT(m_kDecoration < spv::DecorationMax, "Invalid decoration"); 21 | 22 | // target / base id 23 | std::vector Operands = { SPIRVOperand(kOperandType_Intermediate, uTargetId) }; 24 | 25 | spv::Op kOp = spv::OpNop; 26 | if (uMemberIndex == HUNDEFINED32) 27 | { 28 | kOp = spv::OpDecorate; 29 | } 30 | else 31 | { 32 | kOp = spv::OpMemberDecorate; 33 | Operands.push_back(SPIRVOperand::Literal(uMemberIndex)); 34 | } 35 | 36 | Operands.push_back(SPIRVOperand::Literal((uint32_t)m_kDecoration)); 37 | 38 | SPIRVOperation OpDecorate(kOp, Operands); 39 | OpDecorate.AddLiterals(m_Literals); 40 | 41 | return OpDecorate; 42 | } 43 | 44 | //--------------------------------------------------------------------------------------------------- 45 | -------------------------------------------------------------------------------- /SPIRVGen/SPIRVDecoration.h: -------------------------------------------------------------------------------- 1 | //Copyright(c) 2018 2 | //Authors: Fabian Wahlster 3 | //Website: https://twitter.com/singul4rity 4 | //Contact: f.wahlster@tum.de 5 | //License: MIT with attribution (see LICENSE.txt) 6 | 7 | #ifndef SPEAR_SPRIVDECORATION_H 8 | #define SPEAR_SPRIVDECORATION_H 9 | 10 | #include "SPIRVOperation.h" 11 | 12 | namespace Spear 13 | { 14 | class SPIRVDecoration 15 | { 16 | public: 17 | // invalid 18 | SPIRVDecoration() noexcept {} 19 | 20 | // explicit 21 | SPIRVDecoration( 22 | const spv::Decoration _kDecoration, 23 | const std::vector& _Literals, 24 | const uint32_t _uTargetId, 25 | const uint32_t _uMemberIndex) : 26 | m_kDecoration(_kDecoration), 27 | m_uTargetId(_uTargetId), 28 | m_uMemberIndex(_uMemberIndex), 29 | m_Literals(_Literals){} 30 | 31 | // helper 32 | SPIRVDecoration( 33 | const spv::Decoration _kDecoration, 34 | const uint32_t _uLiteral = HUNDEFINED32, 35 | const uint32_t _uMemberIndex = HUNDEFINED32, 36 | const uint32_t _uTargetId = HUNDEFINED32) : 37 | m_kDecoration(_kDecoration), 38 | m_uTargetId(_uTargetId), 39 | m_uMemberIndex(_uMemberIndex), 40 | m_Literals(_uLiteral != HUNDEFINED32 ? 1u : 0u, _uLiteral) {} 41 | 42 | ~SPIRVDecoration() {}; 43 | 44 | SPIRVOperation MakeOperation(const uint32_t _uTargetId = HUNDEFINED32, const uint32_t _uMemberIndex = HUNDEFINED32) const; 45 | 46 | private: 47 | spv::Decoration m_kDecoration = spv::DecorationMax; 48 | uint32_t m_uTargetId = HUNDEFINED32; 49 | uint32_t m_uMemberIndex = HUNDEFINED32; 50 | std::vector m_Literals; 51 | }; 52 | } // !Spear 53 | 54 | #endif // !SPEAR_SPRIVDECORATION_H 55 | -------------------------------------------------------------------------------- /SPIRVGen/SPIRVExtensionAMD.h: -------------------------------------------------------------------------------- 1 | //Copyright(c) 2018 2 | //Authors: Fabian Wahlster 3 | //Website: https://twitter.com/singul4rity 4 | //Contact: f.wahlster@tum.de 5 | //License: MIT with attribution (see LICENSE.txt) 6 | 7 | #ifndef SPEAR_SPIRVEXTENSIONAMD_H 8 | #define SPEAR_SPIRVEXTENSIONAMD_H 9 | 10 | #include "SPIRVOperatorImpl.h" 11 | 12 | namespace Spear 13 | { 14 | namespace ExtAMD 15 | { 16 | //https://www.khronos.org/registry/spir-v/extensions/AMD/SPV_AMD_gcn_shader.html 17 | 18 | static const std::string ExtGCNShader = "SPV_AMD_gcn_shader"; 19 | enum EGCNShader 20 | { 21 | kGCNShader_CubeFaceCoordAMD = 2, 22 | kGCNShader_CubeFaceIndexAMD = 1, 23 | kGCNShader_TimeAMD = 3, 24 | }; 25 | 26 | namespace GCNShader 27 | { 28 | //The function cubeFaceCoordAMD returns a two-component floating point vector that represents the 2D texture coordinates that would be used for accessing the selected cube map face for the given cube map texture coordinates given as parameter P. 29 | template 30 | inline var_t CubeFaceCoord(const var_t& _Point) 31 | { 32 | // TODO: implement uv lookup 33 | const auto facecoord = [](const float3_t& p) -> float2_t 34 | { 35 | return { 0.f, 0.f }; 36 | }; 37 | 38 | return make_ext_op1(_Point, facecoord, ExtGCNShader, kGCNShader_CubeFaceCoordAMD); 39 | } 40 | 41 | //The function CubeFaceIndexAMD returns a single floating point value that represents the index of the cube map face that would be accessed by texture lookup functions for the cube map texture coordinates given as parameter. The returned value correspond to cube map faces as follows: 42 | template 43 | inline var_t CubeFaceIndex(const var_t& _Point) 44 | { 45 | // TODO: implement index lookup 46 | const auto faceindex = [](const float3_t& p) -> float 47 | { 48 | return 0.f; 49 | }; 50 | 51 | return make_ext_op1(_Point, faceindex, ExtGCNShader, kGCNShader_CubeFaceIndexAMD); 52 | } 53 | 54 | //The timeAMD function returns a 64-bit value representing the current execution clock as seen by the shader processor. Time monotonically increments as the processor executes instructions. The returned time will wrap after it exceeds the maximum value representable in 64 bits. The units of time are not defined and need not be constant. Time is not dynamically uniform. That is, shader invocations executing as part of a single draw or dispatch will not necessarily see the same value of time. Time is also not guaranteed to be consistent across shader stages. For example, there is no requirement that time sampled inside a fragment shader invocation will be greater than the time sampled in the vertex that lead to its execution. 55 | template 56 | inline var_t Time() 57 | { 58 | const auto time = []() -> int64_t 59 | { 60 | return static_cast(CPUClockType::now().time_since_epoch().count()); 61 | }; 62 | 63 | return make_ext_op0(time, ExtGCNShader, kGCNShader_TimeAMD); 64 | } 65 | } 66 | } // extamd 67 | } // Spear 68 | 69 | #endif // !SPEAR_SPIRVEXTENSIONAMD_H 70 | -------------------------------------------------------------------------------- /SPIRVGen/SPIRVInlineAssembler.h: -------------------------------------------------------------------------------- 1 | //Copyright(c) 2018 2 | //Authors: Fabian Wahlster 3 | //Website: https://twitter.com/singul4rity 4 | //Contact: f.wahlster@tum.de 5 | //License: MIT with attribution (see LICENSE.txt) 6 | 7 | #ifndef SPEAR_SPIRVINLINEASSEMBLER_H 8 | #define SPEAR_SPIRVINLINEASSEMBLER_H 9 | 10 | #include "SPIRVAssembler.h" 11 | #include "SPIRVProgram.h" 12 | 13 | namespace Spear 14 | { 15 | template 16 | class SPIRVInlineFunctor : public SPIRVProgram 17 | { 18 | public: 19 | SPIRVInlineFunctor(const TLambdaFunc& _Func) : SPIRVProgram(), Func(_Func) {} 20 | inline void operator()(Ts&& ..._args){Func(std::forward(_args)...); } 21 | private: 22 | const TLambdaFunc& Func; 23 | }; 24 | 25 | #ifndef _spv_begin 26 | #define _spv_begin class _inl_spv : public Spear::SPIRVProgram { public: inline void operator()() { 27 | #endif // !_spv_begin 28 | #ifndef _spv_end 29 | #define _spv_end }}; 30 | #endif // !_spv_end 31 | 32 | #ifndef _spv_code 33 | #define _spv_code GlobalAssembler.AssembleSimple<_inl_spv>(); 34 | #endif // !_spv_code 35 | 36 | 37 | template 38 | SPIRVModule AssembleInline( 39 | const TLambdaFunc& _Func, 40 | const bool _bUseDefaults = true, 41 | Ts&& ..._args) 42 | { 43 | if (_bUseDefaults) 44 | { 45 | GlobalAssembler.SetDefaults(); 46 | } 47 | 48 | using TInlFunc = SPIRVInlineFunctor; 49 | GlobalAssembler.InitializeProgram(_Func); 50 | GlobalAssembler.RecordInstructions(std::forward(_args)...); 51 | return GlobalAssembler.Assemble(); 52 | } 53 | } // !Spear 54 | 55 | #endif // !SPEAR_SPIRVINLINEASSEMBLER_H 56 | -------------------------------------------------------------------------------- /SPIRVGen/SPIRVInstruction.cpp: -------------------------------------------------------------------------------- 1 | //Copyright(c) 2018 2 | //Authors: Fabian Wahlster 3 | //Website: https://twitter.com/singul4rity 4 | //Contact: f.wahlster@tum.de 5 | //License: MIT with attribution (see LICENSE.txt) 6 | 7 | #include "SPIRVInstruction.h" 8 | #include "SPIRVBinaryDefines.h" // for decode 9 | 10 | using namespace Spear; 11 | 12 | //--------------------------------------------------------------------------------------------------- 13 | 14 | SPIRVInstruction::SPIRVInstruction( 15 | const spv::Op _kOp, 16 | const uint32_t _uTypeId, 17 | const uint32_t _uResultId, 18 | const std::vector& _Operands) noexcept : 19 | m_kOperation(_kOp), 20 | m_uTypeId(_uTypeId), 21 | m_uResultId(_uResultId), 22 | m_Operands(_Operands) 23 | { 24 | } 25 | 26 | //--------------------------------------------------------------------------------------------------- 27 | 28 | uint32_t Decode(const std::vector& _Words, const uint32_t _uOffset, SPIRVInstruction& _OutInstr) 29 | { 30 | uint32_t uWordCount = 1; 31 | uint32_t uOffset = _uOffset; 32 | 33 | auto GetWord = [&]() -> uint32_t 34 | { 35 | return (uOffset < _Words.size() && (--uWordCount > 0)) ? _Words[uOffset++] : SPIRVInstruction::kInvalidId; 36 | }; 37 | 38 | const uint32_t& uOpCode = GetWord(); 39 | 40 | if (uOpCode != SPIRVInstruction::kInvalidId) 41 | { 42 | const spv::Op kOp = static_cast(uOpCode & spv::OpCodeMask); 43 | uWordCount = uOpCode & (spv::OpCodeMask << spv::WordCountShift); 44 | uint32_t uTypeId = SPIRVInstruction::kInvalidId; 45 | uint32_t uResultId = SPIRVInstruction::kInvalidId; 46 | std::vector Operands; 47 | 48 | const TSPVArgFlag kArgs = GetOpCodeArgs(kOp); 49 | 50 | if (kArgs.CheckFlag(kSPVOpArgs_TypeId)) 51 | { 52 | uTypeId = GetWord(); 53 | } 54 | 55 | if (kArgs.CheckFlag(kSPVOpArgs_ResultId)) 56 | { 57 | uResultId = GetWord(); 58 | } 59 | 60 | for (uint32_t uOperand = GetWord(); uOperand != SPIRVInstruction::kInvalidId; uOperand = GetWord()) 61 | { 62 | Operands.push_back(uOperand); 63 | } 64 | 65 | _OutInstr = SPIRVInstruction(kOp, uTypeId, uResultId, Operands); 66 | } 67 | 68 | return uOffset - _uOffset; 69 | } 70 | //--------------------------------------------------------------------------------------------------- 71 | 72 | SPIRVInstruction::~SPIRVInstruction() 73 | { 74 | } 75 | //--------------------------------------------------------------------------------------------------- 76 | 77 | uint32_t SPIRVInstruction::GetOpCode() const noexcept 78 | { 79 | uint16_t uWordCount = 1u + static_cast(m_Operands.size()); 80 | 81 | if (m_uTypeId != kInvalidId) 82 | ++uWordCount; 83 | 84 | if (m_uResultId != kInvalidId) 85 | ++uWordCount; 86 | 87 | return (m_kOperation & spv::OpCodeMask) | (uWordCount << spv::WordCountShift); 88 | } 89 | //--------------------------------------------------------------------------------------------------- 90 | 91 | std::string SPIRVInstruction::GetString() const 92 | { 93 | std::string sOp; 94 | if (m_uResultId != kInvalidId) 95 | { 96 | sOp = "%" + std::to_string(m_uResultId) + "="; 97 | } 98 | 99 | sOp = "\t" + GetOpCodeString(m_kOperation); 100 | 101 | if (m_uTypeId != kInvalidId) 102 | { 103 | sOp += " type_" + std::to_string(m_uTypeId); 104 | } 105 | 106 | std::string sLiteralStr; 107 | for (const uint32_t& uOperand : m_Operands) 108 | { 109 | if (uOperand < 255) 110 | { 111 | sOp += " op_"+ std::to_string(uOperand); 112 | } 113 | else 114 | { 115 | sLiteralStr += LiteralToString(uOperand); 116 | } 117 | } 118 | 119 | if (sLiteralStr.empty() == false) 120 | sOp += " " + sLiteralStr; 121 | 122 | return sOp; 123 | } 124 | //--------------------------------------------------------------------------------------------------- 125 | -------------------------------------------------------------------------------- /SPIRVGen/SPIRVInstruction.h: -------------------------------------------------------------------------------- 1 | //Copyright(c) 2018 2 | //Authors: Fabian Wahlster 3 | //Website: https://twitter.com/singul4rity 4 | //Contact: f.wahlster@tum.de 5 | //License: MIT with attribution (see LICENSE.txt) 6 | 7 | #ifndef SPEAR_SPIRVINSTRUCTION_H 8 | #define SPEAR_SPIRVINSTRUCTION_H 9 | 10 | #include 11 | #include 12 | 13 | namespace Spear 14 | { 15 | class SPIRVInstruction 16 | { 17 | public: 18 | static constexpr uint32_t kInvalidId = 0xffffffff; 19 | 20 | SPIRVInstruction( 21 | const spv::Op _kOp = spv::OpNop, 22 | const uint32_t _uTypeId = kInvalidId, 23 | const uint32_t _uResultId = kInvalidId, 24 | const std::vector& _Operands = {}) noexcept; 25 | 26 | //SPIRVInstruction(const std::vector& _Words); 27 | 28 | // raw instruction words to be decoded, returns number of consumed words, 0 if failed 29 | static uint32_t Decode(const std::vector& _Words, const uint32_t _uIndex, SPIRVInstruction& _OutInstr); 30 | 31 | ~SPIRVInstruction(); 32 | 33 | uint32_t GetOpCode() const noexcept; 34 | const uint32_t GetTypeId() const noexcept; 35 | const uint32_t& GetResultId() const noexcept; 36 | const std::vector& GetOperands() const noexcept; 37 | spv::Op GetOp() const noexcept; 38 | std::string GetString() const; 39 | 40 | private: 41 | spv::Op m_kOperation; 42 | 43 | uint32_t m_uTypeId = kInvalidId; 44 | uint32_t m_uResultId = kInvalidId; 45 | std::vector m_Operands; 46 | 47 | // format: 48 | // OpCode u16 49 | // WordCount u16 50 | // Id u32 (optional) 51 | // Result Id (optional) 52 | // Operands x u32 (WordCount-(1-3)) (optional) 53 | }; 54 | 55 | inline const uint32_t SPIRVInstruction::GetTypeId() const noexcept {return m_uTypeId;} 56 | inline const uint32_t& SPIRVInstruction::GetResultId() const noexcept { return m_uResultId; } 57 | inline const std::vector& SPIRVInstruction::GetOperands() const noexcept {return m_Operands;} 58 | inline spv::Op SPIRVInstruction::GetOp() const noexcept{return m_kOperation;} 59 | }; // Spear 60 | 61 | #endif // !SPEAR_SPIRVINSTRUCTION_H 62 | -------------------------------------------------------------------------------- /SPIRVGen/SPIRVModule.cpp: -------------------------------------------------------------------------------- 1 | //Copyright(c) 2018 2 | //Authors: Fabian Wahlster 3 | //Website: https://twitter.com/singul4rity 4 | //Contact: f.wahlster@tum.de 5 | //License: MIT with attribution (see LICENSE.txt) 6 | 7 | #include "SPIRVModule.h" 8 | #include "SPIRVInstruction.h" 9 | #include "HashUtils.h" 10 | #include 11 | 12 | using namespace Spear; 13 | //--------------------------------------------------------------------------------------------------- 14 | SPIRVModule::SPIRVModule(const SPIRVModule& _Other) : 15 | m_uBounds(_Other.m_uBounds), 16 | m_uGenerator(_Other.m_uGenerator), 17 | m_uSchema(_Other.m_uSchema), 18 | m_uSPVVersion(_Other.m_uSPVVersion), 19 | m_InstructionStream(_Other.m_InstructionStream), 20 | m_Extensions(_Other.m_Extensions), 21 | m_kMode(_Other.m_kMode), 22 | m_kModel(_Other.m_kModel), 23 | m_sEntryPoint(_Other.m_sEntryPoint), 24 | m_uHash(_Other.m_uHash), 25 | m_uSPVOperations(_Other.m_uSPVOperations), 26 | m_Variables(_Other.m_Variables) 27 | { 28 | } 29 | //--------------------------------------------------------------------------------------------------- 30 | 31 | SPIRVModule::SPIRVModule(const std::vector& _Optimized, const SPIRVModule& _Other) : 32 | m_uBounds(_Other.m_uBounds), 33 | m_uGenerator(_Other.m_uGenerator), 34 | m_uSchema(_Other.m_uSchema), 35 | m_uSPVVersion(_Other.m_uSPVVersion), 36 | m_InstructionStream(_Optimized), 37 | m_Extensions(_Other.m_Extensions), 38 | m_kMode(_Other.m_kMode), 39 | m_kModel(_Other.m_kModel), 40 | m_sEntryPoint(_Other.m_sEntryPoint), 41 | m_uSPVOperations(_Other.m_uSPVOperations), 42 | m_Variables(_Other.m_Variables) 43 | { 44 | m_uHash = 0u; 45 | 46 | for (const uint32_t& uWord : _Optimized) 47 | { 48 | m_uHash = hlx::AddHash(m_uHash, uWord); 49 | } 50 | } 51 | //--------------------------------------------------------------------------------------------------- 52 | SPIRVModule::SPIRVModule(const uint32_t _uBounds) noexcept : 53 | m_uBounds(_uBounds) 54 | { 55 | } 56 | //--------------------------------------------------------------------------------------------------- 57 | 58 | SPIRVModule::~SPIRVModule() 59 | { 60 | } 61 | 62 | //--------------------------------------------------------------------------------------------------- 63 | void SPIRVModule::Write(const std::vector& _Instructions) 64 | { 65 | m_InstructionStream.resize(0); 66 | m_uHash = 0u; 67 | 68 | // write header 69 | Put(spv::MagicNumber); 70 | Put(m_uSPVVersion); 71 | Put(uGenerator); // tracy 72 | Put(m_uBounds); // Bounds 73 | Put(uSchema); 74 | 75 | m_uSPVOperations = static_cast(_Instructions.size()); 76 | 77 | // write instructions 78 | for (const SPIRVInstruction& Instr : _Instructions) 79 | { 80 | Put(Instr); 81 | } 82 | } 83 | 84 | //--------------------------------------------------------------------------------------------------- 85 | 86 | bool SPIRVModule::Save(const std::string& _sFilePath) const 87 | { 88 | std::ofstream File(_sFilePath, std::ios::out | std::ios::binary); 89 | 90 | if (File.is_open() == false) 91 | return false; 92 | 93 | File.write(reinterpret_cast(m_InstructionStream.data()), m_InstructionStream.size() * sizeof(uint32_t)); 94 | File.close(); 95 | 96 | return true; 97 | } 98 | //--------------------------------------------------------------------------------------------------- 99 | 100 | void SPIRVModule::Put(const uint32_t& _uWord) 101 | { 102 | m_uHash = hlx::AddHash(m_uHash, _uWord); 103 | m_InstructionStream.push_back(_uWord); 104 | } 105 | //--------------------------------------------------------------------------------------------------- 106 | 107 | void SPIRVModule::Put(const SPIRVInstruction& _Instr) 108 | { 109 | // TODO: check if operation can be skipped (like OpNop etc) 110 | 111 | Put(_Instr.GetOpCode()); 112 | 113 | const uint32_t& uTypeId(_Instr.GetTypeId()); 114 | const uint32_t& uResultId(_Instr.GetResultId()); 115 | 116 | if(uTypeId != SPIRVInstruction::kInvalidId) 117 | Put(uTypeId); 118 | 119 | if (uResultId != SPIRVInstruction::kInvalidId) 120 | Put(uResultId); 121 | 122 | for (const uint32_t& uOperand : _Instr.GetOperands()) 123 | { 124 | Put(uOperand); 125 | } 126 | } 127 | //--------------------------------------------------------------------------------------------------- 128 | bool SPIRVModule::GetVariableByName(const std::string& _sName, VariableInfo & _OutVar) 129 | { 130 | for (const VariableInfo& Var : m_Variables) 131 | { 132 | if (Var.sName == _sName) 133 | { 134 | _OutVar = Var; 135 | return true; 136 | } 137 | } 138 | 139 | return false; 140 | } 141 | //--------------------------------------------------------------------------------------------------- 142 | 143 | size_t VariableInfo::ComputeHash() const 144 | { 145 | return 146 | hlx::CombineHashes(Type.GetHash(), 147 | hlx::Hash( 148 | kStorageClass, 149 | uMemberOffset, 150 | uDescriptorSet, 151 | uBinding, 152 | uLocation, 153 | uSpecConstId, 154 | uInputAttachmentIndex, 155 | bTexSampled, 156 | bTexStored, 157 | bInstanceData)); 158 | } 159 | //--------------------------------------------------------------------------------------------------- 160 | -------------------------------------------------------------------------------- /SPIRVGen/SPIRVModule.h: -------------------------------------------------------------------------------- 1 | //Copyright(c) 2018 2 | //Authors: Fabian Wahlster 3 | //Website: https://twitter.com/singul4rity 4 | //Contact: f.wahlster@tum.de 5 | //License: MIT with attribution (see LICENSE.txt) 6 | 7 | #ifndef SPEAR_SPIRVMODULE_H 8 | #define SPEAR_SPIRVMODULE_H 9 | 10 | #include "StandardDefines.h" 11 | #include "SPIRVType.h" 12 | 13 | namespace Spear 14 | { 15 | // forward decls 16 | class SPIRVInstruction; 17 | 18 | struct VariableInfo 19 | { 20 | uint32_t uVarId = HUNDEFINED32; 21 | SPIRVType Type; 22 | //std::vector Decorations; 23 | spv::StorageClass kStorageClass = spv::StorageClassMax; 24 | uint32_t uMemberOffset = HUNDEFINED32; 25 | uint32_t uDescriptorSet = HUNDEFINED32; 26 | uint32_t uBinding = HUNDEFINED32; 27 | uint32_t uLocation = HUNDEFINED32; 28 | uint32_t uSpecConstId = HUNDEFINED32; 29 | uint32_t uInputAttachmentIndex = HUNDEFINED32; 30 | bool bTexSampled = false; 31 | bool bTexStored = false; 32 | bool bInstanceData = false; 33 | bool bBuiltIn = false; 34 | std::string sName; 35 | 36 | // for internal use only 37 | uint32_t uStageFlags = 0u; // maps to vk::ShaderStageFlagBits 38 | size_t uHash = 0u; 39 | size_t ComputeHash() const; 40 | }; 41 | 42 | class SPIRVModule 43 | { 44 | public: 45 | SPIRVModule(const SPIRVModule& _Other); 46 | SPIRVModule(const std::vector& _Optimized, const SPIRVModule& _Other); 47 | SPIRVModule(const uint32_t _uBounds = 4096) noexcept; 48 | virtual ~SPIRVModule(); 49 | 50 | //bool Read(std::vector _InstructionStream); 51 | void Write(const std::vector& _Instructions); 52 | bool Save(const std::string& _sFilePath) const; 53 | 54 | static constexpr uint32_t uVersion = 1u; 55 | static constexpr uint32_t uGenerator = uVersion | 'ty' << 16u; 56 | static constexpr uint32_t uSchema = 0u; 57 | 58 | const std::vector& GetCode() const noexcept; 59 | 60 | const uint32_t& GetNumberOfOperations() const noexcept; 61 | 62 | void AddVariable(const VariableInfo& _VarInfo); 63 | const std::vector& GetVariables() const noexcept; 64 | 65 | void SetEntryPoint(const std::string& _sEntryPoint); 66 | const std::string& GetEntryPoint() const noexcept; 67 | 68 | void SetExtensions(const std::vector& _Extensions); 69 | const std::vector& GetExtensions() const noexcept; 70 | 71 | void SetCapabilities(const std::vector& _Capabilities); 72 | const std::vector& GetCapabilities() const noexcept; 73 | 74 | void SetExecutionMode(const spv::ExecutionMode _kMode) noexcept; 75 | void SetExecutionModel(const spv::ExecutionModel _kModel) noexcept; 76 | 77 | const spv::ExecutionMode& GetExectionMode() const noexcept; 78 | const spv::ExecutionModel& GetExectionModel() const noexcept; 79 | 80 | bool GetVariableByName(const std::string& _sName, VariableInfo& _OutVar); 81 | 82 | const size_t& GetHash() const noexcept; 83 | 84 | private: 85 | void Put(const uint32_t& _uWord); 86 | void Put(const SPIRVInstruction& _Instr); 87 | 88 | private: 89 | uint32_t m_uBounds = std::numeric_limits::max(); 90 | uint32_t m_uSchema = uSchema; 91 | uint32_t m_uGenerator = uGenerator; 92 | uint32_t m_uSPVVersion = 0x00010000;//spv::Version 93 | 94 | uint32_t m_uSPVOperations = 0u; 95 | std::vector m_InstructionStream; 96 | std::vector m_Variables; // no function class variables (in out uniform etc) 97 | 98 | size_t m_uHash = kUndefinedSizeT; 99 | 100 | std::string m_sEntryPoint; 101 | spv::ExecutionModel m_kModel = spv::ExecutionModelMax; 102 | spv::ExecutionMode m_kMode = spv::ExecutionModeMax; 103 | std::vector m_Extensions; 104 | std::vector m_Capabilities; 105 | }; 106 | 107 | inline const size_t& SPIRVModule::GetHash() const noexcept { return m_uHash; } 108 | 109 | inline const std::vector& SPIRVModule::GetCode() const noexcept 110 | { 111 | return m_InstructionStream; 112 | } 113 | 114 | inline const uint32_t& SPIRVModule::GetNumberOfOperations() const noexcept 115 | { 116 | return m_uSPVOperations; 117 | } 118 | 119 | inline void SPIRVModule::AddVariable(const VariableInfo& _VarInfo) 120 | { 121 | m_Variables.push_back(_VarInfo); 122 | } 123 | 124 | inline const std::vector& SPIRVModule::GetVariables() const noexcept 125 | { 126 | return m_Variables; 127 | } 128 | inline void SPIRVModule::SetEntryPoint(const std::string& _sEntryPoint) 129 | { 130 | m_sEntryPoint = _sEntryPoint; 131 | } 132 | inline const std::string& SPIRVModule::GetEntryPoint() const noexcept 133 | { 134 | return m_sEntryPoint; 135 | } 136 | inline void SPIRVModule::SetExtensions(const std::vector& _Extensions) 137 | { 138 | m_Extensions = _Extensions; 139 | } 140 | inline const std::vector& SPIRVModule::GetExtensions() const noexcept 141 | { 142 | return m_Extensions; 143 | } 144 | inline void SPIRVModule::SetCapabilities(const std::vector& _Capabilities) 145 | { 146 | m_Capabilities = _Capabilities; 147 | } 148 | inline const std::vector& SPIRVModule::GetCapabilities() const noexcept 149 | { 150 | return m_Capabilities; 151 | } 152 | inline void SPIRVModule::SetExecutionMode(const spv::ExecutionMode _kMode) noexcept 153 | { 154 | m_kMode = _kMode; 155 | } 156 | inline void SPIRVModule::SetExecutionModel(const spv::ExecutionModel _kModel) noexcept 157 | { 158 | m_kModel = _kModel; 159 | } 160 | inline const spv::ExecutionMode& SPIRVModule::GetExectionMode() const noexcept 161 | { 162 | return m_kMode; 163 | } 164 | inline const spv::ExecutionModel& SPIRVModule::GetExectionModel() const noexcept 165 | { 166 | return m_kModel; 167 | } 168 | }; // !Spear 169 | 170 | #endif // !SPEAR_SPIRVMODULE_H 171 | -------------------------------------------------------------------------------- /SPIRVGen/SPIRVOperation.cpp: -------------------------------------------------------------------------------- 1 | //Copyright(c) 2018 2 | //Authors: Fabian Wahlster 3 | //Website: https://twitter.com/singul4rity 4 | //Contact: f.wahlster@tum.de 5 | //License: MIT with attribution (see LICENSE.txt) 6 | 7 | #include "SPIRVOperation.h" 8 | #include "SPIRVBinaryDefines.h" 9 | 10 | using namespace Spear; 11 | 12 | SPIRVOperation::SPIRVOperation(const spv::Op _kOp, const uint32_t _uResultTypeId, const SPIRVOperand& _Operand) : 13 | m_kOpCode(_kOp), m_Operands(1u, _Operand), m_uResultTypeId(_uResultTypeId) 14 | { 15 | } 16 | //--------------------------------------------------------------------------------------------------- 17 | 18 | SPIRVOperation::SPIRVOperation(const spv::Op _kOp, const SPIRVOperand& _Operand) : 19 | m_kOpCode(_kOp), m_Operands(1u, _Operand) 20 | { 21 | } 22 | //--------------------------------------------------------------------------------------------------- 23 | 24 | SPIRVOperation::SPIRVOperation(const spv::Op _kOp, const uint32_t _uResultTypeId, const std::vector& _Operands) : 25 | m_kOpCode(_kOp), m_Operands(_Operands), m_uResultTypeId(_uResultTypeId) 26 | { 27 | } 28 | //--------------------------------------------------------------------------------------------------- 29 | 30 | SPIRVOperation::SPIRVOperation(const spv::Op _kOp, const uint32_t _uResultTypeId, std::vector&& _Operands) : 31 | m_kOpCode(_kOp), m_uResultTypeId(_uResultTypeId), m_Operands(std::move(_Operands)) 32 | { 33 | } 34 | //--------------------------------------------------------------------------------------------------- 35 | 36 | SPIRVOperation::SPIRVOperation(const spv::Op _kOp, const std::vector& _Operands) noexcept : 37 | m_kOpCode(_kOp), m_Operands(_Operands) 38 | { 39 | } 40 | //--------------------------------------------------------------------------------------------------- 41 | 42 | SPIRVOperation::SPIRVOperation(const spv::Op _kOp, const std::vector& _Literals) : 43 | m_kOpCode(_kOp) 44 | { 45 | AddLiterals(_Literals); 46 | } 47 | //--------------------------------------------------------------------------------------------------- 48 | 49 | SPIRVOperation::SPIRVOperation(const SPIRVOperation& _Other) : 50 | m_bTranslated(_Other.m_bTranslated), 51 | m_bUsed(_Other.m_bUsed), 52 | m_kOpCode(_Other.m_kOpCode), 53 | m_Operands(_Other.m_Operands), 54 | m_uInstrId(_Other.m_uInstrId), 55 | m_uResultId(_Other.m_uResultId), 56 | m_uResultTypeId(_Other.m_uResultTypeId) 57 | { 58 | } 59 | //--------------------------------------------------------------------------------------------------- 60 | 61 | SPIRVOperation::SPIRVOperation(SPIRVOperation&& _Other) : 62 | m_bTranslated(std::move(_Other.m_bTranslated)), 63 | m_bUsed(std::move(_Other.m_bUsed)), 64 | m_kOpCode(std::move(_Other.m_kOpCode)), 65 | m_Operands(std::move(_Other.m_Operands)), 66 | m_uInstrId(std::move(_Other.m_uInstrId)), 67 | m_uResultId(std::move(_Other.m_uResultId)), 68 | m_uResultTypeId(std::move(_Other.m_uResultTypeId)) 69 | { 70 | } 71 | //--------------------------------------------------------------------------------------------------- 72 | 73 | SPIRVOperation::~SPIRVOperation() 74 | { 75 | } 76 | //--------------------------------------------------------------------------------------------------- 77 | 78 | SPIRVOperation& SPIRVOperation::operator=(const SPIRVOperation & _Other) 79 | { 80 | m_bTranslated =_Other.m_bTranslated; 81 | m_bUsed = _Other.m_bUsed; 82 | m_kOpCode = _Other.m_kOpCode; 83 | m_Operands = _Other.m_Operands; 84 | m_uInstrId = _Other.m_uInstrId; 85 | m_uResultId = _Other.m_uResultId; 86 | m_uResultTypeId = _Other.m_uResultTypeId; 87 | return *this; 88 | } 89 | //--------------------------------------------------------------------------------------------------- 90 | 91 | SPIRVOperation& SPIRVOperation::operator=(SPIRVOperation&& _Other) 92 | { 93 | m_bTranslated = std::move(_Other.m_bTranslated); 94 | m_bUsed = std::move(_Other.m_bUsed); 95 | m_kOpCode = std::move(_Other.m_kOpCode); 96 | m_Operands = std::move(_Other.m_Operands); 97 | m_uInstrId = std::move(_Other.m_uInstrId); 98 | m_uResultId = std::move(_Other.m_uResultId); 99 | m_uResultTypeId = std::move(_Other.m_uResultTypeId); 100 | return *this; 101 | } 102 | //--------------------------------------------------------------------------------------------------- 103 | 104 | std::string SPIRVOperation::GetString() const 105 | { 106 | std::string sOp; 107 | 108 | if (m_uInstrId != HUNDEFINED32) 109 | { 110 | sOp += "%" + std::to_string(m_uInstrId) + " =\t"; 111 | } 112 | 113 | sOp += GetOpCodeString(m_kOpCode) + " "; 114 | 115 | if (m_uResultTypeId != HUNDEFINED32) 116 | { 117 | sOp += "%" + std::to_string(m_uResultTypeId) + "t "; 118 | } 119 | 120 | for (const SPIRVOperand& Operand : m_Operands) 121 | { 122 | if (Operand.kType == kOperandType_Intermediate) 123 | { 124 | sOp += "%" + std::to_string(Operand.uId) + "i "; 125 | } 126 | else if (Operand.kType == kOperandType_Literal) 127 | { 128 | if (Operand.uId < 255) 129 | { 130 | sOp += std::to_string(Operand.uId) + " "; 131 | } 132 | else 133 | { 134 | sOp += LiteralToString(Operand.uId) + " "; 135 | } 136 | } 137 | } 138 | 139 | return sOp; 140 | } 141 | //--------------------------------------------------------------------------------------------------- 142 | 143 | void SPIRVOperation::AddOperand(const SPIRVOperand& _Operand) 144 | { 145 | m_Operands.push_back(_Operand); 146 | } 147 | //--------------------------------------------------------------------------------------------------- 148 | 149 | void SPIRVOperation::AddIntermediate(const uint32_t _uId) 150 | { 151 | m_Operands.push_back(SPIRVOperand(kOperandType_Intermediate, _uId)); 152 | } 153 | //--------------------------------------------------------------------------------------------------- 154 | 155 | void SPIRVOperation::AddLiteral(const uint32_t _uLiteral1) 156 | { 157 | m_Operands.push_back(SPIRVOperand(kOperandType_Literal, _uLiteral1)); 158 | } 159 | //--------------------------------------------------------------------------------------------------- 160 | 161 | void SPIRVOperation::AddLiterals(const std::vector& _Literals) 162 | { 163 | for (const uint32_t& uLiteral : _Literals) 164 | { 165 | m_Operands.push_back(SPIRVOperand(kOperandType_Literal, uLiteral)); 166 | } 167 | } 168 | //--------------------------------------------------------------------------------------------------- 169 | 170 | void SPIRVOperation::AddTypes(const std::vector& _Types) 171 | { 172 | for (const uint32_t& uType : _Types) 173 | { 174 | m_Operands.push_back(SPIRVOperand(kOperandType_Intermediate, uType)); 175 | } 176 | } 177 | //--------------------------------------------------------------------------------------------------- 178 | -------------------------------------------------------------------------------- /SPIRVGen/SPIRVOperation.h: -------------------------------------------------------------------------------- 1 | //Copyright(c) 2018 2 | //Authors: Fabian Wahlster 3 | //Website: https://twitter.com/singul4rity 4 | //Contact: f.wahlster@tum.de 5 | //License: MIT with attribution (see LICENSE.txt) 6 | 7 | #ifndef SPEAR_SPIRVOPERATION_H 8 | #define SPEAR_SPIRVOPERATION_H 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include "StandardDefines.h" 16 | 17 | namespace Spear 18 | { 19 | enum EOperandType : uint32_t 20 | { 21 | kOperandType_Intermediate, // result of a instruction 22 | kOperandType_Literal, 23 | kOperandType_Unknown, // unmapped 24 | }; 25 | 26 | struct SPIRVOperand 27 | { 28 | SPIRVOperand(const EOperandType _kType = kOperandType_Unknown, const uint32_t _uId = HUNDEFINED32) noexcept : 29 | kType(_kType), uId(_uId) {}; 30 | 31 | SPIRVOperand(const SPIRVOperand& _Other) noexcept : kType(_Other.kType), uId(_Other.uId) {} 32 | SPIRVOperand(SPIRVOperand&& _Other) noexcept : kType(std::move(_Other.kType)), uId(std::move(_Other.uId)) {} 33 | 34 | SPIRVOperand& operator=(const SPIRVOperand& _Other) noexcept 35 | { 36 | kType = _Other.kType; 37 | uId = _Other.uId; 38 | return *this; 39 | } 40 | 41 | SPIRVOperand& operator=(SPIRVOperand&& _Other) noexcept 42 | { 43 | kType = std::move(_Other.kType); 44 | uId = std::move(_Other.uId); 45 | return *this; 46 | } 47 | 48 | static SPIRVOperand Intermediate(const uint32_t _uId) noexcept {return SPIRVOperand(kOperandType_Intermediate, _uId); } 49 | static SPIRVOperand Literal(const uint32_t _uLiteral1) noexcept { return SPIRVOperand(kOperandType_Literal, _uLiteral1); } 50 | 51 | EOperandType kType; 52 | uint32_t uId; 53 | }; 54 | 55 | inline bool operator==(const SPIRVOperand& l, const SPIRVOperand& r) noexcept 56 | { 57 | return l.kType == r.kType && l.uId == r.uId; 58 | } 59 | 60 | inline bool operator!=(const SPIRVOperand& l, const SPIRVOperand& r) noexcept 61 | { 62 | return l.kType != r.kType || l.uId != r.uId; 63 | } 64 | 65 | 66 | // The SPIRV operation is the immediate logical counter part to the SPIRV instruction 67 | // and is used in a SPIRV program when resolving and assembling the instruction stream 68 | class SPIRVOperation 69 | { 70 | friend class SPIRVAssembler; 71 | public: 72 | SPIRVOperation(const spv::Op _kOp, const uint32_t _uResultTypeId, const SPIRVOperand& _Operand); 73 | SPIRVOperation(const spv::Op _kOp, const SPIRVOperand& _Operand); 74 | 75 | template 76 | SPIRVOperation(const spv::Op _kOp, const uint32_t _uResultTypeId, Operands&&... _Operands); 77 | 78 | SPIRVOperation(const spv::Op _kOp, const uint32_t _uResultTypeId, const std::vector& _Operands = {}); 79 | SPIRVOperation(const spv::Op _kOp, const uint32_t _uResultTypeId, std::vector&& _Operands); 80 | 81 | SPIRVOperation(const spv::Op _kOp = spv::OpNop, const std::vector& _Operands = {}) noexcept; 82 | 83 | SPIRVOperation(const spv::Op _kOp, const std::vector& _Literals); 84 | 85 | SPIRVOperation(const SPIRVOperation& _Other); 86 | SPIRVOperation(SPIRVOperation&& _Other); 87 | 88 | ~SPIRVOperation(); 89 | 90 | SPIRVOperation& operator=(const SPIRVOperation& _Other); 91 | SPIRVOperation& operator=(SPIRVOperation&& _Other); 92 | 93 | std::string GetString() const; 94 | 95 | void AddOperand(const SPIRVOperand& _Operand); 96 | void AddIntermediate(const uint32_t _uId); 97 | void AddLiteral(const uint32_t _uLiteral1); 98 | 99 | void AddLiterals(const std::vector& _Literals); 100 | void AddTypes(const std::vector& _Types); 101 | 102 | const spv::Op& GetOpCode() const noexcept; 103 | bool GetUsed() const noexcept; 104 | bool GetTranslated() const noexcept; 105 | 106 | const uint32_t& GetResultType() const noexcept; 107 | const std::vector& GetOperands() const noexcept; 108 | std::vector& GetOperands() noexcept; 109 | 110 | private: 111 | spv::Op m_kOpCode = spv::OpNop; 112 | uint32_t m_uInstrId = HUNDEFINED32; 113 | uint32_t m_uResultId = HUNDEFINED32; 114 | std::vector m_Operands; 115 | uint32_t m_uResultTypeId = HUNDEFINED32; 116 | bool m_bUsed = true; 117 | bool m_bTranslated = false; 118 | }; 119 | 120 | template 121 | inline SPIRVOperation::SPIRVOperation(const spv::Op _kOp, const uint32_t _uResultTypeId, Operands&& ..._Operands) : 122 | m_kOpCode(_kOp), m_uResultTypeId(_uResultTypeId), m_Operands({ std::forward(_Operands)... }) 123 | { 124 | } 125 | 126 | inline const spv::Op& SPIRVOperation::GetOpCode() const noexcept 127 | { 128 | return m_kOpCode; 129 | } 130 | 131 | inline bool SPIRVOperation::GetUsed() const noexcept 132 | { 133 | return m_bUsed; 134 | } 135 | 136 | inline bool SPIRVOperation::GetTranslated() const noexcept 137 | { 138 | return m_bTranslated; 139 | } 140 | 141 | inline const std::vector& SPIRVOperation::GetOperands() const noexcept 142 | { 143 | return m_Operands; 144 | } 145 | 146 | inline std::vector& SPIRVOperation::GetOperands() noexcept 147 | { 148 | return m_Operands; 149 | } 150 | 151 | inline const uint32_t& SPIRVOperation::GetResultType() const noexcept 152 | { 153 | return m_uResultTypeId; 154 | } 155 | } // !Spear 156 | 157 | #endif // !SPEAR_SPIRVOPERATION_H 158 | -------------------------------------------------------------------------------- /SPIRVGen/SPIRVProgram.h: -------------------------------------------------------------------------------- 1 | //Copyright(c) 2018 2 | //Authors: Fabian Wahlster 3 | //Website: https://twitter.com/singul4rity 4 | //Contact: f.wahlster@tum.de 5 | //License: MIT with attribution (see LICENSE.txt) 6 | 7 | #ifndef SPEAR_SPIRVPROGRAM_H 8 | #define SPEAR_SPIRVPROGRAM_H 9 | 10 | #include "SPIRVQuaternion.h" 11 | #include "SPIRVComplex.h" 12 | #include "SPIRVBranchOperations.h" 13 | 14 | namespace Spear 15 | { 16 | template 17 | class SPIRVProgram 18 | { 19 | friend class SPIRVAssembler; 20 | public: 21 | static constexpr bool bAssembleProg = Assemble; 22 | #pragma region type_defs 23 | 24 | // extract underlying variable type 25 | //template 26 | //using underlying_var_t = cond_t, var_value_t, T>; 27 | 28 | template 29 | using var = var_t; 30 | 31 | template 32 | using var_in = var_in_t; 33 | 34 | template 35 | using var_out = var_out_t; 36 | 37 | template 38 | using var_uniform = var_uniform_t; 39 | 40 | template 41 | using var_uniform_constant = var_uniform_constant_t; 42 | 43 | template 44 | using CBuffer = var_uniform_t; 45 | 46 | template 47 | using Array = var_uniform_t, Assemble, Binding, Set>; 48 | 49 | template 50 | using ArrayElement = var; 51 | 52 | template 53 | using VertexInput = var_in_t; 54 | 55 | template 56 | using InstanceInput = var_in_t; 57 | 58 | const var_per_vertex kPerVertex; 59 | 60 | const var_builtin_t kVertexIndex; 61 | const var_builtin_t kInstanceIndex; 62 | const var_builtin_t kDrawIndex; 63 | 64 | const var_builtin_t kBaseVertex; 65 | const var_builtin_t kBaseInstance; 66 | 67 | const var_builtin_t kFragCoord; 68 | const var_builtin_t kFragDepth; 69 | 70 | using s32 = var; 71 | using s64 = var; 72 | using int2 = var; 73 | using int3 = var; 74 | using int4 = var; 75 | 76 | using u32 = var; 77 | using u64 = var; 78 | using uint2 = var; 79 | using uint3 = var; 80 | using uint4 = var; 81 | 82 | using f32 = var; 83 | using f64 = var; 84 | using float2 = var; 85 | using float3 = var; 86 | using float4 = var; 87 | 88 | using quaternion = SPIRVQuaternion; 89 | using complex = SPIRVComplex; 90 | using boolean = var; 91 | 92 | using float2x2 = var; 93 | using float3x3 = var; 94 | using float3x4 = var; 95 | using float4x3 = var; 96 | using float4x4 = var; 97 | using matrix = var; 98 | 99 | template 100 | using SpecConst = var_spec_const_t; 101 | 102 | using SamplerState = var_uniform_constant; 103 | // TODO: SamplerComparisonState 104 | 105 | // float4 component texture types 106 | using Texture1D = var_uniform_constant>; 107 | using Texture2D = var_uniform_constant>; 108 | using Texture3D = var_uniform_constant>; 109 | using TextureCube = var_uniform_constant>; 110 | 111 | // generic texture types 112 | template 113 | using Texture1DEx = var_uniform_constant, Binding, Set, Location>; 114 | 115 | template 116 | using Texture2DEx = var_uniform_constant, Binding, Set, Location>; 117 | 118 | template 119 | using Texture3DEx = var_uniform_constant, Binding, Set, Location>; 120 | 121 | template 122 | using TextureCubeEx = var_uniform_constant, Binding, Set, Location>; 123 | 124 | template 125 | using RenderTargetEx = var_out_t; 126 | 127 | using RenderTarget = var_out_t; 128 | 129 | template 130 | using SubPassColorEx = var_subpass_t; 131 | 132 | template 133 | using SubPassDepthEx = var_subpass_t; 134 | 135 | using SubPassColor = var_subpass_t; 136 | using SubPassDepth = var_subpass_t; 137 | 138 | template 139 | using PushConstant = var_push_const_t; 140 | 141 | // TODO: array types 142 | 143 | #pragma endregion 144 | SPIRVProgram( 145 | const spv::ExecutionModel _kExecutionModel = spv::ExecutionModelFragment, 146 | const spv::ExecutionMode _kMode = spv::ExecutionModeOriginLowerLeft, 147 | const std::string& _sEntryPoint = "main", 148 | const std::vector& _Extensions = { ExtGLSL450 }, 149 | const std::vector& _Capabilities = {spv::CapabilityShader}); 150 | 151 | virtual ~SPIRVProgram(); 152 | 153 | template 154 | void Execute(Ts&& ..._args); 155 | 156 | inline const spv::ExecutionModel GetExecutionModel() const { return m_kExecutionModel; } 157 | inline const spv::ExecutionMode GetExecutionMode() const { return m_kExecutionMode; } 158 | inline const std::string& GetEntryPoint() const { return m_sEntryPoint; } 159 | 160 | inline const std::vector& GetExtensions() const { return m_Extensions; } 161 | // should only be called in the constructor of the derived program 162 | inline void AddExtension(const std::string& _sExtension) { m_Extensions.push_back(_sExtension); } 163 | 164 | inline const std::vector& GetCapabilities() const { return m_Capabilities; } 165 | // should only be called in the constructor of the derived program 166 | inline void AddCapability(const spv::Capability _kCapability) { m_Capabilities.push_back(_kCapability); } 167 | 168 | protected: 169 | const spv::ExecutionModel m_kExecutionModel; 170 | const spv::ExecutionMode m_kExecutionMode; 171 | const std::string m_sEntryPoint; 172 | std::vector m_Extensions; 173 | std::vector m_Capabilities; 174 | }; 175 | 176 | //--------------------------------------------------------------------------------------------------- 177 | // Predefined stage programs 178 | template 179 | class VertexProgram : public SPIRVProgram 180 | { 181 | public: 182 | VertexProgram( 183 | const std::string& _sEntryPoint = "vertex_main", 184 | const std::vector& _Extensions = { ExtGLSL450 }, 185 | const std::vector& _Capabilities = { spv::CapabilityShader }) 186 | : SPIRVProgram(spv::ExecutionModelVertex, spv::ExecutionModeMax, _sEntryPoint, _Extensions, _Capabilities) {} 187 | virtual ~VertexProgram() {} 188 | }; 189 | 190 | template 191 | class FragmentProgram : public SPIRVProgram 192 | { 193 | public: 194 | FragmentProgram( 195 | const std::string& _sEntryPoint = "fragment_main", 196 | const spv::ExecutionMode _kMode = spv::ExecutionModeOriginLowerLeft, 197 | const std::vector& _Extensions = { ExtGLSL450 }, 198 | const std::vector& _Capabilities = { spv::CapabilityShader, spv::CapabilityInputAttachment }) 199 | : SPIRVProgram(spv::ExecutionModelFragment, _kMode, _sEntryPoint, _Extensions, _Capabilities) {} 200 | virtual ~FragmentProgram() {} 201 | }; 202 | 203 | #pragma endregion 204 | 205 | //--------------------------------------------------------------------------------------------------- 206 | template 207 | SPIRVProgram::SPIRVProgram( 208 | const spv::ExecutionModel _kExecutionModel, 209 | const spv::ExecutionMode _kExecutionMode, 210 | const std::string& _sEntryPoint, 211 | const std::vector& _Extensions, 212 | const std::vector& _Capabilities) : 213 | m_kExecutionModel(_kExecutionModel), 214 | m_kExecutionMode(_kExecutionMode), 215 | m_sEntryPoint(_sEntryPoint), 216 | m_Extensions(_Extensions), 217 | m_Capabilities(_Capabilities) 218 | { 219 | } 220 | 221 | //--------------------------------------------------------------------------------------------------- 222 | template 223 | SPIRVProgram::~SPIRVProgram() 224 | { 225 | } 226 | //--------------------------------------------------------------------------------------------------- 227 | 228 | template 229 | template 230 | inline void SPIRVProgram::Execute(Ts&& ..._args) 231 | { 232 | ((TProg*)this)->operator()(std::forward(_args)...); 233 | } 234 | //--------------------------------------------------------------------------------------------------- 235 | }; // !Spear 236 | 237 | #endif // !SPEAR_SPIRVPROGRAM_H 238 | -------------------------------------------------------------------------------- /SPIRVGen/SPIRVQuaternion.h: -------------------------------------------------------------------------------- 1 | //Copyright(c) 2018 2 | //Authors: Fabian Wahlster 3 | //Website: https://twitter.com/singul4rity 4 | //Contact: f.wahlster@tum.de 5 | //License: MIT with attribution (see LICENSE.txt) 6 | 7 | #ifndef SPEAR_SPIRVQUATERNION_H 8 | #define SPEAR_SPIRVQUATERNION_H 9 | 10 | #include "SPIRVOperatorImpl.h" 11 | //http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-17-quaternions/ 12 | 13 | namespace Spear 14 | { 15 | // from Assembly pov it might make more sense to define quaternion_t as {float s, float3_t v} to spare all the extract & insert operations when accessing components 16 | // but the main benefit is that quaternion_t is a float4_t equivalent and can be indexed & transformed in the same way 17 | // the previous version used the glm:quat type but since it does not derive from vec4 to inherit all the implemented operations & traits, float4_t is used here 18 | 19 | template 20 | struct SPIRVQuaternion : public var_t 21 | { 22 | using var_t::var_t; 23 | 24 | SPIRVQuaternion() {} 25 | 26 | // construct from rotation axis & radian angle 27 | template 28 | SPIRVQuaternion(const var_t& _vAxis, const var_t& _fAngleRad); 29 | 30 | SPIRVQuaternion(const float3_t& _vAxis, const float& _fAngleRad); 31 | 32 | SPIRVQuaternion(const float4_t& _vQuat); 33 | 34 | template 35 | const SPIRVQuaternion& operator*=(const SPIRVQuaternion& _Other) const; 36 | 37 | SPIRVQuaternion Conjugate() const; 38 | var_t Norm() const; 39 | SPIRVQuaternion Inverse() const; 40 | 41 | var_t Rotate(const var_t& _Point) const; 42 | 43 | // assumes quaternion has unit length => q^-1 = conjugate(q) 44 | var_t RotateUnit(const var_t& _Point) const; 45 | 46 | var_t InverseRotate(const var_t& _Point) const; 47 | var_t InverseRotateUnit(const var_t& _Point) const; 48 | 49 | // helper 50 | static inline float4_t angleAxis(const float3_t& _vAxis, const float& _fAngleRad) 51 | { 52 | return { _vAxis * std::sinf(_fAngleRad * 0.5f), std::cosf(_fAngleRad * 0.5f) }; 53 | } 54 | }; 55 | 56 | //--------------------------------------------------------------------------------------------------- 57 | template 58 | template 59 | inline SPIRVQuaternion::SPIRVQuaternion(const var_t& _vAxis, const var_t& _fAngleRad) 60 | { 61 | const auto a = _fAngleRad * 0.5f; 62 | xyz = _vAxis * Sin(a); 63 | w = Cos(a); 64 | } 65 | 66 | template 67 | inline SPIRVQuaternion::SPIRVQuaternion(const float3_t& _vAxis, const float& _fAngleRad) : VarType(angleAxis(_vAxis, _fAngleRad)){ } 68 | 69 | template 70 | inline SPIRVQuaternion::SPIRVQuaternion(const float4_t& _vQuat) : VarType(_vQuat){} 71 | 72 | //--------------------------------------------------------------------------------------------------- 73 | // Helper function 74 | 75 | template 76 | inline void QMul(const SPIRVQuaternion& q1, const SPIRVQuaternion& q2, const SPIRVQuaternion& qout) 77 | { 78 | //https://gist.github.com/mattatz/40a91588d5fb38240403f198a938a593 79 | //var.xyz = q2.xyz * q1.w + q1.xyz * q2.w + cross(q1.xyz, q2.xyz); 80 | //var.w = q1.w * q2.w - dot(q1.xyz, q2.xyz); 81 | 82 | const auto q1axis = q1.xyz; const auto q1angle = q1.w; 83 | const auto q2axis = q2.xyz; const auto q2angle = q2.w; 84 | qout.xyz = q2axis * q1angle + q1axis * q2angle + Cross(q1axis, q2axis); 85 | qout.w = q1angle * q2angle - Dot(q1axis, q2axis); 86 | } 87 | //--------------------------------------------------------------------------------------------------- 88 | 89 | template 90 | inline SPIRVQuaternion operator*(const SPIRVQuaternion& l, const SPIRVQuaternion& r) 91 | { 92 | auto var = SPIRVQuaternion(); 93 | QMul(l, r, var); 94 | return var; 95 | } 96 | 97 | //--------------------------------------------------------------------------------------------------- 98 | 99 | template 100 | template 101 | inline const SPIRVQuaternion& SPIRVQuaternion::operator*=(const SPIRVQuaternion& _Other) const 102 | { 103 | QMul(*this, _Other, *this); 104 | return *this; 105 | } 106 | 107 | //--------------------------------------------------------------------------------------------------- 108 | 109 | 110 | template 111 | inline SPIRVQuaternion SPIRVQuaternion::Conjugate() const 112 | { 113 | return SPIRVQuaternion(-xyz, w); // todo: replace with construct_var 114 | } 115 | 116 | template 117 | inline var_t SPIRVQuaternion::Norm() const 118 | { 119 | return Sqrt(Dot(*this, *this)); 120 | } 121 | 122 | template 123 | inline SPIRVQuaternion SPIRVQuaternion::Inverse() const 124 | { 125 | return Conjugate() / Dot(*this, *this); 126 | } 127 | 128 | template 129 | inline var_t SPIRVQuaternion::Rotate(const var_t& _Point) const 130 | { 131 | return (*this * SPIRVQuaternion(_Point, 0.f) * Inverse()).xyz; 132 | } 133 | 134 | template 135 | inline var_t SPIRVQuaternion::RotateUnit(const var_t& _Point) const 136 | { 137 | return (*this * SPIRVQuaternion(_Point, 0.f) * Conjugate()).xyz; 138 | } 139 | 140 | template 141 | inline var_t SPIRVQuaternion::InverseRotate(const var_t& _Point) const 142 | { 143 | return (Inverse() * SPIRVQuaternion(_Point, 0.f) * (*this)).xyz; 144 | } 145 | 146 | template 147 | inline var_t SPIRVQuaternion::InverseRotateUnit(const var_t& _Point) const 148 | { 149 | return (Conjugate() * SPIRVQuaternion(_Point, 0.f) * (*this)).xyz; 150 | } 151 | 152 | } //Spear 153 | 154 | #endif // !SPEAR_SPIRVQUATERNION_H 155 | -------------------------------------------------------------------------------- /SPIRVGen/SPIRVType.cpp: -------------------------------------------------------------------------------- 1 | //Copyright(c) 2018 2 | //Authors: Fabian Wahlster 3 | //Website: https://twitter.com/singul4rity 4 | //Contact: f.wahlster@tum.de 5 | //License: MIT with attribution (see LICENSE.txt) 6 | 7 | #include "SPIRVType.h" 8 | #include "Logger.h" 9 | #include "HashUtils.h" 10 | 11 | using namespace Spear; 12 | 13 | //--------------------------------------------------------------------------------------------------- 14 | 15 | SPIRVType::SPIRVType(const spv::Op _kOp, uint32_t _uDimension, const bool _bSign) : 16 | m_kBaseType(_kOp), m_uDimension(_uDimension), m_bSign(_bSign) 17 | { 18 | HASSERT(_kOp >= spv::OpTypeVoid && _kOp <= spv::OpTypeForwardPointer, "Invalid Type"); 19 | } 20 | //--------------------------------------------------------------------------------------------------- 21 | 22 | SPIRVType::SPIRVType(const spv::Op _kOp, const SPIRVType& _SubType, const uint32_t _uDimension, const bool _bSign) : 23 | m_kBaseType(_kOp), m_uDimension(_uDimension), m_bSign(_bSign), m_SubTypes({_SubType}) 24 | { 25 | HASSERT(_kOp >= spv::OpTypeVoid && _kOp <= spv::OpTypeForwardPointer, "Invalid Type"); 26 | } 27 | //--------------------------------------------------------------------------------------------------- 28 | 29 | SPIRVType::SPIRVType(const spv::Op _kOp, const std::vector& _SubTypes, const uint32_t _uDimension, const bool _bSign) : 30 | m_kBaseType(_kOp), m_uDimension(_uDimension), m_bSign(_bSign), m_SubTypes(_SubTypes) 31 | { 32 | HASSERT(_kOp >= spv::OpTypeVoid && _kOp <= spv::OpTypeForwardPointer, "Invalid Type"); 33 | } 34 | //--------------------------------------------------------------------------------------------------- 35 | 36 | SPIRVType::SPIRVType(const SPIRVType& _SampledType, const spv::Dim _uDimension, const bool _bArray, const ETexDepthType _kDepthType, const bool _bMultiSampled, const ETexSamplerAccess _kSamplerAccess) : 37 | m_SubTypes(1u, _SampledType), m_kBaseType(spv::OpTypeImage), m_uDimension(_uDimension), m_bArray(_bArray), m_kTexDepthType(_kDepthType), m_bMultiSampled(_bMultiSampled), m_kSamplerAccess(_kSamplerAccess) 38 | { 39 | } 40 | //--------------------------------------------------------------------------------------------------- 41 | 42 | SPIRVType::~SPIRVType() 43 | { 44 | } 45 | //--------------------------------------------------------------------------------------------------- 46 | 47 | SPIRVType& SPIRVType::Append(const SPIRVType& _SubType) 48 | { 49 | if (m_SubTypes.empty()) 50 | { 51 | m_SubTypes.push_back(_SubType); 52 | } 53 | else 54 | { 55 | m_SubTypes.back().Append(_SubType); 56 | } 57 | 58 | return *this; 59 | } 60 | //--------------------------------------------------------------------------------------------------- 61 | 62 | SPIRVType& SPIRVType::Member(const SPIRVType& _SubType) 63 | { 64 | m_SubTypes.push_back(_SubType); 65 | return *this; 66 | } 67 | //--------------------------------------------------------------------------------------------------- 68 | 69 | size_t SPIRVType::GetHash() const 70 | { 71 | size_t uHash = hlx::Hash(m_kBaseType, m_uDimension, m_bSign, m_bArray, m_bMultiSampled, m_kTexDepthType, m_kSamplerAccess); 72 | 73 | for (const SPIRVType& subtype : m_SubTypes) 74 | { 75 | uHash = hlx::CombineHashes(uHash, subtype.GetHash()); 76 | } 77 | 78 | return uHash; 79 | } 80 | //--------------------------------------------------------------------------------------------------- 81 | uint32_t SPIRVType::GetSize() const 82 | { 83 | uint32_t uSize = 0u; 84 | 85 | switch (m_kBaseType) 86 | { 87 | case spv::OpTypeBool: // not sure about the bool, in uniformes its implicitly converted to int 88 | case spv::OpTypeInt: 89 | case spv::OpTypeFloat: 90 | uSize += 4u; 91 | break; 92 | case spv::OpTypeVector: 93 | case spv::OpTypeMatrix: 94 | case spv::OpTypeArray: 95 | HASSERT(m_SubTypes.size() == 1u, "Invalid number of sub types"); 96 | uSize += m_SubTypes.front().GetSize() * m_uDimension; 97 | break; 98 | case spv::OpTypeStruct: 99 | for (const SPIRVType& SubType : m_SubTypes) 100 | { 101 | uSize += SubType.GetSize(); 102 | } 103 | break; 104 | default: 105 | break; 106 | } 107 | 108 | return uSize; 109 | } 110 | //--------------------------------------------------------------------------------------------------- 111 | -------------------------------------------------------------------------------- /SPIRVGen/SPIRVVariable.cpp: -------------------------------------------------------------------------------- 1 | //Copyright(c) 2018 2 | //Authors: Fabian Wahlster 3 | //Website: https://twitter.com/singul4rity 4 | //Contact: f.wahlster@tum.de 5 | //License: MIT with attribution (see LICENSE.txt) 6 | 7 | #include "SPIRVVariable.h" 8 | 9 | using namespace Spear; 10 | 11 | void var_decoration::Decorate(const SPIRVDecoration& _Decoration) 12 | { 13 | Decorations.push_back(_Decoration); 14 | } 15 | //--------------------------------------------------------------------------------------------------- 16 | void var_decoration::MaterializeDecorations() const 17 | { 18 | // TODO: materialize decorations of base variables too! 19 | 20 | if (uVarId == HUNDEFINED32) 21 | return; 22 | 23 | GlobalAssembler.AddVariableInfo(*this); 24 | 25 | // instantiate variable decorations 26 | for (const SPIRVDecoration& Decoration : Decorations) 27 | { 28 | GlobalAssembler.AddOperation(Decoration.MakeOperation(uMemberIndex == HUNDEFINED ? uVarId : uBaseTypeId, uMemberIndex)); 29 | } 30 | Decorations.clear(); 31 | 32 | // instantiate variable name 33 | 34 | if (sName.empty() == false && bMaterializedName == false) 35 | { 36 | if (uMemberIndex == HUNDEFINED32) 37 | { 38 | SPIRVOperation OpName(spv::OpName); 39 | OpName.AddLiteral(uVarId); 40 | OpName.AddLiterals(MakeLiteralString(sName)); 41 | GlobalAssembler.AddOperation(std::move(OpName)); 42 | } 43 | else 44 | { 45 | SPIRVOperation OpName(spv::OpMemberName); 46 | OpName.AddIntermediate(uBaseTypeId); 47 | OpName.AddLiteral(uMemberIndex); 48 | OpName.AddLiterals(MakeLiteralString(sName)); 49 | GlobalAssembler.AddOperation(std::move(OpName)); 50 | } 51 | 52 | bMaterializedName = true; 53 | } 54 | } 55 | //--------------------------------------------------------------------------------------------------- 56 | void var_decoration::Store() const 57 | { 58 | // store the lastest intermediate result 59 | #ifdef HDIRECT_MEMACCESS 60 | if (uVarId != HUNDEFINED32 && 61 | uResultId != HUNDEFINED32 && 62 | uResultId != uLastStoreId) 63 | { 64 | uLastStoreId = uResultId; 65 | #else 66 | if (uVarId != HUNDEFINED32 && uResultId != HUNDEFINED32 && 67 | (kStorageClass != spv::StorageClassUniformConstant && 68 | kStorageClass != spv::StorageClassInput && 69 | kStorageClass != spv::StorageClassPushConstant)) 70 | { 71 | const uint32_t uScopeLevel = GlobalAssembler.GetScopeLevel(); 72 | const uint32_t uScopeID = GlobalAssembler.GetScopeID(); 73 | 74 | // check if we can skip the store 75 | for (auto it = MemAccess.rbegin(); it != MemAccess.rend(); ++it) 76 | { 77 | const LSInfo& LS(*it); 78 | if ((LS.uResultId == uResultId && LS.kType == kLSType_Store) && // this result has been stored 79 | (LS.uScopeId == uScopeID || LS.uScopeLevel <= uScopeLevel)) // in a preceding scope 80 | { 81 | return; 82 | } 83 | } 84 | 85 | // save store info 86 | LSInfo& LD = MemAccess.emplace_back(); 87 | LD.kType = kLSType_Store; 88 | LD.uScopeId = uScopeID; 89 | LD.uScopeLevel = uScopeLevel; 90 | LD.uResultId = uResultId; 91 | #endif 92 | 93 | // create store 94 | GlobalAssembler.AddOperation(SPIRVOperation(spv::OpStore, 95 | { 96 | SPIRVOperand(kOperandType_Intermediate, uVarId), // destination 97 | SPIRVOperand(kOperandType_Intermediate, uResultId) // source 98 | })); 99 | 100 | MaterializeDecorations(); 101 | } 102 | } 103 | //--------------------------------------------------------------------------------------------------- 104 | 105 | void var_decoration::CreateAccessChain() const 106 | { 107 | // create access chain for structures and composite types 108 | if (uVarId == HUNDEFINED32 && uBaseId != HUNDEFINED32 && AccessChain.empty() == false) 109 | { 110 | const uint32_t uPtrTypeId = GlobalAssembler.AddType(SPIRVType::Pointer(Type, kStorageClass)); 111 | SPIRVOperation OpAccessChain(spv::OpAccessChain, uPtrTypeId, SPIRVOperand(kOperandType_Intermediate, uBaseId)); 112 | 113 | for (const uint32_t& uMemberIdx : AccessChain) 114 | { 115 | OpAccessChain.AddIntermediate(GlobalAssembler.AddConstant(SPIRVConstant::Make(uMemberIdx))); 116 | } 117 | 118 | uVarId = GlobalAssembler.AddOperation(std::move(OpAccessChain)); 119 | } 120 | } 121 | //--------------------------------------------------------------------------------------------------- 122 | 123 | uint32_t var_decoration::Load() const 124 | { 125 | HASSERT(uTypeId != HUNDEFINED32, "Invalid TypeId"); 126 | 127 | CreateAccessChain(); 128 | 129 | // instantiate variable decorations 130 | MaterializeDecorations(); 131 | 132 | #ifdef HDIRECT_MEMACCESS 133 | if (uResultId != HUNDEFINED32) // its an intermediate 134 | return uResultId; 135 | #else 136 | if (uResultId != HUNDEFINED32 && uVarId == HUNDEFINED32) // its an intermediate 137 | return uResultId; 138 | 139 | const uint32_t uScopeLevel = GlobalAssembler.GetScopeLevel(); 140 | const uint32_t uScopeID = GlobalAssembler.GetScopeID(); 141 | 142 | // search for last memory access in parent/same scope 143 | for (auto it = MemAccess.rbegin(); it != MemAccess.rend(); ++it) 144 | { 145 | const LSInfo& LS(*it); 146 | if (LS.uScopeId == uScopeID || LS.uScopeLevel <= uScopeLevel) 147 | { 148 | return LS.uResultId; 149 | } 150 | } 151 | #endif 152 | 153 | HASSERT(uVarId != HUNDEFINED32, "Invalid variable id"); 154 | 155 | // OpLoad: 156 | // Result Type is the type of the loaded object. 157 | // Pointer is the pointer to load through. Its type must be an OpTypePointer whose Type operand is the same as ResultType. 158 | // Memory Access must be a Memory Access literal. If not present, it is the same as specifying None. 159 | // bsp: None, Volatile, Aligned, Nontemporal 160 | 161 | uResultId = GlobalAssembler.EmplaceOperation(spv::OpLoad, uTypeId, SPIRVOperand(kOperandType_Intermediate, uVarId)); 162 | 163 | #ifdef HDIRECT_MEMACCESS 164 | uLastStoreId = uResultId; 165 | #else 166 | LSInfo& LD = MemAccess.emplace_back(); 167 | LD.kType = kLSType_Load; 168 | LD.uScopeId = uScopeID; 169 | LD.uScopeLevel = uScopeLevel; 170 | LD.uResultId = uResultId; 171 | #endif 172 | 173 | return uResultId; 174 | } 175 | //--------------------------------------------------------------------------------------------------- 176 | var_decoration::var_decoration(const var_decoration& _Other) : 177 | uVarId(_Other.uVarId), 178 | uResultId(_Other.uResultId), 179 | uBaseId(_Other.uBaseId), 180 | kStorageClass(_Other.kStorageClass), 181 | uTypeId(_Other.uTypeId), 182 | AccessChain(_Other.AccessChain), 183 | Type(_Other.Type), 184 | #ifndef HDIRECT_MEMACCESS 185 | MemAccess(_Other.MemAccess), 186 | #endif 187 | Decorations(_Other.Decorations) 188 | { 189 | // TODO: copy descriptorset and others? 190 | } 191 | //--------------------------------------------------------------------------------------------------- 192 | 193 | var_decoration::var_decoration(var_decoration&& _Other) noexcept: 194 | uVarId(_Other.uVarId), 195 | uResultId(_Other.uResultId), 196 | uBaseId(_Other.uBaseId), 197 | kStorageClass(_Other.kStorageClass), 198 | uTypeId(_Other.uTypeId), 199 | AccessChain(std::move(_Other.AccessChain)), 200 | Type(std::move(_Other.Type)), 201 | #ifndef HDIRECT_MEMACCESS 202 | MemAccess(std::move(_Other.MemAccess)), 203 | #endif 204 | Decorations(std::move(_Other.Decorations)) 205 | { 206 | _Other.uVarId = HUNDEFINED32; 207 | _Other.uResultId = HUNDEFINED32; 208 | _Other.uTypeId = HUNDEFINED32; 209 | _Other.uBaseId = HUNDEFINED32; 210 | } 211 | 212 | //--------------------------------------------------------------------------------------------------- 213 | 214 | const var_decoration& var_decoration::operator=(const var_decoration& _Other) const 215 | { 216 | if (this == &_Other) 217 | return *this; 218 | 219 | HASSERT(uTypeId != HUNDEFINED32 && uTypeId == _Other.uTypeId, "Type mismatch!"); 220 | 221 | CreateAccessChain(); // creat var id for structs 222 | _Other.Load();// load source 223 | 224 | if (uVarId != HUNDEFINED32) // this is a mem object (no intermediate) 225 | { 226 | uResultId = _Other.uResultId; // get result 227 | Store(); // store result 228 | } 229 | else // intermediate 230 | { 231 | uResultId = _Other.uResultId; 232 | uBaseId = _Other.uBaseId; 233 | } 234 | 235 | return *this; 236 | } 237 | 238 | //--------------------------------------------------------------------------------------------------- 239 | 240 | var_decoration::~var_decoration() 241 | { 242 | // store the lastest intermediate result 243 | Store(); 244 | } 245 | //--------------------------------------------------------------------------------------------------- 246 | void var_decoration::SetBinding(const uint32_t _uBinding, const uint32_t _uDescriptorSet) 247 | { 248 | HASSERT(uDescriptorSet == HUNDEFINED32 && uBinding == HUNDEFINED32, "Variable already has a binding"); 249 | Decorate(SPIRVDecoration(spv::DecorationDescriptorSet, _uDescriptorSet)); 250 | Decorate(SPIRVDecoration(spv::DecorationBinding, _uBinding)); 251 | 252 | uDescriptorSet = _uDescriptorSet; 253 | uBinding = _uBinding; 254 | } 255 | //--------------------------------------------------------------------------------------------------- 256 | 257 | void var_decoration::SetLocation(const uint32_t _uLocation) 258 | { 259 | HASSERT(uLocation == HUNDEFINED32, "Variable already has a location"); 260 | Decorate(SPIRVDecoration(spv::DecorationLocation, _uLocation)); 261 | 262 | uLocation = _uLocation; 263 | } 264 | //--------------------------------------------------------------------------------------------------- 265 | void var_decoration::SetName(const std::string& _sName) 266 | { 267 | sName = _sName; 268 | } 269 | //--------------------------------------------------------------------------------------------------- 270 | uint32_t var_decoration::GetLastStore() const 271 | { 272 | #ifdef HDIRECT_MEMACCESS 273 | return uLastStoreId; 274 | #else 275 | for (auto it = MemAccess.rbegin(); it != MemAccess.rend(); ++it) 276 | { 277 | const LSInfo& LS(*it); 278 | if (LS.kType == kLSType_Store) 279 | { 280 | return LS.uResultId; 281 | } 282 | } 283 | 284 | return HUNDEFINED32; 285 | #endif 286 | } 287 | -------------------------------------------------------------------------------- /SPIRVGen/SPIRVVariable.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rAzoR8/SPEAR/8e8714542ff54efc95b40dfaf51fb500eb5458eb/SPIRVGen/SPIRVVariable.h -------------------------------------------------------------------------------- /SPIRVGen/SPIRVVariableTypeDefs.h: -------------------------------------------------------------------------------- 1 | //Copyright(c) 2018 2 | //Authors: Fabian Wahlster 3 | //Website: https://twitter.com/singul4rity 4 | //Contact: f.wahlster@tum.de 5 | //License: MIT with attribution (see LICENSE.txt) 6 | 7 | #ifndef SPEAR_SPIRVVARIABLETYPEDEFS_H 8 | #define SPEAR_SPIRVVARIABLETYPEDEFS_H 9 | 10 | #define S32 Spear::var_t 11 | #define S64 Spear::var_t 12 | #define Int2 Spear::var_t 13 | #define Int3 Spear::var_t 14 | #define Int4 Spear::var_t 15 | 16 | #define U32 Spear::var_t 17 | #define U64 Spear::var_t 18 | #define UInt2 Spear::var_t 19 | #define UInt3 Spear::var_t 20 | #define UInt4 Spear::var_t 21 | 22 | #define F32 Spear::var_t 23 | #define F64 Spear::var_t 24 | #define Float2 Spear::var_t 25 | #define Float3 Spear::var_t 26 | #define Float4 Spear::var_t 27 | 28 | #define Quaternion = SPIRVQuaternion; 29 | #define Complex = SPIRVComplex; 30 | #define Boolean Spear::var_t 31 | 32 | #define Float2x2 Spear::var_t 33 | #define Float3x3 Spear::var_t 34 | #define Float3x4 Spear::var_t 35 | #define Float4x3 Spear::var_t 36 | #define Float4x4 Spear::var_t 37 | #define Matrix Spear::var_t 38 | 39 | //#define SamplerState Spear::var_t 40 | // 41 | //#define Texture1D Spear::var_t, spv::StorageClassUniformConstant> 42 | //#define Texture2D Spear::var_t, spv::StorageClassUniformConstant> 43 | //#define Texture3D Spear::var_t, spv::StorageClassUniformConstant> 44 | //#define TextureCube Spear::var_t, spv::StorageClassUniformConstant> 45 | 46 | #endif // !SPEAR_SPIRVVARIABLETYPEDEFS_H 47 | -------------------------------------------------------------------------------- /SPIRVGenTest/ExampleProg.h: -------------------------------------------------------------------------------- 1 | //Copyright(c) 2018 2 | //Authors: Fabian Wahlster 3 | //Website: https://twitter.com/singul4rity 4 | //Contact: f.wahlster@tum.de 5 | //License: MIT with attribution (see LICENSE.txt) 6 | 7 | #ifndef SPEAR_EXAMPLEPROG_H 8 | #define SPEAR_EXAMPLEPROG_H 9 | 10 | #include "SPIRVProgram.h" 11 | #include "SPIRVAssembler.h" 12 | #include "SPIRVExtensionAMD.h" 13 | 14 | #include "..\SPIRVShaderFactory\MicrofacetReflection.h" 15 | 16 | namespace Spear 17 | { 18 | template 19 | class ExampleProg : public SPIRVProgram 20 | { 21 | public: 22 | ExampleProg() : SPIRVProgram() 23 | { 24 | AddExtension(ExtAMD::ExtGCNShader); 25 | AddCapability(spv::CapabilityInt64); 26 | AddCapability(spv::CapabilityImageQuery); 27 | GlobalAssembler.RemoveUnusedOperations(false); // for debugging 28 | }; 29 | 30 | ~ExampleProg() {}; 31 | 32 | struct B 33 | { 34 | SPVStruct 35 | float2 UVCoord = "UVCoords"; 36 | float2 Offset; 37 | 38 | u32 SampleCount; 39 | }; 40 | 41 | struct PushBlock 42 | { 43 | SPVStruct 44 | float4 stuff; 45 | }; 46 | 47 | CBuffer BufferBlock; 48 | RenderTarget OutputColor; 49 | SamplerState Sampler; 50 | Texture2DEx InputImg; 51 | //SubPassColor SubPass; 52 | PushConstant Push; 53 | Array TestArray; 54 | 55 | inline void operator()() 56 | { 57 | f32 sum = 0.f; 58 | f32 sum2 = 1.f; 59 | 60 | float3 l, v, h, n; 61 | 62 | auto ddd = Saturate(l); 63 | 64 | l += ddd; 65 | 66 | auto bl = l != v && l == n; 67 | auto an = Any(bl); 68 | 69 | uint3 u1, u2; 70 | 71 | auto rep = replicate<3>(sum); 72 | 73 | l += rep; 74 | 75 | l = Saturate(l); 76 | 77 | auto u = Select(an, u1, u2); 78 | 79 | auto bit = u1 >= u2; 80 | auto bit2 = sum >= 1.f; 81 | 82 | auto k = Select(an, sum, sum2); 83 | 84 | auto f = FresnelSchlick(l, h, sum); 85 | auto d = BlinnPhongDistribution(n, h, sum); 86 | auto geoi = GeoImplicit(n, l, v); 87 | auto geotc = GeoCookTorrance(n, l, v, h); 88 | u32 size = TestArray.Length(); 89 | //size = SizeOf(TestArray); 90 | 91 | auto dif = Ddx(l); 92 | dif = dif + Ddy(v); 93 | 94 | auto dims = InputImg.Dimensions(size); 95 | //v3.xy = dims; 96 | 97 | auto sampldrf = InputImg.SampleDref(Sampler, float2(0.5f, 0.5f), sum); 98 | auto fetch = InputImg.Fetch(int2(1, 1)); 99 | auto gather = InputImg.Gather(Sampler, float2(0.5f, 0.5f), u32(0u)); 100 | 101 | auto time = ExtAMD::GCNShader::Time(); 102 | 103 | complex z1(3.0f, 4.0f); 104 | complex z2(3.0f, -2.0f); 105 | 106 | z1 *= z2; 107 | 108 | If(sum < 2.f) 109 | { 110 | sum += 2.f; 111 | } 112 | Else 113 | { 114 | sum -= 1.f; 115 | }); 116 | 117 | //u32 uVertexID(1); 118 | auto id1 = (kVertexIndex & 1) << 2; 119 | auto id2 = (kInstanceIndex & 2) << 1; 120 | 121 | For(u32 e = 0u, e < size, ++e) 122 | { 123 | auto elem = TestArray[e]; 124 | sum += Length(elem); 125 | }); 126 | 127 | float3x4 m34; 128 | 129 | float3 v3 = { 1.f, 2.f, 3.f }; 130 | float3 a, b, c; 131 | 132 | matrix m; 133 | 134 | m = Inverse(m); 135 | float4x3 m43 = Transpose(m34); 136 | auto det = Determinant(m); 137 | 138 | c = Atan2(a, b); 139 | b = Pow(c, a); 140 | a = Exp2(c); 141 | c = Log(a); 142 | b = InvSqrt(a + b); 143 | a = Reflect(b, Normalize(c)); 144 | b = Refract(a, c, 0.5f); 145 | 146 | v3 = Fma(a, float3{ 1.f, 2.f, 3.f }, c); 147 | //v3 = Cross(a, b) * Dot(a, c); 148 | quaternion q1 = quaternion(v3, sum); 149 | quaternion q2; 150 | 151 | auto q = q1 * q2; 152 | q *= q2; 153 | q = q + q2; 154 | 155 | v3 = q.Rotate(v3); 156 | v3 = q.RotateUnit(v3); 157 | 158 | auto sp = SpecConst(2.f); 159 | 160 | auto res = m34 * v3 * sp; // instead of using mul 161 | auto baj = Length(res.xyz); 162 | 163 | float2 offset = BufferBlock->Offset; 164 | For(u32 i = 0u, i < BufferBlock->SampleCount, ++i) 165 | { 166 | OutputColor.rgb = InputImg.Sample(Sampler, BufferBlock->UVCoord + offset); 167 | OutputColor.a = Length(OutputColor.rgb); 168 | }); 169 | }; 170 | private: 171 | }; 172 | 173 | }; // !Spear 174 | 175 | #endif // !SPEAR_EXAMPLEPROG_H 176 | -------------------------------------------------------------------------------- /SPIRVGenTest/GenerateSwizzleHeader.h: -------------------------------------------------------------------------------- 1 | //Copyright(c) 2018 2 | //Authors: Fabian Wahlster 3 | //Website: https://twitter.com/singul4rity 4 | //Contact: f.wahlster@tum.de 5 | //License: MIT with attribution (see LICENSE.txt) 6 | 7 | #ifndef SPEAR_GENERATESWIZZLEHEADER_H 8 | #define SPEAR_GENERATESWIZZLEHEADER_H 9 | 10 | #include 11 | #include 12 | 13 | void GenerateSwizzleHeader() 14 | { 15 | const std::string ups[4] = { "X", "Y", "Z", "W" }; 16 | const char lows[2][4] = { { 'x', 'y', 'z', 'w' },{ 'r', 'g', 'b', 'a' } }; 17 | 18 | std::ofstream out("SPIRVVectorComponentAccess.h"); 19 | 20 | if (out.is_open()) 21 | { 22 | out << "//Copyright(c) 2018" << std::endl; 23 | out << "//Authors: Fabian Wahlster" << std::endl; 24 | out << "//Website: https://twitter.com/singul4rity" << std::endl; 25 | out << "//Contact: f.wahlster@tum.de" << std::endl; 26 | out << "//License: MIT with attribution (see LICENSE.txt)" << std::endl; 27 | 28 | out << "#ifndef SPEAR_SPIRVVECTORCOMPONENTACCESS_H" << std::endl; 29 | out << "#define SPEAR_SPIRVVECTORCOMPONENTACCESS_H" << std::endl; 30 | 31 | std::string sTplArgs; 32 | std::string sExtract; 33 | std::string sExtractType; 34 | std::string sInsert; 35 | std::string sInsertConst; 36 | std::string sInsertValue; 37 | std::string sFuncName; 38 | 39 | auto GetSet = [&]() { 40 | // getter 41 | out << sExtractType << " " 42 | << sFuncName << "() const { return " << sExtract << "(); } " << std::endl; 43 | 44 | // setter var 45 | out << "template void " 46 | << sFuncName << "(" + sInsertValue + " _var) const { " + sInsert + "(_var);}" << std::endl; 47 | 48 | // setter const 49 | out << "void " 50 | << sFuncName << "(const " + sInsertConst + "& _var) const { " + sInsert + "(make_const(_var));}" << std::endl; 51 | }; 52 | 53 | for (uint32_t x = 0; x < 4; ++x) 54 | { 55 | sTplArgs = "1, " + std::to_string(x); 56 | sExtract = "ExtractComponent<" + sTplArgs + ">"; 57 | sInsert = "InsertComponent<" + sTplArgs + ">"; 58 | sInsertConst = "vec_type_t, 1>"; 59 | sInsertValue = "const var_t, 1>, Assemble, C1>&"; 60 | sFuncName = ups[x]; 61 | sExtractType = "TExtractType<1>"; 62 | 63 | GetSet(); 64 | 65 | // property 66 | out << "#ifdef SPEAR_ENABLE_PROPERTIES" << std::endl; 67 | for (uint32_t l = 0; l < 2; ++l) 68 | { 69 | out << "__declspec(property(get = " << sFuncName << ", put = " << sFuncName << 70 | ")) " << sExtractType << " " << lows[l][x] << ";" << std::endl; 71 | } 72 | out << "#endif // !SPEAR_ENABLE_PROPERTIES" << std::endl; 73 | 74 | for (uint32_t y = 0; y < 4; ++y) 75 | { 76 | sTplArgs = "2, " + std::to_string(x) + ", " + std::to_string(y); 77 | sExtract = "ExtractComponent<" + sTplArgs + ">"; 78 | sInsert = "InsertComponent<" + sTplArgs + ">"; 79 | sInsertConst = "vec_type_t, 2>"; 80 | sInsertValue = "const var_t, 2>, Assemble, C1>&"; 81 | sFuncName = ups[x] + ups[y]; 82 | sExtractType = "TExtractType<2>"; 83 | 84 | GetSet(); 85 | 86 | // property 87 | out << "#ifdef SPEAR_ENABLE_PROPERTIES" << std::endl; 88 | for (uint32_t l = 0; l < 2; ++l) 89 | { 90 | out << "__declspec(property(get = " << sFuncName << ", put = " << sFuncName << 91 | ")) " << sExtractType << " " << lows[l][x] << lows[l][y] << ";" << std::endl; 92 | } 93 | out << "#endif // !SPEAR_ENABLE_PROPERTIES" << std::endl; 94 | 95 | for (uint32_t z = 0; z < 4; ++z) 96 | { 97 | sTplArgs = "3, " + std::to_string(x) + ", " + std::to_string(y) + ", " + std::to_string(z); 98 | sExtract = "ExtractComponent<" + sTplArgs + ">"; 99 | sInsert = "InsertComponent<" + sTplArgs + ">"; 100 | sInsertConst = "vec_type_t, 3>"; 101 | sInsertValue = "const var_t, 3>, Assemble, C1>&"; 102 | sFuncName = ups[x] + ups[y] + ups[z]; 103 | sExtractType = "TExtractType<3>"; 104 | 105 | GetSet(); 106 | 107 | // property 108 | out << "#ifdef SPEAR_ENABLE_PROPERTIES" << std::endl; 109 | for (uint32_t l = 0; l < 2; ++l) 110 | { 111 | out << "__declspec(property(get = " << sFuncName << ", put = " << sFuncName << 112 | ")) " << sExtractType << " " << lows[l][x] << lows[l][y] << lows[l][z] << ";" << std::endl; 113 | } 114 | out << "#endif // !SPEAR_ENABLE_PROPERTIES" << std::endl; 115 | 116 | for (uint32_t w = 0; w < 4; ++w) 117 | { 118 | sTplArgs = "3, " + std::to_string(x) + ", " + std::to_string(y) + ", " + std::to_string(z) + ", " + std::to_string(w); 119 | sExtract = "ExtractComponent<" + sTplArgs + ">"; 120 | sInsert = "InsertComponent<" + sTplArgs + ">"; 121 | sInsertConst = "vec_type_t, 4>"; 122 | sInsertValue = "const var_t, 4>, Assemble, C1>&"; 123 | sFuncName = ups[x] + ups[y] + ups[z] + ups[w]; 124 | sExtractType = "TExtractType<4>"; 125 | 126 | GetSet(); 127 | 128 | // property 129 | out << "#ifdef SPEAR_ENABLE_PROPERTIES" << std::endl; 130 | for (uint32_t l = 0; l < 2; ++l) 131 | { 132 | out << "__declspec(property(get = " << sFuncName << ", put = " << sFuncName << 133 | ")) " << sExtractType << " " << lows[l][x] << lows[l][y] << lows[l][z] << lows[l][w] << ";" << std::endl; 134 | } 135 | out << "#endif // !SPEAR_ENABLE_PROPERTIES" << std::endl; 136 | } 137 | } 138 | } 139 | } 140 | 141 | out << "#endif // !SPEAR_SPIRVVECTORCOMPONENTACCESS_H" << std::endl; 142 | } 143 | 144 | out.close(); 145 | } 146 | 147 | #endif // !SPEAR_GENERATESWIZZLEHEADER_H 148 | -------------------------------------------------------------------------------- /SPIRVGenTest/main.cpp: -------------------------------------------------------------------------------- 1 | //Copyright(c) 2018 2 | //Authors: Fabian Wahlster 3 | //Website: https://twitter.com/singul4rity 4 | //Contact: f.wahlster@tum.de 5 | //License: MIT with attribution (see LICENSE.txt) 6 | 7 | #define ExprCaptureRule & 8 | 9 | #include "SPIRVModule.h" 10 | //#include "SPIRVInlineAssembler.h" 11 | //#include "GenerateSwizzleHeader.h" 12 | //#include "ExampleProg.h" 13 | //#include "..\SPIRVShaderFactory\CSGExampleShader.h" 14 | #include "DeferredLightingExample.h" 15 | #include "StopWatch.h" 16 | 17 | using namespace Spear; 18 | 19 | uint32_t uPerm = 0u; 20 | 21 | template 22 | uint32_t compile(const TDLPerm& _Perm, const std::string& _sOutputPath = {}, const bool _vValidate = false) 23 | { 24 | 25 | SPIRVModule Shader = GlobalAssembler.AssembleSimple>(true, _Perm); 26 | const uint32_t uWordCount = static_cast(Shader.GetCode().size()); 27 | const uint32_t uInstrCount = Shader.GetNumberOfOperations(); 28 | HLOG("P %u PL %u SL %u [%u] Instr %u Words %u", _Perm.GetBase(), pl, sl, ++uPerm, uInstrCount, uWordCount); 29 | 30 | if (_sOutputPath.empty() == false) 31 | { 32 | Shader.Save(_sOutputPath); 33 | 34 | if (_vValidate) 35 | { 36 | system(("spirv-dis " + _sOutputPath).c_str()); 37 | system(("spirv-val " + _sOutputPath).c_str()); 38 | } 39 | } 40 | 41 | return uWordCount; 42 | } 43 | 44 | inline uint32_t AssembleTest() 45 | { 46 | uint32_t uWordCount = 0u; 47 | 48 | for (uint32_t p = 0; p < 4; ++p) 49 | { 50 | //compile<1u, 1u>(0u); 51 | 52 | uWordCount += compile<1u, 1u>(TDLPerm(p)); 53 | uWordCount += compile<16u, 1u>(TDLPerm(p)); 54 | uWordCount += compile<32u, 1u>(TDLPerm(p)); 55 | uWordCount += compile<48u, 1u>(TDLPerm(p)); 56 | 57 | uWordCount += compile<1u, 16u>(TDLPerm(p)); 58 | uWordCount += compile<1u, 32u>(TDLPerm(p)); 59 | uWordCount += compile<1u, 48u>(TDLPerm(p)); 60 | 61 | uWordCount += compile<16u, 16u>(TDLPerm(p)); 62 | uWordCount += compile<16u, 32u>(TDLPerm(p)); 63 | uWordCount += compile<16u, 48u>(TDLPerm(p)); 64 | 65 | uWordCount += compile<32u, 16u>(TDLPerm(p)); 66 | uWordCount += compile<32u, 32u>(TDLPerm(p)); 67 | uWordCount += compile<32u, 48u>(TDLPerm(p)); 68 | 69 | uWordCount += compile<48u, 16u>(TDLPerm(p)); 70 | uWordCount += compile<48u, 32u>(TDLPerm(p)); 71 | uWordCount += compile<48u, 48u>(TDLPerm(p)); 72 | } 73 | 74 | return uWordCount; 75 | } 76 | 77 | int main(int argc, char* argv[]) 78 | { 79 | //GenerateSwizzleHeader(); 80 | 81 | //CSGExampleShader prog; 82 | //prog.kFragCoord.xy = { 800.f, 450.f }; 83 | //prog(); 84 | 85 | //auto col = prog.OutputColor.Value; 86 | 87 | //return 0; 88 | 89 | //GlobalAssembler.AssembleSimple>().Save("test.spv"); 90 | //system("spirv-dis test.spv"); 91 | //system("spirv-val test.spv"); 92 | //system("pause"); 93 | 94 | //return 0; 95 | 96 | OptimizationSettings Settings{}; 97 | //Settings.kPasses = kOptimizationPassFlag_AllPerformance; 98 | //Settings.kPasses = kOptimizationPassFlag_AllSize; 99 | //Settings.kPasses = kOptimizationPassFlag_All; 100 | 101 | GlobalAssembler.ConfigureOptimization(Settings); 102 | GlobalAssembler.RemoveUnusedOperations(false); // Disable own implementation 103 | 104 | if (false) 105 | { 106 | TDLPerm Perm = {}; 107 | compile<1u, 1u>(Perm, "unopt.spv", true); 108 | 109 | GlobalAssembler.RemoveUnusedOperations(true); 110 | compile<1u, 1u>(Perm, "rem.spv", true); 111 | GlobalAssembler.RemoveUnusedOperations(false); 112 | 113 | Settings.kPasses = kOptimizationPassFlag_AllPerformance; 114 | GlobalAssembler.ConfigureOptimization(Settings); 115 | 116 | compile<1u, 1u>(Perm, "opt.spv", true); 117 | } 118 | else 119 | { 120 | if (false) // word count teste 121 | { 122 | hlx::Logger::Instance()->WriteToStream(&std::wcout); 123 | 124 | GlobalAssembler.ConfigureOptimization({}); // no opt 125 | GlobalAssembler.RemoveUnusedOperations(false); // Disable own implementation 126 | 127 | HLOG("UNOPTIMIZED:"); 128 | const uint32_t uUnOptWords = AssembleTest(); 129 | 130 | GlobalAssembler.RemoveUnusedOperations(true); 131 | 132 | HLOG("REMOVED UNREFERENCED OPERATIONS:"); 133 | const uint32_t uUnRefWords = AssembleTest(); 134 | 135 | Settings.kPasses = kOptimizationPassFlag_AllPerformance; 136 | GlobalAssembler.ConfigureOptimization(Settings); 137 | GlobalAssembler.RemoveUnusedOperations(false); 138 | 139 | HLOG("SPIRV-OPT ALL PERFORMANCE:"); 140 | const uint32_t uOptWords = AssembleTest(); 141 | 142 | GlobalAssembler.RemoveUnusedOperations(true); 143 | 144 | HLOG("REMOVED UNREFERENCED + SPIRV-OPT ALL PERFORMANCE:"); 145 | const uint32_t uOptUnRefWords = AssembleTest(); 146 | 147 | const auto percent = [](uint32_t uCount, uint32_t uTotal) -> float 148 | { 149 | return ((float)uCount / (float)uTotal) * 100.f; 150 | }; 151 | 152 | const auto factor = [](uint32_t uCount, uint32_t uTotal) -> float 153 | { 154 | return ((float)uTotal / (float)uCount); 155 | }; 156 | 157 | HLOG("\nTotal instruction word count (4byte integers in stream):"); 158 | HLOG("Unoptimized:\t\t%u %.2f%% %.3fx", uUnOptWords, percent(uUnOptWords, uUnOptWords), factor(uUnOptWords, uUnOptWords)); 159 | HLOG("RemovedUnRef:\t%u %.2f%% %.3fx", uUnRefWords, percent(uUnRefWords, uUnOptWords), factor(uUnRefWords, uUnOptWords)); 160 | HLOG("Optimized:\t\t%u %.2f%% %.3fx", uOptWords, percent(uOptWords, uUnOptWords), factor(uOptWords, uUnOptWords)); 161 | HLOG("UnRefOptimized:\t%u %.2f%% %.3fx", uOptUnRefWords, percent(uOptUnRefWords, uUnOptWords), factor(uOptUnRefWords, uUnOptWords)); 162 | } 163 | else // assemble time test 164 | { 165 | // warmup 166 | AssembleTest(); 167 | 168 | hlx::Logger::Instance()->SetLogLevel(hlx::kMessageType_Fatal); 169 | 170 | hlx::StopWatch<> total; 171 | constexpr uint32_t uSampleCount = 10u; 172 | for (uint32_t i = 0; i < uSampleCount; i++) 173 | { 174 | hlx::StopWatch<> tone; 175 | 176 | AssembleTest(); 177 | 178 | std::cout << tone.Elapsed() << "s" << std::endl; 179 | } 180 | 181 | const auto fElapsed = total.Elapsed(); 182 | const float fAvg = fElapsed / (float)uSampleCount; 183 | std::cout << "Samples " << uSampleCount << " elapsed " << fElapsed << " avg " << fAvg << std::endl; 184 | } 185 | } 186 | 187 | //system("pause"); 188 | 189 | return 0; 190 | } -------------------------------------------------------------------------------- /SPIRVShaderFactory/CSGExampleShader.h: -------------------------------------------------------------------------------- 1 | //Copyright(c) 2018 2 | //Authors: Fabian Wahlster 3 | //Website: https://twitter.com/singul4rity 4 | //Contact: f.wahlster@tum.de 5 | //License: MIT with attribution (see LICENSE.txt) 6 | 7 | #ifndef SPEAR_CSGEXAMPLESHADER_H 8 | #define SPEAR_CSGEXAMPLESHADER_H 9 | 10 | #include "SimpleCSGRayMarching.h" 11 | #include "SPIRVProgram.h" 12 | #include "PhongMaterial.h" 13 | 14 | namespace Spear 15 | { 16 | template 17 | class CSGExampleShader : public FragmentProgram 18 | { 19 | public: 20 | CSGExampleShader() : FragmentProgram("CSGExampleShader") 21 | { 22 | OptimizationSettings Settings; 23 | Settings.kPasses = kOptimizationPassFlag_AllPerformance; 24 | GlobalAssembler.ConfigureOptimization(Settings); 25 | } 26 | ~CSGExampleShader() {}; 27 | 28 | RenderTarget OutputColor; 29 | inline void operator()() 30 | { 31 | float3 vCamPos = { 0.f, 0.f, 5.f }; 32 | float2 vViewport = { 1600.f, 900.f }; 33 | f32 fFoV = 45.f; 34 | 35 | auto Red = PhongMaterial::Make(float3_t{ 0.f, 0.0f, 0.f }); 36 | auto Blue = PhongMaterial::Make(float3_t{ 0.f, 0.0f, 0.f }, float3_t{ 0.0f, 0.15f, 0.85f }); 37 | auto White = PhongMaterial::Make(float3_t{ 0.f, 0.0f, 0.f }, float3_t{ 1.0f, 1.0f, 1.f }); 38 | 39 | std::vector> Lights = { PointLight({ 2.f, 0.5f, 2.f })/* PointLight({ -2.f, -2.5f, 10.f })*//*, DirectionalLight({ 0.25f, 0.8f, 0.f })*/ }; 40 | 41 | quaternion vRot({ 1.f, 0.5f, 0.f }, 0.3f); 42 | 43 | auto sphere = SphereSDF::Make(0.2f); 44 | auto cube = CubeSDF::Make(); 45 | auto plane = PlaneSDF::Make(glm::normalize(float3_t(1.f, 0.25f, 0.25f))); 46 | //auto cross = csg(CrossSDF::Make() * 0.1f) /** vRot*/; 47 | 48 | // translation 49 | auto csgobj1 = sphere + float3_t(1.f, 0.f, 0.f); 50 | // scale & rotation 51 | auto csgobj2 = (0.25f * cube) /** vRot*/; 52 | 53 | // linear blending 54 | //auto blend = Blend(csgobj1, csgobj2, 0.5f); 55 | 56 | ////auto menger1 = cube / (cross % float3_t(0.5f, 0.5f, 0.5f)); 57 | ////auto menger2 = menger1 / (cross % float3_t(1.f, 1.f, 1.f)); 58 | ////auto menger3 = menger2 / (cross % float3_t(2.f, 2.f, 2.f)); 59 | ////auto menger = menger3; 60 | 61 | //auto rep = sphere % float3_t(0.5f, 0.5f, 0.5f); 62 | //csgobj1->SetMaterial(Red); 63 | //csgobj2->SetMaterial(Blue); 64 | //blend->SetMaterial(Blue); 65 | //cross->SetMaterial(Blue); 66 | 67 | auto background = plane + float3_t(0.f, -1.f, 0.f); 68 | background->SetMaterial(Red); 69 | 70 | CSGScene scene({csgobj1, csgobj2, background }); 71 | 72 | if (false) 73 | { 74 | auto vRay = RayDirection(fFoV, vViewport, kFragCoord.xy); 75 | OutputColor.rgb = RayMarchCSGSceneEx(scene, vRay, vCamPos, Lights); 76 | } 77 | else 78 | { 79 | PointLight PointLight1({ 2.f, 0.5f, 2.f }); 80 | OutputColor.rgb = RayMarchCSGScene(scene, vCamPos, fFoV, kFragCoord.xy, vViewport, Red.get(), {&PointLight1 }); 81 | } 82 | 83 | OutputColor.a = 0.f; 84 | }; 85 | }; 86 | 87 | } // Spear 88 | 89 | #endif // !SPEAR_CSGEXAMPLESHADER_H 90 | -------------------------------------------------------------------------------- /SPIRVShaderFactory/CameraFunctions.h: -------------------------------------------------------------------------------- 1 | //Copyright(c) 2018 2 | //Authors: Fabian Wahlster 3 | //Website: https://twitter.com/singul4rity 4 | //Contact: f.wahlster@tum.de 5 | //License: MIT with attribution (see LICENSE.txt) 6 | 7 | #ifndef SPEAR_CAMERAFUNCTIONS_H 8 | #define SPEAR_CAMERAFUNCTIONS_H 9 | 10 | #include "SPIRVOperatorImpl.h" 11 | 12 | namespace Spear 13 | { 14 | //--------------------------------------------------------------------------------------------------- 15 | 16 | template 17 | var_t RayDirection( 18 | const var_t& fieldOfViewDeg, // in degree 19 | const var_t& viewportSize, 20 | const var_t& fragCoord) 21 | { 22 | using vec3 = var_t; 23 | 24 | auto xy = fragCoord - viewportSize * 0.5f; 25 | auto z = viewportSize.y / Tan(Radians(fieldOfViewDeg) * 0.5f); 26 | return Normalize(vec3(xy, -z)); 27 | } 28 | //--------------------------------------------------------------------------------------------------- 29 | 30 | template 31 | var_t ViewToWorld(const var_t& _vEye, const var_t& _vCenter, const var_t& _vUp) 32 | { 33 | using vec4 = var_t; 34 | using mat4 = var_t; 35 | 36 | auto f = Normalize(_vCenter - _vEye); 37 | auto s = Normalize(Cross(f, _vUp)); 38 | auto u = Cross(s, f); 39 | 40 | return mat4( 41 | vec4(s, 0.f), 42 | vec4(u, 0.f), 43 | vec4(-f, 0.f), 44 | vec4(0.f, 0.f, 0.f, 1.f) 45 | ); // Transpose? 46 | } 47 | 48 | //--------------------------------------------------------------------------------------------------- 49 | 50 | } // Spear 51 | 52 | #endif // !SPEAR_CAMERAFUNCTIONS_H 53 | -------------------------------------------------------------------------------- /SPIRVShaderFactory/ClearColor.h: -------------------------------------------------------------------------------- 1 | //Copyright(c) 2018 2 | //Authors: Fabian Wahlster 3 | //Website: https://twitter.com/singul4rity 4 | //Contact: f.wahlster@tum.de 5 | //License: MIT with attribution (see LICENSE.txt) 6 | 7 | #ifndef SPEAR_CLEARCOLOR_H 8 | #define SPEAR_CLEARCOLOR_H 9 | 10 | #include "SPIRVProgram.h" 11 | 12 | namespace Spear 13 | { 14 | template 15 | class ClearColor: public FragmentProgram 16 | { 17 | public: 18 | ClearColor() : FragmentProgram("ClearColor") {}; 19 | ~ClearColor() {}; 20 | 21 | //CBuffer BufferBlock; 22 | RenderTarget OutputColor; 23 | 24 | inline void operator()() 25 | { 26 | OutputColor = float4(1.f, 0.f, 0.0f, 0.f); 27 | }; 28 | private: 29 | }; 30 | 31 | } // Spear 32 | 33 | #endif // !SPEAR_CLEARCOLOR_H 34 | -------------------------------------------------------------------------------- /SPIRVShaderFactory/CommonBufferSourceNames.h: -------------------------------------------------------------------------------- 1 | //Copyright(c) 2018 2 | //Authors: Fabian Wahlster 3 | //Website: https://twitter.com/singul4rity 4 | //Contact: f.wahlster@tum.de 5 | //License: MIT with attribution (see LICENSE.txt) 6 | 7 | #ifndef SPEAR_COMMONBUFFERSOURCENAMES_H 8 | #define SPEAR_COMMONBUFFERSOURCENAMES_H 9 | 10 | #include "CompileTimeString.h" 11 | 12 | namespace Spear 13 | { 14 | namespace BufferSources 15 | { 16 | using namespace hlx; 17 | 18 | static constexpr std::string_view sObjectWorldMatrix = "SPEAR_OBJ_WORLD_MATRIX"_sv; 19 | static constexpr std::string_view sViewProjectionMatrix = "SPEAR_VIEW_PROJ_MATRIX"_sv; 20 | static constexpr std::string_view sFrameBufferDimension = "SPEAR_FRAMEBUFFER_DIM"_sv; 21 | 22 | #pragma warning(push) 23 | #pragma warning(disable: 4307) 24 | static constexpr uint64_t kObjectWorldMatrix = const_string_hash(sObjectWorldMatrix); 25 | static constexpr uint64_t kViewProjectionMatrix = const_string_hash(sViewProjectionMatrix); 26 | static constexpr uint64_t kFrameBufferDimension = const_string_hash(sFrameBufferDimension); 27 | #pragma warning(pop) 28 | } 29 | } // Spear 30 | 31 | #endif // !SPEAR_COMMONBUFFERSOURCENAMES_H 32 | -------------------------------------------------------------------------------- /SPIRVShaderFactory/DefaultShaderFactory.cpp: -------------------------------------------------------------------------------- 1 | //Copyright(c) 2018 2 | //Authors: Fabian Wahlster 3 | //Website: https://twitter.com/singul4rity 4 | //Contact: f.wahlster@tum.de 5 | //License: MIT with attribution (see LICENSE.txt) 6 | 7 | #include "DefaultShaderFactory.h" 8 | #include "DefaultShaderIdentifiers.h" 9 | 10 | // shaders 11 | #include "ClearColor.h" 12 | #include "ScreenSpaceTriangle.h" 13 | #include "Mandelbrot.h" 14 | #include "CSGExampleShader.h" 15 | 16 | using namespace Spear; 17 | //--------------------------------------------------------------------------------------------------- 18 | 19 | DefaultShaderFactory::DefaultShaderFactory() 20 | { 21 | } 22 | //--------------------------------------------------------------------------------------------------- 23 | 24 | DefaultShaderFactory::~DefaultShaderFactory() 25 | { 26 | } 27 | //--------------------------------------------------------------------------------------------------- 28 | 29 | SPIRVModule DefaultShaderFactory::GetModule(const ShaderID _ShaderIdentifier, const void* _pUserData, const size_t _uSize) 30 | { 31 | // in this example we don't use the user data, but we could cast it so some structure to control compilation 32 | auto it = m_Modules.find(_ShaderIdentifier); 33 | 34 | if (it != m_Modules.end()) 35 | { 36 | return it->second; 37 | } 38 | 39 | return m_Modules.emplace(_ShaderIdentifier.uID, std::move(Compile(_ShaderIdentifier))).first->second; 40 | } 41 | //--------------------------------------------------------------------------------------------------- 42 | 43 | void DefaultShaderFactory::Release() 44 | { 45 | delete this; 46 | } 47 | //--------------------------------------------------------------------------------------------------- 48 | 49 | SPIRVModule DefaultShaderFactory::Compile(const ShaderID _ShaderIdentifier) const 50 | { 51 | SPIRVModule Shader; 52 | switch (_ShaderIdentifier.uShader) 53 | { 54 | case kDefaultShader_ClearColor: 55 | Shader = GlobalAssembler.AssembleSimple>(); 56 | break; 57 | case kDefaultShader_ScreenSpaceTriangle: 58 | Shader = GlobalAssembler.AssembleSimple>(true, _ShaderIdentifier.uVariant); 59 | break; 60 | case kDefaultShader_Mandelbrot: 61 | Shader = GlobalAssembler.AssembleSimple>(); 62 | break; 63 | case kDefaultShader_CSGExample: 64 | Shader = GlobalAssembler.AssembleSimple>(); 65 | break; 66 | default: 67 | HERROR("Unknown shader %s", WCSTR(_ShaderIdentifier.GetString())); 68 | break; 69 | } 70 | 71 | #ifdef _DEBUG 72 | std::string sName = Shader.GetEntryPoint() + "_" + (_ShaderIdentifier.kType == kShaderType_Vertex ? "vert" : "frag"); 73 | Shader.Save(sName+".spv"); 74 | //system("spirv-dis test.spv"); 75 | //system("spirv-val test.spv"); 76 | #endif 77 | 78 | return Shader; 79 | } 80 | //--------------------------------------------------------------------------------------------------- 81 | -------------------------------------------------------------------------------- /SPIRVShaderFactory/DefaultShaderFactory.h: -------------------------------------------------------------------------------- 1 | //Copyright(c) 2018 2 | //Authors: Fabian Wahlster 3 | //Website: https://twitter.com/singul4rity 4 | //Contact: f.wahlster@tum.de 5 | //License: MIT with attribution (see LICENSE.txt) 6 | 7 | #ifndef SPEAR_DEFAULTFACTORY_H 8 | #define SPEAR_DEFAULTFACTORY_H 9 | 10 | #include "IShaderFactory.h" 11 | #include 12 | 13 | namespace Spear 14 | { 15 | class DefaultShaderFactory : public IShaderFactory 16 | { 17 | public: 18 | DefaultShaderFactory(); 19 | ~DefaultShaderFactory(); 20 | 21 | SPIRVModule GetModule(const ShaderID _ShaderIdentifier, const void* _pUserData = nullptr, const size_t _uSize = 0u) final; 22 | void Release() final; 23 | 24 | PLUGIN_INTERFACE(DefaultShaderFactory, 2u); 25 | private: 26 | 27 | SPIRVModule Compile(const ShaderID _ShaderIdentifier) const; 28 | 29 | private: 30 | std::unordered_map m_Modules; 31 | }; 32 | 33 | PLUGIN_ALIAS(Spear::DefaultShaderFactory::GetPlugin) 34 | } // Spear 35 | 36 | #endif // !SPEAR_DEFAULTFACTORY_H 37 | -------------------------------------------------------------------------------- /SPIRVShaderFactory/DefaultShaderIdentifiers.h: -------------------------------------------------------------------------------- 1 | //Copyright(c) 2018 2 | //Authors: Fabian Wahlster 3 | //Website: https://twitter.com/singul4rity 4 | //Contact: f.wahlster@tum.de 5 | //License: MIT with attribution (see LICENSE.txt) 6 | 7 | #ifndef SPEAR_DEFAULTSHADERIDENTIFIERS_H 8 | #define SPEAR_DEFAULTSHADERIDENTIFIERS_H 9 | 10 | #include "ShaderID.h" 11 | #include 12 | 13 | namespace Spear 14 | { 15 | enum EDefaultShader : uint16_t 16 | { 17 | kDefaultShader_ClearColor, 18 | kDefaultShader_ScreenSpaceTriangle, 19 | kDefaultShader_Mandelbrot, 20 | kDefaultShader_CSGExample 21 | }; 22 | 23 | enum EVertexPerm : uint32_t 24 | { 25 | kVertexPerm_None = 0, 26 | kVertexPerm_UVCoords = 1 << 0, 27 | }; 28 | 29 | using TVertexPermutation = hlx::Flag; 30 | 31 | constexpr ShaderID kShader_ScreenSpaceTriangle = kShaderID; 32 | constexpr ShaderID kShader_ScreenSpaceTriangle_UV = kShaderID; 33 | 34 | constexpr ShaderID kShader_ClearColor = kShaderID; 35 | constexpr ShaderID kShader_Mandelbrot = kShaderID; 36 | constexpr ShaderID kShader_CSGExample = kShaderID; 37 | 38 | } // Spear 39 | 40 | #endif // !SPEAR_DEFAULTSHADERIDENTIFIERS_H -------------------------------------------------------------------------------- /SPIRVShaderFactory/IShaderFactory.h: -------------------------------------------------------------------------------- 1 | //Copyright(c) 2018 2 | //Authors: Fabian Wahlster 3 | //Website: https://twitter.com/singul4rity 4 | //Contact: f.wahlster@tum.de 5 | //License: MIT with attribution (see LICENSE.txt) 6 | 7 | #ifndef SPEAR_ISHADERFACTORY_H 8 | #define SPEAR_ISHADERFACTORY_H 9 | 10 | #include "IPlugin.h" 11 | #include "..\SPIRVGen\SPIRVModule.h" 12 | #include "ShaderID.h" 13 | 14 | namespace Spear 15 | { 16 | class IShaderFactory : public hlx::IPlugin 17 | { 18 | public: 19 | virtual SPIRVModule GetModule(const ShaderID _uShaderIdentifier, const void* _pUserData = nullptr, const size_t _uSize = 0u) = 0; 20 | }; 21 | } // Spear 22 | 23 | #endif // !SPEAR_ISHADERFACTORY_H 24 | -------------------------------------------------------------------------------- /SPIRVShaderFactory/LightingFunctions.h: -------------------------------------------------------------------------------- 1 | //Copyright(c) 2018 2 | //Authors: Fabian Wahlster 3 | //Website: https://twitter.com/singul4rity 4 | //Contact: f.wahlster@tum.de 5 | //License: MIT with attribution (see LICENSE.txt) 6 | 7 | #ifndef SPEAR_LIGHTINGFUNCTIONS_H 8 | #define SPEAR_LIGHTINGFUNCTIONS_H 9 | 10 | #include "SPIRVOperatorImpl.h" 11 | 12 | namespace Spear 13 | { 14 | template 15 | inline var_t CalculateAttenuation( 16 | const var_t& _fSurfacePointToLightDist, 17 | const var_t& _fRange, 18 | const var_t& _fDecayStart) 19 | { 20 | auto fDecayStart = Max(_fDecayStart, 0.0000001f); // ensure light sphere has valid radius 21 | 22 | auto fDmax = Max(_fRange - fDecayStart, 0.f); 23 | auto fD = Max(_fSurfacePointToLightDist - fDecayStart, 0.f); 24 | 25 | auto fDFactor = Square(((fD / (1.f - Square(fD / fDmax))) / fDecayStart) + 1.f); 26 | 27 | return Select(fDFactor == 0.0f, make_const(0.0f), (1.0f / fDFactor) * Step(_fSurfacePointToLightDist, fDmax)); 28 | } 29 | //--------------------------------------------------------------------------------------------------- 30 | 31 | // vL = Light vector from vertex pos to light 32 | template 33 | inline var_t CalculateSpotCone( 34 | const var_t& _fSpotAngleRad, 35 | const var_t _vSpotDirection, 36 | const var_t _vLightToSurfaceDir) 37 | { 38 | auto fMinCos = Cos(_fSpotAngleRad); 39 | auto fMaxCos = (fMinCos + 1.0f) / 2.0f; 40 | return SmoothStep(fMinCos, fMaxCos, Dot(_vSpotDirection, _vLightToSurfaceDir)); 41 | } 42 | //--------------------------------------------------------------------------------------------------- 43 | } // Spear 44 | 45 | #endif // !SPEAR_LIGHTINGFUNCTIONS_H 46 | -------------------------------------------------------------------------------- /SPIRVShaderFactory/Mandelbrot.h: -------------------------------------------------------------------------------- 1 | //Copyright(c) 2018 2 | //Authors: Fabian Wahlster 3 | //Website: https://twitter.com/singul4rity 4 | //Contact: f.wahlster@tum.de 5 | //License: MIT with attribution (see LICENSE.txt) 6 | 7 | #ifndef SPEAR_MANDELBROT_H 8 | #define SPEAR_MANDELBROT_H 9 | 10 | #include "SPIRVProgram.h" 11 | #include "CommonBufferSourceNames.h" 12 | 13 | namespace Spear 14 | { 15 | template 16 | class Mandelbrot : public FragmentProgram 17 | { 18 | public: 19 | Mandelbrot() : FragmentProgram("Mandelbrot"){}; 20 | ~Mandelbrot() {}; 21 | 22 | //CBuffer FrameBufferDim = BufferSources::sFrameBufferDimension; 23 | 24 | RenderTarget OutputColor; 25 | inline void operator()() 26 | { 27 | f32 i = 0.f, max = 100.f; 28 | complex c(Lerp(-1.f, 1.f, kFragCoord.x / 1600.f), kFragCoord.y / 900.f); 29 | complex z(0.f, 0.f); 30 | While(z.Conjugate() < 4.f && i < max) 31 | { 32 | z = z * z + c; 33 | ++i; 34 | }); 35 | f32 scale = i / max; 36 | OutputColor = float4(scale, scale, scale, 0.f); 37 | }; 38 | private: 39 | }; 40 | 41 | } // Spear 42 | 43 | #endif // !SPEAR_MANDELBROT_H 44 | -------------------------------------------------------------------------------- /SPIRVShaderFactory/MaterialInterface.h: -------------------------------------------------------------------------------- 1 | //Copyright(c) 2018 2 | //Authors: Fabian Wahlster 3 | //Website: https://twitter.com/singul4rity 4 | //Contact: f.wahlster@tum.de 5 | //License: MIT with attribution (see LICENSE.txt) 6 | 7 | #ifndef SPEAR_MATERIALINTERFACE_H 8 | #define SPEAR_MATERIALINTERFACE_H 9 | 10 | #include "SPIRVVariable.h" 11 | #include 12 | 13 | namespace Spear 14 | { 15 | template 16 | struct DirectionalLight 17 | { 18 | SPVStruct; 19 | 20 | DirectionalLight( 21 | const float3_t _vDirection = { 0.5f, -1.f, 0.f }, 22 | const float3_t _vColor = { 1.f, 1.f, 1.f }) : 23 | vDirection(glm::normalize(_vDirection)), 24 | vColorIntensity(_vColor) 25 | {} 26 | 27 | var_t vDirection; 28 | var_t DLPAD1; 29 | var_t vColorIntensity; 30 | var_t DLPAD2; 31 | }; 32 | 33 | //--------------------------------------------------------------------------------------------------- 34 | template 35 | struct PointLight 36 | { 37 | SPVStruct; 38 | 39 | PointLight( 40 | const float3_t _vPosition = { 0.f, 0.f, 0.f }, 41 | const float _fRange = 10.f, 42 | const float3_t _vColor = { 1.f, 1.f, 1.f }, 43 | const float _fDecayStart = 2.f) : 44 | vPosition(_vPosition), 45 | fRange(_fRange), 46 | vColorIntensity(_vColor), 47 | fDecayStart(_fDecayStart) 48 | {} 49 | 50 | var_t vPosition; 51 | var_t fRange; 52 | var_t vColorIntensity; 53 | var_t fDecayStart; 54 | }; 55 | //--------------------------------------------------------------------------------------------------- 56 | 57 | template 58 | struct SpotLight 59 | { 60 | SPVStruct; 61 | 62 | SpotLight( 63 | const float3_t _vPosition = { 0.f, 0.f, 0.f }, 64 | const float _fRange = 10.f, 65 | const float3_t _vColor = { 1.f, 1.f, 1.f }, 66 | const float _fDecayStart = 2.f, 67 | const float3_t _vDirection = { 0.5f, -1.f, 0.f }, 68 | const float _fSpotAngleDeg = 30.f) : 69 | vPosition(_vPosition), 70 | fRange(_fRange), 71 | vColorIntensity(_vColor), 72 | fDecayStart(_fDecayStart), 73 | vDirection(glm::normalize(_vDirection)), 74 | fSpotAngle(glm::radians(_fSpotAngleDeg)) 75 | {} 76 | 77 | var_t vPosition; 78 | var_t fRange; 79 | var_t vColorIntensity; 80 | var_t fDecayStart; 81 | 82 | var_t vDirection; 83 | var_t fSpotAngle; // could be encoded as magnitude of vDirection 84 | }; 85 | //--------------------------------------------------------------------------------------------------- 86 | 87 | template 88 | using TLightVariant = std::variant, PointLight, SpotLight>; 89 | 90 | // a material is just some entity that evaluates to some spectrum 91 | template 92 | struct IMaterialInterface 93 | { 94 | // TODO: function: GetDiffuse Reflection Vec & GetSpecularReflection Vec (random under ndf) 95 | 96 | // light default empty implementation 97 | virtual var_t Eval(const var_t& _vPos, const var_t& _vNormal, const var_t& _vCameraPos, const DirectionalLight& _DirLight) const { return _DirLight.vColorIntensity; }; 98 | virtual var_t Eval(const var_t& _vPos, const var_t& _vNormal, const var_t& _vCameraPos, const PointLight& _PointLight) const { return _PointLight.vColorIntensity; }; 99 | virtual var_t Eval(const var_t& _vPos, const var_t& _vNormal, const var_t& _vCameraPos, const SpotLight& _SpotLight) const { return _SpotLight.vColorIntensity; }; 100 | 101 | // std visit matcher 102 | inline var_t operator()(const var_t& _vPos, const var_t& _vNormal, const var_t& _vCameraPos, const DirectionalLight& _DirLight) const { return Eval(_vPos, _vNormal, _vCameraPos, _DirLight); }; 103 | inline var_t operator()(const var_t& _vPos, const var_t& _vNormal, const var_t& _vCameraPos, const PointLight& _PointLight) const { return Eval(_vPos, _vNormal, _vCameraPos, _PointLight); }; 104 | inline var_t operator()(const var_t& _vPos, const var_t& _vNormal, const var_t& _vCameraPos, const SpotLight& _SpotLight) const { return Eval(_vPos, _vNormal, _vCameraPos, _SpotLight); }; 105 | }; 106 | } // Spear 107 | 108 | #endif // !SPEAR_MATERIALINTERFACE_H 109 | -------------------------------------------------------------------------------- /SPIRVShaderFactory/MathFunctions.h: -------------------------------------------------------------------------------- 1 | //Copyright(c) 2018 2 | //Authors: Fabian Wahlster 3 | //Website: https://twitter.com/singul4rity 4 | //Contact: f.wahlster@tum.de 5 | //License: MIT with attribution (see LICENSE.txt) 6 | 7 | #ifndef SPEAR_MATHFUNCTIONS_H 8 | #define SPEAR_MATHFUNCTIONS_H 9 | 10 | #include "SPIRVOperatorImpl.h" 11 | 12 | namespace Spear 13 | { 14 | template 15 | inline var_t RotateY3X3(const var_t& _fAngleRad) 16 | { 17 | using vec3 = var_t; 18 | using mat3 = var_t; 19 | 20 | auto c = Cos(_fAngleRad); 21 | auto s = Sin(_fAngleRad); 22 | 23 | return mat3( 24 | vec3(c, 0.f, s), 25 | vec3(0.f, 1.f, 0.f), // float3_t make_const 26 | vec3(-s, 0.f, c)); 27 | } 28 | 29 | template 30 | inline var_t RotateY4X4(const var_t& _fAngleRad) 31 | { 32 | using vec4 = var_t; 33 | using mat4 = var_t; 34 | 35 | auto c = Cos(_fAngleRad); 36 | auto s = Sin(_fAngleRad); 37 | 38 | return mat4( 39 | vec4(c, 0.f, s, 0.f), 40 | vec4(0.f, 1.f, 0.f, 0.f), 41 | vec4(-s, 0.f, c, 0.f), 42 | vec4(0.f, 0.f, 0.f, 1.f)); 43 | } 44 | } // Spear 45 | 46 | #endif // !SPEAR_MATHFUNCTIONS_H 47 | -------------------------------------------------------------------------------- /SPIRVShaderFactory/MicrofacetReflection.h: -------------------------------------------------------------------------------- 1 | //Copyright(c) 2018 2 | //Authors: Fabian Wahlster 3 | //Website: https://twitter.com/singul4rity 4 | //Contact: f.wahlster@tum.de 5 | //License: MIT with attribution (see LICENSE.txt) 6 | 7 | #ifndef SPEAR_MICROFACETREFLECTION_H 8 | #define SPEAR_MICROFACETREFLECTION_H 9 | 10 | #include "SPIRVProgram.h" 11 | 12 | namespace Spear 13 | { 14 | template // ri = refraction index 15 | inline var_t FresnelSchlick(const var_t& l, const var_t& h, var_t& ri) 16 | { 17 | auto f0 = (1.f - ri) / (1.f + ri); 18 | f0 *= f0; 19 | return f0 + (1.f - f0) * Pow(1.f - Dot(l, h), 5.f); 20 | } 21 | 22 | template // h = half, n = normal, a = exponent 23 | inline var_t BlinnPhongDistribution(const var_t& n, const var_t& h, var_t& a) 24 | { 25 | return ((a + 2.f) / glm::two_pi()) * Pow(Dot(n, h), a); 26 | } 27 | 28 | template 29 | inline var_t GeoImplicit(const var_t& n, const var_t& l, const var_t& v) 30 | { 31 | return Dot(n, l) * Dot(n, v); 32 | } 33 | 34 | template 35 | inline var_t GeoCookTorrance(const var_t& n, const var_t& l, const var_t& v, const var_t& h) 36 | { 37 | auto nh2vh = (2.f * Dot(n, h)) / Dot(v, h); 38 | 39 | return Min(1.f, nh2vh * Dot(n, v), nh2vh * Dot(n, l)); 40 | } 41 | 42 | template 43 | class MicrofacetReflection 44 | { 45 | public: 46 | MicrofacetReflection() {}; 47 | virtual ~MicrofacetReflection() {}; 48 | 49 | //https://simonstechblog.blogspot.de/2011/12/microfacet-brdf.html 50 | template // n = normal, l = lightdir, v = viewdir 51 | inline var_t Eval(const var_t& n, const var_t& l, const var_t& v) const 52 | { 53 | const MRInstance* pThis = static_cast(this); 54 | 55 | auto h = Normalize(l + v); 56 | // we pass all vectors as some variants might use different inputs 57 | return (pThis->F(n, l, v, h) * pThis->G(n, l, v, h) * pThis->D(n, l, v, h)) / (4.f * Dot(n, l) * Dot(n, v)); 58 | } 59 | private: 60 | 61 | }; 62 | } // Spear 63 | 64 | #endif // !SPEAR_MICROFACETREFLECTION_H 65 | -------------------------------------------------------------------------------- /SPIRVShaderFactory/PhongMaterial.h: -------------------------------------------------------------------------------- 1 | //Copyright(c) 2018 2 | //Authors: Fabian Wahlster 3 | //Website: https://twitter.com/singul4rity 4 | //Contact: f.wahlster@tum.de 5 | //License: MIT with attribution (see LICENSE.txt) 6 | 7 | #ifndef SPEAR_PHONGMATERIAL_H 8 | #define SPEAR_PHONGMATERIAL_H 9 | 10 | #include "SPIRVOperatorImpl.h" 11 | #include "MaterialInterface.h" 12 | #include "LightingFunctions.h" 13 | 14 | namespace Spear 15 | { 16 | //--------------------------------------------------------------------------------------------------- 17 | 18 | // standard branchless phong illumination for point light source 19 | template < 20 | bool Assemble, 21 | spv::StorageClass C1, 22 | spv::StorageClass C2, 23 | spv::StorageClass C3, 24 | spv::StorageClass C4, 25 | spv::StorageClass C5, 26 | spv::StorageClass C6, 27 | spv::StorageClass C7, 28 | spv::StorageClass C8> 29 | inline var_t PhongIlluminationPoint( 30 | const var_t& _vPos, // Surface point being lit 31 | const var_t& _vNormal, // Surface normal 32 | const var_t& _vCameraPos, 33 | const var_t& _vDiffuseColor, 34 | const var_t& _vSpecularColor, 35 | const var_t& _Alpha, // Shininess factor 36 | const var_t& _vLightPos, 37 | const var_t& _vLightColor)// intensity 38 | { 39 | auto L = Normalize(_vLightPos - _vPos); 40 | auto V = Normalize(_vCameraPos - _vPos); 41 | auto R = Normalize(Reflect(-L, _vNormal)); 42 | 43 | return _vLightColor * 44 | (_vDiffuseColor * Saturate(Dot(_vNormal, L)) 45 | + _vSpecularColor * Pow(Saturate(Dot(R, V)), _Alpha)); 46 | } 47 | 48 | //--------------------------------------------------------------------------------------------------- 49 | 50 | // standard branchless phong illumination for directional light source 51 | template < 52 | bool Assemble, 53 | spv::StorageClass C1, 54 | spv::StorageClass C2, 55 | spv::StorageClass C3, 56 | spv::StorageClass C4, 57 | spv::StorageClass C5, 58 | spv::StorageClass C6, 59 | spv::StorageClass C7, 60 | spv::StorageClass C8> 61 | inline var_t PhongIlluminationDir( 62 | const var_t& _vPos, // Surface point being lit 63 | const var_t& _vNormal, // Surface normal 64 | const var_t& _vCameraPos, 65 | const var_t& _vDiffuseColor, 66 | const var_t& _vSpecularColor, 67 | const var_t& _Alpha, // Shininess factor 68 | const var_t& _vLightDir, // source to surface 69 | const var_t& _vLightColor)// intensity 70 | { 71 | auto V = Normalize(_vCameraPos - _vPos); 72 | auto R = Normalize(Reflect(_vLightDir, _vNormal)); 73 | 74 | return _vLightColor * 75 | (_vDiffuseColor * Saturate(Dot(_vNormal, -_vLightDir)) 76 | + _vSpecularColor * Pow(Saturate(Dot(R, V)), _Alpha)); 77 | } 78 | 79 | //--------------------------------------------------------------------------------------------------- 80 | 81 | template 82 | struct PhongMaterial : public IMaterialInterface 83 | { 84 | SPVStruct; 85 | 86 | // directional light 87 | inline var_t Eval( 88 | const var_t& _vPos, // surface point lit 89 | const var_t& _vNormal, 90 | const var_t& _vCameraPos, 91 | const DirectionalLight& _Light) const final 92 | { 93 | return vAmbientColor + 94 | PhongIlluminationDir(_vPos, _vNormal, _vCameraPos, vDiffuseColor, vSpecularColor, fShininess, _Light.vDirection, _Light.vColorIntensity); 95 | } 96 | 97 | // point light 98 | inline var_t Eval( 99 | const var_t& _vPos, // surface point lit 100 | const var_t& _vNormal, 101 | const var_t& _vCameraPos, 102 | const PointLight& _Light) const final 103 | { 104 | return vAmbientColor + 105 | PhongIlluminationPoint(_vPos, _vNormal, _vCameraPos, vDiffuseColor, vSpecularColor, fShininess, _Light.vPosition, _Light.vColorIntensity) * 106 | CalculateAttenuation(Length(_Light.vPosition - _vPos), _Light.fRange, _Light.fDecayStart); 107 | } 108 | 109 | // spot light 110 | inline var_t Eval( 111 | const var_t& _vPos, // surface point lit 112 | const var_t& _vNormal, 113 | const var_t& _vCameraPos, 114 | const SpotLight& _Light) const final 115 | { 116 | return vAmbientColor + 117 | PhongIlluminationPoint(_vPos, _vNormal, _vCameraPos, vDiffuseColor, vSpecularColor, fShininess, _Light.vPosition, _Light.vColorIntensity) 118 | * CalculateAttenuation(Length(_Light.vPosition - _vPos), _Light.fRange, _Light.fDecayStart) 119 | * CalculateSpotCone(_Light.fSpotAngle, _Light.vDirection, Normalize(_vPos - _Light.vPosition)); 120 | } 121 | 122 | PhongMaterial( 123 | const float3_t _vAmbient = {0.25f, 0.25f, 0.25f}, 124 | const float3_t _vDiffuse = { 0.75f, 0.25f, 0.25f }, 125 | const float3_t _vSpecular = { 1.f, 1.f, 1.f }, 126 | const float _fShininess = 10.f) : 127 | vAmbientColor(_vAmbient), 128 | vDiffuseColor(_vDiffuse), 129 | vSpecularColor(_vSpecular), 130 | fShininess(_fShininess) {} 131 | 132 | var_t vAmbientColor; 133 | var_t PSPAD1; 134 | var_t vDiffuseColor; 135 | var_t PSPAD2; 136 | var_t vSpecularColor; 137 | var_t fShininess; 138 | 139 | template 140 | static inline std::shared_ptr Make(const Ts& ... args) { return std::make_shared(args...); } 141 | }; 142 | 143 | //--------------------------------------------------------------------------------------------------- 144 | 145 | 146 | } // Spear 147 | 148 | #endif // !SPEAR_PHONGMATERIAL_H 149 | -------------------------------------------------------------------------------- /SPIRVShaderFactory/SDFObject.h: -------------------------------------------------------------------------------- 1 | //Copyright(c) 2018 2 | //Authors: Fabian Wahlster 3 | //Website: https://twitter.com/singul4rity 4 | //Contact: f.wahlster@tum.de 5 | //License: MIT with attribution (see LICENSE.txt) 6 | 7 | #ifndef SPEAR_SDFOBJECT_H 8 | #define SPEAR_SDFOBJECT_H 9 | 10 | #include "SPIRVOperatorImpl.h" 11 | #include 12 | 13 | namespace Spear 14 | { 15 | //--------------------------------------------------------------------------------------------------- 16 | 17 | template 18 | inline var_t ForwardDiffNormal(const var_t& p, const var_t& e, const EvalFunc& _Eval) 19 | { 20 | using vec3 = var_t; 21 | 22 | return Normalize( 23 | vec3( 24 | _Eval(vec3(p.x + e, p.y, p.z)) - _Eval(vec3(p.x - e, p.y, p.z)), 25 | _Eval(vec3(p.x, p.y + e, p.z)) - _Eval(vec3(p.x, p.y - e, p.z)), 26 | _Eval(vec3(p.x, p.y, p.z + e)) - _Eval(vec3(p.x, p.y, p.z - e)) 27 | ) 28 | ); 29 | } 30 | 31 | template 32 | inline var_t DeriveFragmentNormal(const var_t& _PixelViewPos) 33 | { 34 | return Cross(Normalize(Ddx(_PixelViewPos)), Normalize(Ddy(_PixelViewPos))); 35 | } 36 | 37 | //--------------------------------------------------------------------------------------------------- 38 | 39 | template 40 | inline var_t SphereDist(const var_t& _Point, const var_t& _Radius) 41 | { 42 | return Length(_Point) - _Radius; 43 | } 44 | 45 | template 46 | inline var_t CubeDist(const var_t& _Point, const var_t& _vExtents) 47 | { 48 | auto d = Abs(_Point) - _vExtents; 49 | return Min(0.f, Max(d.x, d.y, d.z)) + Length(Max(d, make_const(float3_t(0.f, 0.f, 0.f)))); 50 | } 51 | 52 | template // plane at origin 53 | inline var_t PlaneDist(const var_t& _Point, const var_t& _vNormal) 54 | { 55 | return Dot(_Point, _vNormal); 56 | } 57 | 58 | template // xyz = normal box extents, w = extent towards info 59 | inline var_t CrossDist(const var_t& _Point, const var_t& _fExtent) 60 | { 61 | return Min(Max(Abs(_Point.x), Abs(_Point.y)), Max(Abs(_Point.y), Abs(_Point.z)), Max(Abs(_Point.z), Abs(_Point.x))) - _fExtent; 62 | } 63 | 64 | //--------------------------------------------------------------------------------------------------- 65 | 66 | template 67 | struct SDFObject 68 | { 69 | static constexpr bool AssembleParam = Assemble; 70 | 71 | using vec3 = var_t; 72 | 73 | SDFObject() {}; 74 | virtual ~SDFObject() {}; 75 | 76 | // user has to override this function: 77 | virtual var_t Distance(const var_t& _Point) const = 0; 78 | 79 | template 80 | inline var_t Eval(const var_t& _Point) const { return Distance(make_intermediate(_Point)); }; 81 | 82 | template 83 | inline var_t Normal(const var_t& _Point, const var_t& _Epsilon) const 84 | { 85 | return ForwardDiffNormal(_Point, _Epsilon, [&](const auto& v) {return this->Eval(v); }); 86 | }; 87 | }; 88 | 89 | template 90 | using TSDFObj = std::shared_ptr>; 91 | 92 | //--------------------------------------------------------------------------------------------------- 93 | 94 | template 95 | struct SphereSDF : public SDFObject 96 | { 97 | var_t fRadius; 98 | SphereSDF(const float& _fRadius = 1.f) : fRadius(_fRadius) {} 99 | 100 | template 101 | SphereSDF(const var_t& _fRadius) : fRadius(_fRadius) {} 102 | 103 | inline var_t Distance(const var_t& _Point) const final 104 | { 105 | return SphereDist(_Point, fRadius); 106 | } 107 | 108 | template 109 | static inline std::shared_ptr Make(const Ts& ... args) {return std::make_shared(args...); } 110 | }; 111 | 112 | //--------------------------------------------------------------------------------------------------- 113 | 114 | template 115 | struct CubeSDF : public SDFObject 116 | { 117 | var_t vExtent; 118 | CubeSDF(const float3_t _vExtents = {1.f, 1.f, 1.f}) : vExtent(_vExtents) {} 119 | 120 | template 121 | CubeSDF(const var_t& _vExtents) : vExtent(_vExtents) {} 122 | 123 | inline var_t Distance(const var_t& _Point) const final 124 | { 125 | return CubeDist(_Point, vExtent); 126 | } 127 | 128 | template 129 | static inline std::shared_ptr Make(const Ts& ... args) { return std::make_shared(args...); } 130 | }; 131 | 132 | //--------------------------------------------------------------------------------------------------- 133 | 134 | template 135 | struct PlaneSDF : public SDFObject 136 | { 137 | var_t vNormal; 138 | PlaneSDF(const float3_t _vNormal = { 0.f, 1.f, 0.f }) : vNormal(_vNormal) {} 139 | 140 | template 141 | PlaneSDF(const var_t& _vNormal) : vNormal(_vNormal) {} 142 | 143 | inline var_t Distance(const var_t& _Point) const final 144 | { 145 | return PlaneDist(_Point, vNormal); 146 | } 147 | 148 | template 149 | static inline std::shared_ptr Make(const Ts& ... args) { return std::make_shared(args...); } 150 | }; 151 | 152 | //--------------------------------------------------------------------------------------------------- 153 | 154 | template 155 | struct CrossSDF : public SDFObject 156 | { 157 | var_t fExtent; 158 | CrossSDF(const float& _fExtent = 1.f) : fExtent(_fExtent) {} 159 | 160 | template 161 | CrossSDF(const var_t& _fExtent) : fExtent(_fExtent) {} 162 | 163 | inline var_t Distance(const var_t& _Point) const final 164 | { 165 | return CrossDist(_Point, fExtent); 166 | } 167 | 168 | template 169 | static inline std::shared_ptr Make(const Ts& ... args) { return std::make_shared(args...); } 170 | }; 171 | 172 | //--------------------------------------------------------------------------------------------------- 173 | 174 | } // Spear 175 | 176 | #endif // !SPEAR_SDFOBJECT_H 177 | -------------------------------------------------------------------------------- /SPIRVShaderFactory/ScreenSpaceTriangle.h: -------------------------------------------------------------------------------- 1 | //Copyright(c) 2018 2 | //Authors: Fabian Wahlster 3 | //Website: https://twitter.com/singul4rity 4 | //Contact: f.wahlster@tum.de 5 | //License: MIT with attribution (see LICENSE.txt) 6 | 7 | #ifndef SPEAR_SCREENSPACETRIANGLE_H 8 | #define SPEAR_SCREENSPACETRIANGLE_H 9 | 10 | #include "SPIRVProgram.h" 11 | #include "DefaultShaderIdentifiers.h" 12 | 13 | namespace Spear 14 | { 15 | template 16 | struct SST_VSOUT 17 | { 18 | var_t UVCoords; // if not assigned, the assember will remove the variable from the instruction stream 19 | var_t Position; 20 | }; 21 | 22 | template 23 | inline SST_VSOUT ComputeScreenSpaceTriangle(const var_builtin_t& _kVertexIndex, const TVertexPermutation _Perm = {}) 24 | { 25 | using f32 = var_t; 26 | 27 | SST_VSOUT VS_OUT; 28 | 29 | f32 x = -1.0f + f32((_kVertexIndex & 1) << 2); 30 | f32 y = -1.0f + f32((_kVertexIndex & 2) << 1); 31 | 32 | if (_Perm.CheckFlag(kVertexPerm_UVCoords)) 33 | { 34 | VS_OUT.UVCoords.x = NDCToZeroOne(x); 35 | VS_OUT.UVCoords.y = NDCToZeroOne(y); 36 | } 37 | 38 | VS_OUT.Position = {x, y, 0.f, 1.f }; 39 | 40 | return VS_OUT; 41 | } 42 | 43 | template 44 | class ScreenSpaceTriangle : public VertexProgram 45 | { 46 | public: 47 | ScreenSpaceTriangle(const TVertexPermutation& _Perm) : VertexProgram("ScreenSpaceTriangle"), m_Permutation(_Perm){}; 48 | ~ScreenSpaceTriangle() {}; 49 | 50 | //https://rauwendaal.net/2014/06/14/rendering-a-screen-covering-triangle-in-opengl/ 51 | inline void operator()() 52 | { 53 | f32 x = -1.0f + f32((kVertexIndex & 1) << 2); 54 | f32 y = -1.0f + f32((kVertexIndex & 2) << 1); 55 | 56 | if (m_Permutation.CheckFlag(kVertexPerm_UVCoords)) 57 | { 58 | var_out UVCoords; 59 | UVCoords.x = NDCToZeroOne(x); 60 | UVCoords.y = NDCToZeroOne(y); 61 | } 62 | 63 | kPerVertex->kPostion = float4(x, y, 0.f, 1.f); 64 | } 65 | 66 | private: 67 | const TVertexPermutation m_Permutation; 68 | }; 69 | } // Spear 70 | 71 | #endif // SPEAR_SCREENSPACETRIANGLE_H -------------------------------------------------------------------------------- /SPIRVShaderFactory/ShaderID.h: -------------------------------------------------------------------------------- 1 | //Copyright(c) 2018 2 | //Authors: Fabian Wahlster 3 | //Website: https://twitter.com/singul4rity 4 | //Contact: f.wahlster@tum.de 5 | //License: MIT with attribution (see LICENSE.txt) 6 | 7 | #ifndef SPEAR_SHADERID_H 8 | #define SPEAR_SHADERID_H 9 | 10 | #include 11 | #include 12 | 13 | namespace Spear 14 | { 15 | enum EShaderType : uint8_t 16 | { 17 | kShaderType_Vertex = 0, 18 | kShaderType_TessellationControl = 1, 19 | kShaderType_TessellationEvaluation = 2, 20 | kShaderType_Geometry = 3, 21 | kShaderType_Fragment = 4, 22 | kShaderType_GLCompute = 5, 23 | kShaderType_Kernel = 6, 24 | 25 | kShaderType_NumOf, 26 | kShaderType_Unknown = kShaderType_NumOf 27 | }; 28 | 29 | template 30 | constexpr uint64_t kShaderID = (uint8_t)kType | ((uint64_t)uShader << 16u) | ((uint64_t)uVariant << 32u); 31 | 32 | struct ShaderID 33 | { 34 | constexpr ShaderID(const uint64_t _uID = kShaderType_Unknown) : uID(_uID) {} 35 | constexpr ShaderID(const EShaderType _kType, const uint8_t _uCompileFlags, const uint16_t _uShader, const uint32_t _uVariant) : 36 | kType(_kType), uCompileFlags(_uCompileFlags), uShader(_uShader), uVariant(_uVariant) {} 37 | constexpr ShaderID(const ShaderID& _Other) : uID(_Other.uID) {} 38 | 39 | inline std::string GetString() const { return "Type " + std::to_string(kType) + " Shader " + std::to_string(uShader) + " Variant " + std::to_string(uVariant) + " Flags " + std::to_string(uCompileFlags); } 40 | 41 | static constexpr uint64_t kInvalid = kShaderType_Unknown; 42 | 43 | const bool Valid() const { return kType < kShaderType_NumOf; } 44 | 45 | union 46 | { 47 | struct 48 | { 49 | EShaderType kType; // 8 50 | uint8_t uCompileFlags; // debug, optimization etc 51 | uint16_t uShader; // which shader 52 | uint32_t uVariant; // which permutation of the shader 53 | }; 54 | uint64_t uID; 55 | }; 56 | 57 | operator uint64_t() const { return uID; } 58 | }; 59 | } // Spear 60 | 61 | #endif // !SPEAR_SHADERID_H 62 | -------------------------------------------------------------------------------- /SPIRVShaderFactory/SimpleCSGRayMarching.h: -------------------------------------------------------------------------------- 1 | //Copyright(c) 2018 2 | //Authors: Fabian Wahlster 3 | //Website: https://twitter.com/singul4rity 4 | //Contact: f.wahlster@tum.de 5 | //License: MIT with attribution (see LICENSE.txt) 6 | 7 | #ifndef SPEAR_SIMPLECSGRAYMARCHING_H 8 | #define SPEAR_SIMPLECSGRAYMARCHING_H 9 | 10 | #include "CSGObject.h" 11 | #include "SPIRVBranchOperations.h" 12 | #include "CameraFunctions.h" 13 | #include "MaterialInterface.h" 14 | 15 | namespace Spear 16 | { 17 | //--------------------------------------------------------------------------------------------------- 18 | 19 | template 20 | inline var_t ShortestDistToSurface( 21 | const TEvalFunc& _Eval, 22 | const var_t& _vEye, // view pos 23 | const var_t& _vMarchDir, // ray dir 24 | const float _fStartDepth = 0.f, 25 | const float _fEndDepth = 100.f, 26 | const float _fEpsilon = 0.0001f, 27 | const uint32_t _uStepCount = 100u) 28 | { 29 | auto depth = make_var(_fStartDepth); 30 | For(auto i = make_var(0u), i < _uStepCount && depth < _fEndDepth, ++i) 31 | { 32 | auto dist = _Eval(_vEye + depth * _vMarchDir); 33 | If(dist < _fEpsilon) 34 | { 35 | i = _uStepCount; // break from loop 36 | } 37 | Else 38 | { 39 | depth += dist; 40 | }); 41 | }); 42 | 43 | return depth;// Min(depth, _fEndDepth); 44 | } 45 | 46 | //--------------------------------------------------------------------------------------------------- 47 | 48 | template 49 | inline var_t ShortestDistToSurface( 50 | const TCSGObj& _Object, 51 | const var_t& _vEye, // view pos 52 | const var_t& _vMarchDir, // ray dir 53 | const float _fStartDepth = 0.f, 54 | const float _fEndDepth = 100.f, 55 | const float _fEpsilon = 0.0001f, 56 | const uint32_t _uStepCount = 100u) 57 | { 58 | return ShortestDistToSurface([&](const var_t& e) {return _Object->Eval(e); }, _vEye, _vMarchDir, _fStartDepth, _fEndDepth, _fEpsilon, _uStepCount); 59 | } 60 | 61 | //--------------------------------------------------------------------------------------------------- 62 | 63 | template 64 | inline var_t ShortestDistToSurface( 65 | const CSGScene& _Scene, 66 | const var_t& _vEye, // view pos 67 | const var_t& _vMarchDir, // ray dir 68 | const float _fStartDepth = 0.f, 69 | const float _fEndDepth = 100.f, 70 | const float _fEpsilon = 0.0001f, 71 | const uint32_t _uStepCount = 100u) 72 | { 73 | return ShortestDistToSurface([&](const var_t& e) {return _Scene.Eval(e); }, _vEye, _vMarchDir, _fStartDepth, _fEndDepth, _fEpsilon, _uStepCount); 74 | } 75 | 76 | //--------------------------------------------------------------------------------------------------- 77 | 78 | // single material 79 | template 80 | inline var_t RayMarchDistanceFunction( 81 | const TEvalFunc& _DistFunc, 82 | const var_t& _vCameraPos, 83 | const var_t& _vRay, 84 | const IMaterialInterface* _pMaterial = nullptr, 85 | const std::vector*> _PointLights = {}, // todo: use std::variant and std visit 86 | const float _fStartDepth = 0.f, 87 | const float _fEndDepth = 100.f, 88 | const float _fEpsilon = 0.0001f, 89 | const uint32_t _uStepCount = 100u) 90 | { 91 | auto fDist = ShortestDistToSurface(_DistFunc, _vCameraPos, _vRay, _fStartDepth, _fEndDepth, _fEpsilon, _uStepCount); 92 | 93 | auto vPos = _vCameraPos + _vRay * fDist; 94 | auto vNormal = ForwardDiffNormal(vPos, mcvar(_fEpsilon), _DistFunc); 95 | //auto vNormal = DeriveFragmentNormal(vPos); 96 | 97 | auto vColor = make_const(float3_t(0.f, 0.f, 0.f)); 98 | 99 | if (_pMaterial != nullptr) 100 | { 101 | for (const PointLight* pLight : _PointLights) 102 | { 103 | vColor += _pMaterial->Eval(vPos, vNormal, _vCameraPos, *pLight); 104 | } 105 | } 106 | else 107 | { 108 | //vColor.r = fDist / _fEndDepth; // for debugging 109 | vColor = vNormal; // print normal instead 110 | } 111 | 112 | // ray escaped 113 | auto bEscaped = fDist > _fEndDepth - _fEpsilon; 114 | return Select(bEscaped, mvar(float3_t(0.f, 0.f, 0.f)), vColor); 115 | 116 | return vColor; 117 | } 118 | 119 | //--------------------------------------------------------------------------------------------------- 120 | 121 | // Material per CSG object 122 | template 123 | inline var_t RayMarchCSGSceneEx( 124 | const CSGScene& _Scene, 125 | const var_t& _vRay, 126 | const var_t& _vCameraPos, 127 | const std::vector> _Lights, 128 | const float _fStartDepth = 0.f, 129 | const float _fEndDepth = 100.f, 130 | const float _fEpsilon = 0.0001f, 131 | const uint32_t _uStepCount = 100u) 132 | { 133 | var_t vColor = { 0.f, 0.f, 0.f }; 134 | 135 | //auto fDist = ShortestDistToSurface([&](const var_t& e) {return _Scene.Eval(e); }, _vCameraPos, _vRay, _fStartDepth, _fEndDepth, _fEpsilon, _uStepCount); 136 | 137 | //auto vPos = _vCameraPos + _vRay * fDist; 138 | //auto vNormal = _Scene.Normal(vPos, mcvar(_fEpsilon)); 139 | 140 | for (const auto& pObj : _Scene.GetObjects()) 141 | { 142 | const auto& pMaterial = pObj->GetMaterial(); 143 | 144 | if (pMaterial) 145 | { 146 | auto fDist = ShortestDistToSurface(pObj, _vCameraPos, _vRay, _fStartDepth, _fEndDepth, _fEpsilon, _uStepCount); 147 | 148 | auto vPos = _vCameraPos + _vRay * fDist; 149 | auto vNormal = pObj->Normal(vPos, mcvar(_fEpsilon)); 150 | 151 | for (const auto Light : _Lights) 152 | { 153 | vColor += std::visit([&](auto&& arg) {return pMaterial->Eval(vPos, vNormal, _vCameraPos, arg); }, Light); 154 | //vColor += Select(fDist < _fEndDepth, vObjColor, mcvar(float3_t(0.f, 0.f, 0.f))); 155 | } 156 | } 157 | } 158 | 159 | return vColor; 160 | } 161 | //--------------------------------------------------------------------------------------------------- 162 | 163 | // simple pointlight monomaterial marching 164 | template 165 | inline var_t RayMarchCSGScene( 166 | const CSGScene& _Scene, 167 | const var_t& _vCameraPos, 168 | const var_t& _fFoVDeg, // camera field of view Y in degrees 169 | const var_t& _vFragCoords, // fragment coordinates relative to viewport 170 | const var_t& _vViewportSize,// resolution of the viewport 171 | const IMaterialInterface* _pMaterial = nullptr, 172 | const std::vector*> _PointLights = {}) 173 | { 174 | return RayMarchDistanceFunction( 175 | [&](const var_t& e) {return _Scene.Eval(e); }, // depth function 176 | _vCameraPos, // origin 177 | RayDirection(_fFoVDeg, _vViewportSize, _vFragCoords), // view 178 | _pMaterial, // shading 179 | _PointLights); 180 | } 181 | } // Spear 182 | 183 | #endif // !SPEAR_SIMPLECSGRAYMARCHING_H 184 | -------------------------------------------------------------------------------- /misc/Paper.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rAzoR8/SPEAR/8e8714542ff54efc95b40dfaf51fb500eb5458eb/misc/Paper.pdf -------------------------------------------------------------------------------- /misc/Slides.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rAzoR8/SPEAR/8e8714542ff54efc95b40dfaf51fb500eb5458eb/misc/Slides.pdf -------------------------------------------------------------------------------- /misc/fractal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rAzoR8/SPEAR/8e8714542ff54efc95b40dfaf51fb500eb5458eb/misc/fractal.png -------------------------------------------------------------------------------- /misc/vs_shader_dbg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rAzoR8/SPEAR/8e8714542ff54efc95b40dfaf51fb500eb5458eb/misc/vs_shader_dbg.png --------------------------------------------------------------------------------