diff options
Diffstat (limited to 'components/script')
-rw-r--r-- | components/script/dom/bindings/trace.rs | 5 | ||||
-rw-r--r-- | components/script/dom/webgl2renderingcontext.rs | 357 | ||||
-rw-r--r-- | components/script/dom/webglbuffer.rs | 8 | ||||
-rw-r--r-- | components/script/dom/webglprogram.rs | 149 | ||||
-rw-r--r-- | components/script/dom/webglrenderingcontext.rs | 68 | ||||
-rw-r--r-- | components/script/dom/webidls/WebGL2RenderingContext.webidl | 16 |
6 files changed, 553 insertions, 50 deletions
diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 3bad24b1b1d..1d83fff920d 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -49,7 +49,9 @@ use canvas_traits::canvas::{ }; use canvas_traits::canvas::{CompositionOrBlending, LineCapStyle, LineJoinStyle, RepetitionStyle}; use canvas_traits::webgl::WebGLVertexArrayId; -use canvas_traits::webgl::{ActiveAttribInfo, ActiveUniformInfo, GlType, TexDataType, TexFormat}; +use canvas_traits::webgl::{ + ActiveAttribInfo, ActiveUniformBlockInfo, ActiveUniformInfo, GlType, TexDataType, TexFormat, +}; use canvas_traits::webgl::{GLLimits, WebGLQueryId, WebGLSamplerId}; use canvas_traits::webgl::{WebGLBufferId, WebGLChan, WebGLContextId, WebGLError}; use canvas_traits::webgl::{WebGLFramebufferId, WebGLMsgSender, WebGLPipeline, WebGLProgramId}; @@ -437,6 +439,7 @@ unsafe impl<A: JSTraceable, B: JSTraceable, C: JSTraceable> JSTraceable for (A, unsafe_no_jsmanaged_fields!(ActiveAttribInfo); unsafe_no_jsmanaged_fields!(ActiveUniformInfo); +unsafe_no_jsmanaged_fields!(ActiveUniformBlockInfo); 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/webgl2renderingcontext.rs b/components/script/dom/webgl2renderingcontext.rs index 2c63b775bb1..e8993f472d9 100644 --- a/components/script/dom/webgl2renderingcontext.rs +++ b/components/script/dom/webgl2renderingcontext.rs @@ -45,13 +45,14 @@ use dom_struct::dom_struct; use euclid::default::{Point2D, Rect, Size2D}; use ipc_channel::ipc; use js::jsapi::{JSObject, Type}; -use js::jsval::{BooleanValue, DoubleValue, Int32Value, JSVal, NullValue, UInt32Value}; +use js::jsval::{BooleanValue, DoubleValue, Int32Value, UInt32Value}; +use js::jsval::{JSVal, NullValue, ObjectValue, UndefinedValue}; use js::rust::CustomAutoRooterGuard; -use js::typedarray::ArrayBufferView; +use js::typedarray::{ArrayBufferView, CreateWith, Uint32Array}; use script_layout_interface::HTMLCanvasDataSource; use std::cell::Cell; use std::cmp; -use std::ptr::NonNull; +use std::ptr::{self, NonNull}; #[dom_struct] pub struct WebGL2RenderingContext { @@ -160,6 +161,18 @@ impl WebGL2RenderingContext { } } + pub fn buffer_usage(&self, usage: u32) -> WebGLResult<u32> { + match usage { + constants::STATIC_READ | + constants::DYNAMIC_READ | + constants::STREAM_READ | + constants::STATIC_COPY | + constants::DYNAMIC_COPY | + constants::STREAM_COPY => Ok(usage), + _ => self.base.buffer_usage(usage), + } + } + fn unbind_from(&self, slot: &MutNullableDom<WebGLBuffer>, buffer: &WebGLBuffer) { if slot.get().map_or(false, |b| buffer == &*b) { buffer.decrement_attached_counter(); @@ -411,40 +424,94 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext { fn GetParameter(&self, cx: JSContext, parameter: u32) -> JSVal { match parameter { constants::MAX_CLIENT_WAIT_TIMEOUT_WEBGL => { - Int32Value(self.base.limits().max_client_wait_timeout_webgl.as_nanos() as i32) + return Int32Value( + self.base.limits().max_client_wait_timeout_webgl.as_nanos() as i32 + ); }, constants::SAMPLER_BINDING => unsafe { let idx = (self.base.textures().active_unit_enum() - constants::TEXTURE0) as usize; assert!(idx < self.samplers.len()); let sampler = self.samplers[idx].get(); - optional_root_object_to_js_or_null!(*cx, sampler) + return optional_root_object_to_js_or_null!(*cx, sampler); }, constants::COPY_READ_BUFFER_BINDING => unsafe { - optional_root_object_to_js_or_null!(*cx, &self.bound_copy_read_buffer.get()) + return optional_root_object_to_js_or_null!( + *cx, + &self.bound_copy_read_buffer.get() + ); }, constants::COPY_WRITE_BUFFER_BINDING => unsafe { - optional_root_object_to_js_or_null!(*cx, &self.bound_copy_write_buffer.get()) + return optional_root_object_to_js_or_null!( + *cx, + &self.bound_copy_write_buffer.get() + ); }, constants::PIXEL_PACK_BUFFER_BINDING => unsafe { - optional_root_object_to_js_or_null!(*cx, &self.bound_pixel_pack_buffer.get()) + return optional_root_object_to_js_or_null!( + *cx, + &self.bound_pixel_pack_buffer.get() + ); }, constants::PIXEL_UNPACK_BUFFER_BINDING => unsafe { - optional_root_object_to_js_or_null!(*cx, &self.bound_pixel_unpack_buffer.get()) + return optional_root_object_to_js_or_null!( + *cx, + &self.bound_pixel_unpack_buffer.get() + ); }, constants::TRANSFORM_FEEDBACK_BUFFER_BINDING => unsafe { - optional_root_object_to_js_or_null!( + return optional_root_object_to_js_or_null!( *cx, &self.bound_transform_feedback_buffer.get() - ) + ); }, constants::UNIFORM_BUFFER_BINDING => unsafe { - optional_root_object_to_js_or_null!(*cx, &self.bound_uniform_buffer.get()) + return optional_root_object_to_js_or_null!(*cx, &self.bound_uniform_buffer.get()); }, constants::TRANSFORM_FEEDBACK_BINDING => unsafe { - optional_root_object_to_js_or_null!(*cx, self.current_transform_feedback.get()) + return optional_root_object_to_js_or_null!( + *cx, + self.current_transform_feedback.get() + ); }, - _ => self.base.GetParameter(cx, parameter), + _ => {}, } + + let limit = match parameter { + constants::MAX_UNIFORM_BUFFER_BINDINGS => { + Some(self.base.limits().max_uniform_buffer_bindings) + }, + constants::MAX_UNIFORM_BLOCK_SIZE => Some(self.base.limits().max_uniform_block_size), + constants::MAX_COMBINED_UNIFORM_BLOCKS => { + Some(self.base.limits().max_combined_uniform_blocks) + }, + constants::MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS => { + Some(self.base.limits().max_combined_vertex_uniform_components) + }, + constants::MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS => { + Some(self.base.limits().max_combined_fragment_uniform_components) + }, + constants::MAX_VERTEX_UNIFORM_BLOCKS => { + Some(self.base.limits().max_vertex_uniform_blocks) + }, + constants::MAX_VERTEX_UNIFORM_COMPONENTS => { + Some(self.base.limits().max_vertex_uniform_components) + }, + constants::MAX_FRAGMENT_UNIFORM_BLOCKS => { + Some(self.base.limits().max_fragment_uniform_blocks) + }, + constants::MAX_FRAGMENT_UNIFORM_COMPONENTS => { + Some(self.base.limits().max_fragment_uniform_components) + }, + constants::UNIFORM_BUFFER_OFFSET_ALIGNMENT => { + Some(self.base.limits().uniform_buffer_offset_alignment) + }, + _ => None, + }; + if let Some(limit) = limit { + return UInt32Value(limit); + } + + self.base.GetParameter(cx, parameter) } /// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8 @@ -571,6 +638,7 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext { /// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5 fn BufferData(&self, target: u32, data: Option<ArrayBufferViewOrArrayBuffer>, usage: u32) { + let usage = handle_potential_webgl_error!(self.base, self.buffer_usage(usage), return); let bound_buffer = handle_potential_webgl_error!(self.base, self.bound_buffer(target), return); self.base.buffer_data(target, data, usage, bound_buffer) @@ -578,6 +646,7 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext { /// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5 fn BufferData_(&self, target: u32, size: i64, usage: u32) { + let usage = handle_potential_webgl_error!(self.base, self.buffer_usage(usage), return); let bound_buffer = handle_potential_webgl_error!(self.base, self.bound_buffer(target), return); self.base.buffer_data_(target, size, usage, bound_buffer) @@ -593,6 +662,7 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext { elem_offset: u32, length: u32, ) { + let usage = handle_potential_webgl_error!(self.base, self.buffer_usage(usage), return); let bound_buffer = handle_potential_webgl_error!(self.base, self.bound_buffer(target), return); let bound_buffer = @@ -628,7 +698,10 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext { /// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5 fn BufferSubData(&self, target: u32, offset: i64, data: ArrayBufferViewOrArrayBuffer) { - self.base.BufferSubData(target, offset, data) + let bound_buffer = + handle_potential_webgl_error!(self.base, self.bound_buffer(target), return); + self.base + .buffer_sub_data(target, offset, data, bound_buffer) } /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.3 @@ -2304,6 +2377,260 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext { DOMString::from(name), )) } + + /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.16 + fn BindBufferBase(&self, target: u32, index: u32, buffer: Option<&WebGLBuffer>) { + let (bind_limit, slot) = match target { + constants::TRANSFORM_FEEDBACK_BUFFER => ( + self.base.limits().max_transform_feedback_separate_attribs, + &self.bound_transform_feedback_buffer, + ), + constants::UNIFORM_BUFFER => ( + self.base.limits().max_uniform_buffer_bindings, + &self.bound_uniform_buffer, + ), + _ => return self.base.webgl_error(InvalidEnum), + }; + if index >= bind_limit { + return self.base.webgl_error(InvalidValue); + } + + if let Some(buffer) = buffer { + handle_potential_webgl_error!(self.base, self.base.validate_ownership(buffer), return); + + if buffer.is_marked_for_deletion() { + return self.base.webgl_error(InvalidOperation); + } + handle_potential_webgl_error!(self.base, buffer.set_target_maybe(target), return); + buffer.increment_attached_counter(); + } + + self.base.send_command(WebGLCommand::BindBufferBase( + target, + index, + buffer.map(|b| b.id()), + )); + if let Some(old) = slot.get() { + old.decrement_attached_counter(); + } + + slot.set(buffer); + } + + /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.16 + fn BindBufferRange( + &self, + target: u32, + index: u32, + buffer: Option<&WebGLBuffer>, + offset: i64, + size: i64, + ) { + let (bind_limit, slot) = match target { + constants::TRANSFORM_FEEDBACK_BUFFER => ( + self.base.limits().max_transform_feedback_separate_attribs, + &self.bound_transform_feedback_buffer, + ), + constants::UNIFORM_BUFFER => ( + self.base.limits().max_uniform_buffer_bindings, + &self.bound_uniform_buffer, + ), + _ => return self.base.webgl_error(InvalidEnum), + }; + if index >= bind_limit { + return self.base.webgl_error(InvalidValue); + } + + if offset < 0 || size < 0 { + return self.base.webgl_error(InvalidValue); + } + if buffer.is_some() && size == 0 { + return self.base.webgl_error(InvalidValue); + } + + match target { + constants::TRANSFORM_FEEDBACK_BUFFER => { + if size % 4 != 0 && offset % 4 != 0 { + return self.base.webgl_error(InvalidValue); + } + }, + constants::UNIFORM_BUFFER => { + let offset_alignment = self.base.limits().uniform_buffer_offset_alignment; + if offset % offset_alignment as i64 != 0 { + return self.base.webgl_error(InvalidValue); + } + }, + _ => unreachable!(), + } + + if let Some(buffer) = buffer { + handle_potential_webgl_error!(self.base, self.base.validate_ownership(buffer), return); + + if buffer.is_marked_for_deletion() { + return self.base.webgl_error(InvalidOperation); + } + handle_potential_webgl_error!(self.base, buffer.set_target_maybe(target), return); + buffer.increment_attached_counter(); + } + + self.base.send_command(WebGLCommand::BindBufferRange( + target, + index, + buffer.map(|b| b.id()), + offset, + size, + )); + if let Some(old) = slot.get() { + old.decrement_attached_counter(); + } + + slot.set(buffer); + } + + /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.16 + fn GetUniformIndices(&self, program: &WebGLProgram, names: Vec<DOMString>) -> Option<Vec<u32>> { + handle_potential_webgl_error!( + self.base, + self.base.validate_ownership(program), + return None + ); + let indices = handle_potential_webgl_error!( + self.base, + program.get_uniform_indices(names), + return None + ); + Some(indices) + } + + /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.16 + #[allow(unsafe_code)] + fn GetActiveUniforms( + &self, + cx: JSContext, + program: &WebGLProgram, + indices: Vec<u32>, + pname: u32, + ) -> JSVal { + handle_potential_webgl_error!( + self.base, + self.base.validate_ownership(program), + return NullValue() + ); + let values = handle_potential_webgl_error!( + self.base, + program.get_active_uniforms(indices, pname), + return NullValue() + ); + + rooted!(in(*cx) let mut rval = UndefinedValue()); + match pname { + constants::UNIFORM_SIZE | + constants::UNIFORM_TYPE | + constants::UNIFORM_BLOCK_INDEX | + constants::UNIFORM_OFFSET | + constants::UNIFORM_ARRAY_STRIDE | + constants::UNIFORM_MATRIX_STRIDE => unsafe { + values.to_jsval(*cx, rval.handle_mut()); + }, + constants::UNIFORM_IS_ROW_MAJOR => unsafe { + let values = values.iter().map(|&v| v != 0).collect::<Vec<_>>(); + values.to_jsval(*cx, rval.handle_mut()); + }, + _ => unreachable!(), + } + rval.get() + } + + /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.16 + fn GetUniformBlockIndex(&self, program: &WebGLProgram, block_name: DOMString) -> u32 { + handle_potential_webgl_error!( + self.base, + self.base.validate_ownership(program), + return constants::INVALID_INDEX + ); + let index = handle_potential_webgl_error!( + self.base, + program.get_uniform_block_index(block_name), + return constants::INVALID_INDEX + ); + index + } + + /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.16 + #[allow(unsafe_code)] + fn GetActiveUniformBlockParameter( + &self, + cx: JSContext, + program: &WebGLProgram, + block_index: u32, + pname: u32, + ) -> JSVal { + handle_potential_webgl_error!( + self.base, + self.base.validate_ownership(program), + return NullValue() + ); + let values = handle_potential_webgl_error!( + self.base, + program.get_active_uniform_block_parameter(block_index, pname), + return NullValue() + ); + match pname { + constants::UNIFORM_BLOCK_BINDING | + constants::UNIFORM_BLOCK_DATA_SIZE | + constants::UNIFORM_BLOCK_ACTIVE_UNIFORMS => { + assert!(values.len() == 1); + UInt32Value(values[0] as u32) + }, + constants::UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES => unsafe { + let values = values.iter().map(|&v| v as u32).collect::<Vec<_>>(); + rooted!(in(*cx) let mut result = ptr::null_mut::<JSObject>()); + let _ = Uint32Array::create(*cx, CreateWith::Slice(&values), result.handle_mut()) + .unwrap(); + ObjectValue(result.get()) + }, + constants::UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER | + constants::UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER => { + assert!(values.len() == 1); + BooleanValue(values[0] != 0) + }, + _ => unreachable!(), + } + } + + /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.16 + fn GetActiveUniformBlockName( + &self, + program: &WebGLProgram, + block_index: u32, + ) -> Option<DOMString> { + handle_potential_webgl_error!( + self.base, + self.base.validate_ownership(program), + return None + ); + let name = handle_potential_webgl_error!( + self.base, + program.get_active_uniform_block_name(block_index), + return None + ); + Some(DOMString::from(name)) + } + + /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.16 + fn UniformBlockBinding(&self, program: &WebGLProgram, block_index: u32, block_binding: u32) { + handle_potential_webgl_error!(self.base, self.base.validate_ownership(program), return); + + if block_binding >= self.base.limits().max_uniform_buffer_bindings { + return self.base.webgl_error(InvalidValue); + } + + handle_potential_webgl_error!( + self.base, + program.bind_uniform_block(block_index, block_binding), + return + ) + } } impl LayoutCanvasWebGLRenderingContextHelpers for LayoutDom<WebGL2RenderingContext> { diff --git a/components/script/dom/webglbuffer.rs b/components/script/dom/webglbuffer.rs index 182100ae41f..6e951f3f53e 100644 --- a/components/script/dom/webglbuffer.rs +++ b/components/script/dom/webglbuffer.rs @@ -75,7 +75,13 @@ impl WebGLBuffer { match usage { WebGLRenderingContextConstants::STREAM_DRAW | WebGLRenderingContextConstants::STATIC_DRAW | - WebGLRenderingContextConstants::DYNAMIC_DRAW => (), + WebGLRenderingContextConstants::DYNAMIC_DRAW | + WebGL2RenderingContextConstants::STATIC_READ | + WebGL2RenderingContextConstants::DYNAMIC_READ | + WebGL2RenderingContextConstants::STREAM_READ | + WebGL2RenderingContextConstants::STATIC_COPY | + WebGL2RenderingContextConstants::DYNAMIC_COPY | + WebGL2RenderingContextConstants::STREAM_COPY => (), _ => return Err(WebGLError::InvalidEnum), } diff --git a/components/script/dom/webglprogram.rs b/components/script/dom/webglprogram.rs index 3b040a170b1..556573aae2e 100644 --- a/components/script/dom/webglprogram.rs +++ b/components/script/dom/webglprogram.rs @@ -4,6 +4,7 @@ // https://www.khronos.org/registry/webgl/specs/latest/1.0/webgl.idl use crate::dom::bindings::cell::{DomRefCell, Ref}; +use crate::dom::bindings::codegen::Bindings::WebGL2RenderingContextBinding::WebGL2RenderingContextConstants as constants2; use crate::dom::bindings::codegen::Bindings::WebGLProgramBinding; use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants; use crate::dom::bindings::inheritance::Castable; @@ -16,7 +17,9 @@ use crate::dom::webglrenderingcontext::WebGLRenderingContext; use crate::dom::webglshader::WebGLShader; use crate::dom::webgluniformlocation::WebGLUniformLocation; use canvas_traits::webgl::{webgl_channel, WebGLProgramId, WebGLResult}; -use canvas_traits::webgl::{ActiveAttribInfo, ActiveUniformInfo, WebGLCommand, WebGLError}; +use canvas_traits::webgl::{ + ActiveAttribInfo, ActiveUniformBlockInfo, ActiveUniformInfo, WebGLCommand, WebGLError, +}; use dom_struct::dom_struct; use fnv::FnvHashSet; use std::cell::Cell; @@ -34,6 +37,7 @@ pub struct WebGLProgram { vertex_shader: MutNullableDom<WebGLShader>, active_attribs: DomRefCell<Box<[ActiveAttribInfo]>>, active_uniforms: DomRefCell<Box<[ActiveUniformInfo]>>, + active_uniform_blocks: DomRefCell<Box<[ActiveUniformBlockInfo]>>, transform_feedback_varyings_length: Cell<i32>, transform_feedback_mode: Cell<i32>, } @@ -52,6 +56,7 @@ impl WebGLProgram { vertex_shader: Default::default(), active_attribs: DomRefCell::new(vec![].into()), active_uniforms: DomRefCell::new(vec![].into()), + active_uniform_blocks: DomRefCell::new(vec![].into()), transform_feedback_varyings_length: Default::default(), transform_feedback_mode: Default::default(), } @@ -143,6 +148,7 @@ impl WebGLProgram { .set(self.link_generation.get().checked_add(1).unwrap()); *self.active_attribs.borrow_mut() = Box::new([]); *self.active_uniforms.borrow_mut() = Box::new([]); + *self.active_uniform_blocks.borrow_mut() = Box::new([]); match self.fragment_shader.get() { Some(ref shader) if shader.successfully_compiled() => {}, @@ -197,6 +203,7 @@ impl WebGLProgram { .set(link_info.transform_feedback_mode); *self.active_attribs.borrow_mut() = link_info.active_attribs; *self.active_uniforms.borrow_mut() = link_info.active_uniforms; + *self.active_uniform_blocks.borrow_mut() = link_info.active_uniform_blocks; Ok(()) } @@ -208,6 +215,10 @@ impl WebGLProgram { Ref::map(self.active_uniforms.borrow(), |uniforms| &**uniforms) } + pub fn active_uniform_blocks(&self) -> Ref<[ActiveUniformBlockInfo]> { + Ref::map(self.active_uniform_blocks.borrow(), |blocks| &**blocks) + } + /// glValidateProgram pub fn validate(&self) -> WebGLResult<()> { if self.is_deleted() { @@ -413,6 +424,142 @@ impl WebGLProgram { ))) } + pub fn get_uniform_block_index(&self, name: DOMString) -> WebGLResult<u32> { + if !self.link_called.get() || self.is_deleted() { + return Err(WebGLError::InvalidOperation); + } + + if !validate_glsl_name(&name)? { + return Ok(constants2::INVALID_INDEX); + } + + let (sender, receiver) = webgl_channel().unwrap(); + self.upcast::<WebGLObject>() + .context() + .send_command(WebGLCommand::GetUniformBlockIndex( + self.id, + name.into(), + sender, + )); + Ok(receiver.recv().unwrap()) + } + + pub fn get_uniform_indices(&self, names: Vec<DOMString>) -> WebGLResult<Vec<u32>> { + if !self.link_called.get() || self.is_deleted() { + return Err(WebGLError::InvalidOperation); + } + + let validation_errors = names + .iter() + .map(|name| validate_glsl_name(&name)) + .collect::<Vec<_>>(); + let first_validation_error = validation_errors.iter().find(|result| result.is_err()); + if let Some(error) = first_validation_error { + return Err(error.unwrap_err()); + } + + let names = names + .iter() + .map(|name| name.to_string()) + .collect::<Vec<_>>(); + + let (sender, receiver) = webgl_channel().unwrap(); + self.upcast::<WebGLObject>() + .context() + .send_command(WebGLCommand::GetUniformIndices(self.id, names, sender)); + Ok(receiver.recv().unwrap()) + } + + pub fn get_active_uniforms(&self, indices: Vec<u32>, pname: u32) -> WebGLResult<Vec<i32>> { + if !self.is_linked() || self.is_deleted() { + return Err(WebGLError::InvalidOperation); + } + + match pname { + constants2::UNIFORM_TYPE | + constants2::UNIFORM_SIZE | + constants2::UNIFORM_BLOCK_INDEX | + constants2::UNIFORM_OFFSET | + constants2::UNIFORM_ARRAY_STRIDE | + constants2::UNIFORM_MATRIX_STRIDE | + constants2::UNIFORM_IS_ROW_MAJOR => {}, + _ => return Err(WebGLError::InvalidEnum), + } + + if indices.len() > self.active_uniforms.borrow().len() { + return Err(WebGLError::InvalidValue); + } + + let (sender, receiver) = webgl_channel().unwrap(); + self.upcast::<WebGLObject>() + .context() + .send_command(WebGLCommand::GetActiveUniforms( + self.id, indices, pname, sender, + )); + Ok(receiver.recv().unwrap()) + } + + pub fn get_active_uniform_block_parameter( + &self, + block_index: u32, + pname: u32, + ) -> WebGLResult<Vec<i32>> { + if !self.link_called.get() || self.is_deleted() { + return Err(WebGLError::InvalidOperation); + } + + if block_index as usize >= self.active_uniform_blocks.borrow().len() { + return Err(WebGLError::InvalidValue); + } + + match pname { + constants2::UNIFORM_BLOCK_BINDING | + constants2::UNIFORM_BLOCK_DATA_SIZE | + constants2::UNIFORM_BLOCK_ACTIVE_UNIFORMS | + constants2::UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES | + constants2::UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER | + constants2::UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER => {}, + _ => return Err(WebGLError::InvalidEnum), + } + + let (sender, receiver) = webgl_channel().unwrap(); + self.upcast::<WebGLObject>().context().send_command( + WebGLCommand::GetActiveUniformBlockParameter(self.id, block_index, pname, sender), + ); + Ok(receiver.recv().unwrap()) + } + + pub fn get_active_uniform_block_name(&self, block_index: u32) -> WebGLResult<String> { + if !self.link_called.get() || self.is_deleted() { + return Err(WebGLError::InvalidOperation); + } + + if block_index as usize >= self.active_uniforms.borrow().len() { + return Err(WebGLError::InvalidValue); + } + + let (sender, receiver) = webgl_channel().unwrap(); + self.upcast::<WebGLObject>().context().send_command( + WebGLCommand::GetActiveUniformBlockName(self.id, block_index, sender), + ); + Ok(receiver.recv().unwrap()) + } + + pub fn bind_uniform_block(&self, block_index: u32, block_binding: u32) -> WebGLResult<()> { + if block_index as usize >= self.active_uniform_blocks.borrow().len() { + return Err(WebGLError::InvalidValue); + } + + self.upcast::<WebGLObject>() + .context() + .send_command(WebGLCommand::UniformBlockBinding( + self.id, + block_index, + block_binding, + )); + Ok(()) + } + /// glGetProgramInfoLog pub fn get_info_log(&self) -> WebGLResult<String> { if self.is_deleted() { diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index 85930cd3529..68eccfa711d 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -1020,6 +1020,13 @@ impl WebGLRenderingContext { } } + pub fn buffer_usage(&self, usage: u32) -> WebGLResult<u32> { + match usage { + constants::STREAM_DRAW | constants::STATIC_DRAW | constants::DYNAMIC_DRAW => Ok(usage), + _ => Err(WebGLError::InvalidEnum), + } + } + pub fn create_vertex_array(&self) -> Option<DomRoot<WebGLVertexArrayObjectOES>> { let (sender, receiver) = webgl_channel().unwrap(); self.send_command(WebGLCommand::CreateVertexArray(sender)); @@ -1146,6 +1153,40 @@ impl WebGLRenderingContext { handle_potential_webgl_error!(self, bound_buffer.buffer_data(target, &data, usage)); } + #[allow(unsafe_code)] + pub fn buffer_sub_data( + &self, + target: u32, + offset: i64, + data: ArrayBufferViewOrArrayBuffer, + bound_buffer: Option<DomRoot<WebGLBuffer>>, + ) { + let bound_buffer = + handle_potential_webgl_error!(self, bound_buffer.ok_or(InvalidOperation), return); + + if offset < 0 { + return self.webgl_error(InvalidValue); + } + + let data = unsafe { + // Safe because we don't do anything with JS until the end of the method. + match data { + ArrayBufferViewOrArrayBuffer::ArrayBuffer(ref data) => data.as_slice(), + ArrayBufferViewOrArrayBuffer::ArrayBufferView(ref data) => data.as_slice(), + } + }; + if (offset as u64) + data.len() as u64 > bound_buffer.capacity() as u64 { + return self.webgl_error(InvalidValue); + } + let (sender, receiver) = ipc::bytes_channel().unwrap(); + self.send_command(WebGLCommand::BufferSubData( + target, + offset as isize, + receiver, + )); + sender.send(data).unwrap(); + } + pub fn bind_buffer_maybe( &self, slot: &MutNullableDom<WebGLBuffer>, @@ -1764,12 +1805,14 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5 fn BufferData(&self, target: u32, data: Option<ArrayBufferViewOrArrayBuffer>, usage: u32) { + let usage = handle_potential_webgl_error!(self, self.buffer_usage(usage), return); let bound_buffer = handle_potential_webgl_error!(self, self.bound_buffer(target), return); self.buffer_data(target, data, usage, bound_buffer) } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5 fn BufferData_(&self, target: u32, size: i64, usage: u32) { + let usage = handle_potential_webgl_error!(self, self.buffer_usage(usage), return); let bound_buffer = handle_potential_webgl_error!(self, self.bound_buffer(target), return); self.buffer_data_(target, size, usage, bound_buffer) } @@ -1778,30 +1821,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { #[allow(unsafe_code)] fn BufferSubData(&self, target: u32, offset: i64, data: ArrayBufferViewOrArrayBuffer) { let bound_buffer = handle_potential_webgl_error!(self, self.bound_buffer(target), return); - let bound_buffer = - handle_potential_webgl_error!(self, bound_buffer.ok_or(InvalidOperation), return); - - if offset < 0 { - return self.webgl_error(InvalidValue); - } - - let data = unsafe { - // Safe because we don't do anything with JS until the end of the method. - match data { - ArrayBufferViewOrArrayBuffer::ArrayBuffer(ref data) => data.as_slice(), - ArrayBufferViewOrArrayBuffer::ArrayBufferView(ref data) => data.as_slice(), - } - }; - if (offset as u64) + data.len() as u64 > bound_buffer.capacity() as u64 { - return self.webgl_error(InvalidValue); - } - let (sender, receiver) = ipc::bytes_channel().unwrap(); - self.send_command(WebGLCommand::BufferSubData( - target, - offset as isize, - receiver, - )); - sender.send(data).unwrap(); + self.buffer_sub_data(target, offset, data, bound_buffer) } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8 diff --git a/components/script/dom/webidls/WebGL2RenderingContext.webidl b/components/script/dom/webidls/WebGL2RenderingContext.webidl index 71b5ab10034..1dca400b742 100644 --- a/components/script/dom/webidls/WebGL2RenderingContext.webidl +++ b/components/script/dom/webidls/WebGL2RenderingContext.webidl @@ -553,15 +553,15 @@ interface mixin WebGL2RenderingContextBase void resumeTransformFeedback(); /* Uniform Buffer Objects and Transform Feedback Buffers */ - // void bindBufferBase(GLenum target, GLuint index, WebGLBuffer? buffer); - // void bindBufferRange(GLenum target, GLuint index, WebGLBuffer? buffer, GLintptr offset, GLsizeiptr size); + void bindBufferBase(GLenum target, GLuint index, WebGLBuffer? buffer); + void bindBufferRange(GLenum target, GLuint index, WebGLBuffer? buffer, GLintptr offset, GLsizeiptr size); // any getIndexedParameter(GLenum target, GLuint index); - // sequence<GLuint>? getUniformIndices(WebGLProgram program, sequence<DOMString> uniformNames); - // any getActiveUniforms(WebGLProgram program, sequence<GLuint> uniformIndices, GLenum pname); - // GLuint getUniformBlockIndex(WebGLProgram program, DOMString uniformBlockName); - // any getActiveUniformBlockParameter(WebGLProgram program, GLuint uniformBlockIndex, GLenum pname); - // DOMString? getActiveUniformBlockName(WebGLProgram program, GLuint uniformBlockIndex); - // void uniformBlockBinding(WebGLProgram program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); + sequence<GLuint>? getUniformIndices(WebGLProgram program, sequence<DOMString> uniformNames); + any getActiveUniforms(WebGLProgram program, sequence<GLuint> uniformIndices, GLenum pname); + GLuint getUniformBlockIndex(WebGLProgram program, DOMString uniformBlockName); + any getActiveUniformBlockParameter(WebGLProgram program, GLuint uniformBlockIndex, GLenum pname); + DOMString? getActiveUniformBlockName(WebGLProgram program, GLuint uniformBlockIndex); + void uniformBlockBinding(WebGLProgram program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); /* Vertex Array Objects */ /*WebGLVertexArrayObject? createVertexArray(); |