From 96b5d1a299b9e31a5ba2b5008f0a70ed7b4601c2 Mon Sep 17 00:00:00 2001 From: Jorijn van der Graaf Date: Thu, 29 Jan 2026 19:18:47 +0100 Subject: [PATCH] vulkan triangle --- examples/VulkanTriangle/closesthit.glsl | 12 ++++ examples/VulkanTriangle/main.cpp | 45 +++++++----- examples/VulkanTriangle/miss.glsl | 9 +++ examples/VulkanTriangle/project.json | 12 +++- examples/VulkanTriangle/raygen.glsl | 43 +++++++++-- ...fter.Graphics-RenderingElement3DVulkan.cpp | 11 ++- .../Crafter.Graphics-PipelineRTVulkan.cppm | 72 ++++++++++++++----- interfaces/Crafter.Graphics-Window.cppm | 14 ++-- 8 files changed, 170 insertions(+), 48 deletions(-) diff --git a/examples/VulkanTriangle/closesthit.glsl b/examples/VulkanTriangle/closesthit.glsl index e69de29..9a511b6 100644 --- a/examples/VulkanTriangle/closesthit.glsl +++ b/examples/VulkanTriangle/closesthit.glsl @@ -0,0 +1,12 @@ +#version 460 +#extension GL_EXT_ray_tracing : enable +#extension GL_EXT_nonuniform_qualifier : enable + +layout(location = 0) rayPayloadInEXT vec3 hitValue; +hitAttributeEXT vec2 attribs; + +void main() +{ + const vec3 barycentricCoords = vec3(1.0f - attribs.x - attribs.y, attribs.x, attribs.y); + hitValue = barycentricCoords; +} \ No newline at end of file diff --git a/examples/VulkanTriangle/main.cpp b/examples/VulkanTriangle/main.cpp index 1f7ebb3..f699497 100644 --- a/examples/VulkanTriangle/main.cpp +++ b/examples/VulkanTriangle/main.cpp @@ -5,9 +5,12 @@ using namespace Crafter; import std; typedef VulkanShader<"raygen.spv", "main", VK_SHADER_STAGE_RAYGEN_BIT_KHR, 2, {{{VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 0}, {VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1}}}> Raygenspv; +typedef VulkanShader<"closesthit.spv", "main", VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, 0, {{}}> Closesthitspv; +typedef VulkanShader<"miss.spv", "main", VK_SHADER_STAGE_MISS_BIT_KHR, 0, {{}}> Misspv; int main() { + std::this_thread::sleep_for(std::chrono::milliseconds(500)); /* This sets up all necessary things and creates the vulkan device. This must be called before any vulkan related things. @@ -15,9 +18,11 @@ int main() { */ VulkanDevice::CreateDevice(); Raygenspv::CreateShader(); - DescriptorLayoutVulkan::Init(); - PipelineRTVulkan::Init(); - DescriptorPool<1, Raygenspv> pool; + Closesthitspv::CreateShader(); + Misspv::CreateShader(); + DescriptorLayoutVulkan::Init(); + PipelineRTVulkan::Init(); + DescriptorPool<1, Raygenspv, Closesthitspv, Misspv> pool; pool.setsCount = 1; pool.BuildPool(0); @@ -30,8 +35,8 @@ int main() { VkCommandBuffer cmd = window.StartInit(); Mesh triangleMesh; - std::array verts {{{-0.1, 0, 0}, {0, 0.1, 0}, {0.1, 0, 0}}}; - std::array index {{0,1,2}}; + std::array verts {{{-150, -150, 100}, {0, 150, 100}, {150, -150, 100}}}; + std::array index {{2,1,0}}; triangleMesh.Build(verts, index, cmd); RenderingElement3DVulkan::elements.emplace_back(triangleMesh); RenderingElement3DVulkan::BuildTLAS(cmd); @@ -41,8 +46,6 @@ int main() { .imageLayout = VK_IMAGE_LAYOUT_GENERAL }; - std::cout << pool.sets.size() << std::endl; - VkWriteDescriptorSetAccelerationStructureKHR writeDescriptorSetAccelerationStructure { .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR, .accelerationStructureCount = 1, @@ -51,21 +54,22 @@ int main() { VkWriteDescriptorSet write[2] = { { - .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, .pNext = &writeDescriptorSetAccelerationStructure, - .dstSet = pool.sets[0], + .dstSet = pool.sets[0], .dstBinding = 0, + .dstArrayElement = 0, .descriptorCount = 1, - .descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, - .pBufferInfo = &RenderingElement3DVulkan::tlasBuffer.descriptor + .descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, }, { - .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - .dstSet = pool.sets[0], + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = pool.sets[0], .dstBinding = 1, + .dstArrayElement = 0, .descriptorCount = 1, - .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, - .pImageInfo = &imageInfo + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + .pImageInfo = &imageInfo } }; vkUpdateDescriptorSets(VulkanDevice::device, 2, write, 0, nullptr); @@ -77,9 +81,18 @@ int main() { */ window.FinishInit(); - window.SetPipelineRT(); + window.SetPipelineRT(); window.descriptorsRt = pool.sets; window.Render(); + window.Render(); + window.Render(); + window.Render(); + // window.Render(); + // window.Render(); + // window.Render(); + // window.Render(); + // window.Render(); + // window.Render(); window.StartSync(); } diff --git a/examples/VulkanTriangle/miss.glsl b/examples/VulkanTriangle/miss.glsl index e69de29..1478ecf 100644 --- a/examples/VulkanTriangle/miss.glsl +++ b/examples/VulkanTriangle/miss.glsl @@ -0,0 +1,9 @@ +#version 460 +#extension GL_EXT_ray_tracing : enable + +layout(location = 0) rayPayloadInEXT vec3 hitValue; + +void main() +{ + hitValue = vec3(1, 1, 1); +} \ No newline at end of file diff --git a/examples/VulkanTriangle/project.json b/examples/VulkanTriangle/project.json index 5e7d608..61eba87 100644 --- a/examples/VulkanTriangle/project.json +++ b/examples/VulkanTriangle/project.json @@ -13,7 +13,17 @@ "shaders": [ { "path":"raygen.glsl", - "type":6, + "type": 6, + "entrypoint":"main" + }, + { + "path":"closesthit.glsl", + "type": 9, + "entrypoint":"main" + }, + { + "path":"miss.glsl", + "type": 10, "entrypoint":"main" } ] diff --git a/examples/VulkanTriangle/raygen.glsl b/examples/VulkanTriangle/raygen.glsl index c7b8e5c..02f57a2 100644 --- a/examples/VulkanTriangle/raygen.glsl +++ b/examples/VulkanTriangle/raygen.glsl @@ -3,10 +3,45 @@ #extension GL_EXT_shader_image_load_formatted : enable layout(binding = 0, set = 0) uniform accelerationStructureEXT topLevelAS; -layout(binding = 1, set = 0) uniform image2D image; +layout(binding = 1, set = 0, rgba32f) uniform image2D image; layout(location = 0) rayPayloadEXT vec3 hitValue; -void main() { - imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(1,1,1, 0.0)); -} \ No newline at end of file +void main() +{ + // Pixel coordinates + uvec2 pixel = gl_LaunchIDEXT.xy; + uvec2 resolution = gl_LaunchSizeEXT.xy; + + // Normalized coordinates in range [-1, 1] + vec2 uv = (vec2(pixel) + 0.5) / vec2(resolution); + vec2 ndc = uv * 2.0 - 1.0; + + // Camera parameters + vec3 origin = vec3(0.0, 0.0, -300.0); + + float aspect = float(resolution.x) / float(resolution.y); + float fov = radians(60.0); + float tanHalfFov = tan(fov * 0.5); + + // Simple pinhole camera facing +Z + vec3 direction = normalize(vec3( + ndc.x * aspect * tanHalfFov, + -ndc.y * tanHalfFov, + 1.0 + )); + + traceRayEXT( + topLevelAS, + gl_RayFlagsNoneEXT, + 0xff, + 0, 0, 0, + origin, + 0.001, + direction, + 10000.0, + 0 + ); + + imageStore(image, ivec2(pixel), vec4(hitValue, 1.0)); +} diff --git a/implementations/Crafter.Graphics-RenderingElement3DVulkan.cpp b/implementations/Crafter.Graphics-RenderingElement3DVulkan.cpp index 8864d91..b14167a 100644 --- a/implementations/Crafter.Graphics-RenderingElement3DVulkan.cpp +++ b/implementations/Crafter.Graphics-RenderingElement3DVulkan.cpp @@ -43,9 +43,12 @@ RenderingElement3DVulkan::RenderingElement3DVulkan(Mesh& mesh) { VkDeviceAddress blasDeviceAddr = VulkanDevice::vkGetAccelerationStructureDeviceAddressKHR(VulkanDevice::device, &addrInfo); instance = { - .transform = identity, - .mask = 0xFF, - .accelerationStructureReference = blasDeviceAddr + .transform = identity, + .instanceCustomIndex = 0, + .mask = 0xFF, + .instanceShaderBindingTableRecordOffset = 0, + .flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR | VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR, + .accelerationStructureReference = blasDeviceAddr }; } @@ -56,6 +59,8 @@ void RenderingElement3DVulkan::BuildTLAS(VkCommandBuffer cmd) { instanceBuffer.value[i] = elements[i].instance; } + instanceBuffer.FlushDevice(cmd, VK_ACCESS_MEMORY_READ_BIT, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR); + VkAccelerationStructureGeometryInstancesDataKHR instancesData = VkAccelerationStructureGeometryInstancesDataKHR { .sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR, .arrayOfPointers = VK_FALSE, diff --git a/interfaces/Crafter.Graphics-PipelineRTVulkan.cppm b/interfaces/Crafter.Graphics-PipelineRTVulkan.cppm index 74f6dee..b433403 100644 --- a/interfaces/Crafter.Graphics-PipelineRTVulkan.cppm +++ b/interfaces/Crafter.Graphics-PipelineRTVulkan.cppm @@ -30,7 +30,7 @@ import :VulkanBuffer; import :Types; export namespace Crafter { - template + template class PipelineRTVulkan { public: inline static VkPipeline pipeline; @@ -51,7 +51,7 @@ export namespace Crafter { VulkanDevice::CheckVkResult(vkCreatePipelineLayout(VulkanDevice::device, &pipelineLayoutInfo, nullptr, &pipelineLayout)); - std::array shaderStages; + std::array shaderStages; shaderStages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; shaderStages[0].stage = Raygen::_stage; @@ -61,20 +61,56 @@ export namespace Crafter { shaderStages[0].pSpecializationInfo = nullptr; shaderStages[0].pNext = nullptr; - VkRayTracingShaderGroupCreateInfoKHR group { - .sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR, - .generalShader = 0, - .closestHitShader = VK_SHADER_UNUSED_KHR, - .anyHitShader = VK_SHADER_UNUSED_KHR, - .intersectionShader = VK_SHADER_UNUSED_KHR - }; + shaderStages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + shaderStages[1].stage = Miss::_stage; + shaderStages[1].module = Miss::shader; + shaderStages[1].pName = Miss::_entrypoint.value; + shaderStages[1].flags = 0; + shaderStages[1].pSpecializationInfo = nullptr; + shaderStages[1].pNext = nullptr; + + shaderStages[2].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + shaderStages[2].stage = ClosestHit::_stage; + shaderStages[2].module = ClosestHit::shader; + shaderStages[2].pName = ClosestHit::_entrypoint.value; + shaderStages[2].flags = 0; + shaderStages[2].pSpecializationInfo = nullptr; + shaderStages[2].pNext = nullptr; + + + std::array groups {{ + { + .sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR, + .type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR, + .generalShader = 0, + .closestHitShader = VK_SHADER_UNUSED_KHR, + .anyHitShader = VK_SHADER_UNUSED_KHR, + .intersectionShader = VK_SHADER_UNUSED_KHR + }, + { + .sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR, + .type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR, + .generalShader = 1, + .closestHitShader = VK_SHADER_UNUSED_KHR, + .anyHitShader = VK_SHADER_UNUSED_KHR, + .intersectionShader = VK_SHADER_UNUSED_KHR + }, + { + .sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR, + .type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR, + .generalShader = VK_SHADER_UNUSED_KHR, + .closestHitShader = 2, + .anyHitShader = VK_SHADER_UNUSED_KHR, + .intersectionShader = VK_SHADER_UNUSED_KHR + } + }}; VkRayTracingPipelineCreateInfoKHR rtPipelineInfo{ .sType = VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR, .stageCount = static_cast(shaderStages.size()), .pStages = shaderStages.data(), - .groupCount = static_cast(1), - .pGroups = &group, + .groupCount = static_cast(groups.size()), + .pGroups = groups.data(), .maxPipelineRayRecursionDepth = 1, .layout = pipelineLayout }; @@ -110,13 +146,15 @@ export namespace Crafter { raygenRegion.stride = raygenSize; raygenRegion.size = raygenSize; - missRegion.deviceAddress = 0; - missRegion.stride = 0; - missRegion.size = 0; + std::memcpy(sbtBuffer.value + missOffset, shaderHandles.data() + 1 * handleSize, handleSize); + missRegion.deviceAddress = sbtBuffer.address + missOffset; + missRegion.stride = missSize; + missRegion.size = missSize; - hitRegion.deviceAddress = 0; - hitRegion.stride = 0; - hitRegion.size = 0; + std::memcpy(sbtBuffer.value + hitOffset, shaderHandles.data() + 2 * handleSize, handleSize); + hitRegion.deviceAddress = sbtBuffer.address + hitOffset; + hitRegion.stride = hitSize; + hitRegion.size = hitSize; callableRegion.deviceAddress = 0; callableRegion.stride = 0; diff --git a/interfaces/Crafter.Graphics-Window.cppm b/interfaces/Crafter.Graphics-Window.cppm index 67cb907..e6b77f1 100644 --- a/interfaces/Crafter.Graphics-Window.cppm +++ b/interfaces/Crafter.Graphics-Window.cppm @@ -311,14 +311,14 @@ export namespace Crafter { VkCommandBuffer StartInit(); void FinishInit(); - template + template void SetPipelineRT() { - rtPipeline = PipelineRTVulkan::pipeline; - rtPipelineLayout = PipelineRTVulkan::pipelineLayout; - raygenRegion = PipelineRTVulkan::raygenRegion; - missRegion = PipelineRTVulkan::missRegion; - hitRegion = PipelineRTVulkan::hitRegion; - callableRegion = PipelineRTVulkan::callableRegion; + rtPipeline = PipelineRTVulkan::pipeline; + rtPipelineLayout = PipelineRTVulkan::pipelineLayout; + raygenRegion = PipelineRTVulkan::raygenRegion; + missRegion = PipelineRTVulkan::missRegion; + hitRegion = PipelineRTVulkan::hitRegion; + callableRegion = PipelineRTVulkan::callableRegion; } inline static wl_compositor* compositor = nullptr; static void wl_surface_frame_done(void *data, wl_callback *cb, uint32_t time);