From a62a4b3ff3b7d72bb1765f4c59ae2e4a121aeb3f Mon Sep 17 00:00:00 2001 From: Igor Gutorov Date: Sat, 17 Mar 2018 20:32:40 +0200 Subject: [PATCH] Implement WebGL GetUniform API --- components/canvas/webgl_thread.rs | 40 ++++++++++++++++ components/canvas_traits/webgl.rs | 11 +++++ .../script/dom/webgl2renderingcontext.rs | 11 +++++ components/script/dom/webglprogram.rs | 48 +++++++++++++++++++ .../script/dom/webglrenderingcontext.rs | 40 +++++++++++++++- .../dom/webidls/WebGLRenderingContext.webidl | 2 +- ...ncorrect-context-object-behaviour.html.ini | 3 -- .../conformance/context/methods.html.ini | 3 -- .../misc/bad-arguments-test.html.ini | 14 ------ .../uniforms/uniform-location.html.ini | 20 -------- 10 files changed, 150 insertions(+), 42 deletions(-) delete mode 100644 tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/misc/bad-arguments-test.html.ini diff --git a/components/canvas/webgl_thread.rs b/components/canvas/webgl_thread.rs index 7b0b120d037a..ad5bc0dd2ad5 100644 --- a/components/canvas/webgl_thread.rs +++ b/components/canvas/webgl_thread.rs @@ -765,6 +765,8 @@ impl WebGLImpl { Self::shader_precision_format(ctx.gl(), shader_type, precision_type, chan), WebGLCommand::GetExtensions(ref chan) => Self::get_extensions(ctx.gl(), chan), + WebGLCommand::GetUniform(program, location, ref uniform_type, ref chan) => + Self::get_uniform(ctx.gl(), program, location, uniform_type, chan), WebGLCommand::GetUniformLocation(program_id, ref name, ref chan) => Self::uniform_location(ctx.gl(), program_id, &name, chan), WebGLCommand::GetShaderInfoLog(shader_id, ref chan) => @@ -1162,6 +1164,44 @@ impl WebGLImpl { chan.send(location).unwrap(); } + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 + fn get_uniform( + gl: &gl::Gl, + program: u32, + location: i32, + uniform_type: &UniformType, + chan: &WebGLSender, + ) { + let uniform = match uniform_type { + UniformType::FloatVec(_) => + UniformType::FloatVec(gl.get_uniform_fv(program, location)), + UniformType::IntVec(_) => + UniformType::IntVec(gl.get_uniform_iv(program, location)), + UniformType::BoolVec(_) => { + let result = gl.get_uniform_iv(program, location) + .iter() + .map(|el| *el == 1) + .collect::>(); + UniformType::BoolVec(result) + } + UniformType::Int(_) => { + // returns a single int in a vector + let result = gl.get_uniform_iv(program, location); + UniformType::Int(result[0]) + } + UniformType::Bool(_) => { + // returns a single bool in a vector + let result = gl.get_uniform_iv(program, location); + UniformType::Bool(result[0] == 1) + } + UniformType::Float(_) => { + // returns a single float in a vector + let result = gl.get_uniform_fv(program, location); + UniformType::Float(result[0]) + } + }; + chan.send(uniform).unwrap(); + } fn shader_info_log(gl: &gl::Gl, shader_id: WebGLShaderId, chan: &WebGLSender) { let log = gl.get_shader_info_log(shader_id.get()); diff --git a/components/canvas_traits/webgl.rs b/components/canvas_traits/webgl.rs index 2f39cbada27c..8f81803ac37d 100644 --- a/components/canvas_traits/webgl.rs +++ b/components/canvas_traits/webgl.rs @@ -216,6 +216,7 @@ pub enum WebGLCommand { GetProgramInfoLog(WebGLProgramId, WebGLSender), GetFramebufferAttachmentParameter(u32, u32, u32, WebGLSender), GetRenderbufferParameter(u32, u32, WebGLSender), + GetUniform(u32, i32, UniformType, WebGLSender), PolygonOffset(f32, f32), RenderbufferStorage(u32, u32, i32, i32), ReadPixels(i32, i32, i32, i32, u32, u32, WebGLSender), @@ -287,6 +288,16 @@ pub enum WebGLCommand { TexParameterf(u32, TexParameterFloat, f32), } +#[derive(Clone, Debug, Deserialize, Serialize)] +pub enum UniformType { + FloatVec(Vec), + IntVec(Vec), + BoolVec(Vec), + Float(f32), + Int(i32), + Bool(bool), +} + macro_rules! define_resource_id_struct { ($name:ident) => { #[derive(Clone, Copy, Eq, Hash, PartialEq)] diff --git a/components/script/dom/webgl2renderingcontext.rs b/components/script/dom/webgl2renderingcontext.rs index cb5e17dfe26d..27df67dc9010 100644 --- a/components/script/dom/webgl2renderingcontext.rs +++ b/components/script/dom/webgl2renderingcontext.rs @@ -170,6 +170,17 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext { self.base.GetRenderbufferParameter(cx, target, pname) } + #[allow(unsafe_code)] + /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8 + unsafe fn GetUniform( + &self, + cx: *mut JSContext, + program: &WebGLProgram, + location: &WebGLUniformLocation + ) -> JSVal { + self.base.GetUniform(cx, program, location) + } + /// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3 fn ActiveTexture(&self, texture: u32) { self.base.ActiveTexture(texture) diff --git a/components/script/dom/webglprogram.rs b/components/script/dom/webglprogram.rs index d710568d1ca2..e72c3c06b9a2 100644 --- a/components/script/dom/webglprogram.rs +++ b/components/script/dom/webglprogram.rs @@ -4,7 +4,9 @@ // https://www.khronos.org/registry/webgl/specs/latest/1.0/webgl.idl use canvas_traits::webgl::{WebGLCommand, WebGLError, WebGLMsgSender, WebGLProgramId, WebGLResult}; +use canvas_traits::webgl::UniformType; use canvas_traits::webgl::webgl_channel; +use dom::bindings::codegen::Bindings::WebGLActiveInfoBinding::WebGLActiveInfoBinding::WebGLActiveInfoMethods; use dom::bindings::codegen::Bindings::WebGLProgramBinding; use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants; use dom::bindings::reflector::{DomObject, reflect_dom_object}; @@ -14,8 +16,10 @@ 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 gleam::gl; use std::cell::Cell; #[dom_struct] @@ -374,6 +378,50 @@ impl WebGLProgram { (None, None) => vec![] }) } + + /// glGetUniform + pub fn get_uniform( + &self, + location: &WebGLUniformLocation + ) -> WebGLResult { + let is_location_valid = location.program_id().get() == self.id().get(); + if !self.is_linked() || !is_location_valid { + return Err(WebGLError::InvalidOperation); + } + + // TODO: Alternatively use ANGLE to obtain uniform type. + let uniform_type = self.get_active_uniform(0)?.Type(); + let uniform_type = match uniform_type { + gl::FLOAT_VEC2 | + gl::FLOAT_VEC3 | + gl::FLOAT_VEC4 | + gl::FLOAT_MAT2 | + gl::FLOAT_MAT3 | + gl::FLOAT_MAT4 => UniformType::FloatVec(vec![]), + + gl::INT_VEC2 | + gl::INT_VEC3 | + gl::INT_VEC4 => UniformType::IntVec(vec![]), + + gl::BOOL_VEC2 | + gl::BOOL_VEC3 | + gl::BOOL_VEC4 => UniformType::BoolVec(vec![]), + + gl::INT | + gl::SAMPLER_2D | + gl::SAMPLER_CUBE => UniformType::Int(0), + + gl::BOOL => UniformType::Bool(false), + + gl::FLOAT => UniformType::Float(0.), + + _ => return Err(WebGLError::InvalidOperation), + }; + + let (sender, receiver) = webgl_channel().unwrap(); + self.renderer.send(WebGLCommand::GetUniform(self.id().get(), location.id(), uniform_type, sender)).unwrap(); + Ok(receiver.recv().unwrap()) + } } impl Drop for WebGLProgram { diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index 60474753eb3c..e16de28c7d4d 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -6,7 +6,7 @@ use byteorder::{NativeEndian, ReadBytesExt, WriteBytesExt}; use canvas_traits::canvas::{byte_swap, multiply_u8_pixel}; use canvas_traits::webgl::{DOMToTextureCommand, Parameter, ProgramParameter}; use canvas_traits::webgl::{ShaderParameter, TexParameter, VertexAttrib, WebGLCommand}; -use canvas_traits::webgl::{WebGLContextShareMode, WebGLError}; +use canvas_traits::webgl::{WebGLContextShareMode, WebGLError, UniformType}; use canvas_traits::webgl::{WebGLFramebufferBindingRequest, WebGLMsg, WebGLMsgSender}; use canvas_traits::webgl::{WebGLResult, WebGLSLVersion, WebGLVersion}; use canvas_traits::webgl::{WebVRCommand, webgl_channel}; @@ -2579,6 +2579,44 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { }) } + #[allow(unsafe_code)] + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 + unsafe fn GetUniform( + &self, + cx: *mut JSContext, + program: &WebGLProgram, + location: &WebGLUniformLocation + ) -> JSVal { + let uniform = match program.get_uniform(location) { + Ok(uniform) => uniform, + Err(e) => { + self.webgl_error(e); + return NullValue(); + } + }; + + match uniform { + UniformType::Int(value) => Int32Value(value), + UniformType::Bool(value) => BooleanValue(value), + UniformType::Float(value) => DoubleValue(value as f64), + UniformType::IntVec(values) => { + rooted!(in(cx) let mut result = UndefinedValue()); + values.to_jsval(cx, result.handle_mut()); + result.get() + }, + UniformType::BoolVec(values) => { + rooted!(in(cx) let mut result = UndefinedValue()); + values.to_jsval(cx, result.handle_mut()); + result.get() + }, + UniformType::FloatVec(values) => { + rooted!(in(cx) let mut result = UndefinedValue()); + values.to_jsval(cx, result.handle_mut()); + result.get() + }, + } + } + #[allow(unsafe_code)] // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9 unsafe fn GetVertexAttrib(&self, cx: *mut JSContext, index: u32, param: u32) -> JSVal { diff --git a/components/script/dom/webidls/WebGLRenderingContext.webidl b/components/script/dom/webidls/WebGLRenderingContext.webidl index 8ec02ce95ea1..6b7f63cac188 100644 --- a/components/script/dom/webidls/WebGLRenderingContext.webidl +++ b/components/script/dom/webidls/WebGLRenderingContext.webidl @@ -580,7 +580,7 @@ interface WebGLRenderingContextBase any getTexParameter(GLenum target, GLenum pname); - // any getUniform(WebGLProgram program, WebGLUniformLocation location); + any getUniform(WebGLProgram program, WebGLUniformLocation location); WebGLUniformLocation? getUniformLocation(WebGLProgram program, DOMString name); diff --git a/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/context/incorrect-context-object-behaviour.html.ini b/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/context/incorrect-context-object-behaviour.html.ini index 309d087d9fd5..e69756bfd332 100644 --- a/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/context/incorrect-context-object-behaviour.html.ini +++ b/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/context/incorrect-context-object-behaviour.html.ini @@ -45,9 +45,6 @@ [WebGL test #19: getError expected: INVALID_OPERATION. Was NO_ERROR : after evaluating: contextA.getShaderSource(shaderB)] expected: FAIL - [WebGL test #20: contextA.getUniform(programB, locationA) threw exception TypeError: contextA.getUniform is not a function] - expected: FAIL - [WebGL test #21: getError expected: INVALID_OPERATION. Was NO_ERROR : after evaluating: contextA.getUniformLocation(programB, 'u_modelViewProjMatrix')] expected: FAIL diff --git a/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/context/methods.html.ini b/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/context/methods.html.ini index 9afaa0848b64..4e844b26bd49 100644 --- a/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/context/methods.html.ini +++ b/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/context/methods.html.ini @@ -1,7 +1,4 @@ [methods.html] - [WebGL test #0: Property either does not exist or is not a function: getUniform] - expected: FAIL - [WebGL test #1: Property either does not exist or is not a function: isContextLost] expected: FAIL diff --git a/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/misc/bad-arguments-test.html.ini b/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/misc/bad-arguments-test.html.ini deleted file mode 100644 index 9caac9fee7c8..000000000000 --- a/tests/wpt/mozilla/meta/webgl/conformance-1.0.3/conformance/misc/bad-arguments-test.html.ini +++ /dev/null @@ -1,14 +0,0 @@ -[bad-arguments-test.html] - type: testharness - [WebGL test #78: context.getUniform(argument, loc) should be null. Threw exception TypeError: context.getUniform is not a function] - expected: FAIL - - [WebGL test #79: context.getUniform(program, argument) should be null. Threw exception TypeError: context.getUniform is not a function] - expected: FAIL - - [WebGL test #104: context.getUniform(argument, loc) should be null. Threw exception TypeError: context.getUniform is not a function] - expected: FAIL - - [WebGL test #105: context.getUniform(program, argument) should be null. Threw exception TypeError: context.getUniform is not a function] - expected: FAIL - 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 21de226cc01a..3d6c47445c36 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,26 +1,6 @@ [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 - - [WebGL test #10: contextA.getUniform(programS, locationArray0) should be 4. Threw exception TypeError: contextA.getUniform is not a function] - expected: FAIL - - [WebGL test #11: contextA.getUniform(programS, locationArray1) should be 5. Threw exception TypeError: contextA.getUniform is not a function] - expected: FAIL - - [WebGL test #14: contextA.getUniform(programV, locationVec4) should be 1,2,3,4. Threw exception TypeError: contextA.getUniform is not a function] - expected: FAIL [WebGL test #20: getError expected: INVALID_OPERATION. Was NO_ERROR : after evaluating: contextA.uniform1i(locationSx, 3)] expected: FAIL - [WebGL test #21: contextA.getUniform(programS, locationSx) threw exception TypeError: contextA.getUniform is not a function] - expected: FAIL - - [WebGL test #24: contextA.getUniform(programS, locationSx) should be 3. Threw exception TypeError: contextA.getUniform is not a function] - expected: FAIL - - [WebGL test #25: contextA.getUniform(programS, locationArray0) should be 123. Threw exception TypeError: contextA.getUniform is not a function] - expected: FAIL -