diff options
author | Josh Matthews <josh@joshmatthews.net> | 2025-01-06 13:37:35 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-01-06 18:37:35 +0000 |
commit | c43762faea97c24e6135f426fbde8224f261abf6 (patch) | |
tree | 94fdd8834416cc47a0d5676c9a50e56ea4b70d50 /components/script | |
parent | 2575a0daf15a5bee3daed5190909c25c0382b85b (diff) | |
download | servo-c43762faea97c24e6135f426fbde8224f261abf6.tar.gz servo-c43762faea97c24e6135f426fbde8224f261abf6.zip |
Add initial support for WebGL 2 BlitFramebuffer (#26389)
Add initial support for the WebGL2 BlitFramebuffer call.
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: Istvan <istvan.miklos@h-lab.eu>
Diffstat (limited to 'components/script')
-rw-r--r-- | components/script/dom/webgl2renderingcontext.rs | 102 | ||||
-rw-r--r-- | components/script/dom/webglframebuffer.rs | 19 | ||||
-rw-r--r-- | components/script/dom/webidls/WebGL2RenderingContext.webidl | 4 |
3 files changed, 123 insertions, 2 deletions
diff --git a/components/script/dom/webgl2renderingcontext.rs b/components/script/dom/webgl2renderingcontext.rs index a38a974a166..5041a82b25d 100644 --- a/components/script/dom/webgl2renderingcontext.rs +++ b/components/script/dom/webgl2renderingcontext.rs @@ -7,6 +7,7 @@ use std::cmp; use std::ptr::{self, NonNull}; use std::rc::Rc; +use bitflags::bitflags; use canvas_traits::webgl::WebGLError::*; use canvas_traits::webgl::{ webgl_channel, GLContextAttributes, InternalFormatParameter, WebGLCommand, WebGLResult, @@ -3321,6 +3322,107 @@ impl WebGL2RenderingContextMethods<crate::DomTypeHolder> for WebGL2RenderingCont .RenderbufferStorage(target, internal_format, width, height) } + /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.4S> + fn BlitFramebuffer( + &self, + src_x0: i32, + src_y0: i32, + src_x1: i32, + src_y1: i32, + dst_x0: i32, + dst_y0: i32, + dst_x1: i32, + dst_y1: i32, + mask: u32, + filter: u32, + ) { + bitflags! { + struct BlitFrameBufferFlags: u32 { + const DEPTH = constants::DEPTH_BUFFER_BIT; + const COLOR = constants::COLOR_BUFFER_BIT; + const STENCIL = constants::STENCIL_BUFFER_BIT; + const DEPTH_STENCIL = constants::DEPTH_BUFFER_BIT | constants::STENCIL_BUFFER_BIT; + } + }; + let Some(bits) = BlitFrameBufferFlags::from_bits(mask) else { + return self.base.webgl_error(InvalidValue); + }; + let attributes = self.base.GetContextAttributes().unwrap(); + + if bits.intersects(BlitFrameBufferFlags::DEPTH_STENCIL) { + match filter { + constants::LINEAR => return self.base.webgl_error(InvalidOperation), + constants::NEAREST => {}, + _ => return self.base.webgl_error(InvalidOperation), + } + } + + let src_fb = self.base.get_read_framebuffer_slot().get(); + let dst_fb = self.base.get_draw_framebuffer_slot().get(); + + let get_default_formats = || -> WebGLResult<(Option<u32>, Option<u32>, Option<u32>)> { + // All attempts to blit to an antialiased back buffer should fail. + if attributes.antialias { + return Err(InvalidOperation); + }; + let color = if attributes.alpha { + Some(constants::RGBA8) + } else { + Some(constants::RGB8) + }; + let (depth, stencil) = match (attributes.depth, attributes.stencil) { + (true, true) => ( + Some(constants::DEPTH24_STENCIL8), + Some(constants::DEPTH24_STENCIL8), + ), + (true, false) => (Some(constants::DEPTH_COMPONENT16), None), + (false, true) => (None, Some(constants::STENCIL_INDEX8)), + _ => (None, None), + }; + Ok((color, depth, stencil)) + }; + + let (src_color, src_depth, src_stencil) = match src_fb { + Some(fb) => { + handle_potential_webgl_error!(self.base, fb.get_attachment_formats(), return) + }, + None => handle_potential_webgl_error!(self.base, get_default_formats(), return), + }; + let (dst_color, dst_depth, dst_stencil) = match dst_fb { + Some(fb) => { + handle_potential_webgl_error!(self.base, fb.get_attachment_formats(), return) + }, + None => handle_potential_webgl_error!(self.base, get_default_formats(), return), + }; + + if bits.intersects(BlitFrameBufferFlags::COLOR) && src_color != dst_color { + return self.base.webgl_error(InvalidOperation); + } + if bits.intersects(BlitFrameBufferFlags::DEPTH) && src_depth != dst_depth { + return self.base.webgl_error(InvalidOperation); + } + if bits.intersects(BlitFrameBufferFlags::STENCIL) && src_stencil != dst_stencil { + return self.base.webgl_error(InvalidOperation); + } + + let src_width = src_x1.checked_sub(src_x0); + let dst_width = dst_x1.checked_sub(dst_x0); + let src_height = src_y1.checked_sub(src_y0); + let dst_height = dst_y1.checked_sub(dst_y0); + + if src_width.is_none() || + dst_width.is_none() || + src_height.is_none() || + dst_height.is_none() + { + return self.base.webgl_error(InvalidOperation); + } + + self.base.send_command(WebGLCommand::BlitFrameBuffer( + src_x0, src_y0, src_x1, src_y1, dst_x0, dst_y0, dst_x1, dst_y1, mask, filter, + )); + } + /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.6> fn FramebufferRenderbuffer( &self, diff --git a/components/script/dom/webglframebuffer.rs b/components/script/dom/webglframebuffer.rs index 99f051da9ea..5c015e36549 100644 --- a/components/script/dom/webglframebuffer.rs +++ b/components/script/dom/webglframebuffer.rs @@ -234,6 +234,25 @@ impl WebGLFramebuffer { self.size.get() } + pub fn get_attachment_formats(&self) -> WebGLResult<(Option<u32>, Option<u32>, Option<u32>)> { + if self.check_status() != constants::FRAMEBUFFER_COMPLETE { + return Err(WebGLError::InvalidFramebufferOperation); + } + let color = match self.attachment(constants::COLOR_ATTACHMENT0) { + Some(WebGLFramebufferAttachmentRoot::Renderbuffer(rb)) => Some(rb.internal_format()), + _ => None, + }; + let depth = match self.attachment(constants::DEPTH_ATTACHMENT) { + Some(WebGLFramebufferAttachmentRoot::Renderbuffer(rb)) => Some(rb.internal_format()), + _ => None, + }; + let stencil = match self.attachment(constants::STENCIL_ATTACHMENT) { + Some(WebGLFramebufferAttachmentRoot::Renderbuffer(rb)) => Some(rb.internal_format()), + _ => None, + }; + Ok((color, depth, stencil)) + } + fn check_attachment_constraints<'a>( &self, attachment: &Option<WebGLFramebufferAttachment>, diff --git a/components/script/dom/webidls/WebGL2RenderingContext.webidl b/components/script/dom/webidls/WebGL2RenderingContext.webidl index 3d5d086f554..72cedc30da6 100644 --- a/components/script/dom/webidls/WebGL2RenderingContext.webidl +++ b/components/script/dom/webidls/WebGL2RenderingContext.webidl @@ -295,8 +295,8 @@ interface mixin WebGL2RenderingContextBase optional GLuint dstOffset = 0, optional GLuint length = 0); /* Framebuffer objects */ - // void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, - // GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); + undefined blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, + GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); undefined framebufferTextureLayer(GLenum target, GLenum attachment, WebGLTexture? texture, GLint level, GLint layer); undefined invalidateFramebuffer(GLenum target, sequence<GLenum> attachments); |