diff options
Diffstat (limited to 'components/script')
-rw-r--r-- | components/script/dom/webgl2renderingcontext.rs | 226 | ||||
-rw-r--r-- | components/script/dom/webglrenderingcontext.rs | 112 | ||||
-rw-r--r-- | components/script/dom/webidls/WebGL2RenderingContext.webidl | 26 |
3 files changed, 297 insertions, 67 deletions
diff --git a/components/script/dom/webgl2renderingcontext.rs b/components/script/dom/webgl2renderingcontext.rs index e8993f472d9..4967c0a940e 100644 --- a/components/script/dom/webgl2renderingcontext.rs +++ b/components/script/dom/webgl2renderingcontext.rs @@ -11,6 +11,7 @@ use crate::dom::bindings::codegen::UnionTypes::ArrayBufferViewOrArrayBuffer; use crate::dom::bindings::codegen::UnionTypes::Float32ArrayOrUnrestrictedFloatSequence; use crate::dom::bindings::codegen::UnionTypes::ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement; use crate::dom::bindings::codegen::UnionTypes::Int32ArrayOrLongSequence; +use crate::dom::bindings::codegen::UnionTypes::Uint32ArrayOrUnsignedLongSequence; use crate::dom::bindings::error::{ErrorResult, Fallible}; use crate::dom::bindings::reflector::DomObject; use crate::dom::bindings::reflector::{reflect_dom_object, Reflector}; @@ -25,7 +26,8 @@ use crate::dom::webglprogram::WebGLProgram; use crate::dom::webglquery::WebGLQuery; use crate::dom::webglrenderbuffer::WebGLRenderbuffer; use crate::dom::webglrenderingcontext::{ - LayoutCanvasWebGLRenderingContextHelpers, Size2DExt, WebGLRenderingContext, + uniform_get, uniform_typed, LayoutCanvasWebGLRenderingContextHelpers, Size2DExt, + WebGLRenderingContext, }; use crate::dom::webglsampler::{WebGLSampler, WebGLSamplerValue}; use crate::dom::webglshader::WebGLShader; @@ -48,7 +50,7 @@ use js::jsapi::{JSObject, Type}; use js::jsval::{BooleanValue, DoubleValue, Int32Value, UInt32Value}; use js::jsval::{JSVal, NullValue, ObjectValue, UndefinedValue}; use js::rust::CustomAutoRooterGuard; -use js::typedarray::{ArrayBufferView, CreateWith, Uint32Array}; +use js::typedarray::{ArrayBufferView, CreateWith, Uint32, Uint32Array}; use script_layout_interface::HTMLCanvasDataSource; use std::cell::Cell; use std::cmp; @@ -386,6 +388,49 @@ impl WebGL2RenderingContext { .copy_from_slice(&src[src_start..src_start + src_row_bytes as usize]); } } + + fn uniform_vec_section( + &self, + vec: Uint32ArrayOrUnsignedLongSequence, + offset: u32, + length: u32, + uniform_size: usize, + uniform_location: &WebGLUniformLocation, + ) -> WebGLResult<Vec<u32>> { + let vec = match vec { + Uint32ArrayOrUnsignedLongSequence::Uint32Array(v) => v.to_vec(), + Uint32ArrayOrUnsignedLongSequence::UnsignedLongSequence(v) => v, + }; + + let offset = offset as usize; + if offset > vec.len() { + return Err(InvalidValue); + } + + let length = if length > 0 { + length as usize + } else { + vec.len() - offset + }; + if offset + length > vec.len() { + return Err(InvalidValue); + } + + let vec = if offset == 0 && length == vec.len() { + vec + } else { + vec[offset..offset + length].to_vec() + }; + + if vec.len() < uniform_size || vec.len() % uniform_size != 0 { + return Err(InvalidValue); + } + if uniform_location.size().is_none() && vec.len() != uniform_size { + return Err(InvalidOperation); + } + + Ok(vec) + } } impl WebGL2RenderingContextMethods for WebGL2RenderingContext { @@ -1457,6 +1502,57 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext { self.base.Uniform1iv(location, v) } + // https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8 + fn Uniform1ui(&self, location: Option<&WebGLUniformLocation>, val: u32) { + self.base.with_location(location, |location| { + match location.type_() { + constants::BOOL | constants::UNSIGNED_INT => (), + _ => return Err(InvalidOperation), + } + self.base + .send_command(WebGLCommand::Uniform1ui(location.id(), val)); + Ok(()) + }); + } + + // https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8 + fn Uniform1uiv( + &self, + location: Option<&WebGLUniformLocation>, + val: Uint32ArrayOrUnsignedLongSequence, + src_offset: u32, + src_length: u32, + ) { + self.base.with_location(location, |location| { + match location.type_() { + constants::BOOL | + constants::UNSIGNED_INT | + constants::SAMPLER_2D | + constants::SAMPLER_CUBE => {}, + _ => return Err(InvalidOperation), + } + + let val = self.uniform_vec_section(val, src_offset, src_length, 1, location)?; + + 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 >= self.base.limits().max_combined_texture_image_units { + return Err(InvalidValue); + } + } + }, + _ => {}, + } + self.base + .send_command(WebGLCommand::Uniform1uiv(location.id(), val)); + Ok(()) + }); + } + /// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 fn Uniform1fv( &self, @@ -1490,6 +1586,39 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext { self.base.Uniform2iv(location, v) } + // https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8 + fn Uniform2ui(&self, location: Option<&WebGLUniformLocation>, x: u32, y: u32) { + self.base.with_location(location, |location| { + match location.type_() { + constants::BOOL_VEC2 | constants::UNSIGNED_INT_VEC2 => {}, + _ => return Err(InvalidOperation), + } + self.base + .send_command(WebGLCommand::Uniform2ui(location.id(), x, y)); + Ok(()) + }); + } + + // https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8 + fn Uniform2uiv( + &self, + location: Option<&WebGLUniformLocation>, + val: Uint32ArrayOrUnsignedLongSequence, + src_offset: u32, + src_length: u32, + ) { + self.base.with_location(location, |location| { + match location.type_() { + constants::BOOL_VEC2 | constants::UNSIGNED_INT_VEC2 => {}, + _ => return Err(InvalidOperation), + } + let val = self.uniform_vec_section(val, src_offset, src_length, 2, location)?; + self.base + .send_command(WebGLCommand::Uniform2uiv(location.id(), val)); + Ok(()) + }); + } + /// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 fn Uniform3f(&self, location: Option<&WebGLUniformLocation>, x: f32, y: f32, z: f32) { self.base.Uniform3f(location, x, y, z) @@ -1514,6 +1643,39 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext { self.base.Uniform3iv(location, v) } + // https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8 + fn Uniform3ui(&self, location: Option<&WebGLUniformLocation>, x: u32, y: u32, z: u32) { + self.base.with_location(location, |location| { + match location.type_() { + constants::BOOL_VEC3 | constants::UNSIGNED_INT_VEC3 => {}, + _ => return Err(InvalidOperation), + } + self.base + .send_command(WebGLCommand::Uniform3ui(location.id(), x, y, z)); + Ok(()) + }); + } + + // https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8 + fn Uniform3uiv( + &self, + location: Option<&WebGLUniformLocation>, + val: Uint32ArrayOrUnsignedLongSequence, + src_offset: u32, + src_length: u32, + ) { + self.base.with_location(location, |location| { + match location.type_() { + constants::BOOL_VEC3 | constants::UNSIGNED_INT_VEC3 => {}, + _ => return Err(InvalidOperation), + } + let val = self.uniform_vec_section(val, src_offset, src_length, 3, location)?; + self.base + .send_command(WebGLCommand::Uniform3uiv(location.id(), val)); + Ok(()) + }); + } + /// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 fn Uniform4i(&self, location: Option<&WebGLUniformLocation>, x: i32, y: i32, z: i32, w: i32) { self.base.Uniform4i(location, x, y, z, w) @@ -1524,6 +1686,39 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext { self.base.Uniform4iv(location, v) } + // https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8 + fn Uniform4ui(&self, location: Option<&WebGLUniformLocation>, x: u32, y: u32, z: u32, w: u32) { + self.base.with_location(location, |location| { + match location.type_() { + constants::BOOL_VEC4 | constants::UNSIGNED_INT_VEC4 => {}, + _ => return Err(InvalidOperation), + } + self.base + .send_command(WebGLCommand::Uniform4ui(location.id(), x, y, z, w)); + Ok(()) + }); + } + + // https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8 + fn Uniform4uiv( + &self, + location: Option<&WebGLUniformLocation>, + val: Uint32ArrayOrUnsignedLongSequence, + src_offset: u32, + src_length: u32, + ) { + self.base.with_location(location, |location| { + match location.type_() { + constants::BOOL_VEC4 | constants::UNSIGNED_INT_VEC4 => {}, + _ => return Err(InvalidOperation), + } + let val = self.uniform_vec_section(val, src_offset, src_length, 4, location)?; + self.base + .send_command(WebGLCommand::Uniform4uiv(location.id(), val)); + Ok(()) + }); + } + /// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 fn Uniform4f(&self, location: Option<&WebGLUniformLocation>, x: f32, y: f32, z: f32, w: f32) { self.base.Uniform4f(location, x, y, z, w) @@ -1568,14 +1763,37 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext { self.base.UniformMatrix4fv(location, transpose, v) } - // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 + /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8 + #[allow(unsafe_code)] fn GetUniform( &self, cx: JSContext, program: &WebGLProgram, location: &WebGLUniformLocation, ) -> JSVal { - self.base.GetUniform(cx, program, location) + handle_potential_webgl_error!( + self.base, + self.base.uniform_check_program(program, location), + return NullValue() + ); + + let triple = (&*self.base, program.id(), location.id()); + + match location.type_() { + constants::UNSIGNED_INT => { + UInt32Value(uniform_get(triple, WebGLCommand::GetUniformUint)) + }, + constants::UNSIGNED_INT_VEC2 => unsafe { + uniform_typed::<Uint32>(*cx, &uniform_get(triple, WebGLCommand::GetUniformUint2)) + }, + constants::UNSIGNED_INT_VEC3 => unsafe { + uniform_typed::<Uint32>(*cx, &uniform_get(triple, WebGLCommand::GetUniformUint3)) + }, + constants::UNSIGNED_INT_VEC4 => unsafe { + uniform_typed::<Uint32>(*cx, &uniform_get(triple, WebGLCommand::GetUniformUint4)) + }, + _ => self.base.GetUniform(cx, program, location), + } } /// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9 diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index 68eccfa711d..cf01a53e0f3 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -114,6 +114,27 @@ fn has_invalid_blend_constants(arg1: u32, arg2: u32) -> bool { } } +pub fn uniform_get<T, F>(triple: (&WebGLRenderingContext, WebGLProgramId, i32), f: F) -> T +where + F: FnOnce(WebGLProgramId, i32, WebGLSender<T>) -> WebGLCommand, + T: for<'de> Deserialize<'de> + Serialize, +{ + let (sender, receiver) = webgl_channel().unwrap(); + triple.0.send_command(f(triple.1, triple.2, sender)); + receiver.recv().unwrap() +} + +#[allow(unsafe_code)] +pub unsafe fn uniform_typed<T>(cx: *mut JSContext, value: &[T::Element]) -> JSVal +where + T: TypedArrayElementCreator, +{ + rooted!(in(cx) let mut rval = ptr::null_mut::<JSObject>()); + <TypedArray<T, *mut JSObject>>::create(cx, CreateWith::Slice(&value), rval.handle_mut()) + .unwrap(); + ObjectValue(rval.get()) +} + bitflags! { /// Set of bitflags for texture unpacking (texImage2d, etc...) #[derive(JSTraceable, MallocSizeOf)] @@ -401,7 +422,7 @@ impl WebGLRenderingContext { Ok(()) } - fn with_location<F>(&self, location: Option<&WebGLUniformLocation>, f: F) + pub fn with_location<F>(&self, location: Option<&WebGLUniformLocation>, f: F) where F: FnOnce(&WebGLUniformLocation) -> WebGLResult<()>, { @@ -1214,6 +1235,25 @@ impl WebGLRenderingContext { pub fn current_program(&self) -> Option<DomRoot<WebGLProgram>> { self.current_program.get() } + + pub fn uniform_check_program( + &self, + program: &WebGLProgram, + location: &WebGLUniformLocation, + ) -> WebGLResult<()> { + self.validate_ownership(program)?; + + if program.is_deleted() || + !program.is_linked() || + self.context_id() != location.context_id() || + program.id() != location.program_id() || + program.link_generation() != location.link_generation() + { + return Err(InvalidOperation); + } + + Ok(()) + } } #[cfg(not(feature = "webgl_backtrace"))] @@ -3548,88 +3588,60 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { program: &WebGLProgram, location: &WebGLUniformLocation, ) -> JSVal { - handle_potential_webgl_error!(self, self.validate_ownership(program), return NullValue()); - - if program.is_deleted() || - !program.is_linked() || - self.context_id() != location.context_id() || - program.id() != location.program_id() || - program.link_generation() != location.link_generation() - { - self.webgl_error(InvalidOperation); - return NullValue(); - } - - fn get<T, F>(triple: (&WebGLRenderingContext, WebGLProgramId, i32), f: F) -> T - where - F: FnOnce(WebGLProgramId, i32, WebGLSender<T>) -> WebGLCommand, - T: for<'de> Deserialize<'de> + Serialize, - { - let (sender, receiver) = webgl_channel().unwrap(); - triple.0.send_command(f(triple.1, triple.2, sender)); - receiver.recv().unwrap() - } + handle_potential_webgl_error!( + self, + self.uniform_check_program(program, location), + return NullValue() + ); let triple = (self, program.id(), location.id()); - unsafe fn typed<T>(cx: *mut JSContext, value: &[T::Element]) -> JSVal - where - T: TypedArrayElementCreator, - { - rooted!(in(cx) let mut rval = ptr::null_mut::<JSObject>()); - <TypedArray<T, *mut JSObject>>::create( - cx, - CreateWith::Slice(&value), - rval.handle_mut(), - ) - .unwrap(); - ObjectValue(rval.get()) - } - match location.type_() { - constants::BOOL => BooleanValue(get(triple, WebGLCommand::GetUniformBool)), + constants::BOOL => BooleanValue(uniform_get(triple, WebGLCommand::GetUniformBool)), constants::BOOL_VEC2 => unsafe { rooted!(in(*cx) let mut rval = NullValue()); - get(triple, WebGLCommand::GetUniformBool2).to_jsval(*cx, rval.handle_mut()); + uniform_get(triple, WebGLCommand::GetUniformBool2).to_jsval(*cx, rval.handle_mut()); rval.get() }, constants::BOOL_VEC3 => unsafe { rooted!(in(*cx) let mut rval = NullValue()); - get(triple, WebGLCommand::GetUniformBool3).to_jsval(*cx, rval.handle_mut()); + uniform_get(triple, WebGLCommand::GetUniformBool3).to_jsval(*cx, rval.handle_mut()); rval.get() }, constants::BOOL_VEC4 => unsafe { rooted!(in(*cx) let mut rval = NullValue()); - get(triple, WebGLCommand::GetUniformBool4).to_jsval(*cx, rval.handle_mut()); + uniform_get(triple, WebGLCommand::GetUniformBool4).to_jsval(*cx, rval.handle_mut()); rval.get() }, constants::INT | constants::SAMPLER_2D | constants::SAMPLER_CUBE => { - Int32Value(get(triple, WebGLCommand::GetUniformInt)) + Int32Value(uniform_get(triple, WebGLCommand::GetUniformInt)) }, constants::INT_VEC2 => unsafe { - typed::<Int32>(*cx, &get(triple, WebGLCommand::GetUniformInt2)) + uniform_typed::<Int32>(*cx, &uniform_get(triple, WebGLCommand::GetUniformInt2)) }, constants::INT_VEC3 => unsafe { - typed::<Int32>(*cx, &get(triple, WebGLCommand::GetUniformInt3)) + uniform_typed::<Int32>(*cx, &uniform_get(triple, WebGLCommand::GetUniformInt3)) }, constants::INT_VEC4 => unsafe { - typed::<Int32>(*cx, &get(triple, WebGLCommand::GetUniformInt4)) + uniform_typed::<Int32>(*cx, &uniform_get(triple, WebGLCommand::GetUniformInt4)) + }, + constants::FLOAT => { + DoubleValue(uniform_get(triple, WebGLCommand::GetUniformFloat) as f64) }, - constants::FLOAT => DoubleValue(get(triple, WebGLCommand::GetUniformFloat) as f64), constants::FLOAT_VEC2 => unsafe { - typed::<Float32>(*cx, &get(triple, WebGLCommand::GetUniformFloat2)) + uniform_typed::<Float32>(*cx, &uniform_get(triple, WebGLCommand::GetUniformFloat2)) }, constants::FLOAT_VEC3 => unsafe { - typed::<Float32>(*cx, &get(triple, WebGLCommand::GetUniformFloat3)) + uniform_typed::<Float32>(*cx, &uniform_get(triple, WebGLCommand::GetUniformFloat3)) }, constants::FLOAT_VEC4 | constants::FLOAT_MAT2 => unsafe { - typed::<Float32>(*cx, &get(triple, WebGLCommand::GetUniformFloat4)) + uniform_typed::<Float32>(*cx, &uniform_get(triple, WebGLCommand::GetUniformFloat4)) }, constants::FLOAT_MAT3 => unsafe { - typed::<Float32>(*cx, &get(triple, WebGLCommand::GetUniformFloat9)) + uniform_typed::<Float32>(*cx, &uniform_get(triple, WebGLCommand::GetUniformFloat9)) }, constants::FLOAT_MAT4 => unsafe { - typed::<Float32>(*cx, &get(triple, WebGLCommand::GetUniformFloat16)) + uniform_typed::<Float32>(*cx, &uniform_get(triple, WebGLCommand::GetUniformFloat16)) }, _ => panic!("wrong uniform type"), } diff --git a/components/script/dom/webidls/WebGL2RenderingContext.webidl b/components/script/dom/webidls/WebGL2RenderingContext.webidl index 1dca400b742..33e8d1bf99b 100644 --- a/components/script/dom/webidls/WebGL2RenderingContext.webidl +++ b/components/script/dom/webidls/WebGL2RenderingContext.webidl @@ -15,7 +15,7 @@ typedef unsigned long long GLuint64; // interface WebGLVertexArrayObject : WebGLObject { // }; -// typedef ([AllowShared] Uint32Array or sequence<GLuint>) Uint32List; +typedef (/*[AllowShared]*/ Uint32Array or sequence<GLuint>) Uint32List; interface mixin WebGL2RenderingContextBase { @@ -425,10 +425,10 @@ interface mixin WebGL2RenderingContextBase // [WebGLHandlesContextLoss] GLint getFragDataLocation(WebGLProgram program, DOMString name); /* Uniforms */ - // void uniform1ui(WebGLUniformLocation? location, GLuint v0); - // void uniform2ui(WebGLUniformLocation? location, GLuint v0, GLuint v1); - // void uniform3ui(WebGLUniformLocation? location, GLuint v0, GLuint v1, GLuint v2); - // void uniform4ui(WebGLUniformLocation? location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); + void uniform1ui(WebGLUniformLocation? location, GLuint v0); + void uniform2ui(WebGLUniformLocation? location, GLuint v0, GLuint v1); + void uniform3ui(WebGLUniformLocation? location, GLuint v0, GLuint v1, GLuint v2); + void uniform4ui(WebGLUniformLocation? location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); // void uniform1fv(WebGLUniformLocation? location, Float32List data, optional GLuint srcOffset = 0, // optional GLuint srcLength = 0); @@ -448,14 +448,14 @@ interface mixin WebGL2RenderingContextBase // void uniform4iv(WebGLUniformLocation? location, Int32List data, optional GLuint srcOffset = 0, // optional GLuint srcLength = 0); - // void uniform1uiv(WebGLUniformLocation? location, Uint32List data, optional GLuint srcOffset = 0, - // optional GLuint srcLength = 0); - // void uniform2uiv(WebGLUniformLocation? location, Uint32List data, optional GLuint srcOffset = 0, - // optional GLuint srcLength = 0); - // void uniform3uiv(WebGLUniformLocation? location, Uint32List data, optional GLuint srcOffset = 0, - // optional GLuint srcLength = 0); - // void uniform4uiv(WebGLUniformLocation? location, Uint32List data, optional GLuint srcOffset = 0, - // optional GLuint srcLength = 0); + void uniform1uiv(WebGLUniformLocation? location, Uint32List data, optional GLuint srcOffset = 0, + optional GLuint srcLength = 0); + void uniform2uiv(WebGLUniformLocation? location, Uint32List data, optional GLuint srcOffset = 0, + optional GLuint srcLength = 0); + void uniform3uiv(WebGLUniformLocation? location, Uint32List data, optional GLuint srcOffset = 0, + optional GLuint srcLength = 0); + void uniform4uiv(WebGLUniformLocation? location, Uint32List data, optional GLuint srcOffset = 0, + optional GLuint srcLength = 0); // void uniformMatrix2fv(WebGLUniformLocation? location, GLboolean transpose, Float32List data, // optional GLuint srcOffset = 0, optional GLuint srcLength = 0); |