diff options
Diffstat (limited to 'components/script')
-rw-r--r-- | components/script/dom/webglframebuffer.rs | 7 | ||||
-rw-r--r-- | components/script/dom/webglrenderingcontext.rs | 62 |
2 files changed, 68 insertions, 1 deletions
diff --git a/components/script/dom/webglframebuffer.rs b/components/script/dom/webglframebuffer.rs index 6e426fa0969..cd212d644bf 100644 --- a/components/script/dom/webglframebuffer.rs +++ b/components/script/dom/webglframebuffer.rs @@ -5,6 +5,7 @@ // https://www.khronos.org/registry/webgl/specs/latest/1.0/webgl.idl use canvas_traits::CanvasMsg; use dom::bindings::codegen::Bindings::WebGLFramebufferBinding; +use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants; use dom::bindings::global::GlobalRef; use dom::bindings::js::Root; use dom::bindings::reflector::reflect_dom_object; @@ -79,6 +80,12 @@ impl WebGLFramebuffer { self.is_deleted.get() } + pub fn check_status(&self) -> u32 { + // Until we build support for attaching renderbuffers or + // textures, all user FBOs are incomplete. + return constants::FRAMEBUFFER_UNSUPPORTED; + } + pub fn target(&self) -> Option<u32> { self.target.get() } diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index 3fc63349634..f42eeab4dbf 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -212,6 +212,38 @@ impl WebGLRenderingContext { } } + // Helper function for validating framebuffer completeness in + // calls touching the framebuffer. From the GLES 2.0.25 spec, + // page 119: + // + // "Effects of Framebuffer Completeness on Framebuffer + // Operations + // + // If the currently bound framebuffer is not framebuffer + // complete, then it is an error to attempt to use the + // framebuffer for writing or reading. This means that + // rendering commands such as DrawArrays and DrawElements, as + // well as commands that read the framebuffer such as + // ReadPixels and CopyTexSubImage, will generate the error + // INVALID_FRAMEBUFFER_OPERATION if called while the + // framebuffer is not framebuffer complete." + // + // The WebGL spec mentions a couple more operations that trigger + // this: clear() and getParameter(IMPLEMENTATION_COLOR_READ_*). + fn validate_framebuffer_complete(&self) -> bool { + match self.bound_framebuffer.get() { + Some(fb) => match fb.check_status() { + constants::FRAMEBUFFER_COMPLETE => return true, + _ => { + self.webgl_error(InvalidFramebufferOperation); + return false; + } + }, + // The default framebuffer is always complete. + None => return true, + } + } + fn tex_parameter(&self, target: u32, name: u32, value: TexParameterValue) { let texture = match target { constants::TEXTURE_2D => self.bound_texture_2d.get(), @@ -591,6 +623,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { let error_code = if let Some(error) = self.last_error.get() { match error { WebGLError::InvalidEnum => constants::INVALID_ENUM, + WebGLError::InvalidFramebufferOperation => constants::INVALID_FRAMEBUFFER_OPERATION, WebGLError::InvalidValue => constants::INVALID_VALUE, WebGLError::InvalidOperation => constants::INVALID_OPERATION, WebGLError::OutOfMemory => constants::OUT_OF_MEMORY, @@ -748,9 +781,11 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { // case: Chromium currently unbinds, and Gecko silently // returns. The conformance tests don't cover this case. Some(renderbuffer) if !renderbuffer.is_deleted() => { - renderbuffer.bind(target) + self.bound_renderbuffer.set(Some(renderbuffer)); + renderbuffer.bind(target); } _ => { + self.bound_renderbuffer.set(None); // Unbind the currently bound renderbuffer self.ipc_renderer .send(CanvasMsg::WebGL(WebGLCommand::BindRenderbuffer(target, None))) @@ -773,6 +808,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { Err(err) => return self.webgl_error(err), } } else { + slot.set(None); // Unbind the currently bound texture self.ipc_renderer .send(CanvasMsg::WebGL(WebGLCommand::BindTexture(target, None))) @@ -882,6 +918,10 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8 fn CopyTexImage2D(&self, target: u32, level: i32, internal_format: u32, x: i32, y: i32, width: i32, height: i32, border: i32) { + if !self.validate_framebuffer_complete() { + return; + } + let validator = CommonTexImage2DValidator::new(self, target, level, internal_format, width, height, border); @@ -935,6 +975,10 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8 fn CopyTexSubImage2D(&self, target: u32, level: i32, xoffset: i32, yoffset: i32, x: i32, y: i32, width: i32, height: i32) { + if !self.validate_framebuffer_complete() { + return; + } + // NB: We use a dummy (valid) format and border in order to reuse the // common validations, but this should have its own validator. let validator = CommonTexImage2DValidator::new(self, target, level, @@ -974,6 +1018,10 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.11 fn Clear(&self, mask: u32) { + if !self.validate_framebuffer_complete() { + return; + } + self.ipc_renderer.send(CanvasMsg::WebGL(WebGLCommand::Clear(mask))).unwrap(); self.mark_as_dirty(); } @@ -1200,6 +1248,10 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { return self.webgl_error(InvalidValue); } + if !self.validate_framebuffer_complete() { + return; + } + self.ipc_renderer .send(CanvasMsg::WebGL(WebGLCommand::DrawArrays(mode, first, count))) .unwrap(); @@ -1236,6 +1288,10 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { return self.webgl_error(InvalidOperation); } + if !self.validate_framebuffer_complete() { + return; + } + match mode { constants::POINTS | constants::LINE_STRIP | constants::LINE_LOOP | constants::LINES | @@ -1504,6 +1560,10 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { None => return self.webgl_error(InvalidValue), }; + if !self.validate_framebuffer_complete() { + return; + } + match unsafe { JS_GetArrayBufferViewType(pixels) } { Type::Uint8 => (), _ => return self.webgl_error(InvalidOperation) |