├── .clang-tidy
├── .gitattributes
├── .github
└── workflows
│ ├── cmake_linux.yml
│ ├── cmake_macos.yml
│ └── cmake_windows.yml
├── .gitignore
├── .gitmodules
├── CMakeLists.txt
├── LICENSE
├── OPCODE_CORE.md
├── OPCODE_EXT.md
├── README.md
├── example
├── CMakeLists.txt
├── main.cpp
└── shaders
│ ├── simple.frag
│ ├── simple.frag.spv
│ └── simple.frag.spv.txt
├── images
├── Nt3BzM.png
├── XdlSDs.png
├── fstyD4.png
└── ftdfWn.png
├── shadertoy
├── CMakeLists.txt
├── assets
│ ├── images
│ │ ├── awesomeface.png
│ │ └── wood.png
│ ├── shaders
│ │ ├── Nt3BzM.frag
│ │ ├── XdlSDs.frag
│ │ ├── basic.frag
│ │ ├── fstyD4.frag
│ │ └── ftdfWn.frag
│ └── wrapper.frag
├── compiler.cpp
├── compiler.h
├── main.cpp
├── renderer.cpp
├── renderer.h
├── resourcelimits.cpp
├── resourcelimits.h
├── settingpanel.cpp
├── settingpanel.h
├── settings.h
├── third_party
│ ├── glad
│ │ ├── include
│ │ │ ├── KHR
│ │ │ │ └── khrplatform.h
│ │ │ └── glad
│ │ │ │ └── glad.h
│ │ └── src
│ │ │ └── glad.c
│ ├── glfw
│ │ ├── include
│ │ │ └── GLFW
│ │ │ │ ├── glfw3.h
│ │ │ │ └── glfw3native.h
│ │ ├── lib-macos-universal
│ │ │ ├── libglfw.3.dylib
│ │ │ └── libglfw3.a
│ │ ├── lib-mingw-w64
│ │ │ ├── glfw3.dll
│ │ │ ├── libglfw3.a
│ │ │ └── libglfw3dll.a
│ │ └── lib-vc2022
│ │ │ ├── glfw3.dll
│ │ │ ├── glfw3.lib
│ │ │ ├── glfw3_mt.lib
│ │ │ └── glfw3dll.lib
│ ├── imgui
│ │ └── imgui
│ │ │ ├── imconfig.h
│ │ │ ├── imgui.cpp
│ │ │ ├── imgui.h
│ │ │ ├── imgui_demo.cpp
│ │ │ ├── imgui_draw.cpp
│ │ │ ├── imgui_impl_glfw.cpp
│ │ │ ├── imgui_impl_glfw.h
│ │ │ ├── imgui_impl_opengl3.cpp
│ │ │ ├── imgui_impl_opengl3.h
│ │ │ ├── imgui_impl_opengl3_loader.h
│ │ │ ├── imgui_internal.h
│ │ │ ├── imgui_tables.cpp
│ │ │ ├── imgui_widgets.cpp
│ │ │ ├── imstb_rectpack.h
│ │ │ ├── imstb_textedit.h
│ │ │ └── imstb_truetype.h
│ └── stb
│ │ └── include
│ │ └── stb
│ │ ├── stb_image.h
│ │ └── stb_image_write.h
├── threadpool.h
├── timer.cpp
└── timer.h
├── src
├── CMakeLists.txt
├── decoder.cpp
├── decoder.h
├── ext
│ ├── GLSL.std.450.h
│ └── GLSL.std.450.inc
├── image.cpp
├── image.h
├── interface.cpp
├── interface.h
├── logger.cpp
├── logger.h
├── module.cpp
├── module.h
├── opcodes.inc
├── opstrings.h
├── runtime.cpp
├── runtime.h
├── spirv.h
├── spvm.cpp
├── spvm.h
└── utils.h
└── test
├── CMakeLists.txt
├── assets
├── arithmetic_0.frag
├── arithmetic_0.frag.spv
├── arithmetic_0.frag.spv.txt
├── arithmetic_1.frag
├── arithmetic_1.frag.spv
├── arithmetic_1.frag.spv.txt
├── array.frag
├── array.frag.spv
├── array.frag.spv.txt
├── assert.glsl
├── bit.frag
├── bit.frag.spv
├── bit.frag.spv.txt
├── built_in.vert
├── built_in.vert.spv
├── built_in.vert.spv.txt
├── composite.frag
├── composite.frag.spv
├── composite.frag.spv.txt
├── control_flow.frag
├── control_flow.frag.spv
├── control_flow.frag.spv.txt
├── conversion.frag
├── conversion.frag.spv
├── conversion.frag.spv.txt
├── derivative.frag
├── derivative.frag.spv
├── derivative.frag.spv.txt
├── function.frag
├── function.frag.spv
├── function.frag.spv.txt
├── glsl_std_450_0.frag
├── glsl_std_450_0.frag.spv
├── glsl_std_450_0.frag.spv.txt
├── glsl_std_450_1.frag
├── glsl_std_450_1.frag.spv
├── glsl_std_450_1.frag.spv.txt
├── glsl_std_450_2.frag
├── glsl_std_450_2.frag.spv
├── glsl_std_450_2.frag.spv.txt
├── image.frag
├── image.frag.spv
├── image.frag.spv.txt
├── location.frag
├── location.frag.spv
├── location.frag.spv.txt
├── relational_logical.frag
├── relational_logical.frag.spv
├── relational_logical.frag.spv.txt
├── uniform_block.vert
├── uniform_block.vert.spv
└── uniform_block.vert.spv.txt
├── main.cpp
├── test.h
├── test_core.cpp
├── test_ext.cpp
├── test_image.cpp
└── tools
└── glsl.py
/.clang-tidy:
--------------------------------------------------------------------------------
1 | Checks: '-modernize-use-auto'
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | shadertoy/third_party/** linguist-vendored
2 | test/googletest/** linguist-vendored
--------------------------------------------------------------------------------
/.github/workflows/cmake_linux.yml:
--------------------------------------------------------------------------------
1 | name: CMake Linux
2 |
3 | on:
4 | push:
5 | branches: [ main, dev ]
6 | pull_request:
7 | branches: [ main, dev ]
8 |
9 | env:
10 | BUILD_TYPE: Release
11 |
12 | jobs:
13 | build_linux:
14 | name: build_linux
15 | runs-on: ubuntu-latest
16 |
17 | steps:
18 | - uses: actions/checkout@v3
19 | with:
20 | submodules: true
21 |
22 | - name: Install OpenGL Library
23 | run: sudo apt-get install -y libglfw3-dev libgl1-mesa-dev libglu1-mesa-dev libglfw3 libglfw3-dev
24 |
25 | - name: Configure CMake
26 | run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
27 |
28 | - name: Build
29 | run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
30 |
31 | - name: Test
32 | run: cd ${{github.workspace}}/build && ctest
33 |
--------------------------------------------------------------------------------
/.github/workflows/cmake_macos.yml:
--------------------------------------------------------------------------------
1 | name: CMake MacOS
2 |
3 | on:
4 | push:
5 | branches: [ main, dev ]
6 | pull_request:
7 | branches: [ main, dev ]
8 |
9 | env:
10 | BUILD_TYPE: Release
11 |
12 | jobs:
13 | build_macOS:
14 | name: build_macOS
15 | runs-on: macos-latest
16 |
17 | steps:
18 | - uses: actions/checkout@v3
19 | with:
20 | submodules: true
21 |
22 | - name: Configure CMake
23 | run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
24 |
25 | - name: Build
26 | run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
27 |
28 | - name: Test
29 | run: cd ${{github.workspace}}/build && ctest
30 |
--------------------------------------------------------------------------------
/.github/workflows/cmake_windows.yml:
--------------------------------------------------------------------------------
1 | name: CMake Windows
2 |
3 | on:
4 | push:
5 | branches: [ main, dev ]
6 | pull_request:
7 | branches: [ main, dev ]
8 |
9 | env:
10 | BUILD_TYPE: Release
11 |
12 | jobs:
13 | build_windows:
14 | name: build_windows
15 | runs-on: windows-latest
16 |
17 | steps:
18 | - uses: actions/checkout@v3
19 | with:
20 | submodules: true
21 |
22 | - name: Configure CMake
23 | run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
24 |
25 | - name: Build
26 | run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
27 |
28 | - name: Test
29 | run: cd ${{github.workspace}}/build && ctest
30 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | .vscode
3 | cmake-build*/
4 | build/
5 | bin/spvm*
6 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "shadertoy/third_party/glslang"]
2 | path = shadertoy/third_party/glslang
3 | url = https://github.com/KhronosGroup/glslang
4 | [submodule "test/googletest"]
5 | path = test/googletest
6 | url = https://github.com/google/googletest
7 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.3)
2 | project(spvm)
3 |
4 | set(CMAKE_CXX_STANDARD 11)
5 |
6 | add_subdirectory(src)
7 | add_subdirectory(shadertoy)
8 |
9 | option(BUILD_EXAMPLE "Whether or not to build the example" ON)
10 | if (${BUILD_EXAMPLE})
11 | message(STATUS "Building example")
12 | add_subdirectory(example)
13 | endif ()
14 |
15 | option(BUILD_TEST "Whether or not to build the tests" ON)
16 | if (${BUILD_TEST})
17 | message(STATUS "Building tests")
18 | enable_testing()
19 | add_subdirectory(test)
20 | endif ()
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 keith2018
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/OPCODE_EXT.md:
--------------------------------------------------------------------------------
1 | ## GLSL.std.450
2 |
3 | | Opcode | Status |
4 | |-----------------------|--------|
5 | | Round | ✅DONE |
6 | | RoundEven | ✅DONE |
7 | | Trunc | ✅DONE |
8 | | FAbs | ✅DONE |
9 | | SAbs | ✅DONE |
10 | | FSign | ✅DONE |
11 | | SSign | ✅DONE |
12 | | Floor | ✅DONE |
13 | | Ceil | ✅DONE |
14 | | Fract | ✅DONE |
15 | | Radians | ✅DONE |
16 | | Degrees | ✅DONE |
17 | | Sin | ✅DONE |
18 | | Cos | ✅DONE |
19 | | Tan | ✅DONE |
20 | | Asin | ✅DONE |
21 | | Acos | ✅DONE |
22 | | Atan | ✅DONE |
23 | | Sinh | ✅DONE |
24 | | Cosh | ✅DONE |
25 | | Tanh | ✅DONE |
26 | | Asinh | ✅DONE |
27 | | Acosh | ✅DONE |
28 | | Atanh | ✅DONE |
29 | | Atan2 | ✅DONE |
30 | | Pow | ✅DONE |
31 | | Exp | ✅DONE |
32 | | Log | ✅DONE |
33 | | Exp2 | ✅DONE |
34 | | Log2 | ✅DONE |
35 | | Sqrt | ✅DONE |
36 | | InverseSqrt | ✅DONE |
37 | | Determinant | 🟥TODO |
38 | | MatrixInverse | 🟥TODO |
39 | | Modf | ✅DONE |
40 | | ModfStruct | ✅DONE |
41 | | FMin | ✅DONE |
42 | | UMin | ✅DONE |
43 | | SMin | ✅DONE |
44 | | FMax | ✅DONE |
45 | | UMax | ✅DONE |
46 | | SMax | ✅DONE |
47 | | FClamp | ✅DONE |
48 | | UClamp | ✅DONE |
49 | | SClamp | ✅DONE |
50 | | FMix | ✅DONE |
51 | | IMix | 🟥TODO |
52 | | Step | ✅DONE |
53 | | SmoothStep | ✅DONE |
54 | | Fma | ✅DONE |
55 | | Frexp | ✅DONE |
56 | | FrexpStruct | ✅DONE |
57 | | Ldexp | ✅DONE |
58 | | PackSnorm4x8 | ✅DONE |
59 | | PackUnorm4x8 | ✅DONE |
60 | | PackSnorm2x16 | ✅DONE |
61 | | PackUnorm2x16 | ✅DONE | |
62 | | PackHalf2x16 | 🟥TODO |
63 | | PackDouble2x32 | 🟥TODO |
64 | | UnpackSnorm2x16 | ✅DONE |
65 | | UnpackUnorm2x16 | ✅DONE |
66 | | UnpackHalf2x16 | 🟥TODO |
67 | | UnpackSnorm4x8 | ✅DONE |
68 | | UnpackUnorm4x8 | ✅DONE |
69 | | UnpackDouble2x32 | 🟥TODO |
70 | | Length | ✅DONE |
71 | | Distance | ✅DONE |
72 | | Cross | ✅DONE |
73 | | Normalize | ✅DONE |
74 | | FaceForward | ✅DONE |
75 | | Reflect | ✅DONE |
76 | | Refract | ✅DONE |
77 | | FindILsb | ✅DONE |
78 | | FindSMsb | ✅DONE |
79 | | FindUMsb | ✅DONE |
80 | | InterpolateAtCentroid | 🟥TODO |
81 | | InterpolateAtSample | 🟥TODO |
82 | | InterpolateAtOffset | 🟥TODO |
83 | | NMin | ✅DONE |
84 | | NMax | ✅DONE |
85 | | NClamp | ✅DONE |
86 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SPVM
2 | Tiny C++ [SPIR-V](https://registry.khronos.org/SPIR-V/) virtual machine (interpreter), you can use it to debug shaders: first compile your shader code(GLSL/HLSL) to SPIR-V binary file (using tools such as [glslangValidator](https://github.com/KhronosGroup/glslang)), then decode and execute entry point function `main` with SPVM, and check the output.
3 |
4 | [](./LICENSE)
5 | [](https://github.com/keith2018/spvm/actions/workflows/cmake_linux.yml)
6 | [](https://github.com/keith2018/spvm/actions/workflows/cmake_macos.yml)
7 | [](https://github.com/keith2018/spvm/actions/workflows/cmake_windows.yml)
8 |
9 | Specifications that the project follows is:
10 | - [SPIR-V 1.0](https://registry.khronos.org/SPIR-V/specs/1.0/SPIRV.html)
11 | - [GLSL.std.450](https://registry.khronos.org/SPIR-V/specs/1.0/GLSL.std.450.html)
12 |
13 | ### Limits
14 | - Only part of SPIR-V 1.0 instructions has been implemented right now, see the opcodes support status:
15 | - [Core (SPIR-V 1.0) Opcodes](OPCODE_CORE.md)
16 | - [Ext (GLSL.std.450) Opcodes](OPCODE_EXT.md)
17 | - Only support 32-bits width [Numerical type](https://registry.khronos.org/SPIR-V/specs/1.0/SPIRV.html#_types) (float, integer)
18 | - Only support [Addressing Model](https://registry.khronos.org/SPIR-V/specs/1.0/SPIRV.html#Addressing_Model) `Logical`
19 | - Not support derivative opcodes (dFdx\dFdy\...)
20 | - Not support OpenCL related instructions
21 |
22 | ### TODO
23 | - [ ] 64-bit float/integer support
24 | - [ ] Performance optimizations
25 | - [ ] SIMD
26 | - [ ] JIT/AOT
27 |
28 | The project is still working in progress ...
29 |
30 | ## Spvm-ShaderToy
31 | Spvm-ShaderToy simulated the runtime environment of [shadertoy](https://www.shadertoy.com/), and execute shader code using SPVM (may very slow 😀).
32 |
33 | ### Gallery
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | ## Example
46 |
47 | GLSL fragment shader (see [example/shaders/simple.frag](example/shaders/simple.frag))
48 |
49 | ```glsl
50 | #version 450
51 |
52 | layout (location = 0) in vec3 inColor;
53 | layout (location = 0) out vec4 outFragColor;
54 |
55 | void main()
56 | {
57 | outFragColor = vec4(inColor.yxz, 1.0f);
58 | }
59 | ```
60 |
61 | run with spvm (see [example/main.cpp](example/main.cpp))
62 |
63 | ```cpp
64 | #define HEAP_SIZE 128 * 1024
65 | const char *SPV_PATH = "shaders/simple.frag.spv";
66 |
67 | SPVM::SpvmModule module;
68 | SPVM::Runtime runtime;
69 |
70 | // decode spir-v file
71 | bool success = SPVM::Decoder::decodeFile(SPV_PATH, &module);
72 | if (!success) {
73 | std::cout << "error decode spir-v file";
74 | return -1;
75 | }
76 |
77 | // init runtime
78 | success = runtime.initWithModule(&module, HEAP_SIZE);
79 | if (!success) {
80 | std::cout << "error init module";
81 | return -1;
82 | }
83 |
84 | // get uniform locations
85 | SPVM::SpvmWord inColorLoc = runtime.getLocationByName("inColor");
86 | SPVM::SpvmWord outFragColorLoc = runtime.getLocationByName("outFragColor");
87 |
88 | // write input
89 | float inColor[3]{0.2f, 0.3f, 0.4f};
90 | runtime.writeInput(inColor, inColorLoc);
91 |
92 | // execute shader entry function 'main'
93 | success = runtime.execEntryPoint();
94 | if (!success) {
95 | std::cout << "error exec entrypoint function";
96 | return -1;
97 | }
98 |
99 | // read output
100 | float outFragColor[4];
101 | runtime.readOutput(outFragColor, outFragColorLoc);
102 |
103 | std::cout << "outFragColor[0]: " << outFragColor[0] << std::endl;
104 | std::cout << "outFragColor[1]: " << outFragColor[1] << std::endl;
105 | std::cout << "outFragColor[2]: " << outFragColor[2] << std::endl;
106 | std::cout << "outFragColor[3]: " << outFragColor[3] << std::endl;
107 | ```
108 |
109 | ## Clone
110 | ```bash
111 | git clone --recursive https://github.com/keith2018/spvm
112 | cd spvm
113 | ```
114 |
115 | ## Build
116 | ```bash
117 | mkdir build
118 | cmake -B ./build -DCMAKE_BUILD_TYPE=Release
119 | cmake --build ./build --config Release
120 | ```
121 |
122 | ## Test
123 | ```bash
124 | cd build
125 | ctest
126 | ```
127 |
128 | ## License
129 | This code is licensed under the MIT License (see [LICENSE](LICENSE)).
130 |
--------------------------------------------------------------------------------
/example/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.3)
2 | project(spvm_example)
3 |
4 | set(CMAKE_CXX_STANDARD 11)
5 |
6 | include_directories("../src")
7 | add_executable(${PROJECT_NAME} main.cpp)
8 |
9 | set(LIBRARIES spvm_lib)
10 | target_link_libraries(${PROJECT_NAME} ${LIBRARIES})
11 |
12 | if (MSVC)
13 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /std:c++latest")
14 | endif ()
15 |
16 | SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/../bin)
17 | SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/../bin)
18 |
19 | # copy assets
20 | add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
21 | COMMAND ${CMAKE_COMMAND} -E remove_directory $/shaders
22 | COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/shaders $/shaders
23 | )
--------------------------------------------------------------------------------
/example/main.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * spvm
3 | * @author : keith@robot9.me
4 | *
5 | */
6 |
7 | #include
8 |
9 | #include "decoder.h"
10 | #include "runtime.h"
11 |
12 | #define HEAP_SIZE 128 * 1024
13 | const char *SPV_PATH = "shaders/simple.frag.spv";
14 |
15 | int main(int argc, char *argv[]) {
16 | SPVM::SpvmModule module;
17 | SPVM::Runtime runtime;
18 |
19 | // decode spir-v file
20 | bool success = SPVM::Decoder::decodeFile(SPV_PATH, &module);
21 | if (!success) {
22 | std::cout << "error decode spir-v file";
23 | return -1;
24 | }
25 |
26 | // init runtime
27 | success = runtime.initWithModule(&module, HEAP_SIZE);
28 | if (!success) {
29 | std::cout << "error init module";
30 | return -1;
31 | }
32 |
33 | // get uniform locations
34 | SPVM::SpvmWord inColorLoc = runtime.getLocationByName("inColor");
35 | SPVM::SpvmWord outFragColorLoc = runtime.getLocationByName("outFragColor");
36 |
37 | // write input
38 | float inColor[3]{0.2f, 0.3f, 0.4f};
39 | runtime.writeInput(inColor, inColorLoc);
40 |
41 | // execute shader entry function 'main'
42 | success = runtime.execEntryPoint();
43 | if (!success) {
44 | std::cout << "error exec entrypoint function";
45 | return -1;
46 | }
47 |
48 | // read output
49 | float outFragColor[4];
50 | runtime.readOutput(outFragColor, outFragColorLoc);
51 |
52 | std::cout << "outFragColor[0]: " << outFragColor[0] << std::endl;
53 | std::cout << "outFragColor[1]: " << outFragColor[1] << std::endl;
54 | std::cout << "outFragColor[2]: " << outFragColor[2] << std::endl;
55 | std::cout << "outFragColor[3]: " << outFragColor[3] << std::endl;
56 |
57 | return 0;
58 | }
--------------------------------------------------------------------------------
/example/shaders/simple.frag:
--------------------------------------------------------------------------------
1 | #version 450
2 |
3 | layout (location = 0) in vec3 inColor;
4 | layout (location = 0) out vec4 outFragColor;
5 |
6 | void main()
7 | {
8 | outFragColor = vec4(inColor.yxz, 1.0f);
9 | }
10 |
--------------------------------------------------------------------------------
/example/shaders/simple.frag.spv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keith2018/spvm/a232ea822562dde8d9de47be458a3777392d98bb/example/shaders/simple.frag.spv
--------------------------------------------------------------------------------
/example/shaders/simple.frag.spv.txt:
--------------------------------------------------------------------------------
1 | .\location.frag
2 | // Module Version 10000
3 | // Generated by (magic number): 8000a
4 | // Id's are bound by 20
5 |
6 | Capability Shader
7 | 1: ExtInstImport "GLSL.std.450"
8 | MemoryModel Logical GLSL450
9 | EntryPoint Fragment 4 "main" 9 12
10 | ExecutionMode 4 OriginUpperLeft
11 | Source GLSL 450
12 | Name 4 "main"
13 | Name 9 "outFragColor"
14 | Name 12 "inColor"
15 | Decorate 9(outFragColor) Location 0
16 | Decorate 12(inColor) Location 0
17 | 2: TypeVoid
18 | 3: TypeFunction 2
19 | 6: TypeFloat 32
20 | 7: TypeVector 6(float) 4
21 | 8: TypePointer Output 7(fvec4)
22 | 9(outFragColor): 8(ptr) Variable Output
23 | 10: TypeVector 6(float) 3
24 | 11: TypePointer Input 10(fvec3)
25 | 12(inColor): 11(ptr) Variable Input
26 | 15: 6(float) Constant 1065353216
27 | 4(main): 2 Function None 3
28 | 5: Label
29 | 13: 10(fvec3) Load 12(inColor)
30 | 14: 10(fvec3) VectorShuffle 13 13 1 0 2
31 | 16: 6(float) CompositeExtract 14 0
32 | 17: 6(float) CompositeExtract 14 1
33 | 18: 6(float) CompositeExtract 14 2
34 | 19: 7(fvec4) CompositeConstruct 16 17 18 15
35 | Store 9(outFragColor) 19
36 | Return
37 | FunctionEnd
38 |
--------------------------------------------------------------------------------
/images/Nt3BzM.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keith2018/spvm/a232ea822562dde8d9de47be458a3777392d98bb/images/Nt3BzM.png
--------------------------------------------------------------------------------
/images/XdlSDs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keith2018/spvm/a232ea822562dde8d9de47be458a3777392d98bb/images/XdlSDs.png
--------------------------------------------------------------------------------
/images/fstyD4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keith2018/spvm/a232ea822562dde8d9de47be458a3777392d98bb/images/fstyD4.png
--------------------------------------------------------------------------------
/images/ftdfWn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keith2018/spvm/a232ea822562dde8d9de47be458a3777392d98bb/images/ftdfWn.png
--------------------------------------------------------------------------------
/shadertoy/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.3)
2 | project(spvm_shadertoy)
3 |
4 | set(CMAKE_CXX_STANDARD 11)
5 | set(THIRD_PARTY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party")
6 |
7 | include_directories(
8 | "${THIRD_PARTY_DIR}/glfw/include"
9 | "${THIRD_PARTY_DIR}/glad/include"
10 | "${THIRD_PARTY_DIR}/imgui"
11 | "${THIRD_PARTY_DIR}/stb/include"
12 | "${THIRD_PARTY_DIR}/glslang/include"
13 | "../src"
14 | )
15 |
16 | set(SKIP_GLSLANG_INSTALL ON)
17 | set(ENABLE_GLSLANG_BINARIES OFF)
18 | set(ENABLE_CTEST OFF)
19 | set(BUILD_TESTING OFF)
20 | add_subdirectory("${THIRD_PARTY_DIR}/glslang")
21 |
22 | # imgui src
23 | file(GLOB IMGUI_SRC
24 | ${THIRD_PARTY_DIR}/imgui/imgui/*.cpp
25 | )
26 |
27 | add_executable(${PROJECT_NAME}
28 | "${IMGUI_SRC}"
29 | "${THIRD_PARTY_DIR}/glad/src/glad.c"
30 | renderer.cpp
31 | compiler.cpp
32 | resourcelimits.cpp
33 | settingpanel.cpp
34 | timer.cpp
35 | main.cpp
36 | )
37 |
38 | set(LIBRARIES
39 | spvm_lib
40 | glslang
41 | SPIRV)
42 |
43 | if (WIN32)
44 | if (MSVC)
45 | target_link_libraries(${PROJECT_NAME}
46 | ${LIBRARIES}
47 | "${THIRD_PARTY_DIR}/glfw/lib-vc2022/glfw3.lib"
48 | "${THIRD_PARTY_DIR}/glfw/lib-vc2022/glfw3dll.lib"
49 | )
50 | else ()
51 | target_link_libraries(${PROJECT_NAME}
52 | ${LIBRARIES}
53 | "${THIRD_PARTY_DIR}/glfw/lib-mingw-w64/libglfw3.a"
54 | "${THIRD_PARTY_DIR}/glfw/lib-mingw-w64/libglfw3dll.a"
55 | )
56 | endif ()
57 | endif ()
58 |
59 | if (APPLE)
60 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -framework Cocoa -framework OpenGL -framework IOKit")
61 | add_compile_definitions(GL_SILENCE_DEPRECATION)
62 | target_link_libraries(${PROJECT_NAME}
63 | ${LIBRARIES}
64 | "${THIRD_PARTY_DIR}/glfw/lib-macos-universal/libglfw3.a"
65 | )
66 | endif ()
67 |
68 | if (UNIX AND NOT APPLE)
69 | find_package(OpenGL REQUIRED)
70 | target_link_libraries(${PROJECT_NAME}
71 | ${LIBRARIES}
72 | glfw
73 | OpenGL::GL
74 | pthread
75 | ${CMAKE_DL_LIBS}
76 | )
77 | endif ()
78 |
79 | if (MSVC)
80 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /std:c++latest")
81 | else ()
82 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3")
83 | endif ()
84 |
85 | SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/../bin)
86 | SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/../bin)
87 |
88 | # copy assets
89 | add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
90 | COMMAND ${CMAKE_COMMAND} -E remove_directory $/assets
91 | COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/assets $/assets
92 | )
--------------------------------------------------------------------------------
/shadertoy/assets/images/awesomeface.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keith2018/spvm/a232ea822562dde8d9de47be458a3777392d98bb/shadertoy/assets/images/awesomeface.png
--------------------------------------------------------------------------------
/shadertoy/assets/images/wood.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keith2018/spvm/a232ea822562dde8d9de47be458a3777392d98bb/shadertoy/assets/images/wood.png
--------------------------------------------------------------------------------
/shadertoy/assets/shaders/Nt3BzM.frag:
--------------------------------------------------------------------------------
1 | // from https://www.shadertoy.com/view/Nt3BzM
2 |
3 | #define cx_arg(a) atan(a.y, a.x)
4 |
5 |
6 | #define PI 3.14159265
7 | #define TAU (2.*PI)
8 |
9 | #define cx_mul(a, b) vec2(a.x*b.x - a.y*b.y, a.x*b.y + a.y*b.x)
10 | #define cx_div(a, b) vec2(((a.x*b.x + a.y*b.y)/(b.x*b.x + b.y*b.y)),((a.y*b.x - a.x*b.y)/(b.x*b.x + b.y*b.y)))
11 | #define cx_sin(a) vec2(sin(a.x) * cosh(a.y), cos(a.x) * sinh(a.y))
12 | #define cx_cos(a) vec2(cos(a.x) * cosh(a.y), -sin(a.x) * sinh(a.y))
13 |
14 | float sharp = 0.39; // delay
15 | float b = 0.655; // brightness 0 -> dark, 1 -> bright
16 | float nMod = 2.; // num of level curves mod
17 | float nPhase = 20.; // num. of level curves phase
18 | float base = 2.; // For the base of a logarithm
19 | float nContour = 16.;
20 |
21 | vec2 as_polar(vec2 z) {
22 | return vec2(
23 | length(z),
24 | atan(z.y, z.x)
25 | );
26 | }
27 |
28 | vec2 cx_tan(vec2 a) {return cx_div(cx_sin(a), cx_cos(a)); }
29 | vec2 cx_log(vec2 a) {
30 | vec2 polar = as_polar(a);
31 | float rpart = polar.x;
32 | float ipart = polar.y;
33 | if (ipart > PI) ipart=ipart-(2.0*PI);
34 | return vec2(log(rpart),ipart);
35 | }
36 | vec2 cx_pow(vec2 v, float p) {
37 | vec2 z = as_polar(v);
38 | return pow(z.x, p) * vec2(cos(z.y * p), sin(z.y * p));
39 | }
40 |
41 | vec3 rgb2hsv(vec3 c)
42 | {
43 | vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
44 | vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
45 | vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
46 |
47 | float d = q.x - min(q.w, q.y);
48 | float e = 1.0e-10;
49 | return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
50 | }
51 |
52 | vec3 hsv2rgb(vec3 c)
53 | {
54 | vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
55 | vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
56 | return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
57 | }
58 |
59 | vec3 palette( in float t, in vec3 a, in vec3 b, in vec3 c, in vec3 d )
60 | {
61 | return a + b*cos(2. * PI *(c*t+d) );
62 | }
63 |
64 | float funPhase(vec2 p) {
65 | return (PI - atan(p.y, -p.x)) / (2. * PI);
66 | }
67 |
68 | float funColor(vec2 p) {
69 | return sharp * (nContour * (PI - atan(p.y, -p.x)) / (2. * PI) - floor(nContour * (PI - atan(p.y, -p.x)) / (2. * PI))) + 0.7;
70 | }
71 |
72 | void mainImage( out vec4 fragColor, in vec2 fragCoord )
73 | {
74 | // Normalized pixel coordinates (from 0 to 1)
75 | vec2 uv = (fragCoord.xy - 0.5 * iResolution.xy) / min(iResolution.y, iResolution.x);
76 | vec2 z = uv;
77 | float angle = sin(iTime/5.) * TAU;
78 | float length = .2;
79 |
80 | // Spin our points in a circle of radius length
81 | float c = cos(angle);
82 | float s = sin(angle);
83 | vec2 p = vec2( s*length, c*length);
84 | vec2 q = vec2( s*-length, c*-length );
85 |
86 | //(z-1)/(z^3+z+1)
87 |
88 | vec2 z_minus_one = z - vec2(sin(iTime / 2.), cos(iTime));
89 | vec2 z_cubed_plus_one = cx_mul(cx_mul(z, z), z) + z * (sin(iTime / 10.) + 0.1) - vec2(1, 0);
90 | vec2 division = cx_div(z_minus_one, z_cubed_plus_one);
91 |
92 |
93 | vec3 col = palette( funPhase(division) * (8. * sin(iTime / 10.)), vec3(0.50,.52,0.53), vec3(.46,.32,.35), vec3(.82,.84,.65), vec3(0.53,0.23,0.22));
94 | vec3 hsv = rgb2hsv(col);
95 | col = vec3(hsv.r, hsv.b, funColor(division));
96 | //vec3 col = vec3(funPhase(division), 1., funColor(division));
97 | fragColor = vec4(col, 1.0);
98 | }
--------------------------------------------------------------------------------
/shadertoy/assets/shaders/XdlSDs.frag:
--------------------------------------------------------------------------------
1 | // from https://www.shadertoy.com/view/XdlSDs
2 |
3 | void mainImage( out vec4 fragColor, in vec2 fragCoord )
4 | {
5 | vec2 p = (2.0*fragCoord.xy-iResolution.xy)/iResolution.y;
6 | float tau = 3.1415926535*2.0;
7 | float a = atan(p.x,p.y);
8 | float r = length(p)*0.75;
9 | vec2 uv = vec2(a/tau,r);
10 |
11 | //get the color
12 | float xCol = (uv.x - (iTime / 3.0)) * 3.0;
13 | xCol = mod(xCol, 3.0);
14 | vec3 horColour = vec3(0.25, 0.25, 0.25);
15 |
16 | if (xCol < 1.0) {
17 |
18 | horColour.r += 1.0 - xCol;
19 | horColour.g += xCol;
20 | }
21 | else if (xCol < 2.0) {
22 |
23 | xCol -= 1.0;
24 | horColour.g += 1.0 - xCol;
25 | horColour.b += xCol;
26 | }
27 | else {
28 |
29 | xCol -= 2.0;
30 | horColour.b += 1.0 - xCol;
31 | horColour.r += xCol;
32 | }
33 |
34 | // draw color beam
35 | uv = (2.0 * uv) - 1.0;
36 | float beamWidth = (0.7+0.5*cos(uv.x*10.0*tau*0.15*clamp(floor(5.0 + 10.0*cos(iTime)), 0.0, 10.0))) * abs(1.0 / (30.0 * uv.y));
37 | vec3 horBeam = vec3(beamWidth);
38 | fragColor = vec4((( horBeam) * horColour), 1.0);
39 | }
--------------------------------------------------------------------------------
/shadertoy/assets/shaders/basic.frag:
--------------------------------------------------------------------------------
1 | void mainImage( out vec4 fragColor, in vec2 fragCoord )
2 | {
3 | // Normalized pixel coordinates (from 0 to 1)
4 | vec2 uv = fragCoord/iResolution.xy;
5 |
6 | // Time varying pixel color
7 | vec3 col = 0.5 + 0.5*cos(iTime+uv.xyx+vec3(0,2,4));
8 |
9 | // Output to screen
10 | fragColor = vec4(col,1.0);
11 | }
--------------------------------------------------------------------------------
/shadertoy/assets/shaders/fstyD4.frag:
--------------------------------------------------------------------------------
1 | // from https://www.shadertoy.com/view/fstyD4
2 |
3 | // Author: bitless
4 | // Title: Coastal Landscape
5 |
6 | // Thanks to Patricio Gonzalez Vivo & Jen Lowe for "The Book of Shaders"
7 | // and Fabrice Neyret (FabriceNeyret2) for https://shadertoyunofficial.wordpress.com/
8 | // and Inigo Quilez (iq) for https://iquilezles.org/www/index.htm
9 | // and whole Shadertoy community for inspiration.
10 |
11 | #define p(t, a, b, c, d) ( a + b*cos( 6.28318*(c*t+d) ) ) //IQ's palette function (https://www.iquilezles.org/www/articles/palettes/palettes.htm)
12 | #define sp(t) p(t,vec3(.26,.76,.77),vec3(1,.3,1),vec3(.8,.4,.7),vec3(0,.12,.54)) //sky palette
13 | #define hue(v) ( .6 + .76 * cos(6.3*(v) + vec4(0,23,21,0) ) ) //hue
14 |
15 | // "Hash without Sine" by Dave_Hoskins.
16 | // https://www.shadertoy.com/view/4djSRW
17 | float hash12(vec2 p)
18 | {
19 | vec3 p3 = fract(vec3(p.xyx) * .1031);
20 | p3 += dot(p3, p3.yzx + 33.33);
21 | return fract((p3.x + p3.y) * p3.z);
22 | }
23 |
24 | vec2 hash22(vec2 p)
25 | {
26 | vec3 p3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973));
27 | p3 += dot(p3, p3.yzx+33.33);
28 | return fract((p3.xx+p3.yz)*p3.zy);
29 | }
30 | ////////////////////////
31 |
32 | vec2 rotate2D (vec2 st, float a){
33 | return mat2(cos(a),-sin(a),sin(a),cos(a))*st;
34 | }
35 |
36 | float st(float a, float b, float s) //AA bar
37 | {
38 | return smoothstep (a-s, a+s, b);
39 | }
40 |
41 | float noise( in vec2 p ) //gradient noise
42 | {
43 | vec2 i = floor( p );
44 | vec2 f = fract( p );
45 |
46 | vec2 u = f*f*(3.-2.*f);
47 |
48 | return mix( mix( dot( hash22( i+vec2(0,0) ), f-vec2(0,0) ),
49 | dot( hash22( i+vec2(1,0) ), f-vec2(1,0) ), u.x),
50 | mix( dot( hash22( i+vec2(0,1) ), f-vec2(0,1) ),
51 | dot( hash22( i+vec2(1,1) ), f-vec2(1,1) ), u.x), u.y);
52 | }
53 |
54 | void mainImage( out vec4 O, in vec2 g)
55 | {
56 | vec2 r = iResolution.xy
57 | ,uv = (g+g-r)/r.y
58 | ,sun_pos = vec2(r.x/r.y*.42,-.53) //sun position
59 | ,tree_pos = vec2(-r.x/r.y*.42,-.2) //tree position
60 | ,sh, u, id, lc, t;
61 |
62 | vec3 f, c;
63 | float xd, yd, h, a, l;
64 | vec4 C;
65 |
66 | float sm = 3./r.y; //smoothness factor for AA
67 |
68 | sh = rotate2D(sun_pos, noise(uv+iTime*.25)*.3); //big noise on the sky
69 |
70 | if (uv.y > -.4) //drawing the sky
71 | {
72 | u = uv + sh;
73 |
74 | yd = 60.; //number of rings
75 |
76 | id = vec2((length(u)+.01)*yd,0); //segment id: x - ring number, y - segment number in the ring
77 | xd = floor(id.x)*.09; //number of ring segments
78 | h = (hash12(floor(id.xx))*.5+.25)*(iTime+10.)*.25; //ring shift
79 | t = rotate2D (u,h); //rotate the ring to the desired angle
80 |
81 | id.y = atan(t.y,t.x)*xd;
82 | lc = fract(id); //segment local coordinates
83 | id -= lc;
84 |
85 | // determining the coordinates of the center of the segment in uv space
86 | t = vec2(cos((id.y+.5)/xd)*(id.x+.5)/yd,sin((id.y+.5)/xd)*(id.x+.5)/yd);
87 | t = rotate2D(t,-h) - sh;
88 |
89 | h = noise(t*vec2(.5,1)-vec2(iTime*.2,0)) //clouds
90 | * step(-.25,t.y); //do not draw clouds below -.25
91 | h = smoothstep (.052,.055, h);
92 |
93 |
94 | lc += (noise(lc*vec2(1,4)+id))*vec2(.7,.2); //add fine noise
95 |
96 | f = mix (sp(sin(length(u)-.1))*.35, //sky background
97 | mix(sp(sin(length(u)-.1)+(hash12(id)-.5)*.15),vec3(1),h), //mix sky color and clouds
98 | st(abs(lc.x-.5),.4,sm*yd)*st(abs(lc.y-.5),.48,sm*xd));
99 | };
100 |
101 | if (uv.y < -.35) //drawing water
102 | {
103 |
104 | float cld = noise(-sh*vec2(.5,1) - vec2(iTime*.2,0)); //cloud density opposite the center of the sun
105 | cld = 1.- smoothstep(.0,.15,cld)*.5;
106 |
107 | u = uv*vec2(1,15);
108 | id = floor(u);
109 |
110 | for (float i = 1.; i > -1.; i--) //drawing a wave and its neighbors from above and below
111 | {
112 | if (id.y+i < -5.)
113 | {
114 | lc = fract(u)-.5;
115 | lc.y = (lc.y+(sin(uv.x*12.-iTime*3.+id.y+i))*.25-i)*4.; //set the waveform and divide it into four strips
116 | h = hash12(vec2(id.y+i,floor(lc.y))); //the number of segments in the strip and its horizontal offset
117 |
118 | xd = 6.+h*4.;
119 | yd = 30.;
120 | lc.x = uv.x*xd+sh.x*9.; //divide the strip into segments
121 | lc.x += sin(iTime * (.5 + h*2.))*.5; //add a cyclic shift of the strips horizontally
122 | h = .8*smoothstep(5.,.0,abs(floor(lc.x)))*cld+.1; //determine brightness of the sun track
123 | f = mix(f,mix(vec3(0,.1,.5),vec3(.35,.35,0),h),st(lc.y,0.,sm*yd)); //mix the color of the water and the color of the track for the background of the water
124 | lc += noise(lc*vec2(3,.5))*vec2(.1,.6); //add fine noise to the segment
125 |
126 | f = mix(f, //mix the background color
127 | mix(hue(hash12(floor(lc))*.1+.56).rgb*(1.2+floor(lc.y)*.17),vec3(1,1,0),h) //and the stroke color
128 | ,st(lc.y,0.,sm*xd)
129 | *st(abs(fract(lc.x)-.5),.48,sm*xd)*st(abs(fract(lc.y)-.5),.3,sm*yd)
130 | );
131 | }
132 | }
133 | }
134 |
135 | O = vec4(f,1);
136 |
137 | ////////////////////// drawing the grass
138 | a = 0.;
139 | u = uv+noise(uv*2.)*.1 + vec2(0,sin(uv.x*1.+3.)*.4+.8);
140 |
141 | f = mix(vec3(.7,.6,.2),vec3(0,1,0),sin(iTime*.2)*.5+.5); //color of the grass, changing from green to yellow and back again
142 | O = mix(O,vec4(f*.4,1),step(u.y,.0)); //draw grass background
143 |
144 | xd = 60.; //grass size
145 | u = u*vec2(xd,xd/3.5);
146 |
147 |
148 | if (u.y < 1.2)
149 | {
150 | for (float y = 0.; y > -3.; y--)
151 | {
152 | for (float x = -2.; x <3.; x++)
153 | {
154 | id = floor(u) + vec2(x,y);
155 | lc = (fract(u) + vec2(1.-x,-y))/vec2(5,3);
156 | h = (hash12(id)-.5)*.25+.5; //shade and length for an individual blade of grass
157 |
158 | lc-= vec2(.3,.5-h*.4);
159 | lc.x += sin(((iTime*1.7+h*2.-id.x*.05-id.y*.05)*1.1+id.y*.5)*2.)*(lc.y+.5)*.5;
160 | t = abs(lc)-vec2(.02,.5-h*.5);
161 | l = length(max(t,0.)) + min(max(t.x,t.y),0.); //distance to the segment (blade of grass)
162 |
163 | l -= noise (lc*7.+id)*.1; //add fine noise
164 | C = vec4(f*.25,st(l,.1,sm*xd*.09)); //grass outline
165 | C = mix(C,vec4(f //grass foregroud
166 | *(1.2+lc.y*2.) //the grass is a little darker at the root
167 | *(1.8-h*2.5),1.) //brightness variations for individual blades of grass
168 | ,st(l,.04,sm*xd*.09));
169 |
170 | O = mix (O,C,C.a*step (id.y,-1.));
171 | a = max (a, C.a*step (id.y,-5.)); //a mask to cover the trunk of the tree with grasses in the foreground
172 | }
173 | }
174 | }
175 |
176 | float T = sin(iTime*.5); //tree swing cycle
177 |
178 | if (abs(uv.x+tree_pos.x-.1-T*.1) < .6) // drawing the tree
179 | {
180 | u = uv + tree_pos;
181 | // draw the trunk of the tree first
182 | u.x -= sin(u.y+1.)*.2*(T+.75); //the trunk bends in the wind
183 | u += noise(u*4.5-7.)*.25; //trunk curvature
184 |
185 | xd = 10., yd = 60.;
186 | t = u * vec2(1,yd); //divide the trunk into segments
187 | h = hash12(floor(t.yy)); //horizontal shift of the segments and the color tint of the segment
188 | t.x += h*.01;
189 | t.x *= xd;
190 |
191 | lc = fract(t); //segment local coordinates
192 |
193 | float m = st(abs(t.x-.5),.5,sm*xd)*step(abs(t.y+20.),45.); //trunk mask
194 | C = mix(vec4(.07) //outline color
195 | ,vec4(.5,.3,0,1)*(.4+h*.4) //foreground color
196 | ,st(abs(lc.y-.5),.4,sm*yd)*st(abs(lc.x-.5),.45,sm*xd));
197 | C.a = m;
198 |
199 | xd = 30., yd = 15.;
200 |
201 | for (float xs =0.;xs<4.;xs++) //drawing four layers of foliage
202 | {
203 | u = uv + tree_pos + vec2 (xs/xd*.5 -(T +.75)*.15,-.7); //crown position
204 | u += noise(u*vec2(2,1)+vec2(-iTime+xs*.05,0))*vec2(-.25,.1)*smoothstep (.5,-1.,u.y+.7)*.75; //leaves rippling in the wind
205 |
206 | t = u * vec2(xd,1.);
207 | h = hash12(floor(t.xx)+xs*1.4); //number of segments for the row
208 |
209 | yd = 5.+ h*7.;
210 | t.y *= yd;
211 |
212 | sh = t;
213 | lc = fract(t);
214 | h = hash12(t-lc); //segment color shade
215 |
216 |
217 | t = (t-lc)/vec2(xd,yd)+vec2(0,.7);
218 |
219 | m = (step(0.,t.y)*step (length(t),.45) //the shape of the crown - the top
220 | + step (t.y,0.)*step (-0.7+sin((floor(u.x)+xs*.5)*15.)*.2,t.y)) //the bottom
221 | *step (abs(t.x),.5) //crown size horizontally
222 | *st(abs(lc.x-.5),.35,sm*xd*.5);
223 |
224 | lc += noise((sh)*vec2(1.,3.))*vec2(.3,.3); //add fine noise
225 |
226 | f = hue((h+(sin(iTime*.2)*.5+.5))*.2).rgb-t.x; //color of the segment changes cyclically
227 |
228 | C = mix(C,
229 | vec4(mix(f*.15,f*.6*(.7+xs*.2), //mix outline and foreground color
230 | st(abs(lc.y-.5),.47,sm*yd)*st(abs(lc.x-.5),.2,sm*xd)),m)
231 | ,m);
232 | }
233 |
234 | O = mix (O,C,C.a*(1.-a));
235 | }
236 | }
--------------------------------------------------------------------------------
/shadertoy/assets/shaders/ftdfWn.frag:
--------------------------------------------------------------------------------
1 | // from https://www.shadertoy.com/view/ftdfWn
2 |
3 | #define ITER_MAX 13
4 | #define TIME_SCALE 6
5 | #define ZOOM 4
6 | //#define CUSTOM_EXPONENT vec2(-2., 0.)
7 |
8 |
9 |
10 | // conversions between cartesian (x+yi) and polar (xe^(iy)) forms of complex numbers
11 | vec2 cartesian_of_polar(vec2 polar) {
12 | return vec2(polar.x * cos(polar.y), polar.x * sin(polar.y));
13 | }
14 |
15 | vec2 polar_of_cartesian(vec2 cartesian) {
16 | return vec2(length(cartesian), atan(cartesian.y, cartesian.x));
17 | }
18 |
19 | // multiplication of two complex numbers in cartesian form
20 | vec2 cmul(vec2 a, vec2 b) {
21 | return vec2(a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x);
22 | }
23 |
24 | // exponential of a complex number by a complex number, both in cartesian form
25 | vec2 cexp(vec2 b, vec2 e) {
26 | vec2 b_polar = polar_of_cartesian(b);
27 | vec2 logb = vec2(log(b_polar.x), b_polar.y);
28 | vec2 new_e = cmul(logb, e);
29 | vec2 ans_polar = vec2(exp(new_e.x), new_e.y);
30 | return cartesian_of_polar(ans_polar);
31 | }
32 |
33 | // cexp, specialized to e = vec2(-2., 0.)
34 | vec2 cexp_m2(vec2 b) {
35 | vec2 b_invmag = b / vec2(dot(b, b));
36 | return vec2((b_invmag.x*b_invmag.x - b_invmag.y*b_invmag.y), -2.*b_invmag.x*b_invmag.y);
37 | }
38 |
39 | void mainImage(out vec4 fragColor, in vec2 fragCoord)
40 | {
41 | // Normalized pixel coordinates (from -ZOOM to ZOOM)
42 | vec2 uv = vec2(2. * float(ZOOM)) * (fragCoord - iResolution.xy/vec2(2.)) / vec2(max(iResolution.x, iResolution.y));
43 |
44 | // Animate the constant c
45 | float t = iTime/float(TIME_SCALE);
46 | vec2 c = (vec2(cos(t)*abs(cos(t)), sin(t)*abs(sin(t)))) * vec2(0.7665);
47 |
48 | // Computation of the Julia set defined by the iteration x -> x^-2 + c
49 | vec2 x = uv;
50 | int iter = 0;
51 | for (iter = 0; iter < ITER_MAX; ++iter) {
52 |
53 | if (dot(x, x) > 40.) break;
54 | #ifdef CUSTOM_EXPONENT
55 | x = cexp(x, CUSTOM_EXPONENT);
56 | #else
57 | x = cexp_m2(x);
58 | #endif
59 | x += c;
60 | }
61 | vec3 col = vec3(float(iter) / float(ITER_MAX)) * vec3(c, 1.0);
62 |
63 | // Output to screen
64 | fragColor = vec4(col,1.0);
65 | }
66 |
--------------------------------------------------------------------------------
/shadertoy/assets/wrapper.frag:
--------------------------------------------------------------------------------
1 | #version 450
2 |
3 | layout(set = 0, binding = 0) uniform InputData
4 | {
5 | vec3 iResolution; // viewport resolution (in pixels)
6 | float iTime; // shader playback time (in seconds)
7 | float iTimeDelta; // render time (in seconds)
8 | int iFrame; // shader playback frame
9 | vec4 iMouse; // mouse pixel coords. xy: current (if MLB down), zw: click
10 | vec4 iDate; // (year, month, day, time in seconds)
11 | float iSampleRate; // sound sample rate (i.e., 44100)
12 | };
13 |
14 | layout(set = 0, binding = 1) uniform sampler2D iChannel0;
15 |
16 | layout (location = 0) in vec2 fragCoord;
17 | layout (location = 0) out vec4 fragColor;
18 |
19 | void mainImage(out vec4 fragColor, in vec2 fragCoord);
20 |
21 | void main()
22 | {
23 | mainImage(fragColor, fragCoord);
24 | }
25 |
26 |
--------------------------------------------------------------------------------
/shadertoy/compiler.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * spvm-shadertoy
3 | * @author : keith@robot9.me
4 | *
5 | */
6 |
7 | #include "compiler.h"
8 | #include "glslang/Include/glslang_c_interface.h"
9 | #include "glslang/Public/ShaderLang.h"
10 | #include "resourcelimits.h"
11 | #include "logger.h"
12 |
13 | namespace SPVM {
14 | namespace ShaderToy {
15 |
16 | static std::vector compileShaderInternal(glslang_stage_t stage, const char *shaderSource) {
17 | const glslang_input_t input = {
18 | .language = GLSLANG_SOURCE_GLSL,
19 | .stage = stage,
20 | .client = GLSLANG_CLIENT_VULKAN,
21 | .client_version = GLSLANG_TARGET_VULKAN_1_2,
22 | .target_language = GLSLANG_TARGET_SPV,
23 | .target_language_version = GLSLANG_TARGET_SPV_1_5,
24 | .code = shaderSource,
25 | .default_version = 100,
26 | .default_profile = GLSLANG_NO_PROFILE,
27 | .force_default_version_and_profile = false,
28 | .forward_compatible = false,
29 | .messages = GLSLANG_MSG_DEFAULT_BIT,
30 | .resource = reinterpret_cast(&glslang::DefaultTBuiltInResource),
31 | };
32 |
33 | glslang_shader_t *shader = glslang_shader_create(&input);
34 |
35 | if (!glslang_shader_preprocess(shader, &input)) {
36 | LOGE("GLSL preprocessing failed:");
37 | LOGE("%s", glslang_shader_get_info_log(shader));
38 | LOGE("%s", glslang_shader_get_info_debug_log(shader));
39 | LOGE("%s", input.code);
40 | glslang_shader_delete(shader);
41 | return std::vector();
42 | }
43 |
44 | if (!glslang_shader_parse(shader, &input)) {
45 | LOGE("GLSL parsing failed:");
46 | LOGE("%s", glslang_shader_get_info_log(shader));
47 | LOGE("%s", glslang_shader_get_info_debug_log(shader));
48 | LOGE("%s", glslang_shader_get_preprocessed_code(shader));
49 | glslang_shader_delete(shader);
50 | return std::vector();
51 | }
52 |
53 | glslang_program_t *program = glslang_program_create();
54 | glslang_program_add_shader(program, shader);
55 |
56 | if (!glslang_program_link(program, GLSLANG_MSG_SPV_RULES_BIT | GLSLANG_MSG_VULKAN_RULES_BIT)) {
57 | LOGE("GLSL linking failed:");
58 | LOGE("%s", glslang_program_get_info_log(program));
59 | LOGE("%s", glslang_program_get_info_debug_log(program));
60 | glslang_program_delete(program);
61 | glslang_shader_delete(shader);
62 | return std::vector();
63 | }
64 |
65 | glslang_program_SPIRV_generate(program, stage);
66 |
67 | std::vector outShaderModule(glslang_program_SPIRV_get_size(program));
68 | glslang_program_SPIRV_get(program, outShaderModule.data());
69 |
70 | const char *spirv_messages = glslang_program_SPIRV_get_messages(program);
71 | if (spirv_messages) {
72 | LOGI("GLSLang: %s", spirv_messages);
73 | }
74 |
75 | glslang_program_delete(program);
76 | glslang_shader_delete(shader);
77 |
78 | return outShaderModule;
79 | }
80 |
81 | std::vector Compiler::compileShaderFragment(const char *shaderSource) {
82 | glslang::InitializeProcess();
83 | auto ret = compileShaderInternal(GLSLANG_STAGE_FRAGMENT, shaderSource);
84 | glslang::FinalizeProcess();
85 | return ret;
86 | }
87 |
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/shadertoy/compiler.h:
--------------------------------------------------------------------------------
1 | /*
2 | * spvm-shadertoy
3 | * @author : keith@robot9.me
4 | *
5 | */
6 |
7 | #pragma once
8 |
9 | #include
10 | #include
11 |
12 | namespace SPVM {
13 | namespace ShaderToy {
14 |
15 | class Compiler {
16 | public:
17 | static std::vector compileShaderFragment(const char *shaderSource);
18 |
19 | };
20 |
21 | }
22 | }
--------------------------------------------------------------------------------
/shadertoy/renderer.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * spvm-shadertoy
3 | * @author : keith@robot9.me
4 | *
5 | */
6 |
7 | #include "renderer.h"
8 | #include "decoder.h"
9 | #include "compiler.h"
10 | #include "utils.h"
11 | #include "logger.h"
12 |
13 | #define STB_IMAGE_IMPLEMENTATION
14 | #include
15 |
16 | #define HEAP_SIZE 512 * 1024
17 | #define PIXEL_CONVERT(val) 255 * fClamp(val, 0.f, 1.f)
18 | #define PIXEL_ROW_PTR(row) (row) >= colorBuffer_->height ? nullptr : &colorBuffer_->data[(row) * colorBuffer_->width * 4]
19 |
20 | const char *IMAGE_0_PATH = "assets/images/awesomeface.png";
21 | #define SOUND_SAMPLE_RATE 44100
22 |
23 | namespace SPVM {
24 | namespace ShaderToy {
25 |
26 | Renderer::Renderer() : colorBuffer_(nullptr) {}
27 |
28 | Renderer::~Renderer() {
29 | destroy();
30 | }
31 |
32 | bool Renderer::create(void *window, int width, int height) {
33 | colorBuffer_ = new Buffer2D();
34 | colorBuffer_->data = nullptr;
35 | createBuffer(width, height);
36 |
37 | // init uniform
38 | uniformInput_.iResolution.x = (float) colorBuffer_->width;
39 | uniformInput_.iResolution.y = (float) colorBuffer_->height;
40 | uniformInput_.iResolution.z = 0;
41 | uniformInput_.iSampleRate = SOUND_SAMPLE_RATE;
42 | updateUniformDate(uniformInput_.iDate);
43 |
44 | int iw = 0, ih = 0, n = 0;
45 | stbi_set_flip_vertically_on_load(true);
46 | unsigned char *pixelBytes = stbi_load(IMAGE_0_PATH, &iw, &ih, &n, STBI_default);
47 | if (pixelBytes != nullptr && n > 0) {
48 | // image
49 | SPVM::SpvmImageInfo imageInfo;
50 | imageInfo.dim = SpvDim2D;
51 | imageInfo.format = SPVM_FORMAT_UNDEFINED;
52 | imageInfo.width = iw;
53 | imageInfo.height = ih;
54 | imageInfo.depth = 1;
55 | imageInfo.mipmaps = true;
56 | imageInfo.baseMipLevel = 0;
57 | imageInfo.mipLevels = 5;
58 | imageInfo.arrayed = false;
59 | imageInfo.baseArrayLayer = 0;
60 | imageInfo.arrayLayers = 1;
61 | imageInfo.samples = 1;
62 | switch (n) {
63 | case 1:
64 | imageInfo.format = SPVM_FORMAT_R8_UNORM;
65 | break;
66 | case 2:
67 | imageInfo.format = SPVM_FORMAT_R8G8_UNORM;
68 | break;
69 | case 3:
70 | imageInfo.format = SPVM_FORMAT_R8G8B8_UNORM;
71 | break;
72 | case 4:
73 | imageInfo.format = SPVM_FORMAT_R8G8B8A8_UNORM;
74 | break;
75 | default:
76 | break;
77 | }
78 |
79 | iChannel0Image_ = SPVM::createImage(&imageInfo);
80 | SPVM::uploadImageData(iChannel0Image_, pixelBytes, iw * ih * n, iw, ih, 1);
81 | stbi_image_free(pixelBytes);
82 |
83 | // mipmaps
84 | generateMipmaps(iChannel0Image_, SpvSamplerFilterModeLinear);
85 |
86 | // sampler
87 | iChannel0Sampler_ = SPVM::createSampler();
88 | iChannel0Sampler_->info.minFilter = SpvSamplerFilterModeLinear;
89 | iChannel0Sampler_->info.magFilter = SpvSamplerFilterModeLinear;
90 | iChannel0Sampler_->info.mipmapMode = SpvSamplerFilterModeLinear;
91 |
92 | // sampledImage
93 | iChannel0SampledImage_ = SPVM::createSampledImage(iChannel0Image_, iChannel0Sampler_);
94 | }
95 |
96 | // load shader
97 | settings_.loadShaderCallback_ = [&](const std::string &shaderPath) {
98 | reloadShader(shaderPath.c_str());
99 | };
100 | shaderWrapperStr_ = readFileString(settings_.shaderWrapperPath_.c_str());
101 | if (shaderWrapperStr_.empty()) {
102 | LOGE("error read shader wrapper file: %s", settings_.shaderWrapperPath_.c_str());
103 | return false;
104 | }
105 |
106 | return reloadShader(settings_.getShaderPath().c_str());
107 | }
108 |
109 | bool Renderer::reloadShader(const char *shaderPath) {
110 | LOGI("start load shader: %s", shaderPath);
111 | std::string shaderStr = readFileString(shaderPath);
112 | if (shaderStr.empty()) {
113 | LOGE("error read shader file: %s", shaderPath);
114 | return false;
115 | }
116 |
117 | shaderStr = shaderWrapperStr_ + shaderStr;
118 | spvBytes_ = Compiler::compileShaderFragment(shaderStr.c_str());
119 | if (spvBytes_.empty()) {
120 | LOGE("error compile shader file to spir-v");
121 | return false;
122 | }
123 |
124 | // decode spv file
125 | delete module_;
126 | module_ = new SpvmModule();
127 | bool success = SPVM::Decoder::decodeBytes((const SpvmByte *) (spvBytes_.data()),
128 | spvBytes_.size() * sizeof(uint32_t),
129 | module_);
130 | if (!success) {
131 | LOGE("decode spv file failed");
132 | return false;
133 | }
134 |
135 | // init runtime
136 | runtimes_.clear();
137 | runtimes_.resize(threadPool_.getThreadCnt());
138 | for (auto &rt : runtimes_) {
139 | success = rt.initWithModule(module_, HEAP_SIZE);
140 | if (!success) {
141 | LOGE("init spvm runtime failed");
142 | return false;
143 | }
144 |
145 | if (iChannel0SampledImage_) {
146 | rt.writeUniformBinding(iChannel0SampledImage_, 0, 1, 0);
147 | }
148 | }
149 |
150 | lastFrameTime_ = 0.f;
151 | frameIdx_ = 0;
152 | timer_.start();
153 |
154 | LOGI("load shader success, derivative instructions found: %s.", module_->hasDerivativeOpcodes ? "true" : "false");
155 | return true;
156 | }
157 |
158 | void Renderer::drawFrame() {
159 | if (colorBuffer_ == nullptr || module_ == nullptr) {
160 | LOGE("drawFrame error: not inited");
161 | return;
162 | }
163 |
164 | // update uniform
165 | uniformInput_.iTime = (float) timer_.elapse() / 1000.f;
166 | uniformInput_.iTimeDelta = uniformInput_.iTime - lastFrameTime_;
167 | lastFrameTime_ = uniformInput_.iTime;
168 | frameIdx_++;
169 | uniformInput_.iFrame = frameIdx_;
170 |
171 | for (auto &rt : runtimes_) {
172 | rt.writeUniformBinding(&uniformInput_, 0, 0);
173 | }
174 |
175 | // fragment shading
176 | float blockSize = (float) rasterBlockSize_;
177 | int blockCntY = (int) (((float) colorBuffer_->height + blockSize - 1.f) / blockSize);
178 | int blockCntX = (int) (((float) colorBuffer_->width + blockSize - 1.f) / blockSize);
179 |
180 | for (int blockY = 0; blockY < blockCntY; blockY++) {
181 | for (int blockX = 0; blockX < blockCntX; blockX++) {
182 | threadPool_.pushTask([&, blockX, blockY](int threadId) {
183 | execBlockShadingSingle(threadId, blockX, blockY, (int) blockSize);
184 | });
185 | }
186 | }
187 |
188 | threadPool_.waitTasksFinish();
189 | }
190 |
191 | void Renderer::execBlockShadingSingle(int threadId, int blockX, int blockY, int blockSize) {
192 | Runtime &rt = runtimes_[threadId];
193 | float fragCoord[2];
194 | float fragColor[4];
195 |
196 | int blockStartX = blockX * blockSize;
197 | int blockStartY = blockY * blockSize;
198 |
199 | for (size_t y = blockStartY; y < blockStartY + blockSize && y < colorBuffer_->height; y++) {
200 | uint8_t *rowPtr = PIXEL_ROW_PTR(y);
201 | for (size_t x = blockStartX; x < blockStartX + blockSize && x < colorBuffer_->width; x++) {
202 | fragCoord[0] = (float) x;
203 | fragCoord[1] = (float) y;
204 |
205 | rt.writeInput(fragCoord, 0);
206 | rt.execEntryPoint();
207 | rt.readOutput(fragColor, 0);
208 |
209 | pixelColorCvt(rowPtr, x, colorBuffer_->width, fragColor);
210 | }
211 | }
212 | }
213 |
214 | void Renderer::pixelColorCvt(uint8_t *rowPtr, size_t x, size_t width, float fragColor[4]) {
215 | if (rowPtr == nullptr || x >= width) {
216 | return;
217 | }
218 |
219 | uint8_t *pixel = &rowPtr[x * 4];
220 | pixel[0] = PIXEL_CONVERT(fragColor[0]);
221 | pixel[1] = PIXEL_CONVERT(fragColor[1]);
222 | pixel[2] = PIXEL_CONVERT(fragColor[2]);
223 | pixel[3] = PIXEL_CONVERT(fragColor[3]);
224 | }
225 |
226 | void Renderer::updateSize(int width, int height) {
227 | if (colorBuffer_) {
228 | createBuffer(width, height);
229 | uniformInput_.iResolution.x = (float) colorBuffer_->width;
230 | uniformInput_.iResolution.y = (float) colorBuffer_->height;
231 | }
232 | }
233 |
234 | void Renderer::createBuffer(int width, int height) {
235 | colorBuffer_->width = width;
236 | colorBuffer_->height = height;
237 | if (colorBuffer_->data) {
238 | delete[] colorBuffer_->data;
239 | }
240 | colorBuffer_->data = new uint8_t[width * height * 4];
241 | }
242 |
243 | void Renderer::destroyBuffer() {
244 | if (colorBuffer_) {
245 | delete[] colorBuffer_->data;
246 | delete colorBuffer_;
247 | colorBuffer_ = nullptr;
248 | }
249 | }
250 |
251 | void Renderer::destroy() {
252 | destroyBuffer();
253 | if (module_) {
254 | delete module_;
255 | module_ = nullptr;
256 | }
257 | }
258 |
259 | std::string Renderer::readFileString(const char *path) {
260 | std::string retStr;
261 | FILE *file = fopen(path, "rb");
262 | if (!file) {
263 | LOGE("error open file");
264 | return retStr;
265 | }
266 |
267 | fseek(file, 0, SEEK_END);
268 | size_t fileLength = ftell(file);
269 | if (fileLength <= 0) {
270 | LOGE("error get file size");
271 | fclose(file);
272 | return retStr;
273 | }
274 |
275 | char *buffer = new char[fileLength + 1];
276 | rewind(file);
277 | fread(buffer, 1, fileLength, file);
278 | buffer[fileLength] = '\0';
279 | retStr = buffer;
280 | fclose(file);
281 | delete[] buffer;
282 |
283 | return retStr;
284 | }
285 |
286 | void Renderer::updateUniformDate(vec4 &date) {
287 | std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
288 | time_t tt = std::chrono::system_clock::to_time_t(now);
289 | tm localTime = *localtime(&tt);
290 |
291 | date.x = (float) (localTime.tm_year + 1900);
292 | date.y = (float) (localTime.tm_mon + 1);
293 | date.z = (float) (localTime.tm_mday);
294 | date.w = (float) (localTime.tm_hour * 3600 + localTime.tm_min * 60 + localTime.tm_sec);
295 | }
296 |
297 | }
298 | }
299 |
--------------------------------------------------------------------------------
/shadertoy/renderer.h:
--------------------------------------------------------------------------------
1 | /*
2 | * spvm-shadertoy
3 | * @author : keith@robot9.me
4 | *
5 | */
6 |
7 | #pragma once
8 |
9 | #include
10 | #include "module.h"
11 | #include "runtime.h"
12 | #include "image.h"
13 | #include "timer.h"
14 | #include "settings.h"
15 | #include "threadpool.h"
16 |
17 | namespace SPVM {
18 | namespace ShaderToy {
19 |
20 | typedef struct Buffer2D_ {
21 | size_t width;
22 | size_t height;
23 | uint8_t *data;
24 | } Buffer2D;
25 |
26 | typedef struct vec3_ {
27 | float x;
28 | float y;
29 | float z;
30 | } vec3;
31 |
32 | typedef struct vec4_ {
33 | float x;
34 | float y;
35 | float z;
36 | float w;
37 | } vec4;
38 |
39 | typedef struct UniformInput_ {
40 | vec3 iResolution; // viewport resolution (in pixels)
41 | float iTime; // shader playback time (in seconds)
42 | float iTimeDelta; // render time (in seconds)
43 | int iFrame; // shader playback frame
44 | vec4 iMouse; // mouse pixel coords. xy: current (if MLB down), zw: click
45 | vec4 iDate; // (year, month, day, time in seconds)
46 | float iSampleRate; // sound sample rate (i.e., 44100)
47 | } UniformInput;
48 |
49 | class Renderer {
50 | public:
51 | Renderer();
52 | ~Renderer();
53 | bool create(void *window, int width, int height);
54 | bool reloadShader(const char *shaderPath);
55 | void drawFrame();
56 | void updateSize(int width, int height);
57 | void destroy();
58 |
59 | inline Buffer2D *getFrame() {
60 | return colorBuffer_;
61 | }
62 |
63 | inline Settings &getSettings() {
64 | return settings_;
65 | }
66 |
67 | private:
68 | void createBuffer(int width, int height);
69 | void destroyBuffer();
70 |
71 | static std::string readFileString(const char *path);
72 | inline void execBlockShadingSingle(int threadId, int blockX, int blockY, int blockSize);
73 | static inline void pixelColorCvt(uint8_t *rowPtr, size_t x, size_t width, float fragColor[4]);
74 |
75 | static void updateUniformDate(vec4 &date);
76 |
77 | private:
78 | Settings settings_;
79 | int rasterBlockSize_ = 32;
80 | ThreadPool threadPool_;
81 |
82 | SpvmModule *module_ = nullptr;
83 | std::vector runtimes_;
84 |
85 | std::string shaderWrapperStr_;
86 | std::vector spvBytes_;
87 | Buffer2D *colorBuffer_ = nullptr;
88 |
89 | UniformInput uniformInput_;
90 | Timer timer_;
91 | float lastFrameTime_ = 0.f;
92 | int frameIdx_ = 0;
93 |
94 | SpvmImage *iChannel0Image_ = nullptr;
95 | SpvmSampler *iChannel0Sampler_ = nullptr;
96 | SpvmSampledImage *iChannel0SampledImage_ = nullptr;
97 | };
98 |
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/shadertoy/resourcelimits.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (C) 2016 Google, Inc.
3 | //
4 | // All rights reserved.
5 | //
6 | // Redistribution and use in source and binary forms, with or without
7 | // modification, are permitted provided that the following conditions
8 | // are met:
9 | //
10 | // Redistributions of source code must retain the above copyright
11 | // notice, this list of conditions and the following disclaimer.
12 | //
13 | // Redistributions in binary form must reproduce the above
14 | // copyright notice, this list of conditions and the following
15 | // disclaimer in the documentation and/or other materials provided
16 | // with the distribution.
17 | //
18 | // Neither the name of Google Inc. nor the names of its
19 | // contributors may be used to endorse or promote products derived
20 | // from this software without specific prior written permission.
21 | //
22 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 | // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 | // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 | // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 | // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32 | // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 | // POSSIBILITY OF SUCH DAMAGE.
34 |
35 | #ifndef _STAND_ALONE_RESOURCE_LIMITS_INCLUDED_
36 | #define _STAND_ALONE_RESOURCE_LIMITS_INCLUDED_
37 |
38 | #include
39 |
40 | #include "glslang/Include/ResourceLimits.h"
41 |
42 | namespace glslang {
43 |
44 | // These are the default resources for TBuiltInResources, used for both
45 | // - parsing this string for the case where the user didn't supply one,
46 | // - dumping out a template for user construction of a config file.
47 | extern const TBuiltInResource DefaultTBuiltInResource;
48 |
49 | // Returns the DefaultTBuiltInResource as a human-readable string.
50 | std::string GetDefaultTBuiltInResourceString();
51 |
52 | // Decodes the resource limits from |config| to |resources|.
53 | void DecodeResourceLimits(TBuiltInResource* resources, char* config);
54 |
55 | } // end namespace glslang
56 |
57 | #endif // _STAND_ALONE_RESOURCE_LIMITS_INCLUDED_
58 |
--------------------------------------------------------------------------------
/shadertoy/settingpanel.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * spvm-shadertoy
3 | * @author : keith@robot9.me
4 | *
5 | */
6 |
7 | #include "settingpanel.h"
8 | #include "imgui/imgui_impl_glfw.h"
9 | #include "imgui/imgui_impl_opengl3.h"
10 |
11 | namespace SPVM {
12 | namespace ShaderToy {
13 |
14 | void SettingPanel::init(void *window, int width, int height) {
15 | frameWidth_ = width;
16 | frameHeight_ = height;
17 |
18 | // Setup Dear ImGui context
19 | IMGUI_CHECKVERSION();
20 | ImGui::CreateContext();
21 | ImGuiIO &io = ImGui::GetIO();
22 | io.IniFilename = nullptr;
23 |
24 | // Setup Dear ImGui style
25 | ImGui::StyleColorsDark();
26 | ImGuiStyle *style = &ImGui::GetStyle();
27 | style->Alpha = 0.8f;
28 |
29 | // Setup Platform/Renderer backends
30 | ImGui_ImplGlfw_InitForOpenGL((GLFWwindow *) window, true);
31 | ImGui_ImplOpenGL3_Init("#version 150");
32 | }
33 |
34 | void SettingPanel::onDraw() {
35 | if (!visible) {
36 | return;
37 | }
38 |
39 | // Start the Dear ImGui frame
40 | ImGui_ImplOpenGL3_NewFrame();
41 | ImGui_ImplGlfw_NewFrame();
42 | ImGui::NewFrame();
43 |
44 | // Settings window
45 | ImGui::Begin("Settings", nullptr,
46 | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize
47 | | ImGuiWindowFlags_AlwaysAutoResize);
48 | drawSettings();
49 | ImGui::SetWindowPos(ImVec2(frameWidth_ - ImGui::GetWindowWidth(), 0));
50 | ImGui::End();
51 |
52 | ImGui::Render();
53 | ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
54 | }
55 |
56 | void SettingPanel::drawSettings() {
57 | // fps
58 | ImGui::Separator();
59 | ImGui::Text("fps: %.01f", ImGui::GetIO().Framerate);
60 | ImGui::Text("frame: %.02f ms", 1000.0f / ImGui::GetIO().Framerate);
61 |
62 | // shader
63 | ImGui::Separator();
64 | ImGui::Text("load shader");
65 | for (const auto &kv : settings_.shaderPaths_) {
66 | if (ImGui::RadioButton(kv.first.c_str(), settings_.shaderPathKey_ == kv.first)) {
67 | settings_.shaderPathKey_ = kv.first;
68 | if (settings_.loadShaderCallback_) {
69 | settings_.loadShaderCallback_(settings_.getShaderPath());
70 | }
71 | }
72 | }
73 | }
74 |
75 | void SettingPanel::destroy() {
76 | ImGui_ImplOpenGL3_Shutdown();
77 | ImGui_ImplGlfw_Shutdown();
78 | ImGui::DestroyContext();
79 | }
80 |
81 | void SettingPanel::updateSize(int width, int height) {
82 | frameWidth_ = width;
83 | frameHeight_ = height;
84 | }
85 |
86 | void SettingPanel::toggleShowState() {
87 | visible = !visible;
88 | }
89 |
90 | bool SettingPanel::wantCaptureKeyboard() {
91 | ImGuiIO &io = ImGui::GetIO();
92 | return io.WantCaptureKeyboard;
93 | }
94 |
95 | bool SettingPanel::wantCaptureMouse() {
96 | ImGuiIO &io = ImGui::GetIO();
97 | return io.WantCaptureMouse;
98 | }
99 |
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/shadertoy/settingpanel.h:
--------------------------------------------------------------------------------
1 | /*
2 | * spvm-shadertoy
3 | * @author : keith@robot9.me
4 | *
5 | */
6 |
7 | #pragma once
8 |
9 | #include "imgui/imgui.h"
10 | #include "settings.h"
11 |
12 | namespace SPVM {
13 | namespace ShaderToy {
14 |
15 | class SettingPanel {
16 | public:
17 | explicit SettingPanel(Settings &settings) : settings_(settings) {}
18 |
19 | void init(void *window, int width, int height);
20 | void onDraw();
21 | void destroy();
22 | void updateSize(int width, int height);
23 | void toggleShowState();
24 |
25 | bool wantCaptureKeyboard();
26 | bool wantCaptureMouse();
27 |
28 | private:
29 | void drawSettings();
30 |
31 | private:
32 | Settings &settings_;
33 |
34 | bool visible = true;
35 | int frameWidth_ = 0;
36 | int frameHeight_ = 0;
37 | };
38 |
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/shadertoy/settings.h:
--------------------------------------------------------------------------------
1 | /*
2 | * spvm-shadertoy
3 | * @author : keith@robot9.me
4 | *
5 | */
6 |
7 | #pragma once
8 |
9 | #include
10 | #include
11 | #include
12 | #include
13 |
14 | namespace SPVM {
15 | namespace ShaderToy {
16 |
17 | const std::string ASSETS_DIR = "assets/shaders/";
18 | const std::string SHADER_WRAPPER_PATH = "assets/wrapper.frag";
19 |
20 | class Settings {
21 | public:
22 | Settings() {
23 | shaderPaths_["basic"] = ASSETS_DIR + "basic.frag";
24 | shaderPaths_["fstyD4"] = ASSETS_DIR + "fstyD4.frag";
25 | shaderPaths_["ftdfWn"] = ASSETS_DIR + "ftdfWn.frag";
26 | shaderPaths_["Nt3BzM"] = ASSETS_DIR + "Nt3BzM.frag";
27 | shaderPaths_["XdlSDs"] = ASSETS_DIR + "XdlSDs.frag";
28 |
29 | shaderPathKey_ = shaderPaths_.begin()->first;
30 | }
31 |
32 | inline std::string getShaderPath() {
33 | auto it = shaderPaths_.find(shaderPathKey_);
34 | return it == shaderPaths_.end() ? "" : it->second;
35 | }
36 |
37 | public:
38 | std::string shaderWrapperPath_ = SHADER_WRAPPER_PATH;
39 | std::function loadShaderCallback_;
40 |
41 | std::string shaderPathKey_;
42 | std::unordered_map shaderPaths_;
43 | };
44 |
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/shadertoy/third_party/glfw/lib-macos-universal/libglfw.3.dylib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keith2018/spvm/a232ea822562dde8d9de47be458a3777392d98bb/shadertoy/third_party/glfw/lib-macos-universal/libglfw.3.dylib
--------------------------------------------------------------------------------
/shadertoy/third_party/glfw/lib-macos-universal/libglfw3.a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keith2018/spvm/a232ea822562dde8d9de47be458a3777392d98bb/shadertoy/third_party/glfw/lib-macos-universal/libglfw3.a
--------------------------------------------------------------------------------
/shadertoy/third_party/glfw/lib-mingw-w64/glfw3.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keith2018/spvm/a232ea822562dde8d9de47be458a3777392d98bb/shadertoy/third_party/glfw/lib-mingw-w64/glfw3.dll
--------------------------------------------------------------------------------
/shadertoy/third_party/glfw/lib-mingw-w64/libglfw3.a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keith2018/spvm/a232ea822562dde8d9de47be458a3777392d98bb/shadertoy/third_party/glfw/lib-mingw-w64/libglfw3.a
--------------------------------------------------------------------------------
/shadertoy/third_party/glfw/lib-mingw-w64/libglfw3dll.a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keith2018/spvm/a232ea822562dde8d9de47be458a3777392d98bb/shadertoy/third_party/glfw/lib-mingw-w64/libglfw3dll.a
--------------------------------------------------------------------------------
/shadertoy/third_party/glfw/lib-vc2022/glfw3.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keith2018/spvm/a232ea822562dde8d9de47be458a3777392d98bb/shadertoy/third_party/glfw/lib-vc2022/glfw3.dll
--------------------------------------------------------------------------------
/shadertoy/third_party/glfw/lib-vc2022/glfw3.lib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keith2018/spvm/a232ea822562dde8d9de47be458a3777392d98bb/shadertoy/third_party/glfw/lib-vc2022/glfw3.lib
--------------------------------------------------------------------------------
/shadertoy/third_party/glfw/lib-vc2022/glfw3_mt.lib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keith2018/spvm/a232ea822562dde8d9de47be458a3777392d98bb/shadertoy/third_party/glfw/lib-vc2022/glfw3_mt.lib
--------------------------------------------------------------------------------
/shadertoy/third_party/glfw/lib-vc2022/glfw3dll.lib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keith2018/spvm/a232ea822562dde8d9de47be458a3777392d98bb/shadertoy/third_party/glfw/lib-vc2022/glfw3dll.lib
--------------------------------------------------------------------------------
/shadertoy/third_party/imgui/imgui/imgui_impl_glfw.h:
--------------------------------------------------------------------------------
1 | // dear imgui: Platform Backend for GLFW
2 | // This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan, WebGPU..)
3 | // (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)
4 |
5 | // Implemented features:
6 | // [X] Platform: Clipboard support.
7 | // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLFW_KEY_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
8 | // [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
9 | // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+).
10 |
11 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
12 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
13 | // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
14 | // Read online: https://github.com/ocornut/imgui/tree/master/docs
15 |
16 | // About GLSL version:
17 | // The 'glsl_version' initialization parameter defaults to "#version 150" if NULL.
18 | // Only override if your GL version doesn't handle this GLSL version. Keep NULL if unsure!
19 |
20 | #pragma once
21 | #include "imgui.h" // IMGUI_IMPL_API
22 |
23 | struct GLFWwindow;
24 | struct GLFWmonitor;
25 |
26 | IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks);
27 | IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks);
28 | IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window, bool install_callbacks);
29 | IMGUI_IMPL_API void ImGui_ImplGlfw_Shutdown();
30 | IMGUI_IMPL_API void ImGui_ImplGlfw_NewFrame();
31 |
32 | // GLFW callbacks
33 | // - When calling Init with 'install_callbacks=true': GLFW callbacks will be installed for you. They will call user's previously installed callbacks, if any.
34 | // - When calling Init with 'install_callbacks=false': GLFW callbacks won't be installed. You will need to call those function yourself from your own GLFW callbacks.
35 | IMGUI_IMPL_API void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused); // Since 1.84
36 | IMGUI_IMPL_API void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered); // Since 1.84
37 | IMGUI_IMPL_API void ImGui_ImplGlfw_CursorPosCallback(GLFWwindow* window, double x, double y); // Since 1.87
38 | IMGUI_IMPL_API void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods);
39 | IMGUI_IMPL_API void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset);
40 | IMGUI_IMPL_API void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
41 | IMGUI_IMPL_API void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c);
42 | IMGUI_IMPL_API void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor* monitor, int event);
43 |
--------------------------------------------------------------------------------
/shadertoy/third_party/imgui/imgui/imgui_impl_opengl3.h:
--------------------------------------------------------------------------------
1 | // dear imgui: Renderer Backend for modern OpenGL with shaders / programmatic pipeline
2 | // - Desktop GL: 2.x 3.x 4.x
3 | // - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0)
4 | // This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
5 |
6 | // Implemented features:
7 | // [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!
8 | // [x] Renderer: Desktop GL only: Support for large meshes (64k+ vertices) with 16-bit indices.
9 |
10 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
11 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
12 | // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
13 | // Read online: https://github.com/ocornut/imgui/tree/master/docs
14 |
15 | // About GLSL version:
16 | // The 'glsl_version' initialization parameter should be NULL (default) or a "#version XXX" string.
17 | // On computer platform the GLSL version default to "#version 130". On OpenGL ES 3 platform it defaults to "#version 300 es"
18 | // Only override if your GL version doesn't handle this GLSL version. See GLSL version table at the top of imgui_impl_opengl3.cpp.
19 |
20 | #pragma once
21 | #include "imgui.h" // IMGUI_IMPL_API
22 |
23 | // Backend API
24 | IMGUI_IMPL_API bool ImGui_ImplOpenGL3_Init(const char* glsl_version = NULL);
25 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_Shutdown();
26 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_NewFrame();
27 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data);
28 |
29 | // (Optional) Called by Init/NewFrame/Shutdown
30 | IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateFontsTexture();
31 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyFontsTexture();
32 | IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateDeviceObjects();
33 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyDeviceObjects();
34 |
35 | // Specific OpenGL ES versions
36 | //#define IMGUI_IMPL_OPENGL_ES2 // Auto-detected on Emscripten
37 | //#define IMGUI_IMPL_OPENGL_ES3 // Auto-detected on iOS/Android
38 |
39 | // You can explicitly select GLES2 or GLES3 API by using one of the '#define IMGUI_IMPL_OPENGL_LOADER_XXX' in imconfig.h or compiler command-line.
40 | #if !defined(IMGUI_IMPL_OPENGL_ES2) \
41 | && !defined(IMGUI_IMPL_OPENGL_ES3)
42 |
43 | // Try to detect GLES on matching platforms
44 | #if defined(__APPLE__)
45 | #include
46 | #endif
47 | #if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV)) || (defined(__ANDROID__))
48 | #define IMGUI_IMPL_OPENGL_ES3 // iOS, Android -> GL ES 3, "#version 300 es"
49 | #elif defined(__EMSCRIPTEN__)
50 | #define IMGUI_IMPL_OPENGL_ES2 // Emscripten -> GL ES 2, "#version 100"
51 | #else
52 | // Otherwise imgui_impl_opengl3_loader.h will be used.
53 | #endif
54 |
55 | #endif
56 |
--------------------------------------------------------------------------------
/shadertoy/threadpool.h:
--------------------------------------------------------------------------------
1 | /*
2 | * spvm-shadertoy
3 | * @author : keith@robot9.me
4 | *
5 | */
6 |
7 | #pragma once
8 |
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 |
17 | namespace SPVM {
18 | namespace ShaderToy {
19 |
20 | class ThreadPool {
21 | public:
22 |
23 | explicit ThreadPool(const size_t threadCnt = std::thread::hardware_concurrency())
24 | : threadCnt_(threadCnt),
25 | threads_(new std::thread[threadCnt_]) {
26 | createThreads();
27 | }
28 |
29 | ~ThreadPool() {
30 | waitTasksFinish();
31 | running_ = false;
32 | joinThreads();
33 | }
34 |
35 | size_t getThreadCnt() const {
36 | return threadCnt_;
37 | }
38 |
39 | size_t getTasksCnt() const {
40 | return tasksCnt_;
41 | }
42 |
43 | template
44 | void pushTask(const F &task) {
45 | tasksCnt_++;
46 | {
47 | const std::lock_guard lock(mutex_);
48 | tasks_.push(std::function(task));
49 | }
50 | }
51 |
52 | template
53 | void pushTask(const F &task, const A &...args) {
54 | pushTask([task, args...] { task(args...); });
55 | }
56 |
57 | void waitTasksFinish() const {
58 | while (true) {
59 | if (!paused) {
60 | if (tasksCnt_ == 0)
61 | break;
62 | } else {
63 | if (tasksRunningCnt() == 0)
64 | break;
65 | }
66 | std::this_thread::yield();
67 | }
68 | }
69 |
70 | std::atomic paused{false};
71 |
72 | private:
73 | void createThreads() {
74 | for (size_t i = 0; i < threadCnt_; i++) {
75 | threads_[i] = std::thread(&ThreadPool::taskWorker, this, i);
76 | }
77 | }
78 |
79 | void joinThreads() {
80 | for (size_t i = 0; i < threadCnt_; i++) {
81 | threads_[i].join();
82 | }
83 | }
84 |
85 | size_t tasksQueuedCnt() const {
86 | const std::lock_guard lock(mutex_);
87 | return tasks_.size();
88 | }
89 |
90 | size_t tasksRunningCnt() const {
91 | return tasksCnt_ - tasksQueuedCnt();
92 | }
93 |
94 | bool popTask(std::function &task) {
95 | const std::lock_guard lock(mutex_);
96 | if (tasks_.empty())
97 | return false;
98 | else {
99 | task = std::move(tasks_.front());
100 | tasks_.pop();
101 | return true;
102 | }
103 | }
104 |
105 | void taskWorker(size_t threadId) {
106 | while (running_) {
107 | std::function task;
108 | if (!paused && popTask(task)) {
109 | task(threadId);
110 | tasksCnt_--;
111 | } else {
112 | std::this_thread::yield();
113 | }
114 | }
115 | }
116 |
117 | private:
118 | mutable std::mutex mutex_ = {};
119 | std::atomic running_{true};
120 |
121 | size_t threadCnt_;
122 | std::unique_ptr threads_;
123 |
124 | std::queue> tasks_ = {};
125 | std::atomic tasksCnt_{0};
126 | };
127 |
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/shadertoy/timer.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * spvm-shadertoy
3 | * @author : keith@robot9.me
4 | *
5 | */
6 |
7 | #include "timer.h"
8 |
9 | namespace SPVM {
10 | namespace ShaderToy {
11 |
12 | void Timer::start() {
13 | start_ = std::chrono::steady_clock::now();
14 | }
15 |
16 | int64_t Timer::elapse() const {
17 | auto end = std::chrono::steady_clock::now();
18 | auto duration = std::chrono::duration_cast(end - start_);
19 | return duration.count();
20 | }
21 |
22 | }
23 | }
--------------------------------------------------------------------------------
/shadertoy/timer.h:
--------------------------------------------------------------------------------
1 | /*
2 | * spvm-shadertoy
3 | * @author : keith@robot9.me
4 | *
5 | */
6 |
7 | #pragma once
8 |
9 | #include
10 | #include
11 |
12 | namespace SPVM {
13 | namespace ShaderToy {
14 |
15 | class Timer {
16 | public:
17 | Timer() = default;
18 |
19 | ~Timer() = default;
20 |
21 | void start();
22 |
23 | int64_t elapse() const;
24 |
25 | private:
26 | std::chrono::time_point start_;
27 | };
28 |
29 | class ScopedTimer {
30 | public:
31 |
32 | explicit ScopedTimer(const char *str)
33 | : tag_(str) {
34 | timer_.start();
35 | }
36 |
37 | ~ScopedTimer() {
38 | printf("%s: %lld ms\n", tag_.c_str(), timer_.elapse());
39 | }
40 |
41 | explicit operator bool() {
42 | return true;
43 | }
44 |
45 | private:
46 | Timer timer_;
47 | std::string tag_;
48 | };
49 |
50 | #ifndef NDEBUG
51 | # define TIMED(X) if(SoftGL::ScopedTimer _ScopedTimer = (X))
52 | #else
53 | # define TIMED(X)
54 | #endif
55 |
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.3)
2 | project(spvm_lib)
3 |
4 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3")
5 |
6 | if (CMAKE_BUILD_TYPE STREQUAL Debug)
7 | add_definitions(-DDEBUG)
8 | endif ()
9 |
10 | aux_source_directory(. SPVM_SRCS)
11 | add_library(${PROJECT_NAME} ${SPVM_SRCS})
12 |
13 | target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR})
14 |
--------------------------------------------------------------------------------
/src/decoder.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * spvm
3 | * @author : keith@robot9.me
4 | *
5 | */
6 |
7 | #include "decoder.h"
8 | #include
9 |
10 | #include "spvm.h"
11 | #include "logger.h"
12 |
13 | namespace SPVM {
14 |
15 | typedef enum {
16 | I32_ENDIAN_UNKNOWN,
17 | I32_ENDIAN_LITTLE = 0x03020100ul,
18 | I32_ENDIAN_BIG = 0x00010203ul,
19 | } I32_ENDIAN;
20 |
21 | static const union {
22 | unsigned char bytes[4];
23 | SpvmU32 value;
24 | } o32_host_order = {{0, 1, 2, 3}};
25 |
26 | #define I32_ENDIAN_HOST (o32_host_order.value)
27 |
28 | bool Decoder::checkEndian(const SpvmWord *ptr) {
29 | uint8_t bytes[4];
30 | memcpy(bytes, ptr, sizeof(SpvmU32));
31 |
32 | I32_ENDIAN endian = I32_ENDIAN_UNKNOWN;
33 | if (0x03 == bytes[0] && 0x02 == bytes[1] && 0x23 == bytes[2] && 0x07 == bytes[3]) {
34 | endian = I32_ENDIAN_LITTLE;
35 | }
36 |
37 | if (0x07 == bytes[0] && 0x23 == bytes[1] && 0x02 == bytes[2] && 0x03 == bytes[3]) {
38 | endian = I32_ENDIAN_BIG;
39 | }
40 |
41 | return I32_ENDIAN_HOST == endian;
42 | }
43 |
44 | bool Decoder::decodeFile(const char *path, SpvmModule *module) {
45 | if (path == nullptr) {
46 | LOGE("invalid file path");
47 | return false;
48 | }
49 |
50 | FILE *file = fopen(path, "rb");
51 | if (!file) {
52 | LOGE("error open file");
53 | return false;
54 | }
55 |
56 | fseek(file, 0, SEEK_END);
57 | SpvmWord fileLength = ftell(file);
58 | if (fileLength <= 0) {
59 | LOGE("error get file size");
60 | fclose(file);
61 | return false;
62 | }
63 |
64 | module->buffer = new SpvmByte[fileLength];
65 | rewind(file);
66 | fread(module->buffer, 1, fileLength, file);
67 | fclose(file);
68 |
69 | return decodeBytes(module->buffer, fileLength, module);
70 | }
71 |
72 | bool Decoder::decodeBytes(const SpvmByte *bytes, SpvmWord length, SpvmModule *module) {
73 | auto *ptr = (SpvmWord *) bytes;
74 |
75 | // check endian by magic number
76 | if (!checkEndian(ptr++)) {
77 | LOGE("binary endian not support");
78 | return false;
79 | }
80 |
81 | SpvmWord version = *ptr++;
82 | module->versionMajor = (version & 0x00FF0000) >> 16;
83 | module->versionMinor = (version & 0x0000FF00) >> 8;
84 |
85 | module->generatorMagic = *ptr++;
86 | module->bound = *ptr++;
87 | module->instructionSchema = *ptr++;
88 |
89 | module->code = ptr;
90 | module->codeSize = length - 5 * sizeof(SpvmWord);
91 |
92 | module->hasDerivativeOpcodes = false;
93 | module->inited = false;
94 |
95 | // check derivative opcodes
96 | while ((ptr - module->code) * sizeof(SpvmWord) < module->codeSize) {
97 | SpvmOpcode insOp = readOpcode(ptr);
98 | if (checkDerivativeOpcodes(insOp)) {
99 | module->hasDerivativeOpcodes = true;
100 | break;
101 | }
102 | ptr += insOp.wordCount;
103 | }
104 |
105 | if (module->hasDerivativeOpcodes) {
106 | LOGE("Derivative opcodes not support");
107 | return false;
108 | }
109 |
110 | return true;
111 | }
112 |
113 | bool Decoder::checkDerivativeOpcodes(SpvmOpcode opcode) {
114 | if (opcode.op == SpvOpDPdx || opcode.op == SpvOpDPdy || opcode.op == SpvOpFwidth
115 | || opcode.op == SpvOpDPdxFine || opcode.op == SpvOpDPdyFine || opcode.op == SpvOpFwidthFine
116 | || opcode.op == SpvOpDPdxCoarse || opcode.op == SpvOpDPdyCoarse || opcode.op == SpvOpFwidthCoarse) {
117 | return true;
118 | }
119 | return false;
120 | }
121 |
122 | }
--------------------------------------------------------------------------------
/src/decoder.h:
--------------------------------------------------------------------------------
1 | /*
2 | * spvm
3 | * @author : keith@robot9.me
4 | *
5 | */
6 |
7 | #pragma once
8 |
9 | #include
10 | #include "spvm.h"
11 | #include "module.h"
12 |
13 | namespace SPVM {
14 |
15 | class Decoder {
16 | public:
17 | static bool decodeFile(const char *path, SpvmModule *module);
18 | static bool decodeBytes(const SpvmByte *bytes, SpvmWord length, SpvmModule *module);
19 |
20 | private:
21 | static bool checkEndian(const SpvmWord *ptr);
22 | static bool checkDerivativeOpcodes(SpvmOpcode opcode);
23 | };
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/ext/GLSL.std.450.h:
--------------------------------------------------------------------------------
1 | /*
2 | ** Copyright (c) 2014-2016 The Khronos Group Inc.
3 | **
4 | ** Permission is hereby granted, free of charge, to any person obtaining a copy
5 | ** of this software and/or associated documentation files (the "Materials"),
6 | ** to deal in the Materials without restriction, including without limitation
7 | ** the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 | ** and/or sell copies of the Materials, and to permit persons to whom the
9 | ** Materials are furnished to do so, subject to the following conditions:
10 | **
11 | ** The above copyright notice and this permission notice shall be included in
12 | ** all copies or substantial portions of the Materials.
13 | **
14 | ** MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS
15 | ** STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND
16 | ** HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/
17 | **
18 | ** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 | ** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 | ** THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 | ** FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS
24 | ** IN THE MATERIALS.
25 | */
26 |
27 | #ifndef GLSLstd450_H
28 | #define GLSLstd450_H
29 |
30 | static const int GLSLstd450Version = 100;
31 | static const int GLSLstd450Revision = 3;
32 |
33 | enum GLSLstd450 {
34 | GLSLstd450Bad = 0, // Don't use
35 |
36 | GLSLstd450Round = 1,
37 | GLSLstd450RoundEven = 2,
38 | GLSLstd450Trunc = 3,
39 | GLSLstd450FAbs = 4,
40 | GLSLstd450SAbs = 5,
41 | GLSLstd450FSign = 6,
42 | GLSLstd450SSign = 7,
43 | GLSLstd450Floor = 8,
44 | GLSLstd450Ceil = 9,
45 | GLSLstd450Fract = 10,
46 |
47 | GLSLstd450Radians = 11,
48 | GLSLstd450Degrees = 12,
49 | GLSLstd450Sin = 13,
50 | GLSLstd450Cos = 14,
51 | GLSLstd450Tan = 15,
52 | GLSLstd450Asin = 16,
53 | GLSLstd450Acos = 17,
54 | GLSLstd450Atan = 18,
55 | GLSLstd450Sinh = 19,
56 | GLSLstd450Cosh = 20,
57 | GLSLstd450Tanh = 21,
58 | GLSLstd450Asinh = 22,
59 | GLSLstd450Acosh = 23,
60 | GLSLstd450Atanh = 24,
61 | GLSLstd450Atan2 = 25,
62 |
63 | GLSLstd450Pow = 26,
64 | GLSLstd450Exp = 27,
65 | GLSLstd450Log = 28,
66 | GLSLstd450Exp2 = 29,
67 | GLSLstd450Log2 = 30,
68 | GLSLstd450Sqrt = 31,
69 | GLSLstd450InverseSqrt = 32,
70 |
71 | GLSLstd450Determinant = 33,
72 | GLSLstd450MatrixInverse = 34,
73 |
74 | GLSLstd450Modf = 35, // second operand needs an OpVariable to write to
75 | GLSLstd450ModfStruct = 36, // no OpVariable operand
76 | GLSLstd450FMin = 37,
77 | GLSLstd450UMin = 38,
78 | GLSLstd450SMin = 39,
79 | GLSLstd450FMax = 40,
80 | GLSLstd450UMax = 41,
81 | GLSLstd450SMax = 42,
82 | GLSLstd450FClamp = 43,
83 | GLSLstd450UClamp = 44,
84 | GLSLstd450SClamp = 45,
85 | GLSLstd450FMix = 46,
86 | GLSLstd450IMix = 47, // Reserved
87 | GLSLstd450Step = 48,
88 | GLSLstd450SmoothStep = 49,
89 |
90 | GLSLstd450Fma = 50,
91 | GLSLstd450Frexp = 51, // second operand needs an OpVariable to write to
92 | GLSLstd450FrexpStruct = 52, // no OpVariable operand
93 | GLSLstd450Ldexp = 53,
94 |
95 | GLSLstd450PackSnorm4x8 = 54,
96 | GLSLstd450PackUnorm4x8 = 55,
97 | GLSLstd450PackSnorm2x16 = 56,
98 | GLSLstd450PackUnorm2x16 = 57,
99 | GLSLstd450PackHalf2x16 = 58,
100 | GLSLstd450PackDouble2x32 = 59,
101 | GLSLstd450UnpackSnorm2x16 = 60,
102 | GLSLstd450UnpackUnorm2x16 = 61,
103 | GLSLstd450UnpackHalf2x16 = 62,
104 | GLSLstd450UnpackSnorm4x8 = 63,
105 | GLSLstd450UnpackUnorm4x8 = 64,
106 | GLSLstd450UnpackDouble2x32 = 65,
107 |
108 | GLSLstd450Length = 66,
109 | GLSLstd450Distance = 67,
110 | GLSLstd450Cross = 68,
111 | GLSLstd450Normalize = 69,
112 | GLSLstd450FaceForward = 70,
113 | GLSLstd450Reflect = 71,
114 | GLSLstd450Refract = 72,
115 |
116 | GLSLstd450FindILsb = 73,
117 | GLSLstd450FindSMsb = 74,
118 | GLSLstd450FindUMsb = 75,
119 |
120 | GLSLstd450InterpolateAtCentroid = 76,
121 | GLSLstd450InterpolateAtSample = 77,
122 | GLSLstd450InterpolateAtOffset = 78,
123 |
124 | GLSLstd450NMin = 79,
125 | GLSLstd450NMax = 80,
126 | GLSLstd450NClamp = 81,
127 |
128 | GLSLstd450Count
129 | };
130 |
131 | #endif // #ifndef GLSLstd450_H
--------------------------------------------------------------------------------
/src/image.h:
--------------------------------------------------------------------------------
1 | /*
2 | * spvm
3 | * @author : keith@robot9.me
4 | *
5 | */
6 |
7 | #pragma once
8 |
9 | #include "spvm.h"
10 |
11 | namespace SPVM {
12 |
13 | #define kMaxSamplerLodBias 64.f
14 | #define kMaxSamplerLod 64.f
15 |
16 | typedef enum SpvmFormat_ {
17 | SPVM_FORMAT_UNDEFINED = 0,
18 | SPVM_FORMAT_R8_UNORM = 9,
19 | SPVM_FORMAT_R8G8_UNORM = 16,
20 | SPVM_FORMAT_R8G8B8_UNORM = 23,
21 | SPVM_FORMAT_R8G8B8A8_UNORM = 37,
22 | } SpvmFormat;
23 |
24 | typedef enum SpvmBorderColor_ {
25 | SPVM_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK = 0,
26 | SPVM_BORDER_COLOR_INT_TRANSPARENT_BLACK = 1,
27 | SPVM_BORDER_COLOR_FLOAT_OPAQUE_BLACK = 2,
28 | SPVM_BORDER_COLOR_INT_OPAQUE_BLACK = 3,
29 | SPVM_BORDER_COLOR_FLOAT_OPAQUE_WHITE = 4,
30 | SPVM_BORDER_COLOR_INT_OPAQUE_WHITE = 5,
31 | } SpvmBorderColor;
32 |
33 | typedef enum SpvmCompareOp_ {
34 | SPVM_COMPARE_OP_NEVER = 0,
35 | SPVM_COMPARE_OP_LESS = 1,
36 | SPVM_COMPARE_OP_EQUAL = 2,
37 | SPVM_COMPARE_OP_LESS_OR_EQUAL = 3,
38 | SPVM_COMPARE_OP_GREATER = 4,
39 | SPVM_COMPARE_OP_NOT_EQUAL = 5,
40 | SPVM_COMPARE_OP_GREATER_OR_EQUAL = 6,
41 | SPVM_COMPARE_OP_ALWAYS = 7,
42 | } SpvmCompareOp;
43 |
44 | typedef struct SpvmImageInfo_ {
45 | SpvDim dim;
46 | SpvmFormat format;
47 | SpvmWord width;
48 | SpvmWord height;
49 | SpvmWord depth;
50 | SpvmBool mipmaps;
51 | SpvmWord baseMipLevel;
52 | SpvmWord mipLevels;
53 | SpvmBool arrayed;
54 | SpvmWord baseArrayLayer;
55 | SpvmWord arrayLayers;
56 | SpvmWord samples;
57 | } SpvmImageInfo;
58 |
59 | typedef struct SpvmSamplerInfo_ {
60 | SpvSamplerFilterMode magFilter;
61 | SpvSamplerFilterMode minFilter;
62 | SpvSamplerFilterMode mipmapMode;
63 | SpvSamplerAddressingMode addressModeU;
64 | SpvSamplerAddressingMode addressModeV;
65 | SpvSamplerAddressingMode addressModeW;
66 | SpvmF32 mipLodBias;
67 | SpvmBool compareEnable;
68 | SpvmCompareOp compareOp;
69 | SpvmF32 minLod;
70 | SpvmF32 maxLod;
71 | SpvmBorderColor borderColor;
72 | SpvmBool unnormalizedCoordinates;
73 | } SpvmSamplerInfo;
74 |
75 | typedef struct SpvmSampler_ {
76 | SpvmSamplerInfo info;
77 | } SpvmSampler;
78 |
79 | typedef struct SpvmImageLevel_ {
80 | SpvmWord level;
81 | SpvmWord width;
82 | SpvmWord height;
83 | SpvmWord depth;
84 | SpvmWord dataSize;
85 | SpvmByte *data;
86 | } SpvmImageLevel;
87 |
88 | typedef struct SpvmImageLayer_ {
89 | SpvmWord layer;
90 | SpvmWord width;
91 | SpvmWord height;
92 | SpvmWord depth;
93 | SpvmWord levelCount;
94 | SpvmImageLevel *levels;
95 | } SpvmImageLayer;
96 |
97 | typedef struct SpvmImage_ {
98 | SpvmImageInfo info;
99 | SpvmWord layerCount;
100 | SpvmImageLayer *layers;
101 | } SpvmImage;
102 |
103 | typedef struct SpvmSampledImage_ {
104 | SpvmImage *image;
105 | SpvmSampler *sampler;
106 | } SpvmSampledImage;
107 |
108 | SpvmImage *createImage(SpvmImageInfo *imageInfo);
109 | SpvmSampler *createSampler(SpvmSamplerInfo *samplerInfo = nullptr);
110 | SpvmSampler *createSamplerConstant(SpvmSamplerAttribute *attribute);
111 | SpvmSampledImage *createSampledImage(SpvmImage *image, SpvmSampler *sampler);
112 |
113 | bool uploadImageData(SpvmImage *image, SpvmByte *dataPtr, SpvmWord dataSize,
114 | SpvmWord width, SpvmWord height, SpvmWord depth = 1,
115 | SpvmWord mipLevel = 0, SpvmWord arrayLayer = 0);
116 |
117 | void generateMipmaps(SpvmImage *image, SpvSamplerFilterMode filterMode);
118 | void generateMipmaps(SpvmSampledImage *sampledImage);
119 |
120 | void destroyImage(SpvmImage *image);
121 | void destroySampler(SpvmSampler *sampler);
122 | void destroySampledImager(SpvmSampledImage *sampledImage);
123 |
124 | bool checkImageType(SpvmImage *image, SpvmTypeImage *type);
125 |
126 | void sampleImage(void *ctx,
127 | SpvmValue *retValue,
128 | SpvmValue *sampledImageValue,
129 | SpvmValue *coordinateValue,
130 | SpvmWord coordinateId,
131 | SpvmImageOperands *operands,
132 | SpvmValue *depthCompValue = nullptr,
133 | bool proj = false);
134 |
135 | void fetchImage(void *ctx,
136 | SpvmValue *retValue,
137 | SpvmValue *imageValue,
138 | SpvmValue *coordinateValue,
139 | SpvmWord coordinateId,
140 | SpvmImageOperands *operands);
141 |
142 | void queryImageFormat(void *ctx, SpvmValue *retValue, SpvmValue *imageValue);
143 | void queryImageOrder(void *ctx, SpvmValue *retValue, SpvmValue *imageValue);
144 | void queryImageSizeLod(void *ctx, SpvmValue *retValue, SpvmValue *imageValue, SpvmValue *lodValue);
145 | void queryImageSize(void *ctx, SpvmValue *retValue, SpvmValue *imageValue);
146 | void queryImageLod(void *ctx,
147 | SpvmValue *retValue,
148 | SpvmValue *sampledImageValue,
149 | SpvmValue *coordinateValue,
150 | SpvmWord coordinateId);
151 | void queryImageLevels(void *ctx, SpvmValue *retValue, SpvmValue *imageValue);
152 | void queryImageSamples(void *ctx, SpvmValue *retValue, SpvmValue *imageValue);
153 |
154 | }
--------------------------------------------------------------------------------
/src/interface.h:
--------------------------------------------------------------------------------
1 | /*
2 | * spvm
3 | * @author : keith@robot9.me
4 | *
5 | */
6 |
7 | #pragma once
8 |
9 | #include
10 | #include
11 |
12 | #include "spvm.h"
13 |
14 | namespace SPVM {
15 |
16 | struct RuntimeContext;
17 |
18 | typedef struct SpvmUniformBinding_ {
19 | SpvmWord set;
20 | SpvmWord binding;
21 |
22 | bool operator==(const struct SpvmUniformBinding_ &o) const {
23 | return o.set == set && o.binding == binding;
24 | }
25 | } SpvmUniformBinding;
26 |
27 | struct SpvmUniformBindingHash {
28 | SpvmWord operator()(const SpvmUniformBinding &o) const {
29 | return (std::hash()(o.set)) ^ (std::hash()(o.binding));
30 | }
31 | };
32 |
33 | class Interface {
34 | public:
35 | void init(RuntimeContext *ctx);
36 |
37 | SpvmWord getLocationByName(const char *name);
38 | SpvmUniformBinding getBindingByName(const char *name);
39 |
40 | void writeInput(void *data, SpvmWord location);
41 | void writeInputBuiltIn(void *data, SpvBuiltIn builtIn);
42 | void writeUniformBinding(void *data, SpvmWord length, SpvmWord binding, SpvmWord set = 0);
43 | void writeUniformPushConstants(void *data, SpvmWord length);
44 |
45 | void readOutput(void *data, SpvmWord location);
46 | void readOutputBuiltIn(void *data, SpvBuiltIn builtIn);
47 |
48 | private:
49 | void checkDecorations(SpvmPointer *pointer, SpvmWord pointerId, std::vector &decorations);
50 | void *writeValue(SpvmValue *value, void *data, SpvmWord length);
51 | void *readValue(SpvmValue *value, void *data);
52 |
53 | private:
54 | RuntimeContext *runtimeCtx_;
55 |
56 | std::unordered_map inputLocation_; //
57 | std::unordered_map outputLocation_; //
58 | std::unordered_map inoutBuiltIn_; //
59 | std::unordered_map bindings_; //
60 | SpvmValue *pushConstants_ = nullptr;
61 |
62 | std::unordered_map locationMap_; //
63 | std::unordered_map bindingMap_; //
64 | };
65 |
66 | }
--------------------------------------------------------------------------------
/src/logger.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * spvm
3 | * @author : keith@robot9.me
4 | *
5 | */
6 |
7 | #include "logger.h"
8 |
9 | namespace SPVM {
10 |
11 | void *Logger::logContext_ = nullptr;
12 | LogFunc Logger::logFunc_ = nullptr;
13 |
14 | #if DEBUG
15 | LogLevel Logger::minLevel_ = LOG_INFO;
16 | #else
17 | LogLevel Logger::minLevel_ = LOG_WARNING;
18 | #endif
19 |
20 | char Logger::buf_[MAX_LOG_LENGTH] = {};
21 |
22 | void Logger::setLogFunc(void *ctx, LogFunc func) {
23 | logContext_ = ctx;
24 | logFunc_ = func;
25 | }
26 |
27 | void Logger::setLogLevel(LogLevel level) {
28 | minLevel_ = level;
29 | }
30 |
31 | void Logger::log(LogLevel level, const char *file, int line, const char *message, ...) {
32 | if (level < minLevel_) {
33 | return;
34 | }
35 |
36 | va_list argPtr;
37 | va_start(argPtr, message);
38 | vsnprintf(buf_, MAX_LOG_LENGTH - 1, message, argPtr);
39 | va_end(argPtr);
40 | buf_[MAX_LOG_LENGTH - 1] = '\0';
41 |
42 | if (logFunc_ != nullptr) {
43 | logFunc_(logContext_, level, buf_);
44 | return;
45 | }
46 |
47 | switch (level) {
48 | #ifdef LOG_SOURCE_LINE
49 | case LOG_INFO: fprintf(stdout, "[SPVM][INFO] %s:%d: %s\n", file, line, buf_); break;
50 | case LOG_DEBUG: fprintf(stdout, "[SPVM][DEBUG] %s:%d: %s\n", file, line, buf_); break;
51 | case LOG_WARNING: fprintf(stdout, "[SPVM][WARNING] %s:%d: %s\n", file, line, buf_); break;
52 | case LOG_ERROR: fprintf(stdout, "[SPVM][ERROR] %s:%d: %s\n", file, line, buf_); break;
53 | #else
54 | case LOG_INFO: fprintf(stdout, "[SPVM][INFO] : %s\n", buf_); break;
55 | case LOG_DEBUG: fprintf(stdout, "[SPVM][DEBUG] : %s\n", buf_); break;
56 | case LOG_WARNING: fprintf(stdout, "[SPVM][WARNING] : %s\n", buf_); break;
57 | case LOG_ERROR: fprintf(stdout, "[SPVM][ERROR] : %s\n", buf_); break;
58 | #endif
59 | }
60 | fflush(stdout);
61 | }
62 |
63 | }
--------------------------------------------------------------------------------
/src/logger.h:
--------------------------------------------------------------------------------
1 | /*
2 | * spvm
3 | * @author : keith@robot9.me
4 | *
5 | */
6 |
7 | #pragma once
8 |
9 | #include
10 | #include
11 | #include
12 |
13 | namespace SPVM {
14 |
15 | #define LOG_SOURCE_LINE
16 |
17 | #define SPVM_FILENAME (strrchr(__FILE__, '/') ? (strrchr(__FILE__, '/') + 1) : __FILE__)
18 |
19 | #define LOGI(...) SPVM::Logger::log(SPVM::LOG_INFO, SPVM_FILENAME, __LINE__, __VA_ARGS__)
20 | #define LOGD(...) SPVM::Logger::log(SPVM::LOG_DEBUG, SPVM_FILENAME, __LINE__, __VA_ARGS__)
21 | #define LOGW(...) SPVM::Logger::log(SPVM::LOG_WARNING, SPVM_FILENAME, __LINE__, __VA_ARGS__)
22 | #define LOGE(...) SPVM::Logger::log(SPVM::LOG_ERROR, SPVM_FILENAME, __LINE__, __VA_ARGS__)
23 |
24 | static constexpr int MAX_LOG_LENGTH = 1024;
25 |
26 | typedef void (*LogFunc)(void *context, int level, const char *msg);
27 |
28 | enum LogLevel {
29 | LOG_INFO,
30 | LOG_DEBUG,
31 | LOG_WARNING,
32 | LOG_ERROR,
33 | };
34 |
35 | class Logger {
36 | public:
37 | static void setLogFunc(void *ctx, LogFunc func);
38 | static void setLogLevel(LogLevel level);
39 | static void log(LogLevel level, const char *file, int line, const char *message, ...);
40 |
41 | private:
42 | static void *logContext_;
43 | static LogFunc logFunc_;
44 | static LogLevel minLevel_;
45 |
46 | static char buf_[MAX_LOG_LENGTH];
47 | };
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/src/module.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * spvm
3 | * @author : keith@robot9.me
4 | *
5 | */
6 |
7 | #include "module.h"
8 |
9 | namespace SPVM {
10 |
11 | SpvmModule::SpvmModule() : buffer(nullptr) {}
12 |
13 | SpvmModule::~SpvmModule() {
14 | if (buffer) {
15 | delete[] buffer;
16 | buffer = nullptr;
17 | }
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/src/module.h:
--------------------------------------------------------------------------------
1 | /*
2 | * spvm
3 | * @author : keith@robot9.me
4 | *
5 | */
6 |
7 | #pragma once
8 |
9 | #include "spvm.h"
10 |
11 | #include
12 | #include
13 |
14 | namespace SPVM {
15 |
16 | class SpvmModule {
17 | public:
18 | SPVM::SpvmByte *buffer;
19 |
20 | SpvmByte versionMajor;
21 | SpvmByte versionMinor;
22 | SpvmWord generatorMagic;
23 | SpvmWord bound;
24 | SpvmWord instructionSchema;
25 |
26 | SpvmSource source;
27 | std::vector sourceExtensions;
28 | std::vector names;
29 |
30 | SpvmWord *code;
31 | SpvmWord codeSize; // bytes
32 |
33 | std::vector capabilities;
34 | std::vector extensions;
35 | SpvAddressingModel addressingModel;
36 | SpvMemoryModel memoryModel;
37 | std::vector entryPoints;
38 | std::vector executionModes;
39 |
40 | std::unordered_map> decorations;
41 | std::vector globalPointers;
42 |
43 | // whether the module contains derivative opcodes(OpDPdx, OpDPdy, ...)
44 | bool hasDerivativeOpcodes;
45 | bool inited;
46 | public:
47 | SpvmModule();
48 | ~SpvmModule();
49 | };
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/src/runtime.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * spvm
3 | * @author : keith@robot9.me
4 | *
5 | */
6 |
7 | #include "runtime.h"
8 | #include "opcodes.inc"
9 |
10 | namespace SPVM {
11 |
12 | Runtime::Runtime() : heapSize_(0), heap_(nullptr) {}
13 |
14 | Runtime::~Runtime() {
15 | if (heap_) {
16 | delete[] heap_;
17 | heap_ = nullptr;
18 | }
19 | }
20 |
21 | bool Runtime::initWithModule(SpvmModule *module, SpvmWord heapSize, SpvmByte *heap) {
22 | if (heapSize_ != 0) {
23 | LOGE("initWithModule already inited");
24 | return false;
25 | }
26 |
27 | if (heapSize <= 0) {
28 | LOGE("initWithModule error heapSize: %d", heapSize);
29 | return false;
30 | }
31 |
32 | heapSize_ = heapSize;
33 | SpvmByte *heapBase = heap;
34 | if (heapBase == nullptr) {
35 | heap_ = new SpvmByte[heapSize_];
36 | memset(heap_, 0, heapSize_ * sizeof(SpvmByte));
37 | heapBase = heap_;
38 | } else {
39 | heap_ = nullptr;
40 | }
41 |
42 | ctx_.module = module;
43 | ctx_.resultsInit = (void **) heapBase;
44 | ctx_.results = (void **) (heapBase + module->bound * sizeof(void *));
45 | ctx_.currFrame = nullptr;
46 |
47 | ctx_.pc = ctx_.module->code;
48 | ctx_.sp = (SpvmByte *) ctx_.results + module->bound * sizeof(void *);
49 |
50 | execRet_ = Result_NoError;
51 | bool success = execContinue();
52 | if (!success) {
53 | LOGE("initWithModule failed");
54 | return false;
55 | }
56 |
57 | // store init results status
58 | memcpy(ctx_.resultsInit, ctx_.results, module->bound * sizeof(void *));
59 |
60 | module->inited = true;
61 | interface_.init(&ctx_);
62 | return true;
63 | }
64 |
65 | bool Runtime::execEntryPoint(SpvmWord entryIdx) {
66 | bool success = execPrepare(entryIdx);
67 | if (!success) {
68 | LOGE("prepare exec failed");
69 | return false;
70 | }
71 |
72 | return execContinue();
73 | }
74 |
75 | bool Runtime::execPrepare(SpvmWord entryIdx) {
76 | if (ctx_.module->entryPoints.empty()) {
77 | LOGE("execPrepare error: no entry point defined");
78 | return false;
79 | }
80 |
81 | // load init results status
82 | memcpy(ctx_.results, ctx_.resultsInit, ctx_.module->bound * sizeof(void *));
83 |
84 | auto &entry = ctx_.module->entryPoints[entryIdx];
85 | auto *func = (SpvmFunction *) ctx_.results[entry.id];
86 | ctx_.sp = ctx_.stackBase;
87 | ctx_.pc = func->code;
88 |
89 | SpvmWord *pc = ctx_.pc;
90 | SpvmByte *sp = ctx_.sp;
91 |
92 | // create frame
93 | ctx_.currFrame = (SpvmFrame *) HEAP_MALLOC(sizeof(SpvmFrame));
94 | ctx_.currFrame->prevFrame = nullptr;
95 | ctx_.currFrame->paramsIdx = 0;
96 | ctx_.currFrame->params = nullptr;
97 | ctx_.currFrame->resultValue = nullptr;
98 | ctx_.currFrame->parentBlockId = 0;
99 | ctx_.currFrame->currBlockId = 0;
100 | ctx_.currFrame->pc = pc;
101 |
102 | // write back
103 | ctx_.pc = pc;
104 | ctx_.sp = sp;
105 |
106 | execRet_ = Result_NoError;
107 | return true;
108 | }
109 |
110 | bool Runtime::execContinue() {
111 | if (execRet_ == Result_ExecEnd) {
112 | return true;
113 | }
114 | RuntimeContext *ctx = &ctx_;
115 |
116 | SpvmWord *pc = ctx->pc;
117 | SpvmByte *sp = ctx->sp;
118 | SpvmOpcode opcode = READ_OPCODE();
119 | execRet_ = execOpCodes(pc, sp, opcode, ctx);
120 |
121 | return execRet_ != Result_Error;
122 | }
123 |
124 | }
125 |
--------------------------------------------------------------------------------
/src/runtime.h:
--------------------------------------------------------------------------------
1 | /*
2 | * spvm
3 | * @author : keith@robot9.me
4 | *
5 | */
6 |
7 | #pragma once
8 |
9 | #include "spvm.h"
10 | #include "module.h"
11 | #include "interface.h"
12 |
13 | namespace SPVM {
14 |
15 | typedef struct SpvmFrame {
16 | struct SpvmFrame *prevFrame;
17 | SpvmWord paramsIdx;
18 | void **params;
19 | SpvmValue *resultValue;
20 | SpvmWord parentBlockId;
21 | SpvmWord currBlockId;
22 | SpvmWord *pc;
23 | } SpvmFrame;
24 |
25 | class Runtime;
26 |
27 | typedef enum {
28 | Result_NoError = 0,
29 | Result_Unreachable,
30 | Result_Killed,
31 | Result_Error,
32 | Result_InitEnd,
33 | Result_ExecEnd,
34 | } RuntimeResult;
35 |
36 | typedef struct RuntimeContext {
37 | SpvmModule *module;
38 | void **resultsInit;
39 | void **results;
40 | SpvmByte *stackBase;
41 | SpvmFrame *currFrame;
42 | SpvmWord *pc;
43 | SpvmByte *sp;
44 | } RuntimeContext;
45 |
46 | class Runtime {
47 | public:
48 | Runtime();
49 | ~Runtime();
50 | bool initWithModule(SpvmModule *module, SpvmWord heapSize, SpvmByte *heap = nullptr);
51 | bool execEntryPoint(SpvmWord entryIdx = 0);
52 |
53 | bool execPrepare(SpvmWord entryIdx = 0);
54 | bool execContinue();
55 |
56 | inline SpvmWord getLocationByName(const char *name) {
57 | return interface_.getLocationByName(name);
58 | }
59 |
60 | inline SpvmUniformBinding getBindingByName(const char *name) {
61 | return interface_.getBindingByName(name);
62 | }
63 |
64 | inline void writeInput(void *data, SpvmWord location) {
65 | interface_.writeInput(data, location);
66 | }
67 | inline void writeInputBuiltIn(void *data, SpvBuiltIn builtIn) {
68 | interface_.writeInputBuiltIn(data, builtIn);
69 | }
70 | inline void writeUniformBinding(void *data, SpvmWord length, SpvmWord binding, SpvmWord set = 0) {
71 | interface_.writeUniformBinding(data, length, binding, set);
72 | }
73 | inline void writeUniformPushConstants(void *data, SpvmWord length) {
74 | interface_.writeUniformPushConstants(data, length);
75 | }
76 | inline void readOutput(void *data, SpvmWord location) {
77 | interface_.readOutput(data, location);
78 | }
79 | inline void readOutputBuiltIn(void *data, SpvBuiltIn builtIn) {
80 | interface_.readOutputBuiltIn(data, builtIn);
81 | }
82 |
83 | inline RuntimeContext &getRuntimeContext() {
84 | return ctx_;
85 | }
86 |
87 | private:
88 | RuntimeContext ctx_;
89 | Interface interface_;
90 | RuntimeResult execRet_;
91 | SpvmWord heapSize_;
92 | SpvmByte *heap_; // [resultIds-init][resultIds][types, global vars][frame0, frame0 vars][frame1, frame1 vars] ...
93 | };
94 |
95 | }
96 |
--------------------------------------------------------------------------------
/src/spvm.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * spvm
3 | * @author : keith@robot9.me
4 | *
5 | */
6 |
7 | #include "spvm.h"
8 | #include "opstrings.h"
9 | #include "logger.h"
10 |
11 | namespace SPVM {
12 |
13 | #ifndef HEAP_MALLOC
14 | #define HEAP_MALLOC(n) sp; sp += (n)
15 | #endif
16 |
17 | SpvmOpcode readOpcode(const SpvmWord *pc) {
18 | SpvmWord word = *pc;
19 |
20 | SpvmOpcode opcode;
21 | opcode.op = SpvOp(word & SpvOpCodeMask);
22 | opcode.wordCount = (word & (~SpvOpCodeMask)) >> SpvWordCountShift;
23 |
24 | // LOGD("read opcode: %s, size: %d", spvmOpString(opcode.op), opcode.wordCount);
25 | return opcode;
26 | }
27 |
28 | SpvmValue *createValue(SpvmTypeBase *type, SpvmByte **psp) {
29 | if (type->type == SpvOpTypeVoid) {
30 | return nullptr;
31 | }
32 | SpvmByte *sp = *psp;
33 | SpvmValue *ret = (SpvmValue *) HEAP_MALLOC(sizeof(SpvmValue));
34 | ret->type = type;
35 | ret->memberCnt = type->memberCnt;
36 | switch (type->type) {
37 | case SpvOpTypeBool:
38 | case SpvOpTypeInt:
39 | case SpvOpTypeFloat: {
40 | ret->value.members = nullptr;
41 | break;
42 | }
43 | case SpvOpTypeVector: {
44 | SpvmTypeVector *vecType = (SpvmTypeVector *) type;
45 | ret->value.members = (SpvmValue **) HEAP_MALLOC(ret->memberCnt * sizeof(SpvmValue *));
46 | for (SpvmWord i = 0; i < ret->memberCnt; i++) {
47 | ret->value.members[i] = createValue(vecType->componentType, &sp);
48 | }
49 | break;
50 | }
51 | case SpvOpTypeMatrix: {
52 | SpvmTypeMatrix *matType = (SpvmTypeMatrix *) type;
53 | ret->value.members = (SpvmValue **) HEAP_MALLOC(ret->memberCnt * sizeof(SpvmValue *));
54 | for (SpvmWord i = 0; i < ret->memberCnt; i++) {
55 | ret->value.members[i] = createValue(matType->columnType, &sp);
56 | }
57 | break;
58 | }
59 | case SpvOpTypeArray: {
60 | SpvmTypeArray *arrayType = (SpvmTypeArray *) type;
61 | ret->value.members = (SpvmValue **) HEAP_MALLOC(ret->memberCnt * sizeof(SpvmValue *));
62 | for (SpvmWord i = 0; i < ret->memberCnt; i++) {
63 | ret->value.members[i] = createValue(arrayType->elementType, &sp);
64 | }
65 | break;
66 | }
67 | case SpvOpTypeRuntimeArray: {
68 | SpvmTypeRuntimeArray *rtArrType = (SpvmTypeRuntimeArray *) type;
69 | if (rtArrType->memberCnt <= 0) {
70 | ret->value.members = nullptr;
71 | } else {
72 | ret->value.members = (SpvmValue **) HEAP_MALLOC(ret->memberCnt * sizeof(SpvmValue *));
73 | for (SpvmWord i = 0; i < ret->memberCnt; i++) {
74 | ret->value.members[i] = createValue(rtArrType->elementType, &sp);
75 | }
76 | }
77 | break;
78 | }
79 | case SpvOpTypeStruct: {
80 | SpvmTypeStruct *structType = (SpvmTypeStruct *) type;
81 | ret->value.members = (SpvmValue **) HEAP_MALLOC(ret->memberCnt * sizeof(SpvmValue *));
82 | for (SpvmWord i = 0; i < ret->memberCnt; i++) {
83 | ret->value.members[i] = createValue(structType->memberTypes[i], &sp);
84 | }
85 | break;
86 | }
87 | case SpvOpTypeImage: {
88 | SpvmTypeImage *imgType = (SpvmTypeImage *) type;
89 | ret->value.image = (SpvmImageInternal *) HEAP_MALLOC(sizeof(SpvmImageInternal));
90 | ret->value.image->type = imgType;
91 | ret->value.image->opaque = nullptr;
92 | break;
93 | }
94 | case SpvOpTypeSampler: {
95 | ret->value.sampler = (SpvmSamplerInternal *) HEAP_MALLOC(sizeof(SpvmSamplerInternal));
96 | ret->value.sampler->attributes = nullptr;
97 | ret->value.sampler->opaque = nullptr;
98 | break;
99 | }
100 | case SpvOpTypeSampledImage: {
101 | SpvmTypeSampledImage *sampledImgType = (SpvmTypeSampledImage *) type;
102 | ret->value.sampledImage = (SpvmSampledImageInternal *) HEAP_MALLOC(sizeof(SpvmSampledImageInternal));
103 | SpvmValue *imageVal = createValue(sampledImgType->imageType, &sp);
104 | ret->value.sampledImage->image = imageVal->value.image;
105 | ret->value.sampledImage->sampler = (SpvmSamplerInternal *) HEAP_MALLOC(sizeof(SpvmSamplerInternal));
106 | ret->value.sampledImage->sampler->attributes = nullptr;
107 | ret->value.sampledImage->sampler->opaque = nullptr;
108 | break;
109 | }
110 | default: {
111 | LOGE("createWithType not implement: %s", spvmOpString(type->type));
112 | break;
113 | }
114 | }
115 |
116 | *psp = sp;
117 | return ret;
118 | }
119 |
120 | SpvmWord getTypeSize(SpvmTypeBase *type) {
121 | switch (type->type) {
122 | case SpvOpTypeBool:
123 | return sizeof(SpvmBool);
124 | case SpvOpTypeInt: {
125 | SpvmTypeInt *intType = (SpvmTypeInt *) type;
126 | return intType->width / 8;
127 | }
128 | case SpvOpTypeFloat: {
129 | SpvmTypeFloat *floatType = (SpvmTypeFloat *) type;
130 | return floatType->width / 8;
131 | }
132 | case SpvOpTypeRuntimeArray: {
133 | SpvmTypeRuntimeArray *rtArrType = (SpvmTypeRuntimeArray *) type;
134 | return rtArrType->memberCnt * getTypeSize(rtArrType->elementType);
135 | }
136 | case SpvOpTypeVector: {
137 | SpvmTypeVector *vecType = (SpvmTypeVector *) type;
138 | return vecType->memberCnt * getTypeSize(vecType->componentType);
139 | }
140 | case SpvOpTypeMatrix: {
141 | SpvmTypeMatrix *matType = (SpvmTypeMatrix *) type;
142 | return matType->memberCnt * getTypeSize(matType->columnType);
143 | }
144 | case SpvOpTypeArray: {
145 | SpvmTypeArray *arrType = (SpvmTypeArray *) type;
146 | return arrType->memberCnt * getTypeSize(arrType->elementType);
147 | }
148 | case SpvOpTypeStruct: {
149 | SpvmTypeStruct *structType = (SpvmTypeStruct *) type;
150 | SpvmWord totalSize = 0;
151 | for (SpvmWord i = 0; i < structType->memberCnt; i++) {
152 | totalSize += getTypeSize(structType->memberTypes[i]);
153 | }
154 | return totalSize;
155 | }
156 | default:
157 | break;
158 | }
159 |
160 | return 0;
161 | }
162 |
163 | void copyValue(SpvmValue *dst, SpvmValue *src) {
164 | if (src->memberCnt > 0) {
165 | for (SpvmWord i = 0; i < src->memberCnt; i++) {
166 | copyValue(dst->value.members[i], src->value.members[i]);
167 | }
168 | } else {
169 | dst->value = src->value;
170 | }
171 | }
172 |
173 | SpvmValue *setValueF32(SpvmValue *ret, SpvmF32 val) {
174 | if (ret->memberCnt > 0) {
175 | for (SpvmWord i = 0; i < ret->memberCnt; i++) {
176 | ret->VECTOR_f32(i) = val;
177 | }
178 | } else {
179 | ret->value.f32 = val;
180 | }
181 |
182 | return ret;
183 | }
184 |
185 | void writeToValue(SpvmValue *retValue, SpvmVec4 vec) {
186 | if (retValue->memberCnt == 0) {
187 | retValue->value.i32 = vec.elem[0].i32;
188 | } else {
189 | for (SpvmWord i = 0; i < retValue->memberCnt && i < 4; i++) {
190 | retValue->value.members[i]->value.i32 = vec.elem[i].i32;
191 | }
192 | }
193 | }
194 |
195 | SpvmVec4 readFromValue(SpvmValue *value) {
196 | SpvmVec4 retVec{0, 0, 0, 0};
197 | if (value->memberCnt > 0) {
198 | for (SpvmWord i = 0; i < value->memberCnt && i < 3; i++) {
199 | retVec.elem[i].i32 = value->value.members[i]->value.i32;
200 | }
201 | } else {
202 | retVec.elem[0].i32 = value->value.i32;
203 | }
204 | return retVec;
205 | }
206 |
207 | void valueSubF32(SpvmValue *ret, SpvmValue *a, SpvmValue *b) {
208 | if (ret->memberCnt > 0) {
209 | for (SpvmWord i = 0; i < ret->memberCnt; i++) {
210 | ret->VECTOR_f32(i) = a->VECTOR_f32(i) - b->VECTOR_f32(i);
211 | }
212 | } else {
213 | ret->value.f32 = a->value.f32 - b->value.f32;
214 | }
215 | }
216 |
217 | }
--------------------------------------------------------------------------------
/src/spvm.h:
--------------------------------------------------------------------------------
1 | /*
2 | * spvm
3 | * @author : keith@robot9.me
4 | *
5 | */
6 |
7 | #pragma once
8 |
9 | #include
10 |
11 | #include "spirv.h"
12 |
13 | namespace SPVM {
14 |
15 | #define EXT_GLSLstd450 "GLSL.std.450"
16 |
17 | #define VECTOR_boolean(idx) value.members[(idx)]->value.boolean
18 | #define VECTOR_i32(idx) value.members[(idx)]->value.i32
19 | #define VECTOR_u32(idx) value.members[(idx)]->value.u32
20 | #define VECTOR_f32(idx) value.members[(idx)]->value.f32
21 | #define VECTOR_value(idx) value.members[(idx)]->value
22 |
23 | #define MATRIX_boolean(col, row) value.members[(col)]->value.members[(row)]->value.boolean
24 | #define MATRIX_i32(col, row) value.members[(col)]->value.members[(row)]->value.i32
25 | #define MATRIX_u32(col, row) value.members[(col)]->value.members[(row)]->value.u32
26 | #define MATRIX_f32(col, row) value.members[(col)]->value.members[(row)]->value.f32
27 | #define MATRIX_value(col, row) value.members[(col)]->value.members[(row)]->value
28 |
29 | typedef void SpvmVoid;
30 | typedef uint8_t SpvmByte;
31 | typedef uint32_t SpvmWord;
32 | typedef bool SpvmBool;
33 | typedef int8_t SpvmI8;
34 | typedef uint8_t SpvmU8;
35 | typedef int16_t SpvmI16;
36 | typedef uint16_t SpvmU16;
37 | typedef int32_t SpvmI32;
38 | typedef uint32_t SpvmU32;
39 | typedef int64_t SpvmI64;
40 | typedef uint64_t SpvmU64;
41 | typedef float SpvmF32;
42 | typedef double SpvmF64;
43 |
44 | #define SpvmTrue true
45 | #define SpvmFalse false
46 | #define SpvmResultIdInvalid 0
47 | #define SpvmNAN nan("")
48 |
49 | typedef struct SpvmString_ {
50 | SpvmWord wordCount;
51 | SpvmWord strLen;
52 | SpvmByte *str;
53 | } SpvmString;
54 |
55 | typedef struct SpvmOpcode_ {
56 | SpvOp op;
57 | SpvmWord wordCount;
58 | } SpvmOpcode;
59 |
60 | typedef struct SpvmDebugSource_ {
61 | SpvSourceLanguage language;
62 | SpvmWord languageVersion;
63 | } SpvmSource;
64 |
65 | typedef struct SpvmName_ {
66 | SpvmWord targetId;
67 | SpvmWord memberIdx;
68 | SpvmString name;
69 | } SpvmName;
70 |
71 | typedef struct SpvmExtension_ {
72 | SpvmString name;
73 | } SpvmExtension;
74 |
75 | typedef struct SpvmExtInstImport_ {
76 | SpvmWord setId;
77 | } SpvmExtInstImport;
78 |
79 | typedef struct SpvmEntryPoint_ {
80 | SpvExecutionModel executionModel;
81 | SpvmWord id;
82 | SpvmString name;
83 | SpvmWord globalIdCnt;
84 | SpvmWord *globalIds;
85 | } SpvmEntryPoint;
86 |
87 | typedef struct SpvmExecutionMode_ {
88 | SpvmWord entryPointId;
89 | SpvExecutionMode mode;
90 | } SpvmExecutionMode;
91 |
92 | typedef struct SpvmDecorationExtra_ {
93 | union {
94 | SpvmWord location;
95 | SpvBuiltIn builtIn;
96 | SpvmWord binding;
97 | SpvmWord descriptorSet;
98 | } value;
99 | } SpvmDecorationExtra;
100 |
101 | typedef struct SpvmDecoration_ {
102 | SpvmWord targetId;
103 | SpvmWord memberIdx;
104 | SpvDecoration decoration;
105 | SpvmDecorationExtra extra;
106 | } SpvmDecoration;
107 |
108 | typedef struct SpvmTypeBase_ {
109 | SpvOp type;
110 | SpvmWord memberCnt;
111 | SpvmWord resultId;
112 | } SpvmTypeBase;
113 |
114 | typedef struct SpvmTypeVoid_ : SpvmTypeBase {
115 | } SpvmTypeVoid;
116 |
117 | typedef struct SpvmTypeBool_ : SpvmTypeBase {
118 | } SpvmTypeBool;
119 |
120 | typedef struct SpvmTypeInt_ : SpvmTypeBase {
121 | SpvmWord width;
122 | SpvmByte signedness;
123 | } SpvmTypeInt;
124 |
125 | typedef struct SpvmTypeFloat_ : SpvmTypeBase {
126 | SpvmWord width;
127 | } SpvmTypeFloat;
128 |
129 | typedef struct SpvmTypeVector_ : SpvmTypeBase {
130 | SpvmTypeBase *componentType;
131 | } SpvmTypeVector;
132 |
133 | typedef struct SpvmTypeMatrix_ : SpvmTypeBase {
134 | SpvmTypeBase *columnType;
135 | } SpvmTypeMatrix;
136 |
137 | typedef struct SpvmTypeImage_ : SpvmTypeBase {
138 | SpvmTypeBase *sampledType;
139 | SpvDim dim;
140 | SpvmByte depth;
141 | SpvmByte arrayed;
142 | SpvmByte ms;
143 | SpvmByte sampled;
144 | SpvImageFormat format;
145 | SpvAccessQualifier accessQualifier;
146 | } SpvmTypeImage;
147 |
148 | typedef struct SpvmTypeSampler_ : SpvmTypeBase {
149 | } SpvmTypeSampler;
150 |
151 | typedef struct SpvmTypeSampledImage_ : SpvmTypeBase {
152 | SpvmTypeImage *imageType;
153 | } SpvmTypeSampledImage;
154 |
155 | typedef struct SpvmTypeArray_ : SpvmTypeBase {
156 | SpvmTypeBase *elementType;
157 | } SpvmTypeArray;
158 |
159 | typedef struct SpvmTypeRuntimeArray_ : SpvmTypeBase {
160 | SpvmTypeBase *elementType;
161 | } SpvmTypeRuntimeArray;
162 |
163 | typedef struct SpvmTypeStruct_ : SpvmTypeBase {
164 | SpvmTypeBase **memberTypes;
165 | } SpvmTypeStruct;
166 |
167 | typedef struct SpvmTypePointer_ : SpvmTypeBase {
168 | SpvStorageClass storageClass;
169 | SpvmTypeBase *objType;
170 | } SpvmTypePointer;
171 |
172 | typedef struct SpvmTypeFunction_ : SpvmTypeBase {
173 | SpvmTypeBase *returnType;
174 | SpvmWord parameterCnt;
175 | SpvmTypeBase **parameterTypes;
176 | } SpvmTypeFunction;
177 |
178 | typedef struct SpvmFunction_ {
179 | SpvmWord functionControl;
180 | SpvmTypeBase *functionType;
181 | SpvmWord *code;
182 | } SpvmFunction;
183 |
184 | typedef struct SpvmSamplerAttribute_ {
185 | SpvSamplerAddressingMode addressingMode;
186 | SpvmByte normalized;
187 | SpvSamplerFilterMode filterMode;
188 | } SpvmSamplerAttribute;
189 |
190 | typedef struct SpvmSamplerInternal_ {
191 | SpvmSamplerAttribute *attributes;
192 | SpvmVoid *opaque;
193 | } SpvmSamplerInternal;
194 |
195 | typedef struct SpvmImageInternal_ {
196 | SpvmTypeImage *type;
197 | SpvmVoid *opaque;
198 | } SpvmImageInternal;
199 |
200 | typedef struct SpvmSampledImageInternal_ {
201 | SpvmImageInternal *image;
202 | SpvmSamplerInternal *sampler;
203 | } SpvmSampledImageInternal;
204 |
205 | typedef struct SpvmValue_ {
206 | SpvmTypeBase *type;
207 | SpvmWord memberCnt;
208 |
209 | union {
210 | SpvmBool boolean;
211 | SpvmI32 i32;
212 | SpvmU32 u32;
213 | SpvmF32 f32;
214 |
215 | SpvmSamplerInternal *sampler;
216 | SpvmImageInternal *image;
217 | SpvmSampledImageInternal *sampledImage;
218 |
219 | SpvmValue_ **members;
220 | } value;
221 | } SpvmValue;
222 |
223 | typedef struct SpvmPointer_ {
224 | SpvmTypePointer *resultType;
225 | SpvmValue *objPtr;
226 | } SpvmPointer;
227 |
228 | typedef struct SpvmImageOperands_ {
229 | SpvmValue *bias;
230 | SpvmValue *lod;
231 | SpvmValue *dx, *dy;
232 | SpvmValue *offset;
233 | SpvmValue *offsets; // OpImageGather, OpImageDrefGather
234 | SpvmValue *sample;
235 | SpvmValue *minLod;
236 | } SpvmImageOperands;
237 |
238 | typedef union SpvmVecElement_ {
239 | SpvmI32 i32;
240 | SpvmU32 u32;
241 | SpvmF32 f32;
242 | } SpvmVecElement;
243 |
244 | typedef struct SpvmVec2_ {
245 | SpvmVecElement elem[2];
246 | } SpvmVec2;
247 |
248 | typedef struct SpvmVec3_ {
249 | SpvmVecElement elem[3];
250 | } SpvmVec3;
251 |
252 | typedef struct SpvmVec4_ {
253 | SpvmVecElement elem[4];
254 | } SpvmVec4;
255 |
256 | SpvmOpcode readOpcode(const SpvmWord *pc);
257 | SpvmValue *createValue(SpvmTypeBase *type, SpvmByte **psp);
258 | void copyValue(SpvmValue *dst, SpvmValue *src);
259 | SpvmValue *setValueF32(SpvmValue *ret, SpvmF32 val);
260 | SpvmWord getTypeSize(SpvmTypeBase *type);
261 | void writeToValue(SpvmValue *retValue, SpvmVec4 vec);
262 | SpvmVec4 readFromValue(SpvmValue *value);
263 |
264 | void valueSubF32(SpvmValue *ret, SpvmValue *a, SpvmValue *b);
265 |
266 | }
--------------------------------------------------------------------------------
/test/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.3)
2 | project(spvm_test)
3 |
4 | set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
5 | add_subdirectory(googletest)
6 |
7 | add_executable(${PROJECT_NAME} main.cpp
8 | test_core.cpp
9 | test_image.cpp
10 | test_ext.cpp
11 | )
12 | target_link_libraries(${PROJECT_NAME} spvm_lib gtest_main)
13 |
14 | include(GoogleTest)
15 | gtest_discover_tests(${PROJECT_NAME} WORKING_DIRECTORY $)
16 |
17 | # copy assets
18 | add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
19 | COMMAND ${CMAKE_COMMAND} -E remove_directory $/assets
20 | COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/assets $/assets
21 | )
22 |
--------------------------------------------------------------------------------
/test/assets/arithmetic_0.frag:
--------------------------------------------------------------------------------
1 | #version 450
2 |
3 | #extension GL_GOOGLE_include_directive : require
4 | #include "assert.glsl"
5 |
6 | void main()
7 | {
8 | ASSERT_BEGIN(32)
9 |
10 | // OpSNegate
11 | int a0 = 5;
12 | int outOpSNegate = -a0;
13 | ASSERT(outOpSNegate == -5);
14 |
15 | // OpFNegate
16 | float a1 = 5.f;
17 | float outOpFNegate = -a1;
18 | ASSERT(outOpFNegate == -5.f);
19 |
20 | // OpIAdd
21 | int a2 = 5;
22 | int outOpIAdd = a2 + 1;
23 | ASSERT(outOpIAdd == 6);
24 |
25 | // OpFAdd
26 | vec3 a3 = vec3(1.f, 1.f, 1.f);
27 | vec3 outOpFAdd = a3 + vec3(0.1f, 0.2f, 0.3f);
28 | ASSERT(outOpFAdd == vec3(1.1f, 1.2f, 1.3f));
29 |
30 | // OpISub
31 | ivec3 a4 = ivec3(5, 5, 5);
32 | ivec3 outOpISub = a4 - ivec3(4, 5, 6);
33 | ASSERT(outOpISub == ivec3(1, 0, -1));
34 |
35 | // OpFSub
36 | vec3 a5 = vec3(1.f, 1.f, 1.f);
37 | vec3 outOpFSub = a5 - vec3(0.1f, 0.2f, 0.3f);
38 | ASSERT(outOpFSub == vec3(0.9f, 0.8f, 0.7f));
39 |
40 | // OpIMul
41 | ivec3 a6 = ivec3(1, -2, 3);
42 | ivec3 outOpIMul = a6 * ivec3(4, 5, 6);
43 | ASSERT(outOpIMul == ivec3(4, -10, 18));
44 |
45 | // OpFMul
46 | vec3 a7 = vec3(1.f, -2.f, 1.f);
47 | vec3 outOpFMul = a7 * vec3(0.1f, 0.2f, 0.3f);
48 | ASSERT(outOpFMul == vec3(0.1f, -0.4f, 0.3f));
49 |
50 | // OpUDiv
51 | uvec3 a8 = uvec3(10, 20, 3);
52 | uvec3 outOpUDiv = a8 / uvec3(4, 5, 6);
53 | ASSERT(outOpUDiv == uvec3(2u, 4u, 0u));
54 |
55 | // OpSDiv
56 | ivec3 a9 = ivec3(10, -20, 30);
57 | ivec3 outOpSDiv = a9 / ivec3(4, 5, 6);
58 | ASSERT(outOpSDiv == ivec3(2, -4, 5));
59 |
60 | // OpFDiv
61 | vec3 a10 = vec3(10.f, -20.f, 30.f);
62 | vec3 outOpFDiv = a10 / vec3(4.f, 5.f, 6.f);
63 | ASSERT(outOpFDiv == vec3(2.5f, -4.f, 5.f));
64 |
65 | // OpUMod
66 | uvec3 a11 = uvec3(10, 21, 31);
67 | uvec3 outOpUMod = a11 % uvec3(4, 5, 6);
68 | ASSERT(outOpUMod == uvec3(2u, 1u, 1u));
69 |
70 | // OpSMod
71 | ivec3 a12 = ivec3(10, -21, 31);
72 | ivec3 outOpSMod = a12 % ivec3(4, 5, 6);
73 | ASSERT(outOpSMod == ivec3(2, 4, 1));
74 |
75 | // OpSRem TODO
76 |
77 | // OpFMod
78 | vec3 a13 = vec3(10.1f, -21.4f, 31.3f);
79 | vec3 outOpFMod = mod(a13, vec3(4.f, 5.f, 6.f));
80 | ASSERT(outOpFMod == vec3(2.1f, 3.6f, 1.3f));
81 |
82 | // OpFRem TODO
83 |
84 | ASSERT_END
85 | }
86 |
--------------------------------------------------------------------------------
/test/assets/arithmetic_0.frag.spv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keith2018/spvm/a232ea822562dde8d9de47be458a3777392d98bb/test/assets/arithmetic_0.frag.spv
--------------------------------------------------------------------------------
/test/assets/arithmetic_1.frag:
--------------------------------------------------------------------------------
1 | #version 450
2 |
3 | #extension GL_GOOGLE_include_directive : require
4 | #include "assert.glsl"
5 |
6 | void main()
7 | {
8 | ASSERT_BEGIN(32)
9 |
10 | vec4 inVec = vec4(0.2f, 0.3f, 0.4f, 1.f);
11 |
12 | mat4 inMat = mat4(1.f, 1.f, 0.f, 0.f,
13 | 0.f, 1.f, 0.f, 0.f,
14 | 0.f, 0.f, 1.f, 0.f,
15 | 0.f, 0.f, 0.f, 1.f);
16 |
17 | mat4 inMat2 = mat4(1.f, 2.f, 0.f, 0.f,
18 | 0.f, 1.f, 0.f, 0.f,
19 | 0.f, 0.f, 1.f, 0.f,
20 | 0.f, 0.f, 0.f, 1.f);
21 |
22 | // OpVectorTimesScalar
23 | vec4 outOpVectorTimesScalar = inVec * 0.2f;
24 | ASSERT(outOpVectorTimesScalar == vec4(0.04f, 0.06f, 0.08f, 0.2f));
25 |
26 | // OpMatrixTimesScalar
27 | mat4 outOpMatrixTimesScalar = inMat * 0.2f;
28 | ASSERT(outOpMatrixTimesScalar[0] == vec4(0.2f, 0.2f, 0.f, 0.f));
29 | ASSERT(outOpMatrixTimesScalar[1] == vec4(0.f, 0.2f, 0.f, 0.f));
30 | ASSERT(outOpMatrixTimesScalar[2] == vec4(0.f, 0.f, 0.2f, 0.f));
31 | ASSERT(outOpMatrixTimesScalar[3] == vec4(0.f, 0.f, 0.f, 0.2f));
32 |
33 | // OpVectorTimesMatrix
34 | vec4 outOpVectorTimesMatrix = inVec * inMat;
35 | ASSERT(outOpVectorTimesMatrix == vec4(0.5f, 0.3f, 0.4f, 1.f));
36 |
37 | // OpMatrixTimesVector
38 | vec4 outOpMatrixTimesVector = inMat * inVec;
39 | ASSERT(outOpMatrixTimesVector == vec4(0.2f, 0.5f, 0.4f, 1.f));
40 |
41 | // OpMatrixTimesMatrix
42 | mat4 inMat22 = mat4(inMat2[0], inMat2[1], inMat2[3], inMat2[2]);
43 | mat4 outOpMatrixTimesMatrix = inMat * inMat22;
44 | ASSERT(outOpMatrixTimesMatrix[0] == vec4(1.f, 3.f, 0.f, 0.f));
45 | ASSERT(outOpMatrixTimesMatrix[1] == vec4(0.f, 1.f, 0.f, 0.f));
46 | ASSERT(outOpMatrixTimesMatrix[2] == vec4(0.f, 0.f, 0.f, 1.f));
47 | ASSERT(outOpMatrixTimesMatrix[3] == vec4(0.f, 0.f, 1.f, 0.f));
48 |
49 | vec4 v1 = vec4(1.f, 2.f, 3.f, 4.f);
50 | vec3 v2 = vec3(1.f, 2.f, 1.f);
51 |
52 | // SpvOpOuterProduct
53 | mat3x4 outerProduct = outerProduct(v1, v2);
54 | ASSERT(outerProduct[0] == vec4(1.f, 2.f, 3.f, 4.f));
55 | ASSERT(outerProduct[1] == vec4(2.f, 4.f, 6.f, 8.f));
56 | ASSERT(outerProduct[2] == vec4(1.f, 2.f, 3.f, 4.f));
57 |
58 | // SpvOpOuterProduct
59 | vec3 outCross = cross(v1.xyz, v2);
60 | ASSERT(outCross == vec3(-4.f, 2.f, 0.f));
61 |
62 | // SpvOpDot
63 | float outOpDot = dot(v1.xyz, v2);
64 | ASSERT(outOpDot == 8.f);
65 |
66 | // SpvOpIAddCarry
67 | uint uInteger1 = 0x00000001u;
68 | uint uInteger2 = 0x00000002u;
69 | uint uInteger3 = 0xFFFFFFFEu;
70 | uint carry;
71 | ASSERT(uaddCarry(uInteger1, uInteger3, carry) == 0xFFFFFFFFu);
72 | ASSERT(carry == 0u);
73 | ASSERT(uaddCarry(uInteger2, uInteger3, carry) == 0x00000001u);
74 | ASSERT(carry == 1u);
75 |
76 | // SpvOpISubBorrow
77 | uvec2 borrow;
78 | ASSERT(usubBorrow(uvec2(uInteger1, uInteger2), uvec2(uInteger2, uInteger1), borrow)
79 | == uvec2(0xFFFFFFFEu, 0x00000001u));
80 | ASSERT(borrow == uvec2(1u, 0u));
81 |
82 | // SpvOpUMulExtended
83 | uint ux = 0xffffffff;
84 | uint uy = 0x3;
85 | uint umsb = 0;
86 | uint ulsb = 0;
87 | umulExtended(ux, uy, umsb, ulsb);
88 | ASSERT(uvec2(umsb, ulsb) == uvec2(0x2, 0xfffffffd));
89 |
90 | uvec2 uvx = uvec2(0xffffffff, 0x1);
91 | uvec2 uvy = uvec2(0x3);
92 | uvec2 uvmsb = uvec2(0);
93 | uvec2 uvlsb = uvec2(0);
94 | umulExtended(uvx, uvy, uvmsb, uvlsb);
95 | ASSERT(uvmsb == uvec2(0x2, 0x0));
96 | ASSERT(uvlsb == uvec2(0xfffffffd, 0x3));
97 |
98 | // SpvOpSMulExtended
99 | int ix = 0xfffffff;
100 | int iy = 0xfff;
101 | int imsb = 0;
102 | int ilsb = 0;
103 | imulExtended(ix, iy, imsb, ilsb);
104 | ASSERT(ivec2(imsb, ilsb) == ivec2(0xff, 0xeffff001));
105 |
106 | ivec2 ivx = ivec2(0xfffffff, 0x1);
107 | ivec2 ivy = ivec2(0xfff);
108 | ivec2 ivmsb = ivec2(0);
109 | ivec2 ivlsb = ivec2(0);
110 | imulExtended(ivx, ivy, ivmsb, ivlsb);
111 | ASSERT(ivmsb == ivec2(0xff, 0x0));
112 | ASSERT(ivlsb == ivec2(0xeffff001, 0xfff));
113 |
114 | ASSERT_END
115 | }
116 |
--------------------------------------------------------------------------------
/test/assets/arithmetic_1.frag.spv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keith2018/spvm/a232ea822562dde8d9de47be458a3777392d98bb/test/assets/arithmetic_1.frag.spv
--------------------------------------------------------------------------------
/test/assets/array.frag:
--------------------------------------------------------------------------------
1 | #version 450
2 |
3 | #extension GL_GOOGLE_include_directive : require
4 | #include "assert.glsl"
5 |
6 | layout(set = 0, binding = 0) buffer TestBlock
7 | {
8 | vec3 a;
9 | float[] b;
10 | } tb;
11 |
12 | void main()
13 | {
14 | ASSERT_BEGIN(32)
15 |
16 | float arr[5] = float[5](3.4f, 4.2f, 5.0f, 5.2f, 1.1f);
17 | ASSERT(arr[0] == 3.4f);
18 | ASSERT(arr[1] == 4.2f);
19 | ASSERT(arr[2] == 5.0f);
20 | ASSERT(arr[3] == 5.2f);
21 | ASSERT(arr[4] == 1.1f);
22 | ASSERT(arr.length() == 5);
23 |
24 | ASSERT(tb.a == vec3(4.2f, 5.0f, 5.2f));
25 |
26 | int n = tb.b.length();
27 | ASSERT(n == 6);
28 |
29 | ASSERT(tb.b[0] == 1.2f);
30 | ASSERT(tb.b[1] == 1.0f);
31 | ASSERT(tb.b[2] == 1.3f);
32 | ASSERT(tb.b[3] == 0.2f);
33 | ASSERT(tb.b[4] == 0.3f);
34 | ASSERT(tb.b[5] == 0.5f);
35 |
36 | ASSERT_END
37 | }
38 |
--------------------------------------------------------------------------------
/test/assets/array.frag.spv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keith2018/spvm/a232ea822562dde8d9de47be458a3777392d98bb/test/assets/array.frag.spv
--------------------------------------------------------------------------------
/test/assets/assert.glsl:
--------------------------------------------------------------------------------
1 | layout (location = 0) out int outAssert;
2 |
3 | #define ASSERT_BEGIN(n) \
4 | int assertIdx = 0; \
5 | bool asserts[n];
6 |
7 | #define ASSERT(condition) \
8 | asserts[assertIdx] = (condition); \
9 | assertIdx++;
10 |
11 | #define ASSERT_END \
12 | outAssert = -1; \
13 | for (int i = 0; i < assertIdx; i++) { \
14 | if (!asserts[i]) { \
15 | outAssert = i; \
16 | break; \
17 | } \
18 | }
19 |
--------------------------------------------------------------------------------
/test/assets/bit.frag:
--------------------------------------------------------------------------------
1 | #version 450
2 |
3 | #extension GL_GOOGLE_include_directive : require
4 | #include "assert.glsl"
5 |
6 | void main()
7 | {
8 | ASSERT_BEGIN(64)
9 |
10 | // SpvOpShiftRightLogical
11 | uint ua = 0xfffffffe;
12 | ASSERT((ua >> 1) == 0x7fffffff)
13 | ASSERT((uvec2(ua) >> 1) == uvec2(0x7fffffff))
14 |
15 | // SpvOpShiftRightArithmetic
16 | int ia1 = -2; // 0xfffffffe
17 | ASSERT((ia1 >> 1) == 0xffffffff)
18 | ASSERT((ivec2(ia1) >> 1) == ivec2(0xffffffff))
19 |
20 | int ia2 = 0xff;
21 | ASSERT((ia2 >> 1) == 0x7f)
22 | ASSERT((ivec2(ia2) >> 1) == ivec2(0x7f))
23 |
24 | // SpvOpShiftLeftLogical
25 | ASSERT((ua << 1) == 0xfffffffc)
26 | ASSERT((uvec2(ua) << 1) == uvec2(0xfffffffc))
27 |
28 | ASSERT((ia1 << 1) == -4) // 0xfffffffc
29 | ASSERT((ivec2(ia1) << 1) == ivec2(-4))
30 |
31 | // SpvOpBitwiseOr
32 | ASSERT((ua | 0x1) == 0xffffffff)
33 | ASSERT((ua | 0) == 0xfffffffe)
34 |
35 | // SpvOpBitwiseXor
36 | ASSERT((ua ^ 0x1) == 0xffffffff)
37 | ASSERT((ua ^ 0xff) == 0xffffff01)
38 |
39 | // SpvOpBitwiseAnd
40 | ASSERT((ua & 0x1) == 0)
41 | ASSERT((ua & 0xff) == 0xfe)
42 |
43 | // SpvOpNot
44 | ASSERT((~ua) == 0x1)
45 |
46 | // SpvOpBitFieldInsert
47 | ASSERT(bitfieldInsert(0x00000000, 0xffffffff, 0, 32) == 0xffffffff)
48 | ASSERT(bitfieldInsert(0x00000000, 0xffffffff, 0, 31) == 0x7fffffff)
49 | ASSERT(bitfieldInsert(0x00000000, 0xffffffff, 0, 0) == 0x00000000)
50 | ASSERT(bitfieldInsert(0xff000000, 0x000000ff, 8, 8) == 0xff00ff00)
51 | ASSERT(bitfieldInsert(0xffff0000, 0xffff0000, 16, 16) == 0x00000000)
52 | ASSERT(bitfieldInsert(0x0000ffff, 0x0000ffff, 16, 16) == 0xffffffff)
53 |
54 | // SpvOpBitFieldSExtract
55 | ASSERT(bitfieldExtract(0x0f0f0f0f, 0, 32) == 0x0f0f0f0f)
56 | ASSERT(bitfieldExtract(0x000000ff, 1, 3) == 0x00000007)
57 | ASSERT(bitfieldExtract(0x0000ff00, 8, 8) == 0x000000ff)
58 |
59 | // SpvOpBitFieldUExtract
60 | ASSERT(bitfieldExtract(0xffffffffu, 0, 32) == 0xffffffff)
61 | ASSERT(bitfieldExtract(0xfffffff0u, 0, 5) == 0x00000010)
62 |
63 | // SpvOpBitReverse
64 | ASSERT(bitfieldReverse(0x55555555) == 0xAAAAAAAA)
65 | ASSERT(bitfieldReverse(0x0F0F0F0F) == 0xF0F0F0F0)
66 |
67 | // SpvOpBitCount
68 | ASSERT(bitCount(0x00000001) == 1)
69 | ASSERT(bitCount(0x00000003) == 2)
70 | ASSERT(bitCount(0x7fffffff) == 31)
71 | ASSERT(bitCount(0x00000000) == 0)
72 |
73 | ASSERT_END
74 | }
75 |
--------------------------------------------------------------------------------
/test/assets/bit.frag.spv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keith2018/spvm/a232ea822562dde8d9de47be458a3777392d98bb/test/assets/bit.frag.spv
--------------------------------------------------------------------------------
/test/assets/built_in.vert:
--------------------------------------------------------------------------------
1 | #version 450
2 |
3 | layout (location = 0) out vec3 outColor;
4 |
5 | void main()
6 | {
7 | const vec3 positions[3] = vec3[3](
8 | vec3(1.f, 1.f, 0.0f),
9 | vec3(-1.f, 1.f, 0.0f),
10 | vec3(0.f, -1.f, 0.0f)
11 | );
12 |
13 | const vec3 colors[3] = vec3[3](
14 | vec3(1.0f, 0.0f, 0.0f),
15 | vec3(0.0f, 1.0f, 0.0f),
16 | vec3(0.f, 0.0f, 1.0f)
17 | );
18 |
19 | gl_Position = vec4(positions[gl_VertexIndex], 1.0f);
20 | outColor = colors[gl_VertexIndex];
21 | }
--------------------------------------------------------------------------------
/test/assets/built_in.vert.spv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keith2018/spvm/a232ea822562dde8d9de47be458a3777392d98bb/test/assets/built_in.vert.spv
--------------------------------------------------------------------------------
/test/assets/built_in.vert.spv.txt:
--------------------------------------------------------------------------------
1 | built_in.vert
2 | // Module Version 10000
3 | // Generated by (magic number): 8000a
4 | // Id's are bound by 50
5 |
6 | Capability Shader
7 | 1: ExtInstImport "GLSL.std.450"
8 | MemoryModel Logical GLSL450
9 | EntryPoint Vertex 4 "main" 13 27 41
10 | Source GLSL 450
11 | Name 4 "main"
12 | Name 11 "gl_PerVertex"
13 | MemberName 11(gl_PerVertex) 0 "gl_Position"
14 | MemberName 11(gl_PerVertex) 1 "gl_PointSize"
15 | MemberName 11(gl_PerVertex) 2 "gl_ClipDistance"
16 | MemberName 11(gl_PerVertex) 3 "gl_CullDistance"
17 | Name 13 ""
18 | Name 27 "gl_VertexIndex"
19 | Name 30 "indexable"
20 | Name 41 "outColor"
21 | Name 47 "indexable"
22 | MemberDecorate 11(gl_PerVertex) 0 BuiltIn Position
23 | MemberDecorate 11(gl_PerVertex) 1 BuiltIn PointSize
24 | MemberDecorate 11(gl_PerVertex) 2 BuiltIn ClipDistance
25 | MemberDecorate 11(gl_PerVertex) 3 BuiltIn CullDistance
26 | Decorate 11(gl_PerVertex) Block
27 | Decorate 27(gl_VertexIndex) BuiltIn VertexIndex
28 | Decorate 41(outColor) Location 0
29 | 2: TypeVoid
30 | 3: TypeFunction 2
31 | 6: TypeFloat 32
32 | 7: TypeVector 6(float) 4
33 | 8: TypeInt 32 0
34 | 9: 8(int) Constant 1
35 | 10: TypeArray 6(float) 9
36 | 11(gl_PerVertex): TypeStruct 7(fvec4) 6(float) 10 10
37 | 12: TypePointer Output 11(gl_PerVertex)
38 | 13: 12(ptr) Variable Output
39 | 14: TypeInt 32 1
40 | 15: 14(int) Constant 0
41 | 16: TypeVector 6(float) 3
42 | 17: 8(int) Constant 3
43 | 18: TypeArray 16(fvec3) 17
44 | 19: 6(float) Constant 1065353216
45 | 20: 6(float) Constant 0
46 | 21: 16(fvec3) ConstantComposite 19 19 20
47 | 22: 6(float) Constant 3212836864
48 | 23: 16(fvec3) ConstantComposite 22 19 20
49 | 24: 16(fvec3) ConstantComposite 20 22 20
50 | 25: 18 ConstantComposite 21 23 24
51 | 26: TypePointer Input 14(int)
52 | 27(gl_VertexIndex): 26(ptr) Variable Input
53 | 29: TypePointer Function 18
54 | 31: TypePointer Function 16(fvec3)
55 | 38: TypePointer Output 7(fvec4)
56 | 40: TypePointer Output 16(fvec3)
57 | 41(outColor): 40(ptr) Variable Output
58 | 42: 16(fvec3) ConstantComposite 19 20 20
59 | 43: 16(fvec3) ConstantComposite 20 19 20
60 | 44: 16(fvec3) ConstantComposite 20 20 19
61 | 45: 18 ConstantComposite 42 43 44
62 | 4(main): 2 Function None 3
63 | 5: Label
64 | 30(indexable): 29(ptr) Variable Function
65 | 47(indexable): 29(ptr) Variable Function
66 | 28: 14(int) Load 27(gl_VertexIndex)
67 | Store 30(indexable) 25
68 | 32: 31(ptr) AccessChain 30(indexable) 28
69 | 33: 16(fvec3) Load 32
70 | 34: 6(float) CompositeExtract 33 0
71 | 35: 6(float) CompositeExtract 33 1
72 | 36: 6(float) CompositeExtract 33 2
73 | 37: 7(fvec4) CompositeConstruct 34 35 36 19
74 | 39: 38(ptr) AccessChain 13 15
75 | Store 39 37
76 | 46: 14(int) Load 27(gl_VertexIndex)
77 | Store 47(indexable) 45
78 | 48: 31(ptr) AccessChain 47(indexable) 46
79 | 49: 16(fvec3) Load 48
80 | Store 41(outColor) 49
81 | Return
82 | FunctionEnd
83 |
--------------------------------------------------------------------------------
/test/assets/composite.frag:
--------------------------------------------------------------------------------
1 | #version 450
2 |
3 | #extension GL_GOOGLE_include_directive : require
4 | #include "assert.glsl"
5 |
6 | void main()
7 | {
8 | ASSERT_BEGIN(32)
9 |
10 | mat4 m1 = mat4(1.f, 2.f, 0.f, 0.f,
11 | 0.f, 1.f, 0.f, 0.f,
12 | 0.f, 0.f, 1.f, 0.f,
13 | 0.f, 0.f, 0.f, 1.f);
14 |
15 | mat4 m2 = transpose(m1);
16 | ASSERT(m2[0] == vec4(1.f, 0.f, 0.f, 0.f));
17 | ASSERT(m2[1] == vec4(2.f, 1.f, 0.f, 0.f));
18 | ASSERT(m2[2] == vec4(0.f, 0.f, 1.f, 0.f));
19 | ASSERT(m2[3] == vec4(0.f, 0.f, 0.f, 1.f));
20 |
21 | vec4 v1 = vec4(m1[0].yxz, 1.f);
22 | ASSERT(v1 == vec4(2.f, 1.f, 0.f, 1.f));
23 |
24 | ASSERT_END
25 | }
26 |
--------------------------------------------------------------------------------
/test/assets/composite.frag.spv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keith2018/spvm/a232ea822562dde8d9de47be458a3777392d98bb/test/assets/composite.frag.spv
--------------------------------------------------------------------------------
/test/assets/composite.frag.spv.txt:
--------------------------------------------------------------------------------
1 | composite.frag
2 | // Module Version 10000
3 | // Generated by (magic number): 8000a
4 | // Id's are bound by 111
5 |
6 | Capability Shader
7 | 1: ExtInstImport "GLSL.std.450"
8 | MemoryModel Logical GLSL450
9 | EntryPoint Fragment 4 "main" 90
10 | ExecutionMode 4 OriginUpperLeft
11 | Source GLSL 450
12 | SourceExtension "GL_GOOGLE_cpp_style_line_directive"
13 | SourceExtension "GL_GOOGLE_include_directive"
14 | Name 4 "main"
15 | Name 8 "assertIdx"
16 | Name 14 "m1"
17 | Name 23 "m2"
18 | Name 31 "asserts"
19 | Name 72 "v1"
20 | Name 90 "outAssert"
21 | Name 92 "i"
22 | Decorate 90(outAssert) Location 0
23 | 2: TypeVoid
24 | 3: TypeFunction 2
25 | 6: TypeInt 32 1
26 | 7: TypePointer Function 6(int)
27 | 9: 6(int) Constant 0
28 | 10: TypeFloat 32
29 | 11: TypeVector 10(float) 4
30 | 12: TypeMatrix 11(fvec4) 4
31 | 13: TypePointer Function 12
32 | 15: 10(float) Constant 1065353216
33 | 16: 10(float) Constant 1073741824
34 | 17: 10(float) Constant 0
35 | 18: 11(fvec4) ConstantComposite 15 16 17 17
36 | 19: 11(fvec4) ConstantComposite 17 15 17 17
37 | 20: 11(fvec4) ConstantComposite 17 17 15 17
38 | 21: 11(fvec4) ConstantComposite 17 17 17 15
39 | 22: 12 ConstantComposite 18 19 20 21
40 | 26: TypeBool
41 | 27: TypeInt 32 0
42 | 28: 27(int) Constant 32
43 | 29: TypeArray 26(bool) 28
44 | 30: TypePointer Function 29
45 | 33: TypePointer Function 11(fvec4)
46 | 36: 11(fvec4) ConstantComposite 15 17 17 17
47 | 37: TypeVector 26(bool) 4
48 | 40: TypePointer Function 26(bool)
49 | 43: 6(int) Constant 1
50 | 48: 11(fvec4) ConstantComposite 16 15 17 17
51 | 55: 6(int) Constant 2
52 | 64: 6(int) Constant 3
53 | 73: TypeVector 10(float) 3
54 | 83: 11(fvec4) ConstantComposite 16 15 17 15
55 | 89: TypePointer Output 6(int)
56 | 90(outAssert): 89(ptr) Variable Output
57 | 91: 6(int) Constant 4294967295
58 | 4(main): 2 Function None 3
59 | 5: Label
60 | 8(assertIdx): 7(ptr) Variable Function
61 | 14(m1): 13(ptr) Variable Function
62 | 23(m2): 13(ptr) Variable Function
63 | 31(asserts): 30(ptr) Variable Function
64 | 72(v1): 33(ptr) Variable Function
65 | 92(i): 7(ptr) Variable Function
66 | Store 8(assertIdx) 9
67 | Store 14(m1) 22
68 | 24: 12 Load 14(m1)
69 | 25: 12 Transpose 24
70 | Store 23(m2) 25
71 | 32: 6(int) Load 8(assertIdx)
72 | 34: 33(ptr) AccessChain 23(m2) 9
73 | 35: 11(fvec4) Load 34
74 | 38: 37(bvec4) FOrdEqual 35 36
75 | 39: 26(bool) All 38
76 | 41: 40(ptr) AccessChain 31(asserts) 32
77 | Store 41 39
78 | 42: 6(int) Load 8(assertIdx)
79 | 44: 6(int) IAdd 42 43
80 | Store 8(assertIdx) 44
81 | 45: 6(int) Load 8(assertIdx)
82 | 46: 33(ptr) AccessChain 23(m2) 43
83 | 47: 11(fvec4) Load 46
84 | 49: 37(bvec4) FOrdEqual 47 48
85 | 50: 26(bool) All 49
86 | 51: 40(ptr) AccessChain 31(asserts) 45
87 | Store 51 50
88 | 52: 6(int) Load 8(assertIdx)
89 | 53: 6(int) IAdd 52 43
90 | Store 8(assertIdx) 53
91 | 54: 6(int) Load 8(assertIdx)
92 | 56: 33(ptr) AccessChain 23(m2) 55
93 | 57: 11(fvec4) Load 56
94 | 58: 37(bvec4) FOrdEqual 57 20
95 | 59: 26(bool) All 58
96 | 60: 40(ptr) AccessChain 31(asserts) 54
97 | Store 60 59
98 | 61: 6(int) Load 8(assertIdx)
99 | 62: 6(int) IAdd 61 43
100 | Store 8(assertIdx) 62
101 | 63: 6(int) Load 8(assertIdx)
102 | 65: 33(ptr) AccessChain 23(m2) 64
103 | 66: 11(fvec4) Load 65
104 | 67: 37(bvec4) FOrdEqual 66 21
105 | 68: 26(bool) All 67
106 | 69: 40(ptr) AccessChain 31(asserts) 63
107 | Store 69 68
108 | 70: 6(int) Load 8(assertIdx)
109 | 71: 6(int) IAdd 70 43
110 | Store 8(assertIdx) 71
111 | 74: 33(ptr) AccessChain 14(m1) 9
112 | 75: 11(fvec4) Load 74
113 | 76: 73(fvec3) VectorShuffle 75 75 1 0 2
114 | 77: 10(float) CompositeExtract 76 0
115 | 78: 10(float) CompositeExtract 76 1
116 | 79: 10(float) CompositeExtract 76 2
117 | 80: 11(fvec4) CompositeConstruct 77 78 79 15
118 | Store 72(v1) 80
119 | 81: 6(int) Load 8(assertIdx)
120 | 82: 11(fvec4) Load 72(v1)
121 | 84: 37(bvec4) FOrdEqual 82 83
122 | 85: 26(bool) All 84
123 | 86: 40(ptr) AccessChain 31(asserts) 81
124 | Store 86 85
125 | 87: 6(int) Load 8(assertIdx)
126 | 88: 6(int) IAdd 87 43
127 | Store 8(assertIdx) 88
128 | Store 90(outAssert) 91
129 | Store 92(i) 9
130 | Branch 93
131 | 93: Label
132 | LoopMerge 95 96 None
133 | Branch 97
134 | 97: Label
135 | 98: 6(int) Load 92(i)
136 | 99: 6(int) Load 8(assertIdx)
137 | 100: 26(bool) SLessThan 98 99
138 | BranchConditional 100 94 95
139 | 94: Label
140 | 101: 6(int) Load 92(i)
141 | 102: 40(ptr) AccessChain 31(asserts) 101
142 | 103: 26(bool) Load 102
143 | 104: 26(bool) LogicalNot 103
144 | SelectionMerge 106 None
145 | BranchConditional 104 105 106
146 | 105: Label
147 | 107: 6(int) Load 92(i)
148 | Store 90(outAssert) 107
149 | Branch 95
150 | 106: Label
151 | Branch 96
152 | 96: Label
153 | 109: 6(int) Load 92(i)
154 | 110: 6(int) IAdd 109 43
155 | Store 92(i) 110
156 | Branch 93
157 | 95: Label
158 | Return
159 | FunctionEnd
160 |
--------------------------------------------------------------------------------
/test/assets/control_flow.frag:
--------------------------------------------------------------------------------
1 | #version 450
2 |
3 | #extension GL_GOOGLE_include_directive : require
4 | #include "assert.glsl"
5 |
6 | vec4 func_if(vec3 inColor) {
7 | vec4 outColor;
8 | if (inColor.r > 0.5f) {
9 | outColor = vec4(inColor, 1.f);
10 | } else {
11 | outColor = vec4(inColor, 0.f);
12 | }
13 | return outColor;
14 | }
15 |
16 | float func_switch(vec3 inColor) {
17 | float outColor = 0.f;
18 | switch (int(inColor.g)) {
19 | case 0: outColor = 0.1f; break;
20 | case 1: outColor = 0.2f; break;
21 | case 2: outColor = 0.3f; break;
22 | default :outColor = 0.4f; break;
23 | }
24 | return outColor;
25 | }
26 |
27 | void main()
28 | {
29 | ASSERT_BEGIN(32)
30 |
31 | // if switch
32 | vec3 inColor = vec3(0.2f, 0.3f, 0.4f);
33 | vec4 outColor0 = func_if(inColor);
34 | float outColor1 = func_switch(inColor);
35 | ASSERT(outColor0 == vec4(0.2f, 0.3f, 0.4f, 0.f));
36 | ASSERT(outColor1 == 0.1f);
37 |
38 | inColor[0] = 0.6f;
39 | inColor[1] = 2.0f;
40 | outColor0 = func_if(inColor);
41 | outColor1 = func_switch(inColor);
42 | ASSERT(outColor0 == vec4(0.6f, 2.0f, 0.4f, 1.f));
43 | ASSERT(outColor1 == 0.3f);
44 |
45 | inColor[1] = 4.0f;
46 | outColor0 = func_if(inColor);
47 | outColor1 = func_switch(inColor);
48 | ASSERT(outColor0 == vec4(0.6f, 4.0f, 0.4f, 1.f));
49 | ASSERT(outColor1 == 0.4f);
50 |
51 | // phi
52 | vec3 rgb = vec3(0);
53 | if (inColor[0] >= 0.9f || inColor[1] >= 0.9f) {
54 | rgb = outColor0.yxz;
55 | } else {
56 | rgb = inColor;
57 | }
58 | ASSERT(rgb == vec3(4.0f, 0.6f, 0.4f))
59 |
60 | ASSERT_END
61 | }
62 |
--------------------------------------------------------------------------------
/test/assets/control_flow.frag.spv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keith2018/spvm/a232ea822562dde8d9de47be458a3777392d98bb/test/assets/control_flow.frag.spv
--------------------------------------------------------------------------------
/test/assets/conversion.frag:
--------------------------------------------------------------------------------
1 | #version 450
2 |
3 | #extension GL_GOOGLE_include_directive : require
4 | #include "assert.glsl"
5 |
6 | void main()
7 | {
8 | ASSERT_BEGIN(32)
9 |
10 | // OpConvertFToU
11 | float f0 = 12.5f;
12 | uint outUint0 = uint(f0);
13 | ASSERT(outUint0 == 12u);
14 |
15 | // OpConvertFToS
16 | float f1 = -11.3f;
17 | int outInt0 = int(f1);
18 | ASSERT(outInt0 == -11);
19 |
20 | // OpConvertUToF
21 | float outFloat0 = float(outUint0);
22 | ASSERT(outFloat0 == 12.f);
23 |
24 | // OpConvertSToF
25 | float outFloat1 = float(outInt0);
26 | ASSERT(outFloat1 == -11.f);
27 |
28 | // OpBitcast
29 | uint u32 = 10;
30 | int outInt2 = int(u32);
31 | ASSERT(outInt2 == 10);
32 |
33 | // OpFConvert TODO
34 |
35 | ASSERT_END
36 | }
37 |
--------------------------------------------------------------------------------
/test/assets/conversion.frag.spv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keith2018/spvm/a232ea822562dde8d9de47be458a3777392d98bb/test/assets/conversion.frag.spv
--------------------------------------------------------------------------------
/test/assets/conversion.frag.spv.txt:
--------------------------------------------------------------------------------
1 | .\conversion.frag
2 | // Module Version 10000
3 | // Generated by (magic number): 8000a
4 | // Id's are bound by 99
5 |
6 | Capability Shader
7 | 1: ExtInstImport "GLSL.std.450"
8 | MemoryModel Logical GLSL450
9 | EntryPoint Fragment 4 "main" 78
10 | ExecutionMode 4 OriginUpperLeft
11 | Source GLSL 450
12 | SourceExtension "GL_GOOGLE_cpp_style_line_directive"
13 | SourceExtension "GL_GOOGLE_include_directive"
14 | Name 4 "main"
15 | Name 8 "assertIdx"
16 | Name 12 "f0"
17 | Name 16 "outUint0"
18 | Name 23 "asserts"
19 | Name 33 "f1"
20 | Name 35 "outInt0"
21 | Name 45 "outFloat0"
22 | Name 55 "outFloat1"
23 | Name 65 "u32"
24 | Name 67 "outInt2"
25 | Name 78 "outAssert"
26 | Name 80 "i"
27 | Decorate 78(outAssert) Location 0
28 | 2: TypeVoid
29 | 3: TypeFunction 2
30 | 6: TypeInt 32 1
31 | 7: TypePointer Function 6(int)
32 | 9: 6(int) Constant 0
33 | 10: TypeFloat 32
34 | 11: TypePointer Function 10(float)
35 | 13: 10(float) Constant 1095237632
36 | 14: TypeInt 32 0
37 | 15: TypePointer Function 14(int)
38 | 19: TypeBool
39 | 20: 14(int) Constant 32
40 | 21: TypeArray 19(bool) 20
41 | 22: TypePointer Function 21
42 | 26: 14(int) Constant 12
43 | 28: TypePointer Function 19(bool)
44 | 31: 6(int) Constant 1
45 | 34: 10(float) Constant 3241462989
46 | 40: 6(int) Constant 4294967285
47 | 50: 10(float) Constant 1094713344
48 | 60: 10(float) Constant 3241148416
49 | 66: 14(int) Constant 10
50 | 72: 6(int) Constant 10
51 | 77: TypePointer Output 6(int)
52 | 78(outAssert): 77(ptr) Variable Output
53 | 79: 6(int) Constant 4294967295
54 | 4(main): 2 Function None 3
55 | 5: Label
56 | 8(assertIdx): 7(ptr) Variable Function
57 | 12(f0): 11(ptr) Variable Function
58 | 16(outUint0): 15(ptr) Variable Function
59 | 23(asserts): 22(ptr) Variable Function
60 | 33(f1): 11(ptr) Variable Function
61 | 35(outInt0): 7(ptr) Variable Function
62 | 45(outFloat0): 11(ptr) Variable Function
63 | 55(outFloat1): 11(ptr) Variable Function
64 | 65(u32): 15(ptr) Variable Function
65 | 67(outInt2): 7(ptr) Variable Function
66 | 80(i): 7(ptr) Variable Function
67 | Store 8(assertIdx) 9
68 | Store 12(f0) 13
69 | 17: 10(float) Load 12(f0)
70 | 18: 14(int) ConvertFToU 17
71 | Store 16(outUint0) 18
72 | 24: 6(int) Load 8(assertIdx)
73 | 25: 14(int) Load 16(outUint0)
74 | 27: 19(bool) IEqual 25 26
75 | 29: 28(ptr) AccessChain 23(asserts) 24
76 | Store 29 27
77 | 30: 6(int) Load 8(assertIdx)
78 | 32: 6(int) IAdd 30 31
79 | Store 8(assertIdx) 32
80 | Store 33(f1) 34
81 | 36: 10(float) Load 33(f1)
82 | 37: 6(int) ConvertFToS 36
83 | Store 35(outInt0) 37
84 | 38: 6(int) Load 8(assertIdx)
85 | 39: 6(int) Load 35(outInt0)
86 | 41: 19(bool) IEqual 39 40
87 | 42: 28(ptr) AccessChain 23(asserts) 38
88 | Store 42 41
89 | 43: 6(int) Load 8(assertIdx)
90 | 44: 6(int) IAdd 43 31
91 | Store 8(assertIdx) 44
92 | 46: 14(int) Load 16(outUint0)
93 | 47: 10(float) ConvertUToF 46
94 | Store 45(outFloat0) 47
95 | 48: 6(int) Load 8(assertIdx)
96 | 49: 10(float) Load 45(outFloat0)
97 | 51: 19(bool) FOrdEqual 49 50
98 | 52: 28(ptr) AccessChain 23(asserts) 48
99 | Store 52 51
100 | 53: 6(int) Load 8(assertIdx)
101 | 54: 6(int) IAdd 53 31
102 | Store 8(assertIdx) 54
103 | 56: 6(int) Load 35(outInt0)
104 | 57: 10(float) ConvertSToF 56
105 | Store 55(outFloat1) 57
106 | 58: 6(int) Load 8(assertIdx)
107 | 59: 10(float) Load 55(outFloat1)
108 | 61: 19(bool) FOrdEqual 59 60
109 | 62: 28(ptr) AccessChain 23(asserts) 58
110 | Store 62 61
111 | 63: 6(int) Load 8(assertIdx)
112 | 64: 6(int) IAdd 63 31
113 | Store 8(assertIdx) 64
114 | Store 65(u32) 66
115 | 68: 14(int) Load 65(u32)
116 | 69: 6(int) Bitcast 68
117 | Store 67(outInt2) 69
118 | 70: 6(int) Load 8(assertIdx)
119 | 71: 6(int) Load 67(outInt2)
120 | 73: 19(bool) IEqual 71 72
121 | 74: 28(ptr) AccessChain 23(asserts) 70
122 | Store 74 73
123 | 75: 6(int) Load 8(assertIdx)
124 | 76: 6(int) IAdd 75 31
125 | Store 8(assertIdx) 76
126 | Store 78(outAssert) 79
127 | Store 80(i) 9
128 | Branch 81
129 | 81: Label
130 | LoopMerge 83 84 None
131 | Branch 85
132 | 85: Label
133 | 86: 6(int) Load 80(i)
134 | 87: 6(int) Load 8(assertIdx)
135 | 88: 19(bool) SLessThan 86 87
136 | BranchConditional 88 82 83
137 | 82: Label
138 | 89: 6(int) Load 80(i)
139 | 90: 28(ptr) AccessChain 23(asserts) 89
140 | 91: 19(bool) Load 90
141 | 92: 19(bool) LogicalNot 91
142 | SelectionMerge 94 None
143 | BranchConditional 92 93 94
144 | 93: Label
145 | 95: 6(int) Load 80(i)
146 | Store 78(outAssert) 95
147 | Branch 83
148 | 94: Label
149 | Branch 84
150 | 84: Label
151 | 97: 6(int) Load 80(i)
152 | 98: 6(int) IAdd 97 31
153 | Store 80(i) 98
154 | Branch 81
155 | 83: Label
156 | Return
157 | FunctionEnd
158 |
--------------------------------------------------------------------------------
/test/assets/derivative.frag:
--------------------------------------------------------------------------------
1 | #version 450
2 |
3 | layout (location = 0) in vec3 inColor;
4 | layout (location = 0) out vec4 outDx;
5 | layout (location = 1) out vec4 outDy;
6 |
7 | void main()
8 | {
9 | vec3 m = inColor.xzy;
10 | vec3 dx = dFdx(m);
11 | vec3 dy = dFdy(m);
12 | outDx = vec4(dx, 1.0f);
13 | outDy = vec4(dy, 1.0f);
14 | }
15 |
--------------------------------------------------------------------------------
/test/assets/derivative.frag.spv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keith2018/spvm/a232ea822562dde8d9de47be458a3777392d98bb/test/assets/derivative.frag.spv
--------------------------------------------------------------------------------
/test/assets/derivative.frag.spv.txt:
--------------------------------------------------------------------------------
1 | .\derivative.frag
2 | // Module Version 10000
3 | // Generated by (magic number): 8000a
4 | // Id's are bound by 35
5 |
6 | Capability Shader
7 | 1: ExtInstImport "GLSL.std.450"
8 | MemoryModel Logical GLSL450
9 | EntryPoint Fragment 4 "main" 11 22 29
10 | ExecutionMode 4 OriginUpperLeft
11 | Source GLSL 450
12 | Name 4 "main"
13 | Name 9 "m"
14 | Name 11 "inColor"
15 | Name 14 "dx"
16 | Name 17 "dy"
17 | Name 22 "outDx"
18 | Name 29 "outDy"
19 | Decorate 11(inColor) Location 0
20 | Decorate 22(outDx) Location 0
21 | Decorate 29(outDy) Location 1
22 | 2: TypeVoid
23 | 3: TypeFunction 2
24 | 6: TypeFloat 32
25 | 7: TypeVector 6(float) 3
26 | 8: TypePointer Function 7(fvec3)
27 | 10: TypePointer Input 7(fvec3)
28 | 11(inColor): 10(ptr) Variable Input
29 | 20: TypeVector 6(float) 4
30 | 21: TypePointer Output 20(fvec4)
31 | 22(outDx): 21(ptr) Variable Output
32 | 24: 6(float) Constant 1065353216
33 | 29(outDy): 21(ptr) Variable Output
34 | 4(main): 2 Function None 3
35 | 5: Label
36 | 9(m): 8(ptr) Variable Function
37 | 14(dx): 8(ptr) Variable Function
38 | 17(dy): 8(ptr) Variable Function
39 | 12: 7(fvec3) Load 11(inColor)
40 | 13: 7(fvec3) VectorShuffle 12 12 0 2 1
41 | Store 9(m) 13
42 | 15: 7(fvec3) Load 9(m)
43 | 16: 7(fvec3) DPdx 15
44 | Store 14(dx) 16
45 | 18: 7(fvec3) Load 9(m)
46 | 19: 7(fvec3) DPdy 18
47 | Store 17(dy) 19
48 | 23: 7(fvec3) Load 14(dx)
49 | 25: 6(float) CompositeExtract 23 0
50 | 26: 6(float) CompositeExtract 23 1
51 | 27: 6(float) CompositeExtract 23 2
52 | 28: 20(fvec4) CompositeConstruct 25 26 27 24
53 | Store 22(outDx) 28
54 | 30: 7(fvec3) Load 17(dy)
55 | 31: 6(float) CompositeExtract 30 0
56 | 32: 6(float) CompositeExtract 30 1
57 | 33: 6(float) CompositeExtract 30 2
58 | 34: 20(fvec4) CompositeConstruct 31 32 33 24
59 | Store 29(outDy) 34
60 | Return
61 | FunctionEnd
62 |
--------------------------------------------------------------------------------
/test/assets/function.frag:
--------------------------------------------------------------------------------
1 | #version 450
2 |
3 | #extension GL_GOOGLE_include_directive : require
4 | #include "assert.glsl"
5 |
6 | float func1(float a, float b) {
7 | return a - b;
8 | }
9 |
10 | vec3 func2(vec3 a) {
11 | return a * 0.2f;
12 | }
13 |
14 | void main()
15 | {
16 | ASSERT_BEGIN(32)
17 |
18 | vec3 inColor = vec3(0.2f, 0.3f, 0.4f);
19 | float outColor0 = func1(1.f - inColor.r, func2(inColor).g);
20 | ASSERT(outColor0 == 0.74f)
21 |
22 | vec4 outColor1 = vec4(func2(inColor), func1(1.0f, inColor.r));
23 | ASSERT(outColor1 == vec4(0.04f, 0.06f, 0.08f, 0.8f))
24 |
25 | ASSERT_END
26 | }
27 |
--------------------------------------------------------------------------------
/test/assets/function.frag.spv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keith2018/spvm/a232ea822562dde8d9de47be458a3777392d98bb/test/assets/function.frag.spv
--------------------------------------------------------------------------------
/test/assets/function.frag.spv.txt:
--------------------------------------------------------------------------------
1 | .\function.frag
2 | // Module Version 10000
3 | // Generated by (magic number): 8000a
4 | // Id's are bound by 116
5 |
6 | Capability Shader
7 | 1: ExtInstImport "GLSL.std.450"
8 | MemoryModel Logical GLSL450
9 | EntryPoint Fragment 4 "main" 95
10 | ExecutionMode 4 OriginUpperLeft
11 | Source GLSL 450
12 | SourceExtension "GL_GOOGLE_cpp_style_line_directive"
13 | SourceExtension "GL_GOOGLE_include_directive"
14 | Name 4 "main"
15 | Name 11 "func1(f1;f1;"
16 | Name 9 "a"
17 | Name 10 "b"
18 | Name 17 "func2(vf3;"
19 | Name 16 "a"
20 | Name 31 "assertIdx"
21 | Name 33 "inColor"
22 | Name 37 "outColor0"
23 | Name 44 "param"
24 | Name 47 "param"
25 | Name 48 "param"
26 | Name 56 "asserts"
27 | Name 68 "outColor1"
28 | Name 69 "param"
29 | Name 72 "param"
30 | Name 73 "param"
31 | Name 95 "outAssert"
32 | Name 97 "i"
33 | Decorate 95(outAssert) Location 0
34 | 2: TypeVoid
35 | 3: TypeFunction 2
36 | 6: TypeFloat 32
37 | 7: TypePointer Function 6(float)
38 | 8: TypeFunction 6(float) 7(ptr) 7(ptr)
39 | 13: TypeVector 6(float) 3
40 | 14: TypePointer Function 13(fvec3)
41 | 15: TypeFunction 13(fvec3) 14(ptr)
42 | 25: 6(float) Constant 1045220557
43 | 29: TypeInt 32 1
44 | 30: TypePointer Function 29(int)
45 | 32: 29(int) Constant 0
46 | 34: 6(float) Constant 1050253722
47 | 35: 6(float) Constant 1053609165
48 | 36: 13(fvec3) ConstantComposite 25 34 35
49 | 38: 6(float) Constant 1065353216
50 | 39: TypeInt 32 0
51 | 40: 39(int) Constant 0
52 | 49: 39(int) Constant 1
53 | 52: TypeBool
54 | 53: 39(int) Constant 32
55 | 54: TypeArray 52(bool) 53
56 | 55: TypePointer Function 54
57 | 59: 6(float) Constant 1060991140
58 | 61: TypePointer Function 52(bool)
59 | 64: 29(int) Constant 1
60 | 66: TypeVector 6(float) 4
61 | 67: TypePointer Function 66(fvec4)
62 | 83: 6(float) Constant 1025758986
63 | 84: 6(float) Constant 1031127695
64 | 85: 6(float) Constant 1034147594
65 | 86: 6(float) Constant 1061997773
66 | 87: 66(fvec4) ConstantComposite 83 84 85 86
67 | 88: TypeVector 52(bool) 4
68 | 94: TypePointer Output 29(int)
69 | 95(outAssert): 94(ptr) Variable Output
70 | 96: 29(int) Constant 4294967295
71 | 4(main): 2 Function None 3
72 | 5: Label
73 | 31(assertIdx): 30(ptr) Variable Function
74 | 33(inColor): 14(ptr) Variable Function
75 | 37(outColor0): 7(ptr) Variable Function
76 | 44(param): 14(ptr) Variable Function
77 | 47(param): 7(ptr) Variable Function
78 | 48(param): 7(ptr) Variable Function
79 | 56(asserts): 55(ptr) Variable Function
80 | 68(outColor1): 67(ptr) Variable Function
81 | 69(param): 14(ptr) Variable Function
82 | 72(param): 7(ptr) Variable Function
83 | 73(param): 7(ptr) Variable Function
84 | 97(i): 30(ptr) Variable Function
85 | Store 31(assertIdx) 32
86 | Store 33(inColor) 36
87 | 41: 7(ptr) AccessChain 33(inColor) 40
88 | 42: 6(float) Load 41
89 | 43: 6(float) FSub 38 42
90 | 45: 13(fvec3) Load 33(inColor)
91 | Store 44(param) 45
92 | 46: 13(fvec3) FunctionCall 17(func2(vf3;) 44(param)
93 | Store 47(param) 43
94 | 50: 6(float) CompositeExtract 46 1
95 | Store 48(param) 50
96 | 51: 6(float) FunctionCall 11(func1(f1;f1;) 47(param) 48(param)
97 | Store 37(outColor0) 51
98 | 57: 29(int) Load 31(assertIdx)
99 | 58: 6(float) Load 37(outColor0)
100 | 60: 52(bool) FOrdEqual 58 59
101 | 62: 61(ptr) AccessChain 56(asserts) 57
102 | Store 62 60
103 | 63: 29(int) Load 31(assertIdx)
104 | 65: 29(int) IAdd 63 64
105 | Store 31(assertIdx) 65
106 | 70: 13(fvec3) Load 33(inColor)
107 | Store 69(param) 70
108 | 71: 13(fvec3) FunctionCall 17(func2(vf3;) 69(param)
109 | Store 72(param) 38
110 | 74: 7(ptr) AccessChain 33(inColor) 40
111 | 75: 6(float) Load 74
112 | Store 73(param) 75
113 | 76: 6(float) FunctionCall 11(func1(f1;f1;) 72(param) 73(param)
114 | 77: 6(float) CompositeExtract 71 0
115 | 78: 6(float) CompositeExtract 71 1
116 | 79: 6(float) CompositeExtract 71 2
117 | 80: 66(fvec4) CompositeConstruct 77 78 79 76
118 | Store 68(outColor1) 80
119 | 81: 29(int) Load 31(assertIdx)
120 | 82: 66(fvec4) Load 68(outColor1)
121 | 89: 88(bvec4) FOrdEqual 82 87
122 | 90: 52(bool) All 89
123 | 91: 61(ptr) AccessChain 56(asserts) 81
124 | Store 91 90
125 | 92: 29(int) Load 31(assertIdx)
126 | 93: 29(int) IAdd 92 64
127 | Store 31(assertIdx) 93
128 | Store 95(outAssert) 96
129 | Store 97(i) 32
130 | Branch 98
131 | 98: Label
132 | LoopMerge 100 101 None
133 | Branch 102
134 | 102: Label
135 | 103: 29(int) Load 97(i)
136 | 104: 29(int) Load 31(assertIdx)
137 | 105: 52(bool) SLessThan 103 104
138 | BranchConditional 105 99 100
139 | 99: Label
140 | 106: 29(int) Load 97(i)
141 | 107: 61(ptr) AccessChain 56(asserts) 106
142 | 108: 52(bool) Load 107
143 | 109: 52(bool) LogicalNot 108
144 | SelectionMerge 111 None
145 | BranchConditional 109 110 111
146 | 110: Label
147 | 112: 29(int) Load 97(i)
148 | Store 95(outAssert) 112
149 | Branch 100
150 | 111: Label
151 | Branch 101
152 | 101: Label
153 | 114: 29(int) Load 97(i)
154 | 115: 29(int) IAdd 114 64
155 | Store 97(i) 115
156 | Branch 98
157 | 100: Label
158 | Return
159 | FunctionEnd
160 | 11(func1(f1;f1;): 6(float) Function None 8
161 | 9(a): 7(ptr) FunctionParameter
162 | 10(b): 7(ptr) FunctionParameter
163 | 12: Label
164 | 19: 6(float) Load 9(a)
165 | 20: 6(float) Load 10(b)
166 | 21: 6(float) FSub 19 20
167 | ReturnValue 21
168 | FunctionEnd
169 | 17(func2(vf3;): 13(fvec3) Function None 15
170 | 16(a): 14(ptr) FunctionParameter
171 | 18: Label
172 | 24: 13(fvec3) Load 16(a)
173 | 26: 13(fvec3) VectorTimesScalar 24 25
174 | ReturnValue 26
175 | FunctionEnd
176 |
--------------------------------------------------------------------------------
/test/assets/glsl_std_450_0.frag:
--------------------------------------------------------------------------------
1 | #version 450
2 |
3 | #extension GL_GOOGLE_include_directive : require
4 | #include "assert.glsl"
5 |
6 | #define PI 3.1415926535f
7 |
8 | void main()
9 | {
10 | ASSERT_BEGIN(64)
11 |
12 | // Round
13 | float a = 0.f;
14 | ASSERT(round(a) == 0.f)
15 | a = 0.5f;
16 | ASSERT(round(a) == 1.f)
17 | a = 0.9f;
18 | ASSERT(round(a) == 1.f)
19 | a = -0.f;
20 | ASSERT(round(a) == 0.f)
21 | a = -0.5f;
22 | ASSERT(round(a) == -1.f)
23 | a = -0.9f;
24 | ASSERT(round(a) == -1.f)
25 |
26 | // RoundEven
27 | a = -1.5f;
28 | ASSERT(roundEven(a) == -2.f)
29 | a = 1.5f;
30 | ASSERT(roundEven(a) == 2.f)
31 | a = -2.5f;
32 | ASSERT(roundEven(a) == -2.f)
33 | a = 2.5f;
34 | ASSERT(roundEven(a) == 2.f)
35 | a = -2.6f;
36 | ASSERT(roundEven(a) == -3.f)
37 | a = 2.6f;
38 | ASSERT(roundEven(a) == 3.f)
39 |
40 | // Trunc
41 | a = 1.1f;
42 | ASSERT(trunc(a) == 1.f)
43 | a = -1.1f;
44 | ASSERT(trunc(a) == -1.f)
45 | a = 1.9f;
46 | ASSERT(trunc(a) == 1.f)
47 | a = -1.9f;
48 | ASSERT(trunc(a) == -1.f)
49 |
50 | // FAbs
51 | a = -1.f;
52 | ASSERT(abs(a) == 1.f)
53 |
54 | // SAbs
55 | ivec2 b = ivec2(-2);
56 | ASSERT(abs(b) == ivec2(2))
57 |
58 | // FSign
59 | a = 2.f;
60 | ASSERT(sign(a) == 1.f)
61 | a = 0.f;
62 | ASSERT(sign(a) == 0.f)
63 | a = -2.f;
64 | ASSERT(sign(a) == -1.f)
65 |
66 | // SSign
67 | b = ivec2(-2);
68 | ASSERT(sign(b) == ivec2(-1))
69 | b = ivec2(0);
70 | ASSERT(sign(b) == ivec2(0))
71 | b = ivec2(2);
72 | ASSERT(sign(b) == ivec2(1))
73 |
74 | // Floor
75 | a = 2.8f;
76 | ASSERT(floor(a) == 2.f)
77 | a = -2.8f;
78 | ASSERT(floor(a) == -3.f)
79 |
80 | // Ceil
81 | a = 2.8f;
82 | ASSERT(ceil(a) == 3.f)
83 | a = -2.8f;
84 | ASSERT(ceil(a) == -2.f)
85 |
86 | // Fract
87 | a = 2.8f;
88 | ASSERT(fract(a) == 0.8f)
89 | a = -2.8f;
90 | ASSERT(fract(a) == 0.2f)
91 |
92 | // Radians
93 | a = 180.f;
94 | ASSERT(radians(a) == PI)
95 |
96 | // Degrees
97 | a = PI;
98 | ASSERT(degrees(a) == 180.f)
99 |
100 | // Sin
101 | a = PI;
102 | ASSERT(sin(a) == 0.f)
103 |
104 | // Cos
105 | a = PI;
106 | ASSERT(cos(a) == -1.f)
107 |
108 | // Tan
109 | a = 0.f;
110 | ASSERT(tan(a) == 0.f)
111 |
112 | // Asin
113 | a = 0.f;
114 | ASSERT(asin(a) == 0.f)
115 |
116 | // Acos
117 | a = 1.f;
118 | ASSERT(acos(a) == 0.f)
119 |
120 | // Atan
121 | a = 0.f;
122 | ASSERT(atan(a) == 0.f)
123 |
124 | // Sinh
125 | a = 0.f;
126 | ASSERT(sinh(a) == 0.f)
127 |
128 | // Cosh
129 | a = 0.f;
130 | ASSERT(cosh(a) == 1.f)
131 |
132 | // Tanh
133 | a = 0.f;
134 | ASSERT(tanh(a) == 0.f)
135 |
136 | // Asinh
137 | a = 0.f;
138 | ASSERT(asinh(a) == 0.f)
139 |
140 | // Acosh
141 | a = 1.f;
142 | ASSERT(acosh(a) == 0.f)
143 |
144 | // Atanh
145 | a = 0.f;
146 | ASSERT(atanh(a) == 0.f)
147 |
148 | // Atan2
149 | a = 0.f;
150 | ASSERT(atan(a, 1.f) == 0.f)
151 |
152 | // Pow
153 | a = 2.f;
154 | ASSERT(pow(a, 3) == 8.f)
155 |
156 | // Exp
157 | a = 2.f;
158 | ASSERT(exp(a) == 7.38905609893f)
159 |
160 | // Log
161 | a = 7.38905609893f;
162 | ASSERT(log(a) == 2.f)
163 |
164 | // Exp2
165 | a = 2.f;
166 | ASSERT(exp2(a) == 4.f)
167 |
168 | // Log2
169 | a = 8.f;
170 | ASSERT(log2(a) == 3.f)
171 |
172 | // Sqrt
173 | a = 16.f;
174 | ASSERT(sqrt(a) == 4.f)
175 |
176 | // InverseSqrt
177 | a = 16.f;
178 | ASSERT(inversesqrt(a) == 0.25f)
179 |
180 | ASSERT_END
181 | }
182 |
--------------------------------------------------------------------------------
/test/assets/glsl_std_450_0.frag.spv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keith2018/spvm/a232ea822562dde8d9de47be458a3777392d98bb/test/assets/glsl_std_450_0.frag.spv
--------------------------------------------------------------------------------
/test/assets/glsl_std_450_1.frag:
--------------------------------------------------------------------------------
1 | #version 450
2 |
3 | #extension GL_GOOGLE_include_directive : require
4 | #include "assert.glsl"
5 |
6 | #define PI 3.1415926535f
7 |
8 | void main()
9 | {
10 | ASSERT_BEGIN(64)
11 |
12 | // Determinant
13 | mat2 m1 = mat2(1.f, 0.f, 1.f, 1.f);
14 | float det = determinant(m1);
15 | ASSERT(det == 1.f)
16 |
17 | // MatrixInverse
18 | mat2 m2 = inverse(m1);
19 | ASSERT(m2 == mat2(1.f, 0.f, -1.f, 1.f));
20 |
21 | float f1 = 1.5f;
22 | float f2 = 0.f;
23 | uint u1 = 1;
24 | uint u2 = 2;
25 | int i1 = -1;
26 | int i2 = -2;
27 |
28 | // Modf
29 | ASSERT(modf(f1, f2) == 0.5f)
30 | ASSERT(f2 == 1.f)
31 |
32 | // ModfStruct TODO
33 |
34 | // FMin
35 | f1 = 1.5f;
36 | f2 = 0.f;
37 | ASSERT(min(f1, f2) == 0.f)
38 |
39 | // UMin
40 | ASSERT(min(u1, u2) == 1)
41 |
42 | // SMin
43 | ASSERT(min(i1, i2) == -2)
44 |
45 | // FMax
46 | ASSERT(max(f1, f2) == 1.5f)
47 |
48 | // UMax
49 | ASSERT(max(u1, u2) == 2)
50 |
51 | // SMax
52 | ASSERT(max(i1, i2) == -1)
53 |
54 | // FClamp
55 | ASSERT(clamp(f1, 0.f, 1.f) == 1.f)
56 |
57 | // UClamp
58 | ASSERT(clamp(u1, 0, 1) == 1)
59 |
60 | // SClamp
61 | ASSERT(clamp(i1, 0, 1) == 0)
62 |
63 | // FMix
64 | ASSERT(mix(f1, f2, 0.f) == f1)
65 | ASSERT(mix(f1, f2, 1.f) == f2)
66 | ASSERT(mix(f1, f2, 0.5f) == 0.75f)
67 |
68 | // IMix skip
69 |
70 | // Step
71 | ASSERT(step(1.4f, f1) == 1.f)
72 | ASSERT(step(1.6f, f1) == 0.f)
73 |
74 | // SmoothStep
75 | ASSERT(smoothstep(0.f, 3.f, f1) == 0.5f)
76 |
77 | // Fma
78 | ASSERT(fma(f1, 1.f, 0.5f) == 2.f)
79 |
80 | // Frexp
81 | int n = 0;
82 | ASSERT(frexp(8.f, n) == 0.5f)
83 | ASSERT(n == 4)
84 |
85 | // FrexpStruct TODO
86 |
87 | // Ldexp
88 | n = 4;
89 | ASSERT(ldexp(0.95f, n) == 15.2f)
90 |
91 | // PackSnorm4x8
92 | vec4 v1 = vec4(1.0f, 0.0f, -0.5f, -1.0f);
93 | u1 = 2176843903;
94 | ASSERT(packSnorm4x8(v1) == u1)
95 |
96 | // PackUnorm4x8
97 | vec4 v2 = vec4(1.0f, 0.5f, 0.0f, 1.0f);
98 | u2 = 4278223103;
99 | ASSERT(packUnorm4x8(v2) == u2)
100 |
101 | // PackSnorm2x16
102 | vec2 v3 = vec2(-0.5f, -0.7f);
103 | uint u3 = 2791817216;
104 | ASSERT(packSnorm2x16(v3) == u3)
105 |
106 | // PackUnorm2x16
107 | vec2 v4 = vec2(0.5f, 0.7f);
108 | uint u4 = 3006496768;
109 | ASSERT(packUnorm2x16(v4) == u4)
110 |
111 | // UnpackSnorm2x16
112 | // ASSERT(unpackSnorm2x16(u3) == v3)
113 |
114 | // UnpackUnorm2x16
115 | // ASSERT(unpackUnorm2x16(u4) == v4)
116 |
117 | // UnpackSnorm4x8
118 | // ASSERT(unpackSnorm4x8(u1) == v1)
119 |
120 | // UnpackUnorm4x8
121 | // ASSERT(unpackUnorm4x8(u2) == v2)
122 |
123 | // PackHalf2x16 TODO
124 | // UnpackHalf2x16 TODO
125 | // PackDouble2x32 TODO
126 | // UnpackDouble2x32 TODO
127 |
128 | ASSERT_END
129 | }
130 |
--------------------------------------------------------------------------------
/test/assets/glsl_std_450_1.frag.spv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keith2018/spvm/a232ea822562dde8d9de47be458a3777392d98bb/test/assets/glsl_std_450_1.frag.spv
--------------------------------------------------------------------------------
/test/assets/glsl_std_450_2.frag:
--------------------------------------------------------------------------------
1 | #version 450
2 |
3 | #extension GL_GOOGLE_include_directive : require
4 | #include "assert.glsl"
5 |
6 | #define PI 3.1415926535f
7 |
8 | void main()
9 | {
10 | ASSERT_BEGIN(64)
11 |
12 | // Length
13 | vec2 v2 = vec2(1.f, 0.f);
14 | vec3 v3 = vec3(1.f, 0.f, 0.f);
15 | vec4 v4 = vec4(1.f, 2.f, 3.f, 4.f);
16 | ASSERT(length(v2) == 1.f);
17 | ASSERT(length(v3) == 1.f);
18 | ASSERT(length(v4) == 5.47722578f);
19 |
20 | // Distance
21 | ASSERT(distance(v2, vec2(1.f, 0.f)) == 0.f);
22 | ASSERT(distance(v3, vec3(1.f, 0.f, 1.f)) == 1.f);
23 | ASSERT(distance(v4, vec4(1.f, 0.f, 0.f, 0.f)) == 5.38516474f);
24 |
25 | // Cross
26 | ASSERT(cross(v3, vec3(0.f, 1.f, 0.f)) == vec3(0.f, 0.f, 1.f));
27 | ASSERT(cross(vec3(0.f, 1.f, 0.f), v3) == vec3(0.f, 0.f, -1.f));
28 |
29 | // Normalize
30 | v3 = vec3(1.f, 2.f, 3.f);
31 | ASSERT(normalize(v2) == vec2(1.f, 0.f))
32 | ASSERT(normalize(v3) == vec3(0.267261237f, 0.534522474f, 0.801783681f))
33 |
34 | // FaceForward
35 | vec3 N = vec3(0.0f, 0.0f, 1.0f);
36 | vec3 I = vec3(1.0f, 0.0f, 1.0f);
37 | vec3 Nref = vec3(0.0f, 0.0f, 1.0f);
38 | vec3 F = faceforward(N, I, Nref);
39 | ASSERT(F == vec3(0.f, 0.f, -1.f));
40 |
41 | // Reflect
42 | vec2 A = vec2(1.0f, -1.0f);
43 | vec2 B = vec2(0.0f, 1.0f);
44 | vec2 C = reflect(A, B);
45 | ASSERT(C == vec2(1.f, 1.f))
46 |
47 | // Refract
48 | A = vec2(0.0f, -1.0f);
49 | B = vec2(0.0f, 1.0f);
50 | C = refract(A, B, 0.5f);
51 | ASSERT(C == vec2(0.f, -1.f))
52 |
53 | // FindILsb
54 | ASSERT(findLSB(0x00000001) == 0)
55 | ASSERT(findLSB(0x00000003) == 0)
56 | ASSERT(findLSB(0x00000002) == 1)
57 | ASSERT(findLSB(0x00010000) == 16)
58 | ASSERT(findLSB(0x7FFF0000) == 16)
59 | ASSERT(findLSB(0x7F000000) == 24)
60 | ASSERT(findLSB(0x7F00FF00) == 8)
61 | ASSERT(findLSB(0x00000000) == -1)
62 |
63 | // FindSMsb
64 | int a = 0x00000000;
65 | ASSERT(findMSB(a) == -1)
66 | a = 0x00000001;
67 | ASSERT(findMSB(a) == 0)
68 | a = 0x40000000;
69 | ASSERT(findMSB(a) == 30)
70 | a = -1;
71 | ASSERT(findMSB(a) == -1)
72 |
73 | ivec4 ia = ivec4(0x00000000);
74 | ASSERT(findMSB(ia) == ivec4(-1))
75 | ia = ivec4(0x00000001);
76 | ASSERT(findMSB(ia) == ivec4(0))
77 | ia = ivec4(0x40000000);
78 | ASSERT(findMSB(ia) == ivec4(30))
79 |
80 | // FindUMsb
81 | uint b = 0x00000000;
82 | ASSERT(findMSB(b) == -1)
83 | b = 0x00000001;
84 | ASSERT(findMSB(b) == 0)
85 | b = 0x40000000;
86 | ASSERT(findMSB(b) == 30)
87 |
88 | // InterpolateAtCentroid TODO
89 | // InterpolateAtSample TODO
90 | // InterpolateAtOffset TODO
91 |
92 | // NMin TODO
93 | // NMax TODO
94 | // NClamp TODO
95 |
96 | ASSERT_END
97 | }
98 |
--------------------------------------------------------------------------------
/test/assets/glsl_std_450_2.frag.spv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keith2018/spvm/a232ea822562dde8d9de47be458a3777392d98bb/test/assets/glsl_std_450_2.frag.spv
--------------------------------------------------------------------------------
/test/assets/image.frag:
--------------------------------------------------------------------------------
1 | #version 450
2 |
3 | layout(binding = 0) uniform sampler2D texSampler;
4 |
5 | layout(location = 0) in vec2 fragTexCoord;
6 | layout(location = 1) flat in int inLod;
7 | layout(location = 2) flat in ivec2 inFetchCoord;
8 | layout(location = 3) in vec2 dPdx;
9 | layout(location = 4) in vec2 dPdy;
10 |
11 | layout(location = 0) out vec2 outQueryLod;
12 | layout(location = 1) out ivec2 outTexSize;
13 | layout(location = 2) out int outTexLevel;
14 | layout(location = 3) out vec4 outColorFetch;
15 | layout(location = 4) out vec4 outColorFetchOffset;
16 | layout(location = 5) out vec4 outColorSample;
17 | layout(location = 6) out vec4 outColorSampleGrad;
18 | layout(location = 7) out vec4 outColorSampleLod;
19 | layout(location = 8) out vec4 outColorSampleOffset;
20 |
21 | void main() {
22 | outQueryLod = textureQueryLod(texSampler, fragTexCoord);
23 | outTexSize = textureSize(texSampler, inLod);
24 | outTexLevel = textureQueryLevels(texSampler);
25 |
26 | outColorFetch = texelFetch(texSampler, inFetchCoord, inLod);
27 | outColorFetchOffset = texelFetchOffset(texSampler, inFetchCoord, inLod, ivec2(1, 1));
28 |
29 | outColorSample = texture(texSampler, fragTexCoord);
30 | outColorSampleGrad = textureGrad(texSampler, fragTexCoord, dPdx, dPdy);
31 | outColorSampleLod = textureLod(texSampler, fragTexCoord, inLod);
32 | outColorSampleOffset = textureOffset(texSampler, fragTexCoord, ivec2(1, 0), 0.2f);
33 | }
34 |
--------------------------------------------------------------------------------
/test/assets/image.frag.spv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keith2018/spvm/a232ea822562dde8d9de47be458a3777392d98bb/test/assets/image.frag.spv
--------------------------------------------------------------------------------
/test/assets/image.frag.spv.txt:
--------------------------------------------------------------------------------
1 | image.frag
2 | // Module Version 10000
3 | // Generated by (magic number): 8000a
4 | // Id's are bound by 77
5 |
6 | Capability Shader
7 | Capability ImageQuery
8 | 1: ExtInstImport "GLSL.std.450"
9 | MemoryModel Logical GLSL450
10 | EntryPoint Fragment 4 "main" 9 16 22 25 30 36 39 44 52 56 59 61 64 70
11 | ExecutionMode 4 OriginUpperLeft
12 | Source GLSL 450
13 | Name 4 "main"
14 | Name 9 "outQueryLod"
15 | Name 13 "texSampler"
16 | Name 16 "fragTexCoord"
17 | Name 22 "outTexSize"
18 | Name 25 "inLod"
19 | Name 30 "outTexLevel"
20 | Name 36 "outColorFetch"
21 | Name 39 "inFetchCoord"
22 | Name 44 "outColorFetchOffset"
23 | Name 52 "outColorSample"
24 | Name 56 "outColorSampleGrad"
25 | Name 59 "dPdx"
26 | Name 61 "dPdy"
27 | Name 64 "outColorSampleLod"
28 | Name 70 "outColorSampleOffset"
29 | Decorate 9(outQueryLod) Location 0
30 | Decorate 13(texSampler) DescriptorSet 0
31 | Decorate 13(texSampler) Binding 0
32 | Decorate 16(fragTexCoord) Location 0
33 | Decorate 22(outTexSize) Location 1
34 | Decorate 25(inLod) Flat
35 | Decorate 25(inLod) Location 1
36 | Decorate 30(outTexLevel) Location 2
37 | Decorate 36(outColorFetch) Location 3
38 | Decorate 39(inFetchCoord) Flat
39 | Decorate 39(inFetchCoord) Location 2
40 | Decorate 44(outColorFetchOffset) Location 4
41 | Decorate 52(outColorSample) Location 5
42 | Decorate 56(outColorSampleGrad) Location 6
43 | Decorate 59(dPdx) Location 3
44 | Decorate 61(dPdy) Location 4
45 | Decorate 64(outColorSampleLod) Location 7
46 | Decorate 70(outColorSampleOffset) Location 8
47 | 2: TypeVoid
48 | 3: TypeFunction 2
49 | 6: TypeFloat 32
50 | 7: TypeVector 6(float) 2
51 | 8: TypePointer Output 7(fvec2)
52 | 9(outQueryLod): 8(ptr) Variable Output
53 | 10: TypeImage 6(float) 2D sampled format:Unknown
54 | 11: TypeSampledImage 10
55 | 12: TypePointer UniformConstant 11
56 | 13(texSampler): 12(ptr) Variable UniformConstant
57 | 15: TypePointer Input 7(fvec2)
58 | 16(fragTexCoord): 15(ptr) Variable Input
59 | 19: TypeInt 32 1
60 | 20: TypeVector 19(int) 2
61 | 21: TypePointer Output 20(ivec2)
62 | 22(outTexSize): 21(ptr) Variable Output
63 | 24: TypePointer Input 19(int)
64 | 25(inLod): 24(ptr) Variable Input
65 | 29: TypePointer Output 19(int)
66 | 30(outTexLevel): 29(ptr) Variable Output
67 | 34: TypeVector 6(float) 4
68 | 35: TypePointer Output 34(fvec4)
69 | 36(outColorFetch): 35(ptr) Variable Output
70 | 38: TypePointer Input 20(ivec2)
71 | 39(inFetchCoord): 38(ptr) Variable Input
72 | 44(outColorFetchOffset): 35(ptr) Variable Output
73 | 48: 19(int) Constant 1
74 | 49: 20(ivec2) ConstantComposite 48 48
75 | 52(outColorSample): 35(ptr) Variable Output
76 | 56(outColorSampleGrad): 35(ptr) Variable Output
77 | 59(dPdx): 15(ptr) Variable Input
78 | 61(dPdy): 15(ptr) Variable Input
79 | 64(outColorSampleLod): 35(ptr) Variable Output
80 | 70(outColorSampleOffset): 35(ptr) Variable Output
81 | 73: 19(int) Constant 0
82 | 74: 20(ivec2) ConstantComposite 48 73
83 | 75: 6(float) Constant 1045220557
84 | 4(main): 2 Function None 3
85 | 5: Label
86 | 14: 11 Load 13(texSampler)
87 | 17: 7(fvec2) Load 16(fragTexCoord)
88 | 18: 7(fvec2) ImageQueryLod 14 17
89 | Store 9(outQueryLod) 18
90 | 23: 11 Load 13(texSampler)
91 | 26: 19(int) Load 25(inLod)
92 | 27: 10 Image 23
93 | 28: 20(ivec2) ImageQuerySizeLod 27 26
94 | Store 22(outTexSize) 28
95 | 31: 11 Load 13(texSampler)
96 | 32: 10 Image 31
97 | 33: 19(int) ImageQueryLevels 32
98 | Store 30(outTexLevel) 33
99 | 37: 11 Load 13(texSampler)
100 | 40: 20(ivec2) Load 39(inFetchCoord)
101 | 41: 19(int) Load 25(inLod)
102 | 42: 10 Image 37
103 | 43: 34(fvec4) ImageFetch 42 40 Lod 41
104 | Store 36(outColorFetch) 43
105 | 45: 11 Load 13(texSampler)
106 | 46: 20(ivec2) Load 39(inFetchCoord)
107 | 47: 19(int) Load 25(inLod)
108 | 50: 10 Image 45
109 | 51: 34(fvec4) ImageFetch 50 46 Lod ConstOffset 47 49
110 | Store 44(outColorFetchOffset) 51
111 | 53: 11 Load 13(texSampler)
112 | 54: 7(fvec2) Load 16(fragTexCoord)
113 | 55: 34(fvec4) ImageSampleImplicitLod 53 54
114 | Store 52(outColorSample) 55
115 | 57: 11 Load 13(texSampler)
116 | 58: 7(fvec2) Load 16(fragTexCoord)
117 | 60: 7(fvec2) Load 59(dPdx)
118 | 62: 7(fvec2) Load 61(dPdy)
119 | 63: 34(fvec4) ImageSampleExplicitLod 57 58 Grad 60 62
120 | Store 56(outColorSampleGrad) 63
121 | 65: 11 Load 13(texSampler)
122 | 66: 7(fvec2) Load 16(fragTexCoord)
123 | 67: 19(int) Load 25(inLod)
124 | 68: 6(float) ConvertSToF 67
125 | 69: 34(fvec4) ImageSampleExplicitLod 65 66 Lod 68
126 | Store 64(outColorSampleLod) 69
127 | 71: 11 Load 13(texSampler)
128 | 72: 7(fvec2) Load 16(fragTexCoord)
129 | 76: 34(fvec4) ImageSampleImplicitLod 71 72 Bias ConstOffset 75 74
130 | Store 70(outColorSampleOffset) 76
131 | Return
132 | FunctionEnd
133 |
--------------------------------------------------------------------------------
/test/assets/location.frag:
--------------------------------------------------------------------------------
1 | #version 450
2 |
3 | layout (location = 0) in vec3 inColor;
4 |
5 | layout (location = 0) out vec4 outFragColor;
6 |
7 | void main()
8 | {
9 | outFragColor = vec4(inColor.yxz, 1.0f);
10 | }
11 |
--------------------------------------------------------------------------------
/test/assets/location.frag.spv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keith2018/spvm/a232ea822562dde8d9de47be458a3777392d98bb/test/assets/location.frag.spv
--------------------------------------------------------------------------------
/test/assets/location.frag.spv.txt:
--------------------------------------------------------------------------------
1 | .\location.frag
2 | // Module Version 10000
3 | // Generated by (magic number): 8000a
4 | // Id's are bound by 20
5 |
6 | Capability Shader
7 | 1: ExtInstImport "GLSL.std.450"
8 | MemoryModel Logical GLSL450
9 | EntryPoint Fragment 4 "main" 9 12
10 | ExecutionMode 4 OriginUpperLeft
11 | Source GLSL 450
12 | Name 4 "main"
13 | Name 9 "outFragColor"
14 | Name 12 "inColor"
15 | Decorate 9(outFragColor) Location 0
16 | Decorate 12(inColor) Location 0
17 | 2: TypeVoid
18 | 3: TypeFunction 2
19 | 6: TypeFloat 32
20 | 7: TypeVector 6(float) 4
21 | 8: TypePointer Output 7(fvec4)
22 | 9(outFragColor): 8(ptr) Variable Output
23 | 10: TypeVector 6(float) 3
24 | 11: TypePointer Input 10(fvec3)
25 | 12(inColor): 11(ptr) Variable Input
26 | 15: 6(float) Constant 1065353216
27 | 4(main): 2 Function None 3
28 | 5: Label
29 | 13: 10(fvec3) Load 12(inColor)
30 | 14: 10(fvec3) VectorShuffle 13 13 1 0 2
31 | 16: 6(float) CompositeExtract 14 0
32 | 17: 6(float) CompositeExtract 14 1
33 | 18: 6(float) CompositeExtract 14 2
34 | 19: 7(fvec4) CompositeConstruct 16 17 18 15
35 | Store 9(outFragColor) 19
36 | Return
37 | FunctionEnd
38 |
--------------------------------------------------------------------------------
/test/assets/relational_logical.frag:
--------------------------------------------------------------------------------
1 | #version 450
2 |
3 | #extension GL_GOOGLE_include_directive : require
4 | #include "assert.glsl"
5 |
6 | void main()
7 | {
8 | ASSERT_BEGIN(64)
9 |
10 | bvec2 a = bvec2(true, false);
11 | bvec2 b = bvec2(false, false);
12 | bvec2 c = bvec2(true, true);
13 | bvec2 d = bvec2(false, true);
14 |
15 | // SpvOpAny
16 | ASSERT(any(a))
17 | ASSERT(!any(b))
18 |
19 | // SpvOpAll
20 | ASSERT(!all(a))
21 | ASSERT(!all(b))
22 | ASSERT(all(c))
23 |
24 | float fNan = intBitsToFloat(0x7ff80000); // nan
25 | float fInf = 10.f / 0.f; // inf
26 | vec3 vf = vec3(1.f, fNan, fInf);
27 |
28 | // SpvOpIsNan
29 | ASSERT(isnan(fNan))
30 | ASSERT(isnan(vf) == bvec3(false, true, false))
31 |
32 | // SpvOpIsInf
33 | ASSERT(isinf(fInf))
34 | ASSERT(isinf(vf) == bvec3(false, false, true))
35 |
36 | // SpvOpLogicalEqual
37 | ASSERT(c == bvec2(true))
38 |
39 | // SpvOpLogicalNotEqual
40 | ASSERT(c != bvec2(false))
41 |
42 | // SpvOpLogicalOr
43 | bool b1 = true;
44 | bool b2 = false;
45 | ASSERT((b1 || b2))
46 |
47 | // SpvOpLogicalAnd
48 | ASSERT(!(b1 && b2))
49 |
50 | // SpvOpLogicalNot
51 | ASSERT(not(a) == d)
52 | ASSERT(not(b) == c)
53 |
54 | // SpvOpSelect
55 | ASSERT((b1 ? 0.1f : 0.2f) == 0.1f)
56 | ASSERT((b2 ? 0.1f : 0.2f) == 0.2f)
57 |
58 |
59 | int i1 = -1;
60 | int i2 = -2;
61 | uint u1 = 1;
62 | uint u2 = 2;
63 |
64 | // SpvOpIEqual
65 | ASSERT(i1 - 1 == i2)
66 |
67 | // SpvOpINotEqual
68 | ASSERT(i1 - 2 != i2)
69 |
70 | // SpvOpUGreaterThan
71 | ASSERT(u2 > u1)
72 |
73 | // SpvOpSGreaterThan
74 | ASSERT(i1 > i2)
75 |
76 | // SpvOpUGreaterThanEqual
77 | ASSERT(u2 >= u1)
78 |
79 | // SpvOpSGreaterThanEqual
80 | ASSERT(i1 >= i2)
81 |
82 | // SpvOpULessThan
83 | ASSERT(u1 < u2)
84 |
85 | // SpvOpSLessThan
86 | ASSERT(i2 < i1)
87 |
88 | // SpvOpULessThanEqual
89 | ASSERT(u1 <= u2)
90 |
91 | // SpvOpSLessThanEqual
92 | ASSERT(i2 <= i1)
93 |
94 |
95 | float f1 = 1.f;
96 | float f2 = 2.f;
97 |
98 | // SpvOpFOrdEqual
99 | ASSERT(f1 + 1.f == f2)
100 |
101 | // SpvOpFOrdNotEqual TODO
102 |
103 | // SpvOpFOrdLessThan
104 | ASSERT(f1 < f2)
105 |
106 | // SpvOpFOrdGreaterThan
107 | ASSERT(f2 > f1)
108 |
109 | // SpvOpFOrdLessThanEqual
110 | ASSERT(f1 <= f2)
111 |
112 | // SpvOpFOrdGreaterThanEqual
113 | ASSERT(f2 >= f1)
114 |
115 | // SpvOpFUnordEqual
116 |
117 | // SpvOpFUnordNotEqual
118 | ASSERT(f1 != f2)
119 |
120 | // SpvOpFUnordLessThan TODO
121 | // SpvOpFUnordGreaterThan TODO
122 | // SpvOpFUnordLessThanEqual TODO
123 | // SpvOpFUnordGreaterThanEqual TODO
124 |
125 | ASSERT_END
126 | }
127 |
--------------------------------------------------------------------------------
/test/assets/relational_logical.frag.spv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keith2018/spvm/a232ea822562dde8d9de47be458a3777392d98bb/test/assets/relational_logical.frag.spv
--------------------------------------------------------------------------------
/test/assets/uniform_block.vert:
--------------------------------------------------------------------------------
1 | #version 450
2 | layout (location = 0) in vec3 vPosition;
3 |
4 | layout(set = 0, binding = 0) uniform CameraBuffer
5 | {
6 | vec4 data;
7 | mat4 viewProj;
8 | } cameraData;
9 |
10 | layout(push_constant) uniform constants
11 | {
12 | vec4 data;
13 | mat4 renderMatrix;
14 | } PushConstants;
15 |
16 | void main()
17 | {
18 | mat4 transformMatrix = (cameraData.viewProj * PushConstants.renderMatrix);
19 | gl_Position = transformMatrix * vec4(vPosition, 1.0f);
20 | }
21 |
--------------------------------------------------------------------------------
/test/assets/uniform_block.vert.spv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keith2018/spvm/a232ea822562dde8d9de47be458a3777392d98bb/test/assets/uniform_block.vert.spv
--------------------------------------------------------------------------------
/test/assets/uniform_block.vert.spv.txt:
--------------------------------------------------------------------------------
1 | .\uniform_block.vert
2 | // Module Version 10000
3 | // Generated by (magic number): 8000a
4 | // Id's are bound by 46
5 |
6 | Capability Shader
7 | 1: ExtInstImport "GLSL.std.450"
8 | MemoryModel Logical GLSL450
9 | EntryPoint Vertex 4 "main" 31 36
10 | Source GLSL 450
11 | Name 4 "main"
12 | Name 10 "transformMatrix"
13 | Name 11 "CameraBuffer"
14 | MemberName 11(CameraBuffer) 0 "data"
15 | MemberName 11(CameraBuffer) 1 "viewProj"
16 | Name 13 "cameraData"
17 | Name 19 "constants"
18 | MemberName 19(constants) 0 "data"
19 | MemberName 19(constants) 1 "renderMatrix"
20 | Name 21 "PushConstants"
21 | Name 29 "gl_PerVertex"
22 | MemberName 29(gl_PerVertex) 0 "gl_Position"
23 | MemberName 29(gl_PerVertex) 1 "gl_PointSize"
24 | MemberName 29(gl_PerVertex) 2 "gl_ClipDistance"
25 | MemberName 29(gl_PerVertex) 3 "gl_CullDistance"
26 | Name 31 ""
27 | Name 36 "vPosition"
28 | MemberDecorate 11(CameraBuffer) 0 Offset 0
29 | MemberDecorate 11(CameraBuffer) 1 ColMajor
30 | MemberDecorate 11(CameraBuffer) 1 Offset 16
31 | MemberDecorate 11(CameraBuffer) 1 MatrixStride 16
32 | Decorate 11(CameraBuffer) Block
33 | Decorate 13(cameraData) DescriptorSet 0
34 | Decorate 13(cameraData) Binding 0
35 | MemberDecorate 19(constants) 0 Offset 0
36 | MemberDecorate 19(constants) 1 ColMajor
37 | MemberDecorate 19(constants) 1 Offset 16
38 | MemberDecorate 19(constants) 1 MatrixStride 16
39 | Decorate 19(constants) Block
40 | MemberDecorate 29(gl_PerVertex) 0 BuiltIn Position
41 | MemberDecorate 29(gl_PerVertex) 1 BuiltIn PointSize
42 | MemberDecorate 29(gl_PerVertex) 2 BuiltIn ClipDistance
43 | MemberDecorate 29(gl_PerVertex) 3 BuiltIn CullDistance
44 | Decorate 29(gl_PerVertex) Block
45 | Decorate 36(vPosition) Location 0
46 | 2: TypeVoid
47 | 3: TypeFunction 2
48 | 6: TypeFloat 32
49 | 7: TypeVector 6(float) 4
50 | 8: TypeMatrix 7(fvec4) 4
51 | 9: TypePointer Function 8
52 | 11(CameraBuffer): TypeStruct 7(fvec4) 8
53 | 12: TypePointer Uniform 11(CameraBuffer)
54 | 13(cameraData): 12(ptr) Variable Uniform
55 | 14: TypeInt 32 1
56 | 15: 14(int) Constant 1
57 | 16: TypePointer Uniform 8
58 | 19(constants): TypeStruct 7(fvec4) 8
59 | 20: TypePointer PushConstant 19(constants)
60 | 21(PushConstants): 20(ptr) Variable PushConstant
61 | 22: TypePointer PushConstant 8
62 | 26: TypeInt 32 0
63 | 27: 26(int) Constant 1
64 | 28: TypeArray 6(float) 27
65 | 29(gl_PerVertex): TypeStruct 7(fvec4) 6(float) 28 28
66 | 30: TypePointer Output 29(gl_PerVertex)
67 | 31: 30(ptr) Variable Output
68 | 32: 14(int) Constant 0
69 | 34: TypeVector 6(float) 3
70 | 35: TypePointer Input 34(fvec3)
71 | 36(vPosition): 35(ptr) Variable Input
72 | 38: 6(float) Constant 1065353216
73 | 44: TypePointer Output 7(fvec4)
74 | 4(main): 2 Function None 3
75 | 5: Label
76 | 10(transformMatrix): 9(ptr) Variable Function
77 | 17: 16(ptr) AccessChain 13(cameraData) 15
78 | 18: 8 Load 17
79 | 23: 22(ptr) AccessChain 21(PushConstants) 15
80 | 24: 8 Load 23
81 | 25: 8 MatrixTimesMatrix 18 24
82 | Store 10(transformMatrix) 25
83 | 33: 8 Load 10(transformMatrix)
84 | 37: 34(fvec3) Load 36(vPosition)
85 | 39: 6(float) CompositeExtract 37 0
86 | 40: 6(float) CompositeExtract 37 1
87 | 41: 6(float) CompositeExtract 37 2
88 | 42: 7(fvec4) CompositeConstruct 39 40 41 38
89 | 43: 7(fvec4) MatrixTimesVector 33 42
90 | 45: 44(ptr) AccessChain 31 32
91 | Store 45 43
92 | Return
93 | FunctionEnd
94 |
--------------------------------------------------------------------------------
/test/main.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * spvm
3 | * @author : keith@robot9.me
4 | *
5 | */
6 |
7 | #include "gtest/gtest.h"
8 |
9 | int main(int argc, char *argv[]) {
10 | testing::InitGoogleTest(&argc, argv);
11 | return RUN_ALL_TESTS();
12 | }
13 |
--------------------------------------------------------------------------------
/test/test.h:
--------------------------------------------------------------------------------
1 | /*
2 | * spvm
3 | * @author : keith@robot9.me
4 | *
5 | */
6 |
7 | #pragma once
8 |
9 | #include "gtest/gtest.h"
10 |
11 | #include "decoder.h"
12 | #include "runtime.h"
13 | #include "image.h"
14 |
15 | #define HEAP_SIZE 128 * 1024
16 |
17 | typedef struct TestContext_ {
18 | SPVM::SpvmModule module;
19 | SPVM::Runtime runtime;
20 |
21 | bool decode(const char *path) {
22 | return SPVM::Decoder::decodeFile(path, &module);
23 | }
24 |
25 | bool init() {
26 | return runtime.initWithModule(&module, HEAP_SIZE);
27 | }
28 |
29 | } TestContext;
30 |
31 | #define ASSERT_VEC2_EQ(vec, v0, v1) \
32 | ASSERT_EQ((vec)[0], v0); \
33 | ASSERT_EQ((vec)[1], v1);
34 |
35 | #define ASSERT_VEC3_EQ(vec, v0, v1, v2) \
36 | ASSERT_EQ((vec)[0], v0); \
37 | ASSERT_EQ((vec)[1], v1); \
38 | ASSERT_EQ((vec)[2], v2);
39 |
40 | #define ASSERT_VEC4_EQ(vec, v0, v1, v2, v3) \
41 | ASSERT_EQ((vec)[0], v0); \
42 | ASSERT_EQ((vec)[1], v1); \
43 | ASSERT_EQ((vec)[2], v2); \
44 | ASSERT_EQ((vec)[3], v3);
45 |
46 | #define ASSERT_FLOAT_VEC3_EQ(vec, v0, v1, v2) \
47 | ASSERT_FLOAT_EQ((vec)[0], v0); \
48 | ASSERT_FLOAT_EQ((vec)[1], v1); \
49 | ASSERT_FLOAT_EQ((vec)[2], v2);
50 |
51 | #define ASSERT_FLOAT_VEC4_EQ(vec, v0, v1, v2, v3) \
52 | ASSERT_FLOAT_EQ((vec)[0], v0); \
53 | ASSERT_FLOAT_EQ((vec)[1], v1); \
54 | ASSERT_FLOAT_EQ((vec)[2], v2); \
55 | ASSERT_FLOAT_EQ((vec)[3], v3);
56 |
57 |
58 | #define TEST_GLSL_SPV(name, path) \
59 | TEST(TEST_SPV_EXEC, name) { \
60 | TestContext ctx; \
61 | ASSERT_TRUE(ctx.decode(path)); \
62 | ASSERT_TRUE(ctx.init()); \
63 | ASSERT_TRUE(ctx.runtime.execEntryPoint()); \
64 | int outAssert = -1; \
65 | ctx.runtime.readOutput(&outAssert, 0); \
66 | ASSERT_FLOAT_EQ(outAssert, -1); \
67 | }
68 |
--------------------------------------------------------------------------------
/test/test_core.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * spvm
3 | * @author : keith@robot9.me
4 | *
5 | */
6 |
7 | #include "test.h"
8 |
9 | TEST(TEST_SPV_EXEC, location_frag) {
10 | TestContext ctx;
11 | ASSERT_TRUE(ctx.decode("assets/location.frag.spv"));
12 | ASSERT_TRUE(ctx.init());
13 |
14 | SPVM::SpvmWord inColorIdx = ctx.runtime.getLocationByName("inColor");
15 | SPVM::SpvmWord outColorIdx = ctx.runtime.getLocationByName("outFragColor");
16 |
17 | ASSERT_EQ(inColorIdx, 0);
18 | ASSERT_EQ(outColorIdx, 0);
19 |
20 | float inColor[3]{0.2f, 0.3f, 0.4f};
21 | float outFragColor[4];
22 |
23 | ASSERT_TRUE(ctx.runtime.execEntryPoint());
24 | ctx.runtime.readOutput(outFragColor, outColorIdx);
25 | ASSERT_FLOAT_VEC4_EQ(outFragColor, 0.f, 0.f, 0.f, 1.f)
26 |
27 | ctx.runtime.writeInput(inColor, inColorIdx);
28 | ASSERT_TRUE(ctx.runtime.execEntryPoint());
29 | ctx.runtime.readOutput(outFragColor, outColorIdx);
30 | ASSERT_FLOAT_VEC4_EQ(outFragColor, 0.3f, 0.2f, 0.4f, 1.f)
31 | }
32 |
33 | TEST(TEST_SPV_EXEC, built_in_vert) {
34 | TestContext ctx;
35 | ASSERT_TRUE(ctx.decode("assets/built_in.vert.spv"));
36 | ASSERT_TRUE(ctx.init());
37 |
38 | int inVertexIndex = 0;
39 | float outBuiltInPosition[4];
40 | float outFragColor[3];
41 |
42 | // index 0
43 | inVertexIndex = 0;
44 | ctx.runtime.writeInputBuiltIn(&inVertexIndex, SpvBuiltInVertexIndex);
45 | ASSERT_TRUE(ctx.runtime.execEntryPoint());
46 | ctx.runtime.readOutputBuiltIn(outBuiltInPosition, SpvBuiltInPosition);
47 | ctx.runtime.readOutput(outFragColor, 0);
48 | ASSERT_FLOAT_VEC4_EQ(outBuiltInPosition, 1.f, 1.f, 0.f, 1.f)
49 | ASSERT_FLOAT_VEC3_EQ(outFragColor, 1.f, 0.f, 0.f)
50 |
51 | // index 1
52 | inVertexIndex = 1;
53 | ctx.runtime.writeInputBuiltIn(&inVertexIndex, SpvBuiltInVertexIndex);
54 | ASSERT_TRUE(ctx.runtime.execEntryPoint());
55 | ctx.runtime.readOutputBuiltIn(outBuiltInPosition, SpvBuiltInPosition);
56 | ctx.runtime.readOutput(outFragColor, 0);
57 | ASSERT_FLOAT_VEC4_EQ(outBuiltInPosition, -1.f, 1.f, 0.f, 1.f)
58 | ASSERT_FLOAT_VEC3_EQ(outFragColor, 0.f, 1.f, 0.f)
59 |
60 | // index 2
61 | inVertexIndex = 2;
62 | ctx.runtime.writeInputBuiltIn(&inVertexIndex, SpvBuiltInVertexIndex);
63 | ASSERT_TRUE(ctx.runtime.execEntryPoint());
64 | ctx.runtime.readOutputBuiltIn(outBuiltInPosition, SpvBuiltInPosition);
65 | ctx.runtime.readOutput(outFragColor, 0);
66 | ASSERT_FLOAT_VEC4_EQ(outBuiltInPosition, 0.f, -1.f, 0.f, 1.f)
67 | ASSERT_FLOAT_VEC3_EQ(outFragColor, 0.f, 0.f, 1.f)
68 | }
69 |
70 | TEST(TEST_SPV_EXEC, uniform_block_vert) {
71 | TestContext ctx;
72 | ASSERT_TRUE(ctx.decode("assets/uniform_block.vert.spv"));
73 | ASSERT_TRUE(ctx.init());
74 |
75 | SPVM::SpvmWord vPositionIdx = ctx.runtime.getLocationByName("vPosition");
76 | SPVM::SpvmUniformBinding cameraDataIdx = ctx.runtime.getBindingByName("cameraData");
77 |
78 | ASSERT_EQ(vPositionIdx, 0);
79 | ASSERT_EQ(cameraDataIdx.binding, 0);
80 | ASSERT_EQ(cameraDataIdx.set, 0);
81 |
82 | float vPosition[3]{0.2f, 0.3f, 0.4f};
83 | struct {
84 | float data[4] = {0.f, 0.f, 0.f, 0.f};
85 | float viewProj[16] = {
86 | 1.f, 1.f, 0.f, 0.f,
87 | 0.f, 1.f, 0.f, 0.f,
88 | 0.f, 0.f, 1.f, 0.f,
89 | 0.f, 0.f, 0.f, 1.f
90 | };
91 | } cameraData;
92 | struct {
93 | float data[4] = {0.f, 0.f, 0.f, 0.f};
94 | float renderMatrix[16] = {
95 | 1.f, 2.f, 0.f, 0.f,
96 | 0.f, 1.f, 0.f, 0.f,
97 | 0.f, 0.f, 1.f, 0.f,
98 | 0.f, 0.f, 0.f, 1.f
99 | };
100 | } pushConstants;
101 | float outBuiltInPosition[4];
102 |
103 | ctx.runtime.writeInput(vPosition, vPositionIdx);
104 | ctx.runtime.writeUniformBinding(&cameraData, sizeof(cameraData),
105 | cameraDataIdx.binding, cameraDataIdx.set);
106 | ctx.runtime.writeUniformPushConstants(&pushConstants, sizeof(pushConstants));
107 | ASSERT_TRUE(ctx.runtime.execEntryPoint());
108 | ctx.runtime.readOutputBuiltIn(outBuiltInPosition, SpvBuiltInPosition);
109 | ASSERT_FLOAT_VEC4_EQ(outBuiltInPosition, 0.2f, 0.9f, 0.4f, 1.f)
110 | }
111 |
112 | TEST(TEST_SPV_EXEC, array_frag) {
113 | TestContext ctx;
114 | ASSERT_TRUE(ctx.decode("assets/array.frag.spv"));
115 | ASSERT_TRUE(ctx.init());
116 |
117 | struct {
118 | float a[3] = {4.2f, 5.0f, 5.2f};
119 | float b[6] = {1.2f, 1.0f, 1.3f, 0.2f, 0.3f, 0.5f};
120 | } tb;
121 | ctx.runtime.writeUniformBinding(&tb, sizeof(tb), 0, 0);
122 | ASSERT_TRUE(ctx.runtime.execEntryPoint());
123 |
124 | int outAssert = -1;
125 | ctx.runtime.readOutput(&outAssert, 0);
126 | ASSERT_FLOAT_EQ(outAssert, -1);
127 | }
128 |
129 | TEST_GLSL_SPV(control_flow_frag, "assets/control_flow.frag.spv")
130 | TEST_GLSL_SPV(arithmetic_0_frag, "assets/arithmetic_0.frag.spv")
131 | TEST_GLSL_SPV(arithmetic_1_frag, "assets/arithmetic_1.frag.spv")
132 | TEST_GLSL_SPV(function_frag, "assets/function.frag.spv")
133 | TEST_GLSL_SPV(conversion_frag, "assets/conversion.frag.spv")
134 | TEST_GLSL_SPV(composite_frag, "assets/composite.frag.spv")
135 | TEST_GLSL_SPV(bit_frag, "assets/bit.frag.spv")
136 | TEST_GLSL_SPV(relational_logical, "assets/relational_logical.frag.spv")
137 |
--------------------------------------------------------------------------------
/test/test_ext.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * spvm
3 | * @author : keith@robot9.me
4 | *
5 | */
6 |
7 | #include "test.h"
8 |
9 | TEST_GLSL_SPV(glsl_std_450_0, "assets/glsl_std_450_0.frag.spv")
10 | TEST_GLSL_SPV(glsl_std_450_1, "assets/glsl_std_450_1.frag.spv")
11 | TEST_GLSL_SPV(glsl_std_450_2, "assets/glsl_std_450_2.frag.spv")
12 |
--------------------------------------------------------------------------------
/test/test_image.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * spvm
3 | * @author : keith@robot9.me
4 | *
5 | */
6 |
7 | #include "test.h"
8 |
9 | typedef struct ImageContext_ {
10 | SPVM::SpvmImage *spvmImage;
11 | SPVM::SpvmSampler *spvmSampler;
12 | SPVM::SpvmSampledImage *spvmSampledImage;
13 |
14 | void create2d(int32_t width, int32_t height, int32_t mipLevels = 1) {
15 | SPVM::SpvmImageInfo imageInfo;
16 | imageInfo.dim = SpvDim2D;
17 | imageInfo.format = SPVM::SPVM_FORMAT_R8G8B8A8_UNORM;
18 | imageInfo.width = width;
19 | imageInfo.height = height;
20 | imageInfo.depth = 1;
21 | imageInfo.mipmaps = mipLevels > 1;
22 | imageInfo.baseMipLevel = 0;
23 | imageInfo.mipLevels = mipLevels;
24 | imageInfo.arrayed = false;
25 | imageInfo.baseArrayLayer = 0;
26 | imageInfo.arrayLayers = 1;
27 | imageInfo.samples = 1;
28 |
29 | spvmImage = SPVM::createImage(&imageInfo);
30 | spvmSampler = SPVM::createSampler();
31 | spvmSampledImage = SPVM::createSampledImage(spvmImage, spvmSampler);
32 | }
33 |
34 | void destroy() {
35 | SPVM::destroyImage(spvmImage);
36 | SPVM::destroySampler(spvmSampler);
37 | SPVM::destroySampledImager(spvmSampledImage);
38 | }
39 | } ImageContext;
40 |
41 | static uint8_t pixelBytes2D[] = {255, 0, 0, 255, 0, 255, 0, 255,
42 | 0, 0, 255, 255, 0, 0, 0, 255,
43 | 255, 0, 0, 255, 255, 0, 0, 255,
44 | 255, 0, 0, 255, 255, 0, 0, 255,
45 | 255, 0, 0, 255, 255, 0, 0, 255,
46 | 255, 0, 0, 255, 255, 0, 0, 255,
47 | 255, 0, 0, 255, 255, 0, 0, 255,
48 | 255, 0, 0, 255, 255, 0, 0, 255,};
49 |
50 | static uint8_t pixelBytes2D_mip[] = {128, 0, 0, 128, 0, 128, 0, 128,
51 | 0, 0, 128, 255, 0, 0, 0, 128,};
52 |
53 | TEST(TEST_SPV_EXEC, image_2d_query_frag) {
54 | TestContext ctx;
55 | ASSERT_TRUE(ctx.decode("assets/image.frag.spv"));
56 | ASSERT_TRUE(ctx.init());
57 |
58 | ImageContext imageCtx;
59 | imageCtx.create2d(4, 4, 2);
60 | imageCtx.spvmSampler->info.unnormalizedCoordinates = true;
61 | imageCtx.spvmSampler->info.mipmapMode = SpvSamplerFilterModeLinear;
62 | SPVM::uploadImageData(imageCtx.spvmImage, pixelBytes2D, sizeof(pixelBytes2D), 4, 4, 1, 0);
63 | SPVM::uploadImageData(imageCtx.spvmImage, pixelBytes2D_mip, sizeof(pixelBytes2D_mip), 2, 2, 1, 1);
64 | ctx.runtime.writeUniformBinding(imageCtx.spvmSampledImage, 0, 0, 0);
65 |
66 | SPVM::SpvmWord outQueryLodLoc = ctx.runtime.getLocationByName("outQueryLod");
67 | SPVM::SpvmWord outTexSizeLoc = ctx.runtime.getLocationByName("outTexSize");
68 | SPVM::SpvmWord outTexLevelLoc = ctx.runtime.getLocationByName("outTexLevel");
69 |
70 | // textureQueryLod
71 | float fragTexCoord[2]{0.f, 0.f};
72 | float outQueryLod[2];
73 | ctx.runtime.writeInput(fragTexCoord, 0);
74 | ASSERT_TRUE(ctx.runtime.execEntryPoint());
75 | ctx.runtime.readOutput(&outQueryLod, outQueryLodLoc);
76 | ASSERT_VEC2_EQ(outQueryLod, 0.f, 0.f);
77 |
78 | // textureSize
79 | int32_t inLod[1]{0};
80 | int32_t outTexSize[2];
81 | ctx.runtime.writeInput(inLod, 1);
82 | ASSERT_TRUE(ctx.runtime.execEntryPoint());
83 | ctx.runtime.readOutput(&outTexSize, outTexSizeLoc);
84 | ASSERT_VEC2_EQ(outTexSize, 4, 4);
85 |
86 | inLod[0] = 1;
87 | ctx.runtime.writeInput(inLod, 1);
88 | ASSERT_TRUE(ctx.runtime.execEntryPoint());
89 | ctx.runtime.readOutput(&outTexSize, outTexSizeLoc);
90 | ASSERT_VEC2_EQ(outTexSize, 2, 2);
91 |
92 | // textureQueryLevels
93 | int32_t outTexLevel[1];
94 | ctx.runtime.readOutput(&outTexLevel, outTexLevelLoc);
95 | ASSERT_EQ(outTexLevel[0], 2);
96 |
97 | imageCtx.destroy();
98 | }
99 |
100 | TEST(TEST_SPV_EXEC, image_2d_fetch_frag) {
101 | TestContext ctx;
102 | ASSERT_TRUE(ctx.decode("assets/image.frag.spv"));
103 | ASSERT_TRUE(ctx.init());
104 |
105 | ImageContext imageCtx;
106 | imageCtx.create2d(4, 4, 2);
107 | imageCtx.spvmSampler->info.unnormalizedCoordinates = true;
108 | imageCtx.spvmSampler->info.mipmapMode = SpvSamplerFilterModeLinear;
109 | SPVM::uploadImageData(imageCtx.spvmImage, pixelBytes2D, sizeof(pixelBytes2D), 4, 4, 1, 0);
110 | SPVM::uploadImageData(imageCtx.spvmImage, pixelBytes2D_mip, sizeof(pixelBytes2D_mip), 2, 2, 1, 1);
111 | ctx.runtime.writeUniformBinding(imageCtx.spvmSampledImage, 0, 0, 0);
112 |
113 | SPVM::SpvmWord outColorFetchLoc = ctx.runtime.getLocationByName("outColorFetch");
114 | SPVM::SpvmWord outColorFetchOffsetLoc = ctx.runtime.getLocationByName("outColorFetchOffset");
115 |
116 | int32_t inLod[1]{1};
117 | int32_t fragTexCoord[2]{0, 0};
118 |
119 | // texelFetch
120 | ctx.runtime.writeInput(fragTexCoord, 0);
121 | ctx.runtime.writeInput(inLod, 1);
122 | ASSERT_TRUE(ctx.runtime.execEntryPoint());
123 | float outColorFetch[4];
124 | ctx.runtime.readOutput(&outColorFetch, outColorFetchLoc);
125 | ASSERT_VEC4_EQ(outColorFetch, 128.f / 255.f, 0.f, 0.f, 128.f / 255.f);
126 |
127 | // texelFetchOffset
128 | ASSERT_TRUE(ctx.runtime.execEntryPoint());
129 | float outColorFetchOffset[4];
130 | ctx.runtime.readOutput(&outColorFetchOffset, outColorFetchOffsetLoc);
131 | ASSERT_VEC4_EQ(outColorFetchOffset, 0.f, 0.f, 0.f, 128.f / 255.f);
132 |
133 | imageCtx.destroy();
134 | }
135 |
136 | TEST(TEST_SPV_EXEC, image_2d_lookup_frag) {
137 | TestContext ctx;
138 | ASSERT_TRUE(ctx.decode("assets/image.frag.spv"));
139 | ASSERT_TRUE(ctx.init());
140 |
141 | ImageContext imageCtx;
142 | imageCtx.create2d(4, 4, 2);
143 | imageCtx.spvmSampler->info.unnormalizedCoordinates = true;
144 | imageCtx.spvmSampler->info.mipmapMode = SpvSamplerFilterModeLinear;
145 | SPVM::uploadImageData(imageCtx.spvmImage, pixelBytes2D, sizeof(pixelBytes2D), 4, 4, 1, 0);
146 | SPVM::uploadImageData(imageCtx.spvmImage, pixelBytes2D_mip, sizeof(pixelBytes2D_mip), 2, 2, 1, 1);
147 | ctx.runtime.writeUniformBinding(imageCtx.spvmSampledImage, 0, 0, 0);
148 |
149 | float fragTexCoord[2]{0.f, 0.f};
150 | SPVM::SpvmWord outLoc = ctx.runtime.getLocationByName("outColorSample");
151 |
152 | // texture
153 | float outColorSample[4];
154 | ctx.runtime.writeInput(fragTexCoord, 0);
155 | ASSERT_TRUE(ctx.runtime.execEntryPoint());
156 | ctx.runtime.readOutput(&outColorSample, outLoc);
157 | ASSERT_VEC4_EQ(outColorSample, 1.f, 0.f, 0.f, 1.f);
158 |
159 | fragTexCoord[0] = 1.f;
160 | ctx.runtime.writeInput(fragTexCoord, 0);
161 | ASSERT_TRUE(ctx.runtime.execEntryPoint());
162 | ctx.runtime.readOutput(&outColorSample, outLoc);
163 | ASSERT_VEC4_EQ(outColorSample, 0.f, 1.f, 0.f, 1.f);
164 |
165 | fragTexCoord[0] = 5.f;
166 | ctx.runtime.writeInput(fragTexCoord, 0);
167 | imageCtx.spvmSampler->info.addressModeU = SpvSamplerAddressingModeClampToEdge;
168 | ASSERT_TRUE(ctx.runtime.execEntryPoint());
169 | ctx.runtime.readOutput(&outColorSample, outLoc);
170 | ASSERT_VEC4_EQ(outColorSample, 0.f, 0.f, 0.f, 1.f);
171 |
172 | fragTexCoord[0] = 5.f;
173 | ctx.runtime.writeInput(fragTexCoord, 0);
174 | imageCtx.spvmSampler->info.addressModeU = SpvSamplerAddressingModeClamp;
175 | ASSERT_TRUE(ctx.runtime.execEntryPoint());
176 | ctx.runtime.readOutput(&outColorSample, outLoc);
177 | ASSERT_VEC4_EQ(outColorSample, 0.f, 0.f, 0.f, 0.f);
178 |
179 | fragTexCoord[0] = 5.f;
180 | ctx.runtime.writeInput(fragTexCoord, 0);
181 | imageCtx.spvmSampler->info.addressModeU = SpvSamplerAddressingModeRepeat;
182 | ASSERT_TRUE(ctx.runtime.execEntryPoint());
183 | ctx.runtime.readOutput(&outColorSample, outLoc);
184 | ASSERT_VEC4_EQ(outColorSample, 0.f, 1.f, 0.f, 1.f);
185 |
186 | fragTexCoord[0] = 5.f;
187 | ctx.runtime.writeInput(fragTexCoord, 0);
188 | imageCtx.spvmSampler->info.addressModeU = SpvSamplerAddressingModeRepeatMirrored;
189 | ASSERT_TRUE(ctx.runtime.execEntryPoint());
190 | ctx.runtime.readOutput(&outColorSample, outLoc);
191 | ASSERT_VEC4_EQ(outColorSample, 0.f, 0.f, 1.f, 1.f);
192 |
193 | // textureGrad TODO
194 |
195 | // textureLod
196 | int32_t inLod[1]{1};
197 | fragTexCoord[0] = 0.f;
198 | fragTexCoord[1] = 0.f;
199 | ctx.runtime.writeInput(inLod, 1);
200 | ctx.runtime.writeInput(fragTexCoord, 0);
201 | ASSERT_TRUE(ctx.runtime.execEntryPoint());
202 | outLoc = ctx.runtime.getLocationByName("outColorSampleLod");
203 | float outColorSampleLod[4];
204 | ctx.runtime.readOutput(&outColorSampleLod, outLoc);
205 | ASSERT_VEC4_EQ(outColorSampleLod, 128.f / 255.f, 0.f, 0.f, 128.f / 255.f);
206 |
207 | // textureOffset
208 | fragTexCoord[0] = 0.f;
209 | fragTexCoord[1] = 0.f;
210 | ctx.runtime.writeInput(fragTexCoord, 0);
211 | ASSERT_TRUE(ctx.runtime.execEntryPoint());
212 | outLoc = ctx.runtime.getLocationByName("outColorSampleOffset");
213 | float outColorSampleOffset[4];
214 | ctx.runtime.readOutput(&outColorSampleOffset, outLoc);
215 | ASSERT_VEC4_EQ(outColorSampleOffset, 0.f, 1.f, 0.f, 1.f);
216 |
217 | imageCtx.destroy();
218 | }
--------------------------------------------------------------------------------
/test/tools/glsl.py:
--------------------------------------------------------------------------------
1 | import sys, os
2 |
3 | glslangValidator_name = 'glslangValidator'
4 | if sys.platform == 'win32':
5 | glslangValidator_name = 'glslangValidator.exe'
6 |
7 |
8 | def glsl_cvt(filename):
9 | cmd = "%s -H -V %s -o %s.spv > %s.spv.txt" % (glslangValidator_name, filename, filename, filename)
10 | os.system(cmd)
11 |
12 |
13 | if __name__ == "__main__":
14 | glsl_cvt(sys.argv[1])
--------------------------------------------------------------------------------