diff --git a/components/script/dom/webgl2renderingcontext.rs b/components/script/dom/webgl2renderingcontext.rs index 9bc4b8fe0a8f..7dd7ddd0279f 100644 --- a/components/script/dom/webgl2renderingcontext.rs +++ b/components/script/dom/webgl2renderingcontext.rs @@ -18,7 +18,9 @@ use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom, MutNullableDom}; use crate::dom::bindings::str::DOMString; use crate::dom::globalscope::GlobalScope; use crate::dom::htmlcanvaselement::HTMLCanvasElement; -use crate::dom::webgl_validations::tex_image_2d::{TexStorageValidator, TexStorageValidatorResult}; +use crate::dom::webgl_validations::tex_image_2d::{ + TexImage2DValidator, TexImage2DValidatorResult, TexStorageValidator, TexStorageValidatorResult, +}; use crate::dom::webgl_validations::WebGLValidator; use crate::dom::webglactiveinfo::WebGLActiveInfo; use crate::dom::webglbuffer::WebGLBuffer; @@ -27,8 +29,8 @@ use crate::dom::webglprogram::WebGLProgram; use crate::dom::webglquery::WebGLQuery; use crate::dom::webglrenderbuffer::WebGLRenderbuffer; use crate::dom::webglrenderingcontext::{ - uniform_get, uniform_typed, LayoutCanvasWebGLRenderingContextHelpers, Operation, VertexAttrib, - WebGLRenderingContext, + uniform_get, uniform_typed, LayoutCanvasWebGLRenderingContextHelpers, Operation, TexPixels, + VertexAttrib, WebGLRenderingContext, }; use crate::dom::webglsampler::{WebGLSampler, WebGLSamplerValue}; use crate::dom::webglshader::WebGLShader; @@ -48,7 +50,7 @@ use canvas_traits::webgl::{ }; use dom_struct::dom_struct; use euclid::default::{Point2D, Rect, Size2D}; -use ipc_channel::ipc; +use ipc_channel::ipc::{self, IpcSharedMemory}; use js::jsapi::{JSObject, Type}; use js::jsval::{BooleanValue, DoubleValue, Int32Value, UInt32Value}; use js::jsval::{JSVal, NullValue, ObjectValue, UndefinedValue}; @@ -2914,6 +2916,100 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext { .TexImage2D_(target, level, internal_format, format, data_type, source) } + /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.6 + #[allow(unsafe_code)] + fn TexImage2D__( + &self, + target: u32, + level: i32, + internalformat: i32, + width: i32, + height: i32, + border: i32, + format: u32, + type_: u32, + src_data: CustomAutoRooterGuard, + src_offset: u32, + ) -> Fallible<()> { + if self.bound_pixel_unpack_buffer.get().is_some() { + return Ok(self.base.webgl_error(InvalidOperation)); + } + + if type_ == constants::FLOAT_32_UNSIGNED_INT_24_8_REV { + return Ok(self.base.webgl_error(InvalidOperation)); + } + + let validator = TexImage2DValidator::new( + &self.base, + target, + level, + internalformat as u32, + width, + height, + border, + format, + type_, + ); + + let TexImage2DValidatorResult { + texture, + target, + width, + height, + level, + border, + internal_format, + format, + data_type, + } = match validator.validate() { + Ok(result) => result, + Err(_) => return Ok(()), + }; + + let unpacking_alignment = self.base.texture_unpacking_alignment(); + + let src_elem_size = typedarray_elem_size(src_data.get_array_type()); + let src_byte_offset = src_offset as usize * src_elem_size; + + if src_data.len() <= src_byte_offset { + return Ok(self.base.webgl_error(InvalidOperation)); + } + + let buff = IpcSharedMemory::from_bytes(unsafe { &src_data.as_slice()[src_byte_offset..] }); + + let expected_byte_length = match { + self.base.validate_tex_image_2d_data( + width, + height, + format, + data_type, + unpacking_alignment, + Some(&*src_data), + ) + } { + Ok(byte_length) => byte_length, + Err(()) => return Ok(()), + }; + + if expected_byte_length as usize > buff.len() { + return Ok(self.base.webgl_error(InvalidOperation)); + } + + self.base.tex_image_2d( + &texture, + target, + data_type, + internal_format, + format, + level, + border, + unpacking_alignment, + TexPixels::from_array(buff, Size2D::new(width, height)), + ); + + Ok(()) + } + /// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8 fn TexSubImage2D( &self, diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index ae7272f0ec15..1c45f14b3d3d 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -306,6 +306,10 @@ impl WebGLRenderingContext { &self.limits } + pub fn texture_unpacking_alignment(&self) -> u32 { + self.texture_unpacking_alignment.get() + } + pub fn current_vao(&self) -> DomRoot { self.current_vao.or_init(|| { DomRoot::from_ref( @@ -697,14 +701,14 @@ impl WebGLRenderingContext { } // TODO(emilio): Move this logic to a validator. - fn validate_tex_image_2d_data( + pub fn validate_tex_image_2d_data( &self, width: u32, height: u32, format: TexFormat, data_type: TexDataType, unpacking_alignment: u32, - data: &Option, + data: Option<&ArrayBufferView>, ) -> Result { let element_size = data_type.element_size(); let components_per_element = data_type.components_per_element(); @@ -742,7 +746,7 @@ impl WebGLRenderingContext { } } - fn tex_image_2d( + pub fn tex_image_2d( &self, texture: &WebGLTexture, target: TexImageTarget, @@ -4276,7 +4280,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { format, data_type, unpacking_alignment, - &*pixels, + pixels.as_ref(), ) } { Ok(byte_length) => byte_length, @@ -4503,7 +4507,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { format, data_type, unpacking_alignment, - &*pixels, + pixels.as_ref(), ) } { Ok(byte_length) => byte_length, @@ -4881,7 +4885,7 @@ impl TextureUnit { } } -struct TexPixels { +pub struct TexPixels { data: IpcSharedMemory, size: Size2D, pixel_format: Option, @@ -4903,7 +4907,7 @@ impl TexPixels { } } - fn from_array(data: IpcSharedMemory, size: Size2D) -> Self { + pub fn from_array(data: IpcSharedMemory, size: Size2D) -> Self { Self { data, size, diff --git a/components/script/dom/webidls/WebGL2RenderingContext.webidl b/components/script/dom/webidls/WebGL2RenderingContext.webidl index 96ab1417b7e8..d410f8899e4b 100644 --- a/components/script/dom/webidls/WebGL2RenderingContext.webidl +++ b/components/script/dom/webidls/WebGL2RenderingContext.webidl @@ -512,10 +512,10 @@ interface mixin WebGL2RenderingContextOverloads //void texImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, // GLint border, GLenum format, GLenum type, // TexImageSource source); // May throw DOMException - //[Throws] - //void texImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, - // GLint border, GLenum format, GLenum type, /*[AllowShared]*/ ArrayBufferView srcData, - // GLuint srcOffset); + [Throws] + void texImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, + GLint border, GLenum format, GLenum type, /*[AllowShared]*/ ArrayBufferView srcData, + GLuint srcOffset); //[Throws] //void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, diff --git a/tests/wpt/webgl/meta/conformance2/misc/views-with-offsets.html.ini b/tests/wpt/webgl/meta/conformance2/misc/views-with-offsets.html.ini index c107f8141da2..94ebca674d41 100644 --- a/tests/wpt/webgl/meta/conformance2/misc/views-with-offsets.html.ini +++ b/tests/wpt/webgl/meta/conformance2/misc/views-with-offsets.html.ini @@ -1,11 +1,8 @@ [views-with-offsets.html] expected: ERROR - [WebGL test #0: Does not support texImage2D with offsets into views.] + [WebGL test #47: successfullyParsed should be true (of type boolean). Was undefined (of type undefined).] expected: FAIL - [WebGL test #1: Does not support texSubImage2D with offsets into views.] - expected: FAIL - - [WebGL test #2: successfullyParsed should be true (of type boolean). Was undefined (of type undefined).] + [WebGL test #46: Does not support texSubImage2D with offsets into views.] expected: FAIL