diff options
author | Mátyás Mustoha <matyas.mustoha@h-lab.eu> | 2020-02-14 11:57:11 +0100 |
---|---|---|
committer | Mátyás Mustoha <matyas.mustoha@h-lab.eu> | 2020-02-14 12:10:16 +0100 |
commit | 796ee705976f8072032a0fc88579ca18aed85999 (patch) | |
tree | 96f82216a560567509a08609cf22f33a127535c0 /components/script/dom/webglrenderingcontext.rs | |
parent | 833485887e9e8a4ae4beb71c473df101a4106ee4 (diff) | |
download | servo-796ee705976f8072032a0fc88579ca18aed85999.tar.gz servo-796ee705976f8072032a0fc88579ca18aed85999.zip |
Add initial support for WebGL2 read framebuffer
Adds support for binding to the read framebuffer slot and querying
its status.
Diffstat (limited to 'components/script/dom/webglrenderingcontext.rs')
-rw-r--r-- | components/script/dom/webglrenderingcontext.rs | 159 |
1 files changed, 97 insertions, 62 deletions
diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index 460f50aaada..874a089a637 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -163,7 +163,10 @@ pub struct WebGLRenderingContext { texture_unpacking_settings: Cell<TextureUnpacking>, // TODO(nox): Should be Cell<u8>. texture_unpacking_alignment: Cell<u32>, - bound_framebuffer: MutNullableDom<WebGLFramebuffer>, + bound_draw_framebuffer: MutNullableDom<WebGLFramebuffer>, + // TODO(mmatyas): This was introduced in WebGL2, but listed here because it's used by + // Textures and Renderbuffers, but such WebGLObjects have access only to the GL1 context. + bound_read_framebuffer: MutNullableDom<WebGLFramebuffer>, bound_renderbuffer: MutNullableDom<WebGLRenderbuffer>, bound_buffer_array: MutNullableDom<WebGLBuffer>, current_program: MutNullableDom<WebGLProgram>, @@ -223,7 +226,8 @@ impl WebGLRenderingContext { texture_packing_alignment: Cell::new(4), texture_unpacking_settings: Cell::new(TextureUnpacking::CONVERT_COLORSPACE), texture_unpacking_alignment: Cell::new(4), - bound_framebuffer: MutNullableDom::new(None), + bound_draw_framebuffer: MutNullableDom::new(None), + bound_read_framebuffer: MutNullableDom::new(None), bound_buffer_array: MutNullableDom::new(None), bound_renderbuffer: MutNullableDom::new(None), current_program: MutNullableDom::new(None), @@ -328,7 +332,7 @@ impl WebGLRenderingContext { // Bound framebuffer must not change when the canvas is resized. // Right now surfman generates a new FBO on resize. // Send a command to re-bind the framebuffer, if any. - if let Some(fbo) = self.bound_framebuffer.get() { + if let Some(fbo) = self.bound_draw_framebuffer.get() { let id = WebGLFramebufferBindingRequest::Explicit(fbo.id()); self.send_command(WebGLCommand::BindFramebuffer(constants::FRAMEBUFFER, id)); } @@ -402,7 +406,7 @@ impl WebGLRenderingContext { // The WebGL spec mentions a couple more operations that trigger // this: clear() and getParameter(IMPLEMENTATION_COLOR_READ_*). pub fn validate_framebuffer(&self) -> WebGLResult<()> { - match self.bound_framebuffer.get() { + match self.bound_draw_framebuffer.get() { Some(fb) => match fb.check_status_for_rendering() { CompleteForRendering::Complete => Ok(()), CompleteForRendering::Incomplete => Err(InvalidFramebufferOperation), @@ -478,7 +482,7 @@ impl WebGLRenderingContext { fn mark_as_dirty(&self) { // If we have a bound framebuffer, then don't mark the canvas as dirty. - if self.bound_framebuffer.get().is_some() { + if self.bound_draw_framebuffer.get().is_some() { return; } @@ -503,7 +507,7 @@ impl WebGLRenderingContext { } pub fn get_current_framebuffer_size(&self) -> Option<(i32, i32)> { - match self.bound_framebuffer.get() { + match self.bound_draw_framebuffer.get() { Some(fb) => return fb.size(), // The window system framebuffer is bound @@ -757,7 +761,7 @@ impl WebGLRenderingContext { data: pixels.data.into(), }); - if let Some(fb) = self.bound_framebuffer.get() { + if let Some(fb) = self.bound_draw_framebuffer.get() { fb.invalidate_texture(&*texture); } } @@ -1124,10 +1128,6 @@ impl WebGLRenderingContext { }); } - pub fn bound_framebuffer(&self) -> Option<DomRoot<WebGLFramebuffer>> { - self.bound_framebuffer.get() - } - pub fn extension_manager(&self) -> &WebGLExtensions { &self.extension_manager } @@ -1341,6 +1341,50 @@ impl WebGLRenderingContext { } self.uniform_vec_section::<f32>(vec, offset, length, uniform_size, uniform_location) } + + pub fn get_draw_framebuffer_slot(&self) -> &MutNullableDom<WebGLFramebuffer> { + &self.bound_draw_framebuffer + } + + pub fn get_read_framebuffer_slot(&self) -> &MutNullableDom<WebGLFramebuffer> { + &self.bound_read_framebuffer + } + + pub fn validate_new_framebuffer_binding( + &self, + framebuffer: Option<&WebGLFramebuffer>, + ) -> WebGLResult<()> { + if let Some(fb) = framebuffer { + self.validate_ownership(fb)?; + if fb.is_deleted() { + // From the WebGL spec: + // + // "An attempt to bind a deleted framebuffer will + // generate an INVALID_OPERATION error, and the + // current binding will remain untouched." + return Err(InvalidOperation); + } + } + Ok(()) + } + + pub fn bind_framebuffer_to( + &self, + target: u32, + framebuffer: Option<&WebGLFramebuffer>, + slot: &MutNullableDom<WebGLFramebuffer>, + ) { + match framebuffer { + Some(framebuffer) => framebuffer.bind(target), + None => { + // Bind the default framebuffer + let cmd = + WebGLCommand::BindFramebuffer(target, WebGLFramebufferBindingRequest::Default); + self.send_command(cmd); + }, + } + slot.set(framebuffer); + } } #[cfg(not(feature = "webgl_backtrace"))] @@ -1442,7 +1486,10 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { return optional_root_object_to_js_or_null!(*cx, buffer); }, constants::FRAMEBUFFER_BINDING => unsafe { - return optional_root_object_to_js_or_null!(*cx, &self.bound_framebuffer.get()); + return optional_root_object_to_js_or_null!( + *cx, + &self.bound_draw_framebuffer.get() + ); }, constants::RENDERBUFFER_BINDING => unsafe { return optional_root_object_to_js_or_null!(*cx, &self.bound_renderbuffer.get()); @@ -1845,33 +1892,17 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.6 fn BindFramebuffer(&self, target: u32, framebuffer: Option<&WebGLFramebuffer>) { - if let Some(fb) = framebuffer { - handle_potential_webgl_error!(self, self.validate_ownership(fb), return); - } + handle_potential_webgl_error!( + self, + self.validate_new_framebuffer_binding(framebuffer), + return + ); if target != constants::FRAMEBUFFER { return self.webgl_error(InvalidEnum); } - if let Some(framebuffer) = framebuffer { - if framebuffer.is_deleted() { - // From the WebGL spec: - // - // "An attempt to bind a deleted framebuffer will - // generate an INVALID_OPERATION error, and the - // current binding will remain untouched." - return self.webgl_error(InvalidOperation); - } else { - framebuffer.bind(target); - self.bound_framebuffer.set(Some(framebuffer)); - } - } else { - // Bind the default framebuffer - let cmd = - WebGLCommand::BindFramebuffer(target, WebGLFramebufferBindingRequest::Default); - self.send_command(cmd); - self.bound_framebuffer.set(framebuffer); - } + self.bind_framebuffer_to(target, framebuffer, &self.bound_draw_framebuffer) } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.7 @@ -2009,7 +2040,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { data: pixels.data.into(), }); - if let Some(fb) = self.bound_framebuffer.get() { + if let Some(fb) = self.bound_draw_framebuffer.get() { fb.invalidate_texture(&*texture); } } @@ -2100,7 +2131,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { Err(_) => return, }; - let framebuffer_format = match self.bound_framebuffer.get() { + let framebuffer_format = match self.bound_draw_framebuffer.get() { Some(fb) => match fb.attachment(constants::COLOR_ATTACHMENT0) { Some(WebGLFramebufferAttachmentRoot::Renderbuffer(rb)) => { TexFormat::from_gl_constant(rb.internal_format()) @@ -2419,10 +2450,10 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { handle_potential_webgl_error!(self, self.validate_ownership(framebuffer), return); handle_object_deletion!( self, - self.bound_framebuffer, + self.bound_draw_framebuffer, framebuffer, Some(WebGLCommand::BindFramebuffer( - constants::FRAMEBUFFER, + framebuffer.target().unwrap(), WebGLFramebufferBindingRequest::Default )) ); @@ -2575,7 +2606,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { pname: u32, ) -> JSVal { // Check if currently bound framebuffer is non-zero as per spec. - if let Some(fb) = self.bound_framebuffer.get() { + if let Some(fb) = self.bound_draw_framebuffer.get() { // Opaque framebuffers cannot have their attachments inspected // https://immersive-web.github.io/webxr/#opaque-framebuffer handle_potential_webgl_error!(self, fb.validate_transparent(), return NullValue()); @@ -2617,27 +2648,31 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { _ => false, }; - let bound_attachment_matches = - match self.bound_framebuffer.get().unwrap().attachment(attachment) { - Some(attachment_root) => match attachment_root { - WebGLFramebufferAttachmentRoot::Renderbuffer(_) => match pname { - constants::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE | - constants::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME => true, - _ => false, - }, - WebGLFramebufferAttachmentRoot::Texture(_) => match pname { - constants::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE | - constants::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME | - constants::FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL | - constants::FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE => true, - _ => false, - }, + let bound_attachment_matches = match self + .bound_draw_framebuffer + .get() + .unwrap() + .attachment(attachment) + { + Some(attachment_root) => match attachment_root { + WebGLFramebufferAttachmentRoot::Renderbuffer(_) => match pname { + constants::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE | + constants::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME => true, + _ => false, }, - _ => match pname { - constants::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE => true, + WebGLFramebufferAttachmentRoot::Texture(_) => match pname { + constants::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE | + constants::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME | + constants::FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL | + constants::FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE => true, _ => false, }, - }; + }, + _ => match pname { + constants::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE => true, + _ => false, + }, + }; if !target_matches || !attachment_matches || !pname_matches || !bound_attachment_matches { self.webgl_error(InvalidEnum); @@ -2653,7 +2688,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { if pname == constants::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME { // if fb is None, an INVALID_OPERATION is returned // at the beggining of the function, so `.unwrap()` will never panic - let fb = self.bound_framebuffer.get().unwrap(); + let fb = self.bound_draw_framebuffer.get().unwrap(); if let Some(webgl_attachment) = fb.attachment(attachment) { match webgl_attachment { WebGLFramebufferAttachmentRoot::Renderbuffer(rb) => unsafe { @@ -4158,7 +4193,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { return 0; } - match self.bound_framebuffer.get() { + match self.bound_draw_framebuffer.get() { Some(fb) => return fb.check_status(), None => return constants::FRAMEBUFFER_COMPLETE, } @@ -4185,7 +4220,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { self, rb.storage(self.api_type, internal_format, width, height) ); - if let Some(fb) = self.bound_framebuffer.get() { + if let Some(fb) = self.bound_draw_framebuffer.get() { fb.invalidate_renderbuffer(&*rb); } @@ -4208,7 +4243,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { return self.webgl_error(InvalidEnum); } - match self.bound_framebuffer.get() { + match self.bound_draw_framebuffer.get() { Some(fb) => handle_potential_webgl_error!(self, fb.renderbuffer(attachment, rb)), None => self.webgl_error(InvalidOperation), }; @@ -4231,7 +4266,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { return self.webgl_error(InvalidEnum); } - match self.bound_framebuffer.get() { + match self.bound_draw_framebuffer.get() { Some(fb) => handle_potential_webgl_error!( self, fb.texture2d(attachment, textarget, texture, level) |