Add VertexArrayObject support for WebGL2

The implementation was already in place for OpenGL ES.
My approach with this patch is to add support for WebGL2 by
sharing the implementation between the WebGL2 and GLES.
This commit is contained in:
Istvan Miklos 2020-03-05 15:51:18 +01:00 committed by Josh Matthews
parent 4b1bb895a3
commit 1b4a3d8987
20 changed files with 815 additions and 371 deletions

View file

@ -527,6 +527,7 @@ pub mod userscripts;
pub mod validation;
pub mod validitystate;
pub mod values;
pub mod vertexarrayobject;
pub mod videotrack;
pub mod videotracklist;
pub mod virtualmethods;
@ -560,6 +561,7 @@ pub mod webglsync;
pub mod webgltexture;
pub mod webgltransformfeedback;
pub mod webgluniformlocation;
pub mod webglvertexarrayobject;
pub mod webglvertexarrayobjectoes;
pub mod websocket;
pub mod wheelevent;

View file

@ -0,0 +1,296 @@
/* 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/. */
use crate::dom::bindings::cell::{ref_filter_map, DomRefCell, Ref};
use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants;
use crate::dom::bindings::root::{Dom, MutNullableDom};
use crate::dom::webglbuffer::WebGLBuffer;
use crate::dom::webglrenderingcontext::WebGLRenderingContext;
use canvas_traits::webgl::{
ActiveAttribInfo, WebGLCommand, WebGLError, WebGLResult, WebGLVertexArrayId,
};
use std::cell::Cell;
#[derive(JSTraceable, MallocSizeOf)]
#[unrooted_must_root_lint::must_root]
pub struct VertexArrayObject {
context: Dom<WebGLRenderingContext>,
id: Option<WebGLVertexArrayId>,
ever_bound: Cell<bool>,
is_deleted: Cell<bool>,
vertex_attribs: DomRefCell<Box<[VertexAttribData]>>,
element_array_buffer: MutNullableDom<WebGLBuffer>,
}
impl VertexArrayObject {
pub fn new(context: &WebGLRenderingContext, id: Option<WebGLVertexArrayId>) -> Self {
let max_vertex_attribs = context.limits().max_vertex_attribs as usize;
Self {
context: Dom::from_ref(context),
id,
ever_bound: Default::default(),
is_deleted: Default::default(),
vertex_attribs: DomRefCell::new(vec![Default::default(); max_vertex_attribs].into()),
element_array_buffer: Default::default(),
}
}
pub fn id(&self) -> Option<WebGLVertexArrayId> {
self.id
}
pub fn is_deleted(&self) -> bool {
self.is_deleted.get()
}
pub fn delete(&self, fallible: bool) {
assert!(self.id.is_some());
if self.is_deleted.get() {
return;
}
self.is_deleted.set(true);
let cmd = WebGLCommand::DeleteVertexArray(self.id.unwrap());
if fallible {
self.context.send_command_ignored(cmd);
} else {
self.context.send_command(cmd);
}
for attrib_data in &**self.vertex_attribs.borrow() {
if let Some(buffer) = attrib_data.buffer() {
buffer.decrement_attached_counter();
}
}
if let Some(buffer) = self.element_array_buffer.get() {
buffer.decrement_attached_counter();
}
}
pub fn ever_bound(&self) -> bool {
return self.ever_bound.get();
}
pub fn set_ever_bound(&self) {
self.ever_bound.set(true);
}
pub fn element_array_buffer(&self) -> &MutNullableDom<WebGLBuffer> {
&self.element_array_buffer
}
pub fn get_vertex_attrib(&self, index: u32) -> Option<Ref<VertexAttribData>> {
ref_filter_map(self.vertex_attribs.borrow(), |attribs| {
attribs.get(index as usize)
})
}
pub fn vertex_attrib_pointer(
&self,
index: u32,
size: i32,
type_: u32,
normalized: bool,
stride: i32,
offset: i64,
) -> WebGLResult<()> {
let mut attribs = self.vertex_attribs.borrow_mut();
let data = attribs
.get_mut(index as usize)
.ok_or(WebGLError::InvalidValue)?;
if size < 1 || size > 4 {
return Err(WebGLError::InvalidValue);
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#BUFFER_OFFSET_AND_STRIDE
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#VERTEX_STRIDE
if stride < 0 || stride > 255 || offset < 0 {
return Err(WebGLError::InvalidValue);
}
let bytes_per_component: i32 = match type_ {
constants::BYTE | constants::UNSIGNED_BYTE => 1,
constants::SHORT | constants::UNSIGNED_SHORT => 2,
constants::FLOAT => 4,
_ => return Err(WebGLError::InvalidEnum),
};
if offset % bytes_per_component as i64 > 0 || stride % bytes_per_component > 0 {
return Err(WebGLError::InvalidOperation);
}
let buffer = self.context.array_buffer();
match buffer {
Some(ref buffer) => buffer.increment_attached_counter(),
None if offset != 0 => {
// https://github.com/KhronosGroup/WebGL/pull/2228
return Err(WebGLError::InvalidOperation);
},
_ => {},
}
self.context.send_command(WebGLCommand::VertexAttribPointer(
index,
size,
type_,
normalized,
stride,
offset as u32,
));
if let Some(old) = data.buffer() {
old.decrement_attached_counter();
}
*data = VertexAttribData {
enabled_as_array: data.enabled_as_array,
size: size as u8,
type_,
bytes_per_vertex: size as u8 * bytes_per_component as u8,
normalized,
stride: stride as u8,
offset: offset as u32,
buffer: buffer.map(|b| Dom::from_ref(&*b)),
divisor: data.divisor,
};
Ok(())
}
pub fn vertex_attrib_divisor(&self, index: u32, value: u32) {
self.vertex_attribs.borrow_mut()[index as usize].divisor = value;
}
pub fn enabled_vertex_attrib_array(&self, index: u32, value: bool) {
self.vertex_attribs.borrow_mut()[index as usize].enabled_as_array = value;
}
pub fn unbind_buffer(&self, buffer: &WebGLBuffer) {
for attrib in &mut **self.vertex_attribs.borrow_mut() {
if let Some(b) = attrib.buffer() {
if b.id() != buffer.id() {
continue;
}
b.decrement_attached_counter();
}
attrib.buffer = None;
}
if self
.element_array_buffer
.get()
.map_or(false, |b| buffer == &*b)
{
buffer.decrement_attached_counter();
self.element_array_buffer.set(None);
}
}
pub fn validate_for_draw(
&self,
required_len: u32,
instance_count: u32,
active_attribs: &[ActiveAttribInfo],
) -> WebGLResult<()> {
// TODO(nox): Cache limits per VAO.
let attribs = self.vertex_attribs.borrow();
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#6.2
if attribs
.iter()
.any(|data| data.enabled_as_array && data.buffer.is_none())
{
return Err(WebGLError::InvalidOperation);
}
let mut has_active_attrib = false;
let mut has_divisor_0 = false;
for active_info in active_attribs {
if active_info.location < 0 {
continue;
}
has_active_attrib = true;
let attrib = &attribs[active_info.location as usize];
if attrib.divisor == 0 {
has_divisor_0 = true;
}
if !attrib.enabled_as_array {
continue;
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#6.6
if required_len > 0 && instance_count > 0 {
let max_vertices = attrib.max_vertices();
if attrib.divisor == 0 {
if max_vertices < required_len {
return Err(WebGLError::InvalidOperation);
}
} else if max_vertices
.checked_mul(attrib.divisor)
.map_or(false, |v| v < instance_count)
{
return Err(WebGLError::InvalidOperation);
}
}
}
if has_active_attrib && !has_divisor_0 {
return Err(WebGLError::InvalidOperation);
}
Ok(())
}
}
impl Drop for VertexArrayObject {
fn drop(&mut self) {
if self.id.is_some() {
self.delete(true);
}
}
}
#[derive(Clone, JSTraceable, MallocSizeOf)]
#[unrooted_must_root_lint::must_root]
pub struct VertexAttribData {
pub enabled_as_array: bool,
pub size: u8,
pub type_: u32,
bytes_per_vertex: u8,
pub normalized: bool,
pub stride: u8,
pub offset: u32,
pub buffer: Option<Dom<WebGLBuffer>>,
pub divisor: u32,
}
impl Default for VertexAttribData {
#[allow(unrooted_must_root)]
fn default() -> Self {
Self {
enabled_as_array: false,
size: 4,
type_: constants::FLOAT,
bytes_per_vertex: 16,
normalized: false,
stride: 0,
offset: 0,
buffer: None,
divisor: 0,
}
}
}
impl VertexAttribData {
pub fn buffer(&self) -> Option<&WebGLBuffer> {
self.buffer.as_ref().map(|b| &**b)
}
pub fn max_vertices(&self) -> u32 {
let capacity = (self.buffer().unwrap().capacity() as u32).saturating_sub(self.offset);
if capacity < self.bytes_per_vertex as u32 {
0
} else if self.stride == 0 {
capacity / self.bytes_per_vertex as u32
} else if self.stride < self.bytes_per_vertex {
(capacity - (self.bytes_per_vertex - self.stride) as u32) / self.stride as u32
} else {
let mut max = capacity / self.stride as u32;
if capacity % self.stride as u32 >= self.bytes_per_vertex as u32 {
max += 1;
}
max
}
}
}

View file

@ -36,6 +36,7 @@ use crate::dom::webglsync::WebGLSync;
use crate::dom::webgltexture::WebGLTexture;
use crate::dom::webgltransformfeedback::WebGLTransformFeedback;
use crate::dom::webgluniformlocation::WebGLUniformLocation;
use crate::dom::webglvertexarrayobject::WebGLVertexArrayObject;
use crate::dom::window::Window;
use crate::js::conversions::ToJSValConvertible;
use crate::script_runtime::JSContext;
@ -181,6 +182,10 @@ impl WebGL2RenderingContext {
self.base.recreate(size)
}
pub fn current_vao(&self) -> DomRoot<WebGLVertexArrayObject> {
self.base.current_vao_webgl2()
}
pub fn base_context(&self) -> DomRoot<WebGLRenderingContext> {
DomRoot::from_ref(&*self.base)
}
@ -193,6 +198,7 @@ impl WebGL2RenderingContext {
constants::PIXEL_UNPACK_BUFFER => Ok(self.bound_pixel_unpack_buffer.get()),
constants::TRANSFORM_FEEDBACK_BUFFER => Ok(self.bound_transform_feedback_buffer.get()),
constants::UNIFORM_BUFFER => Ok(self.bound_uniform_buffer.get()),
constants::ELEMENT_ARRAY_BUFFER => Ok(self.current_vao().element_array_buffer().get()),
_ => self.base.bound_buffer(target),
}
}
@ -777,6 +783,15 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
self.current_transform_feedback.get()
);
},
constants::ELEMENT_ARRAY_BUFFER_BINDING => unsafe {
let buffer = self.current_vao().element_array_buffer().get();
return optional_root_object_to_js_or_null!(*cx, buffer);
},
constants::VERTEX_ARRAY_BINDING => unsafe {
let vao = self.current_vao();
let vao = vao.id().map(|_| &*vao);
return optional_root_object_to_js_or_null!(*cx, vao);
},
// NOTE: DRAW_FRAMEBUFFER_BINDING is the same as FRAMEBUFFER_BINDING, handled on the WebGL1 side
constants::READ_FRAMEBUFFER_BINDING => unsafe {
return optional_root_object_to_js_or_null!(
@ -942,6 +957,7 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
/// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.2
fn BindBuffer(&self, target: u32, buffer: Option<&WebGLBuffer>) {
let current_vao;
let slot = match target {
constants::COPY_READ_BUFFER => &self.bound_copy_read_buffer,
constants::COPY_WRITE_BUFFER => &self.bound_copy_write_buffer,
@ -949,6 +965,10 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
constants::PIXEL_UNPACK_BUFFER => &self.bound_pixel_unpack_buffer,
constants::TRANSFORM_FEEDBACK_BUFFER => &self.bound_transform_feedback_buffer,
constants::UNIFORM_BUFFER => &self.bound_uniform_buffer,
constants::ELEMENT_ARRAY_BUFFER => {
current_vao = self.current_vao();
current_vao.element_array_buffer()
},
_ => return self.base.BindBuffer(target, buffer),
};
self.base.bind_buffer_maybe(&slot, target, buffer);
@ -1409,6 +1429,11 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
self.base.CreateShader(shader_type)
}
/// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.17
fn CreateVertexArray(&self) -> Option<DomRoot<WebGLVertexArrayObject>> {
self.base.create_vertex_array_webgl2()
}
/// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5
fn DeleteBuffer(&self, buffer: Option<&WebGLBuffer>) {
let buffer = match buffer {
@ -1419,7 +1444,7 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
if buffer.is_marked_for_deletion() {
return;
}
self.base.current_vao().unbind_buffer(buffer);
self.current_vao().unbind_buffer(buffer);
self.unbind_from(&self.base.array_buffer_slot(), &buffer);
self.unbind_from(&self.bound_copy_read_buffer, &buffer);
self.unbind_from(&self.bound_copy_write_buffer, &buffer);
@ -1463,6 +1488,11 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
self.base.DeleteShader(shader)
}
/// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.17
fn DeleteVertexArray(&self, vertex_array: Option<&WebGLVertexArrayObject>) {
self.base.delete_vertex_array_webgl2(vertex_array);
}
/// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.11
fn DrawArrays(&self, mode: u32, first: i32, count: i32) {
self.base.DrawArrays(mode, first, count)
@ -1662,6 +1692,11 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
self.base.IsTexture(texture)
}
/// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.17
fn IsVertexArray(&self, vertex_array: Option<&WebGLVertexArrayObject>) -> bool {
self.base.is_vertex_array_webgl2(vertex_array)
}
/// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3
fn LineWidth(&self, width: f32) {
self.base.LineWidth(width)
@ -3042,6 +3077,11 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
}
}
/// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.17
fn BindVertexArray(&self, array: Option<&WebGLVertexArrayObject>) {
self.base.bind_vertex_array_webgl2(array);
}
/// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.13
fn SamplerParameteri(&self, sampler: &WebGLSampler, pname: u32, param: i32) {
handle_potential_webgl_error!(self.base, self.base.validate_ownership(sampler), return);

View file

@ -2,6 +2,7 @@
* 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/. */
use crate::dom::bindings::cell::Ref;
use crate::dom::bindings::codegen::Bindings::ANGLEInstancedArraysBinding::ANGLEInstancedArraysConstants;
use crate::dom::bindings::codegen::Bindings::EXTBlendMinmaxBinding::EXTBlendMinmaxConstants;
use crate::dom::bindings::codegen::Bindings::OESVertexArrayObjectBinding::OESVertexArrayObjectConstants;
@ -26,6 +27,7 @@ use crate::dom::htmlcanvaselement::HTMLCanvasElement;
use crate::dom::htmliframeelement::HTMLIFrameElement;
use crate::dom::node::{document_from_node, window_from_node, Node, NodeDamage};
use crate::dom::promise::Promise;
use crate::dom::vertexarrayobject::VertexAttribData;
use crate::dom::webgl_extensions::WebGLExtensions;
use crate::dom::webgl_validations::tex_image_2d::{
CommonCompressedTexImage2DValidatorResult, CommonTexImage2DValidator,
@ -47,6 +49,7 @@ use crate::dom::webglshader::WebGLShader;
use crate::dom::webglshaderprecisionformat::WebGLShaderPrecisionFormat;
use crate::dom::webgltexture::{TexParameterValue, WebGLTexture};
use crate::dom::webgluniformlocation::WebGLUniformLocation;
use crate::dom::webglvertexarrayobject::WebGLVertexArrayObject;
use crate::dom::webglvertexarrayobjectoes::WebGLVertexArrayObjectOES;
use crate::dom::window::Window;
use crate::script_runtime::JSContext as SafeJSContext;
@ -183,6 +186,8 @@ pub struct WebGLRenderingContext {
capabilities: Capabilities,
default_vao: DomOnceCell<WebGLVertexArrayObjectOES>,
current_vao: MutNullableDom<WebGLVertexArrayObjectOES>,
default_vao_webgl2: DomOnceCell<WebGLVertexArrayObject>,
current_vao_webgl2: MutNullableDom<WebGLVertexArrayObject>,
textures: Textures,
api_type: GlType,
}
@ -242,6 +247,8 @@ impl WebGLRenderingContext {
capabilities: Default::default(),
default_vao: Default::default(),
current_vao: Default::default(),
default_vao_webgl2: Default::default(),
current_vao_webgl2: Default::default(),
textures: Textures::new(max_combined_texture_image_units),
api_type: ctx_data.api_type,
}
@ -294,6 +301,15 @@ impl WebGLRenderingContext {
})
}
pub fn current_vao_webgl2(&self) -> DomRoot<WebGLVertexArrayObject> {
self.current_vao_webgl2.or_init(|| {
DomRoot::from_ref(
self.default_vao_webgl2
.init_once(|| WebGLVertexArrayObject::new(self, None)),
)
})
}
pub fn recreate(&self, size: Size2D<u32>) {
let (sender, receiver) = webgl_channel().unwrap();
self.webgl_sender.send_resize(size, sender).unwrap();
@ -889,11 +905,18 @@ impl WebGLRenderingContext {
0
};
self.current_vao().validate_for_draw(
match self.webgl_version() {
WebGLVersion::WebGL1 => self.current_vao().validate_for_draw(
required_len,
primcount as u32,
&current_program.active_attribs(),
)?;
)?,
WebGLVersion::WebGL2 => self.current_vao_webgl2().validate_for_draw(
required_len,
primcount as u32,
&current_program.active_attribs(),
)?,
};
self.validate_framebuffer()?;
@ -950,10 +973,10 @@ impl WebGLRenderingContext {
}
let current_program = self.current_program.get().ok_or(InvalidOperation)?;
let array_buffer = self
.current_vao()
.element_array_buffer()
.get()
let array_buffer = match self.webgl_version() {
WebGLVersion::WebGL1 => self.current_vao().element_array_buffer().get(),
WebGLVersion::WebGL2 => self.current_vao_webgl2().element_array_buffer().get(),
}
.ok_or(InvalidOperation)?;
if count > 0 && primcount > 0 {
@ -965,11 +988,18 @@ impl WebGLRenderingContext {
}
// TODO(nox): Pass the correct number of vertices required.
self.current_vao().validate_for_draw(
match self.webgl_version() {
WebGLVersion::WebGL1 => self.current_vao().validate_for_draw(
0,
primcount as u32,
&current_program.active_attribs(),
)?;
)?,
WebGLVersion::WebGL2 => self.current_vao_webgl2().validate_for_draw(
0,
primcount as u32,
&current_program.active_attribs(),
)?,
};
self.validate_framebuffer()?;
@ -1003,7 +1033,12 @@ impl WebGLRenderingContext {
return self.webgl_error(InvalidValue);
}
self.current_vao().vertex_attrib_divisor(index, divisor);
match self.webgl_version() {
WebGLVersion::WebGL1 => self.current_vao().vertex_attrib_divisor(index, divisor),
WebGLVersion::WebGL2 => self
.current_vao_webgl2()
.vertex_attrib_divisor(index, divisor),
};
self.send_command(WebGLCommand::VertexAttribDivisor { index, divisor });
}
@ -1066,6 +1101,15 @@ impl WebGLRenderingContext {
.map(|id| WebGLVertexArrayObjectOES::new(self, Some(id)))
}
pub fn create_vertex_array_webgl2(&self) -> Option<DomRoot<WebGLVertexArrayObject>> {
let (sender, receiver) = webgl_channel().unwrap();
self.send_command(WebGLCommand::CreateVertexArray(sender));
receiver
.recv()
.unwrap()
.map(|id| WebGLVertexArrayObject::new(self, Some(id)))
}
pub fn delete_vertex_array(&self, vao: Option<&WebGLVertexArrayObjectOES>) {
if let Some(vao) = vao {
handle_potential_webgl_error!(self, self.validate_ownership(vao), return);
@ -1084,6 +1128,24 @@ impl WebGLRenderingContext {
}
}
pub fn delete_vertex_array_webgl2(&self, vao: Option<&WebGLVertexArrayObject>) {
if let Some(vao) = vao {
handle_potential_webgl_error!(self, self.validate_ownership(vao), return);
// The default vertex array has no id and should never be passed around.
assert!(vao.id().is_some());
if vao.is_deleted() {
return;
}
if vao == &*self.current_vao_webgl2() {
// Setting it to None will make self.current_vao() reset it to the default one
// next time it is called.
self.current_vao_webgl2.set(None);
self.send_command(WebGLCommand::BindVertexArray(None));
}
vao.delete(false);
}
}
pub fn is_vertex_array(&self, vao: Option<&WebGLVertexArrayObjectOES>) -> bool {
vao.map_or(false, |vao| {
// The default vertex array has no id and should never be passed around.
@ -1092,6 +1154,14 @@ impl WebGLRenderingContext {
})
}
pub fn is_vertex_array_webgl2(&self, vao: Option<&WebGLVertexArrayObject>) -> bool {
vao.map_or(false, |vao| {
// The default vertex array has no id and should never be passed around.
assert!(vao.id().is_some());
self.validate_ownership(vao).is_ok() && vao.ever_bound() && !vao.is_deleted()
})
}
pub fn bind_vertex_array(&self, vao: Option<&WebGLVertexArrayObjectOES>) {
if let Some(vao) = vao {
// The default vertex array has no id and should never be passed around.
@ -1108,6 +1178,22 @@ impl WebGLRenderingContext {
self.current_vao.set(vao);
}
pub fn bind_vertex_array_webgl2(&self, vao: Option<&WebGLVertexArrayObject>) {
if let Some(vao) = vao {
// The default vertex array has no id and should never be passed around.
assert!(vao.id().is_some());
handle_potential_webgl_error!(self, self.validate_ownership(vao), return);
if vao.is_deleted() {
return self.webgl_error(InvalidOperation);
}
vao.set_ever_bound();
}
self.send_command(WebGLCommand::BindVertexArray(vao.and_then(|vao| vao.id())));
// Setting it to None will make self.current_vao() reset it to the default one
// next time it is called.
self.current_vao_webgl2.set(vao);
}
fn validate_blend_mode(&self, mode: u32) -> WebGLResult<()> {
match mode {
constants::FUNC_ADD | constants::FUNC_SUBTRACT | constants::FUNC_REVERSE_SUBTRACT => {
@ -2552,9 +2638,14 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
if attrib_id >= self.limits.max_vertex_attribs {
return self.webgl_error(InvalidValue);
}
self.current_vao()
.enabled_vertex_attrib_array(attrib_id, true);
match self.webgl_version() {
WebGLVersion::WebGL1 => self
.current_vao()
.enabled_vertex_attrib_array(attrib_id, true),
WebGLVersion::WebGL2 => self
.current_vao_webgl2()
.enabled_vertex_attrib_array(attrib_id, true),
};
self.send_command(WebGLCommand::EnableVertexAttribArray(attrib_id));
}
@ -2563,9 +2654,14 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
if attrib_id >= self.limits.max_vertex_attribs {
return self.webgl_error(InvalidValue);
}
self.current_vao()
.enabled_vertex_attrib_array(attrib_id, false);
match self.webgl_version() {
WebGLVersion::WebGL1 => self
.current_vao()
.enabled_vertex_attrib_array(attrib_id, false),
WebGLVersion::WebGL2 => self
.current_vao_webgl2()
.enabled_vertex_attrib_array(attrib_id, false),
};
self.send_command(WebGLCommand::DisableVertexAttribArray(attrib_id));
}
@ -2890,12 +2986,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
#[allow(unsafe_code)]
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9
fn GetVertexAttrib(&self, cx: SafeJSContext, index: u32, param: u32) -> JSVal {
let current_vao = self.current_vao();
let data = handle_potential_webgl_error!(
self,
current_vao.get_vertex_attrib(index).ok_or(InvalidValue),
return NullValue()
);
let get_attrib = |data: Ref<VertexAttribData>| -> JSVal {
if param == constants::CURRENT_VERTEX_ATTRIB {
let value = if index == 0 {
let (x, y, z, w) = self.current_vertex_attrib_0.get();
@ -2907,12 +2998,12 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
};
unsafe {
rooted!(in(*cx) let mut result = ptr::null_mut::<JSObject>());
let _ = Float32Array::create(*cx, CreateWith::Slice(&value), result.handle_mut())
let _ =
Float32Array::create(*cx, CreateWith::Slice(&value), result.handle_mut())
.unwrap();
return ObjectValue(result.get());
}
}
if !self
.extension_manager
.is_get_vertex_attrib_name_enabled(param)
@ -2942,6 +3033,28 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
NullValue()
},
}
};
match self.webgl_version() {
WebGLVersion::WebGL1 => {
let current_vao = self.current_vao();
let data = handle_potential_webgl_error!(
self,
current_vao.get_vertex_attrib(index).ok_or(InvalidValue),
return NullValue()
);
get_attrib(data)
},
WebGLVersion::WebGL2 => {
let current_vao = self.current_vao_webgl2();
let data = handle_potential_webgl_error!(
self,
current_vao.get_vertex_attrib(index).ok_or(InvalidValue),
return NullValue()
);
get_attrib(data)
},
}
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
@ -2950,13 +3063,26 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
self.webgl_error(InvalidEnum);
return 0;
}
let vao = self.current_vao();
match self.webgl_version() {
WebGLVersion::WebGL1 => {
let current_vao = self.current_vao();
let data = handle_potential_webgl_error!(
self,
vao.get_vertex_attrib(index).ok_or(InvalidValue),
current_vao.get_vertex_attrib(index).ok_or(InvalidValue),
return 0
);
data.offset as i64
},
WebGLVersion::WebGL2 => {
let current_vao = self.current_vao_webgl2();
let data = handle_potential_webgl_error!(
self,
current_vao.get_vertex_attrib(index).ok_or(InvalidValue),
return 0
);
data.offset as i64
},
}
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3
@ -3819,11 +3945,15 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
stride: i32,
offset: i64,
) {
handle_potential_webgl_error!(
self,
self.current_vao()
.vertex_attrib_pointer(index, size, type_, normalized, stride, offset)
);
let res = match self.webgl_version() {
WebGLVersion::WebGL1 => self
.current_vao()
.vertex_attrib_pointer(index, size, type_, normalized, stride, offset),
WebGLVersion::WebGL2 => self
.current_vao_webgl2()
.vertex_attrib_pointer(index, size, type_, normalized, stride, offset),
};
handle_potential_webgl_error!(self, res);
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.4

View file

@ -0,0 +1,100 @@
/* 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/. */
use crate::dom::bindings::cell::Ref;
use crate::dom::bindings::codegen::Bindings::WebGLVertexArrayObjectBinding;
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
use crate::dom::vertexarrayobject::{VertexArrayObject, VertexAttribData};
use crate::dom::webglbuffer::WebGLBuffer;
use crate::dom::webglobject::WebGLObject;
use crate::dom::webglrenderingcontext::WebGLRenderingContext;
use canvas_traits::webgl::{ActiveAttribInfo, WebGLResult, WebGLVertexArrayId};
use dom_struct::dom_struct;
#[dom_struct]
pub struct WebGLVertexArrayObject {
webgl_object_: WebGLObject,
array_object: VertexArrayObject,
}
impl WebGLVertexArrayObject {
fn new_inherited(context: &WebGLRenderingContext, id: Option<WebGLVertexArrayId>) -> Self {
Self {
webgl_object_: WebGLObject::new_inherited(context),
array_object: VertexArrayObject::new(context, id),
}
}
pub fn new(context: &WebGLRenderingContext, id: Option<WebGLVertexArrayId>) -> DomRoot<Self> {
reflect_dom_object(
Box::new(WebGLVertexArrayObject::new_inherited(context, id)),
&*context.global(),
WebGLVertexArrayObjectBinding::Wrap,
)
}
pub fn id(&self) -> Option<WebGLVertexArrayId> {
self.array_object.id()
}
pub fn is_deleted(&self) -> bool {
self.array_object.is_deleted()
}
pub fn delete(&self, fallible: bool) {
self.array_object.delete(fallible);
}
pub fn ever_bound(&self) -> bool {
self.array_object.ever_bound()
}
pub fn set_ever_bound(&self) {
self.array_object.set_ever_bound();
}
pub fn element_array_buffer(&self) -> &MutNullableDom<WebGLBuffer> {
self.array_object.element_array_buffer()
}
pub fn get_vertex_attrib(&self, index: u32) -> Option<Ref<VertexAttribData>> {
self.array_object.get_vertex_attrib(index)
}
pub fn vertex_attrib_pointer(
&self,
index: u32,
size: i32,
type_: u32,
normalized: bool,
stride: i32,
offset: i64,
) -> WebGLResult<()> {
self.array_object
.vertex_attrib_pointer(index, size, type_, normalized, stride, offset)
}
pub fn vertex_attrib_divisor(&self, index: u32, value: u32) {
self.array_object.vertex_attrib_divisor(index, value);
}
pub fn enabled_vertex_attrib_array(&self, index: u32, value: bool) {
self.array_object.enabled_vertex_attrib_array(index, value);
}
pub fn unbind_buffer(&self, buffer: &WebGLBuffer) {
self.array_object.unbind_buffer(buffer);
}
pub fn validate_for_draw(
&self,
required_len: u32,
instance_count: u32,
active_attribs: &[ActiveAttribInfo],
) -> WebGLResult<()> {
self.array_object
.validate_for_draw(required_len, instance_count, active_attribs)
}
}

View file

@ -2,41 +2,28 @@
* 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/. */
use crate::dom::bindings::cell::{ref_filter_map, DomRefCell, Ref};
use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants;
use crate::dom::bindings::cell::Ref;
use crate::dom::bindings::codegen::Bindings::WebGLVertexArrayObjectOESBinding;
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
use crate::dom::vertexarrayobject::{VertexArrayObject, VertexAttribData};
use crate::dom::webglbuffer::WebGLBuffer;
use crate::dom::webglobject::WebGLObject;
use crate::dom::webglrenderingcontext::WebGLRenderingContext;
use canvas_traits::webgl::{
ActiveAttribInfo, WebGLCommand, WebGLError, WebGLResult, WebGLVertexArrayId,
};
use canvas_traits::webgl::{ActiveAttribInfo, WebGLResult, WebGLVertexArrayId};
use dom_struct::dom_struct;
use std::cell::Cell;
#[dom_struct]
pub struct WebGLVertexArrayObjectOES {
webgl_object_: WebGLObject,
id: Option<WebGLVertexArrayId>,
ever_bound: Cell<bool>,
is_deleted: Cell<bool>,
vertex_attribs: DomRefCell<Box<[VertexAttribData]>>,
element_array_buffer: MutNullableDom<WebGLBuffer>,
array_object: VertexArrayObject,
}
impl WebGLVertexArrayObjectOES {
fn new_inherited(context: &WebGLRenderingContext, id: Option<WebGLVertexArrayId>) -> Self {
let max_vertex_attribs = context.limits().max_vertex_attribs as usize;
Self {
webgl_object_: WebGLObject::new_inherited(context),
id,
ever_bound: Default::default(),
is_deleted: Default::default(),
vertex_attribs: DomRefCell::new(vec![Default::default(); max_vertex_attribs].into()),
element_array_buffer: Default::default(),
array_object: VertexArrayObject::new(context, id),
}
}
@ -49,54 +36,31 @@ impl WebGLVertexArrayObjectOES {
}
pub fn id(&self) -> Option<WebGLVertexArrayId> {
self.id
self.array_object.id()
}
pub fn is_deleted(&self) -> bool {
self.is_deleted.get()
self.array_object.is_deleted()
}
pub fn delete(&self, fallible: bool) {
assert!(self.id.is_some());
if self.is_deleted.get() {
return;
}
self.is_deleted.set(true);
let context = self.upcast::<WebGLObject>().context();
let cmd = WebGLCommand::DeleteVertexArray(self.id.unwrap());
if fallible {
context.send_command_ignored(cmd);
} else {
context.send_command(cmd);
}
for attrib_data in &**self.vertex_attribs.borrow() {
if let Some(buffer) = attrib_data.buffer() {
buffer.decrement_attached_counter();
}
}
if let Some(buffer) = self.element_array_buffer.get() {
buffer.decrement_attached_counter();
}
self.array_object.delete(fallible);
}
pub fn ever_bound(&self) -> bool {
return self.ever_bound.get();
self.array_object.ever_bound()
}
pub fn set_ever_bound(&self) {
self.ever_bound.set(true);
self.array_object.set_ever_bound();
}
pub fn element_array_buffer(&self) -> &MutNullableDom<WebGLBuffer> {
&self.element_array_buffer
self.array_object.element_array_buffer()
}
pub fn get_vertex_attrib(&self, index: u32) -> Option<Ref<VertexAttribData>> {
ref_filter_map(self.vertex_attribs.borrow(), |attribs| {
attribs.get(index as usize)
})
self.array_object.get_vertex_attrib(index)
}
pub fn vertex_attrib_pointer(
@ -108,93 +72,20 @@ impl WebGLVertexArrayObjectOES {
stride: i32,
offset: i64,
) -> WebGLResult<()> {
let mut attribs = self.vertex_attribs.borrow_mut();
let data = attribs
.get_mut(index as usize)
.ok_or(WebGLError::InvalidValue)?;
if size < 1 || size > 4 {
return Err(WebGLError::InvalidValue);
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#BUFFER_OFFSET_AND_STRIDE
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#VERTEX_STRIDE
if stride < 0 || stride > 255 || offset < 0 {
return Err(WebGLError::InvalidValue);
}
let bytes_per_component: i32 = match type_ {
constants::BYTE | constants::UNSIGNED_BYTE => 1,
constants::SHORT | constants::UNSIGNED_SHORT => 2,
constants::FLOAT => 4,
_ => return Err(WebGLError::InvalidEnum),
};
if offset % bytes_per_component as i64 > 0 || stride % bytes_per_component > 0 {
return Err(WebGLError::InvalidOperation);
}
let context = self.upcast::<WebGLObject>().context();
let buffer = context.array_buffer();
match buffer {
Some(ref buffer) => buffer.increment_attached_counter(),
None if offset != 0 => {
// https://github.com/KhronosGroup/WebGL/pull/2228
return Err(WebGLError::InvalidOperation);
},
_ => {},
}
context.send_command(WebGLCommand::VertexAttribPointer(
index,
size,
type_,
normalized,
stride,
offset as u32,
));
if let Some(old) = data.buffer() {
old.decrement_attached_counter();
}
*data = VertexAttribData {
enabled_as_array: data.enabled_as_array,
size: size as u8,
type_,
bytes_per_vertex: size as u8 * bytes_per_component as u8,
normalized,
stride: stride as u8,
offset: offset as u32,
buffer: buffer.map(|b| Dom::from_ref(&*b)),
divisor: data.divisor,
};
Ok(())
self.array_object
.vertex_attrib_pointer(index, size, type_, normalized, stride, offset)
}
pub fn vertex_attrib_divisor(&self, index: u32, value: u32) {
self.vertex_attribs.borrow_mut()[index as usize].divisor = value;
self.array_object.vertex_attrib_divisor(index, value);
}
pub fn enabled_vertex_attrib_array(&self, index: u32, value: bool) {
self.vertex_attribs.borrow_mut()[index as usize].enabled_as_array = value;
self.array_object.enabled_vertex_attrib_array(index, value);
}
pub fn unbind_buffer(&self, buffer: &WebGLBuffer) {
for attrib in &mut **self.vertex_attribs.borrow_mut() {
if let Some(b) = attrib.buffer() {
if b.id() != buffer.id() {
continue;
}
b.decrement_attached_counter();
}
attrib.buffer = None;
}
if self
.element_array_buffer
.get()
.map_or(false, |b| buffer == &*b)
{
buffer.decrement_attached_counter();
self.element_array_buffer.set(None);
}
self.array_object.unbind_buffer(buffer);
}
pub fn validate_for_draw(
@ -203,109 +94,7 @@ impl WebGLVertexArrayObjectOES {
instance_count: u32,
active_attribs: &[ActiveAttribInfo],
) -> WebGLResult<()> {
// TODO(nox): Cache limits per VAO.
let attribs = self.vertex_attribs.borrow();
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#6.2
if attribs
.iter()
.any(|data| data.enabled_as_array && data.buffer.is_none())
{
return Err(WebGLError::InvalidOperation);
}
let mut has_active_attrib = false;
let mut has_divisor_0 = false;
for active_info in active_attribs {
if active_info.location < 0 {
continue;
}
has_active_attrib = true;
let attrib = &attribs[active_info.location as usize];
if attrib.divisor == 0 {
has_divisor_0 = true;
}
if !attrib.enabled_as_array {
continue;
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#6.6
if required_len > 0 && instance_count > 0 {
let max_vertices = attrib.max_vertices();
if attrib.divisor == 0 {
if max_vertices < required_len {
return Err(WebGLError::InvalidOperation);
}
} else if max_vertices
.checked_mul(attrib.divisor)
.map_or(false, |v| v < instance_count)
{
return Err(WebGLError::InvalidOperation);
}
}
}
if has_active_attrib && !has_divisor_0 {
return Err(WebGLError::InvalidOperation);
}
Ok(())
}
}
impl Drop for WebGLVertexArrayObjectOES {
fn drop(&mut self) {
if self.id.is_some() {
self.delete(true);
}
}
}
#[derive(Clone, JSTraceable, MallocSizeOf)]
#[unrooted_must_root_lint::must_root]
pub struct VertexAttribData {
pub enabled_as_array: bool,
pub size: u8,
pub type_: u32,
bytes_per_vertex: u8,
pub normalized: bool,
pub stride: u8,
pub offset: u32,
pub buffer: Option<Dom<WebGLBuffer>>,
pub divisor: u32,
}
impl Default for VertexAttribData {
#[allow(unrooted_must_root)]
fn default() -> Self {
Self {
enabled_as_array: false,
size: 4,
type_: constants::FLOAT,
bytes_per_vertex: 16,
normalized: false,
stride: 0,
offset: 0,
buffer: None,
divisor: 0,
}
}
}
impl VertexAttribData {
pub fn buffer(&self) -> Option<&WebGLBuffer> {
self.buffer.as_ref().map(|b| &**b)
}
fn max_vertices(&self) -> u32 {
let capacity = (self.buffer().unwrap().capacity() as u32).saturating_sub(self.offset);
if capacity < self.bytes_per_vertex as u32 {
0
} else if self.stride == 0 {
capacity / self.bytes_per_vertex as u32
} else if self.stride < self.bytes_per_vertex {
(capacity - (self.bytes_per_vertex - self.stride) as u32) / self.stride as u32
} else {
let mut max = capacity / self.stride as u32;
if capacity % self.stride as u32 >= self.bytes_per_vertex as u32 {
max += 1;
}
max
}
self.array_object
.validate_for_draw(required_len, instance_count, active_attribs)
}
}

View file

@ -11,10 +11,6 @@
typedef long long GLint64;
typedef unsigned long long GLuint64;
// interface WebGLVertexArrayObject : WebGLObject {
// };
typedef (/*[AllowShared]*/ Uint32Array or sequence<GLuint>) Uint32List;
interface mixin WebGL2RenderingContextBase
@ -540,10 +536,10 @@ interface mixin WebGL2RenderingContextBase
void uniformBlockBinding(WebGLProgram program, GLuint uniformBlockIndex, GLuint uniformBlockBinding);
/* Vertex Array Objects */
/*WebGLVertexArrayObject? createVertexArray();
WebGLVertexArrayObject? createVertexArray();
void deleteVertexArray(WebGLVertexArrayObject? vertexArray);
[WebGLHandlesContextLoss] GLboolean isVertexArray(WebGLVertexArrayObject? vertexArray);
void bindVertexArray(WebGLVertexArrayObject? array);*/
void bindVertexArray(WebGLVertexArrayObject? array);
};
[Exposed=Window, Pref="dom.webgl2.enabled"]

View file

@ -0,0 +1,11 @@
/* 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/. */
//
// WebGL IDL definitions scraped from the Khronos specification:
// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.17
//
[Exposed=(Window), Pref="dom.webgl2.enabled"]
interface WebGLVertexArrayObject : WebGLObject {
};

View file

@ -1,8 +0,0 @@
[gl-vertex-attrib-render.html]
bug: https://github.com/servo/servo/issues/21132
[WebGL test #0: Unable to fetch WebGL rendering context for Canvas]
expected: FAIL
[WebGL test #1: could not create context]
expected: FAIL

View file

@ -1,8 +0,0 @@
[buffer-data-array-buffer-delete.html]
bug: https://github.com/servo/servo/issues/21132
[WebGL test #0: Unable to fetch WebGL rendering context for Canvas]
expected: FAIL
[WebGL test #1: context does not exist]
expected: FAIL

View file

@ -1,5 +1,5 @@
[incorrect-context-object-behaviour.html]
expected: ERROR
[WebGL test #0: successfullyParsed should be true (of type boolean). Was undefined (of type undefined).]
[WebGL test #1: successfullyParsed should be true (of type boolean). Was undefined (of type undefined).]
expected: FAIL

View file

@ -11,27 +11,15 @@
[WebGL test #18: Property either does not exist or is not a function: drawBuffers]
expected: FAIL
[WebGL test #22: Property either does not exist or is not a function: bindVertexArray]
expected: FAIL
[WebGL test #12: Property either does not exist or is not a function: vertexAttribI4i]
expected: FAIL
[WebGL test #19: Property either does not exist or is not a function: createVertexArray]
expected: FAIL
[WebGL test #6: Property either does not exist or is not a function: texStorage2D]
expected: FAIL
[WebGL test #1: Property either does not exist or is not a function: blitFramebuffer]
expected: FAIL
[WebGL test #21: Property either does not exist or is not a function: isVertexArray]
expected: FAIL
[WebGL test #20: Property either does not exist or is not a function: deleteVertexArray]
expected: FAIL
[WebGL test #5: Property either does not exist or is not a function: texImage3D]
expected: FAIL

View file

@ -1,8 +1,8 @@
[attrib-location-length-limits.html]
[WebGL test #1: getError expected: NO_ERROR. Was INVALID_VALUE : ]
[WebGL test #2: attrib location was -1, should not be]
expected: FAIL
[WebGL test #2: attrib location was -1, should not be]
[WebGL test #1: getError expected: NO_ERROR. Was INVALID_VALUE : ]
expected: FAIL
[WebGL test #3: getError expected: NO_ERROR. Was INVALID_VALUE : ]

View file

@ -1,5 +1,8 @@
[expando-loss-2.html]
expected: ERROR
[WebGL test #10: successfullyParsed should be true (of type boolean). Was undefined (of type undefined).]
[WebGL test #16: successfullyParsed should be true (of type boolean). Was undefined (of type undefined).]
expected: FAIL
[WebGL test #15: getParameter(TEXTURE_BINDING_3D) returns instance that was bound.]
expected: FAIL

View file

@ -1,4 +0,0 @@
[instanceof-test.html]
[WebGL test #10: gl.createVertexArray() instanceof WebGLVertexArrayObject should be true. Threw exception TypeError: gl.createVertexArray is not a function]
expected: FAIL

View file

@ -1,5 +0,0 @@
[object-deletion-behaviour-2.html]
expected: ERROR
[WebGL test #40: successfullyParsed should be true (of type boolean). Was undefined (of type undefined).]
expected: FAIL

View file

@ -1,5 +0,0 @@
[instanced-rendering-bug.html]
expected: ERROR
[WebGL test #1: successfullyParsed should be true (of type boolean). Was undefined (of type undefined).]
expected: FAIL

View file

@ -41,3 +41,13 @@
[WebGL test #182: successfullyParsed should be true (of type boolean). Was undefined (of type undefined).]
expected: FAIL
[WebGL test #3: gl.getBufferParameter(gl.ELEMENT_ARRAY_BUFFER, gl.BUFFER_SIZE) should be 16 (of type number). Was null (of type object).]
expected: FAIL
[WebGL test #4: gl.getBufferParameter(gl.ELEMENT_ARRAY_BUFFER, gl.BUFFER_USAGE) should be 35048 (of type number). Was null (of type object).]
expected: FAIL
[WebGL test #5: getBufferParameter did not generate INVALID_ENUM for invalid parameter enum: NO_ERROR]
expected: FAIL

View file

@ -1,2 +1,116 @@
[simultaneous_binding.html]
expected: ERROR
[WebGL test #6: buffer should match expected values]
expected: FAIL
[WebGL test #50: Unexpected error before drawing: 1282]
expected: FAIL
[WebGL test #4: Unexpected error before drawing: 1282]
expected: FAIL
[WebGL test #59: Unexpected error before drawing: 1282]
expected: FAIL
[WebGL test #45: Unexpected error before drawing: 1282]
expected: FAIL
[WebGL test #13: getError expected: NO_ERROR. Was INVALID_OPERATION : transform feedback should be successful]
expected: FAIL
[WebGL test #41: Unexpected error before drawing: 1282]
expected: FAIL
[WebGL test #46: getError expected: NO_ERROR. Was INVALID_OPERATION : transform feedback should be successful]
expected: FAIL
[WebGL test #8: Unexpected error before drawing: 1282]
expected: FAIL
[WebGL test #15: getError expected: INVALID_OPERATION. Was NO_ERROR : drawArrays: buffer used as vertex attrib and tf simultaneously]
expected: FAIL
[WebGL test #37: Unexpected error before drawing: 1282]
expected: FAIL
[WebGL test #27: getError expected: NO_ERROR. Was INVALID_OPERATION : tf buffer not used as uniform buffer anymore]
expected: FAIL
[WebGL test #16: getError expected: INVALID_OPERATION. Was NO_ERROR : drawElements: buffer used as vertex attrib and tf simultaneously]
expected: FAIL
[WebGL test #29: Unexpected error before drawing: 1282]
expected: FAIL
[WebGL test #55: Unexpected error before drawing: 1282]
expected: FAIL
[WebGL test #14: buffer should match expected values]
expected: FAIL
[WebGL test #38: getError expected: NO_ERROR. Was INVALID_OPERATION : transform feedback should be successful]
expected: FAIL
[WebGL test #54: getError expected: INVALID_OPERATION. Was NO_ERROR : drawElements: buffer used as uniform buffer and tf simultaneously]
expected: FAIL
[WebGL test #47: buffer should match expected values]
expected: FAIL
[WebGL test #49: getError expected: INVALID_OPERATION. Was NO_ERROR : drawElements: buffer used as vertex attrib and tf simultaneously]
expected: FAIL
[WebGL test #10: buffer should match expected values]
expected: FAIL
[WebGL test #12: Unexpected error before drawing: 1282]
expected: FAIL
[WebGL test #48: getError expected: INVALID_OPERATION. Was NO_ERROR : drawArrays: buffer used as vertex attrib and tf simultaneously]
expected: FAIL
[WebGL test #43: buffer should match expected values]
expected: FAIL
[WebGL test #42: getError expected: NO_ERROR. Was INVALID_OPERATION : transform feedback should be successful]
expected: FAIL
[WebGL test #17: Unexpected error before drawing: 1282]
expected: FAIL
[WebGL test #22: Unexpected error before drawing: 1282]
expected: FAIL
[WebGL test #19: should be the same as before as nothing has executed]
expected: FAIL
[WebGL test #52: should be the same as before as nothing has executed]
expected: FAIL
[WebGL test #39: buffer should match expected values]
expected: FAIL
[WebGL test #5: getError expected: NO_ERROR. Was INVALID_OPERATION : transform feedback should be successful]
expected: FAIL
[WebGL test #62: Unexpected error before drawing: 1282]
expected: FAIL
[WebGL test #53: getError expected: INVALID_OPERATION. Was NO_ERROR : drawArrays: buffer used as uniform buffer and tf simultaneously]
expected: FAIL
[WebGL test #26: Unexpected error before drawing: 1282]
expected: FAIL
[WebGL test #21: getError expected: INVALID_OPERATION. Was NO_ERROR : drawElements: buffer used as uniform buffer and tf simultaneously]
expected: FAIL
[WebGL test #20: getError expected: INVALID_OPERATION. Was NO_ERROR : drawArrays: buffer used as uniform buffer and tf simultaneously]
expected: FAIL
[WebGL test #60: getError expected: NO_ERROR. Was INVALID_OPERATION : tf buffer not used as uniform buffer anymore]
expected: FAIL
[WebGL test #9: getError expected: NO_ERROR. Was INVALID_OPERATION : transform feedback should be successful]
expected: FAIL

View file

@ -1,5 +0,0 @@
[vertex-array-object.html]
expected: ERROR
[WebGL test #4: successfullyParsed should be true (of type boolean). Was undefined (of type undefined).]
expected: FAIL