#ifndef CRAFTER_GRAPHICS_WINDOW_DOM #include "vulkan/vulkan.h" #endif #include import Crafter.Graphics; using namespace Crafter; import std; import Crafter.Event; import Crafter.Math; #ifndef CRAFTER_GRAPHICS_WINDOW_DOM int main() { Device::Initialize(); Window window(1280, 720, "HelloVulkan"); VkCommandBuffer cmd = window.StartInit(); DescriptorHeapVulkan descriptorHeap; descriptorHeap.Initialize(1,1,0); VkSpecializationMapEntry entry = { .constantID = 0, .offset = 0, .size = sizeof(uint16_t) }; VkSpecializationInfo specilizationInfo = { .mapEntryCount = 1, .pMapEntries = &entry, .dataSize = sizeof(uint16_t), .pData = &descriptorHeap.bufferStartElement }; std::array shaders{{ {"raygen.spv", "main", VK_SHADER_STAGE_RAYGEN_BIT_KHR, &specilizationInfo}, {"miss.spv", "main", VK_SHADER_STAGE_MISS_BIT_KHR, nullptr}, {"closesthit.spv", "main", VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, nullptr} }}; 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, 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); RenderingElement3D renderer = { .instance = { .instanceCustomIndex = 0, .mask = 0xFF, .instanceShaderBindingTableRecordOffset = 0, .flags = VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR, .accelerationStructureReference = triangleMesh.blasAddr } }; RenderingElement3D::elements.emplace_back(&renderer); MatrixRowMajor transform = MatrixRowMajor::Identity(); transform.Store(reinterpret_cast(renderer.instance.transform.matrix)); RenderingElement3D::BuildTLAS(cmd, 0); RenderingElement3D::BuildTLAS(cmd, 1); RenderingElement3D::BuildTLAS(cmd, 2); window.FinishInit(); auto imgSlots = descriptorHeap.AllocateImageSlots(1); auto bufSlots = descriptorHeap.AllocateBufferSlots(1); VkDeviceAddressRangeKHR tlasRange0 = { .address = RenderingElement3D::tlases[0].address, }; VkDeviceAddressRangeKHR tlasRange1 = { .address = RenderingElement3D::tlases[1].address, }; VkDeviceAddressRangeKHR tlasRange2 = { .address = RenderingElement3D::tlases[2].address, }; VkImageDescriptorInfoEXT imageInfo0 = { .sType = VK_STRUCTURE_TYPE_IMAGE_DESCRIPTOR_INFO_EXT, .pView = &window.imageViews[0], .layout = VK_IMAGE_LAYOUT_GENERAL }; VkImageDescriptorInfoEXT imageInfo1 = { .sType = VK_STRUCTURE_TYPE_IMAGE_DESCRIPTOR_INFO_EXT, .pView = &window.imageViews[1], .layout = VK_IMAGE_LAYOUT_GENERAL }; VkImageDescriptorInfoEXT imageInfo2 = { .sType = VK_STRUCTURE_TYPE_IMAGE_DESCRIPTOR_INFO_EXT, .pView = &window.imageViews[2], .layout = VK_IMAGE_LAYOUT_GENERAL }; VkResourceDescriptorInfoEXT resources[6] = { { .sType = VK_STRUCTURE_TYPE_RESOURCE_DESCRIPTOR_INFO_EXT, .type = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, .data = { .pAddressRange = &tlasRange0} }, { .sType = VK_STRUCTURE_TYPE_RESOURCE_DESCRIPTOR_INFO_EXT, .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, .data = { .pImage = &imageInfo0 } }, { .sType = VK_STRUCTURE_TYPE_RESOURCE_DESCRIPTOR_INFO_EXT, .type = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, .data = { .pAddressRange = &tlasRange1} }, { .sType = VK_STRUCTURE_TYPE_RESOURCE_DESCRIPTOR_INFO_EXT, .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, .data = { .pImage = &imageInfo1 } }, { .sType = VK_STRUCTURE_TYPE_RESOURCE_DESCRIPTOR_INFO_EXT, .type = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, .data = { .pAddressRange = &tlasRange2} }, { .sType = VK_STRUCTURE_TYPE_RESOURCE_DESCRIPTOR_INFO_EXT, .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, .data = { .pImage = &imageInfo2 } }, }; VkHostAddressRangeEXT destinations[6] = { { .address = descriptorHeap.resourceHeap[0].value + descriptorHeap.BufferByteOffset(bufSlots.firstElement), .size = Device::descriptorHeapProperties.bufferDescriptorSize }, { .address = descriptorHeap.resourceHeap[0].value + descriptorHeap.ImageByteOffset(imgSlots.firstElement), .size = Device::descriptorHeapProperties.imageDescriptorSize }, { .address = descriptorHeap.resourceHeap[1].value + descriptorHeap.BufferByteOffset(bufSlots.firstElement), .size = Device::descriptorHeapProperties.bufferDescriptorSize }, { .address = descriptorHeap.resourceHeap[1].value + descriptorHeap.ImageByteOffset(imgSlots.firstElement), .size = Device::descriptorHeapProperties.imageDescriptorSize }, { .address = descriptorHeap.resourceHeap[2].value + descriptorHeap.BufferByteOffset(bufSlots.firstElement), .size = Device::descriptorHeapProperties.bufferDescriptorSize }, { .address = descriptorHeap.resourceHeap[2].value + descriptorHeap.ImageByteOffset(imgSlots.firstElement), .size = Device::descriptorHeapProperties.imageDescriptorSize }, }; Device::vkWriteResourceDescriptorsEXT(Device::device, 6, resources, destinations); descriptorHeap.resourceHeap[0].FlushDevice(); descriptorHeap.resourceHeap[1].FlushDevice(); descriptorHeap.resourceHeap[2].FlushDevice(); window.descriptorHeap = &descriptorHeap; RTPass rtPass(&pipeline); window.passes.push_back(&rtPass); // NOTE: reading the acceleration structure through VK_EXT_descriptor_heap // aborts with VK_ERROR_DEVICE_LOST on NVIDIA 610.43.02 (a driver fault — // see #7). The engine transparently works around it: on the NVIDIA driver // VulkanShader rewrites the heap AS read into a TLAS-device-address + // OpConvertUToAccelerationStructureKHR path and RTPass feeds the address in // as push data. Nothing here (or in raygen.glsl) changes. See README.md // ("Native status") and interfaces/Crafter.Graphics-ShaderVulkan.cppm. window.Render(); window.StartSync(); } #else // DOM-mode port. Same scene (one triangle), software-emulated raytracing // via compute. Shaders are read from .wgsl files shipped as static // assets (see project.cpp). Renders barycentric colors via the // hit/miss/raygen mega-switch in PipelineRTWebGPU. int main() { Device::Initialize(); static Window window(1280, 720, "HelloVulkan"); auto cmd = window.StartInit(); DescriptorHeapWebGPU heap; heap.Initialize(/*images*/ 4, /*buffers*/ 4, /*samplers*/ 2); std::array shaders {{ WebGPUShader(std::filesystem::path("raygen.wgsl"), "raygen_main", WebGPURTStage::Raygen), WebGPUShader(std::filesystem::path("miss.wgsl"), "miss_main", WebGPURTStage::Miss), WebGPUShader(std::filesystem::path("closesthit.wgsl"), "closesthit_main", WebGPURTStage::ClosestHit), }}; ShaderBindingTableWebGPU sbt; sbt.Init(shaders); std::array raygenGroups {{ { .type = RTShaderGroupType::General, .generalShader = 0 }, }}; std::array missGroups {{ { .type = RTShaderGroupType::General, .generalShader = 1 }, }}; std::array hitGroups {{ { .type = RTShaderGroupType::TrianglesHitGroup, .closestHitShader = 2 }, }}; PipelineRTWebGPU pipeline; pipeline.Init(cmd, raygenGroups, missGroups, hitGroups, sbt); 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); static RenderingElement3D renderer; renderer.instance.transform.matrix[0][0] = 1; renderer.instance.transform.matrix[0][1] = 0; renderer.instance.transform.matrix[0][2] = 0; renderer.instance.transform.matrix[0][3] = 0; renderer.instance.transform.matrix[1][0] = 0; renderer.instance.transform.matrix[1][1] = 1; renderer.instance.transform.matrix[1][2] = 0; renderer.instance.transform.matrix[1][3] = 0; renderer.instance.transform.matrix[2][0] = 0; renderer.instance.transform.matrix[2][1] = 0; renderer.instance.transform.matrix[2][2] = 1; renderer.instance.transform.matrix[2][3] = 0; renderer.instance.instanceCustomIndex = 0; renderer.instance.mask = 0xFF; renderer.instance.instanceShaderBindingTableRecordOffset = 0; renderer.instance.flags = kRTGeometryInstanceForceOpaque; renderer.instance.accelerationStructureReference = triangleMesh.blasAddr; RenderingElement3D::Add(&renderer); RenderingElement3D::BuildTLAS(cmd, 0); window.descriptorHeap = &heap; window.FinishInit(); RTPass rtPass(&pipeline); window.passes.push_back(&rtPass); window.Render(); window.StartUpdate(); window.StartSync(); } #endif