diff --git a/components/script/dom/webglbuffer.rs b/components/script/dom/webglbuffer.rs index 3b1a1076dcc..4aa64e90a7d 100644 --- a/components/script/dom/webglbuffer.rs +++ b/components/script/dom/webglbuffer.rs @@ -8,6 +8,7 @@ use std::cell::Cell; use canvas_traits::webgl::{WebGLBufferId, WebGLCommand, WebGLError, WebGLResult, webgl_channel}; use dom_struct::dom_struct; use ipc_channel::ipc; +use script_bindings::weakref::WeakRef; use crate::dom::bindings::codegen::Bindings::WebGL2RenderingContextBinding::WebGL2RenderingContextConstants; use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants; @@ -23,30 +24,112 @@ fn target_is_copy_buffer(target: u32) -> bool { target == WebGL2RenderingContextConstants::COPY_WRITE_BUFFER } +#[derive(JSTraceable, MallocSizeOf)] +struct DroppableWebGLBuffer { + #[no_trace] + id: WebGLBufferId, + marked_for_deletion: Cell, + attached_counter: Cell, + context: WeakRef, +} + +impl DroppableWebGLBuffer { + pub(crate) fn new( + id: WebGLBufferId, + marked_for_deletion: Cell, + attached_counter: Cell, + context: WeakRef, + ) -> Self { + Self { + id, + marked_for_deletion, + attached_counter, + context, + } + } +} + +impl DroppableWebGLBuffer { + pub(crate) fn is_marked_for_deletion(&self) -> bool { + self.marked_for_deletion.get() + } + + pub(crate) fn set_marked_for_deletion(&self, marked_for_deletion: bool) { + self.marked_for_deletion.set(marked_for_deletion); + } + + pub(crate) fn get_attached_counter(&self) -> u32 { + self.attached_counter.get() + } + + pub(crate) fn set_attached_counter(&self, attached_counter: u32) { + self.attached_counter.set(attached_counter); + } + + pub(crate) fn id(&self) -> WebGLBufferId { + self.id + } + + pub(crate) fn is_attached(&self) -> bool { + self.get_attached_counter() != 0 + } + + pub(crate) fn is_deleted(&self) -> bool { + self.is_marked_for_deletion() && !self.is_attached() + } + + pub(crate) fn delete(&self, operation_fallibility: Operation) { + assert!(self.is_deleted()); + if let Some(context) = self.context.root() { + let cmd = WebGLCommand::DeleteBuffer(self.id); + match operation_fallibility { + Operation::Fallible => context.send_command_ignored(cmd), + Operation::Infallible => context.send_command(cmd), + } + } + } + + pub(crate) fn mark_for_deletion(&self, operation_fallibility: Operation) { + if self.is_marked_for_deletion() { + return; + } + self.set_marked_for_deletion(true); + if self.is_deleted() { + self.delete(operation_fallibility); + } + } +} + +impl Drop for DroppableWebGLBuffer { + fn drop(&mut self) { + self.mark_for_deletion(Operation::Fallible); + } +} + #[dom_struct] pub(crate) struct WebGLBuffer { webgl_object: WebGLObject, - #[no_trace] - id: WebGLBufferId, /// The target to which this buffer was bound the first time target: Cell>, capacity: Cell, - marked_for_deletion: Cell, - attached_counter: Cell, /// usage: Cell, + droppable: DroppableWebGLBuffer, } impl WebGLBuffer { 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), + droppable: DroppableWebGLBuffer::new( + id, + Default::default(), + Default::default(), + WeakRef::new(context), + ), } } @@ -77,7 +160,7 @@ impl WebGLBuffer { impl WebGLBuffer { pub(crate) fn id(&self) -> WebGLBufferId { - self.id + self.droppable.id() } pub(crate) fn buffer_data(&self, target: u32, data: &[u8], usage: u32) -> WebGLResult<()> { @@ -109,31 +192,27 @@ impl WebGLBuffer { } pub(crate) 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); - } + self.droppable.mark_for_deletion(operation_fallibility); } fn delete(&self, operation_fallibility: Operation) { - assert!(self.is_deleted()); - let context = self.upcast::().context(); - let cmd = WebGLCommand::DeleteBuffer(self.id); - match operation_fallibility { - Operation::Fallible => context.send_command_ignored(cmd), - Operation::Infallible => context.send_command(cmd), - } + self.droppable.delete(operation_fallibility); } pub(crate) fn is_marked_for_deletion(&self) -> bool { - self.marked_for_deletion.get() + self.droppable.is_marked_for_deletion() + } + + fn get_attached_counter(&self) -> u32 { + self.droppable.get_attached_counter() + } + + fn set_attached_counter(&self, attached_counter: u32) { + self.droppable.set_attached_counter(attached_counter); } pub(crate) fn is_deleted(&self) -> bool { - self.marked_for_deletion.get() && !self.is_attached() + self.droppable.is_deleted() } pub(crate) fn target(&self) -> Option { @@ -161,23 +240,17 @@ impl WebGLBuffer { Ok(()) } - pub(crate) fn is_attached(&self) -> bool { - self.attached_counter.get() != 0 - } - pub(crate) fn increment_attached_counter(&self) { - self.attached_counter.set( - self.attached_counter - .get() + self.set_attached_counter( + self.get_attached_counter() .checked_add(1) .expect("refcount overflowed"), ); } pub(crate) fn decrement_attached_counter(&self, operation_fallibility: Operation) { - self.attached_counter.set( - self.attached_counter - .get() + self.set_attached_counter( + self.get_attached_counter() .checked_sub(1) .expect("refcount underflowed"), ); @@ -190,9 +263,3 @@ impl WebGLBuffer { self.usage.get() } } - -impl Drop for WebGLBuffer { - fn drop(&mut self) { - self.mark_for_deletion(Operation::Fallible); - } -} diff --git a/components/script_bindings/codegen/Bindings.conf b/components/script_bindings/codegen/Bindings.conf index 93691f3bd5f..eb56cfee88c 100644 --- a/components/script_bindings/codegen/Bindings.conf +++ b/components/script_bindings/codegen/Bindings.conf @@ -640,6 +640,7 @@ DOMInterfaces = { 'WebGLRenderingContext': { 'canGc': ['MakeXRCompatible'], + 'weakReferenceable': True, }, 'WebGL2RenderingContext': {