/
githubmirror
/
servo
Обзор
Документация
Войти
/
githubmirror
/
servo
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
components/script/dom/webgl/webglbuffer.rs
282 строки
9 KB
Glenn Skrzypczak
script: Remove most `CanGc` from `dom/webgl` (#45891)
24 июн 2026, 00:44
Не верифицирован
24 июн 2026, 00:44
c8d4985
Код
Авторство
О чём код?
/* 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 https://mozilla.org/MPL/2.0/. */ // https://www.khronos.org/registry/webgl/specs/latest/1.0/webgl.idl use std::cell::Cell; use dom_struct::dom_struct; use js::context::JSContext; use script_bindings::reflector::{DomObject, reflect_dom_object_with_cx}; use script_bindings::weakref::WeakRef; use servo_base::generic_channel; use servo_canvas_traits::webgl::{ WebGLBufferId, WebGLCommand, WebGLError, WebGLResult, webgl_channel, }; 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::DomGlobal; use crate::dom::bindings::root::DomRoot; use crate::dom::webgl::webglobject::WebGLObject; use crate::dom::webgl::webglrenderingcontext::{Operation, WebGLRenderingContext}; fn target_is_copy_buffer(target: u32) -> bool { target == WebGL2RenderingContextConstants::COPY_READ_BUFFER || target == WebGL2RenderingContextConstants::COPY_WRITE_BUFFER } #[derive(JSTraceable, MallocSizeOf)] struct DroppableWebGLBuffer { #[no_trace] id: WebGLBufferId, marked_for_deletion: Cell<bool>, attached_counter: Cell<u32>, context: WeakRef<WebGLRenderingContext>, } impl DroppableWebGLBuffer { pub(crate) fn new( id: WebGLBufferId, marked_for_deletion: Cell<bool>, attached_counter: Cell<u32>, context: WeakRef<WebGLRenderingContext>, ) -> 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(associated_memory)] pub(crate) struct WebGLBuffer { webgl_object: WebGLObject, /// The target to which this buffer was bound the first time target: Cell<Option<u32>>, capacity: Cell<usize>, /// <https://www.khronos.org/registry/OpenGL-Refpages/es2.0/xhtml/glGetBufferParameteriv.xml> usage: Cell<u32>, droppable: DroppableWebGLBuffer, } impl WebGLBuffer { fn new_inherited(context: &WebGLRenderingContext, id: WebGLBufferId) -> Self { Self { webgl_object: WebGLObject::new_inherited(context), target: Default::default(), capacity: Default::default(), usage: Cell::new(WebGLRenderingContextConstants::STATIC_DRAW), droppable: DroppableWebGLBuffer::new( id, Default::default(), Default::default(), WeakRef::new(context), ), } } pub(crate) fn maybe_new( cx: &mut JSContext, context: &WebGLRenderingContext, ) -> Option<DomRoot<Self>> { let (sender, receiver) = webgl_channel().unwrap(); context.send_command(WebGLCommand::CreateBuffer(sender)); receiver .recv() .unwrap() .map(|id| WebGLBuffer::new(cx, context, id)) } pub(crate) fn new( cx: &mut JSContext, context: &WebGLRenderingContext, id: WebGLBufferId, ) -> DomRoot<Self> { reflect_dom_object_with_cx( Box::new(WebGLBuffer::new_inherited(context, id)), &*context.global(), cx, ) } } impl WebGLBuffer { pub(crate) fn id(&self) -> WebGLBufferId { self.droppable.id() } pub(crate) fn buffer_data(&self, target: u32, data: &[u8], usage: u32) -> WebGLResult<()> { 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.reflector() .update_memory_size(self, self.capacity.get()); self.usage.set(usage); let (sender, receiver) = generic_channel::channel().unwrap(); self.upcast() .send_command(WebGLCommand::BufferData(target, receiver, usage)); let buffer = generic_channel::GenericSharedMemory::from_bytes(data); sender.send(buffer).unwrap(); Ok(()) } pub(crate) fn capacity(&self) -> usize { self.capacity.get() } pub(crate) fn mark_for_deletion(&self, operation_fallibility: Operation) { self.droppable.mark_for_deletion(operation_fallibility); } fn delete(&self, operation_fallibility: Operation) { self.droppable.delete(operation_fallibility); } pub(crate) fn is_marked_for_deletion(&self) -> bool { 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.droppable.is_deleted() } pub(crate) fn target(&self) -> Option<u32> { self.target.get() } /// <https://registry.khronos.org/webgl/specs/latest/2.0/#5.1> fn can_bind_to(&self, new_target: u32) -> bool { if let Some(current_target) = self.target.get() && [current_target, new_target] .contains(&WebGLRenderingContextConstants::ELEMENT_ARRAY_BUFFER) { return target_is_copy_buffer(new_target) || new_target == current_target; } true } pub(crate) fn set_target_maybe(&self, target: u32) -> WebGLResult<()> { if !self.can_bind_to(target) { return Err(WebGLError::InvalidOperation); } if self.target.get().is_none() { if target_is_copy_buffer(target) { // Binding a buffer with type undefined to the COPY_READ_BUFFER or COPY_WRITE_BUFFER // binding points will set its type to other data. self.target .set(Some(WebGLRenderingContextConstants::ARRAY_BUFFER)); } else { // Calling bindBuffer, bindBufferRange or bindBufferBase with the target argument // set to any buffer binding point except COPY_READ_BUFFER or COPY_WRITE_BUFFER // will then set the WebGL buffer type of the buffer being bound according to the table above. self.target.set(Some(target)); } } Ok(()) } pub(crate) fn increment_attached_counter(&self) { 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.set_attached_counter( self.get_attached_counter() .checked_sub(1) .expect("refcount underflowed"), ); if self.is_deleted() { self.delete(operation_fallibility); } } pub(crate) fn usage(&self) -> u32 { self.usage.get() } }