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()