aboutsummaryrefslogtreecommitdiffstats
path: root/components/script
diff options
context:
space:
mode:
authorJosh Matthews <josh@joshmatthews.net>2025-01-06 13:37:35 -0500
committerGitHub <noreply@github.com>2025-01-06 18:37:35 +0000
commitc43762faea97c24e6135f426fbde8224f261abf6 (patch)
tree94fdd8834416cc47a0d5676c9a50e56ea4b70d50 /components/script
parent2575a0daf15a5bee3daed5190909c25c0382b85b (diff)
downloadservo-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.rs102
-rw-r--r--components/script/dom/webglframebuffer.rs19
-rw-r--r--components/script/dom/webidls/WebGL2RenderingContext.webidl4
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);