2026-05-18 04:58:52 +02:00
|
|
|
|
/*
|
|
|
|
|
|
Crafter®.Graphics
|
|
|
|
|
|
Copyright (C) 2026 Catcrafts®
|
|
|
|
|
|
catcrafts.net
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
// JS bridge declarations for the DOM-mode WebGPU backend. Each function
|
|
|
|
|
|
// corresponds to one entry in `additional/dom-webgpu.js`. Handles are
|
|
|
|
|
|
// opaque uint32 cookies into the JS-side handle tables.
|
|
|
|
|
|
|
|
|
|
|
|
export module Crafter.Graphics:WebGPU;
|
|
|
|
|
|
#ifdef CRAFTER_GRAPHICS_WINDOW_DOM
|
|
|
|
|
|
import std;
|
|
|
|
|
|
|
|
|
|
|
|
export namespace Crafter {
|
|
|
|
|
|
using WebGPUBufferRef = std::uint32_t;
|
|
|
|
|
|
using WebGPUTextureRef = std::uint32_t;
|
|
|
|
|
|
using WebGPUSamplerRef = std::uint32_t;
|
|
|
|
|
|
using WebGPUCommandEncoderRef = std::uint32_t; // unused as a real handle; just a marker type for portability
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
namespace Crafter::WebGPU {
|
|
|
|
|
|
__attribute__((import_module("env"), import_name("wgpuGetCanvasWidth")))
|
|
|
|
|
|
extern "C" std::int32_t wgpuGetCanvasWidth();
|
|
|
|
|
|
__attribute__((import_module("env"), import_name("wgpuGetCanvasHeight")))
|
|
|
|
|
|
extern "C" std::int32_t wgpuGetCanvasHeight();
|
|
|
|
|
|
__attribute__((import_module("env"), import_name("wgpuSurfaceWidth")))
|
|
|
|
|
|
extern "C" std::int32_t wgpuSurfaceWidth();
|
|
|
|
|
|
__attribute__((import_module("env"), import_name("wgpuSurfaceHeight")))
|
|
|
|
|
|
extern "C" std::int32_t wgpuSurfaceHeight();
|
|
|
|
|
|
__attribute__((import_module("env"), import_name("wgpuInit")))
|
|
|
|
|
|
extern "C" void wgpuInit();
|
|
|
|
|
|
|
2026-07-19 01:38:25 +02:00
|
|
|
|
// Reparent the render canvas into a host DOM element so a scene renders
|
|
|
|
|
|
// inline inside the app's own layout rather than as a full-page layer.
|
|
|
|
|
|
// `idPtr`/`idLen` is a UTF-8 string naming an element id; an empty id
|
|
|
|
|
|
// detaches the canvas back to <body> and hides it. Implemented in
|
|
|
|
|
|
// additional/dom-webgpu.js. Prefer the SetCanvasMount() wrapper below.
|
|
|
|
|
|
__attribute__((import_module("env"), import_name("wgpuSetCanvasMount")))
|
|
|
|
|
|
extern "C" void wgpuSetCanvasMount(const void* idPtr, std::int32_t idLen);
|
|
|
|
|
|
|
|
|
|
|
|
// Mount the render canvas into the DOM element with id `elementId`
|
|
|
|
|
|
// (the render surface is sized to that element each frame). Pass an
|
|
|
|
|
|
// empty string to detach and hide the canvas, leaving a plain DOM page.
|
|
|
|
|
|
// Safe to call any time after the module has started — e.g. from a
|
|
|
|
|
|
// route handler once the target element exists in the DOM.
|
|
|
|
|
|
export inline void SetCanvasMount(std::string_view elementId) {
|
|
|
|
|
|
wgpuSetCanvasMount(elementId.data(), static_cast<std::int32_t>(elementId.size()));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-18 04:58:52 +02:00
|
|
|
|
__attribute__((import_module("env"), import_name("wgpuCreateBuffer")))
|
|
|
|
|
|
extern "C" std::uint32_t wgpuCreateBuffer(std::int32_t byteSize);
|
|
|
|
|
|
__attribute__((import_module("env"), import_name("wgpuWriteBuffer")))
|
|
|
|
|
|
extern "C" void wgpuWriteBuffer(std::uint32_t handle, const void* srcPtr, std::int32_t byteSize);
|
2026-05-24 13:32:08 +02:00
|
|
|
|
__attribute__((import_module("env"), import_name("wgpuWriteBufferRange")))
|
|
|
|
|
|
extern "C" void wgpuWriteBufferRange(std::uint32_t handle,
|
|
|
|
|
|
std::uint32_t dstByteOffset,
|
|
|
|
|
|
const void* srcPtr,
|
|
|
|
|
|
std::int32_t byteSize);
|
|
|
|
|
|
// Kick off a GPU→CPU readback for the entire `byteSize`-byte prefix
|
|
|
|
|
|
// of the buffer at `handle`. Returns immediately; the actual map
|
|
|
|
|
|
// resolves asynchronously. Successive Enqueues without a Poll in
|
|
|
|
|
|
// between are no-ops until the previous map resolves.
|
|
|
|
|
|
//
|
|
|
|
|
|
// `resetBytes` ≥ 0 — if non-zero, the JS bridge encodes a
|
|
|
|
|
|
// clearBuffer over the first `resetBytes` bytes of the source
|
|
|
|
|
|
// buffer immediately after the copy, in the same command encoder.
|
|
|
|
|
|
// Used by Forts3D's GPU event queues to zero the atomic-add count
|
|
|
|
|
|
// for the next frame's substeps. The reset is TIED to a successful
|
|
|
|
|
|
// enqueue: if the enqueue was skipped (previous map still pending),
|
|
|
|
|
|
// the reset is skipped too — so events written by substeps during
|
|
|
|
|
|
// the missed-drain window accumulate into the next successful
|
|
|
|
|
|
// capture instead of being silently wiped.
|
|
|
|
|
|
__attribute__((import_module("env"), import_name("wgpuReadbackEnqueue")))
|
|
|
|
|
|
extern "C" void wgpuReadbackEnqueue(std::uint32_t handle,
|
|
|
|
|
|
std::int32_t byteSize,
|
|
|
|
|
|
std::int32_t resetBytes);
|
|
|
|
|
|
// Poll a previously-enqueued readback. Returns 1 and writes the
|
|
|
|
|
|
// bytes into `dstPtr` if the map resolved; returns 0 otherwise.
|
|
|
|
|
|
__attribute__((import_module("env"), import_name("wgpuReadbackPoll")))
|
|
|
|
|
|
extern "C" std::int32_t wgpuReadbackPoll(std::uint32_t handle, void* dstPtr, std::int32_t byteSize);
|
|
|
|
|
|
// Non-consuming readiness probe. Returns 1 if the readback has
|
|
|
|
|
|
// resolved and the next Poll would succeed; returns 0 otherwise.
|
|
|
|
|
|
// Used to gate multi-buffer drains (header + array) so neither side
|
|
|
|
|
|
// gets consumed until both are ready — otherwise the consumed side's
|
|
|
|
|
|
// data is lost while the other side waits for its map to resolve.
|
|
|
|
|
|
__attribute__((import_module("env"), import_name("wgpuReadbackReady")))
|
|
|
|
|
|
extern "C" std::int32_t wgpuReadbackReady(std::uint32_t handle);
|
2026-05-18 04:58:52 +02:00
|
|
|
|
__attribute__((import_module("env"), import_name("wgpuDestroyBuffer")))
|
|
|
|
|
|
extern "C" void wgpuDestroyBuffer(std::uint32_t handle);
|
|
|
|
|
|
|
|
|
|
|
|
__attribute__((import_module("env"), import_name("wgpuCreateAtlasTexture")))
|
|
|
|
|
|
extern "C" std::uint32_t wgpuCreateAtlasTexture(std::int32_t w, std::int32_t h);
|
|
|
|
|
|
__attribute__((import_module("env"), import_name("wgpuWriteAtlasRegion")))
|
|
|
|
|
|
extern "C" void wgpuWriteAtlasRegion(std::uint32_t handle, const void* srcPtr,
|
|
|
|
|
|
std::int32_t srcW, std::int32_t srcH,
|
|
|
|
|
|
std::int32_t srcBytesPerRow,
|
|
|
|
|
|
std::int32_t dstX, std::int32_t dstY,
|
|
|
|
|
|
std::int32_t copyW, std::int32_t copyH);
|
|
|
|
|
|
__attribute__((import_module("env"), import_name("wgpuDestroyTexture")))
|
|
|
|
|
|
extern "C" void wgpuDestroyTexture(std::uint32_t handle);
|
|
|
|
|
|
|
2026-05-19 00:27:09 +02:00
|
|
|
|
// General-purpose rgba8unorm 2D texture for material albedo etc.
|
|
|
|
|
|
// Separate from the atlas path because atlas uses r8unorm + sub-region
|
|
|
|
|
|
// writes; this one takes the whole image in one shot.
|
|
|
|
|
|
__attribute__((import_module("env"), import_name("wgpuCreateImage2D")))
|
|
|
|
|
|
extern "C" std::uint32_t wgpuCreateImage2D(std::int32_t w, std::int32_t h);
|
|
|
|
|
|
__attribute__((import_module("env"), import_name("wgpuWriteImage2D")))
|
|
|
|
|
|
extern "C" void wgpuWriteImage2D(std::uint32_t handle, const void* srcPtr,
|
|
|
|
|
|
std::int32_t byteSize,
|
|
|
|
|
|
std::int32_t w, std::int32_t h);
|
|
|
|
|
|
|
|
|
|
|
|
// 2D texture array — `layerCount` rgba8unorm layers of identical (w × h).
|
|
|
|
|
|
// Sampled via `texture_2d_array<f32>` in WGSL (UICustomBindingKind 3).
|
|
|
|
|
|
// Used by Image2DArray<RGBA8> to stack per-material albedos for one
|
|
|
|
|
|
// multi-material scene.
|
|
|
|
|
|
__attribute__((import_module("env"), import_name("wgpuCreateImage2DArray")))
|
2026-05-24 13:32:08 +02:00
|
|
|
|
extern "C" std::uint32_t wgpuCreateImage2DArray(std::int32_t w, std::int32_t h,
|
|
|
|
|
|
std::int32_t layerCount, std::int32_t mipLevels);
|
|
|
|
|
|
// Upload a single mip level for one array layer. `level` indexes into
|
|
|
|
|
|
// the texture's mip chain (0 = base); `w` / `h` must be the dimensions
|
|
|
|
|
|
// at that level. Callers pass each level's pixels separately — mip
|
|
|
|
|
|
// generation is host-side.
|
2026-05-19 00:27:09 +02:00
|
|
|
|
__attribute__((import_module("env"), import_name("wgpuWriteImage2DLayer")))
|
2026-05-24 13:32:08 +02:00
|
|
|
|
extern "C" void wgpuWriteImage2DLayer(std::uint32_t handle, std::int32_t layer, std::int32_t level,
|
2026-05-19 00:27:09 +02:00
|
|
|
|
const void* srcPtr, std::int32_t byteSize,
|
|
|
|
|
|
std::int32_t w, std::int32_t h);
|
|
|
|
|
|
|
2026-06-09 12:55:14 +00:00
|
|
|
|
// Runtime storage texture — STORAGE_BINDING | TEXTURE_BINDING usage,
|
|
|
|
|
|
// caller-chosen format (`format` is the WebGPUTexelFormat enum, e.g.
|
|
|
|
|
|
// 1 = rgba16float). Unlike wgpuCreateImage2D this needs no
|
|
|
|
|
|
// CompressedTextureAsset upload: the content is produced on the GPU
|
|
|
|
|
|
// (e.g. an HDR post-process target a compute pass writes via a
|
|
|
|
|
|
// StorageTexture binding and later samples via SampledTexture). Backs
|
|
|
|
|
|
// StorageImage2D<T> in :Image2D.
|
|
|
|
|
|
__attribute__((import_module("env"), import_name("wgpuCreateStorageImage2D")))
|
|
|
|
|
|
extern "C" std::uint32_t wgpuCreateStorageImage2D(std::int32_t w, std::int32_t h,
|
|
|
|
|
|
std::int32_t format);
|
|
|
|
|
|
|
2026-05-18 04:58:52 +02:00
|
|
|
|
__attribute__((import_module("env"), import_name("wgpuCreateLinearClampSampler")))
|
|
|
|
|
|
extern "C" std::uint32_t wgpuCreateLinearClampSampler();
|
|
|
|
|
|
|
2026-05-24 13:32:08 +02:00
|
|
|
|
// Linear-filtered, repeat-addressed sampler with mipmap linear-filter.
|
|
|
|
|
|
// The usual choice for tiled material textures (woodBrace, panel, etc.)
|
|
|
|
|
|
// which expect UV > 1.0 to wrap.
|
|
|
|
|
|
__attribute__((import_module("env"), import_name("wgpuCreateLinearRepeatSampler")))
|
|
|
|
|
|
extern "C" std::uint32_t wgpuCreateLinearRepeatSampler();
|
|
|
|
|
|
|
2026-05-18 04:58:52 +02:00
|
|
|
|
__attribute__((import_module("env"), import_name("wgpuFrameBegin")))
|
|
|
|
|
|
extern "C" void wgpuFrameBegin();
|
|
|
|
|
|
__attribute__((import_module("env"), import_name("wgpuFrameEnd")))
|
|
|
|
|
|
extern "C" void wgpuFrameEnd();
|
|
|
|
|
|
|
|
|
|
|
|
__attribute__((import_module("env"), import_name("wgpuDispatchQuads")))
|
|
|
|
|
|
extern "C" void wgpuDispatchQuads(std::uint32_t itemsHandle, const void* headerPtr,
|
|
|
|
|
|
std::int32_t gx, std::int32_t gy);
|
|
|
|
|
|
__attribute__((import_module("env"), import_name("wgpuDispatchCircles")))
|
|
|
|
|
|
extern "C" void wgpuDispatchCircles(std::uint32_t itemsHandle, const void* headerPtr,
|
|
|
|
|
|
std::int32_t gx, std::int32_t gy);
|
|
|
|
|
|
__attribute__((import_module("env"), import_name("wgpuDispatchImages")))
|
|
|
|
|
|
extern "C" void wgpuDispatchImages(std::uint32_t itemsHandle, const void* headerPtr,
|
|
|
|
|
|
std::int32_t gx, std::int32_t gy,
|
|
|
|
|
|
std::uint32_t texHandle, std::uint32_t sampHandle);
|
|
|
|
|
|
__attribute__((import_module("env"), import_name("wgpuDispatchText")))
|
|
|
|
|
|
extern "C" void wgpuDispatchText(std::uint32_t itemsHandle, const void* headerPtr,
|
|
|
|
|
|
std::int32_t gx, std::int32_t gy,
|
|
|
|
|
|
std::uint32_t atlasHandle, std::uint32_t sampHandle);
|
2026-05-18 05:39:17 +02:00
|
|
|
|
|
|
|
|
|
|
// ─── custom user-authored compute shaders ───────────────────────────
|
2026-05-18 18:43:30 +02:00
|
|
|
|
// 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.
|
2026-05-18 05:39:17 +02:00
|
|
|
|
__attribute__((import_module("env"), import_name("wgpuLoadCustomShader")))
|
|
|
|
|
|
extern "C" std::uint32_t wgpuLoadCustomShader(const void* wgslPtr, std::int32_t wgslLen,
|
2026-05-18 18:43:30 +02:00
|
|
|
|
const void* bindingsPtr, std::int32_t bindingsCount,
|
|
|
|
|
|
std::int32_t rayQueryFlag);
|
2026-05-18 05:39:17 +02:00
|
|
|
|
__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);
|
2026-05-18 18:43:30 +02:00
|
|
|
|
|
|
|
|
|
|
// ─── 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.
|
2026-05-19 00:27:09 +02:00
|
|
|
|
// The optional `attribsPtr` / `attribsByteCount` carry per-vertex
|
|
|
|
|
|
// attribute payload (normals, UVs, etc. — layout is example-defined)
|
|
|
|
|
|
// that gets appended to a global attribs heap and exposed to RT
|
|
|
|
|
|
// closest-hit shaders as `vertexAttribs : array<u32>` at
|
|
|
|
|
|
// @group(1) @binding(7). Pass (nullptr, 0) for positions-only meshes.
|
2026-06-02 22:09:14 +00:00
|
|
|
|
// `geomType` selects the primitive kind: 0 = triangles (the
|
|
|
|
|
|
// verticesPtr/indicesPtr streams), 1 = AABBs (VK_GEOMETRY_TYPE_AABBS) —
|
|
|
|
|
|
// then verticesPtr holds 2 vec3 per primitive [min, max], indexCount is
|
|
|
|
|
|
// 0, and an intersection shader supplies the hit. `opaqueFlag` is the
|
|
|
|
|
|
// geometry's opaque bit (0 lets any-hit run). `primCount` is the
|
|
|
|
|
|
// triangle / AABB primitive count.
|
2026-05-18 18:43:30 +02:00
|
|
|
|
__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,
|
2026-05-19 00:27:09 +02:00
|
|
|
|
const void* primRemapPtr, std::int32_t primRemapCount,
|
2026-06-02 22:09:14 +00:00
|
|
|
|
const void* attribsPtr, std::int32_t attribsByteCount,
|
|
|
|
|
|
std::int32_t geomType, std::int32_t opaqueFlag, std::int32_t primCount);
|
2026-05-18 18:43:30 +02:00
|
|
|
|
|
2026-06-16 14:12:04 +00:00
|
|
|
|
// Zero-copy procedural BLAS registration: the AABB build input already
|
|
|
|
|
|
// lives in an existing device buffer (`aabbBufferHandle`, a GPUBuffer a
|
|
|
|
|
|
// compute pass wrote) rather than a wasm host pointer. The bridge
|
|
|
|
|
|
// copyBufferToBuffer's `count` boxes (24 bytes each, [min,max] vec3 — the
|
|
|
|
|
|
// RTAabb / VkAabbPositionsKHR layout) straight into the vertices heap,
|
|
|
|
|
|
// never round-tripping them through wasm memory. With no host copy of the
|
|
|
|
|
|
// boxes there is nothing to run the SAH builder over, so the BLAS gets a
|
|
|
|
|
|
// single root leaf spanning all `count` primitives bounded by the
|
|
|
|
|
|
// caller-supplied object-space box (min/max) — the traversal then linearly
|
|
|
|
|
|
// intersects every box. `opaqueFlag` is the geometry opaque bit. Returns
|
|
|
|
|
|
// the mesh handle (0 on failure), same contract as wgpuRegisterMeshBLAS.
|
|
|
|
|
|
__attribute__((import_module("env"), import_name("wgpuRegisterMeshBLASDeviceAabbs")))
|
|
|
|
|
|
extern "C" std::uint32_t wgpuRegisterMeshBLASDeviceAabbs(
|
|
|
|
|
|
WebGPUBufferRef aabbBufferHandle, std::int32_t count,
|
|
|
|
|
|
float minX, float minY, float minZ,
|
|
|
|
|
|
float maxX, float maxY, float maxZ,
|
|
|
|
|
|
std::int32_t opaqueFlag);
|
|
|
|
|
|
|
|
|
|
|
|
// Zero-copy procedural BLAS refit: re-copy `count` boxes from the device
|
|
|
|
|
|
// buffer into the existing mesh's vertices-heap region (count unchanged)
|
|
|
|
|
|
// and update the root leaf bounds, preserving the mesh handle so
|
|
|
|
|
|
// RTInstance::accelerationStructureReference stays valid. The device
|
|
|
|
|
|
// counterpart of Mesh::RefitProcedural.
|
|
|
|
|
|
__attribute__((import_module("env"), import_name("wgpuRefitMeshBLASDeviceAabbs")))
|
|
|
|
|
|
extern "C" void wgpuRefitMeshBLASDeviceAabbs(
|
|
|
|
|
|
std::uint32_t meshHandle,
|
|
|
|
|
|
WebGPUBufferRef aabbBufferHandle, std::int32_t count,
|
|
|
|
|
|
float minX, float minY, float minZ,
|
|
|
|
|
|
float maxX, float maxY, float maxZ);
|
|
|
|
|
|
|
2026-05-18 18:43:30 +02:00
|
|
|
|
// RT pipeline build. The library composes WGSL by concatenating the
|
|
|
|
|
|
// traversal library, generated hit-group switches, and the user-
|
2026-05-19 00:27:09 +02:00
|
|
|
|
// supplied raygen / miss / closesthit / anyhit bodies. `bindings` is
|
|
|
|
|
|
// UICustomBinding-shaped (8 bytes each) declaring extra @group(2)+
|
|
|
|
|
|
// resources the user's closest-hit / miss / raygen WGSL references.
|
|
|
|
|
|
// Pass (nullptr, 0) for a pipeline with no user-declared bindings.
|
2026-06-09 12:55:14 +00:00
|
|
|
|
// `hdrOutputFormat` (0 = none) makes the RESOLVE stage write the linear
|
|
|
|
|
|
// accumulator into a user-supplied storage texture of that
|
|
|
|
|
|
// WebGPUTexelFormat (e.g. 1 = rgba16float) instead of the rgba8unorm
|
|
|
|
|
|
// canvas ping-pong — the entry point for an HDR post-process chain. The
|
|
|
|
|
|
// matching output texture handle is passed to wgpuDispatchRT.
|
2026-05-19 00:27:09 +02:00
|
|
|
|
// Returns an opaque pipeline handle.
|
2026-05-18 18:43:30 +02:00
|
|
|
|
__attribute__((import_module("env"), import_name("wgpuLoadRTPipeline")))
|
2026-05-19 00:27:09 +02:00
|
|
|
|
extern "C" std::uint32_t wgpuLoadRTPipeline(const void* wgslPtr, std::int32_t wgslLen,
|
2026-06-09 12:55:14 +00:00
|
|
|
|
const void* bindingsPtr, std::int32_t bindingsCount,
|
|
|
|
|
|
std::int32_t hdrOutputFormat);
|
2026-05-18 18:43:30 +02:00
|
|
|
|
|
|
|
|
|
|
// 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.
|
2026-05-19 00:27:09 +02:00
|
|
|
|
// `handles[]` carries resolved WebGPU resource handles for every user
|
|
|
|
|
|
// binding declared at pipeline-load time, in the same order. Pass
|
|
|
|
|
|
// (nullptr, 0) for a pipeline with no user bindings.
|
2026-06-09 12:55:14 +00:00
|
|
|
|
// `outTexHandle` is the destination texture for an HDR-output pipeline
|
|
|
|
|
|
// (one loaded with hdrOutputFormat != 0); ignored (pass 0) for the
|
|
|
|
|
|
// default canvas path.
|
2026-06-09 22:45:25 +00:00
|
|
|
|
// `raysPerPixel` scales the wavefront ray/hit/payload buffers to
|
|
|
|
|
|
// raysPerPixel·W·H rays per bounce, so closest-hit can emit up to that
|
|
|
|
|
|
// many rays per pixel within one bounce (e.g. one shadow ray per light)
|
|
|
|
|
|
// without rtEmitRay dropping past capacity. 1 = the historical
|
|
|
|
|
|
// single-ray-per-pixel footprint.
|
2026-05-18 18:43:30 +02:00
|
|
|
|
__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,
|
2026-05-19 00:27:09 +02:00
|
|
|
|
std::int32_t gx, std::int32_t gy,
|
2026-05-31 16:24:41 +00:00
|
|
|
|
const void* handlesPtr, std::int32_t handlesCount,
|
2026-06-09 12:55:14 +00:00
|
|
|
|
std::int32_t maxDepth,
|
2026-06-09 22:45:25 +00:00
|
|
|
|
std::uint32_t outTexHandle,
|
|
|
|
|
|
std::int32_t raysPerPixel);
|
2026-05-18 18:43:30 +02:00
|
|
|
|
|
2026-05-24 13:32:08 +02:00
|
|
|
|
// GPU TLAS-build dispatch. Two sequential compute passes:
|
|
|
|
|
|
// 1. tlasBuildMain — per-instance world AABB + identity permutation
|
|
|
|
|
|
// + naive Morton (overwritten in pass 2). Outputs the flat
|
|
|
|
|
|
// tlasBuf SSBO consumed by traceRay / rayQuery.
|
|
|
|
|
|
// 2. lbvhBuildMain — single workgroup of 1024 threads; reduces
|
|
|
|
|
|
// scene AABB, recomputes Morton with proper normalization,
|
|
|
|
|
|
// bitonic-sorts (morton, instance_id), writes the sorted
|
|
|
|
|
|
// permutation into `entryOrderBufHandle`, and refits a
|
|
|
|
|
|
// sweep-tree BVH into `bvhNodesBufHandle` bottom-up.
|
|
|
|
|
|
// Pre-LBVH bin-build is gone; `binsBufHandle` is kept in the
|
|
|
|
|
|
// signature as a placeholder so the C++ side doesn't churn.
|
2026-05-18 18:43:30 +02:00
|
|
|
|
__attribute__((import_module("env"), import_name("wgpuBuildTLAS")))
|
|
|
|
|
|
extern "C" void wgpuBuildTLAS(std::uint32_t instanceBufHandle,
|
|
|
|
|
|
std::int32_t instanceCount,
|
2026-05-24 13:32:08 +02:00
|
|
|
|
std::uint32_t tlasOutBufHandle,
|
|
|
|
|
|
std::uint32_t entryOrderBufHandle,
|
|
|
|
|
|
std::uint32_t mortonBufHandle,
|
|
|
|
|
|
std::uint32_t binsBufHandle,
|
|
|
|
|
|
std::uint32_t bvhNodesBufHandle,
|
|
|
|
|
|
std::uint32_t sortTempABufHandle,
|
|
|
|
|
|
std::uint32_t sortTempBBufHandle);
|
|
|
|
|
|
|
|
|
|
|
|
// ── Standalone compute pipelines ───────────────────────────────────
|
|
|
|
|
|
//
|
|
|
|
|
|
// Mirror of the native ComputeShader API: load a user-authored
|
|
|
|
|
|
// compute WGSL with arbitrary @group bindings, dispatch it at any
|
|
|
|
|
|
// point in the frame (inside or outside the UI compute pass —
|
|
|
|
|
|
// physics ticks dispatch from update lambdas, which fire outside
|
|
|
|
|
|
// the per-frame render encoder).
|
|
|
|
|
|
//
|
|
|
|
|
|
// WGSL contract:
|
|
|
|
|
|
// @group(0) @binding(0) — uniform PushData (optional; only if
|
|
|
|
|
|
// pushUniformSize > 0 at load).
|
|
|
|
|
|
// @group(1+) @binding(N) — user bindings declared via
|
|
|
|
|
|
// UICustomBinding[]. When rayQuery is
|
|
|
|
|
|
// on, @group(1) is reserved for the RT
|
|
|
|
|
|
// heap and user bindings start at
|
|
|
|
|
|
// @group(2).
|
|
|
|
|
|
__attribute__((import_module("env"), import_name("wgpuLoadComputePipeline")))
|
|
|
|
|
|
extern "C" std::uint32_t wgpuLoadComputePipeline(
|
|
|
|
|
|
const void* wgslPtr, std::int32_t wgslLen,
|
|
|
|
|
|
std::int32_t pushUniformSize,
|
|
|
|
|
|
const void* bindingsPtr, std::int32_t bindingsCount,
|
|
|
|
|
|
std::int32_t rayQueryFlag);
|
|
|
|
|
|
|
|
|
|
|
|
__attribute__((import_module("env"), import_name("wgpuDispatchCompute")))
|
|
|
|
|
|
extern "C" void wgpuDispatchCompute(
|
|
|
|
|
|
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);
|
2026-05-18 04:58:52 +02:00
|
|
|
|
}
|
|
|
|
|
|
#endif // CRAFTER_GRAPHICS_WINDOW_DOM
|