mirror of
https://github.com/servo/servo.git
synced 2025-07-30 02:30:21 +01:00
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>
This commit is contained in:
parent
2575a0daf1
commit
c43762faea
29 changed files with 1686 additions and 31 deletions
|
@ -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,
|
||||
|
|
|
@ -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>,
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue