From 1e2a72abfe0d5183a95c7edfa92e531dadd488b0 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Thu, 8 Nov 2018 22:28:58 +0100 Subject: [PATCH 01/11] Call prepare_pixels in tex_image_2d and tex_sub_image_2d --- .../script/dom/webglrenderingcontext.rs | 93 ++++++++++--------- 1 file changed, 48 insertions(+), 45 deletions(-) diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index a129a05fcfd32..a1bdcf7f31135 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -496,9 +496,8 @@ impl WebGLRenderingContext { rgba8[3] = 255u8; } - let pixels = self.prepare_pixels(format, data_type, width, height, 1, true, true, pixels); self.tex_image_2d( - texture, target, data_type, format, level, width, height, 0, 1, pixels, + texture, target, data_type, format, level, width, height, 0, 1, true, true, pixels, ); false @@ -771,9 +770,20 @@ impl WebGLRenderingContext { height: u32, _border: u32, unpacking_alignment: u32, + source_premultiplied: bool, + source_from_image_or_canvas: bool, pixels: Vec, ) { - // NB: pixels should NOT be premultipied + let pixels = self.prepare_pixels( + internal_format, + data_type, + width, + height, + unpacking_alignment, + source_premultiplied, + source_from_image_or_canvas, + pixels, + ); // TexImage2D depth is always equal to 1 handle_potential_webgl_error!( @@ -836,8 +846,21 @@ impl WebGLRenderingContext { format: TexFormat, data_type: TexDataType, unpacking_alignment: u32, + source_premultiplied: bool, + source_from_image_or_canvas: bool, pixels: Vec, ) { + let pixels = self.prepare_pixels( + format, + data_type, + width, + height, + unpacking_alignment, + source_premultiplied, + source_from_image_or_canvas, + pixels, + ); + // We have already validated level let image_info = texture.image_info_for_target(&target, level); @@ -3735,17 +3758,6 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { return Ok(()); // The validator sets the correct error for use } - let pixels = self.prepare_pixels( - format, - data_type, - width, - height, - unpacking_alignment, - false, - false, - buff, - ); - self.tex_image_2d( &texture, target, @@ -3756,7 +3768,9 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { height, border, unpacking_alignment, - pixels, + false, + false, + buff, ); Ok(()) @@ -3813,21 +3827,20 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { return Ok(()); // The validator sets the correct error for use } - let unpacking_alignment = 1; - let pixels = self.prepare_pixels( - format, + self.tex_image_2d( + &texture, + target, data_type, + format, + level, width, height, - unpacking_alignment, + border, + 1, premultiplied, true, pixels, ); - - self.tex_image_2d( - &texture, target, data_type, format, level, width, height, border, 1, pixels, - ); Ok(()) } @@ -3949,18 +3962,6 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { return Ok(self.webgl_error(InvalidOperation)); } - let unpacking_alignment = self.texture_unpacking_alignment.get(); - let pixels = self.prepare_pixels( - format, - data_type, - width, - height, - unpacking_alignment, - false, - false, - buff, - ); - self.tex_sub_image_2d( texture, target, @@ -3972,7 +3973,9 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { format, data_type, unpacking_alignment, - pixels, + false, + false, + buff, ); Ok(()) } @@ -4018,21 +4021,21 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { Err(_) => return Ok(()), // NB: The validator sets the correct error for us. }; - let unpacking_alignment = 1; - let pixels = self.prepare_pixels( - format, - data_type, + self.tex_sub_image_2d( + texture, + target, + level, + xoffset, + yoffset, width, height, - unpacking_alignment, + format, + data_type, + 1, premultiplied, true, pixels, ); - - self.tex_sub_image_2d( - texture, target, level, xoffset, yoffset, width, height, format, data_type, 1, pixels, - ); Ok(()) } From 86987ed75d94ddf8079dccf405073ee3a70bb1e6 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Fri, 9 Nov 2018 11:01:15 +0100 Subject: [PATCH 02/11] Introduce TexPixels --- .../script/dom/webglrenderingcontext.rs | 110 +++++++++++------- 1 file changed, 69 insertions(+), 41 deletions(-) diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index a1bdcf7f31135..346d8905082e6 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -429,8 +429,7 @@ impl WebGLRenderingContext { target, 0, info.internal_format().unwrap_or(TexFormat::RGBA), - info.width(), - info.height(), + Size2D::new(info.width(), info.height()), info.data_type().unwrap_or(TexDataType::UnsignedByte), ); } @@ -475,8 +474,7 @@ impl WebGLRenderingContext { target: TexImageTarget, level: u32, format: TexFormat, - width: u32, - height: u32, + size: Size2D, data_type: TexDataType, ) -> bool { if self @@ -490,14 +488,25 @@ impl WebGLRenderingContext { // Handle validation failed: LINEAR filtering not valid for this texture // WebGL Conformance tests expect to fallback to [0, 0, 0, 255] RGBA UNSIGNED_BYTE let data_type = TexDataType::UnsignedByte; - let expected_byte_length = width * height * 4; + let expected_byte_length = size.area() * 4; let mut pixels = vec![0u8; expected_byte_length as usize]; for rgba8 in pixels.chunks_mut(4) { rgba8[3] = 255u8; } self.tex_image_2d( - texture, target, data_type, format, level, width, height, 0, 1, true, true, pixels, + texture, + target, + data_type, + format, + level, + size.width, + size.height, + 0, + 1, + true, + true, + pixels, ); false @@ -517,13 +526,10 @@ impl WebGLRenderingContext { } } - fn get_image_pixels( - &self, - source: TexImageSource, - ) -> Fallible, Size2D, bool)>> { + fn get_image_pixels(&self, source: TexImageSource) -> Fallible> { Ok(Some(match source { TexImageSource::ImageData(image_data) => { - (image_data.to_vec(), image_data.get_size(), false) + TexPixels::new(image_data.to_vec(), image_data.get_size(), false) }, TexImageSource::HTMLImageElement(image) => { let document = document_from_node(&*self.canvas); @@ -555,7 +561,7 @@ impl WebGLRenderingContext { pixels::byte_swap_colors_inplace(&mut data); - (data, size, false) + TexPixels::new(data, size, false) }, // TODO(emilio): Getting canvas data is implemented in CanvasRenderingContext2D, // but we need to refactor it moving it to `HTMLCanvasElement` and support @@ -567,7 +573,7 @@ impl WebGLRenderingContext { if let Some((mut data, size)) = canvas.fetch_all_data() { // Pixels got from Canvas have already alpha premultiplied pixels::byte_swap_colors_inplace(&mut data); - (data, size, true) + TexPixels::new(data, size, true) } else { return Ok(None); } @@ -3752,10 +3758,12 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { return Ok(self.webgl_error(InvalidOperation)); } - if !self - .validate_filterable_texture(&texture, target, level, format, width, height, data_type) - { - return Ok(()); // The validator sets the correct error for use + let size = Size2D::new(width, height); + + if !self.validate_filterable_texture(&texture, target, level, format, size, data_type) { + // FIXME(nox): What is the spec for this? No error is emitted ever + // by validate_filterable_texture. + return Ok(()); } self.tex_image_2d( @@ -3790,8 +3798,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { return Ok(self.webgl_error(InvalidEnum)); } - let (pixels, size, premultiplied) = match self.get_image_pixels(source)? { - Some(triple) => triple, + let pixels = match self.get_image_pixels(source)? { + Some(pixels) => pixels, None => return Ok(()), }; @@ -3800,8 +3808,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { target, level, internal_format, - size.width as i32, - size.height as i32, + pixels.size.width as i32, + pixels.size.height as i32, 0, format, data_type, @@ -3810,21 +3818,27 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { let TexImage2DValidatorResult { texture, target, - width, - height, level, border, format, data_type, + .. } = match validator.validate() { Ok(result) => result, Err(_) => return Ok(()), // NB: The validator sets the correct error for us. }; - if !self - .validate_filterable_texture(&texture, target, level, format, width, height, data_type) - { - return Ok(()); // The validator sets the correct error for use + if !self.validate_filterable_texture( + &texture, + target, + level, + format, + pixels.size, + data_type, + ) { + // FIXME(nox): What is the spec for this? No error is emitted ever + // by validate_filterable_texture. + return Ok(()); } self.tex_image_2d( @@ -3833,13 +3847,13 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { data_type, format, level, - width, - height, + pixels.size.width, + pixels.size.height, border, 1, - premultiplied, + pixels.premultiplied, true, - pixels, + pixels.data, ); Ok(()) } @@ -3991,8 +4005,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { data_type: u32, source: TexImageSource, ) -> ErrorResult { - let (pixels, size, premultiplied) = match self.get_image_pixels(source)? { - Some(triple) => triple, + let pixels = match self.get_image_pixels(source)? { + Some(pixels) => pixels, None => return Ok(()), }; @@ -4001,8 +4015,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { target, level, format, - size.width as i32, - size.height as i32, + pixels.size.width as i32, + pixels.size.height as i32, 0, format, data_type, @@ -4010,8 +4024,6 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { let TexImage2DValidatorResult { texture, target, - width, - height, level, format, data_type, @@ -4027,14 +4039,14 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { level, xoffset, yoffset, - width, - height, + pixels.size.width, + pixels.size.height, format, data_type, 1, - premultiplied, + pixels.premultiplied, true, - pixels, + pixels.data, ); Ok(()) } @@ -4543,3 +4555,19 @@ fn rgba8_image_to_tex_image_data( _ => unreachable!("Unsupported formats {:?} {:?}", format, data_type), } } + +struct TexPixels { + data: Vec, + size: Size2D, + premultiplied: bool, +} + +impl TexPixels { + fn new(data: Vec, size: Size2D, premultiplied: bool) -> Self { + Self { + data, + size, + premultiplied, + } + } +} From adf363a2085f8af08a38046fae148131d0cbdd06 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Thu, 15 Nov 2018 10:01:19 +0100 Subject: [PATCH 03/11] Move prepare_pixels helper functions to canvas_traits --- Cargo.lock | 77 ++-- components/canvas_traits/Cargo.toml | 5 +- components/canvas_traits/lib.rs | 1 + components/canvas_traits/webgl.rs | 371 ++++++++++++++++++ components/script/Cargo.toml | 1 - components/script/dom/bindings/trace.rs | 12 +- .../dom/webgl_validations/tex_image_2d.rs | 4 +- .../script/dom/webgl_validations/types.rs | 111 +----- .../script/dom/webglrenderingcontext.rs | 366 ++--------------- components/script/dom/webgltexture.rs | 4 +- ports/libsimpleservo/Cargo.toml | 2 +- servo-tidy.toml | 3 + 12 files changed, 481 insertions(+), 476 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3e16573c28761..91e0a042afd9b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -332,11 +332,11 @@ dependencies = [ "cssparser 0.25.0 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "gleam 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "offscreen_gl_context 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)", + "offscreen_gl_context 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)", "pixels 0.0.1", "serde_bytes 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)", "servo_config 0.0.1", @@ -348,14 +348,17 @@ dependencies = [ name = "canvas_traits" version = "0.0.1" dependencies = [ + "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "cssparser 0.25.0 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gleam 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", + "half 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "malloc_size_of 0.0.1", "malloc_size_of_derive 0.0.1", - "offscreen_gl_context 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)", + "offscreen_gl_context 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)", + "pixels 0.0.1", "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", "serde_bytes 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)", "servo_config 0.0.1", @@ -399,7 +402,7 @@ name = "cgl" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gleam 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -509,7 +512,7 @@ dependencies = [ "embedder_traits 0.0.1", "euclid 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", "gfx_traits 0.0.1", - "gleam 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", "image 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)", "keyboard-types 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1275,12 +1278,22 @@ dependencies = [ "xml-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "gl_generator" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "khronos_api 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "xml-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "gleam" -version = "0.6.5" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gl_generator 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gl_generator 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1333,10 +1346,10 @@ dependencies = [ [[package]] name = "glx" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gl_generator 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gl_generator 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1798,7 +1811,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cgl 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "core-foundation 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "gleam 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", "leaky-cow 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1911,6 +1924,11 @@ name = "khronos_api" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "khronos_api" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "layout" version = "0.0.1" @@ -2094,7 +2112,7 @@ dependencies = [ "euclid 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", "gaol 0.0.1 (git+https://github.com/servo/gaol)", "gfx 0.0.1", - "gleam 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)", "layout_thread 0.0.1", "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2126,7 +2144,7 @@ dependencies = [ "android_injected_glue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "android_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", - "gl_generator 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gl_generator 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "jni 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "libservo 0.0.1", @@ -2691,14 +2709,14 @@ dependencies = [ [[package]] name = "offscreen_gl_context" -version = "0.21.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cgl 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "core-foundation 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gl_generator 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gleam 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "gl_generator 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3190,8 +3208,7 @@ dependencies = [ "enum-iterator 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "gleam 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "half 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", "headers-core 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "headers-ext 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "html5ever 0.22.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3217,7 +3234,7 @@ dependencies = [ "msg 0.0.1", "net_traits 0.0.1", "num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "offscreen_gl_context 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)", + "offscreen_gl_context 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "phf 0.7.23 (registry+https://github.com/rust-lang/crates.io-index)", "phf_codegen 0.7.23 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3408,7 +3425,7 @@ dependencies = [ "crossbeam-channel 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", "gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gleam 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", "glutin 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)", "keyboard-types 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3525,9 +3542,9 @@ dependencies = [ "cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", "expat-sys 2.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "gleam 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", "glutin 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)", - "glx 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "glx 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "io-surface 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "servo-egl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4493,7 +4510,7 @@ dependencies = [ "euclid 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", "freetype 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gleam 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", "image 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4707,6 +4724,11 @@ dependencies = [ "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "xml-rs" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "xml5ever" version = "0.12.0" @@ -4849,13 +4871,14 @@ dependencies = [ "checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" "checksum getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "b900c08c1939860ce8b54dc6a89e26e00c04c380fd0e09796799bd7f12861e05" "checksum gif 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff3414b424657317e708489d2857d9575f4403698428b040b609b9d1c1a84a2c" +"checksum gl_generator 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a0ffaf173cf76c73a73e080366bf556b4776ece104b06961766ff11449f38604" "checksum gl_generator 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a795170cbd85b5a7baa58d6d7525cae6a03e486859860c220f7ebbbdd379d0a" -"checksum gleam 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "962cbec852194e0f5f49ea0ca8407740cb14d760d8d86834b19b1f228cb505dd" +"checksum gleam 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bef810e31d619f5b77a7daea76a26ee50e63036637048a9f2128a33d5474141a" "checksum glib 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "740f7fda8dde5f5e3944dabdb4a73ac6094a8a7fdf0af377468e98ca93733e61" "checksum glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3573351e846caed9f11207b275cd67bc07f0c2c94fb628e5d7c92ca056c7882d" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" "checksum glutin 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0be84b852c1dcccde4b1329be778e5bd9c0801b8bbb8766ea327a3f813c6eafe" -"checksum glx 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "63a6e7c2846e12626455f45ebaff9d92161436dd0fa703d9d198012e528ca7b9" +"checksum glx 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "52ec1845f1defffd4e469ff2e3a38b2e042345a0f80a82e84ee508ba5f1e11d6" "checksum gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "08475e4a08f27e6e2287005950114735ed61cec2cb8c1187682a5aec8c69b715" "checksum gstreamer 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df451f98ea8b987b5fc1b647b9f038ca6ea106b08c3bccc1ef3126d4f0a687c1" "checksum gstreamer-app 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3f4f865cf7f22c66907372a2e3b0f0ced3d3fedab823641d6667d2568be71408" @@ -4906,6 +4929,7 @@ dependencies = [ "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum keyboard-types 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "823bf0e5ec01b80424a318e79a0d1375725281acf311c47543ab3413f704dc25" "checksum khronos_api 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9ef23fcc4059260c5936f638c9805ebfc87cb172fa6661d130cba7f97d58f55" +"checksum khronos_api 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "62237e6d326bd5871cd21469323bf096de81f1618cd82cbaf5d87825335aeb49" "checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d" "checksum lazycell 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d33a48d0365c96081958cc663eef834975cb1e8d8bea3378513fc72bdbf11e50" "checksum leak 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bd100e01f1154f2908dfa7d02219aeab25d0b9c7fa955164192e3245255a0c73" @@ -4957,7 +4981,7 @@ dependencies = [ "checksum objc 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5ffd1ab984e2a5ed8a222a6b567d38a69c1d04d64b19eb7c2b10794c6af9f76c" "checksum objc-foundation 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" "checksum objc_id 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e4730aa1c64d722db45f7ccc4113a3e2c465d018de6db4d3e7dfe031e8c8a297" -"checksum offscreen_gl_context 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)" = "95f2e39e3b8c95495cfec835b6fefee3f1e7d63c6f81d99796b4f9926c02db3c" +"checksum offscreen_gl_context 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5e86c90338962922a5f623128079b5c01d03784c8fd0809691f4eba233d69a1c" "checksum openssl 0.10.11 (registry+https://github.com/rust-lang/crates.io-index)" = "6c24d3508b4fb6da175c10baac54c578b33f09c89ae90c6fe9788b3b4768efdc" "checksum openssl-sys 0.9.35 (registry+https://github.com/rust-lang/crates.io-index)" = "912f301a749394e1025d9dcddef6106ddee9252620e6d0a0e5f8d0681de9b129" "checksum ordered-float 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e9a3c8db0fca1fdb34404f0b1286db252f23930b9f7a481e376c16c0d5c309d4" @@ -5120,5 +5144,6 @@ dependencies = [ "checksum xcb 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5e917a3f24142e9ff8be2414e36c649d47d6cc2ba81f16201cdef96e533e02de" "checksum xi-unicode 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "12ea8eda4b1eb72f02d148402e23832d56a33f55d8c1b2d5bcdde91d79d47cb1" "checksum xml-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c1cb601d29fe2c2ac60a2b2e5e293994d87a1f6fa9687a31a15270f909be9c2" +"checksum xml-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "541b12c998c5b56aa2b4e6f18f03664eef9a4fd0a246a55594efae6cc2d964b5" "checksum xml5ever 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ead952cf8bab253fb5cb56e1fff780747bbf7a7258fb0451afe645a166050b1f" "checksum zip 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "77ce0ceee93c995954a31f77903925a6a8bb094709445238e344f2107910e29e" diff --git a/components/canvas_traits/Cargo.toml b/components/canvas_traits/Cargo.toml index ae8eb8e4ec4cd..d24ba593a88ba 100644 --- a/components/canvas_traits/Cargo.toml +++ b/components/canvas_traits/Cargo.toml @@ -14,14 +14,17 @@ path = "lib.rs" webgl_backtrace = [] [dependencies] +byteorder = "1" cssparser = "0.25" euclid = "0.19" ipc-channel = "0.11" -gleam = "0.6" +gleam = "0.6.7" +half = "1" lazy_static = "1" malloc_size_of = { path = "../malloc_size_of" } malloc_size_of_derive = { path = "../malloc_size_of_derive" } offscreen_gl_context = {version = "0.21", features = ["serde"]} +pixels = {path = "../pixels"} serde = "1.0" serde_bytes = "0.10" servo_config = {path = "../config"} diff --git a/components/canvas_traits/lib.rs b/components/canvas_traits/lib.rs index 2e11d1704c661..666e9c9e5b55b 100644 --- a/components/canvas_traits/lib.rs +++ b/components/canvas_traits/lib.rs @@ -14,5 +14,6 @@ extern crate malloc_size_of_derive; extern crate serde; pub mod canvas; +#[macro_use] pub mod webgl; mod webgl_channel; diff --git a/components/canvas_traits/webgl.rs b/components/canvas_traits/webgl.rs index dce9c441e1ca0..a493a4a58cb70 100644 --- a/components/canvas_traits/webgl.rs +++ b/components/canvas_traits/webgl.rs @@ -2,10 +2,13 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use byteorder::{ByteOrder, NativeEndian, WriteBytesExt}; use euclid::{Rect, Size2D}; use gleam::gl; +use half::f16; use ipc_channel::ipc::{IpcBytesReceiver, IpcBytesSender}; use offscreen_gl_context::{GLContextAttributes, GLLimits}; +use pixels; use serde_bytes::ByteBuf; use std::borrow::Cow; use std::num::NonZeroU32; @@ -650,3 +653,371 @@ pub fn is_gles() -> bool { // making assumptions based on platform cfg!(any(target_os = "android", target_os = "ios")) } + +#[macro_export] +macro_rules! gl_enums { + ($(pub enum $name:ident { $($variant:ident = $mod:ident::$constant:ident,)+ })*) => { + $( + #[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq)] + #[repr(u32)] + pub enum $name { $($variant = $mod::$constant,)+ } + + impl $name { + pub fn from_gl_constant(constant: u32) -> Option { + Some(match constant { + $($mod::$constant => $name::$variant, )+ + _ => return None, + }) + } + + #[inline] + pub fn as_gl_constant(&self) -> u32 { + *self as u32 + } + } + )* + } +} + +gl_enums! { + pub enum TexFormat { + DepthComponent = gl::DEPTH_COMPONENT, + Alpha = gl::ALPHA, + RGB = gl::RGB, + RGBA = gl::RGBA, + Luminance = gl::LUMINANCE, + LuminanceAlpha = gl::LUMINANCE_ALPHA, + } + + pub enum TexDataType { + UnsignedByte = gl::UNSIGNED_BYTE, + UnsignedShort4444 = gl::UNSIGNED_SHORT_4_4_4_4, + UnsignedShort5551 = gl::UNSIGNED_SHORT_5_5_5_1, + UnsignedShort565 = gl::UNSIGNED_SHORT_5_6_5, + Float = gl::FLOAT, + HalfFloat = gl::HALF_FLOAT_OES, + } +} + +impl TexFormat { + /// Returns how many components does this format need. For example, RGBA + /// needs 4 components, while RGB requires 3. + pub fn components(&self) -> u32 { + match *self { + TexFormat::DepthComponent => 1, + TexFormat::Alpha => 1, + TexFormat::Luminance => 1, + TexFormat::LuminanceAlpha => 2, + TexFormat::RGB => 3, + TexFormat::RGBA => 4, + } + } +} + +impl TexDataType { + /// Returns the size in bytes of each element of data. + pub fn element_size(&self) -> u32 { + use self::*; + match *self { + TexDataType::UnsignedByte => 1, + TexDataType::UnsignedShort4444 | + TexDataType::UnsignedShort5551 | + TexDataType::UnsignedShort565 => 2, + TexDataType::Float => 4, + TexDataType::HalfFloat => 2, + } + } + + /// Returns how many components a single element may hold. For example, a + /// UnsignedShort4444 holds four components, each with 4 bits of data. + pub fn components_per_element(&self) -> u32 { + match *self { + TexDataType::UnsignedByte => 1, + TexDataType::UnsignedShort565 => 3, + TexDataType::UnsignedShort5551 => 4, + TexDataType::UnsignedShort4444 => 4, + TexDataType::Float => 1, + TexDataType::HalfFloat => 1, + } + } +} + +/// Translates an image in rgba8 (red in the first byte) format to +/// the format that was requested of TexImage. +pub fn rgba8_image_to_tex_image_data( + format: TexFormat, + data_type: TexDataType, + mut pixels: Vec, +) -> Vec { + // hint for vector allocation sizing. + let pixel_count = pixels.len() / 4; + + match (format, data_type) { + (TexFormat::RGBA, TexDataType::UnsignedByte) => pixels, + (TexFormat::RGB, TexDataType::UnsignedByte) => { + for i in 0..pixel_count { + let rgb = { + let rgb = &pixels[i * 4..i * 4 + 3]; + [rgb[0], rgb[1], rgb[2]] + }; + pixels[i * 3..i * 3 + 3].copy_from_slice(&rgb); + } + pixels.truncate(pixel_count * 3); + pixels + }, + (TexFormat::Alpha, TexDataType::UnsignedByte) => { + for i in 0..pixel_count { + let p = pixels[i * 4 + 3]; + pixels[i] = p; + } + pixels.truncate(pixel_count); + pixels + }, + (TexFormat::Luminance, TexDataType::UnsignedByte) => { + for i in 0..pixel_count { + let p = pixels[i * 4]; + pixels[i] = p; + } + pixels.truncate(pixel_count); + pixels + }, + (TexFormat::LuminanceAlpha, TexDataType::UnsignedByte) => { + for i in 0..pixel_count { + let (lum, a) = { + let rgba = &pixels[i * 4..i * 4 + 4]; + (rgba[0], rgba[3]) + }; + pixels[i * 2] = lum; + pixels[i * 2 + 1] = a; + } + pixels.truncate(pixel_count * 2); + pixels + }, + (TexFormat::RGBA, TexDataType::UnsignedShort4444) => { + for i in 0..pixel_count { + let p = { + let rgba = &pixels[i * 4..i * 4 + 4]; + (rgba[0] as u16 & 0xf0) << 8 | + (rgba[1] as u16 & 0xf0) << 4 | + (rgba[2] as u16 & 0xf0) | + (rgba[3] as u16 & 0xf0) >> 4 + }; + NativeEndian::write_u16(&mut pixels[i * 2..i * 2 + 2], p); + } + pixels.truncate(pixel_count * 2); + pixels + }, + (TexFormat::RGBA, TexDataType::UnsignedShort5551) => { + for i in 0..pixel_count { + let p = { + let rgba = &pixels[i * 4..i * 4 + 4]; + (rgba[0] as u16 & 0xf8) << 8 | + (rgba[1] as u16 & 0xf8) << 3 | + (rgba[2] as u16 & 0xf8) >> 2 | + (rgba[3] as u16) >> 7 + }; + NativeEndian::write_u16(&mut pixels[i * 2..i * 2 + 2], p); + } + pixels.truncate(pixel_count * 2); + pixels + }, + (TexFormat::RGB, TexDataType::UnsignedShort565) => { + for i in 0..pixel_count { + let p = { + let rgb = &pixels[i * 4..i * 4 + 3]; + (rgb[0] as u16 & 0xf8) << 8 | + (rgb[1] as u16 & 0xfc) << 3 | + (rgb[2] as u16 & 0xf8) >> 3 + }; + NativeEndian::write_u16(&mut pixels[i * 2..i * 2 + 2], p); + } + pixels.truncate(pixel_count * 2); + pixels + }, + (TexFormat::RGBA, TexDataType::Float) => { + let mut rgbaf32 = Vec::::with_capacity(pixel_count * 16); + for rgba8 in pixels.chunks(4) { + rgbaf32.write_f32::(rgba8[0] as f32).unwrap(); + rgbaf32.write_f32::(rgba8[1] as f32).unwrap(); + rgbaf32.write_f32::(rgba8[2] as f32).unwrap(); + rgbaf32.write_f32::(rgba8[3] as f32).unwrap(); + } + rgbaf32 + }, + + (TexFormat::RGB, TexDataType::Float) => { + let mut rgbf32 = Vec::::with_capacity(pixel_count * 12); + for rgba8 in pixels.chunks(4) { + rgbf32.write_f32::(rgba8[0] as f32).unwrap(); + rgbf32.write_f32::(rgba8[1] as f32).unwrap(); + rgbf32.write_f32::(rgba8[2] as f32).unwrap(); + } + rgbf32 + }, + + (TexFormat::Alpha, TexDataType::Float) => { + for rgba8 in pixels.chunks_mut(4) { + let p = rgba8[3] as f32; + NativeEndian::write_f32(rgba8, p); + } + pixels + }, + + (TexFormat::Luminance, TexDataType::Float) => { + for rgba8 in pixels.chunks_mut(4) { + let p = rgba8[0] as f32; + NativeEndian::write_f32(rgba8, p); + } + pixels + }, + + (TexFormat::LuminanceAlpha, TexDataType::Float) => { + let mut data = Vec::::with_capacity(pixel_count * 8); + for rgba8 in pixels.chunks(4) { + data.write_f32::(rgba8[0] as f32).unwrap(); + data.write_f32::(rgba8[3] as f32).unwrap(); + } + data + }, + + (TexFormat::RGBA, TexDataType::HalfFloat) => { + let mut rgbaf16 = Vec::::with_capacity(pixel_count * 8); + for rgba8 in pixels.chunks(4) { + rgbaf16 + .write_u16::(f16::from_f32(rgba8[0] as f32).as_bits()) + .unwrap(); + rgbaf16 + .write_u16::(f16::from_f32(rgba8[1] as f32).as_bits()) + .unwrap(); + rgbaf16 + .write_u16::(f16::from_f32(rgba8[2] as f32).as_bits()) + .unwrap(); + rgbaf16 + .write_u16::(f16::from_f32(rgba8[3] as f32).as_bits()) + .unwrap(); + } + rgbaf16 + }, + + (TexFormat::RGB, TexDataType::HalfFloat) => { + let mut rgbf16 = Vec::::with_capacity(pixel_count * 6); + for rgba8 in pixels.chunks(4) { + rgbf16 + .write_u16::(f16::from_f32(rgba8[0] as f32).as_bits()) + .unwrap(); + rgbf16 + .write_u16::(f16::from_f32(rgba8[1] as f32).as_bits()) + .unwrap(); + rgbf16 + .write_u16::(f16::from_f32(rgba8[2] as f32).as_bits()) + .unwrap(); + } + rgbf16 + }, + (TexFormat::Alpha, TexDataType::HalfFloat) => { + for i in 0..pixel_count { + let p = f16::from_f32(pixels[i * 4 + 3] as f32).as_bits(); + NativeEndian::write_u16(&mut pixels[i * 2..i * 2 + 2], p); + } + pixels.truncate(pixel_count * 2); + pixels + }, + (TexFormat::Luminance, TexDataType::HalfFloat) => { + for i in 0..pixel_count { + let p = f16::from_f32(pixels[i * 4] as f32).as_bits(); + NativeEndian::write_u16(&mut pixels[i * 2..i * 2 + 2], p); + } + pixels.truncate(pixel_count * 2); + pixels + }, + (TexFormat::LuminanceAlpha, TexDataType::HalfFloat) => { + for rgba8 in pixels.chunks_mut(4) { + let lum = f16::from_f32(rgba8[0] as f32).as_bits(); + let a = f16::from_f32(rgba8[3] as f32).as_bits(); + NativeEndian::write_u16(&mut rgba8[0..2], lum); + NativeEndian::write_u16(&mut rgba8[2..4], a); + } + pixels + }, + + // Validation should have ensured that we only hit the + // above cases, but we haven't turned the (format, type) + // into an enum yet so there's a default case here. + _ => unreachable!("Unsupported formats {:?} {:?}", format, data_type), + } +} + +pub fn premultiply_inplace(format: TexFormat, data_type: TexDataType, pixels: &mut [u8]) { + match (format, data_type) { + (TexFormat::RGBA, TexDataType::UnsignedByte) => { + pixels::premultiply_inplace(pixels); + }, + (TexFormat::LuminanceAlpha, TexDataType::UnsignedByte) => { + for la in pixels.chunks_mut(2) { + la[0] = pixels::multiply_u8_color(la[0], la[1]); + } + }, + (TexFormat::RGBA, TexDataType::UnsignedShort5551) => { + for rgba in pixels.chunks_mut(2) { + if NativeEndian::read_u16(rgba) & 1 == 0 { + NativeEndian::write_u16(rgba, 0); + } + } + }, + (TexFormat::RGBA, TexDataType::UnsignedShort4444) => { + for rgba in pixels.chunks_mut(2) { + let pix = NativeEndian::read_u16(rgba); + let extend_to_8_bits = |val| (val | val << 4) as u8; + let r = extend_to_8_bits(pix >> 12 & 0x0f); + let g = extend_to_8_bits(pix >> 8 & 0x0f); + let b = extend_to_8_bits(pix >> 4 & 0x0f); + let a = extend_to_8_bits(pix & 0x0f); + NativeEndian::write_u16( + rgba, + ((pixels::multiply_u8_color(r, a) & 0xf0) as u16) << 8 | + ((pixels::multiply_u8_color(g, a) & 0xf0) as u16) << 4 | + ((pixels::multiply_u8_color(b, a) & 0xf0) as u16) | + ((a & 0x0f) as u16), + ); + } + }, + // Other formats don't have alpha, so return their data untouched. + _ => {}, + } +} + +pub fn unmultiply_inplace(pixels: &mut [u8]) { + for rgba in pixels.chunks_mut(4) { + let a = (rgba[3] as f32) / 255.0; + rgba[0] = (rgba[0] as f32 / a) as u8; + rgba[1] = (rgba[1] as f32 / a) as u8; + rgba[2] = (rgba[2] as f32 / a) as u8; + } +} + +/// Flips the pixels in the Vec on the Y axis. +pub fn flip_pixels_y( + internal_format: TexFormat, + data_type: TexDataType, + width: usize, + height: usize, + unpacking_alignment: usize, + pixels: Vec, +) -> Vec { + let cpp = (data_type.element_size() * internal_format.components() / + data_type.components_per_element()) as usize; + + let stride = (width * cpp + unpacking_alignment - 1) & !(unpacking_alignment - 1); + + let mut flipped = Vec::::with_capacity(pixels.len()); + + for y in 0..height { + let flipped_y = height - 1 - y; + let start = flipped_y * stride; + + flipped.extend_from_slice(&pixels[start..(start + width * cpp)]); + flipped.extend(vec![0u8; stride - width * cpp]); + } + + flipped +} diff --git a/components/script/Cargo.toml b/components/script/Cargo.toml index a862caadc598a..572bf2fb11f72 100644 --- a/components/script/Cargo.toml +++ b/components/script/Cargo.toml @@ -53,7 +53,6 @@ enum-iterator = "0.2.0" euclid = "0.19" fnv = "1.0" gleam = "0.6" -half = "1.0" headers-core = "0.0.1" headers-ext = "0.0.3" html5ever = "0.22" diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index d8d3000d037b7..f3cc904e807ec 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -34,11 +34,11 @@ use canvas_traits::canvas::{ CanvasGradientStop, CanvasId, LinearGradientStyle, RadialGradientStyle, }; use canvas_traits::canvas::{CompositionOrBlending, LineCapStyle, LineJoinStyle, RepetitionStyle}; -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 canvas_traits::webgl::{ActiveAttribInfo, ActiveUniformInfo, TexDataType, TexFormat}; +use canvas_traits::webgl::{WebGLBufferId, WebGLChan, WebGLContextShareMode, WebGLError}; +use canvas_traits::webgl::{WebGLFramebufferId, WebGLMsgSender, WebGLPipeline, WebGLProgramId}; +use canvas_traits::webgl::{WebGLReceiver, WebGLRenderbufferId, WebGLSLVersion, WebGLSender}; +use canvas_traits::webgl::{WebGLShaderId, WebGLTextureId, WebGLVersion, WebGLVertexArrayId}; use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::error::Error; use crate::dom::bindings::refcounted::{Trusted, TrustedPromise}; @@ -148,6 +148,8 @@ unsafe_no_jsmanaged_fields!(Reflector); unsafe_no_jsmanaged_fields!(Duration); +unsafe_no_jsmanaged_fields!(TexDataType, TexFormat); + /// Trace a `JSVal`. pub fn trace_jsval(tracer: *mut JSTracer, description: &str, val: &Heap) { unsafe { diff --git a/components/script/dom/webgl_validations/tex_image_2d.rs b/components/script/dom/webgl_validations/tex_image_2d.rs index 125ff4918a892..09a96d37a1b51 100644 --- a/components/script/dom/webgl_validations/tex_image_2d.rs +++ b/components/script/dom/webgl_validations/tex_image_2d.rs @@ -2,9 +2,9 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use super::types::{TexDataType, TexFormat, TexImageTarget}; +use super::types::TexImageTarget; use super::WebGLValidator; -use canvas_traits::webgl::WebGLError::*; +use canvas_traits::webgl::{TexDataType, TexFormat, WebGLError::*}; use crate::dom::bindings::root::DomRoot; use crate::dom::webglrenderingcontext::WebGLRenderingContext; use crate::dom::webgltexture::WebGLTexture; diff --git a/components/script/dom/webgl_validations/types.rs b/components/script/dom/webgl_validations/types.rs index adcc51bf1ff80..5ff239ed898d4 100644 --- a/components/script/dom/webgl_validations/types.rs +++ b/components/script/dom/webgl_validations/types.rs @@ -2,47 +2,21 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use crate::dom::bindings::codegen::Bindings::OESTextureHalfFloatBinding::OESTextureHalfFloatConstants; -use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants; - -/// This macro creates type-safe wrappers for WebGL types, associating variants -/// with gl constants. -macro_rules! type_safe_wrapper { - ($name: ident, $($variant:ident => $mod:ident::$constant:ident, )+) => { - #[derive(Clone, Copy, Debug, Eq, Hash, JSTraceable, MallocSizeOf, PartialEq)] - #[repr(u32)] - pub enum $name { - $( - $variant = $mod::$constant, - )+ - } - - impl $name { - pub fn from_gl_constant(constant: u32) -> Option { - Some(match constant { - $($mod::$constant => $name::$variant, )+ - _ => return None, - }) - } - - #[inline] - pub fn as_gl_constant(&self) -> u32 { - *self as u32 - } - } +use canvas_traits::gl_enums; +use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants; + +gl_enums! { + pub enum TexImageTarget { + Texture2D = WebGLRenderingContextConstants::TEXTURE_2D, + CubeMapPositiveX = WebGLRenderingContextConstants::TEXTURE_CUBE_MAP_POSITIVE_X, + CubeMapNegativeX = WebGLRenderingContextConstants::TEXTURE_CUBE_MAP_NEGATIVE_X, + CubeMapPositiveY = WebGLRenderingContextConstants::TEXTURE_CUBE_MAP_POSITIVE_Y, + CubeMapNegativeY = WebGLRenderingContextConstants::TEXTURE_CUBE_MAP_NEGATIVE_Y, + CubeMapPositiveZ = WebGLRenderingContextConstants::TEXTURE_CUBE_MAP_POSITIVE_Z, + CubeMapNegativeZ = WebGLRenderingContextConstants::TEXTURE_CUBE_MAP_NEGATIVE_Z, } } -type_safe_wrapper! { TexImageTarget, - Texture2D => constants::TEXTURE_2D, - CubeMapPositiveX => constants::TEXTURE_CUBE_MAP_POSITIVE_X, - CubeMapNegativeX => constants::TEXTURE_CUBE_MAP_NEGATIVE_X, - CubeMapPositiveY => constants::TEXTURE_CUBE_MAP_POSITIVE_Y, - CubeMapNegativeY => constants::TEXTURE_CUBE_MAP_NEGATIVE_Y, - CubeMapPositiveZ => constants::TEXTURE_CUBE_MAP_POSITIVE_Z, - CubeMapNegativeZ => constants::TEXTURE_CUBE_MAP_NEGATIVE_Z, -} - impl TexImageTarget { pub fn is_cubic(&self) -> bool { match *self { @@ -51,64 +25,3 @@ impl TexImageTarget { } } } - -type_safe_wrapper! { TexDataType, - UnsignedByte => constants::UNSIGNED_BYTE, - UnsignedShort4444 => constants::UNSIGNED_SHORT_4_4_4_4, - UnsignedShort5551 => constants::UNSIGNED_SHORT_5_5_5_1, - UnsignedShort565 => constants::UNSIGNED_SHORT_5_6_5, - Float => constants::FLOAT, - HalfFloat => OESTextureHalfFloatConstants::HALF_FLOAT_OES, -} - -impl TexDataType { - /// Returns the size in bytes of each element of data. - pub fn element_size(&self) -> u32 { - use self::TexDataType::*; - match *self { - UnsignedByte => 1, - UnsignedShort4444 | UnsignedShort5551 | UnsignedShort565 => 2, - Float => 4, - HalfFloat => 2, - } - } - - /// Returns how many components a single element may hold. For example, a - /// UnsignedShort4444 holds four components, each with 4 bits of data. - pub fn components_per_element(&self) -> u32 { - use self::TexDataType::*; - match *self { - UnsignedByte => 1, - UnsignedShort565 => 3, - UnsignedShort5551 => 4, - UnsignedShort4444 => 4, - Float => 1, - HalfFloat => 1, - } - } -} - -type_safe_wrapper! { TexFormat, - DepthComponent => constants::DEPTH_COMPONENT, - Alpha => constants::ALPHA, - RGB => constants::RGB, - RGBA => constants::RGBA, - Luminance => constants::LUMINANCE, - LuminanceAlpha => constants::LUMINANCE_ALPHA, -} - -impl TexFormat { - /// Returns how many components does this format need. For example, RGBA - /// needs 4 components, while RGB requires 3. - pub fn components(&self) -> u32 { - use self::TexFormat::*; - match *self { - DepthComponent => 1, - Alpha => 1, - Luminance => 1, - LuminanceAlpha => 2, - RGB => 3, - RGBA => 4, - } - } -} diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index 346d8905082e6..b5b22f4f46425 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -4,13 +4,13 @@ #[cfg(feature = "webgl_backtrace")] use backtrace::Backtrace; -use byteorder::{ByteOrder, NativeEndian, WriteBytesExt}; use canvas_traits::webgl::WebGLError::*; -use canvas_traits::webgl::{webgl_channel, WebGLVersion, WebVRCommand}; -use canvas_traits::webgl::{DOMToTextureCommand, Parameter, WebGLCommandBacktrace}; -use canvas_traits::webgl::{TexParameter, WebGLCommand, WebGLContextShareMode, WebGLError}; -use canvas_traits::webgl::{WebGLFramebufferBindingRequest, WebGLMsg, WebGLMsgSender}; -use canvas_traits::webgl::{WebGLProgramId, WebGLResult, WebGLSLVersion, WebGLSender}; +use canvas_traits::webgl::{ + self, webgl_channel, DOMToTextureCommand, Parameter, TexDataType, TexFormat, TexParameter, + WebGLCommand, WebGLCommandBacktrace, WebGLContextShareMode, WebGLError, + WebGLFramebufferBindingRequest, WebGLMsg, WebGLMsgSender, WebGLProgramId, WebGLResult, + WebGLSLVersion, WebGLSender, WebGLVersion, WebVRCommand, +}; use crate::dom::bindings::codegen::Bindings::ANGLEInstancedArraysBinding::ANGLEInstancedArraysConstants; use crate::dom::bindings::codegen::Bindings::EXTBlendMinmaxBinding::EXTBlendMinmaxConstants; use crate::dom::bindings::codegen::Bindings::OESVertexArrayObjectBinding::OESVertexArrayObjectConstants; @@ -38,7 +38,7 @@ use crate::dom::webgl_validations::tex_image_2d::{ CommonTexImage2DValidator, CommonTexImage2DValidatorResult, }; use crate::dom::webgl_validations::tex_image_2d::{TexImage2DValidator, TexImage2DValidatorResult}; -use crate::dom::webgl_validations::types::{TexDataType, TexFormat, TexImageTarget}; +use crate::dom::webgl_validations::types::TexImageTarget; use crate::dom::webgl_validations::WebGLValidator; use crate::dom::webglactiveinfo::WebGLActiveInfo; use crate::dom::webglbuffer::WebGLBuffer; @@ -57,7 +57,6 @@ use crate::dom::webglvertexarrayobjectoes::WebGLVertexArrayObjectOES; use crate::dom::window::Window; use dom_struct::dom_struct; use euclid::{Point2D, Rect, Size2D}; -use half::f16; use ipc_channel::ipc; use js::jsapi::{JSContext, JSObject, Type}; use js::jsval::{BooleanValue, DoubleValue, Int32Value, JSVal, UInt32Value}; @@ -70,6 +69,7 @@ use js::typedarray::{TypedArray, TypedArrayElementCreator}; use net_traits::image::base::PixelFormat; use net_traits::image_cache::ImageResponse; use offscreen_gl_context::{GLContextAttributes, GLLimits}; +use pixels; use script_layout_interface::HTMLCanvasDataSource; use serde::{Deserialize, Serialize}; use servo_config::prefs::PREFS; @@ -638,92 +638,6 @@ impl WebGLRenderingContext { } } - /// Flips the pixels in the Vec on the Y axis if - /// UNPACK_FLIP_Y_WEBGL is currently enabled. - fn flip_teximage_y( - &self, - pixels: Vec, - internal_format: TexFormat, - data_type: TexDataType, - width: usize, - height: usize, - unpacking_alignment: usize, - ) -> Vec { - if !self - .texture_unpacking_settings - .get() - .contains(TextureUnpacking::FLIP_Y_AXIS) - { - return pixels; - } - - let cpp = (data_type.element_size() * internal_format.components() / - data_type.components_per_element()) as usize; - - let stride = (width * cpp + unpacking_alignment - 1) & !(unpacking_alignment - 1); - - let mut flipped = Vec::::with_capacity(pixels.len()); - - for y in 0..height { - let flipped_y = height - 1 - y; - let start = flipped_y * stride; - - flipped.extend_from_slice(&pixels[start..(start + width * cpp)]); - flipped.extend(vec![0u8; stride - width * cpp]); - } - - flipped - } - - /// Performs premultiplication of the pixels if - /// UNPACK_PREMULTIPLY_ALPHA_WEBGL is currently enabled. - fn premultiply_pixels(&self, format: TexFormat, data_type: TexDataType, pixels: &mut [u8]) { - if !self - .texture_unpacking_settings - .get() - .contains(TextureUnpacking::PREMULTIPLY_ALPHA) - { - return; - } - - match (format, data_type) { - (TexFormat::RGBA, TexDataType::UnsignedByte) => { - pixels::premultiply_inplace(pixels); - }, - (TexFormat::LuminanceAlpha, TexDataType::UnsignedByte) => { - for la in pixels.chunks_mut(2) { - la[0] = pixels::multiply_u8_color(la[0], la[1]); - } - }, - (TexFormat::RGBA, TexDataType::UnsignedShort5551) => { - for rgba in pixels.chunks_mut(2) { - if NativeEndian::read_u16(rgba) & 1 == 0 { - NativeEndian::write_u16(rgba, 0); - } - } - }, - (TexFormat::RGBA, TexDataType::UnsignedShort4444) => { - for rgba in pixels.chunks_mut(2) { - let pix = NativeEndian::read_u16(rgba); - let extend_to_8_bits = |val| (val | val << 4) as u8; - let r = extend_to_8_bits(pix >> 12 & 0x0f); - let g = extend_to_8_bits(pix >> 8 & 0x0f); - let b = extend_to_8_bits(pix >> 4 & 0x0f); - let a = extend_to_8_bits(pix & 0x0f); - NativeEndian::write_u16( - rgba, - ((pixels::multiply_u8_color(r, a) & 0xf0) as u16) << 8 | - ((pixels::multiply_u8_color(g, a) & 0xf0) as u16) << 4 | - ((pixels::multiply_u8_color(b, a) & 0xf0) as u16) | - ((a & 0x0f) as u16), - ); - } - }, - // Other formats don't have alpha, so return their data untouched. - _ => {}, - } - } - fn prepare_pixels( &self, internal_format: TexFormat, @@ -735,34 +649,36 @@ impl WebGLRenderingContext { source_from_image_or_canvas: bool, mut pixels: Vec, ) -> Vec { - let dest_premultiply = self - .texture_unpacking_settings - .get() - .contains(TextureUnpacking::PREMULTIPLY_ALPHA); + let settings = self.texture_unpacking_settings.get(); + let dest_premultiply = settings.contains(TextureUnpacking::PREMULTIPLY_ALPHA); if !source_premultiplied && dest_premultiply { if source_from_image_or_canvas { // When the pixels come from image or canvas or imagedata, use RGBA8 format - self.premultiply_pixels(TexFormat::RGBA, TexDataType::UnsignedByte, &mut pixels); + webgl::premultiply_inplace(TexFormat::RGBA, TexDataType::UnsignedByte, &mut pixels); } else { - self.premultiply_pixels(internal_format, data_type, &mut pixels); + webgl::premultiply_inplace(internal_format, data_type, &mut pixels); } } else if source_premultiplied && !dest_premultiply { - remove_premultiplied_alpha(&mut pixels); + webgl::unmultiply_inplace(&mut pixels); } if source_from_image_or_canvas { - pixels = rgba8_image_to_tex_image_data(internal_format, data_type, pixels); + pixels = webgl::rgba8_image_to_tex_image_data(internal_format, data_type, pixels); } - // FINISHME: Consider doing premultiply and flip in a single mutable Vec. - self.flip_teximage_y( - pixels, - internal_format, - data_type, - width as usize, - height as usize, - unpacking_alignment as usize, - ) + if settings.contains(TextureUnpacking::FLIP_Y_AXIS) { + // FINISHME: Consider doing premultiply and flip in a single mutable Vec. + pixels = webgl::flip_pixels_y( + internal_format, + data_type, + width as usize, + height as usize, + unpacking_alignment as usize, + pixels, + ); + } + + pixels } fn tex_image_2d( @@ -4328,234 +4244,6 @@ impl TextureUnit { } } -// Remove premultiplied alpha. -// This is only called when texImage2D is called using a canvas2d source and -// UNPACK_PREMULTIPLY_ALPHA_WEBGL is disabled. Pixels got from a canvas2D source -// are always RGBA8 with premultiplied alpha, so we don't have to worry about -// additional formats as happens in the premultiply_pixels method. -fn remove_premultiplied_alpha(pixels: &mut [u8]) { - for rgba in pixels.chunks_mut(4) { - let a = (rgba[3] as f32) / 255.0; - rgba[0] = (rgba[0] as f32 / a) as u8; - rgba[1] = (rgba[1] as f32 / a) as u8; - rgba[2] = (rgba[2] as f32 / a) as u8; - } -} - -/// Translates an image in rgba8 (red in the first byte) format to -/// the format that was requested of TexImage. -/// -/// From the WebGL 1.0 spec, 5.14.8: -/// -/// "The source image data is conceptually first converted to -/// the data type and format specified by the format and type -/// arguments, and then transferred to the WebGL -/// implementation. If a packed pixel format is specified -/// which would imply loss of bits of precision from the image -/// data, this loss of precision must occur." -fn rgba8_image_to_tex_image_data( - format: TexFormat, - data_type: TexDataType, - mut pixels: Vec, -) -> Vec { - // hint for vector allocation sizing. - let pixel_count = pixels.len() / 4; - - match (format, data_type) { - (TexFormat::RGBA, TexDataType::UnsignedByte) => pixels, - (TexFormat::RGB, TexDataType::UnsignedByte) => { - for i in 0..pixel_count { - let rgb = { - let rgb = &pixels[i * 4..i * 4 + 3]; - [rgb[0], rgb[1], rgb[2]] - }; - pixels[i * 3..i * 3 + 3].copy_from_slice(&rgb); - } - pixels.truncate(pixel_count * 3); - pixels - }, - (TexFormat::Alpha, TexDataType::UnsignedByte) => { - for i in 0..pixel_count { - let p = pixels[i * 4 + 3]; - pixels[i] = p; - } - pixels.truncate(pixel_count); - pixels - }, - (TexFormat::Luminance, TexDataType::UnsignedByte) => { - for i in 0..pixel_count { - let p = pixels[i * 4]; - pixels[i] = p; - } - pixels.truncate(pixel_count); - pixels - }, - (TexFormat::LuminanceAlpha, TexDataType::UnsignedByte) => { - for i in 0..pixel_count { - let (lum, a) = { - let rgba = &pixels[i * 4..i * 4 + 4]; - (rgba[0], rgba[3]) - }; - pixels[i * 2] = lum; - pixels[i * 2 + 1] = a; - } - pixels.truncate(pixel_count * 2); - pixels - }, - (TexFormat::RGBA, TexDataType::UnsignedShort4444) => { - for i in 0..pixel_count { - let p = { - let rgba = &pixels[i * 4..i * 4 + 4]; - (rgba[0] as u16 & 0xf0) << 8 | - (rgba[1] as u16 & 0xf0) << 4 | - (rgba[2] as u16 & 0xf0) | - (rgba[3] as u16 & 0xf0) >> 4 - }; - NativeEndian::write_u16(&mut pixels[i * 2..i * 2 + 2], p); - } - pixels.truncate(pixel_count * 2); - pixels - }, - (TexFormat::RGBA, TexDataType::UnsignedShort5551) => { - for i in 0..pixel_count { - let p = { - let rgba = &pixels[i * 4..i * 4 + 4]; - (rgba[0] as u16 & 0xf8) << 8 | - (rgba[1] as u16 & 0xf8) << 3 | - (rgba[2] as u16 & 0xf8) >> 2 | - (rgba[3] as u16) >> 7 - }; - NativeEndian::write_u16(&mut pixels[i * 2..i * 2 + 2], p); - } - pixels.truncate(pixel_count * 2); - pixels - }, - (TexFormat::RGB, TexDataType::UnsignedShort565) => { - for i in 0..pixel_count { - let p = { - let rgb = &pixels[i * 4..i * 4 + 3]; - (rgb[0] as u16 & 0xf8) << 8 | - (rgb[1] as u16 & 0xfc) << 3 | - (rgb[2] as u16 & 0xf8) >> 3 - }; - NativeEndian::write_u16(&mut pixels[i * 2..i * 2 + 2], p); - } - pixels.truncate(pixel_count * 2); - pixels - }, - (TexFormat::RGBA, TexDataType::Float) => { - let mut rgbaf32 = Vec::::with_capacity(pixel_count * 16); - for rgba8 in pixels.chunks(4) { - rgbaf32.write_f32::(rgba8[0] as f32).unwrap(); - rgbaf32.write_f32::(rgba8[1] as f32).unwrap(); - rgbaf32.write_f32::(rgba8[2] as f32).unwrap(); - rgbaf32.write_f32::(rgba8[3] as f32).unwrap(); - } - rgbaf32 - }, - - (TexFormat::RGB, TexDataType::Float) => { - let mut rgbf32 = Vec::::with_capacity(pixel_count * 12); - for rgba8 in pixels.chunks(4) { - rgbf32.write_f32::(rgba8[0] as f32).unwrap(); - rgbf32.write_f32::(rgba8[1] as f32).unwrap(); - rgbf32.write_f32::(rgba8[2] as f32).unwrap(); - } - rgbf32 - }, - - (TexFormat::Alpha, TexDataType::Float) => { - for rgba8 in pixels.chunks_mut(4) { - let p = rgba8[3] as f32; - NativeEndian::write_f32(rgba8, p); - } - pixels - }, - - (TexFormat::Luminance, TexDataType::Float) => { - for rgba8 in pixels.chunks_mut(4) { - let p = rgba8[0] as f32; - NativeEndian::write_f32(rgba8, p); - } - pixels - }, - - (TexFormat::LuminanceAlpha, TexDataType::Float) => { - let mut data = Vec::::with_capacity(pixel_count * 8); - for rgba8 in pixels.chunks(4) { - data.write_f32::(rgba8[0] as f32).unwrap(); - data.write_f32::(rgba8[3] as f32).unwrap(); - } - data - }, - - (TexFormat::RGBA, TexDataType::HalfFloat) => { - let mut rgbaf16 = Vec::::with_capacity(pixel_count * 8); - for rgba8 in pixels.chunks(4) { - rgbaf16 - .write_u16::(f16::from_f32(rgba8[0] as f32).as_bits()) - .unwrap(); - rgbaf16 - .write_u16::(f16::from_f32(rgba8[1] as f32).as_bits()) - .unwrap(); - rgbaf16 - .write_u16::(f16::from_f32(rgba8[2] as f32).as_bits()) - .unwrap(); - rgbaf16 - .write_u16::(f16::from_f32(rgba8[3] as f32).as_bits()) - .unwrap(); - } - rgbaf16 - }, - - (TexFormat::RGB, TexDataType::HalfFloat) => { - let mut rgbf16 = Vec::::with_capacity(pixel_count * 6); - for rgba8 in pixels.chunks(4) { - rgbf16 - .write_u16::(f16::from_f32(rgba8[0] as f32).as_bits()) - .unwrap(); - rgbf16 - .write_u16::(f16::from_f32(rgba8[1] as f32).as_bits()) - .unwrap(); - rgbf16 - .write_u16::(f16::from_f32(rgba8[2] as f32).as_bits()) - .unwrap(); - } - rgbf16 - }, - (TexFormat::Alpha, TexDataType::HalfFloat) => { - for i in 0..pixel_count { - let p = f16::from_f32(pixels[i * 4 + 3] as f32).as_bits(); - NativeEndian::write_u16(&mut pixels[i * 2..i * 2 + 2], p); - } - pixels.truncate(pixel_count * 2); - pixels - }, - (TexFormat::Luminance, TexDataType::HalfFloat) => { - for i in 0..pixel_count { - let p = f16::from_f32(pixels[i * 4] as f32).as_bits(); - NativeEndian::write_u16(&mut pixels[i * 2..i * 2 + 2], p); - } - pixels.truncate(pixel_count * 2); - pixels - }, - (TexFormat::LuminanceAlpha, TexDataType::HalfFloat) => { - for rgba8 in pixels.chunks_mut(4) { - let lum = f16::from_f32(rgba8[0] as f32).as_bits(); - let a = f16::from_f32(rgba8[3] as f32).as_bits(); - NativeEndian::write_u16(&mut rgba8[0..2], lum); - NativeEndian::write_u16(&mut rgba8[2..4], a); - } - pixels - }, - - // Validation should have ensured that we only hit the - // above cases, but we haven't turned the (format, type) - // into an enum yet so there's a default case here. - _ => unreachable!("Unsupported formats {:?} {:?}", format, data_type), - } -} - struct TexPixels { data: Vec, size: Size2D, diff --git a/components/script/dom/webgltexture.rs b/components/script/dom/webgltexture.rs index 2cc42a91f4209..c17747a779a2d 100644 --- a/components/script/dom/webgltexture.rs +++ b/components/script/dom/webgltexture.rs @@ -4,7 +4,7 @@ // https://www.khronos.org/registry/webgl/specs/latest/1.0/webgl.idl -use canvas_traits::webgl::{webgl_channel, WebGLResult, WebGLTextureId}; +use canvas_traits::webgl::{webgl_channel, TexDataType, TexFormat, WebGLResult, WebGLTextureId}; use canvas_traits::webgl::{DOMToTextureCommand, WebGLCommand, WebGLError}; use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::codegen::Bindings::EXTTextureFilterAnisotropicBinding::EXTTextureFilterAnisotropicConstants; @@ -13,7 +13,7 @@ use crate::dom::bindings::codegen::Bindings::WebGLTextureBinding; use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject}; use crate::dom::bindings::root::DomRoot; -use crate::dom::webgl_validations::types::{TexDataType, TexFormat, TexImageTarget}; +use crate::dom::webgl_validations::types::TexImageTarget; use crate::dom::webglobject::WebGLObject; use crate::dom::webglrenderingcontext::WebGLRenderingContext; use dom_struct::dom_struct; diff --git a/ports/libsimpleservo/Cargo.toml b/ports/libsimpleservo/Cargo.toml index a2f6805adf1bd..834ee59c439e1 100644 --- a/ports/libsimpleservo/Cargo.toml +++ b/ports/libsimpleservo/Cargo.toml @@ -30,7 +30,7 @@ libc = "0.2" winapi = "0.3.2" [build-dependencies] -gl_generator = "0.9" +gl_generator = "0.10" cc = "1.0" [features] diff --git a/servo-tidy.toml b/servo-tidy.toml index 6adf31af23bd3..64ee72f2c8f88 100644 --- a/servo-tidy.toml +++ b/servo-tidy.toml @@ -36,6 +36,8 @@ packages = [ "crossbeam-deque", "crossbeam-epoch", "crossbeam-utils", + "gl_generator", + "khronos_api", "log", # TODO: remove num-rational when https://github.com/PistonDevelopers/image/pull/809 is merged. "num-rational", @@ -45,6 +47,7 @@ packages = [ "syn", "unicase", "winapi", + "xml-rs", ] # Files that are ignored for all tidy and lint checks. files = [ From a5779ad372b2b3c1c236c94680d01c60a99f19a4 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Thu, 15 Nov 2018 10:04:52 +0100 Subject: [PATCH 04/11] Prefix some pixels functions with rgba8_ --- components/canvas/canvas_data.rs | 6 +++--- components/canvas/webgl_thread.rs | 2 +- components/canvas_traits/webgl.rs | 2 +- components/net/image_cache.rs | 2 +- components/net_traits/image/base.rs | 2 +- components/pixels/lib.rs | 8 ++++---- components/script/dom/canvasrenderingcontext2d.rs | 2 +- components/script/dom/imagedata.rs | 2 +- components/script/dom/webglrenderingcontext.rs | 4 ++-- 9 files changed, 15 insertions(+), 15 deletions(-) diff --git a/components/canvas/canvas_data.rs b/components/canvas/canvas_data.rs index d07ee2cd9cf53..1c2e5d091184c 100644 --- a/components/canvas/canvas_data.rs +++ b/components/canvas/canvas_data.rs @@ -69,7 +69,7 @@ impl<'a> CanvasData<'a> { let source_rect = source_rect.ceil(); // It discards the extra pixels (if any) that won't be painted let image_data = if Rect::from_size(image_size).contains_rect(&source_rect) { - pixels::get_rect(&image_data, image_size.to_u32(), source_rect.to_u32()).into() + pixels::rgba8_get_rect(&image_data, image_size.to_u32(), source_rect.to_u32()).into() } else { image_data.into() }; @@ -510,7 +510,7 @@ impl<'a> CanvasData<'a> { pub fn put_image_data(&mut self, mut imagedata: Vec, rect: Rect) { assert_eq!(imagedata.len() % 4, 0); assert_eq!(rect.size.area() as usize, imagedata.len() / 4); - pixels::byte_swap_and_premultiply_inplace(&mut imagedata); + pixels::rgba8_byte_swap_and_premultiply_inplace(&mut imagedata); let source_surface = self .drawtarget .create_source_surface_from_data( @@ -602,7 +602,7 @@ impl<'a> CanvasData<'a> { return vec![]; } let data_surface = self.drawtarget.snapshot().get_data_surface(); - pixels::get_rect( + pixels::rgba8_get_rect( unsafe { data_surface.data() }, canvas_size.to_u32(), read_rect.to_u32(), diff --git a/components/canvas/webgl_thread.rs b/components/canvas/webgl_thread.rs index dec2ad332631c..67ac2f497891f 100644 --- a/components/canvas/webgl_thread.rs +++ b/components/canvas/webgl_thread.rs @@ -635,7 +635,7 @@ impl WebGLThread { let src_slice = &orig_pixels[src_start..src_start + stride]; (&mut pixels[dst_start..dst_start + stride]).clone_from_slice(&src_slice[..stride]); } - pixels::byte_swap_colors_inplace(&mut pixels); + pixels::rgba8_byte_swap_colors_inplace(&mut pixels); pixels } diff --git a/components/canvas_traits/webgl.rs b/components/canvas_traits/webgl.rs index a493a4a58cb70..29236615b7987 100644 --- a/components/canvas_traits/webgl.rs +++ b/components/canvas_traits/webgl.rs @@ -950,7 +950,7 @@ pub fn rgba8_image_to_tex_image_data( pub fn premultiply_inplace(format: TexFormat, data_type: TexDataType, pixels: &mut [u8]) { match (format, data_type) { (TexFormat::RGBA, TexDataType::UnsignedByte) => { - pixels::premultiply_inplace(pixels); + pixels::rgba8_premultiply_inplace(pixels); }, (TexFormat::LuminanceAlpha, TexDataType::UnsignedByte) => { for la in pixels.chunks_mut(2) { diff --git a/components/net/image_cache.rs b/components/net/image_cache.rs index cf95d3fc1fdfd..5686b154831fa 100644 --- a/components/net/image_cache.rs +++ b/components/net/image_cache.rs @@ -56,7 +56,7 @@ fn set_webrender_image_key(webrender_api: &webrender_api::RenderApi, image: &mut let is_opaque = match image.format { PixelFormat::BGRA8 => { bytes.extend_from_slice(&*image.bytes); - pixels::premultiply_inplace(bytes.as_mut_slice()) + pixels::rgba8_premultiply_inplace(bytes.as_mut_slice()) }, PixelFormat::RGB8 => { for bgr in image.bytes.chunks(3) { diff --git a/components/net_traits/image/base.rs b/components/net_traits/image/base.rs index 6e67e5b7cd1dd..0517508416289 100644 --- a/components/net_traits/image/base.rs +++ b/components/net_traits/image/base.rs @@ -65,7 +65,7 @@ pub fn load_from_memory(buffer: &[u8]) -> Option { DynamicImage::ImageRgba8(rgba) => rgba, image => image.to_rgba(), }; - pixels::byte_swap_colors_inplace(&mut *rgba); + pixels::rgba8_byte_swap_colors_inplace(&mut *rgba); Some(Image { width: rgba.width(), height: rgba.height(), diff --git a/components/pixels/lib.rs b/components/pixels/lib.rs index 16c93b7b6afbb..de9a3cb3aa8b4 100644 --- a/components/pixels/lib.rs +++ b/components/pixels/lib.rs @@ -5,7 +5,7 @@ use euclid::{Point2D, Rect, Size2D}; use std::borrow::Cow; -pub fn get_rect(pixels: &[u8], size: Size2D, rect: Rect) -> Cow<[u8]> { +pub fn rgba8_get_rect(pixels: &[u8], size: Size2D, rect: Rect) -> Cow<[u8]> { assert!(!rect.is_empty()); assert!(Rect::from_size(size).contains_rect(&rect)); assert_eq!(pixels.len() % 4, 0); @@ -29,7 +29,7 @@ pub fn get_rect(pixels: &[u8], size: Size2D, rect: Rect) -> Cow<[u8]> } // TODO(pcwalton): Speed up with SIMD, or better yet, find some way to not do this. -pub fn byte_swap_colors_inplace(pixels: &mut [u8]) { +pub fn rgba8_byte_swap_colors_inplace(pixels: &mut [u8]) { assert!(pixels.len() % 4 == 0); for rgba in pixels.chunks_mut(4) { let b = rgba[0]; @@ -38,7 +38,7 @@ pub fn byte_swap_colors_inplace(pixels: &mut [u8]) { } } -pub fn byte_swap_and_premultiply_inplace(pixels: &mut [u8]) { +pub fn rgba8_byte_swap_and_premultiply_inplace(pixels: &mut [u8]) { assert!(pixels.len() % 4 == 0); for rgba in pixels.chunks_mut(4) { let b = rgba[0]; @@ -49,7 +49,7 @@ pub fn byte_swap_and_premultiply_inplace(pixels: &mut [u8]) { } /// Returns true if the pixels were found to be completely opaque. -pub fn premultiply_inplace(pixels: &mut [u8]) -> bool { +pub fn rgba8_premultiply_inplace(pixels: &mut [u8]) -> bool { assert!(pixels.len() % 4 == 0); let mut is_opaque = true; for rgba in pixels.chunks_mut(4) { diff --git a/components/script/dom/canvasrenderingcontext2d.rs b/components/script/dom/canvasrenderingcontext2d.rs index 3a031095dc8af..18d6c978caef2 100644 --- a/components/script/dom/canvasrenderingcontext2d.rs +++ b/components/script/dom/canvasrenderingcontext2d.rs @@ -403,7 +403,7 @@ impl CanvasRenderingContext2D { ) -> ErrorResult { debug!("Fetching image {}.", url); let (mut image_data, image_size) = self.fetch_image_data(url).ok_or(Error::InvalidState)?; - pixels::premultiply_inplace(&mut image_data); + pixels::rgba8_premultiply_inplace(&mut image_data); let image_size = image_size.to_f64(); let dw = dw.unwrap_or(image_size.width); diff --git a/components/script/dom/imagedata.rs b/components/script/dom/imagedata.rs index 84280ec0724b6..714c66bf747bb 100644 --- a/components/script/dom/imagedata.rs +++ b/components/script/dom/imagedata.rs @@ -162,7 +162,7 @@ impl ImageData { #[allow(unsafe_code)] pub unsafe fn get_rect(&self, rect: Rect) -> Cow<[u8]> { - pixels::get_rect(self.as_slice(), self.get_size(), rect) + pixels::rgba8_get_rect(self.as_slice(), self.get_size(), rect) } pub fn get_size(&self) -> Size2D { diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index b5b22f4f46425..97e35b058e880 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -559,7 +559,7 @@ impl WebGLRenderingContext { _ => unimplemented!(), }; - pixels::byte_swap_colors_inplace(&mut data); + pixels::rgba8_byte_swap_colors_inplace(&mut data); TexPixels::new(data, size, false) }, @@ -572,7 +572,7 @@ impl WebGLRenderingContext { } if let Some((mut data, size)) = canvas.fetch_all_data() { // Pixels got from Canvas have already alpha premultiplied - pixels::byte_swap_colors_inplace(&mut data); + pixels::rgba8_byte_swap_colors_inplace(&mut data); TexPixels::new(data, size, true) } else { return Ok(None); From da43e35ab290c639c8952809338fe19ea824123e Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Thu, 15 Nov 2018 10:05:40 +0100 Subject: [PATCH 05/11] Optimise memory allocation in set_webrender_image_key --- components/net/image_cache.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/components/net/image_cache.rs b/components/net/image_cache.rs index 5686b154831fa..22d6faccae697 100644 --- a/components/net/image_cache.rs +++ b/components/net/image_cache.rs @@ -59,6 +59,7 @@ fn set_webrender_image_key(webrender_api: &webrender_api::RenderApi, image: &mut pixels::rgba8_premultiply_inplace(bytes.as_mut_slice()) }, PixelFormat::RGB8 => { + bytes.reserve(image.bytes.len() / 3 * 4); for bgr in image.bytes.chunks(3) { bytes.extend_from_slice(&[bgr[2], bgr[1], bgr[0], 0xff]); } From 65d1b11929f73075492a3a66da9f3710be14ac55 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Thu, 15 Nov 2018 10:32:20 +0100 Subject: [PATCH 06/11] Make TexImage2D and TexSubImage2D struct variants --- components/canvas/webgl_thread.rs | 62 ++++++++++--------- components/canvas_traits/webgl.rs | 23 ++++++- .../script/dom/webglrenderingcontext.rs | 32 +++++----- 3 files changed, 70 insertions(+), 47 deletions(-) diff --git a/components/canvas/webgl_thread.rs b/components/canvas/webgl_thread.rs index 67ac2f497891f..c1839e19e3226 100644 --- a/components/canvas/webgl_thread.rs +++ b/components/canvas/webgl_thread.rs @@ -1042,47 +1042,51 @@ impl WebGLImpl { WebGLCommand::SetViewport(x, y, width, height) => { ctx.gl().viewport(x, y, width, height); }, - WebGLCommand::TexImage2D( + WebGLCommand::TexImage2D { target, level, - internal, - width, - height, - format, - data_type, - ref chan, - ) => ctx.gl().tex_image_2d( - target, - level, - internal, + internal_format, width, height, - 0, format, data_type, - Some(&chan.recv().unwrap()), - ), - WebGLCommand::TexSubImage2D( - target, - level, - xoffset, - yoffset, - x, - y, - width, - height, - ref chan, - ) => ctx.gl().tex_sub_image_2d( + ref receiver, + } => { + ctx.gl().tex_image_2d( + target, + level as i32, + internal_format as i32, + width as i32, + height as i32, + 0, + format, + data_type, + Some(&receiver.recv().unwrap()), + ); + }, + WebGLCommand::TexSubImage2D { target, level, xoffset, yoffset, - x, - y, width, height, - &chan.recv().unwrap(), - ), + format, + data_type, + ref receiver, + } => { + ctx.gl().tex_sub_image_2d( + target, + level as i32, + xoffset, + yoffset, + width as i32, + height as i32, + format, + data_type, + &receiver.recv().unwrap(), + ); + }, WebGLCommand::DrawingBufferWidth(ref sender) => sender .send(ctx.borrow_draw_buffer().unwrap().size().width) .unwrap(), diff --git a/components/canvas_traits/webgl.rs b/components/canvas_traits/webgl.rs index 29236615b7987..ae12c9410e14a 100644 --- a/components/canvas_traits/webgl.rs +++ b/components/canvas_traits/webgl.rs @@ -272,8 +272,27 @@ pub enum WebGLCommand { VertexAttribPointer(u32, i32, u32, bool, i32, u32), VertexAttribPointer2f(u32, i32, bool, i32, u32), SetViewport(i32, i32, i32, i32), - TexImage2D(u32, i32, i32, i32, i32, u32, u32, IpcBytesReceiver), - TexSubImage2D(u32, i32, i32, i32, i32, i32, u32, u32, IpcBytesReceiver), + TexImage2D { + target: u32, + level: u32, + internal_format: u32, + width: u32, + height: u32, + format: u32, + data_type: u32, + receiver: IpcBytesReceiver, + }, + TexSubImage2D { + target: u32, + level: u32, + xoffset: i32, + yoffset: i32, + width: u32, + height: u32, + format: u32, + data_type: u32, + receiver: IpcBytesReceiver, + }, DrawingBufferWidth(WebGLSender), DrawingBufferHeight(WebGLSender), Finish(WebGLSender<()>), diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index 97e35b058e880..eb40bc5ac0241 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -739,16 +739,16 @@ impl WebGLRenderingContext { // TODO(emilio): convert colorspace if requested let (sender, receiver) = ipc::bytes_channel().unwrap(); - self.send_command(WebGLCommand::TexImage2D( - target.as_gl_constant(), - level as i32, - internal_format as i32, - width as i32, - height as i32, + self.send_command(WebGLCommand::TexImage2D { + target: target.as_gl_constant(), + level, + internal_format, + width, + height, format, - self.extension_manager.effective_type(data_type), + data_type: self.extension_manager.effective_type(data_type), receiver, - )); + }); sender.send(&pixels).unwrap(); if let Some(fb) = self.bound_framebuffer.get() { @@ -817,17 +817,17 @@ impl WebGLRenderingContext { // TODO(emilio): convert colorspace if requested let (sender, receiver) = ipc::bytes_channel().unwrap(); - self.send_command(WebGLCommand::TexSubImage2D( - target.as_gl_constant(), - level as i32, + self.send_command(WebGLCommand::TexSubImage2D { + target: target.as_gl_constant(), + level, xoffset, yoffset, - width as i32, - height as i32, - format.as_gl_constant(), - data_type.as_gl_constant(), + width, + height, + format: format.as_gl_constant(), + data_type: data_type.as_gl_constant(), receiver, - )); + }); sender.send(&pixels).unwrap(); } From 1675991b1216ce5358da49d8641857b24bfb2108 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Thu, 15 Nov 2018 10:32:47 +0100 Subject: [PATCH 07/11] Fix the data type sent in tex_sub_image_2d --- components/script/dom/webglrenderingcontext.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index eb40bc5ac0241..36ce05256d6dd 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -825,7 +825,9 @@ impl WebGLRenderingContext { width, height, format: format.as_gl_constant(), - data_type: data_type.as_gl_constant(), + data_type: self + .extension_manager + .effective_type(data_type.as_gl_constant()), receiver, }); sender.send(&pixels).unwrap(); From 1c89ac90b9dd6e4a296e3fcfd71b4995910a96eb Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Thu, 15 Nov 2018 10:39:01 +0100 Subject: [PATCH 08/11] Send alignment info directly in TexImage2D and TexSubImage2d messages --- components/canvas/webgl_thread.rs | 6 +++++ components/canvas_traits/webgl.rs | 2 ++ .../script/dom/webglrenderingcontext.rs | 22 ++----------------- 3 files changed, 10 insertions(+), 20 deletions(-) diff --git a/components/canvas/webgl_thread.rs b/components/canvas/webgl_thread.rs index c1839e19e3226..e8af815f9769b 100644 --- a/components/canvas/webgl_thread.rs +++ b/components/canvas/webgl_thread.rs @@ -1050,8 +1050,11 @@ impl WebGLImpl { height, format, data_type, + unpacking_alignment, ref receiver, } => { + ctx.gl() + .pixel_store_i(gl::UNPACK_ALIGNMENT, unpacking_alignment as i32); ctx.gl().tex_image_2d( target, level as i32, @@ -1073,8 +1076,11 @@ impl WebGLImpl { height, format, data_type, + unpacking_alignment, ref receiver, } => { + ctx.gl() + .pixel_store_i(gl::UNPACK_ALIGNMENT, unpacking_alignment as i32); ctx.gl().tex_sub_image_2d( target, level as i32, diff --git a/components/canvas_traits/webgl.rs b/components/canvas_traits/webgl.rs index ae12c9410e14a..7b8bc8103a292 100644 --- a/components/canvas_traits/webgl.rs +++ b/components/canvas_traits/webgl.rs @@ -280,6 +280,7 @@ pub enum WebGLCommand { height: u32, format: u32, data_type: u32, + unpacking_alignment: u32, receiver: IpcBytesReceiver, }, TexSubImage2D { @@ -291,6 +292,7 @@ pub enum WebGLCommand { height: u32, format: u32, data_type: u32, + unpacking_alignment: u32, receiver: IpcBytesReceiver, }, DrawingBufferWidth(WebGLSender), diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index 36ce05256d6dd..42c03b735dc5d 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -721,16 +721,6 @@ impl WebGLRenderingContext { ) ); - // Set the unpack alignment. For textures coming from arrays, - // this will be the current value of the context's - // GL_UNPACK_ALIGNMENT, while for textures from images or - // canvas (produced by rgba8_image_to_tex_image_data()), it - // will be 1. - self.send_command(WebGLCommand::PixelStorei( - constants::UNPACK_ALIGNMENT, - unpacking_alignment as i32, - )); - let format = internal_format.as_gl_constant(); let data_type = data_type.as_gl_constant(); let internal_format = self @@ -747,6 +737,7 @@ impl WebGLRenderingContext { height, format, data_type: self.extension_manager.effective_type(data_type), + unpacking_alignment, receiver, }); sender.send(&pixels).unwrap(); @@ -805,16 +796,6 @@ impl WebGLRenderingContext { return self.webgl_error(InvalidOperation); } - // Set the unpack alignment. For textures coming from arrays, - // this will be the current value of the context's - // GL_UNPACK_ALIGNMENT, while for textures from images or - // canvas (produced by rgba8_image_to_tex_image_data()), it - // will be 1. - self.send_command(WebGLCommand::PixelStorei( - constants::UNPACK_ALIGNMENT, - unpacking_alignment as i32, - )); - // TODO(emilio): convert colorspace if requested let (sender, receiver) = ipc::bytes_channel().unwrap(); self.send_command(WebGLCommand::TexSubImage2D { @@ -828,6 +809,7 @@ impl WebGLRenderingContext { data_type: self .extension_manager .effective_type(data_type.as_gl_constant()), + unpacking_alignment, receiver, }); sender.send(&pixels).unwrap(); From 3f8a3b2887dfec39f8033ccbadc6053c49aed315 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Thu, 15 Nov 2018 11:30:57 +0100 Subject: [PATCH 09/11] Simplify define_resource_id --- components/canvas_traits/webgl.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/components/canvas_traits/webgl.rs b/components/canvas_traits/webgl.rs index 7b8bc8103a292..caec99e35a3d0 100644 --- a/components/canvas_traits/webgl.rs +++ b/components/canvas_traits/webgl.rs @@ -367,7 +367,7 @@ pub enum WebGLCommand { }, } -macro_rules! define_resource_id_struct { +macro_rules! define_resource_id { ($name:ident) => { #[derive(Clone, Copy, Eq, Hash, PartialEq)] pub struct $name(NonZeroU32); @@ -384,12 +384,6 @@ macro_rules! define_resource_id_struct { self.0.get() } } - }; -} - -macro_rules! define_resource_id { - ($name:ident) => { - define_resource_id_struct!($name); #[allow(unsafe_code)] impl<'de> ::serde::Deserialize<'de> for $name { From 947e5afa0c5dd374a59b452655c848754dbe2aac Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Thu, 15 Nov 2018 15:22:05 +0100 Subject: [PATCH 10/11] Remove some boolean flags in tex_image_2d and tex_sub_image_2d --- components/canvas_traits/webgl.rs | 18 ++++ .../script/dom/webglrenderingcontext.rs | 101 ++++++++++++------ 2 files changed, 89 insertions(+), 30 deletions(-) diff --git a/components/canvas_traits/webgl.rs b/components/canvas_traits/webgl.rs index caec99e35a3d0..33bc767d3c232 100644 --- a/components/canvas_traits/webgl.rs +++ b/components/canvas_traits/webgl.rs @@ -757,6 +757,24 @@ impl TexDataType { } } +#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq)] +pub enum AlphaTreatment { + Premultiply, + Unmultiply, +} + +#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq)] +pub enum YAxisTreatment { + AsIs, + Flipped, +} + +#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq)] +pub enum TexSource { + FromHtmlElement, + FromArray, +} + /// Translates an image in rgba8 (red in the first byte) format to /// the format that was requested of TexImage. pub fn rgba8_image_to_tex_image_data( diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index 42c03b735dc5d..8a96fe1dcca3f 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -6,10 +6,10 @@ use backtrace::Backtrace; use canvas_traits::webgl::WebGLError::*; use canvas_traits::webgl::{ - self, webgl_channel, DOMToTextureCommand, Parameter, TexDataType, TexFormat, TexParameter, - WebGLCommand, WebGLCommandBacktrace, WebGLContextShareMode, WebGLError, - WebGLFramebufferBindingRequest, WebGLMsg, WebGLMsgSender, WebGLProgramId, WebGLResult, - WebGLSLVersion, WebGLSender, WebGLVersion, WebVRCommand, + self, webgl_channel, AlphaTreatment, DOMToTextureCommand, Parameter, TexDataType, TexFormat, + TexParameter, TexSource, WebGLCommand, WebGLCommandBacktrace, WebGLContextShareMode, + WebGLError, WebGLFramebufferBindingRequest, WebGLMsg, WebGLMsgSender, WebGLProgramId, + WebGLResult, WebGLSLVersion, WebGLSender, WebGLVersion, WebVRCommand, YAxisTreatment, }; use crate::dom::bindings::codegen::Bindings::ANGLEInstancedArraysBinding::ANGLEInstancedArraysConstants; use crate::dom::bindings::codegen::Bindings::EXTBlendMinmaxBinding::EXTBlendMinmaxConstants; @@ -505,7 +505,7 @@ impl WebGLRenderingContext { 0, 1, true, - true, + TexSource::FromHtmlElement, pixels, ); @@ -645,28 +645,35 @@ impl WebGLRenderingContext { width: u32, height: u32, unpacking_alignment: u32, - source_premultiplied: bool, - source_from_image_or_canvas: bool, + alpha_treatment: Option, + y_axis_treatment: YAxisTreatment, + tex_source: TexSource, mut pixels: Vec, ) -> Vec { - let settings = self.texture_unpacking_settings.get(); - let dest_premultiply = settings.contains(TextureUnpacking::PREMULTIPLY_ALPHA); - if !source_premultiplied && dest_premultiply { - if source_from_image_or_canvas { - // When the pixels come from image or canvas or imagedata, use RGBA8 format - webgl::premultiply_inplace(TexFormat::RGBA, TexDataType::UnsignedByte, &mut pixels); - } else { - webgl::premultiply_inplace(internal_format, data_type, &mut pixels); - } - } else if source_premultiplied && !dest_premultiply { - webgl::unmultiply_inplace(&mut pixels); + match alpha_treatment { + Some(AlphaTreatment::Premultiply) => { + if tex_source == TexSource::FromHtmlElement { + webgl::premultiply_inplace( + TexFormat::RGBA, + TexDataType::UnsignedByte, + &mut pixels, + ); + } else { + webgl::premultiply_inplace(internal_format, data_type, &mut pixels); + } + }, + Some(AlphaTreatment::Unmultiply) => { + assert_eq!(tex_source, TexSource::FromHtmlElement); + webgl::unmultiply_inplace(&mut pixels); + }, + None => {}, } - if source_from_image_or_canvas { + if tex_source == TexSource::FromHtmlElement { pixels = webgl::rgba8_image_to_tex_image_data(internal_format, data_type, pixels); } - if settings.contains(TextureUnpacking::FLIP_Y_AXIS) { + if y_axis_treatment == YAxisTreatment::Flipped { // FINISHME: Consider doing premultiply and flip in a single mutable Vec. pixels = webgl::flip_pixels_y( internal_format, @@ -693,17 +700,33 @@ impl WebGLRenderingContext { _border: u32, unpacking_alignment: u32, source_premultiplied: bool, - source_from_image_or_canvas: bool, + tex_source: TexSource, pixels: Vec, ) { + let settings = self.texture_unpacking_settings.get(); + let dest_premultiplied = settings.contains(TextureUnpacking::PREMULTIPLY_ALPHA); + + let alpha_treatment = match (source_premultiplied, dest_premultiplied) { + (true, false) => Some(AlphaTreatment::Unmultiply), + (false, true) => Some(AlphaTreatment::Premultiply), + _ => None, + }; + + let y_axis_treatment = if settings.contains(TextureUnpacking::FLIP_Y_AXIS) { + YAxisTreatment::Flipped + } else { + YAxisTreatment::AsIs + }; + let pixels = self.prepare_pixels( internal_format, data_type, width, height, unpacking_alignment, - source_premultiplied, - source_from_image_or_canvas, + alpha_treatment, + y_axis_treatment, + tex_source, pixels, ); @@ -760,17 +783,35 @@ impl WebGLRenderingContext { data_type: TexDataType, unpacking_alignment: u32, source_premultiplied: bool, - source_from_image_or_canvas: bool, + tex_source: TexSource, pixels: Vec, ) { + let settings = self.texture_unpacking_settings.get(); + + let alpha_treatment = match ( + source_premultiplied, + settings.contains(TextureUnpacking::PREMULTIPLY_ALPHA), + ) { + (true, false) => Some(AlphaTreatment::Unmultiply), + (false, true) => Some(AlphaTreatment::Premultiply), + _ => None, + }; + + let y_axis_treatment = if settings.contains(TextureUnpacking::FLIP_Y_AXIS) { + YAxisTreatment::Flipped + } else { + YAxisTreatment::AsIs + }; + let pixels = self.prepare_pixels( format, data_type, width, height, unpacking_alignment, - source_premultiplied, - source_from_image_or_canvas, + alpha_treatment, + y_axis_treatment, + tex_source, pixels, ); @@ -3677,7 +3718,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { border, unpacking_alignment, false, - false, + TexSource::FromArray, buff, ); @@ -3752,7 +3793,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { border, 1, pixels.premultiplied, - true, + TexSource::FromHtmlElement, pixels.data, ); Ok(()) @@ -3888,7 +3929,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { data_type, unpacking_alignment, false, - false, + TexSource::FromArray, buff, ); Ok(()) @@ -3945,7 +3986,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { data_type, 1, pixels.premultiplied, - true, + TexSource::FromHtmlElement, pixels.data, ); Ok(()) From af2b4dbc21596b662dcb8c428943422bc0838f4d Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Thu, 15 Nov 2018 15:49:29 +0100 Subject: [PATCH 11/11] Pass a TexPixels value to tex_image_2d and tex_sub_image_2d --- .../script/dom/webglrenderingcontext.rs | 91 ++++++++----------- 1 file changed, 39 insertions(+), 52 deletions(-) diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index 8a96fe1dcca3f..a21d38981120e 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -494,19 +494,19 @@ impl WebGLRenderingContext { rgba8[3] = 255u8; } + // TODO(nox): AFAICT here we construct a RGBA8 array and then we + // convert it to whatever actual format we need, we should probably + // construct the desired format from the start. self.tex_image_2d( texture, target, data_type, format, level, - size.width, - size.height, 0, 1, - true, TexSource::FromHtmlElement, - pixels, + TexPixels::new(pixels, size, true), ); false @@ -642,8 +642,7 @@ impl WebGLRenderingContext { &self, internal_format: TexFormat, data_type: TexDataType, - width: u32, - height: u32, + size: Size2D, unpacking_alignment: u32, alpha_treatment: Option, y_axis_treatment: YAxisTreatment, @@ -678,8 +677,8 @@ impl WebGLRenderingContext { pixels = webgl::flip_pixels_y( internal_format, data_type, - width as usize, - height as usize, + size.width as usize, + size.height as usize, unpacking_alignment as usize, pixels, ); @@ -695,18 +694,15 @@ impl WebGLRenderingContext { data_type: TexDataType, internal_format: TexFormat, level: u32, - width: u32, - height: u32, _border: u32, unpacking_alignment: u32, - source_premultiplied: bool, tex_source: TexSource, - pixels: Vec, + pixels: TexPixels, ) { let settings = self.texture_unpacking_settings.get(); let dest_premultiplied = settings.contains(TextureUnpacking::PREMULTIPLY_ALPHA); - let alpha_treatment = match (source_premultiplied, dest_premultiplied) { + let alpha_treatment = match (pixels.premultiplied, dest_premultiplied) { (true, false) => Some(AlphaTreatment::Unmultiply), (false, true) => Some(AlphaTreatment::Premultiply), _ => None, @@ -718,16 +714,15 @@ impl WebGLRenderingContext { YAxisTreatment::AsIs }; - let pixels = self.prepare_pixels( + let buff = self.prepare_pixels( internal_format, data_type, - width, - height, + pixels.size, unpacking_alignment, alpha_treatment, y_axis_treatment, tex_source, - pixels, + pixels.data, ); // TexImage2D depth is always equal to 1 @@ -735,8 +730,8 @@ impl WebGLRenderingContext { self, texture.initialize( target, - width, - height, + pixels.size.width, + pixels.size.height, 1, internal_format, level, @@ -756,14 +751,14 @@ impl WebGLRenderingContext { target: target.as_gl_constant(), level, internal_format, - width, - height, + width: pixels.size.width, + height: pixels.size.height, format, data_type: self.extension_manager.effective_type(data_type), unpacking_alignment, receiver, }); - sender.send(&pixels).unwrap(); + sender.send(&buff).unwrap(); if let Some(fb) = self.bound_framebuffer.get() { fb.invalidate_texture(&*texture); @@ -777,19 +772,16 @@ impl WebGLRenderingContext { level: u32, xoffset: i32, yoffset: i32, - width: u32, - height: u32, format: TexFormat, data_type: TexDataType, unpacking_alignment: u32, - source_premultiplied: bool, tex_source: TexSource, - pixels: Vec, + pixels: TexPixels, ) { let settings = self.texture_unpacking_settings.get(); let alpha_treatment = match ( - source_premultiplied, + pixels.premultiplied, settings.contains(TextureUnpacking::PREMULTIPLY_ALPHA), ) { (true, false) => Some(AlphaTreatment::Unmultiply), @@ -803,16 +795,15 @@ impl WebGLRenderingContext { YAxisTreatment::AsIs }; - let pixels = self.prepare_pixels( + let buff = self.prepare_pixels( format, data_type, - width, - height, + pixels.size, unpacking_alignment, alpha_treatment, y_axis_treatment, tex_source, - pixels, + pixels.data, ); // We have already validated level @@ -823,9 +814,9 @@ impl WebGLRenderingContext { // - x offset plus the width is greater than the texture width // - y offset plus the height is greater than the texture height if xoffset < 0 || - (xoffset as u32 + width) > image_info.width() || + (xoffset as u32 + pixels.size.width) > image_info.width() || yoffset < 0 || - (yoffset as u32 + height) > image_info.height() + (yoffset as u32 + pixels.size.height) > image_info.height() { return self.webgl_error(InvalidValue); } @@ -844,8 +835,8 @@ impl WebGLRenderingContext { level, xoffset, yoffset, - width, - height, + width: pixels.size.width, + height: pixels.size.height, format: format.as_gl_constant(), data_type: self .extension_manager @@ -853,7 +844,7 @@ impl WebGLRenderingContext { unpacking_alignment, receiver, }); - sender.send(&pixels).unwrap(); + sender.send(&buff).unwrap(); } fn get_gl_extensions(&self) -> String { @@ -3713,13 +3704,10 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { data_type, format, level, - width, - height, border, unpacking_alignment, - false, TexSource::FromArray, - buff, + TexPixels::from_array(buff, Size2D::new(width, height)), ); Ok(()) @@ -3788,13 +3776,10 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { data_type, format, level, - pixels.size.width, - pixels.size.height, border, 1, - pixels.premultiplied, TexSource::FromHtmlElement, - pixels.data, + pixels, ); Ok(()) } @@ -3923,14 +3908,11 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { level, xoffset, yoffset, - width, - height, format, data_type, unpacking_alignment, - false, TexSource::FromArray, - buff, + TexPixels::from_array(buff, Size2D::new(width, height)), ); Ok(()) } @@ -3980,14 +3962,11 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { level, xoffset, yoffset, - pixels.size.width, - pixels.size.height, format, data_type, 1, - pixels.premultiplied, TexSource::FromHtmlElement, - pixels.data, + pixels, ); Ok(()) } @@ -4283,4 +4262,12 @@ impl TexPixels { premultiplied, } } + + fn from_array(data: Vec, size: Size2D) -> Self { + Self { + data, + size, + premultiplied: false, + } + } }