diff --git a/examples/README.md b/examples/README.md index bcb7f50..8940b37 100644 --- a/examples/README.md +++ b/examples/README.md @@ -43,10 +43,8 @@ This series explains the vulkan integration. - Make sure your environment is correctly set up with all dependencies required by `Crafter.Graphics`. - A comaptible WSL envoirement can be set up by running these commands: ```cmd -wsl --update --pre-release +wsl --update wsl --install archlinux --name crafter --no-launch -wsl -d crafter pacman -Syu vulkan-devel mesa vulkan-dzn clang git base-devel code libpqxx onetbb boost lld glslang code --noconfirm -wsl -d crafter bash -c "echo export GALLIUM_DRIVER=d3d12 > /etc/profile.d/wslg.sh" -wsl -d crafter ln -s /usr/lib/libedit.so /usr/lib/libedit.so.2 +wsl -d crafter pacman -Syu vulkan-devel vulkan-swrast clang git base-devel libpqxx onetbb boost lld glslang --noconfirm wsl --terminate crafter ``` diff --git a/examples/VulkanTriangleRuntime/README.md b/examples/VulkanTriangleRuntime/README.md new file mode 100644 index 0000000..7d58bea --- /dev/null +++ b/examples/VulkanTriangleRuntime/README.md @@ -0,0 +1,25 @@ +# HelloWindow Example + +## Description + +This example demonstrates how to load shaders and render a triangle. + +## Expected Result + +A blue tinted vulkan window with a white triangle in the center. + +## Highlighted Code Snippet + +```cpp +EventListener listener(&window.onDraw, [&descriptors, &meshShader](VkCommandBuffer cmd){ + vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, Pipeline::pipelineLayout, 0, 2, &descriptors.set[0], 0, NULL); + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, Pipeline::pipeline); + VulkanDevice::vkCmdDrawMeshTasksEXTProc(cmd, meshShader.threadCount, 1, 1); +}); +``` + +## How to Run + +```bash +crafter-build build executable -r +``` \ No newline at end of file diff --git a/examples/VulkanTriangleRuntime/closesthit.glsl b/examples/VulkanTriangleRuntime/closesthit.glsl new file mode 100644 index 0000000..9a511b6 --- /dev/null +++ b/examples/VulkanTriangleRuntime/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/VulkanTriangleRuntime/main.cpp b/examples/VulkanTriangleRuntime/main.cpp new file mode 100644 index 0000000..04b5907 --- /dev/null +++ b/examples/VulkanTriangleRuntime/main.cpp @@ -0,0 +1,138 @@ +#include + +import Crafter.Graphics; +using namespace Crafter; +import std; +import Crafter.Event; +import Crafter.Math; + + +int main() { + VulkanDevice::CreateDevice(); + WindowVulkan window(1280, 720, "HelloVulkan"); + VkCommandBuffer cmd = window.StartInit(); + + std::vector bindings { + { + .binding = 0, + .descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_RAYGEN_BIT_KHR, + }, + { + .binding = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_RAYGEN_BIT_KHR, + } + }; + DescriptorSetLayoutVulkan layout(std::move(bindings)); + + std::array layouts {{layout.layout}}; + + DescriptorPool pool; + pool.sets.resize(1); + pool.BuildPool(DescriptorPool::GetPoolSizes({layout}), layouts); + + std::array shaders{{ + {"raygen.spv", "main", VK_SHADER_STAGE_RAYGEN_BIT_KHR}, + {"miss.spv", "main", VK_SHADER_STAGE_MISS_BIT_KHR}, + {"closesthit.spv", "main", VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR} + }}; + + ShaderBindingTableVulkan shaderTable; + shaderTable.Init(shaders); + + std::array raygenGroups {{ + { + .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, + }, + }}; + std::array missGroups {{ + { + .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, + }, + }}; + std::array hitGroups {{ + { + .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, + }, + }}; + + PipelineRTVulkan pipeline; + pipeline.Init(cmd, layouts, raygenGroups, missGroups, hitGroups, shaderTable); + + Mesh triangleMesh; + std::array, 3> verts {{{-150, -150, 100}, {0, 150, 100}, {150, -150, 100}}}; + std::array index {{2,1,0}}; + triangleMesh.Build(verts, index, cmd); + RenderingElement3DVulkan renderer = { + .instance = { + .instanceCustomIndex = 0, + .mask = 0xFF, + .instanceShaderBindingTableRecordOffset = 0, + .flags = VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR, + .accelerationStructureReference = triangleMesh.blasAddr + } + }; + MatrixRowMajor transform = MatrixRowMajor::Identity(); + std::memcpy(renderer.instance.transform.matrix, transform.m, sizeof(transform.m)); + RenderingElement3DVulkan::tlases.resize(1); + RenderingElement3DVulkan::elements.push_back(&renderer); + RenderingElement3DVulkan::BuildTLAS(cmd, 0); + + VkDescriptorImageInfo imageInfo = { + .imageView = window.imageViews[0], + .imageLayout = VK_IMAGE_LAYOUT_GENERAL + }; + + VkWriteDescriptorSetAccelerationStructureKHR writeDescriptorSetAccelerationStructure { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR, + .accelerationStructureCount = 1, + .pAccelerationStructures = &RenderingElement3DVulkan::tlases[0].accelerationStructure + }; + + VkWriteDescriptorSet write[2] = { + { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .pNext = &writeDescriptorSetAccelerationStructure, + .dstSet = pool.sets[0], + .dstBinding = 0, + .dstArrayElement = 0, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, + }, + { + .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 + } + }; + vkUpdateDescriptorSets(VulkanDevice::device, 2, write, 0, nullptr); + + window.SetPipelineRT(pipeline); + window.descriptorsRt = pool.sets; + + window.FinishInit(); + window.Render(); + window.StartSync(); +} diff --git a/examples/VulkanTriangleRuntime/miss.glsl b/examples/VulkanTriangleRuntime/miss.glsl new file mode 100644 index 0000000..1478ecf --- /dev/null +++ b/examples/VulkanTriangleRuntime/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/VulkanTriangleRuntime/project.json b/examples/VulkanTriangleRuntime/project.json new file mode 100644 index 0000000..b30faa8 --- /dev/null +++ b/examples/VulkanTriangleRuntime/project.json @@ -0,0 +1,32 @@ +{ + "name": "crafter-graphics", + "configurations": [ + { + "name": "executable", + "implementations": ["main"], + "dependencies": [ + { + "path":"../../project.json", + "configuration":"lib-vulkan-debug" + } + ], + "shaders": [ + { + "path":"raygen.glsl", + "type": 6, + "entrypoint":"main" + }, + { + "path":"closesthit.glsl", + "type": 9, + "entrypoint":"main" + }, + { + "path":"miss.glsl", + "type": 10, + "entrypoint":"main" + } + ] + } + ] +} diff --git a/examples/VulkanTriangleRuntime/raygen.glsl b/examples/VulkanTriangleRuntime/raygen.glsl new file mode 100644 index 0000000..ad7b74c --- /dev/null +++ b/examples/VulkanTriangleRuntime/raygen.glsl @@ -0,0 +1,47 @@ +#version 460 +#extension GL_EXT_ray_tracing : enable +#extension GL_EXT_shader_image_load_formatted : enable + +layout(binding = 0, set = 0) uniform accelerationStructureEXT topLevelAS; +layout(binding = 1, set = 0, rgba8) uniform writeonly image2D image; + +layout(location = 0) rayPayloadEXT vec3 hitValue; + +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-Mesh_vulkan.cpp b/implementations/Crafter.Graphics-Mesh_vulkan.cpp index abe0f4e..fb48192 100644 --- a/implementations/Crafter.Graphics-Mesh_vulkan.cpp +++ b/implementations/Crafter.Graphics-Mesh_vulkan.cpp @@ -22,6 +22,7 @@ module; #include module Crafter.Graphics:Mesh_impl; +import Crafter.Math; import :Mesh; import :VulkanDevice; import :Types; @@ -29,11 +30,11 @@ import std; using namespace Crafter; -void Mesh::Build(std::span verticies, std::span indicies, VkCommandBuffer cmd) { +void Mesh::Build(std::span> verticies, std::span indicies, VkCommandBuffer cmd) { vertexBuffer.Resize(VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_2_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, verticies.size()); indexBuffer.Resize(VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_2_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, indicies.size()); - std::memcpy(vertexBuffer.value, verticies.data(), verticies.size() * sizeof(Vertex)); + std::memcpy(vertexBuffer.value, verticies.data(), verticies.size() * sizeof(Vector)); std::memcpy(indexBuffer.value, indicies.data(), indicies.size() * sizeof(std::uint32_t)); vertexBuffer.FlushDevice(cmd, VK_ACCESS_MEMORY_READ_BIT, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR); @@ -49,7 +50,7 @@ void Mesh::Build(std::span verticies, std::span indicies, .sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR, .vertexFormat = VK_FORMAT_R32G32B32_SFLOAT, .vertexData = vertexAddr, - .vertexStride = sizeof(Vertex), + .vertexStride = sizeof(Vector), .maxVertex = static_cast(verticies.size())-1, .indexType = VK_INDEX_TYPE_UINT32, .indexData = indexAddr, @@ -120,4 +121,10 @@ void Mesh::Build(std::span verticies, std::span indicies, VkAccelerationStructureBuildRangeInfoKHR* blasRangeInfoPP = &blasRangeInfo; VulkanDevice::vkCmdBuildAccelerationStructuresKHR(cmd, 1, &blasBuildGeometryInfo, &blasRangeInfoPP); + + VkAccelerationStructureDeviceAddressInfoKHR addrInfo { + .sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR, + .accelerationStructure = accelerationStructure + }; + blasAddr = VulkanDevice::vkGetAccelerationStructureDeviceAddressKHR(VulkanDevice::device, &addrInfo); } \ No newline at end of file diff --git a/implementations/Crafter.Graphics-RenderingElement3DVulkan.cpp b/implementations/Crafter.Graphics-RenderingElement3DVulkan.cpp index 7b58118..4e57f95 100644 --- a/implementations/Crafter.Graphics-RenderingElement3DVulkan.cpp +++ b/implementations/Crafter.Graphics-RenderingElement3DVulkan.cpp @@ -25,29 +25,13 @@ import std; using namespace Crafter; -std::vector RenderingElement3DVulkan::elements; - -RenderingElement3DVulkan::RenderingElement3DVulkan(Mesh& mesh, std::uint32_t customIndex, std::uint32_t mask, std::uint32_t shaderOffset) { - VkAccelerationStructureDeviceAddressInfoKHR addrInfo { - .sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR, - .accelerationStructure = mesh.accelerationStructure - }; - VkDeviceAddress blasDeviceAddr = VulkanDevice::vkGetAccelerationStructureDeviceAddressKHR(VulkanDevice::device, &addrInfo); - - instance = { - .instanceCustomIndex = customIndex, - .mask = mask, - .instanceShaderBindingTableRecordOffset = shaderOffset, - .flags = VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR, - .accelerationStructureReference = blasDeviceAddr - }; -} +std::vector RenderingElement3DVulkan::elements; void RenderingElement3DVulkan::BuildTLAS(VkCommandBuffer cmd, std::uint32_t index) { tlases[index].instanceBuffer.Resize(VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, elements.size()); for(std::uint32_t i = 0; i < elements.size(); i++) { - tlases[index].instanceBuffer.value[i] = elements[i].instance; + tlases[index].instanceBuffer.value[i] = elements[i]->instance; } tlases[index].instanceBuffer.FlushDevice(cmd, VK_ACCESS_MEMORY_READ_BIT, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR); diff --git a/implementations/Crafter.Graphics-Window_vulkan.cpp b/implementations/Crafter.Graphics-Window_vulkan.cpp index 1cd2710..f2fb871 100644 --- a/implementations/Crafter.Graphics-Window_vulkan.cpp +++ b/implementations/Crafter.Graphics-Window_vulkan.cpp @@ -528,7 +528,7 @@ void WindowVulkan::pointer_handle_button(void* data, wl_pointer* pointer, std::u } } } else { - window->mouseRightHeld = true; + window->mouseRightHeld = false; window->onMouseRightRelease.Invoke(window->currentMousePos); for(MouseElement* element : window->mouseElements) { if(element) { diff --git a/interfaces/Crafter.Graphics-DescriptorPoolVulkan.cppm b/interfaces/Crafter.Graphics-DescriptorPoolVulkan.cppm index 51d7761..3ed0129 100644 --- a/interfaces/Crafter.Graphics-DescriptorPoolVulkan.cppm +++ b/interfaces/Crafter.Graphics-DescriptorPoolVulkan.cppm @@ -26,6 +26,7 @@ export module Crafter.Graphics:DescriptorPoolVulkan; import std; import :VulkanDevice; import :Types; +import :DescriptorSetLayoutVulkan; import Crafter.Event; export namespace Crafter { @@ -97,6 +98,25 @@ export namespace Crafter { return types; } + + constexpr static std::vector GetPoolSizes(const std::span shaders) { + std::vector types; + + for(const DescriptorSetLayoutVulkan& shader : shaders) { + for (const VkDescriptorSetLayoutBinding& binding : shader.descriptors) { + for(VkDescriptorPoolSize& type : types) { + if(type.type == binding.descriptorType) { + type.descriptorCount += binding.descriptorCount; + goto inner; + } + } + types.emplace_back(binding.descriptorType, binding.descriptorCount); + inner:; + } + } + + return types; + } public: void BuildPool(std::span poolSizes, std::span setLayouts) { diff --git a/interfaces/Crafter.Graphics-DescriptorSetLayoutVulkan.cppm b/interfaces/Crafter.Graphics-DescriptorSetLayoutVulkan.cppm index 076d081..20559d3 100644 --- a/interfaces/Crafter.Graphics-DescriptorSetLayoutVulkan.cppm +++ b/interfaces/Crafter.Graphics-DescriptorSetLayoutVulkan.cppm @@ -29,8 +29,22 @@ import :Types; import Crafter.Event; export namespace Crafter { - template Descriptors> class DescriptorSetLayoutVulkan { + public: + VkDescriptorSetLayout layout; + std::vector descriptors; + DescriptorSetLayoutVulkan(std::vector&& layouts) : descriptors(std::move(layouts)) { + VkDescriptorSetLayoutCreateInfo descriptorLayoutInfoMesh = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + .bindingCount = static_cast(descriptors.size()), + .pBindings = descriptors.data() + }; + VulkanDevice::CheckVkResult(vkCreateDescriptorSetLayout(VulkanDevice::device, &descriptorLayoutInfoMesh, nullptr, &layout)); + } + }; + + template Descriptors> + class DescriptorSetLayoutVulkanConst { public: inline static VkDescriptorSetLayout layout; constexpr static std::span descriptors = Descriptors; diff --git a/interfaces/Crafter.Graphics-Mesh.cppm b/interfaces/Crafter.Graphics-Mesh.cppm index 542ef29..96603d8 100644 --- a/interfaces/Crafter.Graphics-Mesh.cppm +++ b/interfaces/Crafter.Graphics-Mesh.cppm @@ -25,27 +25,24 @@ module; export module Crafter.Graphics:Mesh; import std; +import Crafter.Math; import :VulkanBuffer; export namespace Crafter { - struct __attribute__((packed)) Vertex { - float x; - float y; - float z; - }; #ifdef CRAFTER_GRAPHICS_VULKAN class Mesh { public: VulkanBuffer scratchBuffer; VulkanBuffer blasBuffer; - VulkanBuffer vertexBuffer; + VulkanBuffer, true, true, false> vertexBuffer; VulkanBuffer indexBuffer; VkAccelerationStructureGeometryTrianglesDataKHR blasData; VkAccelerationStructureGeometryKHR blas; VkAccelerationStructureKHR accelerationStructure; + VkDeviceAddress blasAddr; bool opaque; - void Build(std::span verticies, std::span indicies, VkCommandBuffer cmd); + void Build(std::span> verticies, std::span indicies, VkCommandBuffer cmd); }; #endif } \ No newline at end of file diff --git a/interfaces/Crafter.Graphics-PipelineRTVulkan.cppm b/interfaces/Crafter.Graphics-PipelineRTVulkan.cppm index bbc2f54..2b8aa52 100644 --- a/interfaces/Crafter.Graphics-PipelineRTVulkan.cppm +++ b/interfaces/Crafter.Graphics-PipelineRTVulkan.cppm @@ -30,6 +30,91 @@ import :ShaderBindingTableVulkan; import :Types; export namespace Crafter { + class PipelineRTVulkan { + public: + VkPipeline pipeline; + VkPipelineLayout pipelineLayout; + std::vector shaderHandles; + VulkanBuffer sbtBuffer; + VkStridedDeviceAddressRegionKHR raygenRegion; + VkStridedDeviceAddressRegionKHR missRegion; + VkStridedDeviceAddressRegionKHR hitRegion; + VkStridedDeviceAddressRegionKHR callableRegion; + + void Init(VkCommandBuffer cmd, std::span setLayouts, std::span raygenGroups, std::span missGroups, std::span hitGroups, ShaderBindingTableVulkan& shaderTable) { + VkPipelineLayoutCreateInfo pipelineLayoutInfo { + .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + .setLayoutCount = static_cast(setLayouts.size()), + .pSetLayouts = setLayouts.data() + }; + + VulkanDevice::CheckVkResult(vkCreatePipelineLayout(VulkanDevice::device, &pipelineLayoutInfo, nullptr, &pipelineLayout)); + + std::vector groups; + groups.reserve(raygenGroups.size() + missGroups.size() + hitGroups.size()); + + groups.insert(groups.end(), raygenGroups.begin(), raygenGroups.end()); + groups.insert(groups.end(), missGroups.begin(), missGroups.end()); + groups.insert(groups.end(), hitGroups.begin(), hitGroups.end()); + + VkRayTracingPipelineCreateInfoKHR rtPipelineInfo{ + .sType = VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR, + .stageCount = static_cast(shaderTable.shaderStages.size()), + .pStages = shaderTable.shaderStages.data(), + .groupCount = static_cast(groups.size()), + .pGroups = groups.data(), + .maxPipelineRayRecursionDepth = 1, + .layout = pipelineLayout + }; + + VulkanDevice::CheckVkResult(VulkanDevice::vkCreateRayTracingPipelinesKHR(VulkanDevice::device, {}, {}, 1, &rtPipelineInfo, nullptr, &pipeline)); + + std::size_t dataSize = VulkanDevice::rayTracingProperties.shaderGroupHandleSize * rtPipelineInfo.groupCount; + shaderHandles.resize(dataSize); + VulkanDevice::CheckVkResult(VulkanDevice::vkGetRayTracingShaderGroupHandlesKHR(VulkanDevice::device, pipeline, 0, rtPipelineInfo.groupCount, dataSize, shaderHandles.data())); + + std::uint32_t sbtStride = AlignUp(VulkanDevice::rayTracingProperties.shaderGroupHandleSize, VulkanDevice::rayTracingProperties.shaderGroupHandleAlignment); + + raygenRegion.stride = sbtStride; + raygenRegion.deviceAddress = 0; + raygenRegion.size = raygenGroups.size() * sbtStride; + + missRegion.stride = sbtStride; + missRegion.deviceAddress = AlignUp(raygenRegion.size, VulkanDevice::rayTracingProperties.shaderGroupBaseAlignment); + missRegion.size = missGroups.size() * sbtStride; + + hitRegion.stride = sbtStride; + hitRegion.deviceAddress = AlignUp(missRegion.deviceAddress + missRegion.size, VulkanDevice::rayTracingProperties.shaderGroupBaseAlignment); + hitRegion.size = hitGroups.size() * sbtStride; + + std::size_t bufferSize = hitRegion.deviceAddress + hitRegion.size; + sbtBuffer.Create(VK_BUFFER_USAGE_2_SHADER_BINDING_TABLE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, bufferSize); + + std::uint8_t* offset = sbtBuffer.value; + std::uint8_t* handleOffset = shaderHandles.data(); + + std::memcpy(offset, handleOffset, raygenGroups.size() * VulkanDevice::rayTracingProperties.shaderGroupHandleSize); + offset += AlignUp(raygenRegion.size, VulkanDevice::rayTracingProperties.shaderGroupBaseAlignment); + handleOffset += raygenGroups.size() * VulkanDevice::rayTracingProperties.shaderGroupHandleSize; + + std::memcpy(offset, handleOffset, missGroups.size() * VulkanDevice::rayTracingProperties.shaderGroupHandleSize); + offset += AlignUp(missRegion.size, VulkanDevice::rayTracingProperties.shaderGroupBaseAlignment); + handleOffset += missGroups.size() * VulkanDevice::rayTracingProperties.shaderGroupHandleSize; + + std::memcpy(offset, handleOffset, hitGroups.size() * VulkanDevice::rayTracingProperties.shaderGroupHandleSize); + + sbtBuffer.FlushDevice(cmd, VK_ACCESS_MEMORY_READ_BIT, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR); + + raygenRegion.deviceAddress += sbtBuffer.address; + missRegion.deviceAddress += sbtBuffer.address; + hitRegion.deviceAddress += sbtBuffer.address; + + callableRegion.deviceAddress = 0; + callableRegion.stride = 0; + callableRegion.size = 0; + } + }; + template struct ShaderGroup { static constexpr std::uint32_t generalShader = GeneralShader; @@ -39,7 +124,7 @@ export namespace Crafter { }; template - class PipelineRTVulkan { + class PipelineRTVulkanConst { public: inline static VkPipeline pipeline; inline static VkPipelineLayout pipelineLayout; @@ -65,8 +150,8 @@ export namespace Crafter { VkRayTracingPipelineCreateInfoKHR rtPipelineInfo{ .sType = VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR, - .stageCount = static_cast(ShaderBindingTableVulkan::shaderStages.size()), - .pStages = ShaderBindingTableVulkan::shaderStages.data(), + .stageCount = static_cast(ShaderBindingTableVulkanConst::shaderStages.size()), + .pStages = ShaderBindingTableVulkanConst::shaderStages.data(), .groupCount = static_cast(groups.size()), .pGroups = groups.data(), .maxPipelineRayRecursionDepth = 1, diff --git a/interfaces/Crafter.Graphics-RenderingElement.cppm b/interfaces/Crafter.Graphics-RenderingElement.cppm index 5a8640d..f6ccf19 100644 --- a/interfaces/Crafter.Graphics-RenderingElement.cppm +++ b/interfaces/Crafter.Graphics-RenderingElement.cppm @@ -18,7 +18,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ module; -#define STB_IMAGE_IMPLEMENTATION #include "../lib/stb_image.h" #include "../lib/stb_truetype.h" export module Crafter.Graphics:RenderingElement; diff --git a/interfaces/Crafter.Graphics-RenderingElement3DVulkan.cppm b/interfaces/Crafter.Graphics-RenderingElement3DVulkan.cppm index 6b25a2b..5f73b1b 100644 --- a/interfaces/Crafter.Graphics-RenderingElement3DVulkan.cppm +++ b/interfaces/Crafter.Graphics-RenderingElement3DVulkan.cppm @@ -38,12 +38,10 @@ export namespace Crafter { class RenderingElement3DVulkan { public: - Mesh* mesh; VkAccelerationStructureInstanceKHR instance; - static std::vector elements; + static std::vector elements; inline static VulkanBuffer scratchBuffer; inline static std::vector tlases; - RenderingElement3DVulkan(Mesh& mesh, std::uint32_t customIndex, std::uint32_t mask, std::uint32_t shaderOffset); static void BuildTLAS(VkCommandBuffer cmd, std::uint32_t index); }; } diff --git a/interfaces/Crafter.Graphics-ShaderBindingTableVulkan.cppm b/interfaces/Crafter.Graphics-ShaderBindingTableVulkan.cppm index 6e1101f..5bea053 100644 --- a/interfaces/Crafter.Graphics-ShaderBindingTableVulkan.cppm +++ b/interfaces/Crafter.Graphics-ShaderBindingTableVulkan.cppm @@ -26,11 +26,23 @@ export module Crafter.Graphics:ShaderBindingTableVulkan; import std; import :VulkanDevice; import :VulkanBuffer; +import :ShaderVulkan; import :Types; export namespace Crafter { - template class ShaderBindingTableVulkan { + public: + std::vector shaderStages; + void Init(std::span shaders) { + shaderStages.reserve(shaders.size()); + for(const VulkanShader& shader: shaders) { + shaderStages.emplace_back(VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, nullptr, 0, shader.stage, shader.shader, shader.entrypoint.c_str(), nullptr); + } + } + }; + + template + class ShaderBindingTableVulkanConst { public: inline static std::array> shaderStages; static void Init() { diff --git a/interfaces/Crafter.Graphics-ShaderVulkan.cppm b/interfaces/Crafter.Graphics-ShaderVulkan.cppm index a0429bd..d9014f8 100644 --- a/interfaces/Crafter.Graphics-ShaderVulkan.cppm +++ b/interfaces/Crafter.Graphics-ShaderVulkan.cppm @@ -37,17 +37,49 @@ export namespace Crafter { char value[N]; }; + class VulkanShader { + public: + VkShaderStageFlagBits stage; + std::string entrypoint; + VkShaderModule shader; + VulkanShader(const std::filesystem::path& path, std::string entrypoint, VkShaderStageFlagBits stage) : stage(stage), entrypoint(entrypoint) { + std::ifstream file(path, std::ios::binary); + if (!file) { + std::cerr << "Error: Could not open file " << path << std::endl; + } + + // Move to the end of the file to determine its size + file.seekg(0, std::ios::end); + std::streamsize size = file.tellg(); + file.seekg(0, std::ios::beg); + + std::vector spirv(size / sizeof(std::uint32_t)); + + // Read the data into the vector + if (!file.read(reinterpret_cast(spirv.data()), size)) { + std::cerr << "Error: Could not read data from file" << std::endl; + } + + file.close(); + + VkShaderModuleCreateInfo module_info{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO}; + module_info.codeSize = spirv.size() * sizeof(uint32_t); + module_info.pCode = spirv.data(); + + VulkanDevice::CheckVkResult(vkCreateShaderModule(VulkanDevice::device, &module_info, nullptr, &shader)); + } + }; + template < StringLiteral path, StringLiteral entrypoint, VkShaderStageFlagBits stage > - class VulkanShader { + class VulkanShaderConst { public: constexpr static VkShaderStageFlagBits _stage = stage; constexpr static StringLiteral _entrypoint = entrypoint; inline static VkShaderModule shader; - static void CreateShader() { std::ifstream file(path.value, std::ios::binary); if (!file) { @@ -72,7 +104,6 @@ export namespace Crafter { module_info.codeSize = spirv.size() * sizeof(uint32_t); module_info.pCode = spirv.data(); - VkShaderModule shader_module; VulkanDevice::CheckVkResult(vkCreateShaderModule(VulkanDevice::device, &module_info, nullptr, &shader)); } }; diff --git a/interfaces/Crafter.Graphics-Types.cppm b/interfaces/Crafter.Graphics-Types.cppm index bbc4ece..bc7d7c4 100644 --- a/interfaces/Crafter.Graphics-Types.cppm +++ b/interfaces/Crafter.Graphics-Types.cppm @@ -215,6 +215,19 @@ export namespace Crafter { } } + template + constexpr double MappedToNDCBoundless(T mapped, std::uint32_t size) requires(std::is_integral_v) { + if constexpr (std::is_same_v || std::is_same_v) { + return mapped / SCALEBOUNDLESSDOUBLE8 - 0.5; + } else if constexpr (std::is_same_v || std::is_same_v) { + return mapped / SCALEBOUNDLESSDOUBLE16 - 0.5; + } else if constexpr (std::is_same_v || std::is_same_v) { + return mapped / SCALEBOUNDLESSDOUBLE32 - 0.5; + } else { + return mapped / SCALEBOUNDLESSDOUBLE64 - 0.5; + } + } + template constexpr T MappedToAbsolute(T mapped, T2 absolute) requires(std::is_integral_v) { if constexpr (std::is_same_v || std::is_same_v) { @@ -354,6 +367,11 @@ export namespace Crafter { return (value + alignment - 1) & ~(alignment - 1); } + template + constexpr T GetTanHalfFov(T fov) { + return std::tan(fov * std::numbers::pi / 360.0); + } + #ifdef CRAFTER_GRAPHICS_VULKAN struct DescriptorBinding { VkDescriptorType type; diff --git a/interfaces/Crafter.Graphics-Window.cppm b/interfaces/Crafter.Graphics-Window.cppm index 5d772a4..bd39133 100644 --- a/interfaces/Crafter.Graphics-Window.cppm +++ b/interfaces/Crafter.Graphics-Window.cppm @@ -322,6 +322,15 @@ export namespace Crafter { hitRegion = Pipeline::hitRegion; callableRegion = Pipeline::callableRegion; } + + void SetPipelineRT(PipelineRTVulkan& pipeline) { + rtPipeline = pipeline.pipeline; + rtPipelineLayout = pipeline.pipelineLayout; + raygenRegion = pipeline.raygenRegion; + missRegion = pipeline.missRegion; + hitRegion = pipeline.hitRegion; + callableRegion = pipeline.callableRegion; + } inline static wl_compositor* compositor = nullptr; static void wl_surface_frame_done(void *data, wl_callback *cb, uint32_t time); static void PointerListenerHandleMotion(void* data, wl_pointer* wl_pointer, uint time, wl_fixed_t surface_x, wl_fixed_t surface_y);