Skip to main content

RayTraceRenderer

Struct RayTraceRenderer 

Source
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.

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.

Source

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.
Source

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> - Ok once the new scene is live.
Source

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> - Ok once the frame is submitted.
Source

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> - Ok once the new size is live.
Source

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.

Trait Implementations§

Source§

impl Debug for RayTraceRenderer

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Drop for RayTraceRenderer

Source§

fn drop(&mut self)

Releases the backend resources the renderer owns.

Cleanup is idempotent: a renderer that was explicitly disposed releases nothing here, and one dropped without being disposed releases exactly what it still owns, once.

Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<S, T> Upcast<T> for S
where T: UpcastFrom<S> + ?Sized, S: ?Sized,

Source§

fn upcast(&self) -> &T
where Self: ErasableGeneric, T: Sized + ErasableGeneric<Repr = Self::Repr>,

Perform a zero-cost type-safe upcast to a wider ref type within the Wasm bindgen generics type system. Read more
Source§

fn upcast_into(self) -> T
where Self: Sized + ErasableGeneric, T: Sized + ErasableGeneric<Repr = Self::Repr>,

Perform a zero-cost type-safe upcast to a wider type within the Wasm bindgen generics type system. Read more