webgpu triangle

This commit is contained in:
Jorijn van der Graaf 2026-05-18 18:43:30 +02:00
commit 5553ded476
22 changed files with 2107 additions and 42 deletions

View file

@ -0,0 +1,91 @@
/*
Crafter®.Graphics
Copyright (C) 2026 Catcrafts®
catcrafts.net
*/
// DOM-mode TLAS upkeep. BuildTLAS copies the per-element RTInstance into
// the host-visible instance buffer (skipping the transform for elements
// whose transform is GPU-owned), uploads it, then dispatches the JS-side
// TLAS-build compute pass — which consults the per-BLAS records published
// at Mesh::Build() time to produce world-space AABBs and inverse
// transforms in the format `traceRay` / `rayQuery` consume.
module;
module Crafter.Graphics:RenderingElement3D_implWebGPU;
import :RenderingElement3D;
import :Mesh;
import :WebGPU;
import :WebGPUBuffer;
import std;
using namespace Crafter;
std::vector<RenderingElement3D*> RenderingElement3D::elements;
void RenderingElement3D::Add(RenderingElement3D* e) {
e->indexInElements = static_cast<std::uint32_t>(elements.size());
elements.push_back(e);
}
void RenderingElement3D::Remove(RenderingElement3D* e) {
std::uint32_t idx = e->indexInElements;
if (idx == std::numeric_limits<std::uint32_t>::max()) return;
std::uint32_t last = static_cast<std::uint32_t>(elements.size() - 1);
if (idx != last) {
elements[idx] = elements[last];
elements[idx]->indexInElements = idx;
}
elements.pop_back();
e->indexInElements = std::numeric_limits<std::uint32_t>::max();
}
void RenderingElement3D::BuildTLAS(WebGPUCommandEncoderRef /*cmd*/, std::uint32_t index) {
auto& tlas = tlases[index];
const std::uint32_t primitiveCount = static_cast<std::uint32_t>(elements.size());
if (primitiveCount == 0) {
tlas.builtInstanceCount = 0;
return;
}
// (Re)allocate instance + metadata + output TLAS buffers if the count
// changed. WebGPUBuffer::Resize destroys and recreates the GPU buffer;
// bind-group caches keyed on the buffer handle are invalidated in the
// JS bridge automatically.
if (primitiveCount != tlas.builtInstanceCount) {
tlas.instanceBuffer.Resize(primitiveCount);
tlas.metadataBuffer.Resize(primitiveCount);
// TLASEntry layout in WGSL is 144 bytes due to vec3 align/pad
// rules. Must match the struct declared in the rtWgslTypes
// block in additional/dom-webgpu.js.
tlas.buffer.Resize(primitiveCount * 144);
}
for (std::uint32_t i = 0; i < primitiveCount; ++i) {
auto& dst = tlas.instanceBuffer.value[i];
const auto& src = elements[i]->instance;
if (elements[i]->transformOwnedByGpu) {
// Preserve whatever the GPU compute shader most recently
// wrote into dst.transform. Update only the non-transform
// fields.
dst.instanceCustomIndex = src.instanceCustomIndex;
dst.mask = src.mask;
dst.instanceShaderBindingTableRecordOffset = src.instanceShaderBindingTableRecordOffset;
dst.flags = src.flags;
dst.accelerationStructureReference = src.accelerationStructureReference;
} else {
dst = src;
}
tlas.metadataBuffer.value[i] = elements[i]->userMetadata;
}
tlas.instanceBuffer.FlushDevice();
tlas.metadataBuffer.FlushDevice();
WebGPU::wgpuBuildTLAS(tlas.instanceBuffer.handle,
static_cast<std::int32_t>(primitiveCount),
tlas.buffer.handle);
tlas.builtInstanceCount = primitiveCount;
}