pub struct RayTraceRenderer { /* private fields */ }Expand description
A reusable ray-trace surface driven by one fixed backend.
The renderer owns every resource its backend needs: the packed CPU
buffers, the GPU textures, buffers, program, pipeline, and bind
groups, and the output pixel buffer. They are created once — during
RayTraceRenderer::init, a resize,
or a scene update — and reused by every later
render. A steady-state frame
allocates nothing and repacks nothing.
The backend is explicit. There is no capability probe and no fallback: a WebGPU request on a browser without WebGPU returns an error instead of quietly drawing a Canvas 2D frame.
Every method returns JsValue. An Ok always means the frame was
submitted; a failure never degrades to JsValue::UNDEFINED, which
would make a dropped frame indistinguishable from a good one.
Every field is pub(crate) but is only ever touched through the
accessors the Data derive generates, so no consumer can hold a
second reference to an owned resource or write a size the renderer’s
own accounting does not know about.
Implementations§
Source§impl RayTraceRenderer
Implements construction, scene updates, rendering, resizing, and
teardown for RayTraceRenderer.
impl RayTraceRenderer
Implements construction, scene updates, rendering, resizing, and
teardown for RayTraceRenderer.
Only RayTraceRenderer::init is asynchronous, because it is the
only step that awaits a browser promise. Every other call is
synchronous, so a render loop drives the renderer without awaiting.
Every step that can fail validates everything it can before it mutates anything, and commits its own state change only after the step that can fail has succeeded. A rejected call therefore leaves the renderer exactly as it was, on the canvas as well as in memory.
Sourcepub async fn init(
canvas: HtmlCanvasElement,
backend: RayTraceBackend,
scene: &RayTraceScene,
) -> Result<Self, JsValue>
pub async fn init( canvas: HtmlCanvasElement, backend: RayTraceBackend, scene: &RayTraceScene, ) -> Result<Self, JsValue>
Creates a renderer bound to one explicitly requested backend.
The requested surface dimensions and the initial scene are both validated before any GPU resource is created, so an illegal input is rejected before a device, a pipeline, or two storage buffers are allocated and then thrown away.
The backend is never substituted. If the requested backend is
unavailable, if a shader fails to compile, or if the WebGPU
pipeline fails validation, this returns the driver’s own
diagnostic — awaiting the WebGPU compilation info and error
scopes, because WebGPU reports both asynchronously and a
catchJs wrapper around the synchronous calls would report
success for an invalid pipeline.
§Arguments
HtmlCanvasElement- The canvas to draw into.RayTraceBackend- The backend to drive, with no fallback.&RayTraceScene- The initial scene, packed and uploaded here.
§Returns
Result<Self, JsValue>- The ready renderer, or the reason it could not be created.
Sourcepub fn update_scene(&mut self, scene: &RayTraceScene) -> Result<(), JsValue>
pub fn update_scene(&mut self, scene: &RayTraceScene) -> Result<(), JsValue>
Replaces the scene, re-packing and re-uploading it exactly once.
The update is transactional. The new scene is packed into a buffer staged outside the renderer, then uploaded; only once the upload has succeeded is the renderer’s own scene mirror swapped in. A failed upload therefore leaves the previous scene both in the renderer and, because the adapter only rebinds a texture after the upload is accepted, still bound on the GPU. The staged block is the only allocation of the call.
§Arguments
&RayTraceScene- The new scene.
§Returns
Result<(), JsValue>-Okonce the new scene is live.
Sourcepub fn render(
&mut self,
camera: &Camera3D,
lights: &LightingUniforms,
settings: &RayTraceSettings,
) -> Result<(), JsValue>
pub fn render( &mut self, camera: &Camera3D, lights: &LightingUniforms, settings: &RayTraceSettings, ) -> Result<(), JsValue>
Traces one frame with the current scene at the given camera.
A steady-state frame reuses every buffer it already owns. The Canvas path moves the pixel buffer out, traces into it, and moves it back whether the trace succeeded or failed, so a rejected frame still leaves the buffer allocated for the next attempt. The GPU paths refill the packed frame through its existing capacity and issue one draw.
§Arguments
&Camera3D- The camera supplying the eye, target, up, and field of view.&LightingUniforms- The lights, ambient, and shading eye.&RayTraceSettings- The sampling grid and bounce limit.
§Returns
Result<(), JsValue>-Okonce the frame is submitted.
Sourcepub fn resize(&mut self, width: u32, height: u32) -> Result<(), JsValue>
pub fn resize(&mut self, width: u32, height: u32) -> Result<(), JsValue>
Resizes the surface, reallocating only what the new size needs.
The call is transactional in both directions. The requested size is validated first, then the adapter applies it, because the adapter is the only step that can fail for a reason the shared layer cannot check: a lost context or a lost device. Only once that step has succeeded are the renderer’s own size, the canvas backing store, and the CPU pixel buffer updated — so a rejected request leaves the canvas showing the previous, still valid, surface instead of one the renderer never adopted. The order within the commit does not matter, because nothing past the adapter can fail.
A zero, overflowing, or oversized request is rejected before any state is touched. A size the hardware cannot address is an error rather than a silent clamp.
§Arguments
u32- The new width in pixels.u32- The new height in pixels.
§Returns
Result<(), JsValue>-Okonce the new size is live.
Sourcepub fn dispose(&mut self)
pub fn dispose(&mut self)
Releases every resource the renderer owns, idempotently.
Calling this twice is safe: the second call finds the disposed flag already set and releases nothing. Cleanup also runs when the renderer is dropped, and the flag is set before the release so a renderer dropped right after an explicit dispose destroys nothing twice.