Skip to main content

WebGl2Backend

Struct WebGl2Backend 

Source
pub struct WebGl2Backend { /* private fields */ }
Expand description

The complete WebGL 2 backend: a context plus the three shadows that make a frame cheap.

§Performance

Three things are shadowed rather than re-queried. The fixed-function state is shadowed by a GlRenderState copy, so applying a state costs only the calls for fields that actually changed. The current texture unit is shadowed by a u32, so binding a texture to the unit that is already active costs no activeTexture at all. The current program is shadowed by a JsValue compared with Object.is, so rebinding the same program costs no useProgram. None of the three can be answered by asking the driver without a synchronous round trip, which is exactly why they are tracked here instead.

Implementations§

Source§

impl WebGl2Backend

Implements construction and lifecycle for the WebGL 2 backend.

Source

pub fn init(config: &RenderConfig) -> Result<WebGl2Backend, WebGl2InitError>

Builds a backend from a render configuration, resolving the canvas, scaling the backing store by the device pixel ratio, and acquiring the webgl2 context.

The shadow state is seeded with the values a freshly created GL context actually starts in rather than with all-zero placeholders, so the first WebGl2Backend::apply_state emits only the calls that genuinely differ from what the driver already set up.

§Arguments
  • &RenderConfig - The rendering configuration.
§Returns
  • Result<WebGl2Backend, WebGl2InitError> - The backend, or a typed error describing the specific failure.
Source

pub fn from_init(init: WebGl2BackendInit) -> Self

Builds a backend around an already-acquired context.

init is the only other constructor and it needs a live document: it queries the canvas by selector and asks for a webgl2 context. This one takes the handles directly, so a caller that already has a context (a test, or a canvas re-created after a context loss) does not have to go through DOM lookup. The shadow state is seeded with the values a freshly created GL context already holds, so the first apply_state emits only what genuinely differs.

§Arguments
  • WebGl2BackendInit - The canvas, context, and viewport.
§Returns
  • WebGl2Backend - The backend, with an empty readback buffer.
Source

pub fn is_available() -> bool

Reports whether the browser can create a WebGL 2 context at all.

Creates a throwaway off-DOM canvas and requests a webgl2 context. No shaders are compiled and nothing on the page is touched, so this is cheap enough to call as a capability probe before deciding which backend to construct.

§Returns
  • bool - true when a webgl2 context could be acquired.
Source

pub fn resize(&mut self, width: u32, height: u32)

Resizes the GL viewport to the given backing-store size and records it in the shadow state.

The call is issued to the driver, not merely folded into the shadow. The shadow is the engine’s record of what the driver already holds, so writing a value there without the matching gl.viewport makes the two disagree: WebGl2Backend::apply_state would diff against a viewport the driver never received and skip the call forever. That is not hypothetical — a caller that sets canvas.width and then calls resize (every demo loop does) left the driver viewport frozen at its init size while the drawing buffer grew, so the frame rendered into a sub-rect of the surface and the browser stretched that corner across the whole element.

Because the viewport is a per-frame-sized property and gl.viewport is a single cheap call, issuing it here costs nothing measurable and removes the “who re-asserts the viewport” question from every caller.

§Arguments
  • u32 - The new physical pixel width, already multiplied by the device pixel ratio.
  • u32 - The new physical pixel height.
Source

pub fn is_context_lost(&self) -> bool

Resizes the canvas backing store and re-asserts the GL viewport Reports whether the context has been lost, which happens when the browser reclaims the GPU: a tab backgrounded for long enough, a driver reset, a device change.

Worth checking once per frame. Every subsequent GL call against a lost context is a no-op that reports no error, so a renderer that does not check silently draws nothing with a clean console.

§Returns
  • bool - true when the context is lost and must be rebuilt.
Source§

impl WebGl2Backend

Implements the state-diffing apply and the frame-level entry points.

Every method here exists to make the per-frame cost proportional to what actually changed rather than to what was asked for.

Source

pub fn apply_state(&mut self, state: &GlRenderState)

Applies a whole GlRenderState, issuing a GL call only for each field that differs from the currently-bound state.

The diff is against a shadow copy of the last applied state, not against the driver, so no getParameter round trip is needed: the driver is known to agree with the shadow because the shadow is only ever updated after the calls that establish it. This is the single largest saving in the whole backend, since a batch of a thousand draws sharing one state pays for it once instead of for a thousand enable / depthFunc / blendFunc / cullFace / colorMask sequences, each of which the driver re-validates.

§Arguments
  • &GlRenderState - The state to make current.
Source

pub fn invalidate_state(&mut self, width: u32, height: u32)

Resets the shadow to the context’s own initial state, which forces the next apply to re-assert everything.

Needed after anything that can change GL state behind the backend’s back: a context restore, a debug extension, or a driver’s own reset. Without it the shadow would claim a state the driver no longer holds and every diffed call would be skipped.

§Arguments
  • u32 - The viewport width to seed the shadow with.
  • u32 - The viewport height to seed the shadow with.
Source

pub fn clear_depth(&self, context: &WebGl2RenderingContext)

Clears only the depth buffer, leaving color untouched.

Split out because a second pass that needs a fresh depth range without disturbing the color underneath is common in deferred and post-process work, and a full clear here would throw away results the pass is about to read.

§Arguments
  • &WebGl2RenderingContext - The context to clear through.
Source

pub fn render_frame( &mut self, context: &WebGl2RenderingContext, program: &GlProgram, color: Color, vertex_count: u32, )

Renders a complete frame: clears to color, binds program, and issues one triangle-list draw.

The one-call frame shape a demo loop needs, built from the same primitives the multi-pass API exposes. Geometry is generated inside the vertex shader from gl_VertexID, so there are no vertex buffers to bind; vertex_count is the number of vertices the shader is expected to emit.

§Arguments
  • &WebGl2RenderingContext - The context to draw through.
  • &GlProgram - The program to draw with.
  • Color - The color to clear to before drawing.
  • u32 - The number of vertices to draw.
Source§

impl WebGl2Backend

Implements every draw entry point, plus binding helpers and readback.

Source

pub fn bind_texture_unit( &mut self, context: &WebGl2RenderingContext, unit: u32, texture: &GlTexture, )

Binds a texture to a unit, issuing activeTexture only when the unit is not already current.

§Arguments
  • &WebGl2RenderingContext - The context to bind against.
  • u32 - The texture unit index, as passed to [gl_texture_unit].
  • &GlTexture - The texture to bind to that unit.
Source

pub fn draw_elements( &self, context: &WebGl2RenderingContext, topology: PrimitiveTopology, args: &DrawIndexedArgs, index_format: IndexFormat, ) -> bool

Draws args.index_count indices from the bound index buffer.

WebGL 2 has no baseVertex, the way WebGPU’s DrawIndexedArgs does: the element offset reaches the vertex fetch through the attribute pointers recorded in the vertex array object instead. base_vertex is therefore only meaningful as an assertion here, and a non-zero value is reported as false rather than silently ignored, because silently ignoring it would draw the wrong mesh with no diagnostic at all.

§Arguments
  • &WebGl2RenderingContext - The context to draw through.
  • PrimitiveTopology - How the vertices are assembled.
  • &DrawIndexedArgs - The counts and offsets to draw.
  • IndexFormat - The element width of the bound index buffer.
§Returns
  • bool - true when the draw was issued, false when base_vertex is non-zero and therefore cannot be honored.
Source

pub fn draw_element_range( &self, context: &WebGl2RenderingContext, topology: PrimitiveTopology, start: u32, end: u32, index_format: IndexFormat, ) -> bool

Draws a contiguous index range without disturbing the rest of the index buffer.

§Arguments
  • &WebGl2RenderingContext - The context to draw through.
  • PrimitiveTopology - How the vertices are assembled.
  • u32 - The first index to read.
  • u32 - The last index to read, inclusive.
  • IndexFormat - The element width of the bound index buffer.
