use glow::HasContext; use parking_lot::{Mutex, RwLock}; use wasm_bindgen::{JsCast, JsValue};
usesuper::TextureFormatDesc;
/// A wrapper around a [`glow::Context`] to provide a fake `lock()` api that makes it compatible /// with the `AdapterContext` API from the EGL implementation. pubstruct AdapterContext { pub glow_context: glow::Context, pub webgl2_context: web_sys::WebGl2RenderingContext,
}
/// Obtain a lock to the EGL context and get handle to the [`glow::Context`] that can be used to /// do rendering. #[track_caller] pubfn lock(&self) -> &glow::Context {
&self.glow_context
}
}
pubfn create_surface_from_offscreen_canvas(
&self,
canvas: web_sys::OffscreenCanvas,
) -> Result<Surface, crate::InstanceError> { let result =
canvas.get_context_with_context_options("webgl2", &Self::create_context_options()); self.create_surface_from_context(Canvas::Offscreen(canvas), result)
}
/// Common portion of public `create_surface_from_*` functions. /// /// Note: Analogous code also exists in the WebGPU backend at /// `wgpu::backend::web::Context`. fn create_surface_from_context(
&self,
canvas: Canvas,
context_result: Result<Option<js_sys::Object>, JsValue>,
) -> Result<Surface, crate::InstanceError> { let context_object: js_sys::Object = match context_result {
Ok(Some(context)) => context,
Ok(None) => { // <https://html.spec.whatwg.org/multipage/canvas.html#dom-canvas-getcontext-dev> // A getContext() call “returns null if contextId is not supported, or if the // canvas has already been initialized with another context type”. Additionally, // “not supported” could include “insufficient GPU resources” or “the GPU process // previously crashed”. So, we must return it as an `Err` since it could occur // for circumstances outside the application author's control. return Err(crate::InstanceError::new(String::from(concat!( "canvas.getContext() returned null; ", "webgl2 not available or canvas already in use"
))));
}
Err(js_error) => { // <https://html.spec.whatwg.org/multipage/canvas.html#dom-canvas-getcontext> // A thrown exception indicates misuse of the canvas state. return Err(crate::InstanceError::new(format!( "canvas.getContext() threw exception {js_error:?}",
)));
}
};
// Not returning this error because it is a type error that shouldn't happen unless // the browser, JS builtin objects, or wasm bindings are misbehaving somehow. let webgl2_context: web_sys::WebGl2RenderingContext = context_object
.dyn_into()
.expect("canvas context is not a WebGl2RenderingContext");
unsafefn create_surface(
&self,
_display_handle: raw_window_handle::RawDisplayHandle,
window_handle: raw_window_handle::RawWindowHandle,
) -> Result<Surface, crate::InstanceError> { let canvas: web_sys::HtmlCanvasElement = match window_handle {
raw_window_handle::RawWindowHandle::Web(handle) => web_sys::window()
.and_then(|win| win.document())
.expect("Cannot get document")
.query_selector(&format!("canvas[data-raw-handle=\"{}\"]", handle.id))
.expect("Cannot query for canvas")
.expect("Canvas is not found")
.dyn_into()
.expect("Failed to downcast to canvas type"),
raw_window_handle::RawWindowHandle::WebCanvas(handle) => { let value: &JsValue = unsafe { handle.obj.cast().as_ref() };
value.clone().unchecked_into()
}
raw_window_handle::RawWindowHandle::WebOffscreenCanvas(handle) => { let value: &JsValue = unsafe { handle.obj.cast().as_ref() }; let canvas: web_sys::OffscreenCanvas = value.clone().unchecked_into();
returnself.create_surface_from_offscreen_canvas(canvas);
}
_ => { return Err(crate::InstanceError::new(format!( "window handle {window_handle:?} is not a web handle"
)))
}
};
impl Surface { pub(super) unsafefn present(
&self,
_suf_texture: super::Texture,
context: &AdapterContext,
) -> Result<(), crate::SurfaceError> { let gl = &context.glow_context; let swapchain = self.swapchain.read(); let swapchain = swapchain.as_ref().ok_or(crate::SurfaceError::Other( "need to configure surface before presenting",
))?;
if swapchain.format.is_srgb() { // Important to set the viewport since we don't know in what state the user left it. unsafe {
gl.viewport( 0, 0,
swapchain.extent.width as _,
swapchain.extent.height as _,
)
}; unsafe { gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, None) }; unsafe { gl.bind_sampler(0, None) }; unsafe { gl.active_texture(glow::TEXTURE0) }; unsafe { gl.bind_texture(glow::TEXTURE_2D, *self.texture.lock()) }; unsafe { gl.use_program(*self.srgb_present_program.lock()) }; unsafe { gl.disable(glow::DEPTH_TEST) }; unsafe { gl.disable(glow::STENCIL_TEST) }; unsafe { gl.disable(glow::SCISSOR_TEST) }; unsafe { gl.disable(glow::BLEND) }; unsafe { gl.disable(glow::CULL_FACE) }; unsafe { gl.draw_buffers(&[glow::BACK]) }; unsafe { gl.draw_arrays(glow::TRIANGLES, 0, 3) };
} else { unsafe { gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(swapchain.framebuffer)) }; unsafe { gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, None) }; // Note the Y-flipping here. GL's presentation is not flipped, // but main rendering is. Therefore, we Y-flip the output positions // in the shader, and also this blit. unsafe {
gl.blit_framebuffer( 0,
swapchain.extent.height as i32,
swapchain.extent.width as i32, 0, 0, 0,
swapchain.extent.width as i32,
swapchain.extent.height as i32,
glow::COLOR_BUFFER_BIT,
glow::NEAREST,
)
};
}
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.15Bemerkung:
(vorverarbeitet am 2026-06-18)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.