From a5b800970a91139ca9790cd6417576e7cc4ff6e9 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Wed, 11 Jul 2018 10:35:53 +0200 Subject: [PATCH 1/4] Remove WebGLCommand::GetActiveAttrib --- components/canvas/webgl_thread.rs | 21 --------------------- components/canvas_traits/webgl.rs | 1 - 2 files changed, 22 deletions(-) diff --git a/components/canvas/webgl_thread.rs b/components/canvas/webgl_thread.rs index a90c996f8bb..8e43d7c1295 100644 --- a/components/canvas/webgl_thread.rs +++ b/components/canvas/webgl_thread.rs @@ -736,8 +736,6 @@ impl WebGLImpl { ctx.gl().stencil_op(fail, zfail, zpass), WebGLCommand::StencilOpSeparate(face, fail, zfail, zpass) => ctx.gl().stencil_op_separate(face, fail, zfail, zpass), - WebGLCommand::GetActiveAttrib(program_id, index, ref chan) => - Self::active_attrib(ctx.gl(), program_id, index, chan), WebGLCommand::GetActiveUniform(program_id, index, ref chan) => Self::active_uniform(ctx.gl(), program_id, index, chan), WebGLCommand::GetRenderbufferParameter(target, pname, ref chan) => @@ -1045,25 +1043,6 @@ impl WebGLImpl { chan.send(result.into()).unwrap() } - #[allow(unsafe_code)] - fn active_attrib( - gl: &gl::Gl, - program_id: WebGLProgramId, - index: u32, - chan: &WebGLSender>, - ) { - let mut max = [0]; - unsafe { - gl.get_program_iv(program_id.get(), gl::ACTIVE_ATTRIBUTES, &mut max); - } - let result = if index >= max[0] as u32 { - Err(WebGLError::InvalidValue) - } else { - Ok(gl.get_active_attrib(program_id.get(), index)) - }; - chan.send(result).unwrap(); - } - #[allow(unsafe_code)] fn active_uniform(gl: &gl::Gl, program_id: WebGLProgramId, diff --git a/components/canvas_traits/webgl.rs b/components/canvas_traits/webgl.rs index 793f687698b..5f5c02333a8 100644 --- a/components/canvas_traits/webgl.rs +++ b/components/canvas_traits/webgl.rs @@ -207,7 +207,6 @@ pub enum WebGLCommand { FramebufferTexture2D(u32, u32, u32, Option, i32), GetExtensions(WebGLSender), GetShaderPrecisionFormat(u32, u32, WebGLSender<(i32, i32, i32)>), - GetActiveAttrib(WebGLProgramId, u32, WebGLSender>), GetActiveUniform(WebGLProgramId, u32, WebGLSender>), GetUniformLocation(WebGLProgramId, String, WebGLSender>), GetShaderInfoLog(WebGLShaderId, WebGLSender), From cbac5d05be13888fa78fcb4678f1620860b80228 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Wed, 11 Jul 2018 11:55:25 +0200 Subject: [PATCH 2/4] Store active uniforms on the DOM side --- components/canvas/webgl_thread.rs | 38 +++++------ components/canvas_traits/webgl.rs | 14 +++- components/script/dom/bindings/trace.rs | 10 +-- components/script/dom/webglprogram.rs | 65 ++++++++++++------- .../script/dom/webglrenderingcontext.rs | 7 +- 5 files changed, 79 insertions(+), 55 deletions(-) diff --git a/components/canvas/webgl_thread.rs b/components/canvas/webgl_thread.rs index 8e43d7c1295..3bfe49125ba 100644 --- a/components/canvas/webgl_thread.rs +++ b/components/canvas/webgl_thread.rs @@ -736,8 +736,6 @@ impl WebGLImpl { ctx.gl().stencil_op(fail, zfail, zpass), WebGLCommand::StencilOpSeparate(face, fail, zfail, zpass) => ctx.gl().stencil_op_separate(face, fail, zfail, zpass), - WebGLCommand::GetActiveUniform(program_id, index, ref chan) => - Self::active_uniform(ctx.gl(), program_id, index, chan), WebGLCommand::GetRenderbufferParameter(target, pname, ref chan) => Self::get_renderbuffer_parameter(ctx.gl(), target, pname, chan), WebGLCommand::GetFramebufferAttachmentParameter(target, attachment, pname, ref chan) => @@ -1001,6 +999,7 @@ impl WebGLImpl { return ProgramLinkInfo { linked: false, active_attribs: vec![].into(), + active_uniforms: vec![].into(), } } @@ -1009,6 +1008,8 @@ impl WebGLImpl { gl.get_program_iv(program.get(), gl::ACTIVE_ATTRIBUTES, &mut num_active_attribs); } let active_attribs = (0..num_active_attribs[0] as u32).map(|i| { + // FIXME(nox): This allocates strings sometimes for nothing + // and the gleam method keeps getting ACTIVE_ATTRIBUTE_MAX_LENGTH. let (size, type_, name) = gl.get_active_attrib(program.get(), i); let location = if name.starts_with("gl_") { -1 @@ -1023,9 +1024,25 @@ impl WebGLImpl { } }).collect::>().into(); + let mut num_active_uniforms = [0]; + unsafe { + gl.get_program_iv(program.get(), gl::ACTIVE_UNIFORMS, &mut num_active_uniforms); + } + let active_uniforms = (0..num_active_uniforms[0] as u32).map(|i| { + // FIXME(nox): This allocates strings sometimes for nothing + // and the gleam method keeps getting ACTIVE_UNIFORM_MAX_LENGTH. + let (size, type_, name) = gl.get_active_uniform(program.get(), i); + ActiveUniformInfo { + name: from_name_in_compiled_shader(&name), + size, + type_, + } + }).collect::>().into(); + ProgramLinkInfo { linked: true, active_attribs, + active_uniforms, } } @@ -1043,23 +1060,6 @@ impl WebGLImpl { chan.send(result.into()).unwrap() } - #[allow(unsafe_code)] - fn active_uniform(gl: &gl::Gl, - program_id: WebGLProgramId, - index: u32, - chan: &WebGLSender>) { - let mut max = [0]; - unsafe { - gl.get_program_iv(program_id.get(), gl::ACTIVE_UNIFORMS, &mut max); - } - let result = if index >= max[0] as u32 { - Err(WebGLError::InvalidValue) - } else { - Ok(gl.get_active_uniform(program_id.get(), index)) - }; - chan.send(result).unwrap(); - } - fn finish(gl: &gl::Gl, chan: &WebGLSender<()>) { gl.finish(); chan.send(()).unwrap(); diff --git a/components/canvas_traits/webgl.rs b/components/canvas_traits/webgl.rs index 5f5c02333a8..451a3d19f19 100644 --- a/components/canvas_traits/webgl.rs +++ b/components/canvas_traits/webgl.rs @@ -207,7 +207,6 @@ pub enum WebGLCommand { FramebufferTexture2D(u32, u32, u32, Option, i32), GetExtensions(WebGLSender), GetShaderPrecisionFormat(u32, u32, WebGLSender<(i32, i32, i32)>), - GetActiveUniform(WebGLProgramId, u32, WebGLSender>), GetUniformLocation(WebGLProgramId, String, WebGLSender>), GetShaderInfoLog(WebGLShaderId, WebGLSender), GetProgramInfoLog(WebGLProgramId, WebGLSender), @@ -424,6 +423,8 @@ pub struct ProgramLinkInfo { pub linked: bool, /// The list of active attributes. pub active_attribs: Box<[ActiveAttribInfo]>, + /// The list of active uniforms. + pub active_uniforms: Box<[ActiveUniformInfo]>, } /// Description of a single active attribute. @@ -439,6 +440,17 @@ pub struct ActiveAttribInfo { pub location: i32, } +/// Description of a single active uniform. +#[derive(Clone, Deserialize, MallocSizeOf, Serialize)] +pub struct ActiveUniformInfo { + /// The name of the uniform. + pub name: String, + /// The size of the uniform. + pub size: i32, + /// The type of the uniform. + pub type_: u32, +} + macro_rules! parameters { ($name:ident { $( $variant:ident($kind:ident { $( diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 06892ec8478..74071e3fda2 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -32,10 +32,11 @@ use app_units::Au; use canvas_traits::canvas::{CanvasGradientStop, CanvasId, LinearGradientStyle, RadialGradientStyle}; use canvas_traits::canvas::{CompositionOrBlending, LineCapStyle, LineJoinStyle, RepetitionStyle}; -use canvas_traits::webgl::{ActiveAttribInfo, WebGLBufferId, WebGLFramebufferId, WebGLProgramId, WebGLRenderbufferId}; -use canvas_traits::webgl::{WebGLChan, WebGLContextShareMode, WebGLError, WebGLPipeline, WebGLMsgSender}; -use canvas_traits::webgl::{WebGLReceiver, WebGLSender, WebGLShaderId, WebGLTextureId, WebGLVertexArrayId}; -use canvas_traits::webgl::{WebGLSLVersion, WebGLVersion}; +use canvas_traits::webgl::{ActiveAttribInfo, ActiveUniformInfo, WebGLBufferId, WebGLChan}; +use canvas_traits::webgl::{WebGLContextShareMode, WebGLError, WebGLFramebufferId, WebGLMsgSender}; +use canvas_traits::webgl::{WebGLPipeline, WebGLProgramId, WebGLReceiver, WebGLRenderbufferId}; +use canvas_traits::webgl::{WebGLSLVersion, WebGLSender, WebGLShaderId, WebGLTextureId}; +use canvas_traits::webgl::{WebGLVersion, WebGLVertexArrayId}; use cssparser::RGBA; use devtools_traits::{CSSError, TimelineMarkerType, WorkerId}; use dom::abstractworker::SharedRt; @@ -343,6 +344,7 @@ unsafe impl JSTraceable for (A, } unsafe_no_jsmanaged_fields!(ActiveAttribInfo); +unsafe_no_jsmanaged_fields!(ActiveUniformInfo); unsafe_no_jsmanaged_fields!(bool, f32, f64, String, AtomicBool, AtomicUsize, Uuid, char); unsafe_no_jsmanaged_fields!(usize, u8, u16, u32, u64); unsafe_no_jsmanaged_fields!(isize, i8, i16, i32, i64); diff --git a/components/script/dom/webglprogram.rs b/components/script/dom/webglprogram.rs index d5902e1afff..e2a6f8fcf8d 100644 --- a/components/script/dom/webglprogram.rs +++ b/components/script/dom/webglprogram.rs @@ -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::{ActiveAttribInfo, WebGLCommand, WebGLError, WebGLMsgSender}; -use canvas_traits::webgl::{WebGLProgramId, WebGLResult, from_name_in_compiled_shader}; -use canvas_traits::webgl::{to_name_in_compiled_shader, webgl_channel}; +use canvas_traits::webgl::{ActiveAttribInfo, ActiveUniformInfo, WebGLCommand, WebGLError, WebGLMsgSender}; +use canvas_traits::webgl::{WebGLProgramId, WebGLResult, to_name_in_compiled_shader, webgl_channel}; use dom::bindings::cell::DomRefCell; use dom::bindings::codegen::Bindings::WebGLProgramBinding; use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants; @@ -33,6 +32,7 @@ pub struct WebGLProgram { #[ignore_malloc_size_of = "Defined in ipc-channel"] renderer: WebGLMsgSender, active_attribs: DomRefCell>, + active_uniforms: DomRefCell>, } impl WebGLProgram { @@ -49,6 +49,7 @@ impl WebGLProgram { vertex_shader: Default::default(), renderer: renderer, active_attribs: DomRefCell::new(vec![].into()), + active_uniforms: DomRefCell::new(vec![].into()), } } @@ -123,20 +124,30 @@ impl WebGLProgram { self.renderer.send(WebGLCommand::LinkProgram(self.id, sender)).unwrap(); let link_info = receiver.recv().unwrap(); - // https://www.khronos.org/registry/webgl/specs/latest/1.0/#6.31 - let mut used_locs = FnvHashSet::default(); - for active_attrib in &*link_info.active_attribs { - if active_attrib.location == -1 { - continue; + { + let mut used_locs = FnvHashSet::default(); + let mut used_names = FnvHashSet::default(); + for active_attrib in &*link_info.active_attribs { + if active_attrib.location == -1 { + continue; + } + let columns = match active_attrib.type_ { + constants::FLOAT_MAT2 => 2, + constants::FLOAT_MAT3 => 3, + constants::FLOAT_MAT4 => 4, + _ => 1, + }; + assert!(used_names.insert(&*active_attrib.name)); + for column in 0..columns { + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#6.31 + if !used_locs.insert(active_attrib.location as u32 + column) { + return Ok(()); + } + } } - let columns = match active_attrib.type_ { - constants::FLOAT_MAT2 => 2, - constants::FLOAT_MAT3 => 3, - constants::FLOAT_MAT4 => 4, - _ => 1, - }; - for column in 0..columns { - if !used_locs.insert(active_attrib.location as u32 + column) { + for active_uniform in &*link_info.active_uniforms { + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#6.41 + if !used_names.insert(&*active_uniform.name) { return Ok(()); } } @@ -144,6 +155,7 @@ impl WebGLProgram { self.linked.set(link_info.linked); *self.active_attribs.borrow_mut() = link_info.active_attribs; + *self.active_uniforms.borrow_mut() = link_info.active_uniforms; Ok(()) } @@ -151,6 +163,10 @@ impl WebGLProgram { Ref::map(self.active_attribs.borrow(), |attribs| &**attribs) } + pub fn active_uniforms(&self) -> Ref<[ActiveUniformInfo]> { + Ref::map(self.active_uniforms.borrow(), |uniforms| &**uniforms) + } + /// glValidateProgram pub fn validate(&self) -> WebGLResult<()> { if self.is_deleted() { @@ -244,15 +260,14 @@ impl WebGLProgram { if self.is_deleted() { return Err(WebGLError::InvalidValue); } - let (sender, receiver) = webgl_channel().unwrap(); - self.renderer - .send(WebGLCommand::GetActiveUniform(self.id, index, sender)) - .unwrap(); - - receiver.recv().unwrap().map(|(size, ty, name)| { - let name = DOMString::from(from_name_in_compiled_shader(&name)); - WebGLActiveInfo::new(self.global().as_window(), size, ty, name) - }) + let uniforms = self.active_uniforms.borrow(); + let data = uniforms.get(index as usize).ok_or(WebGLError::InvalidValue)?; + Ok(WebGLActiveInfo::new( + self.global().as_window(), + data.size, + data.type_, + data.name.clone().into(), + )) } /// glGetActiveAttrib diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index 34d085d7f6b..2a64fb6b938 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -2693,12 +2693,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { Int32Value(program.attached_shaders().map(|shaders| shaders.len() as i32).unwrap_or(0)) } constants::ACTIVE_ATTRIBUTES => Int32Value(program.active_attribs().len() as i32), - constants::ACTIVE_UNIFORMS => { - // FIXME(nox): We'll need to cache that on the DOM side at some point. - let (sender, receiver) = webgl_channel().unwrap(); - self.send_command(WebGLCommand::GetProgramActiveUniforms(program.id(), sender)); - Int32Value(receiver.recv().unwrap()) - } + constants::ACTIVE_UNIFORMS => Int32Value(program.active_uniforms().len() as i32), _ => { self.webgl_error(InvalidEnum); NullValue() From e7631cea61b870db37d6b609e516ec64dd254849 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Wed, 11 Jul 2018 12:18:51 +0200 Subject: [PATCH 3/4] Move ANGLE name shenanigans to WebGL thread --- components/canvas/webgl_thread.rs | 53 +++++++++++++++++++++++---- components/canvas_traits/webgl.rs | 36 ------------------ components/script/dom/webglprogram.rs | 12 ++---- 3 files changed, 50 insertions(+), 51 deletions(-) diff --git a/components/canvas/webgl_thread.rs b/components/canvas/webgl_thread.rs index 3bfe49125ba..5fb1fad4eba 100644 --- a/components/canvas/webgl_thread.rs +++ b/components/canvas/webgl_thread.rs @@ -646,8 +646,9 @@ impl WebGLImpl { ctx.gl().attach_shader(program_id.get(), shader_id.get()), WebGLCommand::DetachShader(program_id, shader_id) => ctx.gl().detach_shader(program_id.get(), shader_id.get()), - WebGLCommand::BindAttribLocation(program_id, index, ref name) => - ctx.gl().bind_attrib_location(program_id.get(), index, name), + WebGLCommand::BindAttribLocation(program_id, index, ref name) => { + ctx.gl().bind_attrib_location(program_id.get(), index, &to_name_in_compiled_shader(name)) + } WebGLCommand::BlendColor(r, g, b, a) => ctx.gl().blend_color(r, g, b, a), WebGLCommand::BlendEquation(mode) => @@ -1100,11 +1101,13 @@ impl WebGLImpl { chan.send(parameter).unwrap(); } - fn uniform_location(gl: &gl::Gl, - program_id: WebGLProgramId, - name: &str, - chan: &WebGLSender>) { - let location = gl.get_uniform_location(program_id.get(), name); + fn uniform_location( + gl: &gl::Gl, + program_id: WebGLProgramId, + name: &str, + chan: &WebGLSender>, + ) { + let location = gl.get_uniform_location(program_id.get(), &to_name_in_compiled_shader(name)); let location = if location == -1 { None } else { @@ -1223,3 +1226,39 @@ impl WebGLImpl { gl.compile_shader(shader_id.get()); } } + +/// ANGLE adds a `_u` prefix to variable names: +/// +/// https://chromium.googlesource.com/angle/angle/+/855d964bd0d05f6b2cb303f625506cf53d37e94f +/// +/// To avoid hard-coding this we would need to use the `sh::GetAttributes` and `sh::GetUniforms` +/// API to look up the `x.name` and `x.mappedName` members. +const ANGLE_NAME_PREFIX: &'static str = "_u"; + +fn to_name_in_compiled_shader(s: &str) -> String { + map_dot_separated(s, |s, mapped| { + mapped.push_str(ANGLE_NAME_PREFIX); + mapped.push_str(s); + }) +} + +fn from_name_in_compiled_shader(s: &str) -> String { + map_dot_separated(s, |s, mapped| { + mapped.push_str(if s.starts_with(ANGLE_NAME_PREFIX) { + &s[ANGLE_NAME_PREFIX.len()..] + } else { + s + }) + }) +} + +fn map_dot_separated(s: &str, f: F) -> String { + let mut iter = s.split('.'); + let mut mapped = String::new(); + f(iter.next().unwrap(), &mut mapped); + for s in iter { + mapped.push('.'); + f(s, &mut mapped); + } + mapped +} diff --git a/components/canvas_traits/webgl.rs b/components/canvas_traits/webgl.rs index 451a3d19f19..0d9046656d0 100644 --- a/components/canvas_traits/webgl.rs +++ b/components/canvas_traits/webgl.rs @@ -589,39 +589,3 @@ parameters! { }), } } - -/// ANGLE adds a `_u` prefix to variable names: -/// -/// https://chromium.googlesource.com/angle/angle/+/855d964bd0d05f6b2cb303f625506cf53d37e94f -/// -/// To avoid hard-coding this we would need to use the `sh::GetAttributes` and `sh::GetUniforms` -/// API to look up the `x.name` and `x.mappedName` members. -const ANGLE_NAME_PREFIX: &'static str = "_u"; - -pub fn to_name_in_compiled_shader(s: &str) -> String { - map_dot_separated(s, |s, mapped| { - mapped.push_str(ANGLE_NAME_PREFIX); - mapped.push_str(s); - }) -} - -pub fn from_name_in_compiled_shader(s: &str) -> String { - map_dot_separated(s, |s, mapped| { - mapped.push_str(if s.starts_with(ANGLE_NAME_PREFIX) { - &s[ANGLE_NAME_PREFIX.len()..] - } else { - s - }) - }) -} - -fn map_dot_separated(s: &str, f: F) -> String { - let mut iter = s.split('.'); - let mut mapped = String::new(); - f(iter.next().unwrap(), &mut mapped); - for s in iter { - mapped.push('.'); - f(s, &mut mapped); - } - mapped -} diff --git a/components/script/dom/webglprogram.rs b/components/script/dom/webglprogram.rs index e2a6f8fcf8d..f0d86b4bc69 100644 --- a/components/script/dom/webglprogram.rs +++ b/components/script/dom/webglprogram.rs @@ -3,8 +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::{ActiveAttribInfo, ActiveUniformInfo, WebGLCommand, WebGLError, WebGLMsgSender}; -use canvas_traits::webgl::{WebGLProgramId, WebGLResult, to_name_in_compiled_shader, webgl_channel}; +use canvas_traits::webgl::{ActiveAttribInfo, ActiveUniformInfo, WebGLCommand, WebGLError}; +use canvas_traits::webgl::{WebGLMsgSender, WebGLProgramId, WebGLResult, webgl_channel}; use dom::bindings::cell::DomRefCell; use dom::bindings::codegen::Bindings::WebGLProgramBinding; use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants; @@ -248,10 +248,8 @@ impl WebGLProgram { return Err(WebGLError::InvalidOperation); } - let name = to_name_in_compiled_shader(&name); - self.renderer - .send(WebGLCommand::BindAttribLocation(self.id, index, name)) + .send(WebGLCommand::BindAttribLocation(self.id, index, name.into())) .unwrap(); Ok(()) } @@ -326,11 +324,9 @@ impl WebGLProgram { return Ok(None); } - let name = to_name_in_compiled_shader(&name); - let (sender, receiver) = webgl_channel().unwrap(); self.renderer - .send(WebGLCommand::GetUniformLocation(self.id, name, sender)) + .send(WebGLCommand::GetUniformLocation(self.id, name.into(), sender)) .unwrap(); Ok(receiver.recv().unwrap()) } From 476640c3ab65d4405f2e3233d2a0dab3d674b7ea Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Mon, 16 Jul 2018 10:16:08 +0200 Subject: [PATCH 4/4] Use active uniforms data to implement gl.uniform* checks --- components/canvas/webgl_thread.rs | 36 +- components/canvas_traits/webgl.rs | 29 +- components/script/dom/webglprogram.rs | 48 +- .../script/dom/webglrenderingcontext.rs | 538 +++++++++++------- components/script/dom/webgluniformlocation.rs | 46 +- .../misc/type-conversion-test.html.ini | 19 +- .../functions/uniformMatrixBadArgs.html.ini | 4 +- .../more/functions/uniformfBadArgs.html.ini | 6 - .../more/functions/uniformiBadArgs.html.ini | 6 - .../uniforms/gl-uniform-arrays.html.ini | 6 +- .../uniforms/gl-uniformmatrix4fv.html.ini | 35 -- .../uniforms/uniform-default-values.html.ini | 4 - .../uniforms/uniform-location.html.ini | 1 - .../uniforms/uniform-samplers-test.html.ini | 3 - 14 files changed, 477 insertions(+), 304 deletions(-) delete mode 100644 tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/more/functions/uniformfBadArgs.html.ini delete mode 100644 tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/more/functions/uniformiBadArgs.html.ini delete mode 100644 tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/uniforms/gl-uniformmatrix4fv.html.ini delete mode 100644 tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/uniforms/uniform-samplers-test.html.ini diff --git a/components/canvas/webgl_thread.rs b/components/canvas/webgl_thread.rs index 5fb1fad4eba..4c6deace945 100644 --- a/components/canvas/webgl_thread.rs +++ b/components/canvas/webgl_thread.rs @@ -817,12 +817,15 @@ impl WebGLImpl { ctx.gl().uniform_4i(uniform_id, x, y, z, w), WebGLCommand::Uniform4iv(uniform_id, ref v) => ctx.gl().uniform_4iv(uniform_id, v), - WebGLCommand::UniformMatrix2fv(uniform_id, transpose, ref v) => - ctx.gl().uniform_matrix_2fv(uniform_id, transpose, v), - WebGLCommand::UniformMatrix3fv(uniform_id, transpose, ref v) => - ctx.gl().uniform_matrix_3fv(uniform_id, transpose, v), - WebGLCommand::UniformMatrix4fv(uniform_id, transpose, ref v) => - ctx.gl().uniform_matrix_4fv(uniform_id, transpose, v), + WebGLCommand::UniformMatrix2fv(uniform_id, ref v) => { + ctx.gl().uniform_matrix_2fv(uniform_id, false, v) + } + WebGLCommand::UniformMatrix3fv(uniform_id, ref v) => { + ctx.gl().uniform_matrix_3fv(uniform_id, false, v) + } + WebGLCommand::UniformMatrix4fv(uniform_id, ref v) => { + ctx.gl().uniform_matrix_4fv(uniform_id, false, v) + } WebGLCommand::ValidateProgram(program_id) => ctx.gl().validate_program(program_id.get()), WebGLCommand::VertexAttrib(attrib_id, x, y, z, w) => @@ -1032,10 +1035,16 @@ impl WebGLImpl { let active_uniforms = (0..num_active_uniforms[0] as u32).map(|i| { // FIXME(nox): This allocates strings sometimes for nothing // and the gleam method keeps getting ACTIVE_UNIFORM_MAX_LENGTH. - let (size, type_, name) = gl.get_active_uniform(program.get(), i); + let (size, type_, mut name) = gl.get_active_uniform(program.get(), i); + let is_array = name.ends_with("[0]"); + if is_array { + // FIXME(nox): NLL + let len = name.len(); + name.truncate(len - 3); + } ActiveUniformInfo { - name: from_name_in_compiled_shader(&name), - size, + base_name: from_name_in_compiled_shader(&name).into(), + size: if is_array { Some(size) } else { None }, type_, } }).collect::>().into(); @@ -1105,15 +1114,10 @@ impl WebGLImpl { gl: &gl::Gl, program_id: WebGLProgramId, name: &str, - chan: &WebGLSender>, + chan: &WebGLSender, ) { let location = gl.get_uniform_location(program_id.get(), &to_name_in_compiled_shader(name)); - let location = if location == -1 { - None - } else { - Some(location) - }; - + assert!(location >= 0); chan.send(location).unwrap(); } diff --git a/components/canvas_traits/webgl.rs b/components/canvas_traits/webgl.rs index 0d9046656d0..e4fc9d0d739 100644 --- a/components/canvas_traits/webgl.rs +++ b/components/canvas_traits/webgl.rs @@ -6,6 +6,7 @@ use euclid::Size2D; use gleam::gl; use offscreen_gl_context::{GLContextAttributes, GLLimits}; use serde_bytes::ByteBuf; +use std::borrow::Cow; use std::num::NonZeroU32; use webrender_api::{DocumentId, ImageKey, PipelineId}; @@ -207,7 +208,7 @@ pub enum WebGLCommand { FramebufferTexture2D(u32, u32, u32, Option, i32), GetExtensions(WebGLSender), GetShaderPrecisionFormat(u32, u32, WebGLSender<(i32, i32, i32)>), - GetUniformLocation(WebGLProgramId, String, WebGLSender>), + GetUniformLocation(WebGLProgramId, String, WebGLSender), GetShaderInfoLog(WebGLShaderId, WebGLSender), GetProgramInfoLog(WebGLProgramId, WebGLSender), GetFramebufferAttachmentParameter(u32, u32, u32, WebGLSender), @@ -244,9 +245,9 @@ pub enum WebGLCommand { Uniform4fv(i32, Vec), Uniform4i(i32, i32, i32, i32, i32), Uniform4iv(i32, Vec), - UniformMatrix2fv(i32, bool, Vec), - UniformMatrix3fv(i32, bool, Vec), - UniformMatrix4fv(i32, bool, Vec), + UniformMatrix2fv(i32, Vec), + UniformMatrix3fv(i32, Vec), + UniformMatrix4fv(i32, Vec), UseProgram(Option), ValidateProgram(WebGLProgramId), VertexAttrib(u32, f32, f32, f32, f32), @@ -443,14 +444,26 @@ pub struct ActiveAttribInfo { /// Description of a single active uniform. #[derive(Clone, Deserialize, MallocSizeOf, Serialize)] pub struct ActiveUniformInfo { - /// The name of the uniform. - pub name: String, - /// The size of the uniform. - pub size: i32, + /// The base name of the uniform. + pub base_name: Box, + /// The size of the uniform, if it is an array. + pub size: Option, /// The type of the uniform. pub type_: u32, } +impl ActiveUniformInfo { + pub fn name(&self) -> Cow { + if self.size.is_some() { + let mut name = String::from(&*self.base_name); + name.push_str("[0]"); + Cow::Owned(name) + } else { + Cow::Borrowed(&self.base_name) + } + } +} + macro_rules! parameters { ($name:ident { $( $variant:ident($kind:ident { $( diff --git a/components/script/dom/webglprogram.rs b/components/script/dom/webglprogram.rs index f0d86b4bc69..8a354ffe9f2 100644 --- a/components/script/dom/webglprogram.rs +++ b/components/script/dom/webglprogram.rs @@ -15,6 +15,7 @@ use dom::webglactiveinfo::WebGLActiveInfo; use dom::webglobject::WebGLObject; use dom::webglrenderingcontext::MAX_UNIFORM_AND_ATTRIBUTE_LEN; use dom::webglshader::WebGLShader; +use dom::webgluniformlocation::WebGLUniformLocation; use dom::window::Window; use dom_struct::dom_struct; use fnv::FnvHashSet; @@ -147,7 +148,7 @@ impl WebGLProgram { } for active_uniform in &*link_info.active_uniforms { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#6.41 - if !used_names.insert(&*active_uniform.name) { + if !used_names.insert(&*active_uniform.base_name) { return Ok(()); } } @@ -262,9 +263,9 @@ impl WebGLProgram { let data = uniforms.get(index as usize).ok_or(WebGLError::InvalidValue)?; Ok(WebGLActiveInfo::new( self.global().as_window(), - data.size, + data.size.unwrap_or(1), data.type_, - data.name.clone().into(), + data.name().into(), )) } @@ -311,7 +312,10 @@ impl WebGLProgram { } /// glGetUniformLocation - pub fn get_uniform_location(&self, name: DOMString) -> WebGLResult> { + pub fn get_uniform_location( + &self, + name: DOMString, + ) -> WebGLResult>> { if !self.is_linked() || self.is_deleted() { return Err(WebGLError::InvalidOperation); } @@ -320,15 +324,37 @@ impl WebGLProgram { } // Check if the name is reserved - if name.starts_with("webgl") || name.starts_with("_webgl_") { + if name.starts_with("gl_") { return Ok(None); } + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#GLSL_CONSTRUCTS + if name.starts_with("webgl_") || name.starts_with("_webgl_") { + return Ok(None); + } + + let (size, type_) = { + let (base_name, array_index) = match parse_uniform_name(&name) { + Some((name, index)) if index.map_or(true, |i| i >= 0) => (name, index), + _ => return Ok(None), + }; + + let uniforms = self.active_uniforms.borrow(); + match uniforms.iter().find(|attrib| &*attrib.base_name == base_name) { + Some(uniform) if array_index.is_none() || array_index < uniform.size => { + (uniform.size.map(|size| size - array_index.unwrap_or_default()), uniform.type_) + }, + _ => return Ok(None), + } + }; + let (sender, receiver) = webgl_channel().unwrap(); self.renderer .send(WebGLCommand::GetUniformLocation(self.id, name.into(), sender)) .unwrap(); - Ok(receiver.recv().unwrap()) + let location = receiver.recv().unwrap(); + + Ok(Some(WebGLUniformLocation::new(self.global().as_window(), location, self.id, size, type_))) } /// glGetProgramInfoLog @@ -369,3 +395,13 @@ impl Drop for WebGLProgram { self.delete(); } } + + +fn parse_uniform_name(name: &str) -> Option<(&str, Option)> { + if !name.ends_with(']') { + return Some((name, None)); + } + let bracket_pos = name[..name.len() - 1].rfind('[')?; + let index = name[(bracket_pos + 1)..(name.len() - 1)].parse::().ok()?; + Some((&name[..bracket_pos], Some(index))) +} diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index 2a64fb6b938..317a51d0cbf 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -425,6 +425,21 @@ impl WebGLRenderingContext { } } + fn with_location(&self, location: Option<&WebGLUniformLocation>, f: F) + where + F: FnOnce(&WebGLUniformLocation) -> WebGLResult<()>, + { + let location = match location { + Some(loc) => loc, + None => return, + }; + match self.current_program.get() { + Some(ref program) if program.id() == location.program_id() => {} + _ => return self.webgl_error(InvalidOperation), + } + handle_potential_webgl_error!(self, f(location)); + } + fn tex_parameter(&self, target: u32, name: u32, value: TexParameterValue) { let texture = match target { constants::TEXTURE_2D | @@ -528,38 +543,6 @@ impl WebGLRenderingContext { } } - // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 - // https://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml - // https://www.khronos.org/registry/gles/specs/2.0/es_full_spec_2.0.25.pdf#nameddest=section-2.10.4 - fn validate_uniform_parameters(&self, - uniform: Option<&WebGLUniformLocation>, - uniform_type: UniformSetterType, - data: &[T]) -> bool { - let uniform = match uniform { - Some(uniform) => uniform, - None => return false, - }; - - let program = self.current_program.get(); - match program { - Some(ref program) if program.id() == uniform.program_id() => {}, - _ => { - self.webgl_error(InvalidOperation); - return false; - }, - }; - - // TODO(emilio): Get more complex uniform info from ANGLE, and use it to - // properly validate that the uniform setter type is compatible with the - // uniform type, and that the uniform size matches. - if data.len() % uniform_type.element_count() != 0 { - self.webgl_error(InvalidOperation); - return false; - } - - true - } - // https://en.wikipedia.org/wiki/Relative_luminance #[inline] fn luminance(r: u8, g: u8, b: u8) -> u8 { @@ -2762,9 +2745,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { program: &WebGLProgram, name: DOMString, ) -> Option> { - handle_potential_webgl_error!(self, program.get_uniform_location(name), None).map(|location| { - WebGLUniformLocation::new(self.global().as_window(), location, program.id()) - }) + handle_potential_webgl_error!(self, program.get_uniform_location(name), None) } #[allow(unsafe_code)] @@ -3166,75 +3147,145 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 - fn Uniform1f(&self, - location: Option<&WebGLUniformLocation>, - val: f32) { - if self.validate_uniform_parameters(location, UniformSetterType::Float, &[val]) { - self.send_command(WebGLCommand::Uniform1f(location.unwrap().id(), val)) - } + fn Uniform1f( + &self, + location: Option<&WebGLUniformLocation>, + val: f32, + ) { + self.with_location(location, |location| { + match location.type_() { + constants::BOOL | constants::FLOAT => {} + _ => return Err(InvalidOperation), + } + self.send_command(WebGLCommand::Uniform1f(location.id(), val)); + Ok(()) + }); } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 - fn Uniform1i(&self, - location: Option<&WebGLUniformLocation>, - val: i32) { - if self.validate_uniform_parameters(location, UniformSetterType::Int, &[val]) { - self.send_command(WebGLCommand::Uniform1i(location.unwrap().id(), val)) - } + fn Uniform1i( + &self, + location: Option<&WebGLUniformLocation>, + val: i32, + ) { + self.with_location(location, |location| { + match location.type_() { + constants::BOOL | constants::INT => {} + constants::SAMPLER_2D | constants::SAMPLER_CUBE => { + if val < 0 || val as u32 >= self.limits.max_combined_texture_image_units { + return Err(InvalidValue); + } + } + _ => return Err(InvalidOperation), + } + self.send_command(WebGLCommand::Uniform1i(location.id(), val)); + Ok(()) + }); } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 fn Uniform1iv( &self, location: Option<&WebGLUniformLocation>, - v: Int32ArrayOrLongSequence, + val: Int32ArrayOrLongSequence, ) { - let v = match v { - Int32ArrayOrLongSequence::Int32Array(v) => v.to_vec(), - Int32ArrayOrLongSequence::LongSequence(v) => v, - }; - if self.validate_uniform_parameters(location, UniformSetterType::Int, &v) { - self.send_command(WebGLCommand::Uniform1iv(location.unwrap().id(), v)) - } + self.with_location(location, |location| { + match location.type_() { + constants::BOOL | constants::INT | constants::SAMPLER_2D | constants::SAMPLER_CUBE => {} + _ => return Err(InvalidOperation), + } + let val = match val { + Int32ArrayOrLongSequence::Int32Array(v) => v.to_vec(), + Int32ArrayOrLongSequence::LongSequence(v) => v, + }; + if val.is_empty() { + return Err(InvalidValue); + } + if location.size().is_none() && val.len() != 1 { + return Err(InvalidOperation); + } + match location.type_() { + constants::SAMPLER_2D | constants::SAMPLER_CUBE => { + for &v in val.iter().take(cmp::min(location.size().unwrap_or(1) as usize, val.len())) { + if v < 0 || v as u32 >= self.limits.max_combined_texture_image_units { + return Err(InvalidValue); + } + } + } + _ => {} + } + self.send_command(WebGLCommand::Uniform1iv(location.id(), val)); + Ok(()) + }); } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 fn Uniform1fv( &self, location: Option<&WebGLUniformLocation>, - v: Float32ArrayOrUnrestrictedFloatSequence, + val: Float32ArrayOrUnrestrictedFloatSequence, ) { - let v = match v { - Float32ArrayOrUnrestrictedFloatSequence::Float32Array(v) => v.to_vec(), - Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v, - }; - if self.validate_uniform_parameters(location, UniformSetterType::Float, &v) { - self.send_command(WebGLCommand::Uniform1fv(location.unwrap().id(), v)); - } + self.with_location(location, |location| { + match location.type_() { + constants::BOOL | constants::FLOAT => {} + _ => return Err(InvalidOperation), + } + let val = match val { + Float32ArrayOrUnrestrictedFloatSequence::Float32Array(v) => v.to_vec(), + Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v, + }; + if val.is_empty() { + return Err(InvalidValue); + } + if location.size().is_none() && val.len() != 1 { + return Err(InvalidOperation); + } + self.send_command(WebGLCommand::Uniform1fv(location.id(), val)); + Ok(()) + }); } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 - fn Uniform2f(&self, - location: Option<&WebGLUniformLocation>, - x: f32, y: f32) { - if self.validate_uniform_parameters(location, UniformSetterType::FloatVec2, &[x, y]) { - self.send_command(WebGLCommand::Uniform2f(location.unwrap().id(), x, y)); - } + fn Uniform2f( + &self, + location: Option<&WebGLUniformLocation>, + x: f32, + y: f32, + ) { + self.with_location(location, |location| { + match location.type_() { + constants::BOOL_VEC2 | constants::FLOAT_VEC2 => {} + _ => return Err(InvalidOperation), + } + self.send_command(WebGLCommand::Uniform2f(location.id(), x, y)); + Ok(()) + }); } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 fn Uniform2fv( &self, location: Option<&WebGLUniformLocation>, - v: Float32ArrayOrUnrestrictedFloatSequence, + val: Float32ArrayOrUnrestrictedFloatSequence, ) { - let v = match v { - Float32ArrayOrUnrestrictedFloatSequence::Float32Array(v) => v.to_vec(), - Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v, - }; - if self.validate_uniform_parameters(location, UniformSetterType::FloatVec2, &v) { - self.send_command(WebGLCommand::Uniform2fv(location.unwrap().id(), v)); - } + self.with_location(location, |location| { + match location.type_() { + constants::BOOL_VEC2 | constants::FLOAT_VEC2 => {} + _ => return Err(InvalidOperation), + } + let val = match val { + Float32ArrayOrUnrestrictedFloatSequence::Float32Array(v) => v.to_vec(), + Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v, + }; + if val.len() < 2 || val.len() % 2 != 0 { + return Err(InvalidValue); + } + if location.size().is_none() && val.len() != 2 { + return Err(InvalidOperation); + } + self.send_command(WebGLCommand::Uniform2fv(location.id(), val)); + Ok(()) + }); } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 @@ -3244,26 +3295,40 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { x: i32, y: i32, ) { - if self.validate_uniform_parameters(location, - UniformSetterType::IntVec2, - &[x, y]) { - self.send_command(WebGLCommand::Uniform2i(location.unwrap().id(), x, y)); - } + self.with_location(location, |location| { + match location.type_() { + constants::BOOL_VEC2 | constants::INT_VEC2 => {} + _ => return Err(InvalidOperation), + } + self.send_command(WebGLCommand::Uniform2i(location.id(), x, y)); + Ok(()) + }); } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 fn Uniform2iv( &self, location: Option<&WebGLUniformLocation>, - v: Int32ArrayOrLongSequence, + val: Int32ArrayOrLongSequence, ) { - let v = match v { - Int32ArrayOrLongSequence::Int32Array(v) => v.to_vec(), - Int32ArrayOrLongSequence::LongSequence(v) => v, - }; - if self.validate_uniform_parameters(location, UniformSetterType::IntVec2, &v) { - self.send_command(WebGLCommand::Uniform2iv(location.unwrap().id(), v)); - } + self.with_location(location, |location| { + match location.type_() { + constants::BOOL_VEC2 | constants::INT_VEC2 => {} + _ => return Err(InvalidOperation), + } + let val = match val { + Int32ArrayOrLongSequence::Int32Array(v) => v.to_vec(), + Int32ArrayOrLongSequence::LongSequence(v) => v, + }; + if val.len() < 2 || val.len() % 2 != 0 { + return Err(InvalidValue); + } + if location.size().is_none() && val.len() != 2 { + return Err(InvalidOperation); + } + self.send_command(WebGLCommand::Uniform2iv(location.id(), val)); + Ok(()) + }); } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 @@ -3274,52 +3339,84 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { y: f32, z: f32, ) { - if self.validate_uniform_parameters(location, - UniformSetterType::FloatVec3, - &[x, y, z]) { - self.send_command(WebGLCommand::Uniform3f(location.unwrap().id(), x, y, z)); - } + self.with_location(location, |location| { + match location.type_() { + constants::BOOL_VEC3 | constants::FLOAT_VEC3 => {} + _ => return Err(InvalidOperation), + } + self.send_command(WebGLCommand::Uniform3f(location.id(), x, y, z)); + Ok(()) + }); } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 fn Uniform3fv( &self, location: Option<&WebGLUniformLocation>, - v: Float32ArrayOrUnrestrictedFloatSequence, + val: Float32ArrayOrUnrestrictedFloatSequence, ) { - let v = match v { - Float32ArrayOrUnrestrictedFloatSequence::Float32Array(v) => v.to_vec(), - Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v, - }; - if self.validate_uniform_parameters(location, UniformSetterType::FloatVec3, &v) { - self.send_command(WebGLCommand::Uniform3fv(location.unwrap().id(), v)) - } + self.with_location(location, |location| { + match location.type_() { + constants::BOOL_VEC3 | constants::FLOAT_VEC3 => {} + _ => return Err(InvalidOperation), + } + let val = match val { + Float32ArrayOrUnrestrictedFloatSequence::Float32Array(v) => v.to_vec(), + Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v, + }; + if val.len() < 3 || val.len() % 3 != 0 { + return Err(InvalidValue); + } + if location.size().is_none() && val.len() != 3 { + return Err(InvalidOperation); + } + self.send_command(WebGLCommand::Uniform3fv(location.id(), val)); + Ok(()) + }); } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 - fn Uniform3i(&self, - location: Option<&WebGLUniformLocation>, - x: i32, y: i32, z: i32) { - if self.validate_uniform_parameters(location, - UniformSetterType::IntVec3, - &[x, y, z]) { - self.send_command(WebGLCommand::Uniform3i(location.unwrap().id(), x, y, z)) - } + fn Uniform3i( + &self, + location: Option<&WebGLUniformLocation>, + x: i32, + y: i32, + z: i32, + ) { + self.with_location(location, |location| { + match location.type_() { + constants::BOOL_VEC3 | constants::INT_VEC3 => {} + _ => return Err(InvalidOperation), + } + self.send_command(WebGLCommand::Uniform3i(location.id(), x, y, z)); + Ok(()) + }); } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 fn Uniform3iv( &self, location: Option<&WebGLUniformLocation>, - v: Int32ArrayOrLongSequence, + val: Int32ArrayOrLongSequence, ) { - let v = match v { - Int32ArrayOrLongSequence::Int32Array(v) => v.to_vec(), - Int32ArrayOrLongSequence::LongSequence(v) => v, - }; - if self.validate_uniform_parameters(location, UniformSetterType::IntVec3, &v) { - self.send_command(WebGLCommand::Uniform3iv(location.unwrap().id(), v)) - } + self.with_location(location, |location| { + match location.type_() { + constants::BOOL_VEC3 | constants::INT_VEC3 => {} + _ => return Err(InvalidOperation), + } + let val = match val { + Int32ArrayOrLongSequence::Int32Array(v) => v.to_vec(), + Int32ArrayOrLongSequence::LongSequence(v) => v, + }; + if val.len() < 3 || val.len() % 3 != 0 { + return Err(InvalidValue); + } + if location.size().is_none() && val.len() != 3 { + return Err(InvalidOperation); + } + self.send_command(WebGLCommand::Uniform3iv(location.id(), val)); + Ok(()) + }); } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 @@ -3331,11 +3428,14 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { z: i32, w: i32, ) { - if self.validate_uniform_parameters(location, - UniformSetterType::IntVec4, - &[x, y, z, w]) { - self.send_command(WebGLCommand::Uniform4i(location.unwrap().id(), x, y, z, w)) - } + self.with_location(location, |location| { + match location.type_() { + constants::BOOL_VEC4 | constants::INT_VEC4 => {} + _ => return Err(InvalidOperation), + } + self.send_command(WebGLCommand::Uniform4i(location.id(), x, y, z, w)); + Ok(()) + }); } @@ -3343,15 +3443,26 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { fn Uniform4iv( &self, location: Option<&WebGLUniformLocation>, - v: Int32ArrayOrLongSequence, + val: Int32ArrayOrLongSequence, ) { - let v = match v { - Int32ArrayOrLongSequence::Int32Array(v) => v.to_vec(), - Int32ArrayOrLongSequence::LongSequence(v) => v, - }; - if self.validate_uniform_parameters(location, UniformSetterType::IntVec4, &v) { - self.send_command(WebGLCommand::Uniform4iv(location.unwrap().id(), v)) - } + self.with_location(location, |location| { + match location.type_() { + constants::BOOL_VEC4 | constants::INT_VEC4 => {} + _ => return Err(InvalidOperation), + } + let val = match val { + Int32ArrayOrLongSequence::Int32Array(v) => v.to_vec(), + Int32ArrayOrLongSequence::LongSequence(v) => v, + }; + if val.len() < 4 || val.len() % 4 != 0 { + return Err(InvalidValue); + } + if location.size().is_none() && val.len() != 4 { + return Err(InvalidOperation); + } + self.send_command(WebGLCommand::Uniform4iv(location.id(), val)); + Ok(()) + }); } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 @@ -3363,26 +3474,40 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { z: f32, w: f32, ) { - if self.validate_uniform_parameters(location, - UniformSetterType::FloatVec4, - &[x, y, z, w]) { - self.send_command(WebGLCommand::Uniform4f(location.unwrap().id(), x, y, z, w)) - } + self.with_location(location, |location| { + match location.type_() { + constants::BOOL_VEC4 | constants::FLOAT_VEC4 => {} + _ => return Err(InvalidOperation), + } + self.send_command(WebGLCommand::Uniform4f(location.id(), x, y, z, w)); + Ok(()) + }); } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 fn Uniform4fv( &self, location: Option<&WebGLUniformLocation>, - v: Float32ArrayOrUnrestrictedFloatSequence, + val: Float32ArrayOrUnrestrictedFloatSequence, ) { - let v = match v { - Float32ArrayOrUnrestrictedFloatSequence::Float32Array(v) => v.to_vec(), - Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v, - }; - if self.validate_uniform_parameters(location, UniformSetterType::FloatVec4, &v) { - self.send_command(WebGLCommand::Uniform4fv(location.unwrap().id(), v)) - } + self.with_location(location, |location| { + match location.type_() { + constants::BOOL_VEC4 | constants::FLOAT_VEC4 => {} + _ => return Err(InvalidOperation), + } + let val = match val { + Float32ArrayOrUnrestrictedFloatSequence::Float32Array(v) => v.to_vec(), + Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v, + }; + if val.len() < 4 || val.len() % 4 != 0 { + return Err(InvalidValue); + } + if location.size().is_none() && val.len() != 4 { + return Err(InvalidOperation); + } + self.send_command(WebGLCommand::Uniform4fv(location.id(), val)); + Ok(()) + }); } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 @@ -3390,15 +3515,29 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { &self, location: Option<&WebGLUniformLocation>, transpose: bool, - v: Float32ArrayOrUnrestrictedFloatSequence, + val: Float32ArrayOrUnrestrictedFloatSequence, ) { - let v = match v { - Float32ArrayOrUnrestrictedFloatSequence::Float32Array(v) => v.to_vec(), - Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v, - }; - if self.validate_uniform_parameters(location, UniformSetterType::FloatMat2, &v) { - self.send_command(WebGLCommand::UniformMatrix2fv(location.unwrap().id(), transpose, v)); - } + self.with_location(location, |location| { + match location.type_() { + constants::FLOAT_MAT2 => {} + _ => return Err(InvalidOperation), + } + let val = match val { + Float32ArrayOrUnrestrictedFloatSequence::Float32Array(v) => v.to_vec(), + Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v, + }; + if transpose { + return Err(InvalidValue); + } + if val.len() < 4 || val.len() % 4 != 0 { + return Err(InvalidValue); + } + if location.size().is_none() && val.len() != 4 { + return Err(InvalidOperation); + } + self.send_command(WebGLCommand::UniformMatrix2fv(location.id(), val)); + Ok(()) + }); } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 @@ -3406,15 +3545,29 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { &self, location: Option<&WebGLUniformLocation>, transpose: bool, - v: Float32ArrayOrUnrestrictedFloatSequence, + val: Float32ArrayOrUnrestrictedFloatSequence, ) { - let v = match v { - Float32ArrayOrUnrestrictedFloatSequence::Float32Array(v) => v.to_vec(), - Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v, - }; - if self.validate_uniform_parameters(location, UniformSetterType::FloatMat3, &v) { - self.send_command(WebGLCommand::UniformMatrix3fv(location.unwrap().id(), transpose, v)); - } + self.with_location(location, |location| { + match location.type_() { + constants::FLOAT_MAT3 => {} + _ => return Err(InvalidOperation), + } + let val = match val { + Float32ArrayOrUnrestrictedFloatSequence::Float32Array(v) => v.to_vec(), + Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v, + }; + if transpose { + return Err(InvalidValue); + } + if val.len() < 9 || val.len() % 9 != 0 { + return Err(InvalidValue); + } + if location.size().is_none() && val.len() != 9 { + return Err(InvalidOperation); + } + self.send_command(WebGLCommand::UniformMatrix3fv(location.id(), val)); + Ok(()) + }); } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 @@ -3422,15 +3575,29 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { &self, location: Option<&WebGLUniformLocation>, transpose: bool, - v: Float32ArrayOrUnrestrictedFloatSequence, + val: Float32ArrayOrUnrestrictedFloatSequence, ) { - let v = match v { - Float32ArrayOrUnrestrictedFloatSequence::Float32Array(v) => v.to_vec(), - Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v, - }; - if self.validate_uniform_parameters(location, UniformSetterType::FloatMat4, &v) { - self.send_command(WebGLCommand::UniformMatrix4fv(location.unwrap().id(), transpose, v)); - } + self.with_location(location, |location| { + match location.type_() { + constants::FLOAT_MAT4 => {} + _ => return Err(InvalidOperation), + } + let val = match val { + Float32ArrayOrUnrestrictedFloatSequence::Float32Array(v) => v.to_vec(), + Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v, + }; + if transpose { + return Err(InvalidValue); + } + if val.len() < 16 || val.len() % 16 != 0 { + return Err(InvalidValue); + } + if location.size().is_none() && val.len() != 16 { + return Err(InvalidOperation); + } + self.send_command(WebGLCommand::UniformMatrix4fv(location.id(), val)); + Ok(()) + }); } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9 @@ -3932,39 +4099,6 @@ impl LayoutCanvasWebGLRenderingContextHelpers for LayoutDom usize { - match *self { - UniformSetterType::Int => 1, - UniformSetterType::IntVec2 => 2, - UniformSetterType::IntVec3 => 3, - UniformSetterType::IntVec4 => 4, - UniformSetterType::Float => 1, - UniformSetterType::FloatVec2 => 2, - UniformSetterType::FloatVec3 => 3, - UniformSetterType::FloatVec4 => 4, - UniformSetterType::FloatMat2 => 4, - UniformSetterType::FloatMat3 => 9, - UniformSetterType::FloatMat4 => 16, - } - } -} - #[derive(JSTraceable, MallocSizeOf)] #[must_root] pub struct VertexAttribs { diff --git a/components/script/dom/webgluniformlocation.rs b/components/script/dom/webgluniformlocation.rs index 45662a446d3..db44ff9c969 100644 --- a/components/script/dom/webgluniformlocation.rs +++ b/components/script/dom/webgluniformlocation.rs @@ -15,26 +15,38 @@ pub struct WebGLUniformLocation { reflector_: Reflector, id: i32, program_id: WebGLProgramId, + size: Option, + type_: u32, } impl WebGLUniformLocation { - fn new_inherited(id: i32, - program_id: WebGLProgramId) - -> WebGLUniformLocation { - WebGLUniformLocation { + fn new_inherited( + id: i32, + program_id: WebGLProgramId, + size: Option, + type_: u32, + ) -> Self { + Self { reflector_: Reflector::new(), - id: id, - program_id: program_id, + id, + program_id, + size, + type_, } } - pub fn new(window: &Window, - id: i32, - program_id: WebGLProgramId) - -> DomRoot { - reflect_dom_object(Box::new(WebGLUniformLocation::new_inherited(id, program_id)), - window, - WebGLUniformLocationBinding::Wrap) + pub fn new( + window: &Window, + id: i32, + program_id: WebGLProgramId, + size: Option, + type_: u32, + ) -> DomRoot { + reflect_dom_object( + Box::new(Self::new_inherited(id, program_id, size, type_)), + window, + WebGLUniformLocationBinding::Wrap, + ) } pub fn id(&self) -> i32 { @@ -44,4 +56,12 @@ impl WebGLUniformLocation { pub fn program_id(&self) -> WebGLProgramId { self.program_id } + + pub fn size(&self) -> Option { + self.size + } + + pub fn type_(&self) -> u32 { + self.type_ + } } diff --git a/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/misc/type-conversion-test.html.ini b/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/misc/type-conversion-test.html.ini index d25329622c1..b2775ef732b 100644 --- a/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/misc/type-conversion-test.html.ini +++ b/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/misc/type-conversion-test.html.ini @@ -1,3 +1,20 @@ [type-conversion-test.html] type: testharness - expected: CRASH + [WebGL test #340: context.bufferData(context.ARRAY_BUFFER, argument, context.STATIC_DRAW) should be undefined. Threw exception TypeError: Not an ArrayBufferView] + expected: FAIL + + [WebGL test #407: context.bufferData(context.ARRAY_BUFFER, argument, context.STATIC_DRAW) should be undefined. Threw exception TypeError: Not an ArrayBufferView] + expected: FAIL + + [WebGL test #474: context.bufferData(context.ARRAY_BUFFER, argument, context.STATIC_DRAW) should be undefined. Threw exception TypeError: Not an ArrayBufferView] + expected: FAIL + + [WebGL test #541: context.bufferData(context.ARRAY_BUFFER, argument, context.STATIC_DRAW) should be undefined. Threw exception TypeError: Not an ArrayBufferView] + expected: FAIL + + [WebGL test #608: context.bufferData(context.ARRAY_BUFFER, argument, context.STATIC_DRAW) should be undefined. Threw exception TypeError: Not an ArrayBufferView] + expected: FAIL + + [WebGL test #675: context.bufferData(context.ARRAY_BUFFER, argument, context.STATIC_DRAW) should be undefined. Threw exception TypeError: Not an ArrayBufferView] + expected: FAIL + diff --git a/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/more/functions/uniformMatrixBadArgs.html.ini b/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/more/functions/uniformMatrixBadArgs.html.ini index 41408c4132b..a9c34e61d2d 100644 --- a/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/more/functions/uniformMatrixBadArgs.html.ini +++ b/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/more/functions/uniformMatrixBadArgs.html.ini @@ -1,3 +1,5 @@ [uniformMatrixBadArgs.html] type: testharness - expected: CRASH + [WebGL test #0: testUniformf] + expected: FAIL + diff --git a/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/more/functions/uniformfBadArgs.html.ini b/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/more/functions/uniformfBadArgs.html.ini deleted file mode 100644 index 0a2ca6a8c1c..00000000000 --- a/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/more/functions/uniformfBadArgs.html.ini +++ /dev/null @@ -1,6 +0,0 @@ -[uniformfBadArgs.html] - type: testharness - expected: CRASH - [WebGL test #0: testUniformf] - expected: FAIL - diff --git a/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/more/functions/uniformiBadArgs.html.ini b/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/more/functions/uniformiBadArgs.html.ini deleted file mode 100644 index 3b6cf9cd8bf..00000000000 --- a/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/more/functions/uniformiBadArgs.html.ini +++ /dev/null @@ -1,6 +0,0 @@ -[uniformiBadArgs.html] - type: testharness - expected: CRASH - [WebGL test #0: testUniformf] - expected: FAIL - diff --git a/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/uniforms/gl-uniform-arrays.html.ini b/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/uniforms/gl-uniform-arrays.html.ini index 65adb481bd3..d557119df79 100644 --- a/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/uniforms/gl-uniform-arrays.html.ini +++ b/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/uniforms/gl-uniform-arrays.html.ini @@ -1,3 +1,5 @@ [gl-uniform-arrays.html] - type: testharness - disabled: flaky + expected: ERROR + [Overall test] + expected: NOTRUN + diff --git a/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/uniforms/gl-uniformmatrix4fv.html.ini b/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/uniforms/gl-uniformmatrix4fv.html.ini deleted file mode 100644 index 6558b7e815f..00000000000 --- a/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/uniforms/gl-uniformmatrix4fv.html.ini +++ /dev/null @@ -1,35 +0,0 @@ -[gl-uniformmatrix4fv.html] - type: testharness - [WebGL test #0: successfullyParsed should be true (of type boolean). Was undefined (of type undefined).] - expected: FAIL - - [WebGL uniformMatrix Conformance Tests] - expected: FAIL - - [WebGL test #0: getError expected: INVALID_VALUE. Was INVALID_OPERATION : should fail with insufficient array size for uniformMatrix2fv] - expected: FAIL - - [WebGL test #2: getError expected: INVALID_VALUE. Was INVALID_OPERATION : should fail with more than 1 array size for uniformMatrix2fv] - expected: FAIL - - [WebGL test #4: getError expected: INVALID_VALUE. Was NO_ERROR : uniformMatrix2fv should return INVALID_VALUE with transpose = true] - expected: FAIL - - [WebGL test #5: getError expected: INVALID_VALUE. Was INVALID_OPERATION : should fail with insufficient array size for uniformMatrix3fv] - expected: FAIL - - [WebGL test #7: getError expected: INVALID_VALUE. Was INVALID_OPERATION : should fail with more than 1 array size for uniformMatrix3fv] - expected: FAIL - - [WebGL test #9: getError expected: INVALID_VALUE. Was NO_ERROR : uniformMatrix3fv should return INVALID_VALUE with transpose = true] - expected: FAIL - - [WebGL test #10: getError expected: INVALID_VALUE. Was INVALID_OPERATION : should fail with insufficient array size for uniformMatrix4fv] - expected: FAIL - - [WebGL test #12: getError expected: INVALID_VALUE. Was INVALID_OPERATION : should fail with more than 1 array size for uniformMatrix4fv] - expected: FAIL - - [WebGL test #14: getError expected: INVALID_VALUE. Was NO_ERROR : uniformMatrix4fv should return INVALID_VALUE with transpose = true] - expected: FAIL - diff --git a/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/uniforms/uniform-default-values.html.ini b/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/uniforms/uniform-default-values.html.ini index bbd7c84970e..d438933647c 100644 --- a/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/uniforms/uniform-default-values.html.ini +++ b/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/uniforms/uniform-default-values.html.ini @@ -1,9 +1,5 @@ [uniform-default-values.html] - type: testharness expected: ERROR - [WebGL uniform default values] - expected: FAIL - [Overall test] expected: NOTRUN diff --git a/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/uniforms/uniform-location.html.ini b/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/uniforms/uniform-location.html.ini index 21de226cc01..fb6c9c25e94 100644 --- a/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/uniforms/uniform-location.html.ini +++ b/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/uniforms/uniform-location.html.ini @@ -1,5 +1,4 @@ [uniform-location.html] - type: testharness [WebGL test #9: contextA.getUniform(programS, locationSx) should be 333. Threw exception TypeError: contextA.getUniform is not a function] expected: FAIL diff --git a/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/uniforms/uniform-samplers-test.html.ini b/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/uniforms/uniform-samplers-test.html.ini deleted file mode 100644 index 77a8b35d2d4..00000000000 --- a/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/uniforms/uniform-samplers-test.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[uniform-samplers-test.html] - type: testharness - disabled: flaky