§Returns
  • bool - true when the range was non-empty and was drawn.
Source

pub fn draw_arrays_instanced( &self, context: &WebGl2RenderingContext, topology: PrimitiveTopology, args: &DrawArgs, )

Draws an instanced vertex range, for geometry generated entirely on the GPU.

§Arguments
  • &WebGl2RenderingContext - The context to draw through.
  • PrimitiveTopology - How the vertices are assembled.
  • &DrawArgs - The counts and offsets to draw.
Source

pub fn draw_elements_instanced( &self, context: &WebGl2RenderingContext, topology: PrimitiveTopology, args: &DrawIndexedArgs, index_format: IndexFormat, ) -> bool

Draws an instanced index range, the form a mesh rendered many times per frame takes.

§Arguments
  • &WebGl2RenderingContext - The context to draw through.
  • PrimitiveTopology - How the vertices are assembled.
  • &DrawIndexedArgs - The counts and offsets to draw.
  • IndexFormat - The element width of the bound index buffer.
§Returns
  • bool - true when the draw was issued, false when base_vertex is non-zero and therefore cannot be honored.
Source

pub fn read_pixels( &mut self, context: &WebGl2RenderingContext, x: i32, y: i32, width: u32, height: u32, ) -> Vec<u8> ⓘ

Reads a rectangle of the bound framebuffer back into Rust memory.

The destination buffer is owned by the backend and reused across calls, so a steady-state readback, a picking query or a screenshot say, allocates nothing after the first time it runs at that size. The result is returned as an owned Vec: a caller that needs the bytes past the next readback keeps its own copy, which is one explicit clone rather than a borrow held across a driver call.

Reading from the default framebuffer is legal but slow on most drivers, because the contents may already have been discarded by the compositor; reading from a bound GlFramebuffer is the supported path.

§Arguments
  • &WebGl2RenderingContext - The context to read through.
  • i32 - The left edge in pixels.
  • i32 - The bottom edge in pixels.
  • u32 - The width in pixels.
  • u32 - The height in pixels.
§Returns
  • Vec<u8> - The tightly packed RGBA bytes, row-major from the bottom edge, or empty when the rectangle has no area.
Source§

impl WebGl2Backend

Source

pub fn get_canvas(&self) -> &HtmlCanvasElement

Source

pub fn get_mut_canvas(&mut self) -> &mut HtmlCanvasElement

Source

pub fn set_canvas(&mut self, val: HtmlCanvasElement) -> &mut Self

Source

pub fn get_context(&self) -> &WebGl2RenderingContext

Source

pub fn get_mut_context(&mut self) -> &mut WebGl2RenderingContext

Source

pub fn set_context(&mut self, val: WebGl2RenderingContext) -> &mut Self

Source

pub fn get_shadow(&self) -> &GlRenderState

Source

pub fn get_mut_shadow(&mut self) -> &mut GlRenderState

Source

pub fn set_shadow(&mut self, val: GlRenderState) -> &mut Self

Source

pub fn get_active_unit(&self) -> u32

Source

pub fn get_mut_active_unit(&mut self) -> &mut u32

Source

pub fn set_active_unit(&mut self, val: u32) -> &mut Self

Source

pub fn get_bound_program(&self) -> &JsValue

Source

pub fn get_mut_bound_program(&mut self) -> &mut JsValue

Source

pub fn set_bound_program(&mut self, val: JsValue) -> &mut Self

Source

pub fn get_clear_color_field(&self) -> Color

Source

pub fn get_mut_clear_color_field(&mut self) -> &mut Color

Source

pub fn set_clear_color_field(&mut self, val: Color) -> &mut Self

Source

pub fn get_readback(&self) -> &Vec<u8> ⓘ

Source

pub fn set_readback(&mut self, val: Vec<u8>) -> &mut Self

Trait Implementations§

Source§

impl Clone for WebGl2Backend

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for WebGl2Backend

Source§

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

Formats the value using the given formatter. 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> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. 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> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
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