wasm improvements
This commit is contained in:
parent
42a479572d
commit
6aa0338c0f
9 changed files with 603 additions and 70 deletions
|
|
@ -94,6 +94,16 @@ document.body.appendChild(canvas);
|
|||
// when set, the canvas is reparented into that element and sized to it.
|
||||
let mountEl = null;
|
||||
|
||||
// Upper bound on the canvas backing store, in pixels. Infinity until an RT
|
||||
// dispatch derives the real budget from the device's buffer limits (see
|
||||
// wgpuDispatchRT): the wavefront ray buffers scale with W·H·raysPerPixel,
|
||||
// and a 256 MiB maxBufferSize (Firefox's baseline) overflows at ~0.5 Mpx
|
||||
// for 4 rays/pixel — far below a HiDPI 16:9 mount — failing not at the
|
||||
// createBuffer call but as an uncapturable device OOM at submit. The
|
||||
// mounted canvas is CSS-pinned to width:100%/height:100%, so a clamped
|
||||
// backing store upscales on screen instead of shrinking.
|
||||
let maxCanvasPixels = Infinity;
|
||||
|
||||
function syncCanvasSize() {
|
||||
// Canvas pixel size = CSS size × devicePixelRatio so the GPU draws
|
||||
// at physical pixel resolution on HiDPI displays — otherwise the
|
||||
|
|
@ -117,8 +127,13 @@ function syncCanvasSize() {
|
|||
cssW = window.innerWidth;
|
||||
cssH = window.innerHeight;
|
||||
}
|
||||
const w = Math.max(1, Math.round(cssW * dpr));
|
||||
const h = Math.max(1, Math.round(cssH * dpr));
|
||||
let w = Math.max(1, Math.round(cssW * dpr));
|
||||
let h = Math.max(1, Math.round(cssH * dpr));
|
||||
if (w * h > maxCanvasPixels) {
|
||||
const s = Math.sqrt(maxCanvasPixels / (w * h));
|
||||
w = Math.max(1, Math.floor(w * s));
|
||||
h = Math.max(1, Math.floor(h * s));
|
||||
}
|
||||
if (canvas.width !== w) canvas.width = w;
|
||||
if (canvas.height !== h) canvas.height = h;
|
||||
return { w, h };
|
||||
|
|
@ -3511,6 +3526,28 @@ env.wgpuDispatchRT = (pipelineHandle, pushPtr, pushBytes,
|
|||
}
|
||||
const W = state.width, H = state.height;
|
||||
const depth = Math.max(1, maxDepth | 0);
|
||||
// Clamp the render resolution to what the wavefront buffers can hold.
|
||||
// The payload store is the largest per-ray cost (2 regions ×
|
||||
// WF_PAYLOAD_BYTES) and must fit both maxBufferSize and one storage
|
||||
// binding; the indirect TRACE/SHADE dispatch additionally bounds rays
|
||||
// at maxComputeWorkgroupsPerDimension×64. When the canvas is over
|
||||
// budget, tighten maxCanvasPixels and sit this frame out — the next
|
||||
// wgpuFrameBegin's ensureSized() shrinks the backing store (CSS keeps
|
||||
// the on-screen size) and rendering resumes within budget.
|
||||
const rpp = Math.max(1, raysPerPixel | 0);
|
||||
const rayBudget = Math.min(
|
||||
Math.floor(Math.min(device.limits.maxBufferSize,
|
||||
device.limits.maxStorageBufferBindingSize)
|
||||
/ (2 * WF_PAYLOAD_BYTES)),
|
||||
device.limits.maxComputeWorkgroupsPerDimension * 64);
|
||||
const pixelBudget = Math.max(1, Math.floor(rayBudget / rpp));
|
||||
if (pixelBudget < maxCanvasPixels) maxCanvasPixels = pixelBudget;
|
||||
if (W * H > maxCanvasPixels) {
|
||||
console.warn(`[crafter-wgpu] ${W}x${H} at ${rpp} rays/px overflows the `
|
||||
+ `wavefront budget (maxBufferSize ${device.limits.maxBufferSize}); `
|
||||
+ `reducing render resolution to ~${maxCanvasPixels}px`);
|
||||
return;
|
||||
}
|
||||
const wf = ensureWavefrontBuffers(W, H, raysPerPixel);
|
||||
const cap = wf.cap; // per-bounce ray capacity = raysPerPixel·W·H
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue