/* Crafter®.Graphics Copyright (C) 2026 Catcrafts® catcrafts.net This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License version 3.0 as published by the Free Software Foundation; This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ module; #ifndef CRAFTER_GRAPHICS_WINDOW_DOM #include "vulkan/vulkan.h" #endif // !CRAFTER_GRAPHICS_WINDOW_DOM export module Crafter.Graphics:RenderingElement3D; #ifndef CRAFTER_GRAPHICS_WINDOW_DOM import std; import :Mesh; import :VulkanBuffer; import Crafter.Math; import :Window; export namespace Crafter { struct TlasWithBuffer { VkDeviceAddress address = 0; VulkanBuffer buffer; VkAccelerationStructureKHR accelerationStructure = VK_NULL_HANDLE; VulkanBuffer instanceBuffer; VulkanBuffer scratchBuffer; // Parallel to instanceBuffer, indexed by TLAS instance ID. Filled // from each element's userMetadata during BuildTLAS. Consumers // (e.g. ray-query collision) bind this in the descriptor heap and // look up via rayQueryGetIntersectionInstanceIdEXT to recover // application-side per-instance data without touching the // Vulkan-mandated instanceCustomIndex (which renderers may already // use for their own encoding). VulkanBuffer metadataBuffer; // Last instance count this TLAS was built (not refit) for. When // elements.size() matches this, BuildTLAS does an in-place refit // (UPDATE mode) which is dramatically cheaper than a full rebuild // — refit walks the existing BVH and updates AABBs, while rebuild // reconstructs the topology from scratch. A change in count forces // a fresh rebuild because the AS is sized for that primitive count. std::uint32_t builtInstanceCount = 0; }; class RenderingElement3D { public: VkAccelerationStructureInstanceKHR instance; // Position in `elements`, maintained by Add/Remove for O(1) swap-and-pop. // Sentinel value = not currently registered. std::uint32_t indexInElements = std::numeric_limits::max(); // Application-defined per-instance tag, copied verbatim into // tlases[*].metadataBuffer at this element's TLAS instance ID // every BuildTLAS. Crafter doesn't interpret it. std::uint32_t userMetadata = 0; // When true, BuildTLAS skips copying instance.transform into the // TLAS instance buffer — the application's compute shader writes // the transform field directly into instanceBuffer at this // element's TLAS instance ID. Other instance fields (mask, // customIndex, SBT offset, BLAS reference) are still copied from // the CPU instance struct. // // Used to take per-frame transform updates off the CPU for bodies // whose transforms derive from GPU-side state (physics nodes that // already live on the GPU). bool transformOwnedByGpu = false; static std::vector elements; inline static TlasWithBuffer tlases[Window::numFrames]; static void BuildTLAS(VkCommandBuffer cmd, std::uint32_t index); // Register / unregister with `elements`. Use these instead of touching // the vector directly: linear find+erase is O(n) and pathological at // the body counts physics targets (millions of braces). static void Add(RenderingElement3D* e); static void Remove(RenderingElement3D* e); }; } #endif // !CRAFTER_GRAPHICS_WINDOW_DOM