diff options
Diffstat (limited to 'components/script/dom/webglrenderbuffer.rs')
-rw-r--r-- | components/script/dom/webglrenderbuffer.rs | 264 |
1 files changed, 212 insertions, 52 deletions
diff --git a/components/script/dom/webglrenderbuffer.rs b/components/script/dom/webglrenderbuffer.rs index 7094a6b3734..204fe9ab46e 100644 --- a/components/script/dom/webglrenderbuffer.rs +++ b/components/script/dom/webglrenderbuffer.rs @@ -1,20 +1,23 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ // https://www.khronos.org/registry/webgl/specs/latest/1.0/webgl.idl -use canvas_traits::CanvasMsg; -use dom::bindings::codegen::Bindings::WebGLRenderbufferBinding; -use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants; -use dom::bindings::js::Root; -use dom::bindings::reflector::reflect_dom_object; -use dom::webglobject::WebGLObject; -use dom::window::Window; +use crate::dom::bindings::codegen::Bindings::EXTColorBufferHalfFloatBinding::EXTColorBufferHalfFloatConstants; +use crate::dom::bindings::codegen::Bindings::WEBGLColorBufferFloatBinding::WEBGLColorBufferFloatConstants; +use crate::dom::bindings::codegen::Bindings::WebGL2RenderingContextBinding::WebGL2RenderingContextConstants as constants; +use crate::dom::bindings::inheritance::Castable; +use crate::dom::bindings::reflector::{reflect_dom_object, DomObject}; +use crate::dom::bindings::root::{DomRoot, MutNullableDom}; +use crate::dom::webglframebuffer::WebGLFramebuffer; +use crate::dom::webglobject::WebGLObject; +use crate::dom::webglrenderingcontext::{Operation, WebGLRenderingContext}; +use canvas_traits::webgl::{ + webgl_channel, GlType, InternalFormatIntVec, WebGLCommand, WebGLError, WebGLRenderbufferId, + WebGLResult, WebGLVersion, +}; use dom_struct::dom_struct; -use ipc_channel::ipc::IpcSender; use std::cell::Cell; -use webrender_traits; -use webrender_traits::{WebGLCommand, WebGLRenderbufferId, WebGLResult, WebGLError}; #[dom_struct] pub struct WebGLRenderbuffer { @@ -24,45 +27,41 @@ pub struct WebGLRenderbuffer { is_deleted: Cell<bool>, size: Cell<Option<(i32, i32)>>, internal_format: Cell<Option<u32>>, - #[ignore_heap_size_of = "Defined in ipc-channel"] - renderer: IpcSender<CanvasMsg>, + is_initialized: Cell<bool>, + attached_framebuffer: MutNullableDom<WebGLFramebuffer>, } impl WebGLRenderbuffer { - fn new_inherited(renderer: IpcSender<CanvasMsg>, - id: WebGLRenderbufferId) - -> WebGLRenderbuffer { - WebGLRenderbuffer { - webgl_object: WebGLObject::new_inherited(), + fn new_inherited(context: &WebGLRenderingContext, id: WebGLRenderbufferId) -> Self { + Self { + webgl_object: WebGLObject::new_inherited(context), id: id, ever_bound: Cell::new(false), is_deleted: Cell::new(false), - renderer: renderer, internal_format: Cell::new(None), size: Cell::new(None), + is_initialized: Cell::new(false), + attached_framebuffer: Default::default(), } } - pub fn maybe_new(window: &Window, renderer: IpcSender<CanvasMsg>) - -> Option<Root<WebGLRenderbuffer>> { - let (sender, receiver) = webrender_traits::channel::msg_channel().unwrap(); - renderer.send(CanvasMsg::WebGL(WebGLCommand::CreateRenderbuffer(sender))).unwrap(); - - let result = receiver.recv().unwrap(); - result.map(|renderbuffer_id| WebGLRenderbuffer::new(window, renderer, renderbuffer_id)) + pub fn maybe_new(context: &WebGLRenderingContext) -> Option<DomRoot<Self>> { + let (sender, receiver) = webgl_channel().unwrap(); + context.send_command(WebGLCommand::CreateRenderbuffer(sender)); + receiver + .recv() + .unwrap() + .map(|id| WebGLRenderbuffer::new(context, id)) } - pub fn new(window: &Window, - renderer: IpcSender<CanvasMsg>, - id: WebGLRenderbufferId) - -> Root<WebGLRenderbuffer> { - reflect_dom_object(box WebGLRenderbuffer::new_inherited(renderer, id), - window, - WebGLRenderbufferBinding::Wrap) + pub fn new(context: &WebGLRenderingContext, id: WebGLRenderbufferId) -> DomRoot<Self> { + reflect_dom_object( + Box::new(WebGLRenderbuffer::new_inherited(context, id)), + &*context.global(), + ) } } - impl WebGLRenderbuffer { pub fn id(&self) -> WebGLRenderbufferId { self.id @@ -72,16 +71,52 @@ impl WebGLRenderbuffer { self.size.get() } + pub fn internal_format(&self) -> u32 { + self.internal_format.get().unwrap_or(constants::RGBA4) + } + + pub fn mark_initialized(&self) { + self.is_initialized.set(true); + } + + pub fn is_initialized(&self) -> bool { + self.is_initialized.get() + } + pub fn bind(&self, target: u32) { self.ever_bound.set(true); - let msg = CanvasMsg::WebGL(WebGLCommand::BindRenderbuffer(target, Some(self.id))); - self.renderer.send(msg).unwrap(); + self.upcast::<WebGLObject>() + .context() + .send_command(WebGLCommand::BindRenderbuffer(target, Some(self.id))); } - pub fn delete(&self) { + pub fn delete(&self, operation_fallibility: Operation) { if !self.is_deleted.get() { self.is_deleted.set(true); - let _ = self.renderer.send(CanvasMsg::WebGL(WebGLCommand::DeleteRenderbuffer(self.id))); + + let context = self.upcast::<WebGLObject>().context(); + + /* + If a renderbuffer object is deleted while its image is attached to one or more + attachment points in a currently bound framebuffer object, then it is as if + FramebufferRenderbuffer had been called, with a renderbuffer of zero, for each + attachment point to which this image was attached in that framebuffer object. + In other words,the renderbuffer image is first detached from all attachment points + in that frame-buffer object. + - GLES 3.0, 4.4.2.3, "Attaching Renderbuffer Images to a Framebuffer" + */ + if let Some(fb) = context.get_draw_framebuffer_slot().get() { + let _ = fb.detach_renderbuffer(self); + } + if let Some(fb) = context.get_read_framebuffer_slot().get() { + let _ = fb.detach_renderbuffer(self); + } + + let cmd = WebGLCommand::DeleteRenderbuffer(self.id); + match operation_fallibility { + Operation::Fallible => context.send_command_ignored(cmd), + Operation::Infallible => context.send_command(cmd), + } } } @@ -93,29 +128,154 @@ impl WebGLRenderbuffer { self.ever_bound.get() } - pub fn storage(&self, internal_format: u32, width: i32, height: i32) -> WebGLResult<()> { + pub fn storage( + &self, + api_type: GlType, + sample_count: i32, + internal_format: u32, + width: i32, + height: i32, + ) -> WebGLResult<()> { + let is_gles = api_type == GlType::Gles; + let webgl_version = self.upcast().context().webgl_version(); + // Validate the internal_format, and save it for completeness // validation. - match internal_format { - constants::RGBA4 | - constants::DEPTH_STENCIL | - constants::DEPTH_COMPONENT16 | - constants::STENCIL_INDEX8 => - self.internal_format.set(Some(internal_format)), - + let actual_format = match internal_format { + constants::RGBA4 | constants::DEPTH_COMPONENT16 | constants::STENCIL_INDEX8 => { + internal_format + }, + constants::R8 | + constants::R8UI | + constants::R8I | + constants::R16UI | + constants::R16I | + constants::R32UI | + constants::R32I | + constants::RG8 | + constants::RG8UI | + constants::RG8I | + constants::RG16UI | + constants::RG16I | + constants::RG32UI | + constants::RG32I | + constants::RGB8 | + constants::RGBA8 | + constants::SRGB8_ALPHA8 | + constants::RGB10_A2 | + constants::RGBA8UI | + constants::RGBA8I | + constants::RGB10_A2UI | + constants::RGBA16UI | + constants::RGBA16I | + constants::RGBA32I | + constants::RGBA32UI | + constants::DEPTH_COMPONENT24 | + constants::DEPTH_COMPONENT32F | + constants::DEPTH24_STENCIL8 | + constants::DEPTH32F_STENCIL8 => match webgl_version { + WebGLVersion::WebGL1 => return Err(WebGLError::InvalidEnum), + _ => internal_format, + }, + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#6.8 + constants::DEPTH_STENCIL => constants::DEPTH24_STENCIL8, + constants::RGB5_A1 => { + // 16-bit RGBA formats are not supported on desktop GL. + if is_gles { + constants::RGB5_A1 + } else { + constants::RGBA8 + } + }, + constants::RGB565 => { + // RGB565 is not supported on desktop GL. + if is_gles { + constants::RGB565 + } else { + constants::RGB8 + } + }, + EXTColorBufferHalfFloatConstants::RGBA16F_EXT | + EXTColorBufferHalfFloatConstants::RGB16F_EXT => { + if !self + .upcast() + .context() + .extension_manager() + .is_half_float_buffer_renderable() + { + return Err(WebGLError::InvalidEnum); + } + internal_format + }, + WEBGLColorBufferFloatConstants::RGBA32F_EXT => { + if !self + .upcast() + .context() + .extension_manager() + .is_float_buffer_renderable() + { + return Err(WebGLError::InvalidEnum); + } + internal_format + }, _ => return Err(WebGLError::InvalidEnum), }; - // FIXME: Check that w/h are < MAX_RENDERBUFFER_SIZE + if webgl_version != WebGLVersion::WebGL1 { + let (sender, receiver) = webgl_channel().unwrap(); + self.upcast::<WebGLObject>().context().send_command( + WebGLCommand::GetInternalFormatIntVec( + constants::RENDERBUFFER, + internal_format, + InternalFormatIntVec::Samples, + sender, + ), + ); + let samples = receiver.recv().unwrap(); + if sample_count < 0 || sample_count > samples.get(0).cloned().unwrap_or(0) { + return Err(WebGLError::InvalidOperation); + } + } - // FIXME: Invalidate completeness after the call + self.internal_format.set(Some(internal_format)); + self.is_initialized.set(false); - let msg = CanvasMsg::WebGL(WebGLCommand::RenderbufferStorage(constants::RENDERBUFFER, - internal_format, width, height)); - self.renderer.send(msg).unwrap(); + if let Some(fb) = self.attached_framebuffer.get() { + fb.update_status(); + } - self.size.set(Some((width, height))); + let command = match sample_count { + 0 => WebGLCommand::RenderbufferStorage( + constants::RENDERBUFFER, + actual_format, + width, + height, + ), + _ => WebGLCommand::RenderbufferStorageMultisample( + constants::RENDERBUFFER, + sample_count, + actual_format, + width, + height, + ), + }; + self.upcast::<WebGLObject>().context().send_command(command); + self.size.set(Some((width, height))); 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 { + fn drop(&mut self) { + self.delete(Operation::Fallible); + } } |