diff --git a/components/canvas/webgl_thread.rs b/components/canvas/webgl_thread.rs index 8ab129680de..046290b7dd8 100644 --- a/components/canvas/webgl_thread.rs +++ b/components/canvas/webgl_thread.rs @@ -746,8 +746,6 @@ impl WebGLImpl { Self::get_renderbuffer_parameter(ctx.gl(), target, pname, chan), WebGLCommand::GetFramebufferAttachmentParameter(target, attachment, pname, ref chan) => Self::get_framebuffer_attachment_parameter(ctx.gl(), target, attachment, pname, chan), - WebGLCommand::GetVertexAttribOffset(index, pname, ref chan) => - Self::vertex_attrib_offset(ctx.gl(), index, pname, chan), WebGLCommand::GetShaderPrecisionFormat(shader_type, precision_type, ref chan) => Self::shader_precision_format(ctx.gl(), shader_type, precision_type, chan), WebGLCommand::GetExtensions(ref chan) => @@ -949,56 +947,12 @@ impl WebGLImpl { } sender.send(value[0]).unwrap() } - WebGLCommand::GetVertexAttribBool(index, param, ref sender) => { - // FIXME(nox): https://github.com/servo/servo/issues/20608 - let mut max = [0]; + WebGLCommand::GetCurrentVertexAttrib(index, ref sender) => { + let mut value = [0.; 4]; unsafe { - ctx.gl().get_integer_v(gl::MAX_VERTEX_ATTRIBS, &mut max); + ctx.gl().get_vertex_attrib_fv(index, gl::CURRENT_VERTEX_ATTRIB, &mut value); } - let result = if index >= max[0] as u32 { - Err(WebGLError::InvalidValue) - } else { - let mut value = [0]; - unsafe { - ctx.gl().get_vertex_attrib_iv(index, param as u32, &mut value); - } - Ok(value[0] != 0) - }; - sender.send(result).unwrap(); - } - WebGLCommand::GetVertexAttribInt(index, param, ref sender) => { - // FIXME(nox): https://github.com/servo/servo/issues/20608 - let mut max = [0]; - unsafe { - ctx.gl().get_integer_v(gl::MAX_VERTEX_ATTRIBS, &mut max); - } - let result = if index >= max[0] as u32 { - Err(WebGLError::InvalidValue) - } else { - let mut value = [0]; - unsafe { - ctx.gl().get_vertex_attrib_iv(index, param as u32, &mut value); - } - Ok(value[0]) - }; - sender.send(result).unwrap(); - } - WebGLCommand::GetVertexAttribFloat4(index, param, ref sender) => { - // FIXME(nox): https://github.com/servo/servo/issues/20608 - let mut max = [0]; - unsafe { - ctx.gl().get_integer_v(gl::MAX_VERTEX_ATTRIBS, &mut max); - } - let result = if index >= max[0] as u32 { - Err(WebGLError::InvalidValue) - } else { - let mut value = [0.; 4]; - unsafe { - ctx.gl().get_vertex_attrib_fv(index, param as u32, &mut value); - } - Ok(value) - }; - sender.send(result).unwrap(); + sender.send(value).unwrap(); } WebGLCommand::GetTexParameterFloat(target, param, ref sender) => { sender.send(ctx.gl().get_tex_parameter_fv(target, param as u32)).unwrap(); @@ -1092,14 +1046,6 @@ impl WebGLImpl { chan.send(()).unwrap(); } - fn vertex_attrib_offset(gl: &gl::Gl, - index: u32, - pname: u32, - chan: &WebGLSender) { - let result = gl.get_vertex_attrib_pointer_v(index, pname); - chan.send(result).unwrap(); - } - fn shader_precision_format(gl: &gl::Gl, shader_type: u32, precision_type: u32, diff --git a/components/canvas_traits/webgl.rs b/components/canvas_traits/webgl.rs index 2f39cbada27..e86935f6f2a 100644 --- a/components/canvas_traits/webgl.rs +++ b/components/canvas_traits/webgl.rs @@ -211,7 +211,6 @@ pub enum WebGLCommand { GetActiveUniform(WebGLProgramId, u32, WebGLSender>), GetAttribLocation(WebGLProgramId, String, WebGLSender>), GetUniformLocation(WebGLProgramId, String, WebGLSender>), - GetVertexAttribOffset(u32, u32, WebGLSender), GetShaderInfoLog(WebGLShaderId, WebGLSender), GetProgramInfoLog(WebGLProgramId, WebGLSender), GetFramebufferAttachmentParameter(u32, u32, u32, WebGLSender), @@ -278,9 +277,7 @@ pub enum WebGLCommand { GetProgramParameterInt(WebGLProgramId, ProgramParameterInt, WebGLSender), GetShaderParameterBool(WebGLShaderId, ShaderParameterBool, WebGLSender), GetShaderParameterInt(WebGLShaderId, ShaderParameterInt, WebGLSender), - GetVertexAttribBool(u32, VertexAttribBool, WebGLSender>), - GetVertexAttribInt(u32, VertexAttribInt, WebGLSender>), - GetVertexAttribFloat4(u32, VertexAttribFloat4, WebGLSender>), + GetCurrentVertexAttrib(u32, WebGLSender<[f32; 4]>), GetTexParameterFloat(u32, TexParameterFloat, WebGLSender), GetTexParameterInt(u32, TexParameterInt, WebGLSender), TexParameteri(u32, TexParameterInt, i32), @@ -568,20 +565,3 @@ parameters! { }), } } - -parameters! { - VertexAttrib { - Bool(VertexAttribBool { - VertexAttribArrayEnabled = gl::VERTEX_ATTRIB_ARRAY_ENABLED, - VertexAttribArrayNormalized = gl::VERTEX_ATTRIB_ARRAY_NORMALIZED, - }), - Int(VertexAttribInt { - VertexAttribArraySize = gl::VERTEX_ATTRIB_ARRAY_SIZE, - VertexAttribArrayStride = gl::VERTEX_ATTRIB_ARRAY_STRIDE, - VertexAttribArrayType = gl::VERTEX_ATTRIB_ARRAY_TYPE, - }), - Float4(VertexAttribFloat4 { - CurrentVertexAttrib = gl::CURRENT_VERTEX_ATTRIB, - }), - } -} diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index c415063deb0..85cfcb132ae 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -5,7 +5,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::{ShaderParameter, TexParameter, WebGLCommand}; use canvas_traits::webgl::{WebGLContextShareMode, WebGLError}; use canvas_traits::webgl::{WebGLFramebufferBindingRequest, WebGLMsg, WebGLMsgSender}; use canvas_traits::webgl::{WebGLResult, WebGLSLVersion, WebGLVersion}; @@ -2579,43 +2579,44 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { #[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 { - if index == 0 && param == constants::CURRENT_VERTEX_ATTRIB { + let data = handle_potential_webgl_error!( + self, + self.vertex_attribs.get(index).ok_or(InvalidValue), + return NullValue() + ); + 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() + }; + // FIXME(nox): https://github.com/servo/servo/issues/20655 rooted!(in(cx) let mut result = UndefinedValue()); - let (x, y, z, w) = self.current_vertex_attrib_0.get(); - let attrib = vec![x, y, z, w]; - attrib.to_jsval(cx, result.handle_mut()); - return result.get() + value.to_jsval(cx, result.handle_mut()); + return result.get(); } - if param == constants::VERTEX_ATTRIB_ARRAY_BUFFER_BINDING { - rooted!(in(cx) let mut jsval = NullValue()); - if let Some(buffer) = self.vertex_attribs.get(index) { - buffer.to_jsval(cx, jsval.handle_mut()); + match param { + constants::VERTEX_ATTRIB_ARRAY_ENABLED => BooleanValue(data.enabled_as_array), + constants::VERTEX_ATTRIB_ARRAY_SIZE => Int32Value(data.size as i32), + constants::VERTEX_ATTRIB_ARRAY_TYPE => Int32Value(data.type_ as i32), + constants::VERTEX_ATTRIB_ARRAY_NORMALIZED => BooleanValue(data.normalized), + constants::VERTEX_ATTRIB_ARRAY_STRIDE => Int32Value(data.stride as i32), + constants::VERTEX_ATTRIB_ARRAY_BUFFER_BINDING => { + rooted!(in(cx) let mut jsval = NullValue()); + if let Some(data) = self.vertex_attribs.get(index) { + if let Some(buffer) = data.buffer() { + buffer.to_jsval(cx, jsval.handle_mut()); + } + } + jsval.get() } - return jsval.get(); - } - - match handle_potential_webgl_error!(self, VertexAttrib::from_u32(param), return NullValue()) { - VertexAttrib::Bool(param) => { - let (sender, receiver) = webgl_channel().unwrap(); - self.send_command(WebGLCommand::GetVertexAttribBool(index, param, sender)); - let value = handle_potential_webgl_error!(self, receiver.recv().unwrap(), return NullValue()); - BooleanValue(value) - } - VertexAttrib::Int(param) => { - let (sender, receiver) = webgl_channel().unwrap(); - self.send_command(WebGLCommand::GetVertexAttribInt(index, param, sender)); - let value = handle_potential_webgl_error!(self, receiver.recv().unwrap(), return NullValue()); - Int32Value(value) - } - VertexAttrib::Float4(param) => { - let (sender, receiver) = webgl_channel().unwrap(); - self.send_command(WebGLCommand::GetVertexAttribFloat4(index, param, sender)); - let value = handle_potential_webgl_error!(self, receiver.recv().unwrap(), return NullValue()); - // FIXME(nox): https://github.com/servo/servo/issues/20655 - rooted!(in(cx) let mut result = UndefinedValue()); - value.to_jsval(cx, result.handle_mut()); - result.get() + _ => { + self.webgl_error(InvalidEnum); + NullValue() } } } @@ -2626,10 +2627,12 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { self.webgl_error(InvalidEnum); return 0; } - let (sender, receiver) = webgl_channel().unwrap(); - self.send_command(WebGLCommand::GetVertexAttribOffset(index, pname, sender)); - - receiver.recv().unwrap() as i64 + let data = handle_potential_webgl_error!( + self, + self.vertex_attribs.get(index).ok_or(InvalidValue), + return 0 + ); + data.offset as i64 } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3 @@ -3316,49 +3319,30 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 - fn VertexAttribPointer(&self, attrib_id: u32, size: i32, data_type: u32, - normalized: bool, stride: i32, offset: i64) { - if attrib_id >= self.limits.max_vertex_attribs { - return self.webgl_error(InvalidValue); - } + fn VertexAttribPointer( + &self, + index: u32, + size: i32, + type_: u32, + normalized: bool, + stride: i32, + offset: i64, + ) { + handle_potential_webgl_error!( + self, + self.vertex_attribs.set_pointer( + index, + size, + type_, + normalized, + stride, + offset, + self.bound_buffer_array.get().as_ref().map(|buffer| &**buffer), + ), + return + ); - // GLES spec: If offset or stride is negative, an INVALID_VALUE error will be generated - // WebGL spec: the maximum supported stride is 255 - if stride < 0 || stride > 255 || offset < 0 { - return self.webgl_error(InvalidValue); - } - if size < 1 || size > 4 { - return self.webgl_error(InvalidValue); - } - - let buffer_array = match self.bound_buffer_array.get() { - Some(buffer) => buffer, - None => { - return self.webgl_error(InvalidOperation); - } - }; - - // stride and offset must be multiple of data_type - match data_type { - constants::BYTE | constants::UNSIGNED_BYTE => {}, - constants::SHORT | constants::UNSIGNED_SHORT => { - if offset % 2 > 0 || stride % 2 > 0 { - return self.webgl_error(InvalidOperation); - } - }, - constants::FLOAT => { - if offset % 4 > 0 || stride % 4 > 0 { - return self.webgl_error(InvalidOperation); - } - }, - _ => return self.webgl_error(InvalidEnum), - - } - - self.vertex_attribs.bind_buffer(attrib_id, &buffer_array); - - let msg = WebGLCommand::VertexAttribPointer(attrib_id, size, data_type, normalized, stride, offset as u32); - self.send_command(msg); + self.send_command(WebGLCommand::VertexAttribPointer(index, size, type_, normalized, stride, offset as u32)); } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.4 @@ -3815,6 +3799,57 @@ impl VertexAttribs { self.attribs.borrow_mut().clone_from_slice(&other.attribs.borrow()); } + pub fn set_pointer( + &self, + index: u32, + size: i32, + type_: u32, + normalized: bool, + stride: i32, + offset: i64, + buffer: Option<&WebGLBuffer>, + ) -> WebGLResult<()> { + let mut attribs = self.attribs.borrow_mut(); + let data = attribs.get_mut(index as usize).ok_or(InvalidValue)?; + + if size < 1 || size > 4 { + return Err(InvalidValue); + } + + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#BUFFER_OFFSET_AND_STRIDE + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#VERTEX_STRIDE + if stride < 0 || stride > 255 || offset < 0 { + return Err(InvalidValue); + } + match type_ { + constants::BYTE | constants::UNSIGNED_BYTE => {}, + constants::SHORT | constants::UNSIGNED_SHORT => { + if offset % 2 > 0 || stride % 2 > 0 { + return Err(InvalidOperation); + } + }, + constants::FLOAT => { + if offset % 4 > 0 || stride % 4 > 0 { + return Err(InvalidOperation); + } + }, + _ => return Err(InvalidEnum), + } + + let buffer = buffer.ok_or(InvalidOperation)?; + + *data = VertexAttribData { + enabled_as_array: data.enabled_as_array, + size: size as u8, + type_, + normalized, + stride: stride as u8, + offset: offset as u32, + buffer: Some(Dom::from_ref(buffer)), + }; + Ok(()) + } + pub fn borrow(&self) -> Ref<[VertexAttribData]> { Ref::map(self.attribs.borrow(), |attribs| &**attribs) } @@ -3827,20 +3862,14 @@ impl VertexAttribs { } } - fn get(&self, index: u32) -> Option> { - ref_filter_map(self.attribs.borrow(), |attribs| { - attribs[index as usize].buffer.as_ref().map(|buffer| &**buffer) - }) + fn get(&self, index: u32) -> Option> { + ref_filter_map(self.attribs.borrow(), |attribs| attribs.get(index as usize)) } fn enabled_as_array(&self, index: u32, value: bool) { self.attribs.borrow_mut()[index as usize].enabled_as_array = value; } - fn bind_buffer(&self, index: u32, buffer: &WebGLBuffer) { - self.attribs.borrow_mut()[index as usize].buffer = Some(Dom::from_ref(buffer)); - } - fn validate_for_draw(&self) -> WebGLResult<()> { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#6.2 if self.borrow().iter().any(|data| data.enabled_as_array && data.buffer.is_none()) { @@ -3850,13 +3879,33 @@ impl VertexAttribs { } } -#[derive(Clone, Default, JSTraceable, MallocSizeOf)] +#[derive(Clone, JSTraceable, MallocSizeOf)] #[must_root] pub struct VertexAttribData { enabled_as_array: bool, + size: u8, + type_: u32, + normalized: bool, + stride: u8, + offset: u32, buffer: Option>, } +impl Default for VertexAttribData { + #[allow(unrooted_must_root)] + fn default() -> Self { + Self { + enabled_as_array: false, + size: 4, + type_: constants::FLOAT, + normalized: false, + stride: 0, + offset: 0, + buffer: None, + } + } +} + impl VertexAttribData { pub fn buffer(&self) -> Option<&WebGLBuffer> { self.buffer.as_ref().map(|b| &**b)