webgpu triangle
This commit is contained in:
parent
64116cd980
commit
5553ded476
22 changed files with 2107 additions and 42 deletions
|
|
@ -60,3 +60,54 @@ export namespace Crafter {
|
|||
};
|
||||
}
|
||||
#endif // !CRAFTER_GRAPHICS_WINDOW_DOM
|
||||
|
||||
#ifdef CRAFTER_GRAPHICS_WINDOW_DOM
|
||||
import std;
|
||||
import Crafter.Math;
|
||||
import :WebGPU;
|
||||
|
||||
export namespace Crafter {
|
||||
// Software-RT BLAS node, packed to 32 bytes. Matches the WGSL
|
||||
// `BVHNode` struct in the RT WGSL prelude (additional/dom-webgpu.js,
|
||||
// rtWgslPrelude) byte-for-byte.
|
||||
//
|
||||
// primCount == 0 → inner node, children at indices
|
||||
// firstChildOrPrim and firstChildOrPrim+1.
|
||||
// primCount > 0 → leaf, `primCount` primitives starting at
|
||||
// primIndex `firstChildOrPrim` in the
|
||||
// global primRemap heap.
|
||||
//
|
||||
// SAH-built BVH2; constructed CPU-side at Build() time, never refit.
|
||||
struct BVHNode {
|
||||
float aabbMin[3];
|
||||
std::uint32_t firstChildOrPrim;
|
||||
float aabbMax[3];
|
||||
std::uint32_t primCount;
|
||||
};
|
||||
static_assert(sizeof(BVHNode) == 32);
|
||||
|
||||
class Mesh {
|
||||
public:
|
||||
// BLAS "handle": opaque identity that goes into
|
||||
// RTInstance::accelerationStructureReference. Set by Build() to a
|
||||
// stable u32 (widened to u64 for Vulkan-struct layout parity), used
|
||||
// by the WebGPU TLAS-build compute shader to look up the BLAS root
|
||||
// AABB and per-mesh heap offsets. Handle 0 is the unassigned
|
||||
// sentinel; never returned by Build().
|
||||
std::uint64_t blasAddr = 0;
|
||||
std::uint32_t triangleCount = 0;
|
||||
|
||||
bool opaque = true;
|
||||
|
||||
// Build BLAS from raw triangle data. Runs the CPU SAH BVH2 builder
|
||||
// and forwards vertex/index/BVH/remap arrays to the JS-side mesh
|
||||
// heap (additional/dom-webgpu.js), which queue.writeBuffers them
|
||||
// into the global heaps and records the per-mesh offsets keyed by
|
||||
// the returned handle. The `cmd` parameter is unused on WebGPU —
|
||||
// kept for API symmetry with the Vulkan signature.
|
||||
void Build(std::span<Crafter::Vector<float, 3, 3>> vertices,
|
||||
std::span<std::uint32_t> indices,
|
||||
WebGPUCommandEncoderRef cmd = 0);
|
||||
};
|
||||
}
|
||||
#endif // CRAFTER_GRAPHICS_WINDOW_DOM
|
||||
|
|
|
|||
51
interfaces/Crafter.Graphics-PipelineRTWebGPU.cppm
Normal file
51
interfaces/Crafter.Graphics-PipelineRTWebGPU.cppm
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
Crafter®.Graphics
|
||||
Copyright (C) 2026 Catcrafts®
|
||||
catcrafts.net
|
||||
*/
|
||||
|
||||
// DOM-mode RT pipeline. Mirrors PipelineRTVulkan's surface — Init takes
|
||||
// the same kind of (raygen, miss, hit) shader-group spans plus an SBT.
|
||||
// The big difference is implementation: there's no native RT pipeline on
|
||||
// WebGPU, so Init assembles a single megakernel WGSL by concatenating
|
||||
// 1. library prelude (types, bindings, ray-flag constants)
|
||||
// 2. user closesthit / anyhit / miss source files
|
||||
// 3. library mega-switches dispatched on per-hit hit-group index
|
||||
// 4. library helpers (rayAabb / rayTriangle / traverseBlas / traverseTlas)
|
||||
// 5. library traceRay function
|
||||
// 6. user raygen source files
|
||||
// 7. @compute entry calling the registered raygen
|
||||
// and hands the result to wgpuLoadRTPipeline.
|
||||
//
|
||||
// The library WGSL itself lives in additional/dom-webgpu.js (rtWgslPrelude
|
||||
// + rtWgslDispatchTemplate). C++ side only knows the substitution markers.
|
||||
|
||||
export module Crafter.Graphics:PipelineRTWebGPU;
|
||||
#ifdef CRAFTER_GRAPHICS_WINDOW_DOM
|
||||
import std;
|
||||
import :RT;
|
||||
import :WebGPU;
|
||||
import :ShaderBindingTableWebGPU;
|
||||
|
||||
export namespace Crafter {
|
||||
class PipelineRTWebGPU {
|
||||
public:
|
||||
std::uint32_t pipelineHandle = 0;
|
||||
|
||||
// Build the megakernel pipeline. Groups carry indices into
|
||||
// `sbt.shaders`. The library generates one `case` per registered
|
||||
// group: closest-hit groups dispatch to their closestHitShader's
|
||||
// entryFn, miss groups to their generalShader's entryFn, etc.
|
||||
// The `cmd` parameter is unused on WebGPU; kept for API symmetry.
|
||||
void Init(WebGPUCommandEncoderRef cmd,
|
||||
std::span<const RTShaderGroup> raygenGroups,
|
||||
std::span<const RTShaderGroup> missGroups,
|
||||
std::span<const RTShaderGroup> hitGroups,
|
||||
const ShaderBindingTableWebGPU& sbt);
|
||||
|
||||
PipelineRTWebGPU() = default;
|
||||
PipelineRTWebGPU(const PipelineRTWebGPU&) = delete;
|
||||
PipelineRTWebGPU& operator=(const PipelineRTWebGPU&) = delete;
|
||||
};
|
||||
}
|
||||
#endif // CRAFTER_GRAPHICS_WINDOW_DOM
|
||||
83
interfaces/Crafter.Graphics-RT.cppm
Normal file
83
interfaces/Crafter.Graphics-RT.cppm
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
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;
|
||||
*/
|
||||
|
||||
// Portable RT types & constants.
|
||||
//
|
||||
// Native: aliases the Vulkan struct so existing code that passes
|
||||
// `RenderingElement3D::instance` directly into vkCmdBuildAccelerationStructuresKHR
|
||||
// is a no-op layout-wise.
|
||||
// DOM: provides a POD with the same byte layout + the same field names, so
|
||||
// user code touching `instance.mask`, `instance.flags`, `instance.transform`
|
||||
// etc. compiles unchanged.
|
||||
//
|
||||
// Flag constants are spelled out as Crafter::kRT* so portable user code can
|
||||
// avoid referencing VK_* on the DOM target. The values match
|
||||
// VkGeometryInstanceFlagBitsKHR / VkRayTracingShaderGroupTypeKHR so the
|
||||
// constants compare-equal on Vulkan if the user wants to mix surfaces.
|
||||
|
||||
module;
|
||||
#ifndef CRAFTER_GRAPHICS_WINDOW_DOM
|
||||
#include "vulkan/vulkan.h"
|
||||
#endif
|
||||
export module Crafter.Graphics:RT;
|
||||
import std;
|
||||
|
||||
export namespace Crafter {
|
||||
#ifndef CRAFTER_GRAPHICS_WINDOW_DOM
|
||||
using RTTransformMatrix = VkTransformMatrixKHR;
|
||||
using RTInstance = VkAccelerationStructureInstanceKHR;
|
||||
#else
|
||||
// Mirrors VkTransformMatrixKHR: row-major affine 3x4.
|
||||
struct RTTransformMatrix {
|
||||
float matrix[3][4];
|
||||
};
|
||||
static_assert(sizeof(RTTransformMatrix) == 48);
|
||||
|
||||
// Mirrors VkAccelerationStructureInstanceKHR byte-for-byte.
|
||||
// On WebGPU the `accelerationStructureReference` slot holds the BLAS
|
||||
// handle returned by MeshWebGPU::blasHandle (a u32 widened to u64).
|
||||
struct RTInstance {
|
||||
RTTransformMatrix transform;
|
||||
std::uint32_t instanceCustomIndex : 24;
|
||||
std::uint32_t mask : 8;
|
||||
std::uint32_t instanceShaderBindingTableRecordOffset : 24;
|
||||
std::uint32_t flags : 8;
|
||||
std::uint64_t accelerationStructureReference;
|
||||
};
|
||||
static_assert(sizeof(RTInstance) == 64);
|
||||
#endif
|
||||
|
||||
// VkGeometryInstanceFlagBitsKHR mirror. Values verbatim so equal on both.
|
||||
inline constexpr std::uint8_t kRTGeometryInstanceTriangleFacingCullDisable = 0x1;
|
||||
inline constexpr std::uint8_t kRTGeometryInstanceTriangleFlipFacing = 0x2;
|
||||
inline constexpr std::uint8_t kRTGeometryInstanceForceOpaque = 0x4;
|
||||
inline constexpr std::uint8_t kRTGeometryInstanceForceNoOpaque = 0x8;
|
||||
|
||||
// Hit-group identification. Matches VkRayTracingShaderGroupTypeKHR for
|
||||
// the two types we actually support (general + triangles-hit).
|
||||
enum class RTShaderGroupType : std::uint8_t {
|
||||
General = 0, // raygen / miss / callable
|
||||
TrianglesHitGroup = 1,
|
||||
};
|
||||
|
||||
// Cross-backend description of one entry in the shader-group array
|
||||
// passed to PipelineRT::Init. Mirrors the meaningful subset of
|
||||
// VkRayTracingShaderGroupCreateInfoKHR: per group, the type and the
|
||||
// indices (into the SBT's shader array) for general / closestHit /
|
||||
// anyHit, with kRTShaderUnused == VK_SHADER_UNUSED_KHR for "none".
|
||||
inline constexpr std::uint32_t kRTShaderUnused = 0xFFFFFFFFu;
|
||||
|
||||
struct RTShaderGroup {
|
||||
RTShaderGroupType type = RTShaderGroupType::General;
|
||||
std::uint32_t generalShader = kRTShaderUnused;
|
||||
std::uint32_t closestHitShader = kRTShaderUnused;
|
||||
std::uint32_t anyHitShader = kRTShaderUnused;
|
||||
};
|
||||
}
|
||||
|
|
@ -46,3 +46,42 @@ export namespace Crafter {
|
|||
};
|
||||
}
|
||||
#endif // !CRAFTER_GRAPHICS_WINDOW_DOM
|
||||
|
||||
#ifdef CRAFTER_GRAPHICS_WINDOW_DOM
|
||||
import std;
|
||||
import :RenderPass;
|
||||
import :Window;
|
||||
import :WebGPU;
|
||||
import :PipelineRTWebGPU;
|
||||
import :RenderingElement3D;
|
||||
|
||||
export namespace Crafter {
|
||||
// DOM-mode RT pass — dispatches the megakernel pipeline at frame Record
|
||||
// time. Picks up the current TLAS for the frame and the application's
|
||||
// raygen-side push data (typically empty in v1; pass via window.passes
|
||||
// wiring if needed later).
|
||||
struct RTPass : RenderPass {
|
||||
PipelineRTWebGPU* pipeline;
|
||||
// Optional per-dispatch push data forwarded after the standard
|
||||
// RTDispatchHeader. Null means "no extra data".
|
||||
const void* pushPtr = nullptr;
|
||||
std::uint32_t pushBytes = 0;
|
||||
|
||||
RTPass(PipelineRTWebGPU* p) : pipeline(p) {}
|
||||
|
||||
void Record(WebGPUCommandEncoderRef /*cmd*/, std::uint32_t frameIdx, Window& window) override {
|
||||
const std::uint32_t gx = (window.width + 7u) / 8u;
|
||||
const std::uint32_t gy = (window.height + 7u) / 8u;
|
||||
auto& tlas = RenderingElement3D::tlases[frameIdx];
|
||||
WebGPU::wgpuDispatchRT(
|
||||
pipeline->pipelineHandle,
|
||||
pushPtr,
|
||||
static_cast<std::int32_t>(pushBytes),
|
||||
tlas.buffer.handle,
|
||||
static_cast<std::int32_t>(tlas.builtInstanceCount),
|
||||
static_cast<std::int32_t>(gx),
|
||||
static_cast<std::int32_t>(gy));
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif // CRAFTER_GRAPHICS_WINDOW_DOM
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ module;
|
|||
#include "vulkan/vulkan.h"
|
||||
#endif // !CRAFTER_GRAPHICS_WINDOW_DOM
|
||||
export module Crafter.Graphics:RenderingElement3D;
|
||||
import :RT;
|
||||
#ifndef CRAFTER_GRAPHICS_WINDOW_DOM
|
||||
import std;
|
||||
import :Mesh;
|
||||
|
|
@ -55,7 +56,7 @@ export namespace Crafter {
|
|||
|
||||
class RenderingElement3D {
|
||||
public:
|
||||
VkAccelerationStructureInstanceKHR instance;
|
||||
RTInstance 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<std::uint32_t>::max();
|
||||
|
|
@ -87,3 +88,63 @@ export namespace Crafter {
|
|||
};
|
||||
}
|
||||
#endif // !CRAFTER_GRAPHICS_WINDOW_DOM
|
||||
|
||||
#ifdef CRAFTER_GRAPHICS_WINDOW_DOM
|
||||
import std;
|
||||
import :Mesh;
|
||||
import :WebGPU;
|
||||
import :WebGPUBuffer;
|
||||
import :Window;
|
||||
|
||||
export namespace Crafter {
|
||||
// Per-frame TLAS storage. WebGPU has no real swapchain frame count
|
||||
// (Window::numFrames = 1 on DOM), so this is effectively a singleton —
|
||||
// the array form is kept for API symmetry with the Vulkan side so user
|
||||
// code that indexes `tlases[frameIdx]` ports unchanged.
|
||||
struct TlasWithBuffer {
|
||||
// Host-visible instance buffer holding RTInstance entries — same
|
||||
// layout as Vulkan's VkAccelerationStructureInstanceKHR, so user
|
||||
// code touching .instance.mask / .flags / .transform.matrix is
|
||||
// identical across backends. Also bound as a storage SSBO so
|
||||
// application compute shaders (e.g. physics-tlas-transform.comp.wgsl)
|
||||
// can write the .transform field directly when
|
||||
// RenderingElement3D::transformOwnedByGpu is set.
|
||||
WebGPUBuffer<RTInstance, true> instanceBuffer;
|
||||
// Per-instance application metadata; parallel to instanceBuffer,
|
||||
// identical semantics to the Vulkan-side counterpart.
|
||||
WebGPUBuffer<std::uint32_t, true> metadataBuffer;
|
||||
// GPU-built TLAS data: one TLASEntry per instance, written each
|
||||
// BuildTLAS by a compute pass on the JS bridge. Read by traceRay /
|
||||
// rayQuery as `@group(1) @binding(0) tlas: array<TLASEntry>`.
|
||||
// TLASEntry layout: 96 bytes — aabbMin (12) + maskHGoffset (4) +
|
||||
// aabbMax (12) + blasHandle (4) + invTransform 3x4 mat (48) +
|
||||
// customIndex (4) + _pad (12). Defined in the WGSL traversal
|
||||
// library; never directly read by C++.
|
||||
WebGPUBuffer<char, false> buffer;
|
||||
|
||||
std::uint32_t builtInstanceCount = 0;
|
||||
};
|
||||
|
||||
class RenderingElement3D {
|
||||
public:
|
||||
RTInstance instance{};
|
||||
std::uint32_t indexInElements = std::numeric_limits<std::uint32_t>::max();
|
||||
std::uint32_t userMetadata = 0;
|
||||
// Application compute shader writes the transform field of this
|
||||
// element's instanceBuffer slot directly — BuildTLAS preserves it.
|
||||
bool transformOwnedByGpu = false;
|
||||
|
||||
static std::vector<RenderingElement3D*> elements;
|
||||
inline static TlasWithBuffer tlases[Window::numFrames];
|
||||
|
||||
// Repopulate the TLAS for frame `index`. WebGPU path always does
|
||||
// a fresh build (no refit) — the GPU build pass is cheap at the
|
||||
// ~10–100 instance counts the design targets; LBVH-for-TLAS is a
|
||||
// future optimization for larger scenes.
|
||||
static void BuildTLAS(WebGPUCommandEncoderRef cmd, std::uint32_t index);
|
||||
|
||||
static void Add(RenderingElement3D* e);
|
||||
static void Remove(RenderingElement3D* e);
|
||||
};
|
||||
}
|
||||
#endif // CRAFTER_GRAPHICS_WINDOW_DOM
|
||||
|
|
|
|||
64
interfaces/Crafter.Graphics-ShaderBindingTableWebGPU.cppm
Normal file
64
interfaces/Crafter.Graphics-ShaderBindingTableWebGPU.cppm
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
Crafter®.Graphics
|
||||
Copyright (C) 2026 Catcrafts®
|
||||
catcrafts.net
|
||||
*/
|
||||
|
||||
// DOM-mode shader-binding-table analog. Stores raw WGSL source strings
|
||||
// plus an explicit entry-function name per shader. PipelineRTWebGPU::Init
|
||||
// concatenates these into the megakernel WGSL at pipeline-build time.
|
||||
|
||||
export module Crafter.Graphics:ShaderBindingTableWebGPU;
|
||||
#ifdef CRAFTER_GRAPHICS_WINDOW_DOM
|
||||
import std;
|
||||
|
||||
export namespace Crafter {
|
||||
enum class WebGPURTStage : std::uint8_t {
|
||||
Raygen = 0,
|
||||
Miss = 1,
|
||||
ClosestHit = 2,
|
||||
AnyHit = 3,
|
||||
};
|
||||
|
||||
// One WGSL shader source + the function name PipelineRTWebGPU should
|
||||
// call from the megakernel switch. The source may declare any helper
|
||||
// functions and (in exactly one raygen file) the `Payload` struct.
|
||||
//
|
||||
// Required signatures inside `source` for `entryFn`:
|
||||
// Raygen: fn <entryFn>(gid: vec3<u32>)
|
||||
// Miss: fn <entryFn>(ray: RayDesc, payload: ptr<function, Payload>)
|
||||
// ClosestHit: fn <entryFn>(ray: RayDesc, hit: HitInfo, payload: ptr<function, Payload>)
|
||||
// AnyHit: fn <entryFn>(ray: RayDesc, hit: HitInfo, payload: ptr<function, Payload>) -> u32
|
||||
// returns RT_ANYHIT_ACCEPT / RT_ANYHIT_IGNORE / RT_ANYHIT_END_SEARCH.
|
||||
//
|
||||
// `RayDesc`, `HitInfo`, the `RT_*` flag/return constants, the `tlas` /
|
||||
// BLAS / mesh-record bindings, and the `traceRay` function are all
|
||||
// injected by the library prelude — see the rtWgslPrelude block in
|
||||
// additional/dom-webgpu.js.
|
||||
struct WebGPUShader {
|
||||
std::string source;
|
||||
std::string entryFn;
|
||||
WebGPURTStage stage = WebGPURTStage::Raygen;
|
||||
|
||||
WebGPUShader() = default;
|
||||
WebGPUShader(std::string src, std::string fn, WebGPURTStage s)
|
||||
: source(std::move(src)), entryFn(std::move(fn)), stage(s) {}
|
||||
|
||||
// Construct from a WGSL source file path. Reads via the WASI VFS
|
||||
// so apps shipping their shaders as static files (see the
|
||||
// `cfg.files.emplace_back("raygen.wgsl")` pattern in
|
||||
// examples/VulkanTriangle/project.cpp) get them at runtime.
|
||||
WebGPUShader(const std::filesystem::path& wgslPath,
|
||||
std::string fn,
|
||||
WebGPURTStage s);
|
||||
};
|
||||
|
||||
class ShaderBindingTableWebGPU {
|
||||
public:
|
||||
std::vector<WebGPUShader> shaders;
|
||||
void Init(std::span<const WebGPUShader> shaders_) {
|
||||
shaders.assign(shaders_.begin(), shaders_.end());
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif // CRAFTER_GRAPHICS_WINDOW_DOM
|
||||
|
|
@ -73,13 +73,62 @@ namespace Crafter::WebGPU {
|
|||
std::uint32_t atlasHandle, std::uint32_t sampHandle);
|
||||
|
||||
// ─── custom user-authored compute shaders ───────────────────────────
|
||||
// rayQueryFlag = 1 swaps group(1) from the UI ping-pong pair to the RT
|
||||
// data heaps (TLAS, BVH, meshRecs, verts, idx, primRemap, outImage) and
|
||||
// prepends a WGSL prelude exposing the rayQuery* API. Shaders that set
|
||||
// this MUST NOT declare their own @group(1) bindings.
|
||||
__attribute__((import_module("env"), import_name("wgpuLoadCustomShader")))
|
||||
extern "C" std::uint32_t wgpuLoadCustomShader(const void* wgslPtr, std::int32_t wgslLen,
|
||||
const void* bindingsPtr, std::int32_t bindingsCount);
|
||||
const void* bindingsPtr, std::int32_t bindingsCount,
|
||||
std::int32_t rayQueryFlag);
|
||||
__attribute__((import_module("env"), import_name("wgpuDispatchCustom")))
|
||||
extern "C" void wgpuDispatchCustom(std::uint32_t pipelineHandle,
|
||||
const void* pushPtr, std::int32_t pushBytes,
|
||||
const void* handlesPtr, std::int32_t handlesCount,
|
||||
std::int32_t gx, std::int32_t gy, std::int32_t gz);
|
||||
|
||||
// ─── software raytracing ───────────────────────────────────────────
|
||||
//
|
||||
// Mesh::Build forwards vertex / index / BVH-node / primRemap arrays
|
||||
// to the JS bridge, which queue.writeBuffers them into the global
|
||||
// RT mesh heaps (growing if needed) and records the per-mesh offsets
|
||||
// under a freshly-allocated u32 handle. The handle is what user code
|
||||
// stores in RTInstance::accelerationStructureReference; the WebGPU
|
||||
// TLAS-build compute shader resolves it back to root AABB + heap
|
||||
// offsets at dispatch time. Returns 0 on failure.
|
||||
__attribute__((import_module("env"), import_name("wgpuRegisterMeshBLAS")))
|
||||
extern "C" std::uint32_t wgpuRegisterMeshBLAS(
|
||||
float minX, float minY, float minZ,
|
||||
float maxX, float maxY, float maxZ,
|
||||
const void* verticesPtr, std::int32_t vertexCount,
|
||||
const void* indicesPtr, std::int32_t indexCount,
|
||||
const void* bvhNodesPtr, std::int32_t bvhNodeCount,
|
||||
const void* primRemapPtr, std::int32_t primRemapCount);
|
||||
|
||||
// RT pipeline build. The library composes WGSL by concatenating the
|
||||
// traversal library, generated hit-group switches, and the user-
|
||||
// supplied raygen / miss / closesthit / anyhit bodies. Returns an
|
||||
// opaque pipeline handle.
|
||||
__attribute__((import_module("env"), import_name("wgpuLoadRTPipeline")))
|
||||
extern "C" std::uint32_t wgpuLoadRTPipeline(const void* wgslPtr, std::int32_t wgslLen);
|
||||
|
||||
// Dispatch a TraceRays-equivalent pass: the RT pipeline is dispatched
|
||||
// over a (gx, gy) tile grid; the library writes the push data (camera,
|
||||
// payload, etc. — opaque) into a uniform ring buffer, attaches the TLAS
|
||||
// + global mesh heap, and runs one workgroup per 8x8 screen tile.
|
||||
__attribute__((import_module("env"), import_name("wgpuDispatchRT")))
|
||||
extern "C" void wgpuDispatchRT(std::uint32_t pipelineHandle,
|
||||
const void* pushPtr, std::int32_t pushBytes,
|
||||
std::uint32_t tlasBufHandle,
|
||||
std::int32_t instanceCount,
|
||||
std::int32_t gx, std::int32_t gy);
|
||||
|
||||
// GPU TLAS-build dispatch. Reads the instance buffer (host-uploaded or
|
||||
// GPU-written), produces per-instance world-space AABBs + per-instance
|
||||
// transform matrices in a flat tlasBuf SSBO consumed by traceRay / rayQuery.
|
||||
__attribute__((import_module("env"), import_name("wgpuBuildTLAS")))
|
||||
extern "C" void wgpuBuildTLAS(std::uint32_t instanceBufHandle,
|
||||
std::int32_t instanceCount,
|
||||
std::uint32_t tlasOutBufHandle);
|
||||
}
|
||||
#endif // CRAFTER_GRAPHICS_WINDOW_DOM
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ export namespace Crafter {
|
|||
class WebGPUComputeShader {
|
||||
public:
|
||||
std::uint32_t pipelineHandle = 0;
|
||||
bool rayQueryCapable = false;
|
||||
std::vector<UICustomBinding> customBindings;
|
||||
|
||||
WebGPUComputeShader() = default;
|
||||
|
|
@ -56,22 +57,28 @@ export namespace Crafter {
|
|||
WebGPUComputeShader& operator=(const WebGPUComputeShader&) = delete;
|
||||
WebGPUComputeShader(WebGPUComputeShader&& o) noexcept
|
||||
: pipelineHandle(o.pipelineHandle),
|
||||
rayQueryCapable(o.rayQueryCapable),
|
||||
customBindings(std::move(o.customBindings)) {
|
||||
o.pipelineHandle = 0;
|
||||
}
|
||||
|
||||
// Compile + link a custom compute shader. `wgsl` is the source
|
||||
// string; the library does NOT add anything to it — the user's
|
||||
// shader must declare @group(0)/@group(1) bindings matching the
|
||||
// contract above. `bindings` lists every additional resource
|
||||
// (groups 2+) that the renderer should bind at dispatch time.
|
||||
// string; the library does NOT add anything to it (except when
|
||||
// `rayQuery` is true — then a RT prelude exposing the rayQuery*
|
||||
// API is prepended). The user's shader must declare
|
||||
// @group(0)/@group(1) bindings matching the contract above
|
||||
// (rayQuery shaders MUST NOT redeclare group(1)).
|
||||
// `bindings` lists every additional resource (groups 2+) that the
|
||||
// renderer should bind at dispatch time.
|
||||
void Load(std::string_view wgsl,
|
||||
std::span<const UICustomBinding> bindings = {});
|
||||
std::span<const UICustomBinding> bindings = {},
|
||||
bool rayQuery = false);
|
||||
|
||||
// Path-based overload for symmetry with the Vulkan ComputeShader.
|
||||
// Reads the file from disk (browser VFS) and forwards to Load(wgsl).
|
||||
void Load(const std::filesystem::path& wgslPath,
|
||||
std::span<const UICustomBinding> bindings = {});
|
||||
std::span<const UICustomBinding> bindings = {},
|
||||
bool rayQuery = false);
|
||||
};
|
||||
}
|
||||
#endif // CRAFTER_GRAPHICS_WINDOW_DOM
|
||||
|
|
|
|||
|
|
@ -58,6 +58,10 @@ export import :UIComponents;
|
|||
export import :InputField;
|
||||
export import :Decompress;
|
||||
|
||||
// Portable RT type aliases (provided on both targets — uses Vulkan
|
||||
// structs natively, plain PODs of the same layout on DOM).
|
||||
export import :RT;
|
||||
|
||||
// DOM-only partitions — empty under native.
|
||||
export import :Dom;
|
||||
export import :DomEvents;
|
||||
|
|
@ -66,3 +70,5 @@ export import :WebGPU;
|
|||
export import :WebGPUBuffer;
|
||||
export import :DescriptorHeapWebGPU;
|
||||
export import :WebGPUComputeShader;
|
||||
export import :ShaderBindingTableWebGPU;
|
||||
export import :PipelineRTWebGPU;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue