├── samples ├── shaders │ ├── quad.hlsl │ ├── generic-frag-shader-input.hlsl │ ├── fullscreen-triangle.hlsl │ ├── simple-texture.hlsl │ ├── imgui.hlsl │ ├── triangle.hlsl │ ├── quat.hlsl │ ├── volume-renderer.hlsl │ ├── compute-demo.hlsl │ ├── cubemap.hlsl │ ├── polygon.hlsl │ ├── instancing.hlsl │ ├── compute-vertices.hlsl │ ├── textured-quad.hlsl │ └── blinn-phong.hlsl ├── common │ ├── staging-image.h │ ├── platform │ │ └── macos │ │ │ ├── glfw-cocoa-contentview.h │ │ │ └── glfw-cocoa-contentview.mm │ ├── diagnostic-callback.h │ ├── diagnostic-callback.cpp │ ├── camera-controller.h │ ├── staging-image.cpp │ ├── imgui-backend.h │ ├── camera-controller.cpp │ └── sample-interface.h ├── 00-template │ └── sample-impl.cpp ├── 01-fullscreen-triangle │ └── fullscreen-triangle.cpp ├── 0a-compute-mandelbrot │ └── compute-mandelbrot.cpp └── 02-render-to-texture │ └── render-to-texture.cpp ├── source ├── ngf-common │ ├── hash-table.h │ ├── frame-token.h │ ├── cmdbuf-state.h │ ├── native-binding-map.h │ ├── stack-alloc.h │ ├── cmdbuf-state.c │ ├── internal.c │ ├── block-alloc.h │ ├── dynamic-array.h │ ├── list.h │ ├── util.c │ ├── chunk-list.h │ ├── dict.h │ ├── stack-alloc.c │ ├── macros.h │ └── native-binding-map.c ├── ngf-vk │ └── ca-metal-layer.mm └── ngf-mtl │ └── layer.mm ├── tests ├── image-comparison │ ├── .gitignore │ ├── references │ │ └── triangle_reference.data │ ├── testcases │ │ └── ngf-triangle-test.cpp │ ├── CMakeLists.txt │ └── framework │ │ └── main.cpp ├── test-suite-runner.c └── nicetest.h ├── docs ├── logo.png ├── logo.xcf └── doxygen │ └── custom.css ├── deps ├── vma │ ├── src │ │ └── vk_mem_alloc.cpp │ ├── CMakeLists.txt │ └── LICENSE.txt ├── SPIRV-reflect │ └── CMakeLists.txt └── vulkan-headers │ └── vulkan │ ├── vulkan_ios.h │ ├── vulkan_macos.h │ ├── vulkan.h │ ├── vulkan_xcb.h │ ├── vk_platform.h │ └── vulkan_metal.h ├── .gitignore ├── .gitmodules ├── .github └── workflows │ └── tests.yml ├── README.md ├── misc ├── common │ ├── shader-loader.h │ ├── file-utils.h │ ├── mesh-loader.h │ ├── file-utils.cpp │ ├── targa-loader.h │ ├── logging.h │ ├── shader-loader.cpp │ ├── check.h │ ├── CMakeLists.txt │ ├── mesh-loader.cpp │ └── targa-loader.cpp └── shaders.cmake ├── .clang-format └── include ├── nicegraf-vk-handles.h ├── nicegraf-util.h └── nicegraf-mtl-handles.h /samples/shaders/quad.hlsl: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /source/ngf-common/hash-table.h: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/image-comparison/.gitignore: -------------------------------------------------------------------------------- 1 | build/* -------------------------------------------------------------------------------- /tests/test-suite-runner.c: -------------------------------------------------------------------------------- 1 | #define NT_IMPL 2 | #include "nicetest.h" 3 | -------------------------------------------------------------------------------- /docs/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicebyte/nicegraf/HEAD/docs/logo.png -------------------------------------------------------------------------------- /docs/logo.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicebyte/nicegraf/HEAD/docs/logo.xcf -------------------------------------------------------------------------------- /deps/vma/src/vk_mem_alloc.cpp: -------------------------------------------------------------------------------- 1 | #define VMA_IMPLEMENTATION 2 | #define WIN32_LEAN_AND_MEAN 3 | #include "vk_mem_alloc.h" -------------------------------------------------------------------------------- /tests/image-comparison/references/triangle_reference.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicebyte/nicegraf/HEAD/tests/image-comparison/references/triangle_reference.data -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/* 2 | tests/build/* 3 | docs/doxygen/html 4 | docs/doxygen/xml 5 | docs/doxygen/latex 6 | tests/ngf_tests 7 | samples/binaries/* 8 | samples/deps/niceshade/* 9 | /out/build/x64-Debug 10 | /.vs 11 | samples-build-files/* 12 | .gitmodules 13 | .idea 14 | cmake-build-debug-visual-studio 15 | docs/doxygen 16 | **/.DS_Store 17 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "samples/deps/imgui"] 2 | path = samples/deps/imgui 3 | url = https://github.com/ocornut/imgui 4 | [submodule "samples/deps/nicemath"] 5 | path = samples/deps/nicemath 6 | url = https://github.com/nicebyte/nicemath 7 | [submodule "samples/deps/glfw"] 8 | path = samples/deps/glfw 9 | url = https://github.com/glfw/glfw 10 | branch = 3.3-stable -------------------------------------------------------------------------------- /deps/SPIRV-reflect/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14.0) 2 | project(spvreflect) 3 | 4 | set(CMAKE_C_STANDARD 99) 5 | 6 | add_library(spvreflect STATIC 7 | ${CMAKE_CURRENT_LIST_DIR}/include/spirv/unified1/spirv.h 8 | ${CMAKE_CURRENT_LIST_DIR}/spirv_reflect.h 9 | ${CMAKE_CURRENT_LIST_DIR}/spirv_reflect.c) 10 | 11 | target_include_directories(spvreflect PUBLIC ${CMAKE_CURRENT_LIST_DIR}) 12 | -------------------------------------------------------------------------------- /samples/shaders/generic-frag-shader-input.hlsl: -------------------------------------------------------------------------------- 1 | struct GenericFragShaderInput { 2 | float4 position : SV_Position; 3 | 4 | #if defined(GENERIC_FS_INPUT_HAS_COLOR) 5 | float4 color : NGF_COLOR; 6 | #endif 7 | 8 | #if defined(GENERIC_FS_INPUT_HAS_CLIPSPACE_POS) 9 | float4 clipSpacePosition : NGF_CLIP_SPACE_POSITION; 10 | #endif 11 | 12 | #if defined(GENERIC_FS_INPUT_HAS_UV) 13 | float2 textureUv : NGF_UV; 14 | #endif 15 | 16 | }; -------------------------------------------------------------------------------- /samples/shaders/fullscreen-triangle.hlsl: -------------------------------------------------------------------------------- 1 | //T: fullscreen-triangle ps:PSMain vs:VSMain 2 | //T: small-triangle ps:PSMain vs:VSMain define:SCALE=0.25 3 | 4 | #define GENERIC_FS_INPUT_HAS_COLOR 5 | #include "triangle.hlsl" 6 | 7 | #ifndef SCALE 8 | #define SCALE 1.0 9 | #endif 10 | 11 | float4 PSMain(GenericFragShaderInput vertexAttribs) : SV_TARGET { 12 | return vertexAttribs.color; 13 | } 14 | 15 | GenericFragShaderInput VSMain(uint vertexId : SV_VertexID) { 16 | return TriangleVertex(vertexId, SCALE, 0.0, 0.0); 17 | } 18 | -------------------------------------------------------------------------------- /docs/doxygen/custom.css: -------------------------------------------------------------------------------- 1 | body { max-width: 120ch; margin-left:auto; margin-right: auto;} 2 | .memtitle { background-image: none } 3 | .fieldtable th {background-image: none } 4 | .sm-dox { background-image: none; background: #f9fafc } 5 | h1.groupheader{ border-bottom: none; } 6 | h2.groupheader{ border-bottom: none; } 7 | h3.groupheader{ border-bottom: none; } 8 | div.header { background-image: none; background: inherit; border-bottom: none; } 9 | #titlearea { padding-bottom: 18pt } 10 | div.header { margin-top: 8pt } 11 | div.fragment { padding: 8pt } -------------------------------------------------------------------------------- /samples/shaders/simple-texture.hlsl: -------------------------------------------------------------------------------- 1 | // T: simple-texture vs:VSMain ps:PSMain 2 | 3 | #define GENERIC_FS_INPUT_HAS_UV 4 | #include "triangle.hlsl" 5 | 6 | [[vk::binding(1, 0)]] uniform Texture2D textureImage; 7 | [[vk::binding(2, 0)]] uniform sampler imageSampler; 8 | 9 | float4 PSMain(GenericFragShaderInput vertexAttribs) : SV_Target { 10 | return textureImage.Sample(imageSampler, vertexAttribs.textureUv); 11 | } 12 | 13 | GenericFragShaderInput VSMain(uint vertexId : SV_VertexID) { 14 | return TriangleVertex(vertexId, 1.0, 0.0, 0.0); 15 | } 16 | -------------------------------------------------------------------------------- /deps/vma/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0.2) 2 | 3 | project(vma) 4 | 5 | 6 | add_library(vma STATIC 7 | ${CMAKE_CURRENT_LIST_DIR}/src/vk_mem_alloc.cpp 8 | ${CMAKE_CURRENT_LIST_DIR}/src/vk_mem_alloc.h) 9 | 10 | if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") 11 | target_compile_options(vma PRIVATE -Wno-nullability-completeness) 12 | endif() 13 | 14 | target_include_directories(vma PRIVATE ${CMAKE_CURRENT_LIST_DIR}/../vulkan-headers) 15 | target_include_directories(vma PUBLIC 16 | ${CMAKE_CURRENT_LIST_DIR}/src) 17 | target_compile_definitions(vma PUBLIC VMA_STATS_STRING_ENABLED=0) 18 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Run tests 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | env: 9 | CC: /usr/bin/clang 10 | CXX: /usr/bin/clang++ 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | - name: update_apt 20 | run: sudo apt-get update 21 | - name: install_deps 22 | run: sudo apt install libx11-xcb-dev 23 | - name: make_build_dir 24 | run: mkdir -p build 25 | - name: run_cmake 26 | run: cd ./build && cmake .. -DNGF_BUILD_TESTS=yes 27 | - name: make 28 | run: cd ./build && make internal-utils-tests && make vk-backend-tests 29 | - name: test 30 | run: ./build/internal-utils-tests && ./build/vk-backend-tests 31 | -------------------------------------------------------------------------------- /samples/shaders/imgui.hlsl: -------------------------------------------------------------------------------- 1 | //T: imgui ps:PSMain vs:VSMain 2 | 3 | #define GENERIC_FS_INPUT_HAS_UV 4 | #define GENERIC_FS_INPUT_HAS_COLOR 5 | #include "generic-frag-shader-input.hlsl" 6 | 7 | struct ImGuiVSInput { 8 | float2 position : ATTR0; 9 | float2 uv : TEXCOORD0; 10 | float4 color : COLOR0; 11 | }; 12 | 13 | struct VertShaderUniforms { 14 | float4x4 projectionTransform; 15 | }; 16 | 17 | [[vk::binding(0, 0)]] ConstantBuffer vertShaderUniforms; 18 | 19 | GenericFragShaderInput VSMain(ImGuiVSInput input) { 20 | GenericFragShaderInput vertexData = { 21 | mul(vertShaderUniforms.projectionTransform, 22 | float4(input.position, 0.0, 1.0)), 23 | input.color, 24 | input.uv 25 | }; 26 | return vertexData; 27 | } 28 | 29 | [[vk::binding(1, 0)]] uniform Texture2D textureImage; 30 | [[vk::binding(2, 0)]] uniform sampler imageSampler; 31 | 32 | float4 PSMain(GenericFragShaderInput vertexAttribs) : SV_Target { 33 | return vertexAttribs.color * textureImage.Sample(imageSampler, vertexAttribs.textureUv); 34 | } 35 | -------------------------------------------------------------------------------- /samples/shaders/triangle.hlsl: -------------------------------------------------------------------------------- 1 | #include "generic-frag-shader-input.hlsl" 2 | 3 | GenericFragShaderInput TriangleVertex(uint vertexId, float scale, float2 offset, float depth) { 4 | float4 pos[] = { 5 | float4(-1.0, 1.0, 0.0, 1.0), 6 | float4( 3.0, 1.0, 0.0, 1.0), 7 | float4(-1.0, -3.0, 0.0, 1.0) 8 | }; 9 | const float2 texcoords[] = { 10 | float2(0.0, 1.0), float2(2.0, 1.0), float2(0.0, -1.0) 11 | }; 12 | const float4 colors[] = { 13 | float4(1.0, 0.0, 0.0, 1.0), 14 | float4(0.0, 1.0, 0.0, 1.0), 15 | float4(0.0, 0.0, 1.0, 1.0) 16 | }; 17 | GenericFragShaderInput triangleVertexData; 18 | vertexId = vertexId % 3; 19 | triangleVertexData.position = float4(pos[vertexId].xyz * scale, 1.0) + float4(offset, depth, 0.0); 20 | #if defined(GENERIC_FS_INPUT_HAS_UV) 21 | triangleVertexData.textureUv = texcoords[vertexId]; 22 | #endif 23 | 24 | #if defined(GENERIC_FS_INPUT_HAS_COLOR) 25 | triangleVertexData.color = colors[vertexId]; 26 | #endif 27 | 28 | #if defined(GENERIC_FS_INPUT_HAS_CLIPSPACE_POS) 29 | triangleVertexData.clipSpacePosition = triangleVertexData.position; 30 | #endif 31 | return triangleVertexData; 32 | } -------------------------------------------------------------------------------- /deps/vma/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017-2025 Advanced Micro Devices, Inc. All rights reserved. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /samples/common/staging-image.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "nicegraf-wrappers.h" 4 | 5 | namespace ngf_samples { 6 | 7 | /** 8 | * This is a helper type used by the samples to upload image data to the rendering device. 9 | * Usually the samples create a staging buffer that is just enough to upload a given image. The raw 10 | * RGBA data is loaded directly into the staging buffer, which the sample can then use to populate 11 | * an image. After that, the staging buffer is discarded. This simple method works for the sample 12 | * code, but more advanced applications will require a different approach. 13 | */ 14 | struct staging_image { 15 | ngf::buffer staging_buffer; /** Staging buffer containing raw image data. */ 16 | uint32_t width_px; /** Image width in pixels. */ 17 | uint32_t height_px; /** Image height in pixels. */ 18 | uint32_t nmax_mip_levels; /** Maximum number of mip level that may be generated for this image. */ 19 | }; 20 | 21 | /** 22 | * Creates a staging_image populated with the raw RGBA data from the given Targa file. 23 | */ 24 | staging_image create_staging_image_from_tga(const char* file_name); 25 | 26 | } // namespace ngf_samples 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | nicegraf 2 | ======== 3 | 4 | ![Run tests](https://github.com/nicebyte/nicegraf/workflows/Run%20tests/badge.svg) 5 | 6 |

7 | 8 |

9 |

10 | An abstraction layer for GPU APIs. 11 |

12 |

13 | Discord · Reference Documentation · Sample Code 14 |

