From 46b1d8faeeeadcddf136ad99096d2d99da7ea36b Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Thu, 19 Sep 2019 17:38:46 -0400 Subject: [PATCH 1/5] webgl: Report invalid operations for more APIs that can't use an incomplete framebuffer. --- .../script/dom/webglrenderingcontext.rs | 11 +++- .../oes-texture-half-float.html.ini | 50 +++---------------- 2 files changed, 18 insertions(+), 43 deletions(-) diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index e50d70cb916..354f918a0dd 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -1241,9 +1241,17 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { // GL_OES_read_format support (assuming an underlying GLES // driver. Desktop is happy to format convert for us). constants::IMPLEMENTATION_COLOR_READ_FORMAT => { + if self.validate_framebuffer().is_err() { + self.webgl_error(InvalidOperation); + return NullValue(); + } return Int32Value(constants::RGBA as i32); }, constants::IMPLEMENTATION_COLOR_READ_TYPE => { + if self.validate_framebuffer().is_err() { + self.webgl_error(InvalidOperation); + return NullValue(); + } return Int32Value(constants::UNSIGNED_BYTE as i32); }, constants::COMPRESSED_TEXTURE_FORMATS => unsafe { @@ -2819,6 +2827,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { pixel_type: u32, mut pixels: CustomAutoRooterGuard>, ) { + handle_potential_webgl_error!(self, self.validate_framebuffer(), return); + let pixels = handle_potential_webgl_error!(self, pixels.as_mut().ok_or(InvalidValue), return); @@ -2834,7 +2844,6 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { return self.webgl_error(InvalidOperation); } - handle_potential_webgl_error!(self, self.validate_framebuffer(), return); let (fb_width, fb_height) = handle_potential_webgl_error!( self, self.get_current_framebuffer_size().ok_or(InvalidOperation), diff --git a/tests/wpt/webgl/meta/conformance/extensions/oes-texture-half-float.html.ini b/tests/wpt/webgl/meta/conformance/extensions/oes-texture-half-float.html.ini index 541f722dbcf..2b2b3b78483 100644 --- a/tests/wpt/webgl/meta/conformance/extensions/oes-texture-half-float.html.ini +++ b/tests/wpt/webgl/meta/conformance/extensions/oes-texture-half-float.html.ini @@ -1,58 +1,24 @@ [oes-texture-half-float.html] - [WebGL test #84: getError expected: INVALID_OPERATION. Was NO_ERROR : IMPLEMENTATION_COLOR_READ_TYPE should fail for incomplete framebuffers.] + [WebGL test #101: getError expected: NO_ERROR. Was INVALID_OPERATION : readPixels should return NO_ERROR when reading FLOAT data.] expected: FAIL - [WebGL test #97: getError expected: INVALID_FRAMEBUFFER_OPERATION. Was INVALID_OPERATION : readPixels should fail on incomplete framebuffers.] + [WebGL test #103: Green channel should be 0.25 for FLOAT readPixels. Received: 0] expected: FAIL - [WebGL test #89: gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_TYPE) should be null (of type object). Was 5121 (of type number).] + [WebGL test #104: Blue channel should be 0.5 for FLOAT readPixels. Received: 0] expected: FAIL - [WebGL test #100: Green channel should be 0.25 for FLOAT readPixels. Received: 0] + [WebGL test #105: Alpha channel should be 0.75 for FLOAT readPixels. Received: 0] expected: FAIL - [WebGL test #91: getError expected: INVALID_FRAMEBUFFER_OPERATION. Was INVALID_OPERATION : readPixels should fail on incomplete framebuffers.] + [WebGL test #110: getError expected: NO_ERROR. Was INVALID_OPERATION : readPixels should return NO_ERROR when reading FLOAT data.] expected: FAIL - [WebGL test #88: getError expected: INVALID_OPERATION. Was NO_ERROR : IMPLEMENTATION_COLOR_READ_FORMAT should fail for incomplete framebuffers.] + [WebGL test #112: Green channel should be 0.25 for FLOAT readPixels. Received: 0] expected: FAIL - [WebGL test #90: getError expected: INVALID_OPERATION. Was NO_ERROR : IMPLEMENTATION_COLOR_READ_TYPE should fail for incomplete framebuffers.] + [WebGL test #113: Blue channel should be 0.5 for FLOAT readPixels. Received: 0] expected: FAIL - [WebGL test #95: gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_TYPE) should be null (of type object). Was 5121 (of type number).] + [WebGL test #114: Alpha channel should be 1 for FLOAT readPixels. Received: 0] expected: FAIL - - [WebGL test #85: getError expected: INVALID_FRAMEBUFFER_OPERATION. Was INVALID_OPERATION : readPixels should fail on incomplete framebuffers.] - expected: FAIL - - [WebGL test #94: getError expected: INVALID_OPERATION. Was NO_ERROR : IMPLEMENTATION_COLOR_READ_FORMAT should fail for incomplete framebuffers.] - expected: FAIL - - [WebGL test #101: Blue channel should be 0.5 for FLOAT readPixels. Received: 0] - expected: FAIL - - [WebGL test #87: gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_FORMAT) should be null (of type object). Was 6408 (of type number).] - expected: FAIL - - [WebGL test #83: gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_TYPE) should be null (of type object). Was 5121 (of type number).] - expected: FAIL - - [WebGL test #81: gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_FORMAT) should be null (of type object). Was 6408 (of type number).] - expected: FAIL - - [WebGL test #98: getError expected: NO_ERROR. Was INVALID_OPERATION : readPixels should return NO_ERROR when reading FLOAT data.] - expected: FAIL - - [WebGL test #102: Alpha channel should be 0.75 for FLOAT readPixels. Received: 0] - expected: FAIL - - [WebGL test #93: gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_FORMAT) should be null (of type object). Was 6408 (of type number).] - expected: FAIL - - [WebGL test #96: getError expected: INVALID_OPERATION. Was NO_ERROR : IMPLEMENTATION_COLOR_READ_TYPE should fail for incomplete framebuffers.] - expected: FAIL - - [WebGL test #82: getError expected: INVALID_OPERATION. Was NO_ERROR : IMPLEMENTATION_COLOR_READ_FORMAT should fail for incomplete framebuffers.] - expected: FAIL - From 7e4cf13f5b1106690f15d84029e31364c0c6907b Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Thu, 19 Sep 2019 17:43:48 -0400 Subject: [PATCH 2/5] webgl: Support RGB color attachments for complete framebuffers. --- components/script/dom/webglframebuffer.rs | 1 + .../conformance/textures/misc/tex-input-validation.html.ini | 6 +----- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/components/script/dom/webglframebuffer.rs b/components/script/dom/webglframebuffer.rs index 114ede38b01..284a51cf483 100644 --- a/components/script/dom/webglframebuffer.rs +++ b/components/script/dom/webglframebuffer.rs @@ -177,6 +177,7 @@ impl WebGLFramebuffer { constants::RGB5_A1, constants::RGB565, constants::RGBA, + constants::RGB, ][..], &[constants::DEPTH_COMPONENT16][..], &[constants::STENCIL_INDEX8][..], diff --git a/tests/wpt/webgl/meta/conformance/textures/misc/tex-input-validation.html.ini b/tests/wpt/webgl/meta/conformance/textures/misc/tex-input-validation.html.ini index a5e193befaf..9611a8b8c64 100644 --- a/tests/wpt/webgl/meta/conformance/textures/misc/tex-input-validation.html.ini +++ b/tests/wpt/webgl/meta/conformance/textures/misc/tex-input-validation.html.ini @@ -6,9 +6,5 @@ [WebGL test #61: getError expected: INVALID_OPERATION. Was NO_ERROR : colorBufferFormat: RGB internalFormat: RGBA] expected: FAIL - [WebGL test #53: getError expected: INVALID_OPERATION. Was NO_ERROR : colorBufferFormat: RGB internalFormat: RGBA] + [WebGL test #37: getError expected: NO_ERROR. Was INVALID_OPERATION : colorBufferFormat: RGB565 internalFormat: RGB target: TEXTURE_2D border: 0] expected: FAIL - - [WebGL test #34: getError expected: INVALID_OPERATION. Was NO_ERROR : colorBufferFormat: RGB565 internalFormat: RGBA target: TEXTURE_2D border: 0] - expected: FAIL - From 778b48fa47d1fd13d77464373c7f0bc8a2b51d2a Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Thu, 19 Sep 2019 17:45:19 -0400 Subject: [PATCH 3/5] webgl: Implement component narrowing checks for CopyTexImage2D. --- .../script/dom/webglrenderingcontext.rs | 41 +++++++++++++++++++ .../misc/copy-tex-image-2d-formats.html.ini | 11 ----- 2 files changed, 41 insertions(+), 11 deletions(-) delete mode 100644 tests/wpt/webgl/meta/conformance/textures/misc/copy-tex-image-2d-formats.html.ini diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index 354f918a0dd..fb4c13b321e 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -1928,6 +1928,47 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { Err(_) => return, }; + let framebuffer_format = match self.bound_framebuffer.get() { + Some(fb) => match fb.attachment(constants::COLOR_ATTACHMENT0) { + Some(WebGLFramebufferAttachmentRoot::Renderbuffer(rb)) => { + TexFormat::from_gl_constant(rb.internal_format()) + }, + Some(WebGLFramebufferAttachmentRoot::Texture(texture)) => { + texture.image_info_for_target(&target, 0).internal_format() + }, + None => None, + }, + None => { + let attrs = self.GetContextAttributes().unwrap(); + Some(if attrs.alpha { + TexFormat::RGBA + } else { + TexFormat::RGB + }) + }, + }; + + let framebuffer_format = match framebuffer_format { + Some(f) => f, + None => { + self.webgl_error(InvalidOperation); + return; + }, + }; + + match (framebuffer_format, internal_format) { + (a, b) if a == b => (), + (TexFormat::RGBA, TexFormat::RGB) => (), + (TexFormat::RGBA, TexFormat::Alpha) => (), + (TexFormat::RGBA, TexFormat::Luminance) => (), + (TexFormat::RGBA, TexFormat::LuminanceAlpha) => (), + (TexFormat::RGB, TexFormat::Luminance) => (), + _ => { + self.webgl_error(InvalidOperation); + return; + }, + } + // NB: TexImage2D depth is always equal to 1 handle_potential_webgl_error!( self, diff --git a/tests/wpt/webgl/meta/conformance/textures/misc/copy-tex-image-2d-formats.html.ini b/tests/wpt/webgl/meta/conformance/textures/misc/copy-tex-image-2d-formats.html.ini deleted file mode 100644 index a4bd32b2816..00000000000 --- a/tests/wpt/webgl/meta/conformance/textures/misc/copy-tex-image-2d-formats.html.ini +++ /dev/null @@ -1,11 +0,0 @@ -[copy-tex-image-2d-formats.html] - bug: https://github.com/servo/servo/issues/20595 - [WebGL test #32: getError expected: INVALID_OPERATION. Was NO_ERROR : should not be able to copyTexImage2D ALPHA from RGB] - expected: FAIL - - [WebGL test #40: getError expected: INVALID_OPERATION. Was NO_ERROR : should not be able to copyTexImage2D RGBA from RGB] - expected: FAIL - - [WebGL test #36: getError expected: INVALID_OPERATION. Was NO_ERROR : should not be able to copyTexImage2D LUMINANCE_ALPHA from RGB] - expected: FAIL - From 5bd1e86d42b1a9fb6cef77cdcf09c346b778d1ae Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Thu, 19 Sep 2019 17:46:09 -0400 Subject: [PATCH 4/5] webxr: Use the same texture format as the original GL context's framebuffer when creating an XR GL layer. --- components/canvas/gl_context.rs | 19 ++++++++++++++----- components/canvas/webgl_thread.rs | 11 ++++++----- components/canvas_traits/webgl.rs | 8 ++++++++ components/script/dom/bindings/trace.rs | 4 ++-- .../script/dom/webglrenderingcontext.rs | 10 ++++++++-- components/script/dom/xrwebgllayer.rs | 8 +++++--- 6 files changed, 43 insertions(+), 17 deletions(-) diff --git a/components/canvas/gl_context.rs b/components/canvas/gl_context.rs index 66fd3001277..018300129b9 100644 --- a/components/canvas/gl_context.rs +++ b/components/canvas/gl_context.rs @@ -4,14 +4,14 @@ use super::webgl_thread::{GLState, WebGLImpl}; use canvas_traits::webgl::{ - GLContextAttributes, GLLimits, WebGLCommand, WebGLCommandBacktrace, WebGLVersion, + GLContextAttributes, GLFormats, GLLimits, WebGLCommand, WebGLCommandBacktrace, WebGLVersion, }; use euclid::default::Size2D; use offscreen_gl_context::{ ColorAttachmentType, DrawBuffer, GLContext, GLContextAttributes as RawGLContextAttributes, GLContextDispatcher, }; -use offscreen_gl_context::{GLLimits as RawGLLimits, GLVersion}; +use offscreen_gl_context::{GLFormats as RawGLFormats, GLLimits as RawGLLimits, GLVersion}; use offscreen_gl_context::{NativeGLContext, NativeGLContextHandle, NativeGLContextMethods}; use offscreen_gl_context::{OSMesaContext, OSMesaContextHandle}; use sparkle::gl; @@ -179,7 +179,7 @@ impl GLContextWrapper { } } - pub fn get_info(&self) -> (Size2D, u32, GLLimits) { + pub fn get_info(&self) -> (Size2D, u32, GLLimits, GLFormats) { match *self { GLContextWrapper::Native(ref ctx) => { let (real_size, texture_id) = { @@ -191,8 +191,9 @@ impl GLContextWrapper { }; let limits = ctx.borrow_limits().clone(); + let formats = map_formats(ctx.borrow_formats()); - (real_size, texture_id, map_limits(limits)) + (real_size, texture_id, map_limits(limits), formats) }, GLContextWrapper::OSMesa(ref ctx) => { let (real_size, texture_id) = { @@ -204,8 +205,9 @@ impl GLContextWrapper { }; let limits = ctx.borrow_limits().clone(); + let formats = map_formats(ctx.borrow_formats()); - (real_size, texture_id, map_limits(limits)) + (real_size, texture_id, map_limits(limits), formats) }, } } @@ -260,3 +262,10 @@ pub fn map_attrs_to_script_attrs(attrs: RawGLContextAttributes) -> GLContextAttr preserve_drawing_buffer: attrs.preserve_drawing_buffer, } } + +fn map_formats(formats: &RawGLFormats) -> GLFormats { + GLFormats { + texture_format: formats.texture, + texture_type: formats.texture_type, + } +} diff --git a/components/canvas/webgl_thread.rs b/components/canvas/webgl_thread.rs index 612117c7095..c9007515ae4 100644 --- a/components/canvas/webgl_thread.rs +++ b/components/canvas/webgl_thread.rs @@ -238,7 +238,7 @@ impl WebGLThread { WebGLMsg::CreateContext(version, size, attributes, result_sender) => { let result = self.create_webgl_context(version, size, attributes); result_sender - .send(result.map(|(id, limits, share_mode)| { + .send(result.map(|(id, limits, share_mode, framebuffer_format)| { let data = Self::make_current_if_needed( id, &self.contexts, @@ -276,6 +276,7 @@ impl WebGLThread { share_mode, glsl_version, api_type, + framebuffer_format, } })) .unwrap(); @@ -406,7 +407,7 @@ impl WebGLThread { version: WebGLVersion, size: Size2D, attributes: GLContextAttributes, - ) -> Result<(WebGLContextId, GLLimits, WebGLContextShareMode), String> { + ) -> Result<(WebGLContextId, GLLimits, WebGLContextShareMode, GLFormats), String> { // Creating a new GLContext may make the current bound context_id dirty. // Clear it to ensure that make_current() is called in subsequent commands. self.bound_context_id = None; @@ -434,7 +435,7 @@ impl WebGLThread { .next_id(WebrenderImageHandlerType::WebGL) .0 as usize, ); - let (size, texture_id, limits) = ctx.get_info(); + let (size, texture_id, limits, framebuffer_formats) = ctx.get_info(); let use_apple_vertex_arrays = needs_apple_vertex_arrays(ctx.gl(), version); self.contexts.insert( id, @@ -458,7 +459,7 @@ impl WebGLThread { }, ); - Ok((id, limits, share_mode)) + Ok((id, limits, share_mode, framebuffer_formats)) } /// Resizes a WebGLContext @@ -476,7 +477,7 @@ impl WebGLThread { .expect("Missing WebGL context!"); match data.ctx.resize(size) { Ok(old_draw_buffer) => { - let (real_size, texture_id, _) = data.ctx.get_info(); + let (real_size, texture_id, _, _) = data.ctx.get_info(); let info = self.cached_context_info.get_mut(&context_id).unwrap(); if let ContextRenderState::Locked(ref mut in_use) = info.render_state { // If there's already an outdated draw buffer present, we can ignore diff --git a/components/canvas_traits/webgl.rs b/components/canvas_traits/webgl.rs index 142119fb75d..9df1c8e56db 100644 --- a/components/canvas_traits/webgl.rs +++ b/components/canvas_traits/webgl.rs @@ -91,6 +91,8 @@ pub struct WebGLCreateContextResult { pub glsl_version: WebGLSLVersion, /// The GL API used by the context. pub api_type: GlType, + /// The format for creating new offscreen framebuffers for this context. + pub framebuffer_format: GLFormats, } #[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, Serialize)] @@ -886,3 +888,9 @@ pub struct GLLimits { pub max_vertex_texture_image_units: u32, pub max_vertex_uniform_vectors: u32, } + +#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, Serialize)] +pub struct GLFormats { + pub texture_format: u32, + pub texture_type: u32, +} diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 91b4c119999..3e7486ed8ca 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -45,8 +45,8 @@ use canvas_traits::canvas::{ CanvasGradientStop, CanvasId, LinearGradientStyle, RadialGradientStyle, }; use canvas_traits::canvas::{CompositionOrBlending, LineCapStyle, LineJoinStyle, RepetitionStyle}; -use canvas_traits::webgl::GLLimits; use canvas_traits::webgl::{ActiveAttribInfo, ActiveUniformInfo, GlType, TexDataType, TexFormat}; +use canvas_traits::webgl::{GLFormats, GLLimits}; use canvas_traits::webgl::{WebGLBufferId, WebGLChan, WebGLContextShareMode, WebGLError}; use canvas_traits::webgl::{WebGLFramebufferId, WebGLMsgSender, WebGLPipeline, WebGLProgramId}; use canvas_traits::webgl::{WebGLReceiver, WebGLRenderbufferId, WebGLSLVersion, WebGLSender}; @@ -437,7 +437,7 @@ unsafe_no_jsmanaged_fields!(StorageType); unsafe_no_jsmanaged_fields!(CanvasGradientStop, LinearGradientStyle, RadialGradientStyle); unsafe_no_jsmanaged_fields!(LineCapStyle, LineJoinStyle, CompositionOrBlending); unsafe_no_jsmanaged_fields!(RepetitionStyle); -unsafe_no_jsmanaged_fields!(WebGLError, GLLimits, GlType); +unsafe_no_jsmanaged_fields!(WebGLError, GLFormats, GLLimits, GlType); unsafe_no_jsmanaged_fields!(TimeProfilerChan); unsafe_no_jsmanaged_fields!(MemProfilerChan); unsafe_no_jsmanaged_fields!(PseudoElement); diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index fb4c13b321e..33aaaf603d4 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -53,8 +53,8 @@ use crate::script_runtime::JSContext as SafeJSContext; use backtrace::Backtrace; use canvas_traits::webgl::WebGLError::*; use canvas_traits::webgl::{ - webgl_channel, AlphaTreatment, DOMToTextureCommand, GLContextAttributes, GLLimits, GlType, - Parameter, TexDataType, TexFormat, TexParameter, WebGLChan, WebGLCommand, + webgl_channel, AlphaTreatment, DOMToTextureCommand, GLContextAttributes, GLFormats, GLLimits, + GlType, Parameter, TexDataType, TexFormat, TexParameter, WebGLChan, WebGLCommand, WebGLCommandBacktrace, WebGLContextId, WebGLContextShareMode, WebGLError, WebGLFramebufferBindingRequest, WebGLMsg, WebGLMsgSender, WebGLProgramId, WebGLResult, WebGLSLVersion, WebGLSendResult, WebGLSender, WebGLVersion, WebVRCommand, YAxisTreatment, @@ -170,6 +170,7 @@ pub struct WebGLRenderingContext { current_vao: MutNullableDom, textures: Textures, api_type: GlType, + framebuffer_format: GLFormats, } impl WebGLRenderingContext { @@ -229,6 +230,7 @@ impl WebGLRenderingContext { current_vao: Default::default(), textures: Textures::new(max_combined_texture_image_units), api_type: ctx_data.api_type, + framebuffer_format: ctx_data.framebuffer_format, } }) } @@ -1109,6 +1111,10 @@ impl WebGLRenderingContext { pub fn extension_manager(&self) -> &WebGLExtensions { &self.extension_manager } + + pub fn formats(&self) -> &GLFormats { + &self.framebuffer_format + } } #[cfg(not(feature = "webgl_backtrace"))] diff --git a/components/script/dom/xrwebgllayer.rs b/components/script/dom/xrwebgllayer.rs index a1e912252e9..dabff8fc947 100644 --- a/components/script/dom/xrwebgllayer.rs +++ b/components/script/dom/xrwebgllayer.rs @@ -110,16 +110,18 @@ impl XRWebGLLayer { let mut pixels = CustomAutoRooter::new(None); let mut clear_bits = constants::COLOR_BUFFER_BIT; + let formats = context.formats(); + context.BindTexture(constants::TEXTURE_2D, Some(&texture)); let sc = context.TexImage2D( constants::TEXTURE_2D, 0, - constants::RGBA, + formats.texture_format, resolution.width, resolution.height, 0, - constants::RGBA, - constants::UNSIGNED_BYTE, + formats.texture_format, + formats.texture_type, pixels.root(*cx), ); From ea715a7a4cae5d2a2f41b059f36e08010d544de1 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Fri, 20 Sep 2019 01:28:06 -0400 Subject: [PATCH 5/5] webgl: Update framebuffer completion status when attached renderbuffer/texture storage changes. --- components/script/dom/webglframebuffer.rs | 24 +++++++++++++++++++++- components/script/dom/webglrenderbuffer.rs | 17 ++++++++++++++- components/script/dom/webgltexture.rs | 19 ++++++++++++++++- 3 files changed, 57 insertions(+), 3 deletions(-) diff --git a/components/script/dom/webglframebuffer.rs b/components/script/dom/webglframebuffer.rs index 284a51cf483..3a31e99be33 100644 --- a/components/script/dom/webglframebuffer.rs +++ b/components/script/dom/webglframebuffer.rs @@ -59,6 +59,15 @@ impl WebGLFramebufferAttachment { }, } } + + fn detach(&self) { + match self { + WebGLFramebufferAttachment::Renderbuffer(rb) => rb.detach_from_framebuffer(), + WebGLFramebufferAttachment::Texture { ref texture, .. } => { + texture.detach_from_framebuffer() + }, + } + } } #[derive(Clone, JSTraceable, MallocSizeOf)] @@ -161,7 +170,7 @@ impl WebGLFramebuffer { self.size.get() } - fn update_status(&self) { + pub fn update_status(&self) { let c = self.color.borrow(); let z = self.depth.borrow(); let s = self.stencil.borrow(); @@ -311,6 +320,7 @@ impl WebGLFramebuffer { } *binding.borrow_mut() = Some(WebGLFramebufferAttachment::Renderbuffer(Dom::from_ref(rb))); + rb.attach_to_framebuffer(self); Some(rb.id()) }, @@ -340,6 +350,9 @@ impl WebGLFramebuffer { binding: &DomRefCell>, attachment: u32, ) { + if let Some(att) = &*binding.borrow() { + att.detach(); + } *binding.borrow_mut() = None; if INTERESTING_ATTACHMENT_POINTS.contains(&attachment) { self.reattach_depth_stencil(); @@ -364,6 +377,7 @@ impl WebGLFramebuffer { let context = self.upcast::().context(); match *attachment { WebGLFramebufferAttachment::Renderbuffer(ref rb) => { + rb.attach_to_framebuffer(self); context.send_command(WebGLCommand::FramebufferRenderbuffer( constants::FRAMEBUFFER, attachment_point, @@ -372,6 +386,7 @@ impl WebGLFramebuffer { )); }, WebGLFramebufferAttachment::Texture { ref texture, level } => { + texture.attach_to_framebuffer(self); context.send_command(WebGLCommand::FramebufferTexture2D( constants::FRAMEBUFFER, attachment_point, @@ -464,6 +479,7 @@ impl WebGLFramebuffer { texture: Dom::from_ref(texture), level: level, }); + texture.attach_to_framebuffer(self); Some(texture.id()) }, @@ -551,6 +567,9 @@ impl WebGLFramebuffer { let mut depth_or_stencil_updated = false; self.with_matching_renderbuffers(rb, |att, name| { depth_or_stencil_updated |= INTERESTING_ATTACHMENT_POINTS.contains(&name); + if let Some(att) = &*att.borrow() { + att.detach(); + } *att.borrow_mut() = None; self.update_status(); }); @@ -564,6 +583,9 @@ impl WebGLFramebuffer { let mut depth_or_stencil_updated = false; self.with_matching_textures(texture, |att, name| { depth_or_stencil_updated |= INTERESTING_ATTACHMENT_POINTS.contains(&name); + if let Some(att) = &*att.borrow() { + att.detach(); + } *att.borrow_mut() = None; self.update_status(); }); diff --git a/components/script/dom/webglrenderbuffer.rs b/components/script/dom/webglrenderbuffer.rs index f210b579e88..07afdbccb44 100644 --- a/components/script/dom/webglrenderbuffer.rs +++ b/components/script/dom/webglrenderbuffer.rs @@ -10,7 +10,8 @@ use crate::dom::bindings::codegen::Bindings::WebGLRenderbufferBinding; use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants; use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject}; -use crate::dom::bindings::root::DomRoot; +use crate::dom::bindings::root::{DomRoot, MutNullableDom}; +use crate::dom::webglframebuffer::WebGLFramebuffer; use crate::dom::webglobject::WebGLObject; use crate::dom::webglrenderingcontext::WebGLRenderingContext; use canvas_traits::webgl::{ @@ -28,6 +29,7 @@ pub struct WebGLRenderbuffer { size: Cell>, internal_format: Cell>, is_initialized: Cell, + attached_framebuffer: MutNullableDom, } impl WebGLRenderbuffer { @@ -40,6 +42,7 @@ impl WebGLRenderbuffer { internal_format: Cell::new(None), size: Cell::new(None), is_initialized: Cell::new(false), + attached_framebuffer: Default::default(), } } @@ -186,6 +189,10 @@ impl WebGLRenderbuffer { self.internal_format.set(Some(internal_format)); self.is_initialized.set(false); + if let Some(fb) = self.attached_framebuffer.get() { + fb.update_status(); + } + self.upcast::() .context() .send_command(WebGLCommand::RenderbufferStorage( @@ -199,6 +206,14 @@ impl WebGLRenderbuffer { Ok(()) } + + pub fn attach_to_framebuffer(&self, fb: &WebGLFramebuffer) { + self.attached_framebuffer.set(Some(fb)); + } + + pub fn detach_from_framebuffer(&self) { + self.attached_framebuffer.set(None); + } } impl Drop for WebGLRenderbuffer { diff --git a/components/script/dom/webgltexture.rs b/components/script/dom/webgltexture.rs index a7e548dcdef..e4a18b519a3 100644 --- a/components/script/dom/webgltexture.rs +++ b/components/script/dom/webgltexture.rs @@ -10,8 +10,9 @@ use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGL use crate::dom::bindings::codegen::Bindings::WebGLTextureBinding; use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject}; -use crate::dom::bindings::root::DomRoot; +use crate::dom::bindings::root::{DomRoot, MutNullableDom}; use crate::dom::webgl_validations::types::TexImageTarget; +use crate::dom::webglframebuffer::WebGLFramebuffer; use crate::dom::webglobject::WebGLObject; use crate::dom::webglrenderingcontext::WebGLRenderingContext; use canvas_traits::webgl::{webgl_channel, TexDataType, TexFormat, WebGLResult, WebGLTextureId}; @@ -48,6 +49,8 @@ pub struct WebGLTexture { mag_filter: Cell, /// True if this texture is used for the DOMToTexture feature. attached_to_dom: Cell, + /// Framebuffer that this texture is attached to. + attached_framebuffer: MutNullableDom, } impl WebGLTexture { @@ -63,6 +66,7 @@ impl WebGLTexture { mag_filter: Cell::new(constants::LINEAR), image_info_array: DomRefCell::new([ImageInfo::new(); MAX_LEVEL_COUNT * MAX_FACE_COUNT]), attached_to_dom: Cell::new(false), + attached_framebuffer: Default::default(), } } @@ -138,6 +142,11 @@ impl WebGLTexture { let face_index = self.face_index_for_target(&target); self.set_image_infos_at_level_and_face(level, face_index, image_info); + + if let Some(fb) = self.attached_framebuffer.get() { + fb.update_status(); + } + Ok(()) } @@ -405,6 +414,14 @@ impl WebGLTexture { pub fn set_attached_to_dom(&self) { self.attached_to_dom.set(true); } + + pub fn attach_to_framebuffer(&self, fb: &WebGLFramebuffer) { + self.attached_framebuffer.set(Some(fb)); + } + + pub fn detach_from_framebuffer(&self) { + self.attached_framebuffer.set(None); + } } impl Drop for WebGLTexture {