Always use a WebGLVertexArrayObject to handle vertex attribs

This lets us clean up how buffers are reference-counted.
This commit is contained in:
Anthony Ramine 2018-08-01 13:44:09 +02:00
parent 3e09d7270a
commit fba6d801a1
6 changed files with 442 additions and 561 deletions

View file

@ -3,9 +3,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// https://www.khronos.org/registry/webgl/specs/latest/1.0/webgl.idl
use canvas_traits::webgl::{WebGLBufferId, WebGLCommand, WebGLError, WebGLResult, WebGLVertexArrayId};
use canvas_traits::webgl::{WebGLBufferId, WebGLCommand, WebGLError, WebGLResult};
use canvas_traits::webgl::webgl_channel;
use dom::bindings::cell::DomRefCell;
use dom::bindings::codegen::Bindings::WebGLBufferBinding;
use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants;
use dom::bindings::inheritance::Castable;
@ -15,8 +14,6 @@ use dom::webglobject::WebGLObject;
use dom::webglrenderingcontext::WebGLRenderingContext;
use dom_struct::dom_struct;
use std::cell::Cell;
use std::collections::HashSet;
#[dom_struct]
pub struct WebGLBuffer {
@ -25,10 +22,8 @@ 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>,
// The Vertex Array Objects that are referencing this buffer
vao_references: DomRefCell<Option<HashSet<WebGLVertexArrayId>>>,
pending_delete: Cell<bool>,
marked_for_deletion: Cell<bool>,
attached_counter: Cell<u32>,
/// https://www.khronos.org/registry/OpenGL-Refpages/es2.0/xhtml/glGetBufferParameteriv.xml
usage: Cell<u32>,
}
@ -37,12 +32,11 @@ impl WebGLBuffer {
fn new_inherited(context: &WebGLRenderingContext, id: WebGLBufferId) -> Self {
Self {
webgl_object: WebGLObject::new_inherited(context),
id: id,
target: Cell::new(None),
capacity: Cell::new(0),
is_deleted: Cell::new(false),
vao_references: DomRefCell::new(None),
pending_delete: Cell::new(false),
id,
target: Default::default(),
capacity: Default::default(),
marked_for_deletion: Default::default(),
attached_counter: Default::default(),
usage: Cell::new(WebGLRenderingContextConstants::STATIC_DRAW),
}
}
@ -68,24 +62,6 @@ impl WebGLBuffer {
self.id
}
// NB: Only valid buffer targets come here
pub fn bind(&self, target: u32) -> WebGLResult<()> {
if self.is_deleted() || self.is_pending_delete() {
return Err(WebGLError::InvalidOperation);
}
if let Some(previous_target) = self.target.get() {
if target != previous_target {
return Err(WebGLError::InvalidOperation);
}
} else {
self.target.set(Some(target));
}
self.upcast::<WebGLObject>()
.context()
.send_command(WebGLCommand::BindBuffer(target, Some(self.id)));
Ok(())
}
pub fn buffer_data<T>(&self, target: u32, data: T, usage: u32) -> WebGLResult<()>
where
T: Into<Vec<u8>>,
@ -115,56 +91,59 @@ impl WebGLBuffer {
self.capacity.get()
}
pub fn delete(&self) {
if !self.is_deleted.get() {
self.is_deleted.set(true);
self.upcast::<WebGLObject>()
.context()
.send_command(WebGLCommand::DeleteBuffer(self.id));
pub fn mark_for_deletion(&self) {
if self.marked_for_deletion.get() {
return;
}
self.marked_for_deletion.set(true);
if self.is_deleted() {
self.delete();
}
}
fn delete(&self) {
assert!(self.is_deleted());
self.upcast::<WebGLObject>()
.context()
.send_command(WebGLCommand::DeleteBuffer(self.id));
}
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()
}
pub fn is_attached_to_vao(&self) -> bool {
self.vao_references.borrow().as_ref().map_or(false, |vaos| !vaos.is_empty())
}
pub fn set_pending_delete(&self) {
self.pending_delete.set(true);
}
pub fn is_pending_delete(&self) -> bool {
self.pending_delete.get()
}
pub fn add_vao_reference(&self, id: WebGLVertexArrayId) {
let mut vao_refs = self.vao_references.borrow_mut();
if let Some(ref mut vao_refs) = *vao_refs {
vao_refs.insert(id);
return;
pub fn set_target(&self, target: u32) -> WebGLResult<()> {
if self.target.get().map_or(false, |t| t != target) {
return Err(WebGLError::InvalidOperation);
}
let mut map = HashSet::new();
map.insert(id);
*vao_refs = Some(map);
self.target.set(Some(target));
Ok(())
}
pub fn remove_vao_reference(&self, id: WebGLVertexArrayId) {
if let Some(ref mut vao_refs) = *self.vao_references.borrow_mut() {
if vao_refs.take(&id).is_some() && self.pending_delete.get() {
// WebGL spec: The deleted buffers should no longer be valid when the VAOs are deleted
self.upcast::<WebGLObject>()
.context()
.send_command(WebGLCommand::DeleteBuffer(self.id));
self.is_deleted.set(true);
}
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) {
self.attached_counter.set(
self.attached_counter.get().checked_sub(1).expect("refcount underflowed"),
);
if self.is_deleted() {
self.delete();
}
}