15 | 16 | # platform support matrix 17 | 18 | | | 🟦 | 🐧 | 🍏 | 19 | |---|---|---|---| 20 | | 🌋 | 🟩 | 🟩 | 🟨 | 21 | | 🤘 | 🟥 | 🟥 | 🟩 | 22 | 23 | 24 | 25 | 26 | # credits 27 | 28 | ## current maintainers 29 | 30 | * nicebyte · [@nice_byte](http://twitter.com/nice_byte) 31 | * Bagrat 'dBuger' Dabaghyan · [@dBagrat](http://twitter.com/dBagrat) 32 | * Andranik 'HedgeTheHog' Melikyan · [@andranik3949](http://twitter.com/andranik3949) 33 | 34 | ## dependencies 35 | 36 | * The Vulkan backend uses SPIRV-Reflect, maintained by the Khronos Group, and the Vulkan Memory Allocator, maintained by AMD. 37 | * The sample code uses GLFW, maintained by Camilla Berglund, and ImGui, maintained by Omar Cornut. 38 | 39 | -------------------------------------------------------------------------------- /samples/shaders/quat.hlsl: -------------------------------------------------------------------------------- 1 | // Helper functions for quaternions. 2 | 3 | float4 quatFromAxisAngle(float3 axis, float angle) { 4 | float3 n = normalize(axis); 5 | return float4(sin(angle/2.0) * n, cos(angle/2.0)); 6 | } 7 | 8 | float4 quatMul(float4 lhs, float4 rhs) { 9 | const float x1 = lhs[0], 10 | x2 = rhs[0], 11 | y1 = lhs[1], 12 | y2 = rhs[1], 13 | z1 = lhs[2], 14 | z2 = rhs[2], 15 | w1 = lhs[3], 16 | w2 = rhs[3]; 17 | 18 | return float4(x1 * w1 + y1 * z2 - z1 * y2 + x2 * w1, 19 | y1 * w2 - x1 * z2 + z1 * x2 + y2 * w1, 20 | x1 * y2 - y1 * x2 + z1 * w2 + z2 * w1, 21 | w1 * w2 - x1 * x2 - y1 * y2 - z1 * z2); 22 | } 23 | 24 | float4 rotateByQuat(float4 a, float4 q) { 25 | float x = a[0], y = a[1], z = a[2]; 26 | float qx = q[0], qy = q[1], qz = q[2], qw = q[3]; 27 | 28 | float ix = qw * x + qy * z - qz * y; 29 | float iy = qw * y + qz * x - qx * z; 30 | float iz = qw * z + qx * y - qy * x; 31 | float iw = -qx * x - qy * y - qz * z; 32 | 33 | return float4(ix * qw + iw * -qx + iy * -qz - iz * -qy, 34 | iy * qw + iw * -qy + iz * -qx - ix * -qz, 35 | iz * qw + iw * -qz + ix * -qy - iy * -qx, 36 | a[3]); 37 | } -------------------------------------------------------------------------------- /samples/common/platform/macos/glfw-cocoa-contentview.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2021 nicegraf contributors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * 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 Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | 25 | namespace ngf_samples { 26 | 27 | void* get_glfw_contentview(GLFWwindow *win); 28 | 29 | } 30 | -------------------------------------------------------------------------------- /samples/shaders/volume-renderer.hlsl: -------------------------------------------------------------------------------- 1 | // T: volume-renderer vs:VSMain ps:PSMain 2 | 3 | struct VertexShaderInput { 4 | float4 position : SV_Position; 5 | float3 textureCoordinate : TexCoord; 6 | }; 7 | 8 | struct VolumeRendererUniforms { 9 | float4x4 transformMatrix; 10 | float aspectRatio; 11 | }; 12 | 13 | [[vk::binding(0,1)]] ConstantBuffer shaderUniforms; 14 | [[vk::binding(0,0)]] Texture3D volumeImage; 15 | 16 | VertexShaderInput VSMain(uint vertexId: SV_VertexID, uint instanceId : SV_InstanceID) { 17 | const float2 vertices[] = { 18 | float2(1.0, -1.0), float2(-1.0, -1.0), float2(1.0, 1.0), 19 | float2(1.0, 1.0), float2(-1.0, -1.0), float2(-1.0, 1.0) 20 | }; 21 | vertexId = vertexId % 6; 22 | float w, h, d; 23 | volumeImage.GetDimensions(w, h, d); 24 | float3 xyz = float3(vertices[vertexId], 2.0 * (instanceId/d) - 1.0); 25 | float3 uvw = xyz * float3(1.0, -1.0, 1.0); 26 | xyz.y *= shaderUniforms.aspectRatio; 27 | uvw = mul(shaderUniforms.transformMatrix, float4(uvw, 1.0)).xyz; 28 | uvw.xy = 0.5 * uvw.xy + 0.5; 29 | VertexShaderInput result = { 30 | float4(xyz.xy, 0.0, 1.0), 31 | uvw, 32 | }; 33 | return result; 34 | } 35 | 36 | [[vk::binding(1,0)]] sampler volumeSampler; 37 | 38 | float4 PSMain(VertexShaderInput input) : SV_Target { 39 | float alpha = volumeImage.Sample(volumeSampler, input.textureCoordinate).r; 40 | return float4(1., 1., 1., alpha); 41 | } -------------------------------------------------------------------------------- /misc/common/shader-loader.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2023 nicegraf contributors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * 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 Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | 27 | namespace ngf_misc { 28 | 29 | ngf::shader_stage 30 | load_shader_stage(const char* shader_file_name, const char* entry_point_name, ngf_stage_type type); 31 | 32 | } -------------------------------------------------------------------------------- /deps/vulkan-headers/vulkan/vulkan_ios.h: -------------------------------------------------------------------------------- 1 | #ifndef VULKAN_IOS_H_ 2 | #define VULKAN_IOS_H_ 1 3 | 4 | /* 5 | ** Copyright 2015-2022 The Khronos Group Inc. 6 | ** 7 | ** SPDX-License-Identifier: Apache-2.0 8 | */ 9 | 10 | /* 11 | ** This header is generated from the Khronos Vulkan XML API Registry. 12 | ** 13 | */ 14 | 15 | 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif 19 | 20 | 21 | 22 | #define VK_MVK_ios_surface 1 23 | #define VK_MVK_IOS_SURFACE_SPEC_VERSION 3 24 | #define VK_MVK_IOS_SURFACE_EXTENSION_NAME "VK_MVK_ios_surface" 25 | typedef VkFlags VkIOSSurfaceCreateFlagsMVK; 26 | typedef struct VkIOSSurfaceCreateInfoMVK { 27 | VkStructureType sType; 28 | const void* pNext; 29 | VkIOSSurfaceCreateFlagsMVK flags; 30 | const void* pView; 31 | } VkIOSSurfaceCreateInfoMVK; 32 | 33 | typedef VkResult (VKAPI_PTR *PFN_vkCreateIOSSurfaceMVK)(VkInstance instance, const VkIOSSurfaceCreateInfoMVK* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); 34 | 35 | #ifndef VK_NO_PROTOTYPES 36 | VKAPI_ATTR VkResult VKAPI_CALL vkCreateIOSSurfaceMVK( 37 | VkInstance instance, 38 | const VkIOSSurfaceCreateInfoMVK* pCreateInfo, 39 | const VkAllocationCallbacks* pAllocator, 40 | VkSurfaceKHR* pSurface); 41 | #endif 42 | 43 | #ifdef __cplusplus 44 | } 45 | #endif 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /deps/vulkan-headers/vulkan/vulkan_macos.h: -------------------------------------------------------------------------------- 1 | #ifndef VULKAN_MACOS_H_ 2 | #define VULKAN_MACOS_H_ 1 3 | 4 | /* 5 | ** Copyright 2015-2022 The Khronos Group Inc. 6 | ** 7 | ** SPDX-License-Identifier: Apache-2.0 8 | */ 9 | 10 | /* 11 | ** This header is generated from the Khronos Vulkan XML API Registry. 12 | ** 13 | */ 14 | 15 | 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif 19 | 20 | 21 | 22 | #define VK_MVK_macos_surface 1 23 | #define VK_MVK_MACOS_SURFACE_SPEC_VERSION 3 24 | #define VK_MVK_MACOS_SURFACE_EXTENSION_NAME "VK_MVK_macos_surface" 25 | typedef VkFlags VkMacOSSurfaceCreateFlagsMVK; 26 | typedef struct VkMacOSSurfaceCreateInfoMVK { 27 | VkStructureType sType; 28 | const void* pNext; 29 | VkMacOSSurfaceCreateFlagsMVK flags; 30 | const void* pView; 31 | } VkMacOSSurfaceCreateInfoMVK; 32 | 33 | typedef VkResult (VKAPI_PTR *PFN_vkCreateMacOSSurfaceMVK)(VkInstance instance, const VkMacOSSurfaceCreateInfoMVK* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); 34 | 35 | #ifndef VK_NO_PROTOTYPES 36 | VKAPI_ATTR VkResult VKAPI_CALL vkCreateMacOSSurfaceMVK( 37 | VkInstance instance, 38 | const VkMacOSSurfaceCreateInfoMVK* pCreateInfo, 39 | const VkAllocationCallbacks* pAllocator, 40 | VkSurfaceKHR* pSurface); 41 | #endif 42 | 43 | #ifdef __cplusplus 44 | } 45 | #endif 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /misc/common/file-utils.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2023 nicegraf contributors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * 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 Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | #include 27 | 28 | #if defined(_WIN64) || defined(_WIN32) 29 | #define NGF_MISC_PATH_SEPARATOR "\\" 30 | #else 31 | #define NGF_MISC_PATH_SEPARATOR "/" 32 | #endif 33 | 34 | namespace ngf_misc { 35 | 36 | std::vector load_file(const char* file_name); 37 | 38 | } 39 | -------------------------------------------------------------------------------- /samples/shaders/compute-demo.hlsl: -------------------------------------------------------------------------------- 1 | // T: compute-demo cs:CSMain 2 | 3 | [[vk::binding(0, 0)]] RWTexture2D outputImage; 4 | 5 | float2 f(float2 x, float2 c) { 6 | return mul(x, float2x2(x.x, x.y, -x.y, x.x)) + c; 7 | } 8 | 9 | float3 palette(float t, float3 a, float3 b, float3 c, float3 d) { 10 | return a + b * cos(6.28318 * (c * t + d)); /* thanks, iq */ 11 | } 12 | 13 | [numthreads(4, 4, 1)] void CSMain(uint3 tid 14 | : SV_DispatchThreadID) { 15 | float2 uv = float2 ((float)tid.x / 512.0f, (float)tid.y / 512.0f); 16 | float2 c = float2(-0.6, 0.0) + (2.0*uv - 1.0); 17 | float2 x = float2(0.0, 0.0); 18 | bool escaped = false; 19 | int iterations = 0; 20 | for (int i = 0; i < 50; i++) { 21 | iterations = i; 22 | x = f(x, c); 23 | if (length(x) > 2.0) { 24 | escaped = true; 25 | break; 26 | } 27 | } 28 | outputImage[tid.xy] = (escaped ? float4( 29 | palette( 30 | float(iterations) / 50.0, 31 | float3(0.3, 0.2, 0.4), 32 | float3(0.2, 0.1, 0.0), 33 | float3(1.0, 1.0, 1.0), 34 | float3(0.3, 0.5, 0.2)), 35 | 1.0) 36 | : float4(0.0, 0.0, 0.0, 1.0)); 37 | } 38 | -------------------------------------------------------------------------------- /misc/common/mesh-loader.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2023 nicegraf contributors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * 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 Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | 25 | namespace ngf_misc { 26 | 27 | struct mesh { 28 | ngf::buffer vertex_data; 29 | ngf::buffer index_data; 30 | uint32_t num_indices; 31 | bool have_normals; 32 | bool have_uvs; 33 | }; 34 | 35 | mesh load_mesh_from_file(const char* file_name, ngf_xfer_encoder xfenc); 36 | 37 | } -------------------------------------------------------------------------------- /samples/shaders/cubemap.hlsl: -------------------------------------------------------------------------------- 1 | // T: cubemap vs:VSMain ps:PSMain define:GENERIC_FS_INPUT_HAS_CLIPSPACE_POS=1 2 | // T: cubemap-array vs:VSMain ps:PSMain define:GENERIC_FS_INPUT_HAS_CLIPSPACE_POS=1 define:USE_CUBEMAP_ARRAY=1 3 | 4 | #include "triangle.hlsl" 5 | 6 | struct ShaderUniforms { 7 | float4x4 cameraTransform; 8 | float aspectRatio; 9 | #if defined(USE_CUBEMAP_ARRAY) 10 | float cubemapArrayIndex; 11 | #endif 12 | }; 13 | 14 | #if defined(USE_CUBEMAP_ARRAY) 15 | #define TEXTURE_IMAGE_TYPE TextureCubeArray 16 | #else 17 | #define TEXTURE_IMAGE_TYPE TextureCube 18 | #endif 19 | 20 | [[vk::binding(0, 0)]] ConstantBuffer shaderUniforms; 21 | [[vk::binding(1, 0)]] uniform TEXTURE_IMAGE_TYPE cubemapImage; 22 | [[vk::binding(2, 0)]] uniform sampler imageSampler; 23 | 24 | float4 PSMain(GenericFragShaderInput vertexAttribs) : SV_Target { 25 | float3 direction = -mul(shaderUniforms.cameraTransform, 26 | float4(vertexAttribs.clipSpacePosition.x * shaderUniforms.aspectRatio, 27 | vertexAttribs.clipSpacePosition.y, 28 | 1.0, 29 | 0.0)).xyz; 30 | #if defined(USE_CUBEMAP_ARRAY) 31 | float4 cubemapSampleCoords = float4(direction, shaderUniforms.cubemapArrayIndex); 32 | #else 33 | float3 cubemapSampleCoords = direction; 34 | #endif 35 | return cubemapImage.Sample(imageSampler, cubemapSampleCoords); 36 | } 37 | 38 | GenericFragShaderInput VSMain(uint vertexId : SV_VertexID) { 39 | return TriangleVertex(vertexId, 1.0, 0.0, 0.0); 40 | } 41 | -------------------------------------------------------------------------------- /source/ngf-vk/ca-metal-layer.mm: -------------------------------------------------------------------------------- 1 | #if defined(__APPLE__) 2 | 3 | #include "nicegraf.h" 4 | #import 5 | #import 6 | #if TARGET_OS_OSX 7 | #import 8 | using NGFMTL_VIEW_TYPE = NSView; 9 | #else 10 | #import 11 | using NGFMTL_VIEW_TYPE = UIView; 12 | #endif 13 | 14 | extern "C" { 15 | void* ngfvk_create_ca_metal_layer(const ngf_swapchain_info* swapchain_info) { 16 | //const MTLPixelFormat pixel_format = get_mtl_pixel_format(swapchain_info->color_format).format; 17 | auto layer = [CAMetalLayer layer]; 18 | layer.drawableSize = CGSizeMake(swapchain_info->width, swapchain_info->height); 19 | //layer.pixelFormat = pixel_format; 20 | layer.framebufferOnly = YES; 21 | #if TARGET_OS_OSX 22 | if (@available(macOS 10.13.2, *)) { 23 | layer.maximumDrawableCount = swapchain_info->capacity_hint; 24 | } 25 | if (@available(macOS 10.13, *)) { 26 | layer.displaySyncEnabled = (swapchain_info->present_mode == NGF_PRESENTATION_MODE_FIFO); 27 | } 28 | #endif 29 | 30 | // Associate the newly created Metal layer with the user-provided View. 31 | NGFMTL_VIEW_TYPE* view = CFBridgingRelease((void*)swapchain_info->native_handle); 32 | #if TARGET_OS_OSX 33 | [view setLayer:layer]; 34 | #else 35 | [view.layer addSublayer:layer]; 36 | [layer setContentsScale:view.layer.contentsScale]; 37 | [layer setContentsGravity:kCAGravityResizeAspect]; 38 | [layer setFrame:view.frame]; 39 | #endif 40 | CFBridgingRetain(view); 41 | return layer; 42 | } 43 | } 44 | #endif 45 | -------------------------------------------------------------------------------- /samples/common/diagnostic-callback.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2021 nicegraf contributors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * 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 Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include "nicegraf.h" 26 | 27 | namespace ngf_samples { 28 | 29 | /** 30 | * A sample diagnostic callback implementation, which forwards received messages to the log. 31 | */ 32 | void sample_diagnostic_callback( 33 | ngf_diagnostic_message_type msg_type, 34 | void* userdata, 35 | const char* fmt, 36 | ...); 37 | 38 | } // namespace ngf_samples 39 | -------------------------------------------------------------------------------- /samples/common/platform/macos/glfw-cocoa-contentview.mm: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2021 nicegraf contributors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * 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 Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #include "platform/macos/glfw-cocoa-contentview.h" 24 | 25 | #define GLFW_EXPOSE_NATIVE_COCOA 26 | #include 27 | 28 | namespace ngf_samples { 29 | 30 | /** 31 | * On Mac, the NSWindow's ContentView needs to be 32 | * passed to nicegraf as the native window handle. 33 | */ 34 | void* get_glfw_contentview(GLFWwindow *win) { 35 | NSWindow* w = glfwGetCocoaWindow(win); 36 | return (void*)CFBridgingRetain(w.contentView); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /misc/common/file-utils.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2023 nicegraf contributors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * 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 Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #include "file-utils.h" 24 | 25 | #include 26 | #include 27 | 28 | namespace ngf_misc { 29 | 30 | std::vector load_file(const char* file_name) { 31 | std::basic_ifstream fs(file_name, std::ios::binary | std::ios::in); 32 | if (!fs.is_open()) { 33 | throw std::runtime_error{ file_name }; 34 | } 35 | return std::vector { std::istreambuf_iterator(fs), 36 | std::istreambuf_iterator() }; 37 | } 38 | 39 | } // namespace ngf_common 40 | -------------------------------------------------------------------------------- /samples/common/diagnostic-callback.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2021 nicegraf contributors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * 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 Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #include "diagnostic-callback.h" 24 | 25 | #include "logging.h" 26 | 27 | #include 28 | 29 | namespace ngf_samples { 30 | 31 | void sample_diagnostic_callback(ngf_diagnostic_message_type msg_type, void*, const char* fmt, ...) { 32 | va_list args; 33 | va_start(args, fmt); 34 | switch (msg_type) { 35 | case NGF_DIAGNOSTIC_ERROR: 36 | case NGF_DIAGNOSTIC_WARNING: 37 | ngf_misc::vloge(fmt, args); 38 | break; 39 | case NGF_DIAGNOSTIC_INFO: 40 | ngf_misc::vlogi(fmt, args); 41 | break; 42 | default:; 43 | } 44 | va_end(args); 45 | } 46 | 47 | } // namespace ngf_samples -------------------------------------------------------------------------------- /samples/shaders/polygon.hlsl: -------------------------------------------------------------------------------- 1 | //T: polygon ps:PSMain vs:VSMain 2 | 3 | #define GENERIC_FS_INPUT_HAS_COLOR 4 | #include "generic-frag-shader-input.hlsl" 5 | 6 | struct VertShaderUniforms { 7 | float scaleA; 8 | float scaleB; 9 | float time; 10 | float aspectRatio; 11 | float theta; 12 | }; 13 | 14 | 15 | [[vk::binding(0, 0)]] ConstantBuffer vertShaderUniforms; 16 | 17 | float4 PSMain(GenericFragShaderInput vertexAttribs) : SV_Target { 18 | return vertexAttribs.color; 19 | } 20 | 21 | GenericFragShaderInput VSMain(uint vertexId : SV_VertexID) { 22 | GenericFragShaderInput polygonVertexData; 23 | if (vertexId % 3 == 0) { 24 | polygonVertexData.position = float4(0.0, 0.0, 0.0, 1.0); 25 | polygonVertexData.color = float4(0.8, 0.7, 0.8, 1.0); 26 | } else { 27 | float rotationAngle = vertShaderUniforms.time; 28 | float2x2 rotationMatrix = { 29 | cos(rotationAngle), -sin(rotationAngle), 30 | sin(rotationAngle), cos(rotationAngle) 31 | }; 32 | float effectiveScale = (vertexId % 2 ? vertShaderUniforms.scaleB : vertShaderUniforms.scaleA); 33 | int outerVertexId = int(round(float(vertexId)/3.0)); 34 | float theta = vertShaderUniforms.theta; 35 | float2 vertexPosition = mul(rotationMatrix, 36 | float2(sin(outerVertexId * theta), 37 | cos(outerVertexId * theta))) * float2(1.0, vertShaderUniforms.aspectRatio) 38 | * effectiveScale; 39 | polygonVertexData.position = float4(vertexPosition, 0.0, 1.0); 40 | polygonVertexData.color = float4(0.5 * (vertexPosition.x + 1.0), 0.5 * (vertexPosition.y + 1.0), abs(1.0 - vertexPosition.x), 1.0); 41 | polygonVertexData.position.y *= -1.0; 42 | } 43 | return polygonVertexData; 44 | } 45 | -------------------------------------------------------------------------------- /samples/shaders/instancing.hlsl: -------------------------------------------------------------------------------- 1 | //T: instancing ps:PSMain vs:VSMain 2 | 3 | #include "quat.hlsl" 4 | 5 | #define GENERIC_FS_INPUT_HAS_UV 6 | #include "generic-frag-shader-input.hlsl" 7 | 8 | struct VertexShaderInput { 9 | float3 objSpacePosition : SV_Position; 10 | float2 textureUv : TEXCOORD0; 11 | }; 12 | 13 | struct ShaderUniforms { 14 | float4x4 worldToClipTransform; 15 | float timestamp; 16 | }; 17 | 18 | [[vk::binding(0, 0)]] ConstantBuffer shaderUniforms; 19 | [[vk::binding(1, 0)]] Buffer perInstanceData; 20 | 21 | GenericFragShaderInput VSMain(VertexShaderInput vertexAttrs, int instanceIdx : SV_InstanceID) { 22 | float4 worldSpaceTranslation = float4(perInstanceData.Load(instanceIdx), 0.0); 23 | const float oscillationFrequency = 5.0; 24 | float oscillationPhase = worldSpaceTranslation.x * worldSpaceTranslation.y; 25 | float4 oscillationOffset = float4(0.0, sin(oscillationFrequency * (shaderUniforms.timestamp + oscillationPhase)), 0.0, 0.0); 26 | float4 rotationQuat = quatFromAxisAngle(worldSpaceTranslation.xyz, shaderUniforms.timestamp); 27 | float4 worldSpacePosition = rotateByQuat(float4(vertexAttrs.objSpacePosition, 1.0), rotationQuat) + 28 | worldSpaceTranslation + 29 | oscillationOffset; 30 | float4 clipSpacePosition = mul(shaderUniforms.worldToClipTransform, worldSpacePosition); 31 | clipSpacePosition.y *= -1.0; 32 | GenericFragShaderInput result = { 33 | clipSpacePosition, 34 | vertexAttrs.textureUv 35 | }; 36 | return result; 37 | } 38 | 39 | [[vk::binding(2, 0)]] uniform Texture2D modelTexture; 40 | [[vk::binding(3, 0)]] uniform sampler textureSampler; 41 | 42 | float4 PSMain(GenericFragShaderInput fragmentAttribs) : SV_Target { 43 | return modelTexture.Sample(textureSampler, fragmentAttribs.textureUv); 44 | } -------------------------------------------------------------------------------- /deps/vulkan-headers/vulkan/vulkan.h: -------------------------------------------------------------------------------- 1 | #ifndef VULKAN_H_ 2 | #define VULKAN_H_ 1 3 | 4 | /* 5 | ** Copyright 2015-2022 The Khronos Group Inc. 6 | ** 7 | ** SPDX-License-Identifier: Apache-2.0 8 | */ 9 | 10 | #include "vk_platform.h" 11 | #include "vulkan_core.h" 12 | 13 | #ifdef VK_USE_PLATFORM_ANDROID_KHR 14 | #include "vulkan_android.h" 15 | #endif 16 | 17 | #ifdef VK_USE_PLATFORM_FUCHSIA 18 | #include 19 | #include "vulkan_fuchsia.h" 20 | #endif 21 | 22 | #ifdef VK_USE_PLATFORM_IOS_MVK 23 | #include "vulkan_ios.h" 24 | #endif 25 | 26 | 27 | #ifdef VK_USE_PLATFORM_MACOS_MVK 28 | #include "vulkan_macos.h" 29 | #endif 30 | 31 | #ifdef VK_USE_PLATFORM_METAL_EXT 32 | #include "vulkan_metal.h" 33 | #endif 34 | 35 | #ifdef VK_USE_PLATFORM_VI_NN 36 | #include "vulkan_vi.h" 37 | #endif 38 | 39 | 40 | #ifdef VK_USE_PLATFORM_WAYLAND_KHR 41 | #include 42 | #include "vulkan_wayland.h" 43 | #endif 44 | 45 | 46 | #ifdef VK_USE_PLATFORM_WIN32_KHR 47 | #include 48 | #include "vulkan_win32.h" 49 | #endif 50 | 51 | 52 | #ifdef VK_USE_PLATFORM_XCB_KHR 53 | #include 54 | #include "vulkan_xcb.h" 55 | #endif 56 | 57 | 58 | #ifdef VK_USE_PLATFORM_XLIB_KHR 59 | #include 60 | #include "vulkan_xlib.h" 61 | #endif 62 | 63 | 64 | #ifdef VK_USE_PLATFORM_DIRECTFB_EXT 65 | #include 66 | #include "vulkan_directfb.h" 67 | #endif 68 | 69 | 70 | #ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT 71 | #include 72 | #include 73 | #include "vulkan_xlib_xrandr.h" 74 | #endif 75 | 76 | 77 | #ifdef VK_USE_PLATFORM_GGP 78 | #include 79 | #include "vulkan_ggp.h" 80 | #endif 81 | 82 | 83 | #ifdef VK_USE_PLATFORM_SCREEN_QNX 84 | #include 85 | #include "vulkan_screen.h" 86 | #endif 87 | 88 | #ifdef VK_ENABLE_BETA_EXTENSIONS 89 | #include "vulkan_beta.h" 90 | #endif 91 | 92 | #endif // VULKAN_H_ 93 | -------------------------------------------------------------------------------- /tests/image-comparison/testcases/ngf-triangle-test.cpp: -------------------------------------------------------------------------------- 1 | #include "nicegraf-wrappers.h" 2 | #include "nicegraf.h" 3 | #include 4 | 5 | #include 6 | 7 | void ngf_test_draw(ngf::render_target& rt, const ngf_attachment_descriptions& rt_attachments, ngf_frame_token frame_token) { 8 | // Initialize the triangle test 9 | ngf::graphics_pipeline offscreen_pipeline; 10 | 11 | const ngf::shader_stage offscreen_vertex_stage = 12 | ngf_misc::load_shader_stage("small-triangle", "VSMain", NGF_STAGE_VERTEX); 13 | const ngf::shader_stage offscreen_fragment_stage = 14 | ngf_misc::load_shader_stage("small-triangle", "PSMain", NGF_STAGE_FRAGMENT); 15 | 16 | ngf_util_graphics_pipeline_data offscreen_pipeline_data; 17 | ngf_util_create_default_graphics_pipeline_data(&offscreen_pipeline_data); 18 | ngf_graphics_pipeline_info& offscreen_pipe_info = offscreen_pipeline_data.pipeline_info; 19 | offscreen_pipe_info.nshader_stages = 2u; 20 | offscreen_pipe_info.shader_stages[0] = offscreen_vertex_stage.get(); 21 | offscreen_pipe_info.shader_stages[1] = offscreen_fragment_stage.get(); 22 | offscreen_pipe_info.compatible_rt_attachment_descs = &rt_attachments; 23 | offscreen_pipeline.initialize(offscreen_pipe_info); 24 | 25 | // Start drawing to output_image 26 | ngf_irect2d offsc_viewport {0, 0, 512, 512}; 27 | ngf_cmd_buffer offscr_cmd_buf = nullptr; 28 | ngf_cmd_buffer_info cmd_info = {}; 29 | ngf_create_cmd_buffer(&cmd_info, &offscr_cmd_buf); 30 | ngf_start_cmd_buffer(offscr_cmd_buf, frame_token); 31 | { 32 | ngf::render_encoder renc {offscr_cmd_buf, rt, .0f, 0.0f, 0.0f, 0.0f, 1.0, 0u}; 33 | ngf_cmd_bind_gfx_pipeline(renc, offscreen_pipeline); 34 | ngf_cmd_viewport(renc, &offsc_viewport); 35 | ngf_cmd_scissor(renc, &offsc_viewport); 36 | ngf_cmd_draw(renc, false, 0u, 3u, 1u); 37 | } 38 | ngf_submit_cmd_buffers(1, &offscr_cmd_buf); 39 | ngf_destroy_cmd_buffer(offscr_cmd_buf); 40 | } 41 | -------------------------------------------------------------------------------- /deps/vulkan-headers/vulkan/vulkan_xcb.h: -------------------------------------------------------------------------------- 1 | #ifndef VULKAN_XCB_H_ 2 | #define VULKAN_XCB_H_ 1 3 | 4 | /* 5 | ** Copyright 2015-2022 The Khronos Group Inc. 6 | ** 7 | ** SPDX-License-Identifier: Apache-2.0 8 | */ 9 | 10 | /* 11 | ** This header is generated from the Khronos Vulkan XML API Registry. 12 | ** 13 | */ 14 | 15 | 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif 19 | 20 | 21 | 22 | #define VK_KHR_xcb_surface 1 23 | #define VK_KHR_XCB_SURFACE_SPEC_VERSION 6 24 | #define VK_KHR_XCB_SURFACE_EXTENSION_NAME "VK_KHR_xcb_surface" 25 | typedef VkFlags VkXcbSurfaceCreateFlagsKHR; 26 | typedef struct VkXcbSurfaceCreateInfoKHR { 27 | VkStructureType sType; 28 | const void* pNext; 29 | VkXcbSurfaceCreateFlagsKHR flags; 30 | xcb_connection_t* connection; 31 | xcb_window_t window; 32 | } VkXcbSurfaceCreateInfoKHR; 33 | 34 | typedef VkResult (VKAPI_PTR *PFN_vkCreateXcbSurfaceKHR)(VkInstance instance, const VkXcbSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); 35 | typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, xcb_connection_t* connection, xcb_visualid_t visual_id); 36 | 37 | #ifndef VK_NO_PROTOTYPES 38 | VKAPI_ATTR VkResult VKAPI_CALL vkCreateXcbSurfaceKHR( 39 | VkInstance instance, 40 | const VkXcbSurfaceCreateInfoKHR* pCreateInfo, 41 | const VkAllocationCallbacks* pAllocator, 42 | VkSurfaceKHR* pSurface); 43 | 44 | VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceXcbPresentationSupportKHR( 45 | VkPhysicalDevice physicalDevice, 46 | uint32_t queueFamilyIndex, 47 | xcb_connection_t* connection, 48 | xcb_visualid_t visual_id); 49 | #endif 50 | 51 | #ifdef __cplusplus 52 | } 53 | #endif 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /samples/shaders/compute-vertices.hlsl: -------------------------------------------------------------------------------- 1 | struct VertexData { 2 | float3 position; 3 | float3 normal; 4 | }; 5 | 6 | struct VertexOutput { 7 | float4 position : SV_Position; 8 | float height : ATTR0; 9 | }; 10 | 11 | // T: render-vertices vs:VSMain ps:PSMain 12 | 13 | struct VertexShaderUniforms { 14 | float4x4 objToViewTransform; 15 | float4x4 viewToClipTransform; 16 | }; 17 | 18 | [[vk::binding(0, 0)]] ConstantBuffer vertShaderUniforms; 19 | 20 | #define maxAmplitude 0.05 21 | 22 | VertexOutput VSMain(uint vertID : SV_VertexID, float4 pos : SV_Position) { 23 | VertexOutput result; 24 | result.height = pos.y; 25 | result.position = 26 | mul(vertShaderUniforms.viewToClipTransform, 27 | mul(vertShaderUniforms.objToViewTransform, float4(pos.xyz, 1.0))); 28 | return result; 29 | } 30 | 31 | float4 PSMain(VertexOutput pxIn) : SV_Target { 32 | float shade = saturate(-(pxIn.height / (maxAmplitude + 0.04)) * 0.5 + 0.5); 33 | shade = shade * shade; 34 | return shade * float4(1., 1., 1.0, 1.0); 35 | } 36 | 37 | // T: compute-vertices cs:CSMain 38 | 39 | struct ComputeShaderUniforms { 40 | float4 time; 41 | }; 42 | 43 | [[vk::binding(0, 1)]] RWStructuredBuffer outputBuffer; 44 | [[vk::binding(1, 1)]] ConstantBuffer computeShaderUniforms; 45 | 46 | [numthreads(2, 2, 1)] void CSMain(uint3 tid 47 | : SV_DispatchThreadID) { 48 | const uint vertsPerSide = 512; 49 | uint vertID = tid.y * vertsPerSide + tid.x; 50 | uint2 vertRowColumn = tid.xy; 51 | float2 vertUV = float2( 52 | (float)vertRowColumn.x / (float)(vertsPerSide - 1), 53 | (float)vertRowColumn.y / (float)(vertsPerSide - 1)); 54 | float2 vertXZ = vertUV * 2.0 - float2(1.0, 1.0); 55 | float height = maxAmplitude * 56 | sin(cos(computeShaderUniforms.time.x * 2.0 + vertRowColumn.x * 0.1) + vertRowColumn.y * 0.1); 57 | float4 position = float4(vertXZ.x, height, vertXZ.y, 1.0); 58 | outputBuffer[vertID] = position; 59 | } -------------------------------------------------------------------------------- /misc/common/targa-loader.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2023 nicegraf contributors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * 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 Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | #include 27 | 28 | namespace ngf_misc { 29 | 30 | /** 31 | * Decodes an RLE-encoded true color targa file with an optional 32 | * alpha channel into the target buffer. 33 | * Assumes the source file uses sRGB color space. 34 | * If `out_buf` is non-NULL, raw RGBA values, in sRGB, with 35 | * premultiplied alpha, will be written to it. The width and 36 | * height of the image are returned in the output parameters. 37 | * If `out_buf` is NULL, no decoding is performed, however 38 | * the width and height of the image are still returned. 39 | */ 40 | void load_targa( 41 | const void* in_buf, 42 | size_t in_buf_size, 43 | void* out_buf, 44 | size_t out_buf_size, 45 | uint32_t* width_px, 46 | uint32_t* height_px); 47 | 48 | } // namespace ngf_misc 49 | -------------------------------------------------------------------------------- /samples/shaders/textured-quad.hlsl: -------------------------------------------------------------------------------- 1 | //T: textured-quad ps:PSMain vs:VSMain define:GENERIC_FS_INPUT_HAS_UV=1 2 | //T: textured-quad-image-array ps:PSMain vs:VSMain define:GENERIC_FS_INPUT_HAS_UV=1 define:USE_IMAGE_ARRAY=1 3 | //T: textured-quad-multiple-images ps:PSMain vs:VSMain define:GENERIC_FS_INPUT_HAS_UV=1 define:NUM_IMAGES=4 4 | 5 | #include "generic-frag-shader-input.hlsl" 6 | 7 | struct ShaderUniforms { 8 | float4x4 transformMatrix; 9 | #if defined(USE_IMAGE_ARRAY) 10 | float imageArrayIdx; 11 | #endif 12 | #if defined(NUM_IMAGES) 13 | uint imageIdx; 14 | #endif 15 | }; 16 | 17 | [[vk::binding(0, 0)]] ConstantBuffer shaderUniforms; 18 | 19 | GenericFragShaderInput VSMain(uint vertexId : SV_VertexID) { 20 | const float2 vertices[] = { 21 | float2(1.0, -1.0), float2(-1.0, -1.0), float2(1.0, 1.0), 22 | float2(1.0, 1.0), float2(-1.0, -1.0), float2(-1.0, 1.0) 23 | }; 24 | const float2 uvs[] = { 25 | float2(1.0, 1.0), float2(0.0, 1.0), float2(1.0, 0.0), 26 | float2(1.0, 0.0), float2(0.0, 1.0), float2(0.0, 0.0) 27 | }; 28 | vertexId = vertexId % 6; 29 | GenericFragShaderInput result = { 30 | mul(shaderUniforms.transformMatrix, 31 | float4(vertices[vertexId], 0.0, 1.0)), 32 | 2 * uvs[vertexId] 33 | }; 34 | return result; 35 | } 36 | 37 | #if defined(USE_IMAGE_ARRAY) 38 | #define TEXTURE_IMAGE_TYPE Texture2DArray 39 | #else 40 | #define TEXTURE_IMAGE_TYPE Texture2D 41 | #endif 42 | 43 | #if !defined(NUM_IMAGES) 44 | #define NUM_IMAGES (1) 45 | #endif 46 | 47 | [[vk::binding(0, 1)]] uniform TEXTURE_IMAGE_TYPE textureImage[NUM_IMAGES]; 48 | [[vk::binding(1, 0)]] uniform sampler imageSampler; 49 | 50 | float4 PSMain(GenericFragShaderInput vertexAttribs) : SV_Target { 51 | #if defined(USE_IMAGE_ARRAY) 52 | float3 sampleCoords = float3(vertexAttribs.textureUv, shaderUniforms.imageArrayIdx); 53 | #else 54 | float2 sampleCoords = vertexAttribs.textureUv; 55 | #endif 56 | #if NUM_IMAGES > 1 57 | uint i = shaderUniforms.imageIdx % NUM_IMAGES; 58 | #else 59 | uint i = 0u; 60 | #endif 61 | return textureImage[i].Sample(imageSampler, sampleCoords); 62 | } 63 | -------------------------------------------------------------------------------- /samples/common/camera-controller.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2021 nicegraf contributors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * 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 Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #include "nicemath.h" 24 | 25 | #include 26 | 27 | namespace ngf_samples { 28 | 29 | struct camera_state { 30 | nm::float3 look_at {0.0f, 0.0f, 0.0f}; 31 | float radius = 3.0f; 32 | float azimuth = 0.0f; 33 | float inclination = 3.14f / 2.0f; 34 | float vfov = 60.0f; 35 | }; 36 | 37 | struct camera_matrices { 38 | nm::float4x4 world_to_view_transform; 39 | nm::float4x4 view_to_clip_transform; 40 | }; 41 | 42 | camera_matrices compute_camera_matrices(const camera_state& state, float aspect_ratio); 43 | void camera_ui( 44 | camera_state& state, 45 | std::pair look_at_range, 46 | float look_at_speed, 47 | std::pair radius_range, 48 | float radius_speed); 49 | 50 | } // namespace ngf_samples -------------------------------------------------------------------------------- /source/ngf-common/frame-token.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2021 nicegraf contributors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * 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 Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | * DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | static inline uintptr_t 32 | ngfi_encode_frame_token(uint16_t ctx_id, uint8_t max_inflight_frames, uint8_t frame_id) { 33 | const uint32_t ctx_id_ext = ctx_id, max_inflight_frames_ext = max_inflight_frames, 34 | frame_id_ext = frame_id; 35 | return (ctx_id_ext << 0x10) | (max_inflight_frames_ext << 0x08) | frame_id_ext; 36 | } 37 | 38 | static inline uint16_t ngfi_frame_ctx_id(uintptr_t frame_token) { 39 | return ((uint16_t)(frame_token >> 0x10)) & 0xffff; 40 | } 41 | 42 | static inline uint8_t ngfi_frame_max_inflight_frames(uintptr_t frame_token) { 43 | return ((uint8_t)(frame_token >> 0x08)) & 0xff; 44 | } 45 | 46 | static inline uint8_t ngfi_frame_id(uintptr_t frame_token) { 47 | return (uint8_t)(frame_token & 0xff); 48 | } 49 | 50 | #ifdef __cplusplus 51 | } 52 | #endif 53 | -------------------------------------------------------------------------------- /samples/00-template/sample-impl.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2021 nicegraf contributors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * 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 Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #include "sample-interface.h" 24 | 25 | #include 26 | 27 | namespace ngf_samples { 28 | 29 | struct sample_data { 30 | uint32_t magic_number = 0xdeadbeef; 31 | }; 32 | 33 | void* sample_initialize(uint32_t , uint32_t ) { 34 | printf("sample initializing.\n"); 35 | auto d = new sample_data{}; 36 | d->magic_number = 0xbadf00d; 37 | printf("sample initialization complete.\n"); 38 | return static_cast(d); 39 | } 40 | 41 | void sample_draw_frame( 42 | ngf_frame_token , 43 | uint32_t , 44 | uint32_t , 45 | float , 46 | void* ) { 47 | //auto data = static_cast(userdata); 48 | //printf("drawing frame %d (w %d h %d) at time %f magic number 0x%x\n", frame_token, width, height, time, data->magic_number); 49 | } 50 | 51 | void sample_draw_ui(void*) { 52 | } 53 | 54 | void sample_shutdown(void* userdata) { 55 | auto data = static_cast(userdata); 56 | delete data; 57 | printf("shutting down\n"); 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /source/ngf-common/cmdbuf-state.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2023 nicegraf contributors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * 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 Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include "nicegraf.h" 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | typedef enum { 32 | NGFI_CMD_BUFFER_NEW, 33 | NGFI_CMD_BUFFER_READY, 34 | NGFI_CMD_BUFFER_RECORDING, 35 | NGFI_CMD_BUFFER_READY_TO_SUBMIT, 36 | NGFI_CMD_BUFFER_PENDING, 37 | NGFI_CMD_BUFFER_SUBMITTED 38 | } ngfi_cmd_buffer_state; 39 | 40 | #define NGFI_CMD_BUF_RECORDABLE(s) \ 41 | (s == NGFI_CMD_BUFFER_READY || s == NGFI_CMD_BUFFER_READY_TO_SUBMIT) 42 | 43 | ngf_error ngfi_transition_cmd_buf( 44 | ngfi_cmd_buffer_state* cur_state, 45 | bool has_active_renderpass, 46 | ngfi_cmd_buffer_state new_state); 47 | 48 | #define NGFI_TRANSITION_CMD_BUF(b, new_state) \ 49 | if (ngfi_transition_cmd_buf(&(b)->state, (b)->renderpass_active, new_state) != NGF_ERROR_OK) { \ 50 | return NGF_ERROR_INVALID_OPERATION; \ 51 | } 52 | 53 | #ifdef __cplusplus 54 | } 55 | #endif 56 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | AccessModifierOffset: 0 2 | AlignAfterOpenBracket: AlwaysBreak 3 | AlignConsecutiveAssignments: true 4 | AlignConsecutiveDeclarations: true 5 | AlignConsecutiveMacros: true 6 | AlignEscapedNewlines: true 7 | AlignOperands: true 8 | AlignTrailingComments: true 9 | AllowAllArgumentsOnNextLine: false 10 | AllowAllConstructorInitializersOnNextLine: false 11 | AllowAllParametersOfDeclarationOnNextLine: false 12 | AllowShortBlocksOnASingleLine: true 13 | AllowShortCaseLabelsOnASingleLine: false 14 | AllowShortFunctionsOnASingleLine: false 15 | AllowShortIfStatementsOnASingleLine: true 16 | AllowShortLambdasOnASingleLine: true 17 | AllowShortLoopsOnASingleLine: true 18 | AlwaysBreakAfterReturnType: None 19 | AlwaysBreakBeforeMultilineStrings: false 20 | BinPackArguments: false 21 | BinPackParameters: false 22 | BreakBeforeBinaryOperators: None 23 | BreakBeforeBraces: Attach 24 | BreakBeforeTernaryOperators: true 25 | BreakConstructorInitializers: BeforeColon 26 | BreakStringLiterals: true 27 | ColumnLimit: 100 28 | CompactNamespaces: false 29 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 30 | ConstructorInitializerIndentWidth: 4 31 | ContinuationIndentWidth: 4 32 | Cpp11BracedListStyle: true 33 | DeriveLineEnding: true 34 | DerivePointerAlignment: false 35 | FixNamespaceComments: true 36 | IncludeBlocks: Regroup 37 | IndentCaseLabels: false 38 | IndentGotoLabels: false 39 | IndentWidth: 2 40 | KeepEmptyLinesAtTheStartOfBlocks: false 41 | MaxEmptyLinesToKeep: 1 42 | NamespaceIndentation: None 43 | PointerAlignment: Left 44 | ReflowComments: true 45 | SortIncludes: true 46 | SortUsingDeclarations: true 47 | SpaceAfterCStyleCast: false 48 | SpaceAfterTemplateKeyword: false 49 | SpaceBeforeAssignmentOperators: true 50 | SpaceBeforeCpp11BracedList: true 51 | SpaceBeforeCtorInitializerColon: true 52 | SpaceBeforeParens: true 53 | SpaceBeforeInheritanceColon: true 54 | SpaceBeforeRangeBasedForLoopColon: true 55 | SpaceBeforeSquareBrackets: false 56 | SpaceInEmptyBlock: false 57 | SpaceInEmptyParentheses: false 58 | SpacesBeforeTrailingComments: 2 59 | SpacesInAngles: false 60 | SpacesInCStyleCastParentheses: false 61 | SpacesInConditionalStatement: false 62 | SpacesInContainerLiterals: false 63 | SpacesInSquareBrackets: false 64 | TabWidth: 2 65 | UseCRLF: false 66 | UseTab: Never 67 | -------------------------------------------------------------------------------- /samples/common/staging-image.cpp: -------------------------------------------------------------------------------- 1 | #include "staging-image.h" 2 | 3 | #include "check.h" 4 | #include "file-utils.h" 5 | #include "targa-loader.h" 6 | 7 | #include 8 | #include 9 | 10 | using namespace ngf_misc; 11 | 12 | namespace ngf_samples { 13 | 14 | staging_image create_staging_image_from_tga(const char* file_name) { 15 | /* Read in the texture image file.*/ 16 | std::vector texture_tga_data = load_file(file_name); 17 | 18 | /* this call does nothing but quickly get the width & height. */ 19 | uint32_t texture_width, texture_height; 20 | load_targa( 21 | texture_tga_data.data(), 22 | texture_tga_data.size(), 23 | nullptr, 24 | 0u, 25 | &texture_width, 26 | &texture_height); 27 | 28 | /* Create an appropriately sized staging buffer for the texture upload. */ 29 | const size_t texture_size_bytes = texture_width * texture_height * 4u; 30 | ngf::buffer staging_buf; 31 | NGF_MISC_CHECK_NGF_ERROR(staging_buf.initialize(ngf_buffer_info { 32 | .size = texture_size_bytes, 33 | .storage_type = NGF_BUFFER_STORAGE_HOST_READABLE_WRITEABLE, 34 | .buffer_usage = NGF_BUFFER_USAGE_XFER_SRC})); 35 | void* mapped_staging_buf = ngf_buffer_map_range(staging_buf.get(), 0, texture_size_bytes); 36 | 37 | /* Decode the loaded targa file, writing RGBA values directly into mapped memory. */ 38 | load_targa( 39 | texture_tga_data.data(), 40 | texture_tga_data.size(), 41 | mapped_staging_buf, 42 | texture_size_bytes, 43 | &texture_width, 44 | &texture_height); 45 | 46 | /* Flush and unmap the staging buffer. */ 47 | ngf_buffer_flush_range(staging_buf.get(), 0, texture_size_bytes); 48 | ngf_buffer_unmap(staging_buf.get()); 49 | 50 | /* Count the number of mipmaps we'll have to generate for trilinear filtering. 51 | Note that we keep generating mip levels until both dimensions are reduced to 1. 52 | */ 53 | uint32_t nmips = 54 | 1 + static_cast(std::floor(std::log2(std::max(texture_width, texture_height)))); 55 | 56 | return staging_image { 57 | .staging_buffer = std::move(staging_buf), 58 | .width_px = texture_width, 59 | .height_px = texture_height, 60 | .nmax_mip_levels = nmips}; 61 | } 62 | 63 | } // namespace ngf_samples 64 | -------------------------------------------------------------------------------- /misc/common/logging.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2023 nicegraf contributors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * 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 Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | #include 27 | 28 | namespace ngf_misc { 29 | 30 | inline void vlog_msg(char prefix, const char* fmt, va_list args) { 31 | auto file = prefix == 'E' ? stderr : stdout; 32 | fprintf(file, "\n[%c] ", prefix); 33 | vfprintf(file, fmt, args); 34 | fprintf(file, "\n"); 35 | } 36 | 37 | inline void vloge(const char* fmt, va_list args) { 38 | vlog_msg('E', fmt, args); 39 | } 40 | 41 | inline void vlogi(const char* fmt, va_list args) { 42 | vlog_msg('I', fmt, args); 43 | } 44 | 45 | inline void vlogd(const char* fmt, va_list args) { 46 | vlog_msg('D', fmt, args); 47 | } 48 | 49 | inline void loge(const char* fmt, ...) { 50 | va_list args; 51 | va_start(args, fmt); 52 | vloge(fmt, args); 53 | va_end(args); 54 | } 55 | 56 | inline void logi(const char* fmt, ...) { 57 | va_list args; 58 | va_start(args, fmt); 59 | vlogi(fmt, args); 60 | va_end(args); 61 | } 62 | 63 | inline void logd(const char* fmt, ...) { 64 | #if !defined(NDEBUG) 65 | va_list args; 66 | va_start(args, fmt); 67 | vlogd(fmt, args); 68 | va_end(args); 69 | #else 70 | (void)fmt; 71 | #endif 72 | } 73 | 74 | } // namespace ngf_misc 75 | -------------------------------------------------------------------------------- /source/ngf-common/native-binding-map.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2021 nicegraf contributors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * 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 Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include "nicegraf.h" 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | /* Provides a mapping from nicegraf's (set, binding) to the backend platform's actual native binding. */ 32 | typedef struct ngfi_native_binding_map ngfi_native_binding_map; 33 | 34 | /** 35 | * Finds the first instance of a serialized native binding map within a given character buffer and 36 | * returns a pointer to it within the buffer. Returns NULL if not found. 37 | */ 38 | const char* ngfi_find_serialized_native_binding_map(const char* input); 39 | 40 | /** 41 | * Parses a native binding map out of the provided buffer. Returns NULL if parsing fails. 42 | */ 43 | ngfi_native_binding_map* ngfi_parse_serialized_native_binding_map(const char* serialized_native_binding_map); 44 | 45 | /** 46 | * Looks up a binding from the given native binding map. 47 | */ 48 | uint32_t ngfi_native_binding_map_lookup(const ngfi_native_binding_map* map, uint32_t set, uint32_t binding); 49 | 50 | /** 51 | * Deallocates any resources associated with the given native binding map. 52 | */ 53 | void ngfi_destroy_native_binding_map(ngfi_native_binding_map* map); 54 | 55 | #ifdef __cplusplus 56 | } 57 | #endif 58 | -------------------------------------------------------------------------------- /tests/image-comparison/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2023 nicegraf contributors 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | this software and associated documentation files (the “Software”), to deal in 6 | the Software without restriction, including without limitation the rights to 7 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 8 | the Software, and to permit persons to whom the Software is furnished to do so, 9 | subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | ]] 22 | 23 | cmake_minimum_required(VERSION 3.23.3) 24 | project(nicegraf-imagetests) 25 | 26 | 27 | set(CMAKE_C_STANDARD 99) 28 | set(CMAKE_CXX_STANDARD 20) 29 | 30 | include("${CMAKE_CURRENT_LIST_DIR}/../../build-utils.cmake") 31 | 32 | add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/../../ "${CMAKE_CURRENT_BINARY_DIR}/nicegraf") 33 | add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/../../misc/common ${CMAKE_CURRENT_BINARY_DIR}/misc-common) 34 | 35 | nmk_static_library(NAME nicegraf-imagetest-framework 36 | SRCS ${CMAKE_CURRENT_LIST_DIR}/framework/main.cpp 37 | DEPS nicegraf-vk nicegraf-misc-common 38 | PUB_DEFINES ${NGF_IMAGE_COMPARISON_BACKEND_DEFINE} 39 | PUB_INCLUDES ${CMAKE_CURRENT_LIST_DIR}/framework) 40 | 41 | function (ngf_imagetest_testcase) 42 | cmake_parse_arguments(TEST "" "NAME" "SRCS" ${ARGN}) 43 | nmk_binary(NAME ${TEST_NAME} 44 | SRCS ${TEST_SRCS} 45 | DEPS nicegraf-imagetest-framework nicegraf-util nicegraf-misc-common 46 | OUTPUT_DIR "${NGF_SAMPLES_OUTPUT_DIR}") 47 | #add_dependencies(${SAMPLE_NAME} sample-shaders) 48 | set_target_properties(${TEST_NAME} PROPERTIES FOLDER "testcases") 49 | endfunction() 50 | 51 | ngf_imagetest_testcase(NAME triangle SRCS ${CMAKE_CURRENT_LIST_DIR}/testcases/ngf-triangle-test.cpp) 52 | 53 | -------------------------------------------------------------------------------- /misc/shaders.cmake: -------------------------------------------------------------------------------- 1 | function (ngf_shaders_target) 2 | cmake_parse_arguments(SHADERS_TARGET "" "NAME;OUTPUT_DIR;NICESHADE_PATH" "SRCS" ${ARGN}) 3 | foreach(source_path ${SHADERS_TARGET_SRCS}) 4 | file(STRINGS ${source_path} tech_lines REGEX "// *T *: *([a-zA-Z0-9_]+)") 5 | if (tech_lines) 6 | set(tech_names "") 7 | foreach(tech_line ${tech_lines}) 8 | string(REPLACE ":" ";" tmp ${tech_line}) 9 | list(GET tmp 1 tmp) 10 | string(STRIP "${tmp}" tmp) 11 | string(REGEX REPLACE " +" ";" tmp ${tmp}) 12 | list(GET tmp 0 tech_name) 13 | list(APPEND tech_names "${tech_name}") 14 | endforeach(tech_line) 15 | set(output_files_list "") 16 | get_filename_component(header_file_name ${source_path} NAME_WE) 17 | if(NOT ${header_file_name} MATCHES "compute-*") 18 | foreach(tech ${tech_names}) 19 | list(APPEND output_files_list "${SHADERS_TARGET_OUTPUT_DIR}/${tech}.vs.21.msl") 20 | list(APPEND output_files_list "${SHADERS_TARGET_OUTPUT_DIR}/${tech}.ps.21.msl") 21 | list(APPEND output_files_list "${SHADERS_TARGET_OUTPUT_DIR}/${tech}.vs.spv") 22 | list(APPEND output_files_list "${SHADERS_TARGET_OUTPUT_DIR}/${tech}.ps.spv") 23 | list(APPEND output_files_list "${SHADERS_TARGET_OUTPUT_DIR}/${tech}.pipeline") 24 | endforeach(tech) 25 | else() 26 | foreach(tech ${tech_names}) 27 | list(APPEND output_files_list "${SHADERS_TARGET_OUTPUT_DIR}/${tech}.cs.21.msl") 28 | list(APPEND output_files_list "${SHADERS_TARGET_OUTPUT_DIR}/${tech}.cs.spv") 29 | list(APPEND output_files_list "${SHADERS_TARGET_OUTPUT_DIR}/${tech}.pipeline") 30 | endforeach(tech) 31 | endif() 32 | list(APPEND output_files_list "${SHADERS_TARGET_OUTPUT_DIR}/${header_file_name}_binding_consts.h") 33 | add_custom_command(OUTPUT ${output_files_list} 34 | MAIN_DEPENDENCY ${source_path} 35 | COMMAND ${SHADERS_TARGET_NICESHADE_PATH}/niceshade ARGS ${source_path} "-t" "msl21" "-t" "spv" "-O" "${SHADERS_TARGET_OUTPUT_DIR}" "-h" "${header_file_name}_binding_consts.h") 36 | #WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/samples/shaders) 37 | set(generated_shaders_list "${output_files_list};${generated_shaders_list}") 38 | endif() 39 | endforeach(source_path) 40 | add_custom_target(${SHADERS_TARGET_NAME} DEPENDS ${generated_shaders_list}) 41 | endfunction() -------------------------------------------------------------------------------- /misc/common/shader-loader.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2023 nicegraf contributors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * 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 Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #include "shader-loader.h" 24 | 25 | #include "file-utils.h" 26 | #include "check.h" 27 | 28 | #include 29 | #include 30 | 31 | namespace ngf_misc { 32 | 33 | #if defined(NGF_BACKEND_NICEGRAF_VK) 34 | #define SHADER_EXTENSION ".spv" 35 | #elif defined(NGF_BACKEND_NICEGRAF_MTL) || defined(NGF_BACKEND_NICEGRAF_MTL_CPP) 36 | #define SHADER_EXTENSION ".21.msl" 37 | #else 38 | #error "build system needs to define samples backend" 39 | #endif 40 | 41 | ngf::shader_stage 42 | load_shader_stage(const char* shader_file_name, const char* entry_point_name, ngf_stage_type type) { 43 | constexpr const char* shaders_root_dir = "shaders" NGF_MISC_PATH_SEPARATOR; 44 | constexpr const char* stage_to_file_ext_map[] = {"vs", "ps", "cs"}; 45 | 46 | const std::string file_name = shaders_root_dir + std::string(shader_file_name) + "." + 47 | stage_to_file_ext_map[type] + SHADER_EXTENSION; 48 | const std::vector content = load_file(file_name.c_str()); 49 | ngf_shader_stage_info stage_info = { 50 | .type = type, 51 | .content = reinterpret_cast(content.data()), 52 | .content_length = (uint32_t)content.size(), 53 | .debug_name = "", 54 | .entry_point_name = entry_point_name}; 55 | 56 | ngf::shader_stage stage; 57 | NGF_MISC_CHECK_NGF_ERROR(stage.initialize(stage_info)); 58 | 59 | return stage; 60 | } 61 | 62 | } // namespace ngf_misc 63 | -------------------------------------------------------------------------------- /misc/common/check.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2023 nicegraf contributors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * 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 Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include "logging.h" 26 | #include 27 | 28 | #include 29 | #include 30 | 31 | #pragma warning(disable:26812) 32 | 33 | namespace ngf_misc { 34 | 35 | #define NGF_MISC_CHECK_NGF_ERROR(expr) \ 36 | { \ 37 | const ngf_error err = (expr); \ 38 | if (err != NGF_ERROR_OK) { \ 39 | ::ngf_misc::loge("nicegraf error %d (file %s line %d), aborting.\n", err, __FILE__, __LINE__); \ 40 | fflush(stderr); \ 41 | abort(); \ 42 | } \ 43 | } 44 | 45 | #define NGF_MISC_ASSERT(expr) \ 46 | { \ 47 | if (!(expr)) { \ 48 | ::ngf_misc::loge("assertion %s failed (file %s line %d)\n", #expr, __FILE__, __LINE__); \ 49 | fflush(stderr); \ 50 | abort(); \ 51 | } \ 52 | } 53 | 54 | } // namespace ngf_misc 55 | -------------------------------------------------------------------------------- /samples/common/imgui-backend.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2023 nicegraf contributors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * 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 Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include "imgui.h" 26 | #include "nicegraf-wrappers.h" 27 | #include "nicegraf.h" 28 | 29 | namespace ngf_samples { 30 | 31 | /** 32 | * This is a nicegraf-based rendering backend for ImGui. 33 | * It's used to render the UI for samples. 34 | */ 35 | class ngf_imgui { 36 | public: 37 | /** 38 | * Initializes the internal state of the ImGui rendering backend, and uploads 39 | * the font texture by recording the appropriate commands into the given 40 | * transfer encoder. 41 | */ 42 | ngf_imgui( 43 | ngf_xfer_encoder font_xfer_encoder, 44 | ngf_sample_count main_render_target_sample_count, 45 | const unsigned char* font_atlast_bytes, 46 | uint32_t font_atlas_width, 47 | uint32_t font_atlas_height); 48 | 49 | /** 50 | * Records commands for rendering the contents ofteh current ImGui draw data into the 51 | * given render encoder. 52 | */ 53 | void record_rendering_commands(ngf_render_encoder enc); 54 | 55 | private: 56 | struct uniform_data { 57 | float ortho_projection[4][4]; 58 | }; 59 | 60 | #if !defined(NGF_NO_IMGUI) 61 | ngf::graphics_pipeline pipeline_; 62 | ngf::uniform_multibuffer uniform_data_; 63 | ngf::image font_texture_; 64 | ngf::sampler tex_sampler_; 65 | ngf::buffer attrib_buffer_; 66 | ngf::buffer index_buffer_; 67 | ngf::buffer texture_data_; 68 | ngf::shader_stage vertex_stage_; 69 | ngf::shader_stage fragment_stage_; 70 | ngf::render_target default_rt_; 71 | #endif 72 | }; 73 | 74 | } // namespace ngf_samples 75 | -------------------------------------------------------------------------------- /samples/common/camera-controller.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2021 nicegraf contributors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * 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 Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #include "camera-controller.h" 24 | 25 | #include "check.h" 26 | #include "imgui.h" 27 | #define _USE_MATH_DEFINES 28 | #include 29 | 30 | namespace ngf_samples { 31 | 32 | camera_matrices compute_camera_matrices(const camera_state& state, float aspect_ratio) { 33 | const float r = state.radius, azimuth = state.azimuth, incline = state.inclination; 34 | const nm::float3 point_on_sphere { 35 | r * sinf(azimuth) * sinf(incline), 36 | r * cosf(incline), 37 | r * sinf(incline) * cosf(azimuth)}; 38 | return { 39 | nm::look_at(state.look_at + point_on_sphere, state.look_at, nm::float3 {0.0f, 1.0f, 0.0f}), 40 | nm::perspective(nm::deg2rad(state.vfov), aspect_ratio, 0.01f, 1000.0f)}; 41 | } 42 | 43 | void camera_ui( 44 | camera_state& state, 45 | std::pair look_at_range, 46 | float look_at_speed, 47 | std::pair radius_range, 48 | float radius_speed) { 49 | NGF_MISC_ASSERT(look_at_range.first < look_at_range.second); 50 | NGF_MISC_ASSERT(radius_range.first < radius_range.second); 51 | ImGui::Text("camera"); 52 | ImGui::DragFloat3( 53 | "look at", 54 | state.look_at.data, 55 | look_at_speed, 56 | look_at_range.first, 57 | look_at_range.second, 58 | "%.1f", 59 | 0); 60 | ImGui::SliderFloat("azimuth", &state.azimuth, 0.0f, (float)M_PI * 2.0f, "%.1f", ImGuiSliderFlags_NoRoundToFormat); 61 | ImGui::SliderFloat("inclination", &state.inclination, 0.0f, (float)M_PI, "%.1f", ImGuiSliderFlags_NoRoundToFormat); 62 | ImGui::DragFloat( 63 | "radius", 64 | &state.radius, 65 | radius_speed, 66 | radius_range.first, 67 | radius_range.second, 68 | "%.1f", 69 | 0); 70 | ImGui::SliderFloat("fov", &state.vfov, 25.0f, 90.0f, "%.1f", 0); 71 | } 72 | 73 | } // namespace ngf_samples -------------------------------------------------------------------------------- /source/ngf-common/stack-alloc.h: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2025 nicegraf contributors 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | The above copyright notice and this permission notice shall be included in all 10 | copies or substantial portions of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 13 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 14 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 15 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 17 | SOFTWARE. 18 | */ 19 | #pragma once 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #ifdef __cplusplus 26 | extern "C" { 27 | #endif 28 | 29 | typedef struct ngfi_sa_t { 30 | uint8_t* ptr; 31 | size_t capacity; 32 | size_t total_consumed; 33 | size_t total_allocd; 34 | struct ngfi_sa_t* next_block; 35 | struct ngfi_sa_t* active_block; 36 | #pragma warning(push) 37 | #pragma warning(disable : 4200) 38 | uint8_t data[]; 39 | #pragma warning(pop) 40 | } ngfi_sa; 41 | 42 | /** 43 | * creates a new stack allocator with the given capacity. 44 | */ 45 | ngfi_sa* ngfi_sa_create(size_t capacity); 46 | 47 | /** 48 | * allocates a specified amount of bytes from the given stack allocator 49 | * and returns a pointer to the start of the allocated region. 50 | * if the allocator has no available capacity to accomodate the request, 51 | * returns a null pointer. 52 | */ 53 | void* ngfi_sa_alloc(ngfi_sa* allocator, size_t nbytes); 54 | 55 | /** 56 | * resets the state of the given stack allocator. capacity is fully restored, 57 | * all pointers to memory previously allocated are invalidated. 58 | */ 59 | void ngfi_sa_reset(ngfi_sa* allocator); 60 | 61 | /** 62 | * tear down the given stack allocator. 63 | */ 64 | void ngfi_sa_destroy(ngfi_sa* allocator); 65 | 66 | /** 67 | * Dumps the given stack allocator's debug statics. 68 | */ 69 | void ngfi_sa_dump_dbgstats(ngfi_sa* allocator, FILE* out); 70 | 71 | /** 72 | * Per-thread temporary storage based on stack allocator. 73 | */ 74 | ngfi_sa* ngfi_tmp_store(void); 75 | 76 | /** 77 | * Per-thread temporary storage that only gets reset at the start of a frame, 78 | * based on stack allocator. 79 | */ 80 | ngfi_sa* ngfi_frame_store(void); 81 | 82 | /** 83 | * Helper macro to allocate N objects from per-thread stack allocator. 84 | */ 85 | #define NGFI_SALLOC(type, n) (ngfi_sa_alloc(ngfi_tmp_store(), sizeof(type) * (n))) 86 | 87 | #ifdef __cplusplus 88 | } 89 | #endif 90 | -------------------------------------------------------------------------------- /misc/common/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2023 nicegraf contributors 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | this software and associated documentation files (the “Software”), to deal in 6 | the Software without restriction, including without limitation the rights to 7 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 8 | the Software, and to permit persons to whom the Software is furnished to do so, 9 | subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | ]] 22 | 23 | cmake_minimum_required(VERSION 3.23.3) 24 | project(nicegraf-misc-common) 25 | 26 | 27 | set(CMAKE_C_STANDARD 99) 28 | set(CMAKE_CXX_STANDARD 20) 29 | 30 | include("${CMAKE_CURRENT_LIST_DIR}/../../build-utils.cmake") 31 | 32 | if (WIN32) 33 | set(NICESHADE_PLATFORM win PARENT_SCOPE) 34 | set(NGF_BACKEND nicegraf-vk) 35 | elseif(APPLE) 36 | set(NICESHADE_PLATFORM macos PARENT_SCOPE) 37 | if (NGF_USE_MVK STREQUAL "yes") 38 | set(NGF_BACKEND nicegraf-vk) 39 | else() 40 | set(NGF_BACKEND nicegraf-mtl) 41 | endif() 42 | elseif(UNIX AND NOT APPLE) 43 | set(NICESHADE_PLATFORM linux PARENT_SCOPE) 44 | set(NGF_BACKEND nicegraf-vk) 45 | else() 46 | message(FATAL_ERROR "Your platform is not currently supported by nicegraf.") 47 | endif() 48 | 49 | nmk_header_library(NAME nicegraf 50 | PUB_INCLUDES ${CMAKE_CURRENT_LIST_DIR}/../../include 51 | PUB_DEPS ${NGF_BACKEND}) 52 | 53 | 54 | string(TOUPPER "NGF_BACKEND_${NGF_BACKEND}" NGF_BACKEND_DEFINE) 55 | string(REPLACE "-" "_" NGF_BACKEND_DEFINE ${NGF_BACKEND_DEFINE}) 56 | 57 | if (NGF_BUILD_SAMPLES STREQUAL "yes") 58 | nmk_static_library(NAME nicegraf-misc-common 59 | SRCS ${CMAKE_CURRENT_LIST_DIR}/shader-loader.h 60 | ${CMAKE_CURRENT_LIST_DIR}/shader-loader.cpp 61 | ${CMAKE_CURRENT_LIST_DIR}/file-utils.h 62 | ${CMAKE_CURRENT_LIST_DIR}/file-utils.cpp 63 | ${CMAKE_CURRENT_LIST_DIR}/mesh-loader.cpp 64 | ${CMAKE_CURRENT_LIST_DIR}/mesh-loader.h 65 | ${CMAKE_CURRENT_LIST_DIR}/targa-loader.cpp 66 | ${CMAKE_CURRENT_LIST_DIR}/targa-loader.h 67 | ${CMAKE_CURRENT_LIST_DIR}/logging.h 68 | DEPS nicegraf 69 | PVT_DEFINES ${NGF_BACKEND_DEFINE} 70 | PUB_INCLUDES ${CMAKE_CURRENT_LIST_DIR}/) 71 | endif() 72 | -------------------------------------------------------------------------------- /deps/vulkan-headers/vulkan/vk_platform.h: -------------------------------------------------------------------------------- 1 | // 2 | // File: vk_platform.h 3 | // 4 | /* 5 | ** Copyright 2014-2022 The Khronos Group Inc. 6 | ** 7 | ** SPDX-License-Identifier: Apache-2.0 8 | */ 9 | 10 | 11 | #ifndef VK_PLATFORM_H_ 12 | #define VK_PLATFORM_H_ 13 | 14 | #ifdef __cplusplus 15 | extern "C" 16 | { 17 | #endif // __cplusplus 18 | 19 | /* 20 | *************************************************************************************************** 21 | * Platform-specific directives and type declarations 22 | *************************************************************************************************** 23 | */ 24 | 25 | /* Platform-specific calling convention macros. 26 | * 27 | * Platforms should define these so that Vulkan clients call Vulkan commands 28 | * with the same calling conventions that the Vulkan implementation expects. 29 | * 30 | * VKAPI_ATTR - Placed before the return type in function declarations. 31 | * Useful for C++11 and GCC/Clang-style function attribute syntax. 32 | * VKAPI_CALL - Placed after the return type in function declarations. 33 | * Useful for MSVC-style calling convention syntax. 34 | * VKAPI_PTR - Placed between the '(' and '*' in function pointer types. 35 | * 36 | * Function declaration: VKAPI_ATTR void VKAPI_CALL vkCommand(void); 37 | * Function pointer type: typedef void (VKAPI_PTR *PFN_vkCommand)(void); 38 | */ 39 | #if defined(_WIN32) 40 | // On Windows, Vulkan commands use the stdcall convention 41 | #define VKAPI_ATTR 42 | #define VKAPI_CALL __stdcall 43 | #define VKAPI_PTR VKAPI_CALL 44 | #elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH < 7 45 | #error "Vulkan is not supported for the 'armeabi' NDK ABI" 46 | #elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7 && defined(__ARM_32BIT_STATE) 47 | // On Android 32-bit ARM targets, Vulkan functions use the "hardfloat" 48 | // calling convention, i.e. float parameters are passed in registers. This 49 | // is true even if the rest of the application passes floats on the stack, 50 | // as it does by default when compiling for the armeabi-v7a NDK ABI. 51 | #define VKAPI_ATTR __attribute__((pcs("aapcs-vfp"))) 52 | #define VKAPI_CALL 53 | #define VKAPI_PTR VKAPI_ATTR 54 | #else 55 | // On other platforms, use the default calling convention 56 | #define VKAPI_ATTR 57 | #define VKAPI_CALL 58 | #define VKAPI_PTR 59 | #endif 60 | 61 | #if !defined(VK_NO_STDDEF_H) 62 | #include 63 | #endif // !defined(VK_NO_STDDEF_H) 64 | 65 | #if !defined(VK_NO_STDINT_H) 66 | #if defined(_MSC_VER) && (_MSC_VER < 1600) 67 | typedef signed __int8 int8_t; 68 | typedef unsigned __int8 uint8_t; 69 | typedef signed __int16 int16_t; 70 | typedef unsigned __int16 uint16_t; 71 | typedef signed __int32 int32_t; 72 | typedef unsigned __int32 uint32_t; 73 | typedef signed __int64 int64_t; 74 | typedef unsigned __int64 uint64_t; 75 | #else 76 | #include 77 | #endif 78 | #endif // !defined(VK_NO_STDINT_H) 79 | 80 | #ifdef __cplusplus 81 | } // extern "C" 82 | #endif // __cplusplus 83 | 84 | #endif 85 | -------------------------------------------------------------------------------- /source/ngf-common/cmdbuf-state.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2023 nicegraf contributors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * 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 Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #include "cmdbuf-state.h" 24 | 25 | #include "macros.h" 26 | 27 | ngf_error ngfi_transition_cmd_buf( 28 | ngfi_cmd_buffer_state* cur_state, 29 | bool has_active_renderpass, 30 | ngfi_cmd_buffer_state new_state) { 31 | switch (new_state) { 32 | case NGFI_CMD_BUFFER_NEW: 33 | NGFI_DIAG_ERROR("command buffer cannot go back to a `new` state"); 34 | return NGF_ERROR_INVALID_OPERATION; 35 | case NGFI_CMD_BUFFER_READY: 36 | if (*cur_state != NGFI_CMD_BUFFER_SUBMITTED && *cur_state != NGFI_CMD_BUFFER_READY && 37 | *cur_state != NGFI_CMD_BUFFER_NEW) { 38 | NGFI_DIAG_ERROR("command buffer not in a startable state."); 39 | return NGF_ERROR_INVALID_OPERATION; 40 | } 41 | break; 42 | case NGFI_CMD_BUFFER_RECORDING: 43 | if (!NGFI_CMD_BUF_RECORDABLE(*cur_state)) { 44 | NGFI_DIAG_ERROR("command buffer not in a recordable state."); 45 | return NGF_ERROR_INVALID_OPERATION; 46 | } 47 | break; 48 | case NGFI_CMD_BUFFER_READY_TO_SUBMIT: 49 | if (*cur_state != NGFI_CMD_BUFFER_RECORDING) { 50 | NGFI_DIAG_ERROR("command buffer is not actively recording."); 51 | return NGF_ERROR_INVALID_OPERATION; 52 | } 53 | if (has_active_renderpass) { 54 | NGFI_DIAG_ERROR("cannot finish render encoder with an unterminated render pass."); 55 | return NGF_ERROR_INVALID_OPERATION; 56 | } 57 | break; 58 | case NGFI_CMD_BUFFER_PENDING: 59 | if (*cur_state != NGFI_CMD_BUFFER_READY_TO_SUBMIT && *cur_state != NGFI_CMD_BUFFER_READY) { 60 | NGFI_DIAG_ERROR("command buffer not ready to be submitted"); 61 | return NGF_ERROR_INVALID_OPERATION; 62 | } 63 | break; 64 | case NGFI_CMD_BUFFER_SUBMITTED: 65 | if (*cur_state != NGFI_CMD_BUFFER_PENDING) { 66 | NGFI_DIAG_ERROR("command buffer not in a submittable state"); 67 | return NGF_ERROR_INVALID_OPERATION; 68 | } 69 | break; 70 | } 71 | *cur_state = new_state; 72 | return NGF_ERROR_OK; 73 | } 74 | -------------------------------------------------------------------------------- /source/ngf-common/internal.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2021 nicegraf contributors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * 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 Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | * DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #include "macros.h" 24 | 25 | #include 26 | #include 27 | 28 | struct { 29 | size_t allocated_mem; 30 | pthread_mutex_t mut; 31 | } ngfi_sys_alloc_stats; 32 | 33 | ngf_diagnostic_info ngfi_diag_info = { 34 | .verbosity = NGF_DIAGNOSTICS_VERBOSITY_DEFAULT, 35 | .userdata = NULL, 36 | .callback = NULL}; 37 | 38 | // Default allocation callbacks. 39 | void* ngf_default_alloc(size_t obj_size, size_t nobjs, void* userdata) { 40 | NGFI_IGNORE_VAR(userdata); 41 | pthread_mutex_lock(&ngfi_sys_alloc_stats.mut); 42 | ngfi_sys_alloc_stats.allocated_mem += obj_size * nobjs; 43 | pthread_mutex_unlock(&ngfi_sys_alloc_stats.mut); 44 | return malloc(obj_size * nobjs); 45 | } 46 | 47 | void ngf_default_free(void* ptr, size_t s, size_t n, void* userdata) { 48 | NGFI_IGNORE_VAR(s); 49 | NGFI_IGNORE_VAR(n); 50 | NGFI_IGNORE_VAR(userdata); 51 | pthread_mutex_lock(&ngfi_sys_alloc_stats.mut); 52 | ngfi_sys_alloc_stats.allocated_mem -= s * n; 53 | pthread_mutex_unlock(&ngfi_sys_alloc_stats.mut); 54 | free(ptr); 55 | } 56 | 57 | const ngf_allocation_callbacks NGF_DEFAULT_ALLOC_CB = {ngf_default_alloc, ngf_default_free, NULL}; 58 | 59 | const ngf_allocation_callbacks* NGF_ALLOC_CB = &NGF_DEFAULT_ALLOC_CB; 60 | 61 | void ngfi_set_allocation_callbacks(const ngf_allocation_callbacks* callbacks) { 62 | static bool mutex_inited = false; 63 | if (callbacks == NULL) { 64 | NGF_ALLOC_CB = &NGF_DEFAULT_ALLOC_CB; 65 | if (!mutex_inited) { 66 | pthread_mutex_init(&ngfi_sys_alloc_stats.mut, 0); 67 | mutex_inited = true; 68 | } 69 | } else { 70 | NGF_ALLOC_CB = callbacks; 71 | } 72 | } 73 | 74 | ngf_sample_count ngfi_get_highest_sample_count(size_t counts_bitmap) { 75 | size_t res = (size_t)NGF_SAMPLE_COUNT_64; 76 | while ((res & counts_bitmap) == 0 && res > 1) { res >>= 1; } 77 | return (ngf_sample_count)res; 78 | } 79 | 80 | void ngfi_dump_sys_alloc_dbgstats(FILE* out) { 81 | fprintf(out, "System allocator debug stats\n"); 82 | fprintf(out, "Requested memory:\t%zu\n", ngfi_sys_alloc_stats.allocated_mem); 83 | } -------------------------------------------------------------------------------- /source/ngf-common/block-alloc.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2023 nicegraf contributors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * 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 Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | #include 27 | 28 | #ifdef __cplusplus 29 | extern "C" { 30 | #endif 31 | 32 | /* A fast fixed-size block allocator. 33 | * Doles out memory in fixed-size blocks from a pool. 34 | * A block allocator is created with a certain initial capacity. If the block 35 | * capacity is exceeded, an additional block pool is allocated. 36 | */ 37 | typedef struct ngfi_block_allocator ngfi_block_allocator; 38 | 39 | /** 40 | * Creates a new block allocator with a given fixed `block_size` and a given 41 | * initial capacity of `nblocks` blocks. 42 | */ 43 | ngfi_block_allocator* ngfi_blkalloc_create(uint32_t block_size, uint32_t nblocks); 44 | 45 | /** 46 | * Destroys the given block allocator. Calling this function will make all unfreed 47 | * pointers obtained from the given allocator invalid. 48 | */ 49 | void ngfi_blkalloc_destroy(ngfi_block_allocator* alloc); 50 | 51 | /** 52 | * Allocates the next free block from the allocator. Returns NULL on error. 53 | */ 54 | void* ngfi_blkalloc_alloc(ngfi_block_allocator* alloc); 55 | 56 | /** 57 | * Returns the size of the block for the given allocator. 58 | */ 59 | uint32_t ngfi_blkalloc_blksize(ngfi_block_allocator* alloc); 60 | 61 | typedef enum { 62 | NGFI_BLK_NO_ERROR, 63 | 64 | /** 65 | * Indicates that a `free` operation failed because the given block had previously 66 | * been freed. This error is checked for in debug builds only. 67 | */ 68 | NGFI_BLK_DOUBLE_FREE, 69 | 70 | /** 71 | * Inidicates that a `free` operation failed because the given block was not allocated from 72 | * the given allocator. This error is checked for in debug builds only. 73 | */ 74 | NGFI_BLK_WRONG_ALLOCATOR 75 | } ngfi_blkalloc_error; 76 | 77 | /** 78 | * Returns the given block to the allocator. 79 | * Freeing a NULL pointer does nothing. 80 | */ 81 | ngfi_blkalloc_error ngfi_blkalloc_free(ngfi_block_allocator* alloc, void* ptr); 82 | 83 | /** 84 | * Cleans up unused pools from the given allocator. 85 | */ 86 | void ngfi_blkalloc_cleanup(ngfi_block_allocator* alloc); 87 | 88 | /** 89 | * Logs the statistics related to the given allocator into the given file. 90 | */ 91 | void ngfi_blkalloc_dump_dbgstats(ngfi_block_allocator* alloc, FILE* out); 92 | 93 | #ifdef __cplusplus 94 | } 95 | #endif 96 | 97 | -------------------------------------------------------------------------------- /source/ngf-common/dynamic-array.h: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2019 nicegraf contributors 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | The above copyright notice and this permission notice shall be included in all 10 | copies or substantial portions of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 13 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 14 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 15 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 17 | SOFTWARE. 18 | */ 19 | #pragma once 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #define NGFI_DARRAY_OF(type) struct { \ 27 | type *data; \ 28 | type *endptr; \ 29 | uint32_t capacity; \ 30 | } 31 | 32 | #if !defined(__cplusplus) 33 | #define decltype(x) void* 34 | #endif 35 | 36 | #define NGFI_DARRAY_RESET(a, c) { \ 37 | a.data = (decltype(a.data))malloc(sizeof(a.data[0]) * c); \ 38 | a.endptr = a.data; \ 39 | a.capacity = c; \ 40 | } 41 | 42 | #define NGFI_DARRAY_RESIZE(a, s) { \ 43 | uint32_t size = (s); \ 44 | if (a.capacity < size) { \ 45 | a.data = (decltype(a.data))realloc(a.data, sizeof(a.data[0]) * size); \ 46 | a.capacity = size; \ 47 | } \ 48 | a.endptr = a.data + size; \ 49 | } 50 | 51 | #define NGFI_DARRAY_DESTROY(a) if(a.data != NULL) { \ 52 | free(a.data); \ 53 | a.data = a.endptr = NULL; \ 54 | } 55 | 56 | #define NGFI_DARRAY_APPEND(a, v) { \ 57 | ptrdiff_t cur_size = a.endptr - a.data; \ 58 | assert(cur_size >= 0); \ 59 | if ((size_t)cur_size >= a.capacity) { \ 60 | a.capacity <<= 1u; \ 61 | decltype(a.data) tmp = (decltype(a.data)) realloc(a.data, sizeof(a.data[0]) * a.capacity); \ 62 | assert(tmp != NULL); \ 63 | a.data = tmp; \ 64 | a.endptr = &a.data[cur_size]; \ 65 | } \ 66 | *(a.endptr++) = v; \ 67 | } 68 | 69 | #define NGFI_DARRAY_APPEND_EMPTY(a) { \ 70 | ptrdiff_t cur_size = a.endptr - a.data; \ 71 | assert(cur_size >= 0); \ 72 | if ((size_t)cur_size >= a.capacity) { \ 73 | a.capacity <<= 1u; \ 74 | decltype(a.data) tmp = (decltype(a.data)) realloc(a.data, sizeof(a.data[0]) * a.capacity); \ 75 | assert(tmp != NULL); \ 76 | a.data = tmp; \ 77 | a.endptr = &a.data[cur_size]; \ 78 | } \ 79 | a.endptr++; \ 80 | } 81 | 82 | #define NGFI_DARRAY_CLEAR(a) ((a).endptr = (a).data) 83 | #define NGFI_DARRAY_SIZE(a) ((uint32_t)((a).endptr - (a).data)) 84 | #define NGFI_DARRAY_AT(a, i) ((a).data[(i)]) 85 | 86 | #define NGFI_DARRAY_POP(a) {\ 87 | assert((a).data != (a).endptr); \ 88 | --((a).endptr); \ 89 | } 90 | 91 | #define NGFI_DARRAY_EMPTY(a) (a.endptr == a.data) 92 | 93 | #define NGFI_DARRAY_BACKPTR(a) (a.endptr - 1) 94 | 95 | #define NGFI_DARRAY_FOREACH(a, countername) \ 96 | for (size_t countername = 0; (countername) < NGFI_DARRAY_SIZE(a); ++(countername)) 97 | -------------------------------------------------------------------------------- /include/nicegraf-vk-handles.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2023 nicegraf contributors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * 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 Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | #include "nicegraf.h" 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | /** 31 | * \ingroup ngf 32 | * 33 | * Returns the underlying VkDevice handle cast to uintptr_t. The caller is responsible for casting 34 | * the return value to a VkDevice. 35 | */ 36 | uintptr_t ngf_get_vk_device_handle() NGF_NOEXCEPT; 37 | 38 | /** 39 | * \ingroup ngf 40 | * 41 | * Returns the underlying VkInstance handle cast to uintptr_t. The caller is responsible for casting 42 | * the return value to a VkInstance. 43 | */ 44 | uintptr_t ngf_get_vk_instance_handle() NGF_NOEXCEPT; 45 | 46 | /** 47 | * \ingroup ngf 48 | * 49 | * Returns a uintptr_t to the underlying VkImage. The caller is responsible for casting the return 50 | * value to a VkImage. 51 | * 52 | * @param image A handle to a nicegraf image. 53 | */ 54 | uintptr_t ngf_get_vk_image_handle(ngf_image image) NGF_NOEXCEPT; 55 | 56 | /** 57 | * \ingroup ngf 58 | * 59 | * Returns a uintptr_t to the underlying VkBuffer. The caller is responsible for casting the return 60 | * value to a VkBuffer. 61 | * 62 | * @param buffer A handle to a nicegraf buffer. 63 | */ 64 | uintptr_t ngf_get_vk_buffer_handle(ngf_buffer buffer) NGF_NOEXCEPT; 65 | 66 | /** 67 | * \ingroup ngf 68 | * 69 | * Returns a uintptr_t to the underlying VkCommandBuffer. The caller is responsible for casting 70 | * the return value to a VkCommandBuffer. 71 | * 72 | * @param cmd_buffer A handle to a nicegraf command buffer. 73 | */ 74 | uintptr_t ngf_get_vk_cmd_buffer_handle(ngf_cmd_buffer cmd_buffer) NGF_NOEXCEPT; 75 | 76 | /** 77 | * \ingroup ngf 78 | * 79 | * Returns a uintptr_t to the underlying VkSampler. The caller is responsible for casting the 80 | * return value to a VkSampler. 81 | * 82 | * @param sampler A handle to a nicegraf sampler. 83 | */ 84 | uintptr_t ngf_get_vk_sampler_handle(ngf_sampler sampler) NGF_NOEXCEPT; 85 | 86 | /** 87 | * \ingroup ngf 88 | * 89 | * Returns a uint32_t representing the underlying VkFormat. The caller is responsible for casting the return 90 | * value to a VkFormat. 91 | * 92 | * @param format A nicegraf image format. 93 | */ 94 | uint32_t ngf_get_vk_image_format_index(ngf_image_format format) NGF_NOEXCEPT; 95 | 96 | #ifdef __cplusplus 97 | } 98 | #endif 99 | 100 | -------------------------------------------------------------------------------- /source/ngf-common/list.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2025 nicegraf contributors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * 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 Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | #include 27 | 28 | #ifdef __cplusplus 29 | extern "C" { 30 | #endif 31 | 32 | /** 33 | * A circular, intrusive, doubly-linked list. 34 | * This data type is not thread-safe. 35 | */ 36 | typedef struct ngfi_list_node { 37 | struct ngfi_list_node* next; 38 | struct ngfi_list_node* prev; 39 | } ngfi_list_node; 40 | 41 | /** 42 | * Appends a new node at the end of the list represented by `head_node`. 43 | */ 44 | static inline void ngfi_list_append(ngfi_list_node* new_node, ngfi_list_node* head_node) { 45 | assert(new_node->next == new_node->prev); 46 | assert(new_node->next == new_node); 47 | ngfi_list_node* old_tail = head_node->prev; 48 | old_tail->next = new_node; 49 | new_node->next = head_node; 50 | new_node->prev = old_tail; 51 | head_node->prev = new_node; 52 | } 53 | 54 | /** 55 | * Removes the given node from the list it's currently in. 56 | */ 57 | static inline void ngfi_list_remove(ngfi_list_node* node) { 58 | assert(node->prev->next == node); 59 | assert(node->next->prev == node); 60 | node->prev->next = node->next; 61 | node->next->prev = node->prev; 62 | node->prev = node; 63 | node->next = node; 64 | } 65 | 66 | /** 67 | * Initializes an isolated node that isn't a member of a list. 68 | */ 69 | static inline void ngfi_list_init(ngfi_list_node* node) { 70 | node->next = node; 71 | node->prev = node; 72 | } 73 | 74 | /** 75 | * Obtains ptr to the structure containing the given list node field. 76 | */ 77 | #define NGFI_LIST_CONTAINER_OF(ptr, type, node_name) (type*)((char*)(ptr)-offsetof(type, node_name)) 78 | 79 | /** 80 | * Iterates over all the elements in the list in order, starting at the given one. 81 | */ 82 | #define NGFI_LIST_FOR_EACH(list, node_name) for (ngfi_list_node* node_name = (list), *node_name##_prev = NULL; \ 83 | (list) && (!node_name##_prev || node_name##_prev->next != (list)); \ 84 | node_name##_prev = node_name, node_name = node_name->next) 85 | 86 | #define NGFI_LIST_FOR_EACH_CONST(list, node_name) for (const ngfi_list_node* node_name = (list), *node_name##_prev = NULL; \ 87 | (list) && (!node_name##_prev || node_name##_prev->next != (list)); \ 88 | node_name##_prev = node_name, node_name = node_name->next) 89 | 90 | #ifdef __cplusplus 91 | } 92 | #endif 93 | 94 | -------------------------------------------------------------------------------- /include/nicegraf-util.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2021 nicegraf contributors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * 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 Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include "nicegraf.h" 26 | 27 | #include 28 | 29 | /** 30 | * @file 31 | * \defgroup ngf_util Utility Library 32 | * 33 | * This module contains routines and structures that provide auxiliary functionality or help reduce boilerplate. 34 | */ 35 | 36 | #ifdef __cplusplus 37 | extern "C" { 38 | #endif 39 | 40 | /** 41 | * @struct ngf_util_graphics_pipeline_data 42 | * \ingroup ngf_util 43 | * 44 | * Contains all the data describing a graphics pipeline, with the exception 45 | * of shader stages. 46 | * 47 | * See \ref ngf_util_create_default_graphics_pipeline_data for more details. 48 | */ 49 | typedef struct ngf_util_graphics_pipeline_data { 50 | ngf_graphics_pipeline_info pipeline_info; /**< Can be used to initialize a new pipeline object. */ 51 | ngf_depth_stencil_info depth_stencil_info; 52 | ngf_vertex_input_info vertex_input_info; 53 | ngf_multisample_info multisample_info; 54 | ngf_rasterization_info rasterization_info; 55 | ngf_input_assembly_info input_assembly_info; 56 | ngf_specialization_info spec_info; 57 | } ngf_util_graphics_pipeline_data; 58 | 59 | /** 60 | * \ingroup ngf_util 61 | * 62 | * Creates a configuration for a graphics pipeline object with some pre-set defaults. 63 | * 64 | * The fields of the members of the resulting \ref ngf_util_graphics_pipeline_data are set such that 65 | * they match OpenGL defaults. They can be adjusted later. The pointer fields of \ref 66 | * ngf_util_graphics_pipeline_data::pipeline_info are set to point to the corresponding members of 67 | * \ref ngf_util_graphics_pipeline_data. 68 | * 69 | * The only aspect of configuration that this function does not set are the programmable shader stages. After the application code sets those, \ref 70 | * ngf_util_graphics_pipeline_data::pipeline_info can be used to create a new pipeline object. 71 | * 72 | * @param result Pipeline configuration data will be stored here. 73 | */ 74 | void ngf_util_create_default_graphics_pipeline_data(ngf_util_graphics_pipeline_data* result); 75 | 76 | /** 77 | * \ingroup ngf_util 78 | * 79 | * Converts a nicegraf error code to a human-readable string. 80 | * 81 | * @param err The error enum to get the string for. 82 | * @return A human-readable error message. 83 | */ 84 | const char* ngf_util_get_error_name(const ngf_error err); 85 | 86 | /** 87 | * \ingroup ngf_util 88 | * 89 | * Rounds `value` up to the nearest multiple of `alignment`. 90 | */ 91 | static inline size_t ngf_util_align_size(size_t value, size_t alignment) { 92 | const size_t m = value % alignment; 93 | return value + (m > 0 ? (alignment - m) : 0u); 94 | } 95 | 96 | #ifdef __cplusplus 97 | } 98 | #endif 99 | -------------------------------------------------------------------------------- /source/ngf-mtl/layer.mm: -------------------------------------------------------------------------------- 1 | #include "nicegraf.h" 2 | 3 | #import 4 | #import 5 | 6 | #if TARGET_OS_OSX 7 | #import 8 | using NGFMTL_VIEW_TYPE = NSView; 9 | #else 10 | #import 11 | using NGFMTL_VIEW_TYPE = UIView; 12 | #endif 13 | 14 | // Implementation is defined in impl.cpp, header only here 15 | #include "MetalSingleHeader.hpp" 16 | 17 | static const CFStringRef get_mtl_colorspace(ngf_colorspace colorspace) { 18 | const CFStringRef color_spaces[NGF_COLORSPACE_COUNT] = { 19 | kCGColorSpaceSRGB, 20 | kCGColorSpaceExtendedSRGB, 21 | kCGColorSpaceExtendedLinearSRGB, 22 | kCGColorSpaceDisplayP3, 23 | kCGColorSpaceExtendedLinearDisplayP3, 24 | kCGColorSpaceDCIP3, 25 | kCGColorSpaceExtendedLinearITUR_2020, 26 | kCGColorSpaceITUR_2100_PQ 27 | }; 28 | return color_spaces[colorspace]; 29 | } 30 | 31 | // Return type of CA::MetalLayer* 32 | CA::MetalLayer* ngf_layer_add_to_view(MTL::Device* device, 33 | uint32_t width, 34 | uint32_t height, 35 | MTL::PixelFormat pixel_format, 36 | ngf_colorspace colorspace, 37 | uint32_t capacity_hint, 38 | bool display_sync_enabled, 39 | bool compute_access_enabled, 40 | uintptr_t native_handle) { 41 | CAMetalLayer* layer_ = [CAMetalLayer layer]; 42 | layer_.device = (__bridge id)device; 43 | layer_.drawableSize = CGSizeMake(width, height); 44 | layer_.pixelFormat = (MTLPixelFormat)pixel_format; // TODO: Is this cast correct? 45 | layer_.colorspace = CGColorSpaceCreateWithName(get_mtl_colorspace(colorspace)); 46 | layer_.framebufferOnly = compute_access_enabled ? NO : YES; 47 | #if TARGET_OS_OSX 48 | if (@available(macOS 10.13.2, *)) { 49 | layer_.maximumDrawableCount = capacity_hint; 50 | } 51 | if (@available(macOS 10.13, *)) { 52 | layer_.displaySyncEnabled = display_sync_enabled; 53 | } 54 | #endif 55 | 56 | const bool supports_edr = colorspace == NGF_COLORSPACE_EXTENDED_SRGB_LINEAR || 57 | colorspace == NGF_COLORSPACE_DISPLAY_P3_LINEAR || 58 | colorspace == NGF_COLORSPACE_ITUR_BT2020 || 59 | colorspace == NGF_COLORSPACE_ITUR_BT2100_PQ; 60 | 61 | if (supports_edr) { 62 | #if TARGET_OS_OSX 63 | if (@available(macOS 10.11, *)) { 64 | layer_.wantsExtendedDynamicRangeContent = YES; 65 | } 66 | #else 67 | if (@available(iOS 16.0, *)) { 68 | layer_.wantsExtendedDynamicRangeContent = YES; 69 | } 70 | #endif 71 | } 72 | 73 | // Associate the newly created Metal layer with the user-provided View. 74 | NGFMTL_VIEW_TYPE* view = CFBridgingRelease((void*)native_handle); 75 | #if TARGET_OS_OSX 76 | [view setLayer:layer_]; 77 | #else 78 | [view.layer addSublayer:layer_]; 79 | [layer_ setContentsScale:view.layer.contentsScale]; 80 | [layer_ setContentsGravity:kCAGravityResizeAspect]; 81 | [layer_ setFrame:view.frame]; 82 | #endif 83 | CFBridgingRetain(view); 84 | 85 | return (__bridge_retained CA::MetalLayer*)layer_; 86 | } 87 | 88 | CA::MetalDrawable* ngf_layer_next_drawable(CA::MetalLayer* layer) { 89 | return (__bridge CA::MetalDrawable*)[(__bridge CAMetalLayer*)layer nextDrawable]; 90 | } 91 | 92 | void ngf_resize_swapchain(CA::MetalLayer* layer, 93 | uint32_t width, 94 | uint32_t height, 95 | uintptr_t native_handle) { 96 | CAMetalLayer* bridged_layer = (__bridge CAMetalLayer*)layer; 97 | 98 | bridged_layer.drawableSize = CGSizeMake(width, height); 99 | 100 | NGFMTL_VIEW_TYPE* view = CFBridgingRelease((void*)native_handle); 101 | 102 | [bridged_layer setContentsScale:view.layer.contentsScale]; 103 | [bridged_layer setFrame:view.frame]; 104 | 105 | CFBridgingRetain(view); 106 | } 107 | -------------------------------------------------------------------------------- /samples/common/sample-interface.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2023 nicegraf contributors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * 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 Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #pragma warning(disable:26812) 26 | #include "nicegraf.h" 27 | 28 | #include 29 | 30 | /** 31 | * Each sample has to implement the functions declared in this header. 32 | * They are called by the common sample code. 33 | */ 34 | namespace ngf_samples { 35 | 36 | /** 37 | * This function is called once at startup, to let the sample set up whatever it needs. 38 | * This function may assume that a nicegraf context has already been created and made current on 39 | * the calling thread. 40 | * It gets passed the dimensions of the window to be rendered to, as well as the sample count 41 | * of the main rendertarget. 42 | * It also gets a transfer encoder, which can samples can use to upload some resources to the 43 | * GPU. 44 | * The function shall return a pointer that will be passed in to other callbacks. 45 | */ 46 | void* sample_initialize( 47 | uint32_t initial_window_width, 48 | uint32_t initial_window_height, 49 | ngf_sample_count main_render_target_sample_count, 50 | ngf_xfer_encoder xfer_encoder); 51 | 52 | /** 53 | * This function gets called every frame before beginning the main render pass. 54 | * It receives the command buffer that the main render pass will eventually be 55 | * recorded into. 56 | */ 57 | void sample_pre_draw_frame(ngf_cmd_buffer cmd_buffer, void* userdata); 58 | 59 | /** 60 | * This function gets called every frame, to render the frame contents. 61 | * It gets passed a token identifying the frame, the current window dimensions, and a (monotonically 62 | * increasing) timestamp. Window resizes are generally handled in the common code, but it's up to 63 | * the specific sample to monitor for size changes and e.g. resize any rendertargets that have to 64 | * match screen resolution. `userdata` is the pointer returned previously by `sample_initialize`. 65 | */ 66 | void sample_draw_frame( 67 | ngf_render_encoder main_render_pass, 68 | float time_delta_ms, 69 | ngf_frame_token frame_token, 70 | uint32_t width, 71 | uint32_t height, 72 | float time, 73 | void* userdata); 74 | 75 | /** 76 | * This function gets called every frame after finishing the main render pass. 77 | * It receives the command buffer that the main render pass was previously 78 | * recorded into. 79 | */ 80 | void sample_post_draw_frame(ngf_cmd_buffer cmd_buffer, void* userdata); 81 | 82 | void sample_post_submit(void* userdata); 83 | 84 | 85 | /** 86 | * This function gets called every frame, to render the UI of the sample. It should mostly consist 87 | * of ImGui calls. `userdata` is the pointer returned previously by `sample_initialize`. 88 | */ 89 | void sample_draw_ui(void* userdata); 90 | 91 | /** 92 | * This function gets called once, before the sample ceases execution, to perform any cleanup 93 | * actions. This function may assume that a nicegraf context is still present and current on the 94 | * calling thread. `userdata` is the pointer returned previously by `sample_initialize`. 95 | */ 96 | void sample_shutdown(void* userdata); 97 | 98 | } // namespace ngf_samples 99 | -------------------------------------------------------------------------------- /source/ngf-common/util.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2021 nicegraf contributors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * 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 Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #include "ngf-common/macros.h" 24 | #include "nicegraf-util.h" 25 | 26 | #include 27 | #include 28 | 29 | #if defined(_WIN32) || defined(_WIN64) 30 | #pragma comment(lib, "ws2_32.lib") 31 | #include 32 | #else 33 | #include 34 | #endif 35 | 36 | void ngf_util_create_default_graphics_pipeline_data(ngf_util_graphics_pipeline_data* result) { 37 | ngf_stencil_info default_stencil = { 38 | .fail_op = NGF_STENCIL_OP_KEEP, 39 | .pass_op = NGF_STENCIL_OP_KEEP, 40 | .depth_fail_op = NGF_STENCIL_OP_KEEP, 41 | .compare_op = NGF_COMPARE_OP_EQUAL, 42 | .compare_mask = 0, 43 | .write_mask = 0, 44 | .reference = 0}; 45 | ngf_depth_stencil_info dsi = { 46 | .stencil_test = false, 47 | .depth_test = false, 48 | .depth_write = false, 49 | .depth_compare = NGF_COMPARE_OP_LESS, 50 | .front_stencil = default_stencil, 51 | .back_stencil = default_stencil}; 52 | result->depth_stencil_info = dsi; 53 | 54 | ngf_vertex_input_info vii = {.nattribs = 0, .nvert_buf_bindings = 0}; 55 | result->vertex_input_info = vii; 56 | 57 | ngf_multisample_info msi = {.sample_count = NGF_SAMPLE_COUNT_1, .alpha_to_coverage = false}; 58 | result->multisample_info = msi; 59 | 60 | ngf_rasterization_info ri = { 61 | .cull_mode = NGF_CULL_MODE_BACK, 62 | .discard = false, 63 | .front_face = NGF_FRONT_FACE_COUNTER_CLOCKWISE, 64 | .polygon_mode = NGF_POLYGON_MODE_FILL}; 65 | result->rasterization_info = ri; 66 | 67 | ngf_specialization_info spi = { 68 | .specializations = NULL, 69 | .nspecializations = 0u, 70 | .value_buffer = NULL}; 71 | result->spec_info = spi; 72 | 73 | ngf_input_assembly_info iai = { 74 | .enable_primitive_restart = false, 75 | .primitive_topology = NGF_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST}; 76 | result->input_assembly_info = iai; 77 | 78 | ngf_graphics_pipeline_info gpi = { 79 | .color_attachment_blend_states = NULL, 80 | .depth_stencil = &result->depth_stencil_info, 81 | .input_info = &result->vertex_input_info, 82 | .multisample = &result->multisample_info, 83 | .input_assembly_info = &result->input_assembly_info, 84 | .shader_stages = {NULL}, 85 | .nshader_stages = 0u, 86 | .rasterization = &result->rasterization_info, 87 | .spec_info = &result->spec_info, 88 | .debug_name = NULL}; 89 | result->pipeline_info = gpi; 90 | } 91 | 92 | const char* ngf_util_get_error_name(const ngf_error err) { 93 | static const char* ngf_error_names[] = { 94 | "NGF_ERROR_OK", 95 | "NGF_ERROR_OUT_OF_MEM", 96 | "NGF_ERROR_OBJECT_CREATION_FAILED", 97 | "NGF_ERROR_OUT_OF_BOUNDS", 98 | "NGF_ERROR_INVALID_FORMAT", 99 | "NGF_ERROR_INVALID_SIZE", 100 | "NGF_ERROR_INVALID_ENUM", 101 | "NGF_ERROR_INVALID_OPERATION"}; 102 | if ((size_t)err > NGFI_ARRAYSIZE(ngf_error_names)) { return "invalid error code"; } 103 | return ngf_error_names[err]; 104 | } 105 | -------------------------------------------------------------------------------- /source/ngf-common/chunk-list.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2023 nicegraf contributors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * 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 Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include "block-alloc.h" 26 | #include "list.h" 27 | 28 | #include 29 | #include 30 | 31 | typedef struct ngfi_chnk_hdr { 32 | ngfi_list_node clnode; 33 | uint32_t bytes_used; 34 | uint32_t bytes_total; 35 | } ngfi_chnk_hdr; 36 | 37 | typedef struct ngfi_chnklist { 38 | ngfi_block_allocator* blkalloc; 39 | ngfi_chnk_hdr* firstchnk; 40 | } ngfi_chnklist; 41 | 42 | static inline void* ngfi_chnk_data(ngfi_chnk_hdr* hdr, uint32_t offset) { 43 | return (void*)((char*)hdr + sizeof(*hdr) + offset); 44 | } 45 | 46 | static inline void* ngfi_chnklist_append(ngfi_chnklist* list, const void* data, uint32_t data_size) { 47 | assert(list); 48 | assert(data); 49 | assert(list->blkalloc); 50 | const uint32_t blksize = ngfi_blkalloc_blksize(list->blkalloc); 51 | if (blksize <= sizeof(ngfi_chnk_hdr) || blksize - sizeof(ngfi_chnk_hdr) < data_size) { 52 | return NULL; 53 | } 54 | ngfi_chnk_hdr* tail = 55 | list->firstchnk ? NGFI_LIST_CONTAINER_OF(&list->firstchnk->clnode, ngfi_chnk_hdr, clnode) 56 | : NULL; 57 | if (tail == NULL || tail->bytes_total - tail->bytes_used <= data_size) { 58 | ngfi_chnk_hdr* new_chnk = (ngfi_chnk_hdr*)ngfi_blkalloc_alloc(list->blkalloc); 59 | if (!new_chnk) { return NULL; } 60 | ngfi_list_init(&new_chnk->clnode); 61 | new_chnk->bytes_used = 0u; 62 | new_chnk->bytes_total = (uint32_t)blksize - (uint32_t)sizeof(ngfi_chnk_hdr); 63 | if (tail != NULL) { 64 | ngfi_list_append(&new_chnk->clnode, &tail->clnode); 65 | } else { 66 | list->firstchnk = new_chnk; 67 | } 68 | tail = new_chnk; 69 | } 70 | void* chnk_data = ngfi_chnk_data(tail, tail->bytes_used); 71 | memcpy(chnk_data, data, data_size); 72 | tail->bytes_used += data_size; 73 | return chnk_data; 74 | } 75 | 76 | #define NGFI_CHNK_FROM_NODE(node) (NGFI_LIST_CONTAINER_OF(node, ngfi_chnk_hdr, clnode)) 77 | 78 | static inline void ngfi_chnklist_clear(ngfi_chnklist* list) { 79 | assert(list); 80 | assert(list->blkalloc); 81 | while (list->firstchnk) { 82 | ngfi_chnk_hdr* old_hdr = list->firstchnk; 83 | list->firstchnk = list->firstchnk->clnode.next == &list->firstchnk->clnode 84 | ? NULL 85 | : NGFI_CHNK_FROM_NODE(list->firstchnk->clnode.next); 86 | ngfi_list_remove(&old_hdr->clnode); 87 | ngfi_blkalloc_free(list->blkalloc, old_hdr); 88 | } 89 | } 90 | 91 | #define NGFI_CHNK_FOR_EACH(chnk, elem_type, ptrname) \ 92 | for (elem_type* ptrname = ngfi_chnk_data((chnk), 0); \ 93 | ptrname - (elem_type*)ngfi_chnk_data((chnk), 0) < \ 94 | (ptrdiff_t)((chnk)->bytes_used / sizeof(elem_type)); \ 95 | ptrname++) 96 | 97 | #define NGFI_CHNKLIST_FOR_EACH(chnklist, elem_type, ptrname) \ 98 | if ((chnklist).firstchnk) NGFI_LIST_FOR_EACH(&(chnklist).firstchnk->clnode, ptrname##_node) \ 99 | NGFI_CHNK_FOR_EACH(NGFI_CHNK_FROM_NODE(ptrname##_node), elem_type, ptrname) 100 | 101 | typedef struct ngfi_chnk_range { 102 | ngfi_chnk_hdr* chnk; 103 | uint32_t start; 104 | uint32_t size; 105 | } ngfi_chnk_range; 106 | -------------------------------------------------------------------------------- /samples/shaders/blinn-phong.hlsl: -------------------------------------------------------------------------------- 1 | //T: blinn-phong vs:VSMain ps:PSMain 2 | 3 | [[vk::constant_id(0)]] const uint enableHalfLambert = 0; 4 | 5 | struct PixelShaderInput { 6 | float4 clipSpacePosition : SV_Position; 7 | float4 viewSpaceInterpNormal : ATTR0; 8 | float4 viewSpacePosition : ATTR1; 9 | }; 10 | 11 | struct VertexShaderInput { 12 | float3 objSpacePosition : SV_Position; 13 | float3 objSpaceNormal : ATTR0; 14 | }; 15 | 16 | struct ShaderUniforms { 17 | float4x4 objToViewTransform; 18 | float4x4 viewToClipTransform; 19 | float4 ambientLightIntensity; 20 | float4 viewSpacePointLightPosition; 21 | float4 pointLightIntensity; 22 | float4 viewSpaceDirectionalLightDirection; 23 | float4 directionalLightIntensity; 24 | float4 diffuseReflectance; 25 | float4 specularCoefficient; 26 | float shininess; 27 | }; 28 | 29 | [[vk::binding(0, 0)]] ConstantBuffer shaderUniforms; 30 | 31 | PixelShaderInput VSMain(VertexShaderInput vertexAttrs) { 32 | float4 viewSpacePosition = mul(shaderUniforms.objToViewTransform, float4(vertexAttrs.objSpacePosition, 1.0)); 33 | float4 viewSpaceNormal = normalize(mul(shaderUniforms.objToViewTransform, float4(vertexAttrs.objSpaceNormal, 0.0))); // TODO inverse transpose. 34 | float4 clipSpacePosition = mul(shaderUniforms.viewToClipTransform, viewSpacePosition); 35 | clipSpacePosition.y *= -1.0; 36 | PixelShaderInput result = { 37 | clipSpacePosition, 38 | viewSpaceNormal, 39 | viewSpacePosition, 40 | }; 41 | return result; 42 | } 43 | 44 | float computeCosineFactor(float3 direction, float3 normal) { 45 | float cosineFactor = dot(direction, normal); 46 | if (enableHalfLambert == 0) { 47 | return max(0.0, cosineFactor); 48 | } else { 49 | cosineFactor = 0.5 * cosineFactor + 0.5; 50 | cosineFactor *= cosineFactor; 51 | return cosineFactor; 52 | } 53 | } 54 | 55 | float3 computeIrradiance(float3 intensity, float3 direction, float3 normal, float distSquared) { 56 | return intensity * computeCosineFactor(direction, normal) / distSquared; 57 | } 58 | 59 | float3 computeSpecular(float3 position, float3 lightDirection, float3 normal, float shininess) { 60 | float3 directionToObserver = normalize(-position); 61 | float3 halfwayVector = normalize(directionToObserver + lightDirection); 62 | return pow(max(0.0, dot(normal, halfwayVector)), shininess); 63 | } 64 | 65 | float4 PSMain(PixelShaderInput fragmentAttribs) : SV_Target { 66 | float4 viewSpaceNormal = normalize(fragmentAttribs.viewSpaceInterpNormal); 67 | float4 viewSpaceVectorToPointLight = shaderUniforms.viewSpacePointLightPosition - fragmentAttribs.viewSpacePosition; 68 | float distanceToPointLightSquared = dot(viewSpaceVectorToPointLight, viewSpaceVectorToPointLight); 69 | float4 viewSpaceDirectionToPointLight = normalize(viewSpaceVectorToPointLight); 70 | float3 pointLightIrradiance = 71 | computeIrradiance( 72 | shaderUniforms.pointLightIntensity.rgb, 73 | viewSpaceDirectionToPointLight.xyz, 74 | viewSpaceNormal.xyz, 75 | distanceToPointLightSquared); 76 | float3 directionalLightIrradiance = 77 | computeIrradiance( 78 | shaderUniforms.directionalLightIntensity.rgb, 79 | normalize(shaderUniforms.viewSpaceDirectionalLightDirection.xyz), 80 | viewSpaceNormal.xyz, 81 | 1.0f); 82 | float3 specularReflectanceFromPointLight = 83 | shaderUniforms.specularCoefficient.rgb * 84 | computeSpecular( 85 | fragmentAttribs.viewSpacePosition.xyz, 86 | viewSpaceDirectionToPointLight.xyz, 87 | viewSpaceNormal.xyz, 88 | shaderUniforms.shininess); 89 | float3 specularReflectanceFromDirectionalLight = 90 | shaderUniforms.specularCoefficient.rgb * 91 | computeSpecular( 92 | fragmentAttribs.viewSpacePosition.xyz, 93 | normalize(shaderUniforms.viewSpaceDirectionalLightDirection.xyz), 94 | viewSpaceNormal.xyz, 95 | shaderUniforms.shininess); 96 | 97 | float3 pointLightContribution = (shaderUniforms.diffuseReflectance.rgb + specularReflectanceFromPointLight) * pointLightIrradiance; 98 | float3 directionalLightContribution = (shaderUniforms.diffuseReflectance.rgb + specularReflectanceFromDirectionalLight) * directionalLightIrradiance; 99 | 100 | return float4(pointLightContribution + directionalLightContribution + shaderUniforms.ambientLightIntensity.rgb, 1.0); 101 | } 102 | -------------------------------------------------------------------------------- /source/ngf-common/dict.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2023 nicegraf contributors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * 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 Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | #pragma once 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | typedef uintptr_t ngfi_dict_key; 29 | typedef struct ngfi_dict_t* ngfi_dict; 30 | typedef void* ngfi_dict_iter; 31 | 32 | typedef struct ngfi_dict_keyhash { 33 | ngfi_dict_key key; 34 | uint64_t hash; 35 | } ngfi_dict_keyhash; 36 | 37 | #define NGFI_DICT_INVALID_KEY (~((size_t)0u)) 38 | 39 | ngfi_dict ngfi_dict_create(size_t nslots, size_t val_size); 40 | void ngfi_dict_destroy(ngfi_dict dict); 41 | void ngfi_dict_clear(ngfi_dict dict); 42 | ngfi_dict_iter ngfi_dict_itstart(ngfi_dict dict); 43 | ngfi_dict_iter ngfi_dict_itnext(ngfi_dict dict, ngfi_dict_iter iter); 44 | void* ngfi_dict_itval(ngfi_dict dict, ngfi_dict_iter iter); 45 | size_t ngfi_dict_count(ngfi_dict dict); 46 | size_t ngfi_dict_nslots(ngfi_dict dict); 47 | float ngfi_dict_max_load_factor(ngfi_dict dict); 48 | void ngfi_dict_set_max_load_factor(ngfi_dict dict, float a); 49 | 50 | void* ngfi_dict_get( 51 | ngfi_dict* dict, 52 | ngfi_dict_key key, 53 | void* default_val, 54 | bool* new_entry, 55 | ngfi_dict_keyhash* keyhash_out); 56 | void* ngfi_dict_get_prehashed( 57 | ngfi_dict* dict, 58 | const ngfi_dict_keyhash* keyhash, 59 | void* default_val, 60 | bool* new_entry); 61 | 62 | #define NGFI_DICT_FOREACH(dict, itname) \ 63 | for (ngfi_dict_iter itname = ngfi_dict_itstart(dict); itname != NULL; \ 64 | itname = ngfi_dict_itnext(dict, itname)) 65 | 66 | #if defined(NGFI_DICT_TEST_MODE) 67 | extern void (*ngfi_dict_hashfn)(uintptr_t, uint32_t, void*); 68 | extern uint32_t ngfi_dict_hashseed; 69 | #endif 70 | 71 | /** 72 | * mumur3 hash function impl below. 73 | * this is a simplified version for keys 8 bytes in length. 74 | */ 75 | 76 | static inline uint64_t rotl64(uint64_t x, int8_t r) { 77 | return (x << r) | (x >> (64 - r)); 78 | } 79 | 80 | static inline uint64_t fmix64(uint64_t k) { 81 | k ^= k >> 33; 82 | k *= (0xff51afd7ed558ccdLLU); 83 | k ^= k >> 33; 84 | k *= (0xc4ceb9fe1a85ec53LLU); 85 | k ^= k >> 33; 86 | return k; 87 | } 88 | 89 | static inline void ngfi_mmh3_x64_128(uintptr_t key, const uint32_t seed, void* out) { 90 | const uint8_t* data = (const uint8_t*)&key; 91 | 92 | uint64_t h1 = seed; 93 | uint64_t h2 = seed; 94 | uint64_t c1 = (0x87c37b91114253d5LLU); 95 | uint64_t c2 = (0x4cf5ad432745937fLLU); 96 | uint64_t k1 = 0; 97 | 98 | k1 ^= (uint64_t)(data[7]) << 56; 99 | k1 ^= (uint64_t)(data[6]) << 48; 100 | k1 ^= (uint64_t)(data[5]) << 40; 101 | k1 ^= (uint64_t)(data[4]) << 32; 102 | k1 ^= (uint64_t)(data[3]) << 24; 103 | k1 ^= (uint64_t)(data[2]) << 16; 104 | k1 ^= (uint64_t)(data[1]) << 8; 105 | k1 ^= (uint64_t)(data[0]) << 0; 106 | k1 *= c1; 107 | k1 = rotl64(k1, 31); 108 | k1 *= c2; 109 | h1 ^= k1; 110 | 111 | h1 ^= sizeof(key); 112 | h2 ^= sizeof(key); 113 | 114 | h1 += h2; 115 | h2 += h1; 116 | 117 | h1 = fmix64(h1); 118 | h2 = fmix64(h2); 119 | 120 | h1 += h2; 121 | h2 += h1; 122 | 123 | ((uint64_t*)out)[0] = h1; 124 | ((uint64_t*)out)[1] = h2; 125 | } 126 | 127 | -------------------------------------------------------------------------------- /samples/01-fullscreen-triangle/fullscreen-triangle.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2023 nicegraf contributors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * 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 Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #include "check.h" 24 | #include "nicegraf-util.h" 25 | #include "nicegraf-wrappers.h" 26 | #include "sample-interface.h" 27 | #include "shader-loader.h" 28 | 29 | #include 30 | 31 | using namespace ngf_misc; 32 | 33 | namespace ngf_samples { 34 | 35 | namespace fullscreen_triangle { 36 | struct state { 37 | ngf::graphics_pipeline pipeline; 38 | }; 39 | } // namespace fullscreen_triangle 40 | 41 | void* sample_initialize( 42 | uint32_t, 43 | uint32_t, 44 | ngf_sample_count main_render_target_sample_count, 45 | ngf_xfer_encoder /*xfer_encoder*/) { 46 | auto state = new fullscreen_triangle::state {}; 47 | 48 | /** 49 | * Load the shader stages. 50 | * Note that these are only necessary when creating pipeline objects. 51 | * After the pipeline objects have been created, the shader stage objects 52 | * can be safely discarded. 53 | */ 54 | const ngf::shader_stage vertex_shader_stage = 55 | load_shader_stage("fullscreen-triangle", "VSMain", NGF_STAGE_VERTEX); 56 | const ngf::shader_stage fragment_shader_stage = 57 | load_shader_stage("fullscreen-triangle", "PSMain", NGF_STAGE_FRAGMENT); 58 | 59 | /** 60 | * Prepare a template with some default values for pipeline initialization. 61 | */ 62 | ngf_util_graphics_pipeline_data pipeline_data; 63 | ngf_util_create_default_graphics_pipeline_data(&pipeline_data); 64 | 65 | /** 66 | * Set shader stages. 67 | */ 68 | pipeline_data.pipeline_info.nshader_stages = 2; 69 | pipeline_data.pipeline_info.shader_stages[0] = vertex_shader_stage.get(); 70 | pipeline_data.pipeline_info.shader_stages[1] = fragment_shader_stage.get(); 71 | 72 | /** 73 | * Set multisampling state. 74 | */ 75 | pipeline_data.multisample_info.sample_count = main_render_target_sample_count; 76 | 77 | /** 78 | * Set the compatible render target description. 79 | */ 80 | pipeline_data.pipeline_info.compatible_rt_attachment_descs = 81 | ngf_default_render_target_attachment_descs(); 82 | 83 | /** 84 | * Initialize the pipeline object. 85 | */ 86 | NGF_MISC_CHECK_NGF_ERROR(state->pipeline.initialize(pipeline_data.pipeline_info)); 87 | 88 | return static_cast(state); 89 | } 90 | 91 | void sample_draw_frame( 92 | ngf_render_encoder main_render_pass, 93 | float /*time_delta*/, 94 | ngf_frame_token /*token*/, 95 | uint32_t w, 96 | uint32_t h, 97 | float /*time*/, 98 | void* userdata) { 99 | auto state = static_cast(userdata); 100 | 101 | ngf_cmd_bind_gfx_pipeline(main_render_pass, state->pipeline.get()); 102 | const ngf_irect2d viewport {0, 0, w, h}; 103 | ngf_cmd_viewport(main_render_pass, &viewport); 104 | ngf_cmd_scissor(main_render_pass, &viewport); 105 | 106 | /** 107 | * Make a drawcall. 108 | */ 109 | ngf_cmd_draw(main_render_pass, false, 0, 3, 1); 110 | } 111 | 112 | void sample_pre_draw_frame(ngf_cmd_buffer, void*) { 113 | } 114 | 115 | void sample_post_draw_frame(ngf_cmd_buffer, void*) { 116 | } 117 | void sample_post_submit(void*) { 118 | } 119 | 120 | void sample_draw_ui(void*) { 121 | } 122 | 123 | void sample_shutdown(void* userdata) { 124 | auto state = static_cast(userdata); 125 | delete state; 126 | } 127 | 128 | } // namespace ngf_samples 129 | -------------------------------------------------------------------------------- /source/ngf-common/stack-alloc.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2025 nicegraf contributors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * 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 Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #include "stack-alloc.h" 24 | 25 | #include "macros.h" 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | ngfi_sa* ngfi_sa_create(size_t capacity) { 32 | ngfi_sa* result = malloc(capacity + sizeof(ngfi_sa)); 33 | if (result) { 34 | result->capacity = capacity; 35 | result->ptr = result->data; 36 | result->active_block = result; 37 | result->next_block = NULL; 38 | result->total_consumed = 0u; 39 | result->total_allocd = capacity + sizeof(ngfi_sa); 40 | } 41 | return result; 42 | } 43 | 44 | void* ngfi_sa_alloc(ngfi_sa* allocator, size_t nbytes) { 45 | assert(allocator); 46 | 47 | nbytes = ngfi_align_size(nbytes); 48 | 49 | ngfi_sa* alloc_block = allocator->active_block; 50 | 51 | void* result = NULL; 52 | const ptrdiff_t consumed_capacity = alloc_block->ptr - alloc_block->data; 53 | const ptrdiff_t available_capacity = (ptrdiff_t)alloc_block->capacity - consumed_capacity; 54 | if (available_capacity >= (ptrdiff_t)nbytes) { 55 | result = alloc_block->ptr; 56 | alloc_block->ptr += nbytes; 57 | } 58 | else { 59 | const size_t new_capacity = NGFI_MAX(alloc_block->capacity, nbytes); 60 | ngfi_sa* new_block = ngfi_sa_create(new_capacity); 61 | if(new_block == NULL) { return NULL; } 62 | allocator->total_allocd += new_capacity + sizeof(ngfi_sa); 63 | 64 | alloc_block->next_block = new_block; 65 | allocator->active_block = new_block; 66 | 67 | result = new_block->ptr; 68 | new_block->ptr += nbytes; 69 | } 70 | if (result) allocator->total_consumed += nbytes; 71 | return result; 72 | } 73 | 74 | void ngfi_sa_reset(ngfi_sa* allocator) { 75 | assert(allocator); 76 | 77 | // free all blocks except for first block 78 | ngfi_sa* curr_block = allocator->next_block; 79 | while (curr_block != NULL) { 80 | ngfi_sa* next = curr_block->next_block; 81 | allocator->total_allocd -= sizeof(ngfi_sa) + curr_block->capacity; 82 | free(curr_block); 83 | curr_block = next; 84 | } 85 | 86 | allocator->ptr = allocator->data; 87 | allocator->active_block = allocator; 88 | allocator->next_block = NULL; 89 | allocator->total_consumed = 0u; 90 | } 91 | 92 | void ngfi_sa_destroy(ngfi_sa* allocator) { 93 | assert(allocator); 94 | ngfi_sa_reset(allocator); 95 | free(allocator); 96 | } 97 | 98 | void ngfi_sa_dump_dbgstats(ngfi_sa* allocator, FILE* out) { 99 | fprintf(out, "Debug stats for stack allocator %p\n", allocator); 100 | fprintf(out, "Block size:\t%zu\n", allocator->active_block->capacity); 101 | fprintf(out, "Total mem:\t%zu\n", (size_t)(allocator->total_allocd)); 102 | fprintf(out, "Used mem:\t%zu\n", (size_t)(allocator->total_consumed)); 103 | 104 | } 105 | ngfi_sa* ngfi_tmp_store(void) { 106 | static NGFI_THREADLOCAL ngfi_sa* temp_storage = NULL; 107 | if (temp_storage == NULL) { 108 | const size_t sa_capacity = 1024 * 100; // 100K 109 | temp_storage = ngfi_sa_create(sa_capacity); 110 | } 111 | return temp_storage; 112 | } 113 | 114 | 115 | ngfi_sa* ngfi_frame_store(void) { 116 | static NGFI_THREADLOCAL ngfi_sa* frame_storage = NULL; 117 | if (frame_storage == NULL) { 118 | const size_t sa_capacity = 1024 * 4; // 4K 119 | frame_storage = ngfi_sa_create(sa_capacity); 120 | } 121 | return frame_storage; 122 | } 123 | 124 | -------------------------------------------------------------------------------- /include/nicegraf-mtl-handles.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2023 nicegraf contributors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * 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 Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | #include "nicegraf.h" 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | /** 31 | * \ingroup ngf 32 | * 33 | * Returns a uintptr_t to the underlying MTLTexture. The caller is responsible for casting the return 34 | * value to a MTLTexture. 35 | * 36 | * @param image A handle to a nicegraf image. 37 | */ 38 | uintptr_t ngf_get_mtl_image_handle(ngf_image image) NGF_NOEXCEPT; 39 | 40 | /** 41 | * \ingroup ngf 42 | * 43 | * Returns a uintptr_t to the underlying MTLBuffer. The caller is responsible for casting the return 44 | * value to a MTLBuffer. 45 | * 46 | * @param buffer A handle to a nicegraf buffer. 47 | */ 48 | uintptr_t ngf_get_mtl_buffer_handle(ngf_buffer buffer) NGF_NOEXCEPT; 49 | 50 | /** 51 | * \ingroup ngf 52 | * 53 | * Returns a uintptr_t to the underlying MTLSamplerState. The caller is responsible for casting the 54 | * return value to a MTLSamplerState. 55 | * 56 | * @param sampler A handle to a nicegraf sampler. 57 | */ 58 | uintptr_t ngf_get_mtl_sampler_handle(ngf_sampler sampler) NGF_NOEXCEPT; 59 | 60 | /** 61 | * \ingroup ngf 62 | * 63 | * Returns a uintptr_t to the underlying MTLCommandBuffer. The caller is responsible for casting 64 | * the return value to a MTLCommandBuffer. 65 | * 66 | * @param cmd_buffer A handle to a nicegraf command buffer. 67 | */ 68 | uintptr_t ngf_get_mtl_cmd_buffer_handle(ngf_cmd_buffer cmd_buffer) NGF_NOEXCEPT; 69 | 70 | /** 71 | * \ingroup ngf 72 | * 73 | * Returns a uintptr_t to the underlying MTLRenderCommandEncoder. The caller is responsible for casting 74 | * the return value to a MTLRenderCommandEncoder. 75 | * 76 | * @param cmd_buffer A handle to a nicegraf command buffer. 77 | */ 78 | uintptr_t ngf_get_mtl_render_encoder_handle(ngf_render_encoder render_encoder) NGF_NOEXCEPT; 79 | 80 | /** 81 | * \ingroup ngf 82 | * 83 | * Returns a uintptr_t to the underlying MTLBlitCommandEncoder. The caller is responsible for casting 84 | * the return value to a MTLBlitCommandEncoder. 85 | * 86 | * @param cmd_buffer A handle to a nicegraf command buffer. 87 | */ 88 | uintptr_t ngf_get_mtl_xfer_encoder_handle(ngf_xfer_encoder xfer_encoder) NGF_NOEXCEPT; 89 | 90 | /** 91 | * \ingroup ngf 92 | * 93 | * Returns a uintptr_t to the underlying MTLComputeCommandEncoder. The caller is responsible for casting 94 | * the return value to a MTLComputeCommandEncoder. 95 | * 96 | * @param cmd_buffer A handle to a nicegraf command buffer. 97 | */ 98 | uintptr_t ngf_get_mtl_compute_encoder_handle(ngf_compute_encoder compute_encoder) NGF_NOEXCEPT; 99 | 100 | /** 101 | * \ingroup ngf 102 | * 103 | * Returns a uint32_t representing the underlying MTLPixelFormat. The caller is responsible for casting the return 104 | * value to a MTLPixelFormat. 105 | * 106 | * @param format A nicegraf image format. 107 | */ 108 | uint32_t ngf_get_mtl_pixel_format_index(ngf_image_format format) NGF_NOEXCEPT; 109 | 110 | /** 111 | * \ingroup ngf 112 | * 113 | * Returns a uintptr_t to the underlying MTLDevice. The caller is responsible for casting the return value 114 | * to a MTLDevice. 115 | */ 116 | uintptr_t ngf_get_mtl_device() NGF_NOEXCEPT; 117 | 118 | /** 119 | * \ingroup ngf 120 | * 121 | * Sets the counter sample buffer attachment descriptor to be used by the next compute pass. 122 | * 123 | * @param cmd_buffer A handle to a nicegraf command buffer. 124 | * @param sample_buf_attachment_descriptor uintptr_t to MTLComputePassSampleBufferAttachmentDescriptor handle. 125 | */ 126 | void ngf_mtl_set_sample_attachment_for_next_compute_pass( ngf_cmd_buffer cmd_buffer, uintptr_t sample_buf_attachment_descriptor ) NGF_NOEXCEPT; 127 | 128 | /** 129 | * \ingroup ngf 130 | * 131 | * Sets the counter sample buffer attachment descriptor to be used by the next render pass. 132 | * 133 | * @param cmd_buffer A handle to a nicegraf command buffer. 134 | * @param sample_buf_attachment_descriptor uintptr_t to MTLRenderPassSampleBufferAttachmentDescriptor handle. 135 | */ 136 | void ngf_mtl_set_sample_attachment_for_next_render_pass( ngf_cmd_buffer cmd_buffer, uintptr_t sample_buf_attachment_descriptor ) NGF_NOEXCEPT; 137 | 138 | #ifdef __cplusplus 139 | } 140 | #endif 141 | 142 | -------------------------------------------------------------------------------- /source/ngf-common/macros.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2025 nicegraf contributors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * 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 Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include "nicegraf.h" 26 | 27 | #include 28 | #include 29 | #if defined(_WIN32) || defined(_WIN64) 30 | #define NGFI_THREADLOCAL __declspec(thread) 31 | #define WIN32_LEAN_AND_MEAN 32 | #include 33 | // emulate pthread mutexes 34 | typedef CRITICAL_SECTION pthread_mutex_t; 35 | #define pthread_mutex_lock(m) (EnterCriticalSection(m), 0) 36 | #define pthread_mutex_unlock(m) (LeaveCriticalSection(m), 0) 37 | #define pthread_mutex_init(m, a) (InitializeCriticalSection(m), 0) 38 | #define pthread_mutex_destroy(m) (DeleteCriticalSection(m), 0) 39 | // dynamic module loading 40 | typedef HMODULE ngfi_module_handle; 41 | #else 42 | #define NGFI_THREADLOCAL __thread 43 | #include 44 | // dynamic module loading (emulate win32 api) 45 | #define LoadLibraryA(name) dlopen(name, RTLD_NOW) 46 | #define GetProcAddress(h, n) dlsym(h, n) 47 | typedef void* ngfi_module_handle; 48 | #endif 49 | 50 | #ifdef __cplusplus 51 | extern "C" { 52 | #endif 53 | 54 | // Custom allocation callbacks. 55 | extern const ngf_allocation_callbacks* NGF_ALLOC_CB; 56 | 57 | // Convenience macros for invoking custom memory allocation callbacks. 58 | #define NGFI_ALLOC(type) ((type*)NGF_ALLOC_CB->allocate(sizeof(type), 1, NGF_ALLOC_CB->userdata)) 59 | #define NGFI_ALLOCN(type, n) ((type*)NGF_ALLOC_CB->allocate(sizeof(type), n, NGF_ALLOC_CB->userdata)) 60 | #define NGFI_FREE(ptr) (NGF_ALLOC_CB->free((void*)(ptr), sizeof(*ptr), 1, NGF_ALLOC_CB->userdata)) 61 | #define NGFI_FREEN(ptr, n) (NGF_ALLOC_CB->free((void*)(ptr), sizeof(*ptr), n, NGF_ALLOC_CB->userdata)) 62 | 63 | // Macro for determining size of arrays. 64 | #if defined(_MSC_VER) 65 | #include 66 | #define NGFI_ARRAYSIZE(arr) _countof(arr) 67 | #else 68 | #define NGFI_ARRAYSIZE(arr) (sizeof(arr) / sizeof(arr[0])) 69 | #endif 70 | 71 | // For when you don't feel like comparing structs field-by-field. 72 | #define NGFI_STRUCT_EQ(s1, s2) \ 73 | (sizeof(s1) == sizeof(s2) && memcmp((void*)&s1, (void*)&s2, sizeof(s1)) == 0) 74 | 75 | // It is $CURRENT_YEAR and C does not have a standard thing for this. 76 | #define NGFI_MAX(a, b) (a > b ? a : b) 77 | #define NGFI_MIN(a, b) (a < b ? a : b) 78 | 79 | // For fixing unreferenced parameter warnings. 80 | #define NGFI_IGNORE_VAR(name) \ 81 | { (void)name; } 82 | 83 | // MSVC warnings that are safe to ignore. 84 | #pragma warning(disable : 4201) 85 | #pragma warning(disable : 4200) 86 | #pragma warning(disable : 4204) 87 | #pragma warning(disable : 4221) 88 | 89 | extern ngf_diagnostic_info ngfi_diag_info; 90 | 91 | // Invoke diagnostic message callback directly. 92 | #define NGFI_DIAG_MSG(level, fmt, ...) \ 93 | if (ngfi_diag_info.callback) { \ 94 | ngfi_diag_info.callback(level, ngfi_diag_info.userdata, fmt, ##__VA_ARGS__); \ 95 | } 96 | #define NGFI_DIAG_INFO(fmt, ...) NGFI_DIAG_MSG(NGF_DIAGNOSTIC_INFO, fmt, ##__VA_ARGS__) 97 | #define NGFI_DIAG_WARNING(fmt, ...) NGFI_DIAG_MSG(NGF_DIAGNOSTIC_WARNING, fmt, ##__VA_ARGS__) 98 | #define NGFI_DIAG_ERROR(fmt, ...) NGFI_DIAG_MSG(NGF_DIAGNOSTIC_ERROR, fmt, ##__VA_ARGS__) 99 | 100 | // Convenience macro to invoke diagnostic callback and raise error on unmet precondition. 101 | #define NGFI_CHECK_CONDITION(cond, err_code, err_fmtstring, ...) \ 102 | if (!(cond)) { \ 103 | NGFI_DIAG_ERROR(err_fmtstring, ##__VA_ARGS__); \ 104 | return err_code; \ 105 | } 106 | 107 | // Convenience macro to immediately die on an unmet precondition. 108 | #define NGFI_CHECK_FATAL(cond, err_fmtstring, ...) \ 109 | if (!(cond)) { \ 110 | NGFI_DIAG_ERROR(err_fmtstring, ##__VA_ARGS__); \ 111 | exit(1); \ 112 | } 113 | 114 | typedef long double ngfi_max_align_t; 115 | 116 | #define NGFI_MAX_ALIGNMENT (sizeof(ngfi_max_align_t)) 117 | 118 | static inline size_t ngfi_align_size(size_t s) { 119 | static const size_t align_mask = NGFI_MAX_ALIGNMENT - 1u; 120 | const size_t q = s & (~align_mask); 121 | const size_t r = s & align_mask; 122 | 123 | return q + ((r == 0) ? 0 : NGFI_MAX_ALIGNMENT); 124 | } 125 | 126 | typedef struct ngfi_range { 127 | size_t first_idx; 128 | size_t last_idx; 129 | } ngfi_range; 130 | 131 | void ngfi_set_allocation_callbacks(const ngf_allocation_callbacks* callbacks); 132 | 133 | #ifdef __cplusplus 134 | } 135 | #endif 136 | -------------------------------------------------------------------------------- /tests/nicetest.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2023 nicegraf contributors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * 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 Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #if !defined(NT_IMPL) 24 | #pragma once 25 | #endif 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #if defined(_WIN32) || defined(_WIN64) 34 | #define NT_THREADLOCAL __declspec(thread) 35 | #else 36 | #define NT_THREADLOCAL __thread 37 | #endif 38 | 39 | #if defined(NT_BREAK_ON_ASSERT_FAIL) 40 | #if !defined(_WIN32) && !defined(_WIN64) 41 | #include 42 | #define NT_ASSERT(condition) \ 43 | do { \ 44 | if (!(condition)) { raise(SIGTRAP); } \ 45 | }while (0) 46 | #else 47 | #define NT_ASSERT(condition) \ 48 | do { \ 49 | if (!(condition)) { __debugbreak(); } \ 50 | } while (0) 51 | #endif 52 | #else 53 | #define NT_ASSERT(condition) \ 54 | do { \ 55 | if (!(condition)) { \ 56 | fprintf( \ 57 | stderr, \ 58 | "assertion failed\n\tcode:\t\"%s\"\n\tfile:\t\"%s\"\n\tline:\t%d\n", \ 59 | #condition, \ 60 | __FILE__, \ 61 | __LINE__); \ 62 | if (nt_internal_mainthread_flag) { \ 63 | longjmp(nt_internal_jmpbuf, 1); \ 64 | } else { \ 65 | fprintf(stderr, "Assertion failure on non-main thread. Aborting.\n"); \ 66 | abort(); \ 67 | } \ 68 | } \ 69 | } while (0) 70 | #endif 71 | 72 | #define NT_TESTCASE(name) \ 73 | if ((setjmp(nt_internal_jmpbuf) == 0 && \ 74 | nt_internal_handle_test_start(#name, test_suite_context)) || \ 75 | nt_internal_handle_test_failure(#name, test_suite_context)) \ 76 | 77 | #define NT_TESTSUITE \ 78 | void nt_internal_test_suite_main(nt_internal_test_suite_context* test_suite_context) 79 | 80 | typedef struct nt_internal_test_suite_context { 81 | uint32_t failed_test_cases; 82 | uint32_t total_test_cases; 83 | } nt_internal_test_suite_context; 84 | 85 | #if !defined(NT_IMPL) 86 | static inline int nt_internal_handle_test_failure( 87 | const char* test_case_name, 88 | nt_internal_test_suite_context* test_suite_context) { 89 | fprintf(stderr, "test case \"%s\" failed.\n", test_case_name); 90 | test_suite_context->failed_test_cases++; 91 | return 0; 92 | } 93 | 94 | static inline int nt_internal_handle_test_start( 95 | const char* test_case_name, 96 | nt_internal_test_suite_context* test_suite_context) { 97 | fprintf(stderr, "\nrunning test case: \"%s\"\n", test_case_name); 98 | test_suite_context->total_test_cases++; 99 | return 1; 100 | } 101 | #endif 102 | 103 | extern NT_THREADLOCAL bool nt_internal_mainthread_flag; 104 | extern jmp_buf nt_internal_jmpbuf; 105 | void nt_internal_test_suite_main(nt_internal_test_suite_context* test_suite_context); 106 | 107 | #if defined(NT_SELF_TEST) 108 | 109 | void failfoo() { 110 | NT_ASSERT(false); 111 | } 112 | 113 | NT_TESTSUITE { 114 | NT_TESTCASE(succesful - tc1) { 115 | NT_ASSERT(true); 116 | } 117 | 118 | NT_TESTCASE(failed - tc1) { 119 | NT_ASSERT(false); 120 | } 121 | 122 | NT_TESTCASE(failed - tc2) { 123 | failfoo(); 124 | } 125 | } 126 | 127 | #endif 128 | 129 | #if defined(NT_IMPL) 130 | 131 | NT_THREADLOCAL bool nt_internal_mainthread_flag; 132 | jmp_buf nt_internal_jmpbuf; 133 | 134 | int main(int argc, char* argv[]) { 135 | (void)argv; 136 | (void)argc; 137 | nt_internal_test_suite_context ctx; 138 | ctx.failed_test_cases = 0u; 139 | ctx.total_test_cases = 0u; 140 | nt_internal_mainthread_flag = true; 141 | fprintf(stderr, "running test suite...\n"); 142 | nt_internal_test_suite_main(&ctx); 143 | fprintf( 144 | stderr, 145 | "\nfinished test suite, with %d failed test cases (out of %d total test cases)\n", 146 | ctx.failed_test_cases, 147 | ctx.total_test_cases); 148 | return ctx.failed_test_cases == 0 ? 0 : 1; 149 | } 150 | #endif 151 | -------------------------------------------------------------------------------- /tests/image-comparison/framework/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void ngf_test_draw(ngf::render_target& rt, const ngf_attachment_descriptions& rt_attachments, ngf_frame_token frame_token); 6 | bool ngf_validate_result( 7 | ngf::image* output_image, 8 | const char* ref_image, 9 | ngf_frame_token frame_token); 10 | 11 | int main(int, char*[]) { 12 | uint32_t ndevices = 0u; 13 | const ngf_device* devices = nullptr; 14 | 15 | ngf_get_device_list(&devices, &ndevices); 16 | 17 | size_t device_idx = ndevices <= 0 ? (~0u) : 0u; 18 | 19 | const ngf_device_handle device_handle = devices[device_idx].handle; 20 | 21 | const ngf_init_info init_info { 22 | .diag_info = nullptr, 23 | .allocation_callbacks = nullptr, 24 | .device = device_handle, 25 | .renderdoc_info = nullptr}; 26 | ngf_initialize(&init_info); 27 | 28 | const ngf_context_info ctx_info = {.swapchain_info = nullptr, .shared_context = nullptr}; 29 | ngf::context context; 30 | 31 | context.initialize(ctx_info); 32 | ngf_set_context(context); 33 | 34 | ngf_frame_token frame_token; 35 | if (ngf_begin_frame(&frame_token) == NGF_ERROR_OK) return {}; 36 | 37 | const ngf_extent3d output_dimensions {512u, 512u, 1u}; 38 | ngf::image output_color; 39 | const ngf_image_info output_color_info { 40 | NGF_IMAGE_TYPE_IMAGE_2D, 41 | output_dimensions, 42 | 1u, 43 | 1u, 44 | NGF_IMAGE_FORMAT_BGRA8_SRGB, 45 | NGF_SAMPLE_COUNT_1, 46 | NGF_IMAGE_USAGE_SAMPLE_FROM | NGF_IMAGE_USAGE_ATTACHMENT}; 47 | ngf::image output_depth; 48 | const ngf_image_info output_depth_info { 49 | NGF_IMAGE_TYPE_IMAGE_2D, 50 | output_dimensions, 51 | 1u, 52 | 1u, 53 | NGF_IMAGE_FORMAT_DEPTH24_STENCIL8, 54 | NGF_SAMPLE_COUNT_1, 55 | NGF_IMAGE_USAGE_ATTACHMENT}; 56 | output_color.initialize(output_color_info); 57 | output_depth.initialize(output_depth_info); 58 | 59 | const ngf_attachment_description attachment_descs[] = { 60 | {.type = NGF_ATTACHMENT_COLOR, 61 | .format = NGF_IMAGE_FORMAT_BGRA8_SRGB, 62 | .sample_count = NGF_SAMPLE_COUNT_1, 63 | .is_sampled = true}, 64 | {.type = NGF_ATTACHMENT_DEPTH, 65 | .format = NGF_IMAGE_FORMAT_DEPTH24_STENCIL8, 66 | .sample_count = NGF_SAMPLE_COUNT_1, 67 | .is_sampled = false}}; 68 | const ngf_attachment_descriptions attachments_list = { 69 | .descs = attachment_descs, 70 | .ndescs = sizeof(attachment_descs) / sizeof(attachment_descs[0]), 71 | }; 72 | const ngf_image_ref img_refs[] = { 73 | {.image = output_color.get(), 74 | .mip_level = 0u, 75 | .layer = 0u, 76 | .cubemap_face = NGF_CUBEMAP_FACE_COUNT}, 77 | {.image = output_depth.get(), 78 | .mip_level = 0u, 79 | .layer = 0u, 80 | .cubemap_face = NGF_CUBEMAP_FACE_COUNT}, 81 | }; 82 | ngf_render_target_info rt_info {&attachments_list, img_refs}; 83 | ngf::render_target main_rt; 84 | main_rt.initialize(rt_info); 85 | 86 | 87 | ngf_test_draw(main_rt, attachments_list, frame_token); 88 | 89 | ngf_end_frame(frame_token); 90 | 91 | if (!ngf_validate_result(&output_color, "references/triangle_reference.data", frame_token)) { 92 | printf("[NICEGRAF TEST] Test failed. Please view output image in the output directory.\n"); 93 | } 94 | 95 | ngf_shutdown(); 96 | 97 | return 0; 98 | } 99 | 100 | bool ngf_validate_result( 101 | ngf::image* output_image, 102 | const char* ref_image, 103 | ngf_frame_token frame_token) { 104 | ngf_cmd_buffer xfer_cmd_buf = nullptr; 105 | ngf_cmd_buffer_info xfer_cmd_info = {}; 106 | 107 | ngf_extent3d src_extent = {512u, 512u, 1u}; 108 | ngf_offset3d src_offset = {0u, 0u, 0u}; 109 | const ngf_image_ref src_image = { 110 | .image = output_image->get(), 111 | .mip_level = 0u, 112 | .layer = 0u, 113 | .cubemap_face = NGF_CUBEMAP_FACE_COUNT}; 114 | ngf_buffer dst_buffer; 115 | ngf_buffer_info dst_buffer_info = { 116 | .size = 512u * 512u * 4u, 117 | .storage_type = NGF_BUFFER_STORAGE_HOST_READABLE, 118 | .buffer_usage = NGF_BUFFER_USAGE_XFER_DST}; 119 | ngf_create_buffer(&dst_buffer_info, &dst_buffer); 120 | ngf_create_cmd_buffer(&xfer_cmd_info, &xfer_cmd_buf); 121 | ngf_start_cmd_buffer(xfer_cmd_buf, frame_token); 122 | ngf_xfer_encoder xfer_encoder {}; 123 | ngf_xfer_pass_info xfer_pass_info {}; 124 | ngf_cmd_begin_xfer_pass(xfer_cmd_buf, &xfer_pass_info, &xfer_encoder); 125 | ngf_cmd_copy_image_to_buffer(xfer_encoder, src_image, src_offset, src_extent, 1u, dst_buffer, 0u); 126 | ngf_cmd_end_xfer_pass(xfer_encoder); 127 | ngf_submit_cmd_buffers(1, &xfer_cmd_buf); 128 | ngf_destroy_cmd_buffer(xfer_cmd_buf); 129 | ngf_finish(); 130 | 131 | void* host_dst = ngf_buffer_map_range(dst_buffer, 0u, 512u * 512u * 4u); 132 | 133 | // compare host_dst to references/ref_image 134 | size_t buff_size = 512u * 512u * 4u; 135 | FILE* file = fopen(ref_image, "rb"); 136 | 137 | if (file == nullptr) return false; 138 | fseek(file, 0, SEEK_END); 139 | long file_size = ftell(file); 140 | if (file_size != buff_size) { 141 | fclose(file); 142 | return false; 143 | } 144 | 145 | fseek(file, 0, SEEK_SET); 146 | char* buffer = (char*)malloc(buff_size); 147 | fread(buffer, 1, buff_size, file); 148 | fclose(file); 149 | 150 | bool equal = true; 151 | const char* mem_data = (const char*)host_dst; 152 | for (size_t i = 0; i < buff_size; i++) { 153 | if (mem_data[i] != buffer[i]) { 154 | free(buffer); 155 | equal = false; 156 | } 157 | } 158 | if (!equal) { 159 | FILE* f = fopen("./output/triangle_test.data", "wb"); 160 | fwrite(host_dst, 1u, 512 * 512 * 4, f); 161 | fclose(f); 162 | } 163 | return equal; 164 | } 165 | -------------------------------------------------------------------------------- /source/ngf-common/native-binding-map.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2021 nicegraf contributors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * 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 Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | #ifndef _CRT_SECURE_NO_WARNINGS 23 | #define _CRT_SECURE_NO_WARNINGS 24 | #endif 25 | #include "ngf-common/native-binding-map.h" 26 | 27 | #include "ngf-common/dynamic-array.h" 28 | #include "ngf-common/macros.h" 29 | 30 | #include 31 | #include 32 | #include 33 | 34 | const char* ngfi_find_serialized_native_binding_map(const char* input) { 35 | const char magic[] = "NGF_NATIVE_BINDING_MAP"; 36 | const char comment_start[] = "/*"; 37 | const char comment_end[] = "*/"; 38 | const size_t magic_len = sizeof(magic) - 1; 39 | bool in_comment = false; 40 | for (const char* i = input; *i; ++i) { 41 | if (!in_comment) { 42 | if (strncmp(i, comment_start, 2) == 0) { in_comment = true; } 43 | } else { 44 | if (strncmp(i, comment_end, 2) == 0) { 45 | in_comment = false; 46 | } else if (strncmp(i, magic, magic_len) == 0) { 47 | return i + magic_len; 48 | } 49 | } 50 | } 51 | return NULL; 52 | } 53 | 54 | typedef struct ngfi_set_map { 55 | uint32_t* bindings; 56 | uint32_t nbindings; 57 | } ngfi_set_map; 58 | 59 | struct ngfi_native_binding_map { 60 | uint32_t nsets; 61 | ngfi_set_map* sets; 62 | }; 63 | 64 | struct native_binding_entry { 65 | int set; 66 | int binding; 67 | int native_binding; 68 | }; 69 | 70 | static int binding_entry_comparator(const void* a, const void* b) { 71 | const struct native_binding_entry* e_a = a; 72 | const struct native_binding_entry* e_b = b; 73 | if (e_a->set < e_b->set) 74 | return -1; 75 | else { 76 | if (e_a->set == e_b->set) { 77 | if (e_a->binding < e_b->binding) 78 | return -1; 79 | else if (e_a->binding == e_b->binding) 80 | return 0; 81 | return 1; 82 | } 83 | } 84 | return 1; 85 | } 86 | 87 | ngfi_native_binding_map* ngfi_parse_serialized_native_binding_map(const char* serialized_map) { 88 | int n = 0; 89 | int consumed_bytes = 0; 90 | struct native_binding_entry current_entry; 91 | NGFI_DARRAY_OF(struct native_binding_entry) entries; 92 | NGFI_DARRAY_RESET(entries, 16); 93 | 94 | while (sscanf( 95 | serialized_map, 96 | " ( %d %d ) : %d%n", 97 | ¤t_entry.set, 98 | ¤t_entry.binding, 99 | ¤t_entry.native_binding, 100 | &n) == 3) { 101 | serialized_map += n; 102 | consumed_bytes += n; 103 | if (current_entry.set == -1 && current_entry.binding == -1 && 104 | current_entry.native_binding == -1) { 105 | break; 106 | } 107 | NGFI_DARRAY_APPEND(entries, current_entry); 108 | } 109 | 110 | /** 111 | * If we didn't consume any input at all, it was ill-formed. 112 | */ 113 | if (consumed_bytes <= 0) { return NULL; } 114 | 115 | if (NGFI_DARRAY_SIZE(entries) > 0) { 116 | qsort( 117 | entries.data, 118 | NGFI_DARRAY_SIZE(entries) - 1, 119 | sizeof(struct native_binding_entry), 120 | binding_entry_comparator); 121 | } 122 | 123 | ngfi_native_binding_map* map = NGFI_ALLOC(ngfi_native_binding_map); 124 | map->nsets = 0; 125 | map->sets = NULL; 126 | for (int i = (int)NGFI_DARRAY_SIZE(entries) - 1; i >= 0; --i) { 127 | const struct native_binding_entry* entry = &(NGFI_DARRAY_AT(entries, i)); 128 | if (map->sets == NULL) { 129 | /* since we're starting at the far end of a sorted array, op->target_set 130 | would be the largest set ID at this point, indicating the max required 131 | number of sets. */ 132 | map->nsets = (uint32_t)entry->set + 1u; 133 | map->sets = NGFI_ALLOCN(ngfi_set_map, map->nsets); 134 | memset(map->sets, 0, sizeof(ngfi_set_map) * map->nsets); 135 | } 136 | const uint32_t current_set = (uint32_t)entry->set; 137 | if (map->sets[current_set].nbindings == 0) { 138 | map->sets[current_set].nbindings = (uint32_t)entry->binding + 1; 139 | map->sets[current_set].bindings = NGFI_ALLOCN(uint32_t, map->sets[current_set].nbindings); 140 | memset( 141 | map->sets[current_set].bindings, 142 | ~0, 143 | sizeof(uint32_t) * (map->sets[current_set].nbindings)); 144 | } 145 | } 146 | 147 | /* Assign binding ids. */ 148 | NGFI_DARRAY_FOREACH(entries, i) { 149 | const struct native_binding_entry* entry = &NGFI_DARRAY_AT(entries, i); 150 | map->sets[entry->set].bindings[entry->binding] = (uint32_t)entry->native_binding; 151 | } 152 | 153 | return map; 154 | } 155 | 156 | uint32_t 157 | ngfi_native_binding_map_lookup(const ngfi_native_binding_map* map, uint32_t set, uint32_t binding) { 158 | if (set >= map->nsets) return ~0u; 159 | if (binding >= map->sets[set].nbindings) return ~0u; 160 | return map->sets[set].bindings[binding]; 161 | } 162 | 163 | void ngfi_destroy_native_binding_map(ngfi_native_binding_map* map) { 164 | for (uint32_t i = 0; i < map->nsets; ++i) { 165 | NGFI_FREEN(map->sets[i].bindings, map->sets[i].nbindings); 166 | } 167 | NGFI_FREEN(map->sets, map->nsets); 168 | NGFI_FREE(map); 169 | } 170 | 171 | -------------------------------------------------------------------------------- /misc/common/mesh-loader.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2023 nicegraf contributors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * 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 Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | #define _CRT_SECURE_NO_WARNINGS 23 | #include "mesh-loader.h" 24 | 25 | #include "check.h" 26 | 27 | #include 28 | #include 29 | 30 | namespace ngf_misc { 31 | 32 | static void read_into_mapped_buffer(FILE* f, ngf_buffer buf, size_t data_size) { 33 | void* mapped_buffer_mem = ngf_buffer_map_range(buf, 0u, data_size); 34 | const size_t read_elements = 35 | fread(mapped_buffer_mem, sizeof(char), data_size, f); 36 | NGF_MISC_ASSERT(read_elements == data_size); 37 | ngf_buffer_flush_range(buf, 0, data_size); 38 | ngf_buffer_unmap(buf); 39 | } 40 | 41 | mesh load_mesh_from_file(const char* mesh_file_name, ngf_xfer_encoder xfenc) { 42 | mesh result; 43 | FILE* mesh_file = fopen(mesh_file_name, "rb"); 44 | NGF_MISC_ASSERT(mesh_file != NULL); 45 | 46 | /* Indicates to skip staging buffers and copy directly to device-local memory if possible. */ 47 | const bool skip_staging = ngf_get_device_capabilities()->device_local_memory_is_host_visible; 48 | 49 | /** 50 | * Read the "file header" - 4-byte field with the lowest bit indicating 51 | * the presence of normals, and the second-lowest bit indicating the 52 | * presence of UV coordinates (position attribute is always assumed). 53 | */ 54 | uint32_t header = 0u; 55 | size_t read_elements = 0u; 56 | read_elements = fread(&header, sizeof(header), 1u, mesh_file); 57 | NGF_MISC_ASSERT(read_elements == 1u); 58 | result.have_normals = header & 1; 59 | result.have_uvs = header & 2; 60 | 61 | /** 62 | * Read the total size of the vertex data. Depending on device capabilities, 63 | * read it all directly into the GPU buffer, or read into a staging buffer. 64 | */ 65 | uint32_t vertex_data_size = 0u; 66 | read_elements = fread(&vertex_data_size, sizeof(vertex_data_size), 1u, mesh_file); 67 | NGF_MISC_ASSERT(read_elements == 1u); 68 | const ngf_buffer_info vertex_data_staging_buffer_info = { 69 | .size = vertex_data_size, 70 | .storage_type = NGF_BUFFER_STORAGE_HOST_WRITEABLE, 71 | .buffer_usage = NGF_BUFFER_USAGE_XFER_SRC, 72 | }; 73 | ngf::buffer vertex_data_staging_buffer; 74 | if (!skip_staging) { 75 | NGF_MISC_CHECK_NGF_ERROR( 76 | vertex_data_staging_buffer.initialize(vertex_data_staging_buffer_info)); 77 | } 78 | const ngf_buffer_info vertex_data_buffer_info = { 79 | .size = vertex_data_staging_buffer_info.size, 80 | .storage_type = skip_staging ? NGF_BUFFER_STORAGE_DEVICE_LOCAL_HOST_WRITEABLE : NGF_BUFFER_STORAGE_DEVICE_LOCAL, 81 | .buffer_usage = NGF_BUFFER_USAGE_VERTEX_BUFFER | NGF_BUFFER_USAGE_XFER_DST, 82 | }; 83 | NGF_MISC_CHECK_NGF_ERROR(result.vertex_data.initialize(vertex_data_buffer_info)); 84 | 85 | read_into_mapped_buffer( 86 | mesh_file, 87 | skip_staging ? result.vertex_data.get() : vertex_data_staging_buffer.get(), 88 | vertex_data_size); 89 | 90 | /** 91 | * Read the number of indices in the mesh. If number of indices is 0, the 92 | * mesh is considered to not have an index buffer, and a non-indexed draw call 93 | * should be used to render it. 94 | */ 95 | read_elements = fread(&result.num_indices, sizeof(uint32_t), 1, mesh_file); 96 | NGF_MISC_ASSERT(read_elements == 1u); 97 | 98 | /** 99 | * Allocate buffer(s) for the index data, and read the index data. 100 | * As before, we try to read directly into the GPU buffer if the device allows it. 101 | */ 102 | ngf::buffer index_data_staging_buffer; 103 | const ngf_buffer_info index_data_staging_buffer_info = { 104 | .size = sizeof(uint32_t) * result.num_indices, 105 | .storage_type = NGF_BUFFER_STORAGE_HOST_WRITEABLE, 106 | .buffer_usage = NGF_BUFFER_USAGE_XFER_SRC, 107 | }; 108 | const ngf_buffer_info index_data_buffer_info = { 109 | .size = sizeof(uint32_t) * result.num_indices, 110 | .storage_type = skip_staging ? NGF_BUFFER_STORAGE_DEVICE_LOCAL_HOST_WRITEABLE 111 | : NGF_BUFFER_STORAGE_DEVICE_LOCAL, 112 | .buffer_usage = NGF_BUFFER_USAGE_INDEX_BUFFER | NGF_BUFFER_USAGE_XFER_DST, 113 | }; 114 | if (result.num_indices > 0) { 115 | NGF_MISC_CHECK_NGF_ERROR(result.index_data.initialize(index_data_buffer_info)); 116 | if (!skip_staging) { 117 | NGF_MISC_CHECK_NGF_ERROR( 118 | index_data_staging_buffer.initialize(index_data_staging_buffer_info)); 119 | } 120 | read_into_mapped_buffer( 121 | mesh_file, 122 | skip_staging ? result.index_data.get() : index_data_staging_buffer.get(), 123 | index_data_staging_buffer_info.size); 124 | } 125 | 126 | /** 127 | * Record commands to upload staging data if we have to. 128 | */ 129 | if (!skip_staging) { 130 | ngf_cmd_copy_buffer( 131 | xfenc, 132 | vertex_data_staging_buffer.get(), 133 | result.vertex_data.get(), 134 | vertex_data_buffer_info.size, 135 | 0u, 136 | 0u); 137 | if (result.num_indices > 0) { 138 | ngf_cmd_copy_buffer( 139 | xfenc, 140 | index_data_staging_buffer.get(), 141 | result.index_data.get(), 142 | index_data_staging_buffer_info.size, 143 | 0u, 144 | 0u); 145 | } 146 | } 147 | 148 | return result; 149 | } 150 | 151 | } // namespace ngf_samples 152 | -------------------------------------------------------------------------------- /deps/vulkan-headers/vulkan/vulkan_metal.h: -------------------------------------------------------------------------------- 1 | #ifndef VULKAN_METAL_H_ 2 | #define VULKAN_METAL_H_ 1 3 | 4 | /* 5 | ** Copyright 2015-2022 The Khronos Group Inc. 6 | ** 7 | ** SPDX-License-Identifier: Apache-2.0 8 | */ 9 | 10 | /* 11 | ** This header is generated from the Khronos Vulkan XML API Registry. 12 | ** 13 | */ 14 | 15 | 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif 19 | 20 | 21 | 22 | #define VK_EXT_metal_surface 1 23 | #ifdef __OBJC__ 24 | @class CAMetalLayer; 25 | #else 26 | typedef void CAMetalLayer; 27 | #endif 28 | 29 | #define VK_EXT_METAL_SURFACE_SPEC_VERSION 1 30 | #define VK_EXT_METAL_SURFACE_EXTENSION_NAME "VK_EXT_metal_surface" 31 | typedef VkFlags VkMetalSurfaceCreateFlagsEXT; 32 | typedef struct VkMetalSurfaceCreateInfoEXT { 33 | VkStructureType sType; 34 | const void* pNext; 35 | VkMetalSurfaceCreateFlagsEXT flags; 36 | const CAMetalLayer* pLayer; 37 | } VkMetalSurfaceCreateInfoEXT; 38 | 39 | typedef VkResult (VKAPI_PTR *PFN_vkCreateMetalSurfaceEXT)(VkInstance instance, const VkMetalSurfaceCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); 40 | 41 | #ifndef VK_NO_PROTOTYPES 42 | VKAPI_ATTR VkResult VKAPI_CALL vkCreateMetalSurfaceEXT( 43 | VkInstance instance, 44 | const VkMetalSurfaceCreateInfoEXT* pCreateInfo, 45 | const VkAllocationCallbacks* pAllocator, 46 | VkSurfaceKHR* pSurface); 47 | #endif 48 | 49 | 50 | #define VK_EXT_metal_objects 1 51 | #ifdef __OBJC__ 52 | @protocol MTLDevice; 53 | typedef id MTLDevice_id; 54 | #else 55 | typedef void* MTLDevice_id; 56 | #endif 57 | 58 | #ifdef __OBJC__ 59 | @protocol MTLCommandQueue; 60 | typedef id MTLCommandQueue_id; 61 | #else 62 | typedef void* MTLCommandQueue_id; 63 | #endif 64 | 65 | #ifdef __OBJC__ 66 | @protocol MTLBuffer; 67 | typedef id MTLBuffer_id; 68 | #else 69 | typedef void* MTLBuffer_id; 70 | #endif 71 | 72 | #ifdef __OBJC__ 73 | @protocol MTLTexture; 74 | typedef id MTLTexture_id; 75 | #else 76 | typedef void* MTLTexture_id; 77 | #endif 78 | 79 | typedef struct __IOSurface* IOSurfaceRef; 80 | #ifdef __OBJC__ 81 | @protocol MTLSharedEvent; 82 | typedef id MTLSharedEvent_id; 83 | #else 84 | typedef void* MTLSharedEvent_id; 85 | #endif 86 | 87 | #define VK_EXT_METAL_OBJECTS_SPEC_VERSION 1 88 | #define VK_EXT_METAL_OBJECTS_EXTENSION_NAME "VK_EXT_metal_objects" 89 | 90 | typedef enum VkExportMetalObjectTypeFlagBitsEXT { 91 | VK_EXPORT_METAL_OBJECT_TYPE_METAL_DEVICE_BIT_EXT = 0x00000001, 92 | VK_EXPORT_METAL_OBJECT_TYPE_METAL_COMMAND_QUEUE_BIT_EXT = 0x00000002, 93 | VK_EXPORT_METAL_OBJECT_TYPE_METAL_BUFFER_BIT_EXT = 0x00000004, 94 | VK_EXPORT_METAL_OBJECT_TYPE_METAL_TEXTURE_BIT_EXT = 0x00000008, 95 | VK_EXPORT_METAL_OBJECT_TYPE_METAL_IOSURFACE_BIT_EXT = 0x00000010, 96 | VK_EXPORT_METAL_OBJECT_TYPE_METAL_SHARED_EVENT_BIT_EXT = 0x00000020, 97 | VK_EXPORT_METAL_OBJECT_TYPE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF 98 | } VkExportMetalObjectTypeFlagBitsEXT; 99 | typedef VkFlags VkExportMetalObjectTypeFlagsEXT; 100 | typedef struct VkExportMetalObjectCreateInfoEXT { 101 | VkStructureType sType; 102 | const void* pNext; 103 | VkExportMetalObjectTypeFlagBitsEXT exportObjectType; 104 | } VkExportMetalObjectCreateInfoEXT; 105 | 106 | typedef struct VkExportMetalObjectsInfoEXT { 107 | VkStructureType sType; 108 | const void* pNext; 109 | } VkExportMetalObjectsInfoEXT; 110 | 111 | typedef struct VkExportMetalDeviceInfoEXT { 112 | VkStructureType sType; 113 | const void* pNext; 114 | MTLDevice_id mtlDevice; 115 | } VkExportMetalDeviceInfoEXT; 116 | 117 | typedef struct VkExportMetalCommandQueueInfoEXT { 118 | VkStructureType sType; 119 | const void* pNext; 120 | VkQueue queue; 121 | MTLCommandQueue_id mtlCommandQueue; 122 | } VkExportMetalCommandQueueInfoEXT; 123 | 124 | typedef struct VkExportMetalBufferInfoEXT { 125 | VkStructureType sType; 126 | const void* pNext; 127 | VkDeviceMemory memory; 128 | MTLBuffer_id mtlBuffer; 129 | } VkExportMetalBufferInfoEXT; 130 | 131 | typedef struct VkImportMetalBufferInfoEXT { 132 | VkStructureType sType; 133 | const void* pNext; 134 | MTLBuffer_id mtlBuffer; 135 | } VkImportMetalBufferInfoEXT; 136 | 137 | typedef struct VkExportMetalTextureInfoEXT { 138 | VkStructureType sType; 139 | const void* pNext; 140 | VkImage image; 141 | VkImageView imageView; 142 | VkBufferView bufferView; 143 | VkImageAspectFlagBits plane; 144 | MTLTexture_id mtlTexture; 145 | } VkExportMetalTextureInfoEXT; 146 | 147 | typedef struct VkImportMetalTextureInfoEXT { 148 | VkStructureType sType; 149 | const void* pNext; 150 | VkImageAspectFlagBits plane; 151 | MTLTexture_id mtlTexture; 152 | } VkImportMetalTextureInfoEXT; 153 | 154 | typedef struct VkExportMetalIOSurfaceInfoEXT { 155 | VkStructureType sType; 156 | const void* pNext; 157 | VkImage image; 158 | IOSurfaceRef ioSurface; 159 | } VkExportMetalIOSurfaceInfoEXT; 160 | 161 | typedef struct VkImportMetalIOSurfaceInfoEXT { 162 | VkStructureType sType; 163 | const void* pNext; 164 | IOSurfaceRef ioSurface; 165 | } VkImportMetalIOSurfaceInfoEXT; 166 | 167 | typedef struct VkExportMetalSharedEventInfoEXT { 168 | VkStructureType sType; 169 | const void* pNext; 170 | VkSemaphore semaphore; 171 | VkEvent event; 172 | MTLSharedEvent_id mtlSharedEvent; 173 | } VkExportMetalSharedEventInfoEXT; 174 | 175 | typedef struct VkImportMetalSharedEventInfoEXT { 176 | VkStructureType sType; 177 | const void* pNext; 178 | MTLSharedEvent_id mtlSharedEvent; 179 | } VkImportMetalSharedEventInfoEXT; 180 | 181 | typedef void (VKAPI_PTR *PFN_vkExportMetalObjectsEXT)(VkDevice device, VkExportMetalObjectsInfoEXT* pMetalObjectsInfo); 182 | 183 | #ifndef VK_NO_PROTOTYPES 184 | VKAPI_ATTR void VKAPI_CALL vkExportMetalObjectsEXT( 185 | VkDevice device, 186 | VkExportMetalObjectsInfoEXT* pMetalObjectsInfo); 187 | #endif 188 | 189 | #ifdef __cplusplus 190 | } 191 | #endif 192 | 193 | #endif 194 | -------------------------------------------------------------------------------- /misc/common/targa-loader.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2023 nicegraf contributors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * 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 Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #include "targa-loader.h" 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | namespace ngf_misc { 30 | namespace tga { 31 | /* image type constants */ 32 | enum class img_type : uint8_t { 33 | none = 0, 34 | color_mapped = 1, 35 | true_color = 2, 36 | black_and_white = 3, 37 | color_mapped_rle = 9, 38 | true_color_rle = 10, 39 | black_and_white_rle = 11 40 | }; 41 | 42 | /* targa structures */ 43 | #pragma pack(push, 1) 44 | struct cmap { 45 | uint16_t first_entry_idx; 46 | uint16_t num_entries; 47 | uint8_t bits_per_entry; 48 | }; 49 | 50 | struct image { 51 | uint16_t x_origin; 52 | uint16_t y_origin; 53 | uint16_t width; 54 | uint16_t height; 55 | uint8_t bitsperpel; 56 | uint8_t descriptor; 57 | }; 58 | 59 | struct header { 60 | uint8_t id_length; 61 | uint8_t has_cmap; 62 | img_type type; 63 | cmap cmap_entry; 64 | image img; 65 | }; 66 | 67 | struct footer { 68 | uint32_t ext_offset; 69 | uint32_t dev_offset; 70 | char sig[18]; 71 | }; 72 | #pragma pack(pop) 73 | 74 | } // namespace tga 75 | 76 | namespace { 77 | 78 | float srgb_to_linear(uint8_t srgb_value) { 79 | const float srgb_valuef = (float)srgb_value / 255.0f; 80 | return srgb_valuef <= 0.04045f ? (srgb_valuef / 12.92f) 81 | : powf(((srgb_valuef + 0.055f) / 1.055f), 2.4f); 82 | } 83 | 84 | uint8_t linear_to_srgb(float linear_value) { 85 | const float srgb_valuef = linear_value <= 0.0031308f 86 | ? (12.92f * linear_value) 87 | : (1.055f * powf(linear_value, 1.0f / 2.4f) - 0.055f); 88 | return (uint8_t)(std::min(1.0f, srgb_valuef) * 255.0f); 89 | } 90 | 91 | } // namespace 92 | 93 | void load_targa( 94 | const void* in_buf, 95 | size_t in_buf_size, 96 | void* out_buf, 97 | size_t out_buf_size, 98 | uint32_t* width_px, 99 | uint32_t* height_px) { 100 | auto in_bytes = (const char*)in_buf; 101 | auto out_bytes = (char*)out_buf; 102 | 103 | /* obtain header and footer data. */ 104 | auto hdr = (const tga::header*)in_buf; 105 | auto ftr = (const tga::footer*)&in_bytes[in_buf_size - sizeof(tga::footer)]; 106 | 107 | /* write width and height outputs. */ 108 | *width_px = hdr->img.width; 109 | *height_px = hdr->img.height; 110 | 111 | /* if the output buffer pointer is null, we're done. */ 112 | if (out_buf == nullptr) { return; } 113 | 114 | /* compute expected output size and check if it fits into the provided 115 | output buffer. */ 116 | const size_t expected_output_size = 4u * hdr->img.width * hdr->img.height; 117 | if (expected_output_size > out_buf_size) { throw std::runtime_error("buffer overflow"); } 118 | 119 | /* verify that footer is valid. */ 120 | const char* expected_sig = "TRUEVISION-XFILE."; 121 | for (size_t si = 0; si < sizeof(ftr->sig); ++si) { 122 | if (ftr->sig[si] != expected_sig[si]) { throw std::runtime_error("tga signature not found"); } 123 | } 124 | 125 | /* only rle-encoded true-color images are allowed. */ 126 | if (hdr->type != tga::img_type::true_color_rle) { 127 | throw std::runtime_error("unsupported tga feature detected"); 128 | } 129 | const bool has_alpha = (hdr->img.descriptor & 0x08) != 0; 130 | 131 | /* obtain extension data offset. */ 132 | const size_t ext_offset = ftr->ext_offset; 133 | 134 | /* read 'attributes type' field to determine whether alpha is 135 | premultiplied. 136 | if no extension section is present, assume non-premultiplied 137 | alpha. */ 138 | const char attr_type = !has_alpha || ext_offset == 0 ? 3 : in_bytes[ext_offset + 494]; 139 | if (attr_type != 3 && attr_type != 4) { throw std::runtime_error("invalid attribute type"); } 140 | const bool is_premul_alpha = attr_type == 4; 141 | 142 | /* read and decode image data, writing result to output. */ 143 | const char* img_data = in_bytes + sizeof(tga::header) + hdr->id_length; 144 | size_t written_pixels = 0; 145 | const size_t bytes_per_pel = has_alpha ? 4 : 3; 146 | while (written_pixels < hdr->img.width * hdr->img.height && 147 | img_data - in_bytes < (ptrdiff_t)in_buf_size) { 148 | const char packet_hdr = *img_data; 149 | const bool is_rle_packet = packet_hdr & 0x80; 150 | const size_t packet_length = 1u + (packet_hdr & 0x7f); 151 | ++img_data; /* advance img. data to point to start of packet data. */ 152 | for (size_t p = 0u; p < packet_length; ++p) { 153 | /* pixel data is stored as BGRA. */ 154 | const uint8_t a = has_alpha ? (uint8_t)img_data[3] : 0xff; 155 | const float af = (float)a / 255.0f; 156 | auto premul = [&](uint8_t v) { 157 | if (is_premul_alpha || !has_alpha) 158 | return v; 159 | else { 160 | /* need to convert from sRGB to linear, premultiply then convert back. */ 161 | const float linear = srgb_to_linear(v); 162 | const float linear_premul = linear * af; 163 | return linear_to_srgb(linear_premul); 164 | } 165 | }; 166 | const uint8_t b = premul((uint8_t)img_data[0]), g = premul((uint8_t)img_data[1]), r = premul((uint8_t)img_data[2]); 167 | out_bytes[written_pixels * 4u + 0] = (char)r; 168 | out_bytes[written_pixels * 4u + 1] = (char)g; 169 | out_bytes[written_pixels * 4u + 2] = (char)b; 170 | out_bytes[written_pixels * 4u + 3] = (char)a; 171 | ++written_pixels; 172 | if (!is_rle_packet) img_data += bytes_per_pel; 173 | } 174 | if (is_rle_packet) img_data += bytes_per_pel; 175 | } 176 | 177 | if (img_data - in_bytes >= (ptrdiff_t)in_buf_size) { 178 | throw std::runtime_error("buffer overflow"); 179 | } 180 | } 181 | 182 | } // namespace ngf_samples 183 | -------------------------------------------------------------------------------- /samples/0a-compute-mandelbrot/compute-mandelbrot.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2025 nicegraf contributors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * 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 Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #define _CRT_SECURE_NO_WARNINGS 24 | #include "check.h" 25 | #include "imgui.h" 26 | #include "logging.h" 27 | #include "nicegraf-util.h" 28 | #include "nicegraf-wrappers.h" 29 | #include "nicemath.h" 30 | #include "sample-interface.h" 31 | #include "shader-loader.h" 32 | 33 | #include 34 | #include 35 | 36 | using namespace ngf_misc; 37 | 38 | namespace ngf_samples { 39 | 40 | namespace compute_demo { 41 | 42 | struct state { 43 | ngf::image image; 44 | ngf::compute_pipeline compute_pipeline; 45 | ngf::graphics_pipeline blit_pipeline; 46 | ngf::sampler sampler; 47 | ngf_compute_encoder prev_compute_enc; 48 | ngf_image_ref image_ref; 49 | uint32_t frame; 50 | }; 51 | 52 | } // namespace compute_demo 53 | 54 | void* sample_initialize( 55 | uint32_t /*width*/, 56 | uint32_t /*height*/, 57 | ngf_sample_count main_render_target_sample_count, 58 | ngf_xfer_encoder /* xfer_encoder*/) { 59 | auto state = new compute_demo::state {}; 60 | 61 | /** 62 | * Load the shader stages. 63 | */ 64 | const ngf::shader_stage compute_shader = 65 | load_shader_stage("compute-demo", "CSMain", NGF_STAGE_COMPUTE); 66 | 67 | /** 68 | * Create the compute pipeline. 69 | */ 70 | ngf_compute_pipeline_info pipeline_info{}; 71 | pipeline_info.shader_stage = compute_shader.get(); 72 | pipeline_info.spec_info = nullptr; 73 | NGF_MISC_CHECK_NGF_ERROR(state->compute_pipeline.initialize(pipeline_info)); 74 | 75 | /** 76 | * Load shader stages. 77 | */ 78 | const ngf::shader_stage blit_vertex_stage = 79 | load_shader_stage("simple-texture", "VSMain", NGF_STAGE_VERTEX); 80 | const ngf::shader_stage blit_fragment_stage = 81 | load_shader_stage("simple-texture", "PSMain", NGF_STAGE_FRAGMENT); 82 | 83 | /** 84 | * Create pipeline for blit. 85 | */ 86 | ngf_util_graphics_pipeline_data blit_pipeline_data; 87 | ngf_util_create_default_graphics_pipeline_data(&blit_pipeline_data); 88 | blit_pipeline_data.multisample_info.sample_count = main_render_target_sample_count; 89 | ngf_graphics_pipeline_info& blit_pipe_info = blit_pipeline_data.pipeline_info; 90 | blit_pipe_info.nshader_stages = 2u; 91 | blit_pipe_info.shader_stages[0] = blit_vertex_stage.get(); 92 | blit_pipe_info.shader_stages[1] = blit_fragment_stage.get(); 93 | blit_pipe_info.compatible_rt_attachment_descs = ngf_default_render_target_attachment_descs(); 94 | NGF_MISC_CHECK_NGF_ERROR(state->blit_pipeline.initialize(blit_pipe_info)); 95 | 96 | /** 97 | * Initialize the image. 98 | */ 99 | ngf_image_info image_info; 100 | image_info.format = NGF_IMAGE_FORMAT_RGBA8; 101 | image_info.extent.depth = 1; 102 | image_info.extent.width = 4 * 128; 103 | image_info.extent.height = 4 * 128; 104 | image_info.nlayers = 1u; 105 | image_info.nmips = 1u; 106 | image_info.sample_count = NGF_SAMPLE_COUNT_1; 107 | image_info.type = NGF_IMAGE_TYPE_IMAGE_2D; 108 | image_info.usage_hint = NGF_IMAGE_USAGE_STORAGE | NGF_IMAGE_USAGE_SAMPLE_FROM; 109 | NGF_MISC_CHECK_NGF_ERROR(state->image.initialize(image_info)); 110 | state->image_ref.image = state->image; 111 | state->image_ref.layer = 0u; 112 | state->image_ref.mip_level = 0u; 113 | 114 | /* Create sampler.*/ 115 | const ngf_sampler_info samp_info { 116 | NGF_FILTER_LINEAR, 117 | NGF_FILTER_LINEAR, 118 | NGF_FILTER_NEAREST, 119 | NGF_WRAP_MODE_CLAMP_TO_EDGE, 120 | NGF_WRAP_MODE_CLAMP_TO_EDGE, 121 | NGF_WRAP_MODE_CLAMP_TO_EDGE, 122 | 0.0f, 123 | 0.0f, 124 | 0.0f, 125 | 1.0f, 126 | false}; 127 | NGF_MISC_CHECK_NGF_ERROR(state->sampler.initialize(samp_info)); 128 | 129 | state->frame = 0u; 130 | 131 | return static_cast(state); 132 | } 133 | 134 | void sample_draw_frame( 135 | ngf_render_encoder main_render_pass, 136 | float /*time_delta*/, 137 | ngf_frame_token /* token*/, 138 | uint32_t w, 139 | uint32_t h, 140 | float /*time*/, 141 | void* userdata) { 142 | auto state = reinterpret_cast(userdata); 143 | if (state->frame > 0u) { 144 | ngf_irect2d onsc_viewport {0, 0, w, h}; 145 | ngf_cmd_bind_gfx_pipeline(main_render_pass, state->blit_pipeline); 146 | ngf_cmd_viewport(main_render_pass, &onsc_viewport); 147 | ngf_cmd_scissor(main_render_pass, &onsc_viewport); 148 | ngf::cmd_bind_resources( 149 | main_render_pass, 150 | ngf::descriptor_set<0>::binding<1>::texture(state->image.get()), 151 | ngf::descriptor_set<0>::binding<2>::sampler(state->sampler.get())); 152 | ngf_cmd_draw(main_render_pass, false, 0u, 3u, 1u); 153 | } 154 | } 155 | 156 | void sample_pre_draw_frame(ngf_cmd_buffer, void*) { } 157 | 158 | void sample_post_draw_frame( 159 | ngf_cmd_buffer cmd_buffer, 160 | void* userdata) { 161 | auto state = reinterpret_cast(userdata); 162 | const ngf_compute_pass_info pass_info {}; 163 | 164 | ngf_compute_encoder compute_enc; 165 | NGF_MISC_CHECK_NGF_ERROR( 166 | ngf_cmd_begin_compute_pass(cmd_buffer, &pass_info, &compute_enc)); 167 | ngf_resource_bind_op bind_op{}; 168 | bind_op.info.image_sampler.is_image_view = false; 169 | bind_op.info.image_sampler.resource.image = state->image; 170 | bind_op.target_set = 0; 171 | bind_op.target_binding = 0; 172 | bind_op.type = NGF_DESCRIPTOR_STORAGE_IMAGE; 173 | ngf_cmd_bind_compute_pipeline(compute_enc, state->compute_pipeline.get()); 174 | ngf_cmd_bind_compute_resources(compute_enc, &bind_op, 1); 175 | ngf_cmd_dispatch(compute_enc, 128, 128, 1); 176 | ngf_cmd_end_compute_pass(compute_enc); 177 | state->prev_compute_enc = compute_enc; 178 | state->frame++; 179 | } 180 | 181 | void sample_post_submit(void*) { 182 | } 183 | 184 | void sample_draw_ui(void* /*userdata*/) { 185 | } 186 | 187 | void sample_shutdown(void* userdata) { 188 | delete reinterpret_cast(userdata); 189 | } 190 | 191 | } // namespace ngf_samples 192 | -------------------------------------------------------------------------------- /samples/02-render-to-texture/render-to-texture.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2021 nicegraf contributors 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * 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 Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #include "sample-interface.h" 24 | #include "nicegraf-wrappers.h" 25 | #include "nicegraf-util.h" 26 | #include "shader-loader.h" 27 | #include "check.h" 28 | 29 | #include 30 | 31 | using namespace ngf_misc; 32 | 33 | namespace ngf_samples { 34 | 35 | struct render_to_texture_data { 36 | ngf::render_target default_rt; 37 | ngf::render_target offscreen_rt; 38 | ngf::graphics_pipeline blit_pipeline; 39 | ngf::graphics_pipeline offscreen_pipeline; 40 | ngf::image rt_texture; 41 | ngf::sampler sampler; 42 | }; 43 | 44 | void* sample_initialize( 45 | uint32_t, 46 | uint32_t, 47 | ngf_sample_count main_render_target_sample_count, 48 | ngf_xfer_encoder /*xfer_encoder*/) { 49 | auto state = new render_to_texture_data{}; 50 | 51 | /* Create the image to render to. */ 52 | const ngf_extent3d img_size { 512u, 512u, 1u }; 53 | const ngf_image_info img_info { 54 | NGF_IMAGE_TYPE_IMAGE_2D, 55 | img_size, 56 | 1u, 57 | 1u, 58 | NGF_IMAGE_FORMAT_BGRA8_SRGB, 59 | NGF_SAMPLE_COUNT_1, 60 | NGF_IMAGE_USAGE_SAMPLE_FROM | NGF_IMAGE_USAGE_ATTACHMENT 61 | }; 62 | NGF_MISC_CHECK_NGF_ERROR(state->rt_texture.initialize(img_info)); 63 | 64 | /* Create the offscreen render target.*/ 65 | const ngf_attachment_description offscreen_color_attachment_description { 66 | .type = NGF_ATTACHMENT_COLOR, 67 | .format = NGF_IMAGE_FORMAT_BGRA8_SRGB, 68 | .sample_count = NGF_SAMPLE_COUNT_1, 69 | }; 70 | const ngf_attachment_descriptions attachments_list = { 71 | .descs = &offscreen_color_attachment_description, 72 | .ndescs = 1u, 73 | }; 74 | const ngf_image_ref img_ref = { 75 | .image = state->rt_texture.get(), 76 | .mip_level = 0u, 77 | .layer = 0u, 78 | .cubemap_face = NGF_CUBEMAP_FACE_COUNT 79 | }; 80 | ngf_render_target_info rt_info { 81 | &attachments_list, 82 | &img_ref 83 | }; 84 | NGF_MISC_CHECK_NGF_ERROR(state->offscreen_rt.initialize(rt_info)); 85 | 86 | /** 87 | * Load shader stages. 88 | */ 89 | const ngf::shader_stage blit_vertex_stage = 90 | load_shader_stage("simple-texture", "VSMain", NGF_STAGE_VERTEX); 91 | const ngf::shader_stage blit_fragment_stage = 92 | load_shader_stage("simple-texture", "PSMain", NGF_STAGE_FRAGMENT); 93 | const ngf::shader_stage offscreen_vertex_stage = 94 | load_shader_stage("small-triangle", "VSMain", NGF_STAGE_VERTEX); 95 | const ngf::shader_stage offscreen_fragment_stage = 96 | load_shader_stage("small-triangle", "PSMain", NGF_STAGE_FRAGMENT); 97 | 98 | /** 99 | * Create pipeline for blit. 100 | */ 101 | ngf_util_graphics_pipeline_data blit_pipeline_data; 102 | ngf_util_create_default_graphics_pipeline_data(&blit_pipeline_data); 103 | blit_pipeline_data.multisample_info.sample_count = main_render_target_sample_count; 104 | ngf_graphics_pipeline_info &blit_pipe_info = 105 | blit_pipeline_data.pipeline_info; 106 | blit_pipe_info.nshader_stages = 2u; 107 | blit_pipe_info.shader_stages[0] = blit_vertex_stage.get(); 108 | blit_pipe_info.shader_stages[1] = blit_fragment_stage.get(); 109 | blit_pipe_info.compatible_rt_attachment_descs = ngf_default_render_target_attachment_descs(); 110 | NGF_MISC_CHECK_NGF_ERROR(state->blit_pipeline.initialize(blit_pipe_info)); 111 | 112 | /** 113 | * Create pipeline for offscreen pass. 114 | */ 115 | ngf_util_graphics_pipeline_data offscreen_pipeline_data; 116 | ngf_util_create_default_graphics_pipeline_data(&offscreen_pipeline_data); 117 | ngf_graphics_pipeline_info &offscreen_pipe_info = 118 | offscreen_pipeline_data.pipeline_info; 119 | offscreen_pipe_info.nshader_stages = 2u; 120 | offscreen_pipe_info.shader_stages[0] = offscreen_vertex_stage.get(); 121 | offscreen_pipe_info.shader_stages[1] = offscreen_fragment_stage.get(); 122 | offscreen_pipe_info.compatible_rt_attachment_descs = &attachments_list; 123 | NGF_MISC_CHECK_NGF_ERROR(state->offscreen_pipeline.initialize(offscreen_pipe_info)); 124 | 125 | /* Create sampler.*/ 126 | const ngf_sampler_info samp_info { 127 | NGF_FILTER_LINEAR, 128 | NGF_FILTER_LINEAR, 129 | NGF_FILTER_NEAREST, 130 | NGF_WRAP_MODE_CLAMP_TO_EDGE, 131 | NGF_WRAP_MODE_CLAMP_TO_EDGE, 132 | NGF_WRAP_MODE_CLAMP_TO_EDGE, 133 | 0.0f, 134 | 0.0f, 135 | 0.0f, 136 | 1.0f, 137 | false 138 | }; 139 | NGF_MISC_CHECK_NGF_ERROR(state->sampler.initialize(samp_info)); 140 | 141 | return static_cast(state); 142 | } 143 | 144 | void sample_draw_frame( 145 | ngf_render_encoder main_render_pass, 146 | float /* time_delta */, 147 | ngf_frame_token frame_token, 148 | uint32_t w, 149 | uint32_t h, 150 | float , 151 | void* userdata) { 152 | auto state = reinterpret_cast(userdata); 153 | ngf_irect2d offsc_viewport {0, 0, 512, 512}; 154 | ngf_irect2d onsc_viewport {0, 0, w, h}; 155 | ngf_cmd_buffer offscr_cmd_buf = nullptr; 156 | ngf_cmd_buffer_info cmd_info = {}; 157 | ngf_create_cmd_buffer(&cmd_info, &offscr_cmd_buf); 158 | ngf_start_cmd_buffer(offscr_cmd_buf, frame_token); 159 | { 160 | ngf::render_encoder renc {offscr_cmd_buf, state->offscreen_rt, .0f, 0.0f, 0.0f, 0.0f, 1.0, 0u}; 161 | ngf_cmd_bind_gfx_pipeline(renc, state->offscreen_pipeline); 162 | ngf_cmd_viewport(renc, &offsc_viewport); 163 | ngf_cmd_scissor(renc, &offsc_viewport); 164 | ngf_cmd_draw(renc, false, 0u, 3u, 1u); 165 | } 166 | ngf_submit_cmd_buffers(1, &offscr_cmd_buf); 167 | ngf_destroy_cmd_buffer(offscr_cmd_buf); 168 | 169 | ngf_cmd_bind_gfx_pipeline(main_render_pass, state->blit_pipeline); 170 | ngf_cmd_viewport(main_render_pass, &onsc_viewport); 171 | ngf_cmd_scissor(main_render_pass, &onsc_viewport); 172 | ngf::cmd_bind_resources( 173 | main_render_pass, 174 | ngf::descriptor_set<0>::binding<1>::texture(state->rt_texture.get()), 175 | ngf::descriptor_set<0>::binding<2>::sampler(state->sampler.get())); 176 | ngf_cmd_draw(main_render_pass, false, 0u, 3u, 1u); 177 | } 178 | 179 | void sample_pre_draw_frame(ngf_cmd_buffer, void*) { 180 | } 181 | 182 | void sample_post_draw_frame(ngf_cmd_buffer, void*) { 183 | } 184 | 185 | void sample_draw_ui(void*) {} 186 | 187 | void sample_post_submit(void*){} 188 | 189 | void sample_shutdown(void* userdata) { 190 | auto data = static_cast(userdata); 191 | delete data; 192 | printf("shutting down\n"); 193 | } 194 | 195 | } 196 | --------------------------------------------------------------------------------