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.
impl WebGl2Backend
Implements construction and lifecycle for the WebGL 2 backend.
Sourcepub fn init(config: &RenderConfig) -> Result<WebGl2Backend, WebGl2InitError>
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.
Sourcepub fn is_available() -> bool
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-truewhen awebgl2context could be acquired.
Sourcepub fn resize(&mut self, width: u32, height: u32)
pub fn resize(&mut self, width: u32, height: u32)
Resizes the canvas backing store and re-points the shadow’s viewport at the new size.
The viewport is written into the shadow rather than issued
immediately, because a resize changes the canvas dimensions and
the viewport that was correct for the old ones must be
re-asserted against the new ones even if the caller’s own state
value did not change. Seeding the shadow makes the next
WebGl2Backend::apply_state emit it exactly once.
§Arguments
u32- The new physical pixel width, already multiplied by the device pixel ratio.u32- The new physical pixel height.
Sourcepub fn resize_now(&mut self, width: u32, height: u32)
pub fn resize_now(&mut self, width: u32, height: u32)
Resizes the canvas backing store and re-asserts the GL viewport
immediately, rather than deferring it to the next
WebGl2Backend::apply_state.
WebGl2Backend::resize is the cheaper call and is what a render
loop should use, because the viewport it seeds is emitted once by
the following state apply. This variant exists for the caller that
resizes the DOM canvas itself and needs the GL viewport correct
before the next paint, with no intervening apply.
§Arguments
u32- The new physical pixel width, already multiplied by the device pixel ratio.u32- The new physical pixel height.
Sourcepub fn is_context_lost(&self) -> bool
pub fn is_context_lost(&self) -> bool
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-truewhen the context is lost and must be rebuilt.
Source§impl WebGl2Backend
Implements the state-diffing apply and the frame-level entry points.
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.
Sourcepub fn apply_state(&mut self, state: &GlRenderState)
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.
Sourcepub fn invalidate_state(&mut self, width: u32, height: u32)
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.
Sourcepub fn set_clear_color(&mut self, color: Color)
pub fn set_clear_color(&mut self, color: Color)
Sets the color WebGl2Backend::begin_frame clears to.
§Arguments
Color- The clear color, with channels in0.0..=1.0.
Sourcepub fn begin_frame(
&mut self,
context: &WebGl2RenderingContext,
width: u32,
height: u32,
)
pub fn begin_frame( &mut self, context: &WebGl2RenderingContext, width: u32, height: u32, )
Clears the bound framebuffer and folds a full-size viewport into the shadow.
The clear is issued through clearColor plus clear rather than
clearBufferfv because the former is a two-call pair the driver
folds into a single tile-clear, while the latter is the WebGL 2
entry point that most drivers route through a slower generic
path. The viewport is written into the shadow as well, so a
caller that set a smaller viewport for a pass does not have it
silently left in place by the next frame.
§Arguments
&WebGl2RenderingContext- The context to clear through.u32- The width of the bound framebuffer, in pixels.u32- The height of the bound framebuffer, in pixels.
Sourcepub fn clear_depth(&self, context: &WebGl2RenderingContext)
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.
Sourcepub fn render_frame(
&mut self,
context: &WebGl2RenderingContext,
program: &GlProgram,
color: Color,
vertex_count: u32,
)
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.
impl WebGl2Backend
Implements every draw entry point, plus binding helpers and readback.
Sourcepub fn use_program(
&mut self,
context: &WebGl2RenderingContext,
program: &GlProgram,
)
pub fn use_program( &mut self, context: &WebGl2RenderingContext, program: &GlProgram, )
Binds a program, issuing useProgram only when it is not already
current.
The identity test is Object.is rather than a pointer compare,
because a WebGlProgram is a JS handle whose Rust address is a
stack slot a later handle may reuse; comparing addresses would let
two different programs compare equal and skip a needed rebind.
§Arguments
&WebGl2RenderingContext- The context to bind against.&GlProgram- The program to make current.
Sourcepub fn bind_texture_unit(
&mut self,
context: &WebGl2RenderingContext,
unit: u32,
texture: &GlTexture,
)
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.
Sourcepub fn draw_arrays(
&self,
context: &WebGl2RenderingContext,
topology: PrimitiveTopology,
args: &DrawArgs,
)
pub fn draw_arrays( &self, context: &WebGl2RenderingContext, topology: PrimitiveTopology, args: &DrawArgs, )
Draws args.vertex_count vertices from the bound vertex streams.
§Arguments
&WebGl2RenderingContext- The context to draw through.PrimitiveTopology- How the vertices are assembled.&DrawArgs- The counts and offsets to draw.
Sourcepub fn draw_elements(
&self,
context: &WebGl2RenderingContext,
topology: PrimitiveTopology,
args: &DrawIndexedArgs,
index_format: IndexFormat,
) -> bool
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-truewhen the draw was issued,falsewhenbase_vertexis non-zero and therefore cannot be honored.
Sourcepub fn draw_element_range(
&self,
context: &WebGl2RenderingContext,
topology: PrimitiveTopology,
start: u32,
end: u32,
index_format: IndexFormat,
) -> bool
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-truewhen the range was non-empty and was drawn.
Sourcepub fn draw_arrays_instanced(
&self,
context: &WebGl2RenderingContext,
topology: PrimitiveTopology,
args: &DrawArgs,
)
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.
Sourcepub fn draw_elements_instanced(
&self,
context: &WebGl2RenderingContext,
topology: PrimitiveTopology,
args: &DrawIndexedArgs,
index_format: IndexFormat,
) -> bool
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-truewhen the draw was issued,falsewhenbase_vertexis non-zero and therefore cannot be honored.
Sourcepub fn read_pixels(
&mut self,
context: &WebGl2RenderingContext,
x: i32,
y: i32,
width: u32,
height: u32,
) -> Vec<u8> ⓘ
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.