From 62f00df79d8945e43c42a6100d87faefa1aa04e0 Mon Sep 17 00:00:00 2001 From: Istvan Date: Fri, 27 Mar 2020 15:56:19 +0100 Subject: Add initial support for VertexAttribI4*, VertexAttribIPointer Adds initial support for the WebGL2 `VertexAttribI4i`, `VertexAttribI4iv`, `VertexAttribI4ui`, `VertexAttribI4uiv` and `VertexAttribIPointer` calls. --- components/script/dom/vertexarrayobject.rs | 22 +++- components/script/dom/webgl2renderingcontext.rs | 134 ++++++++++++++++++++- components/script/dom/webglrenderingcontext.rs | 89 ++++++++++---- components/script/dom/webglvertexarrayobject.rs | 4 + components/script/dom/webglvertexarrayobjectoes.rs | 4 + .../dom/webidls/WebGL2RenderingContext.webidl | 10 +- 6 files changed, 234 insertions(+), 29 deletions(-) (limited to 'components/script/dom') diff --git a/components/script/dom/vertexarrayobject.rs b/components/script/dom/vertexarrayobject.rs index 2dab37b7348..34ef5b428bb 100644 --- a/components/script/dom/vertexarrayobject.rs +++ b/components/script/dom/vertexarrayobject.rs @@ -3,12 +3,13 @@ * 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::WebGL2RenderingContextBinding::WebGL2RenderingContextConstants as constants2; 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, + ActiveAttribInfo, WebGLCommand, WebGLError, WebGLResult, WebGLVersion, WebGLVertexArrayId, }; use std::cell::Cell; @@ -85,6 +86,10 @@ impl VertexArrayObject { }) } + pub fn set_vertex_attrib_type(&self, index: u32, type_: u32) { + self.vertex_attribs.borrow_mut()[index as usize].type_ = type_; + } + pub fn vertex_attrib_pointer( &self, index: u32, @@ -108,12 +113,27 @@ impl VertexArrayObject { if stride < 0 || stride > 255 || offset < 0 { return Err(WebGLError::InvalidValue); } + + let is_webgl2 = match self.context.webgl_version() { + WebGLVersion::WebGL2 => true, + _ => false, + }; + let bytes_per_component: i32 = match type_ { constants::BYTE | constants::UNSIGNED_BYTE => 1, constants::SHORT | constants::UNSIGNED_SHORT => 2, constants::FLOAT => 4, + constants::INT | constants::UNSIGNED_INT if is_webgl2 => 4, + constants2::HALF_FLOAT if is_webgl2 => 2, + sparkle::gl::FIXED if is_webgl2 => 4, + constants2::INT_2_10_10_10_REV | constants2::UNSIGNED_INT_2_10_10_10_REV + if is_webgl2 && size == 4 => + { + 4 + }, _ => return Err(WebGLError::InvalidEnum), }; + if offset % bytes_per_component as i64 > 0 || stride % bytes_per_component > 0 { return Err(WebGLError::InvalidOperation); } diff --git a/components/script/dom/webgl2renderingcontext.rs b/components/script/dom/webgl2renderingcontext.rs index fea8b54e849..ae6b66187cd 100644 --- a/components/script/dom/webgl2renderingcontext.rs +++ b/components/script/dom/webgl2renderingcontext.rs @@ -25,7 +25,7 @@ use crate::dom::webglprogram::WebGLProgram; use crate::dom::webglquery::WebGLQuery; use crate::dom::webglrenderbuffer::WebGLRenderbuffer; use crate::dom::webglrenderingcontext::{ - uniform_get, uniform_typed, LayoutCanvasWebGLRenderingContextHelpers, WebGLRenderingContext, + uniform_get, uniform_typed, LayoutCanvasWebGLRenderingContextHelpers, VertexAttrib, WebGLRenderingContext, }; use crate::dom::webglsampler::{WebGLSampler, WebGLSamplerValue}; use crate::dom::webglshader::WebGLShader; @@ -230,6 +230,62 @@ impl WebGL2RenderingContext { } } + fn validate_vertex_attribs_for_draw(&self) { + let program = match self.base.current_program() { + Some(program) => program, + None => return, + }; + let groups = [ + [ + constants::INT, + constants::INT_VEC2, + constants::INT_VEC3, + constants::INT_VEC4, + ], + [ + constants::UNSIGNED_INT, + constants::UNSIGNED_INT_VEC2, + constants::UNSIGNED_INT_VEC3, + constants::UNSIGNED_INT_VEC4, + ], + [ + constants::FLOAT, + constants::FLOAT_VEC2, + constants::FLOAT_VEC3, + constants::FLOAT_VEC4, + ], + ]; + let vao = self.current_vao(); + for prog_attrib in program.active_attribs().iter() { + let attrib = handle_potential_webgl_error!( + self.base, + vao.get_vertex_attrib(prog_attrib.location as u32) + .ok_or(InvalidOperation), + return + ); + + let current_vertex_attrib = + self.base.current_vertex_attribs()[prog_attrib.location as usize]; + let attrib_data_base_type = if !attrib.enabled_as_array { + match current_vertex_attrib { + VertexAttrib::Int(_, _, _, _) => constants::INT, + VertexAttrib::Uint(_, _, _, _) => constants::UNSIGNED_INT, + VertexAttrib::Float(_, _, _, _) => constants::FLOAT, + } + } else { + attrib.type_ + }; + + let contains = groups + .iter() + .find(|g| g.contains(&attrib_data_base_type) && g.contains(&prog_attrib.type_)); + if contains.is_none() { + self.base.webgl_error(InvalidOperation); + return; + } + } + } + pub fn base_context(&self) -> DomRoot { DomRoot::from_ref(&*self.base) } @@ -739,6 +795,28 @@ impl WebGL2RenderingContext { true } + + fn vertex_attrib_i(&self, index: u32, x: i32, y: i32, z: i32, w: i32) { + if index >= self.base.limits().max_vertex_attribs { + return self.base.webgl_error(InvalidValue); + } + self.base.current_vertex_attribs()[index as usize] = VertexAttrib::Int(x, y, z, w); + self.current_vao() + .set_vertex_attrib_type(index, constants::INT); + self.base + .send_command(WebGLCommand::VertexAttribI(index, x, y, z, w)); + } + + fn vertex_attrib_u(&self, index: u32, x: u32, y: u32, z: u32, w: u32) { + if index >= self.base.limits().max_vertex_attribs { + return self.base.webgl_error(InvalidValue); + } + self.base.current_vertex_attribs()[index as usize] = VertexAttrib::Uint(x, y, z, w); + self.current_vao() + .set_vertex_attrib_type(index, constants::UNSIGNED_INT); + self.base + .send_command(WebGLCommand::VertexAttribU(index, x, y, z, w)); + } } impl WebGL2RenderingContextMethods for WebGL2RenderingContext { @@ -1569,12 +1647,14 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext { /// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.11 fn DrawArrays(&self, mode: u32, first: i32, count: i32) { self.validate_uniform_block_for_draw(); + self.validate_vertex_attribs_for_draw(); self.base.DrawArrays(mode, first, count) } /// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.11 fn DrawElements(&self, mode: u32, count: i32, type_: u32, offset: i64) { self.validate_uniform_block_for_draw(); + self.validate_vertex_attribs_for_draw(); self.base.DrawElements(mode, count, type_, offset) } @@ -2591,6 +2671,40 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext { self.base.VertexAttrib4fv(indx, v) } + /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8 + fn VertexAttribI4i(&self, index: u32, x: i32, y: i32, z: i32, w: i32) { + self.vertex_attrib_i(index, x, y, z, w) + } + + /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8 + fn VertexAttribI4iv(&self, index: u32, v: Int32ArrayOrLongSequence) { + let values = match v { + Int32ArrayOrLongSequence::Int32Array(v) => v.to_vec(), + Int32ArrayOrLongSequence::LongSequence(v) => v, + }; + if values.len() < 4 { + return self.base.webgl_error(InvalidValue); + } + self.vertex_attrib_i(index, values[0], values[1], values[2], values[3]); + } + + /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8 + fn VertexAttribI4ui(&self, index: u32, x: u32, y: u32, z: u32, w: u32) { + self.vertex_attrib_u(index, x, y, z, w) + } + + /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8 + fn VertexAttribI4uiv(&self, index: u32, v: Uint32ArrayOrUnsignedLongSequence) { + let values = match v { + Uint32ArrayOrUnsignedLongSequence::Uint32Array(v) => v.to_vec(), + Uint32ArrayOrUnsignedLongSequence::UnsignedLongSequence(v) => v, + }; + if values.len() < 4 { + return self.base.webgl_error(InvalidValue); + } + self.vertex_attrib_u(index, values[0], values[1], values[2], values[3]); + } + /// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 fn VertexAttribPointer( &self, @@ -2605,6 +2719,21 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext { .VertexAttribPointer(attrib_id, size, data_type, normalized, stride, offset) } + /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8 + fn VertexAttribIPointer(&self, index: u32, size: i32, type_: u32, stride: i32, offset: i64) { + match type_ { + constants::BYTE | + constants::UNSIGNED_BYTE | + constants::SHORT | + constants::UNSIGNED_SHORT | + constants::INT | + constants::UNSIGNED_INT => {}, + _ => return self.base.webgl_error(InvalidEnum), + }; + self.base + .VertexAttribPointer(index, size, type_, false, stride, offset) + } + /// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.4 fn Viewport(&self, x: i32, y: i32, width: i32, height: i32) { self.base.Viewport(x, y, width, height) @@ -2820,6 +2949,7 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext { /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.9 fn DrawArraysInstanced(&self, mode: u32, first: i32, count: i32, primcount: i32) { self.validate_uniform_block_for_draw(); + self.validate_vertex_attribs_for_draw(); handle_potential_webgl_error!( self.base, self.base @@ -2837,6 +2967,7 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext { primcount: i32, ) { self.validate_uniform_block_for_draw(); + self.validate_vertex_attribs_for_draw(); handle_potential_webgl_error!( self.base, self.base @@ -2859,6 +2990,7 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext { return; } self.validate_uniform_block_for_draw(); + self.validate_vertex_attribs_for_draw(); handle_potential_webgl_error!( self.base, self.base diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index d4327f6216a..8e00c79683f 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -2,7 +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::cell::{DomRefCell, Ref, RefMut}; use crate::dom::bindings::codegen::Bindings::ANGLEInstancedArraysBinding::ANGLEInstancedArraysConstants; use crate::dom::bindings::codegen::Bindings::EXTBlendMinmaxBinding::EXTBlendMinmaxConstants; use crate::dom::bindings::codegen::Bindings::OESVertexArrayObjectBinding::OESVertexArrayObjectConstants; @@ -148,6 +148,13 @@ bitflags! { } } +#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf)] +pub enum VertexAttrib { + Float(f32, f32, f32, f32), + Int(i32, i32, i32, i32), + Uint(u32, u32, u32, u32), +} + #[dom_struct] pub struct WebGLRenderingContext { reflector_: Reflector, @@ -173,9 +180,7 @@ pub struct WebGLRenderingContext { bound_renderbuffer: MutNullableDom, bound_buffer_array: MutNullableDom, current_program: MutNullableDom, - /// https://www.khronos.org/webgl/wiki/WebGL_and_OpenGL_Differences#Vertex_Attribute_0 - #[ignore_malloc_size_of = "Because it's small"] - current_vertex_attrib_0: Cell<(f32, f32, f32, f32)>, + current_vertex_attribs: DomRefCell>, #[ignore_malloc_size_of = "Because it's small"] current_scissor: Cell<(i32, i32, u32, u32)>, #[ignore_malloc_size_of = "Because it's small"] @@ -216,6 +221,7 @@ impl WebGLRenderingContext { result.map(|ctx_data| { let max_combined_texture_image_units = ctx_data.limits.max_combined_texture_image_units; + let max_vertex_attribs = ctx_data.limits.max_vertex_attribs as usize; Self { reflector_: Reflector::new(), webgl_sender: WebGLMessageSender::new( @@ -236,7 +242,9 @@ impl WebGLRenderingContext { bound_buffer_array: MutNullableDom::new(None), bound_renderbuffer: MutNullableDom::new(None), current_program: MutNullableDom::new(None), - current_vertex_attrib_0: Cell::new((0f32, 0f32, 0f32, 1f32)), + current_vertex_attribs: DomRefCell::new( + vec![VertexAttrib::Float(0f32, 0f32, 0f32, 1f32); max_vertex_attribs].into(), + ), current_scissor: Cell::new((0, 0, size.width, size.height)), // FIXME(#21718) The backend is allowed to choose a size smaller than // what was requested @@ -305,6 +313,10 @@ impl WebGLRenderingContext { }) } + pub fn current_vertex_attribs(&self) -> RefMut> { + self.current_vertex_attribs.borrow_mut() + } + pub fn recreate(&self, size: Size2D) { let (sender, receiver) = webgl_channel().unwrap(); self.webgl_sender.send_resize(size, sender).unwrap(); @@ -521,9 +533,15 @@ impl WebGLRenderingContext { return self.webgl_error(InvalidValue); } - if indx == 0 { - self.current_vertex_attrib_0.set((x, y, z, w)) - } + match self.webgl_version() { + WebGLVersion::WebGL1 => self + .current_vao() + .set_vertex_attrib_type(indx, constants::FLOAT), + WebGLVersion::WebGL2 => self + .current_vao_webgl2() + .set_vertex_attrib_type(indx, constants::FLOAT), + }; + self.current_vertex_attribs.borrow_mut()[indx as usize] = VertexAttrib::Float(x, y, z, w); self.send_command(WebGLCommand::VertexAttrib(indx, x, y, z, w)); } @@ -3032,21 +3050,48 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { fn GetVertexAttrib(&self, cx: SafeJSContext, index: u32, param: u32) -> JSVal { let get_attrib = |data: Ref| -> JSVal { if param == constants::CURRENT_VERTEX_ATTRIB { - let value = if index == 0 { - let (x, y, z, w) = self.current_vertex_attrib_0.get(); - [x, y, z, w] - } else { - let (sender, receiver) = webgl_channel().unwrap(); - self.send_command(WebGLCommand::GetCurrentVertexAttrib(index, sender)); - receiver.recv().unwrap() - }; - unsafe { - rooted!(in(*cx) let mut result = ptr::null_mut::()); - let _ = - Float32Array::create(*cx, CreateWith::Slice(&value), result.handle_mut()) + let attrib = self.current_vertex_attribs.borrow()[index as usize]; + match attrib { + VertexAttrib::Float(x, y, z, w) => { + let value = [x, y, z, w]; + unsafe { + rooted!(in(*cx) let mut result = ptr::null_mut::()); + let _ = Float32Array::create( + *cx, + CreateWith::Slice(&value), + result.handle_mut(), + ) .unwrap(); - return ObjectValue(result.get()); - } + return ObjectValue(result.get()); + } + }, + VertexAttrib::Int(x, y, z, w) => { + let value = [x, y, z, w]; + unsafe { + rooted!(in(*cx) let mut result = ptr::null_mut::()); + let _ = Int32Array::create( + *cx, + CreateWith::Slice(&value), + result.handle_mut(), + ) + .unwrap(); + return ObjectValue(result.get()); + } + }, + VertexAttrib::Uint(x, y, z, w) => { + let value = [x, y, z, w]; + unsafe { + rooted!(in(*cx) let mut result = ptr::null_mut::()); + let _ = Uint32Array::create( + *cx, + CreateWith::Slice(&value), + result.handle_mut(), + ) + .unwrap(); + return ObjectValue(result.get()); + } + }, + }; } if !self .extension_manager diff --git a/components/script/dom/webglvertexarrayobject.rs b/components/script/dom/webglvertexarrayobject.rs index 098423d860a..b425a7c4219 100644 --- a/components/script/dom/webglvertexarrayobject.rs +++ b/components/script/dom/webglvertexarrayobject.rs @@ -61,6 +61,10 @@ impl WebGLVertexArrayObject { self.array_object.get_vertex_attrib(index) } + pub fn set_vertex_attrib_type(&self, index: u32, type_: u32) { + self.array_object.set_vertex_attrib_type(index, type_); + } + pub fn vertex_attrib_pointer( &self, index: u32, diff --git a/components/script/dom/webglvertexarrayobjectoes.rs b/components/script/dom/webglvertexarrayobjectoes.rs index a3861c50110..f10c10d949b 100644 --- a/components/script/dom/webglvertexarrayobjectoes.rs +++ b/components/script/dom/webglvertexarrayobjectoes.rs @@ -61,6 +61,10 @@ impl WebGLVertexArrayObjectOES { self.array_object.get_vertex_attrib(index) } + pub fn set_vertex_attrib_type(&self, index: u32, type_: u32) { + self.array_object.set_vertex_attrib_type(index, type_); + } + pub fn vertex_attrib_pointer( &self, index: u32, diff --git a/components/script/dom/webidls/WebGL2RenderingContext.webidl b/components/script/dom/webidls/WebGL2RenderingContext.webidl index a05142da935..e7f94cb9a3c 100644 --- a/components/script/dom/webidls/WebGL2RenderingContext.webidl +++ b/components/script/dom/webidls/WebGL2RenderingContext.webidl @@ -451,11 +451,11 @@ interface mixin WebGL2RenderingContextBase optional GLuint srcOffset = 0, optional GLuint srcLength = 0); /* Vertex attribs */ - // void vertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w); - // void vertexAttribI4iv(GLuint index, Int32List values); - // void vertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); - // void vertexAttribI4uiv(GLuint index, Uint32List values); - // void vertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset); + void vertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w); + void vertexAttribI4iv(GLuint index, Int32List values); + void vertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); + void vertexAttribI4uiv(GLuint index, Uint32List values); + void vertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset); /* Writing to the drawing buffer */ void vertexAttribDivisor(GLuint index, GLuint divisor); -- cgit v1.2.3