diff options
Diffstat (limited to 'components/script/dom/webglbuffer.rs')
-rw-r--r-- | components/script/dom/webglbuffer.rs | 198 |
1 files changed, 132 insertions, 66 deletions
diff --git a/components/script/dom/webglbuffer.rs b/components/script/dom/webglbuffer.rs index 6678b3d0b92..f81270d8240 100644 --- a/components/script/dom/webglbuffer.rs +++ b/components/script/dom/webglbuffer.rs @@ -1,19 +1,25 @@ /* 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::WebGLBufferBinding; -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::WebGL2RenderingContextBinding::WebGL2RenderingContextConstants; +use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants; +use crate::dom::bindings::inheritance::Castable; +use crate::dom::bindings::reflector::{reflect_dom_object, DomObject}; +use crate::dom::bindings::root::DomRoot; +use crate::dom::webglobject::WebGLObject; +use crate::dom::webglrenderingcontext::{Operation, WebGLRenderingContext}; +use canvas_traits::webgl::webgl_channel; +use canvas_traits::webgl::{WebGLBufferId, WebGLCommand, WebGLError, WebGLResult}; use dom_struct::dom_struct; -use ipc_channel::ipc::IpcSender; +use ipc_channel::ipc; use std::cell::Cell; -use webrender_traits; -use webrender_traits::{WebGLBufferId, WebGLCommand, WebGLError, WebGLResult}; + +fn target_is_copy_buffer(target: u32) -> bool { + target == WebGL2RenderingContextConstants::COPY_READ_BUFFER || + target == WebGL2RenderingContextConstants::COPY_WRITE_BUFFER +} #[dom_struct] pub struct WebGLBuffer { @@ -22,75 +28,68 @@ pub struct WebGLBuffer { /// The target to which this buffer was bound the first time target: Cell<Option<u32>>, capacity: Cell<usize>, - is_deleted: Cell<bool>, - #[ignore_heap_size_of = "Defined in ipc-channel"] - renderer: IpcSender<CanvasMsg>, + marked_for_deletion: Cell<bool>, + attached_counter: Cell<u32>, + /// https://www.khronos.org/registry/OpenGL-Refpages/es2.0/xhtml/glGetBufferParameteriv.xml + usage: Cell<u32>, } impl WebGLBuffer { - fn new_inherited(renderer: IpcSender<CanvasMsg>, - id: WebGLBufferId) - -> WebGLBuffer { - WebGLBuffer { - webgl_object: WebGLObject::new_inherited(), - id: id, - target: Cell::new(None), - capacity: Cell::new(0), - is_deleted: Cell::new(false), - renderer: renderer, + fn new_inherited(context: &WebGLRenderingContext, id: WebGLBufferId) -> Self { + Self { + webgl_object: WebGLObject::new_inherited(context), + id, + target: Default::default(), + capacity: Default::default(), + marked_for_deletion: Default::default(), + attached_counter: Default::default(), + usage: Cell::new(WebGLRenderingContextConstants::STATIC_DRAW), } } - pub fn maybe_new(window: &Window, renderer: IpcSender<CanvasMsg>) - -> Option<Root<WebGLBuffer>> { - let (sender, receiver) = webrender_traits::channel::msg_channel().unwrap(); - renderer.send(CanvasMsg::WebGL(WebGLCommand::CreateBuffer(sender))).unwrap(); - - let result = receiver.recv().unwrap(); - result.map(|buffer_id| WebGLBuffer::new(window, renderer, buffer_id)) + pub fn maybe_new(context: &WebGLRenderingContext) -> Option<DomRoot<Self>> { + let (sender, receiver) = webgl_channel().unwrap(); + context.send_command(WebGLCommand::CreateBuffer(sender)); + receiver + .recv() + .unwrap() + .map(|id| WebGLBuffer::new(context, id)) } - pub fn new(window: &Window, - renderer: IpcSender<CanvasMsg>, - id: WebGLBufferId) - -> Root<WebGLBuffer> { - reflect_dom_object(box WebGLBuffer::new_inherited(renderer, id), - window, WebGLBufferBinding::Wrap) + pub fn new(context: &WebGLRenderingContext, id: WebGLBufferId) -> DomRoot<Self> { + reflect_dom_object( + Box::new(WebGLBuffer::new_inherited(context, id)), + &*context.global(), + ) } } - impl WebGLBuffer { pub fn id(&self) -> WebGLBufferId { self.id } - // NB: Only valid buffer targets come here - pub fn bind(&self, target: u32) -> WebGLResult<()> { - if let Some(previous_target) = self.target.get() { - if target != previous_target { - return Err(WebGLError::InvalidOperation); - } - } else { - self.target.set(Some(target)); - } - let msg = CanvasMsg::WebGL(WebGLCommand::BindBuffer(target, Some(self.id))); - self.renderer.send(msg).unwrap(); - - Ok(()) - } - pub fn buffer_data(&self, target: u32, data: &[u8], usage: u32) -> WebGLResult<()> { - if let Some(previous_target) = self.target.get() { - if target != previous_target { - return Err(WebGLError::InvalidOperation); - } + match usage { + WebGLRenderingContextConstants::STREAM_DRAW | + WebGLRenderingContextConstants::STATIC_DRAW | + WebGLRenderingContextConstants::DYNAMIC_DRAW | + WebGL2RenderingContextConstants::STATIC_READ | + WebGL2RenderingContextConstants::DYNAMIC_READ | + WebGL2RenderingContextConstants::STREAM_READ | + WebGL2RenderingContextConstants::STATIC_COPY | + WebGL2RenderingContextConstants::DYNAMIC_COPY | + WebGL2RenderingContextConstants::STREAM_COPY => (), + _ => return Err(WebGLError::InvalidEnum), } - self.capacity.set(data.len()); - self.renderer - .send(CanvasMsg::WebGL(WebGLCommand::BufferData(target, data.to_vec(), usage))) - .unwrap(); + self.capacity.set(data.len()); + self.usage.set(usage); + let (sender, receiver) = ipc::bytes_channel().unwrap(); + self.upcast::<WebGLObject>() + .context() + .send_command(WebGLCommand::BufferData(target, receiver, usage)); + sender.send(data).unwrap(); Ok(()) } @@ -98,24 +97,91 @@ impl WebGLBuffer { self.capacity.get() } - pub fn delete(&self) { - if !self.is_deleted.get() { - self.is_deleted.set(true); - let _ = self.renderer.send(CanvasMsg::WebGL(WebGLCommand::DeleteBuffer(self.id))); + pub fn mark_for_deletion(&self, operation_fallibility: Operation) { + if self.marked_for_deletion.get() { + return; + } + self.marked_for_deletion.set(true); + if self.is_deleted() { + self.delete(operation_fallibility); + } + } + + fn delete(&self, operation_fallibility: Operation) { + assert!(self.is_deleted()); + let context = self.upcast::<WebGLObject>().context(); + let cmd = WebGLCommand::DeleteBuffer(self.id); + match operation_fallibility { + Operation::Fallible => context.send_command_ignored(cmd), + Operation::Infallible => context.send_command(cmd), } } + pub fn is_marked_for_deletion(&self) -> bool { + self.marked_for_deletion.get() + } + pub fn is_deleted(&self) -> bool { - self.is_deleted.get() + self.marked_for_deletion.get() && !self.is_attached() } pub fn target(&self) -> Option<u32> { self.target.get() } + + fn can_bind_to(&self, new_target: u32) -> bool { + if let Some(current_target) = self.target.get() { + if [current_target, new_target] + .contains(&WebGLRenderingContextConstants::ELEMENT_ARRAY_BUFFER) + { + return target_is_copy_buffer(new_target) || new_target == current_target; + } + } + true + } + + pub fn set_target_maybe(&self, target: u32) -> WebGLResult<()> { + if !self.can_bind_to(target) { + return Err(WebGLError::InvalidOperation); + } + if !target_is_copy_buffer(target) { + self.target.set(Some(target)); + } + Ok(()) + } + + pub fn is_attached(&self) -> bool { + self.attached_counter.get() != 0 + } + + pub fn increment_attached_counter(&self) { + self.attached_counter.set( + self.attached_counter + .get() + .checked_add(1) + .expect("refcount overflowed"), + ); + } + + pub fn decrement_attached_counter(&self, operation_fallibility: Operation) { + self.attached_counter.set( + self.attached_counter + .get() + .checked_sub(1) + .expect("refcount underflowed"), + ); + if self.is_deleted() { + self.delete(operation_fallibility); + } + } + + pub fn usage(&self) -> u32 { + self.usage.get() + } } impl Drop for WebGLBuffer { fn drop(&mut self) { - self.delete(); + self.mark_for_deletion(Operation::Fallible); } } |