diff --git a/Cargo.lock b/Cargo.lock index 7f6d6f2598d..fdcc04a56b0 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)", @@ -1276,11 +1279,21 @@ dependencies = [ ] [[package]] -name = "gleam" -version = "0.6.5" +name = "gl_generator" +version = "0.10.0" 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)", + "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.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "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/canvas_data.rs b/components/canvas/canvas_data.rs index d07ee2cd9cf..1c2e5d09118 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 dec2ad33263..e8af815f976 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 } @@ -1042,47 +1042,57 @@ impl WebGLImpl { WebGLCommand::SetViewport(x, y, width, height) => { ctx.gl().viewport(x, y, width, height); }, - WebGLCommand::TexImage2D( + WebGLCommand::TexImage2D { target, level, - internal, + internal_format, width, height, format, data_type, - ref chan, - ) => ctx.gl().tex_image_2d( + 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, + internal_format as i32, + width as i32, + height as i32, + 0, + format, + data_type, + Some(&receiver.recv().unwrap()), + ); + }, + WebGLCommand::TexSubImage2D { target, level, - internal, + xoffset, + yoffset, 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( - target, - level, - xoffset, - yoffset, - x, - y, - width, - height, - &chan.recv().unwrap(), - ), + 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, + 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/Cargo.toml b/components/canvas_traits/Cargo.toml index ae8eb8e4ec4..d24ba593a88 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 2e11d1704c6..666e9c9e5b5 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 dce9c441e1c..33bc767d3c2 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; @@ -269,8 +272,29 @@ 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, + unpacking_alignment: u32, + receiver: IpcBytesReceiver, + }, + TexSubImage2D { + target: u32, + level: u32, + xoffset: i32, + yoffset: i32, + width: u32, + height: u32, + format: u32, + data_type: u32, + unpacking_alignment: u32, + receiver: IpcBytesReceiver, + }, DrawingBufferWidth(WebGLSender), DrawingBufferHeight(WebGLSender), Finish(WebGLSender<()>), @@ -343,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); @@ -360,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 { @@ -650,3 +668,389 @@ 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, + } + } +} + +#[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( + 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::rgba8_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/net/image_cache.rs b/components/net/image_cache.rs index cf95d3fc1fd..22d6faccae6 100644 --- a/components/net/image_cache.rs +++ b/components/net/image_cache.rs @@ -56,9 +56,10 @@ 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 => { + 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]); } diff --git a/components/net_traits/image/base.rs b/components/net_traits/image/base.rs index 6e67e5b7cd1..05175084162 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 16c93b7b6af..de9a3cb3aa8 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/Cargo.toml b/components/script/Cargo.toml index cce1dee0bcc..0a7786a9480 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 d8d3000d037..f3cc904e807 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/canvasrenderingcontext2d.rs b/components/script/dom/canvasrenderingcontext2d.rs index 3a031095dc8..18d6c978cae 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 84280ec0724..714c66bf747 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/webgl_validations/tex_image_2d.rs b/components/script/dom/webgl_validations/tex_image_2d.rs index 125ff4918a8..09a96d37a1b 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 adcc51bf1ff..5ff239ed898 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; +use canvas_traits::gl_enums; +use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants; -/// 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 - } - } +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 a129a05fcfd..a21d3898112 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, 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; 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; @@ -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,15 +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; } - let pixels = self.prepare_pixels(format, data_type, width, height, 1, true, true, pixels); + // 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, width, height, 0, 1, pixels, + texture, + target, + data_type, + format, + level, + 0, + 1, + TexSource::FromHtmlElement, + TexPixels::new(pixels, size, true), ); false @@ -518,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); @@ -554,9 +559,9 @@ impl WebGLRenderingContext { _ => unimplemented!(), }; - pixels::byte_swap_colors_inplace(&mut data); + pixels::rgba8_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,8 +572,8 @@ 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) + pixels::rgba8_byte_swap_colors_inplace(&mut data); + TexPixels::new(data, size, true) } else { return Ok(None); } @@ -633,131 +638,53 @@ 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, data_type: TexDataType, - width: u32, - height: u32, + size: Size2D, 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 dest_premultiply = self - .texture_unpacking_settings - .get() - .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); - } else { - self.premultiply_pixels(internal_format, data_type, &mut pixels); - } - } else if source_premultiplied && !dest_premultiply { - remove_premultiplied_alpha(&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 { - pixels = rgba8_image_to_tex_image_data(internal_format, data_type, pixels); + if tex_source == TexSource::FromHtmlElement { + 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 y_axis_treatment == YAxisTreatment::Flipped { + // FINISHME: Consider doing premultiply and flip in a single mutable Vec. + pixels = webgl::flip_pixels_y( + internal_format, + data_type, + size.width as usize, + size.height as usize, + unpacking_alignment as usize, + pixels, + ); + } + + pixels } fn tex_image_2d( @@ -767,21 +694,44 @@ impl WebGLRenderingContext { data_type: TexDataType, internal_format: TexFormat, level: u32, - width: u32, - height: u32, _border: u32, unpacking_alignment: u32, - pixels: Vec, + tex_source: TexSource, + pixels: TexPixels, ) { - // NB: pixels should NOT be premultipied + let settings = self.texture_unpacking_settings.get(); + let dest_premultiplied = settings.contains(TextureUnpacking::PREMULTIPLY_ALPHA); + + let alpha_treatment = match (pixels.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 buff = self.prepare_pixels( + internal_format, + data_type, + pixels.size, + unpacking_alignment, + alpha_treatment, + y_axis_treatment, + tex_source, + pixels.data, + ); // TexImage2D depth is always equal to 1 handle_potential_webgl_error!( self, texture.initialize( target, - width, - height, + pixels.size.width, + pixels.size.height, 1, internal_format, level, @@ -789,16 +739,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 @@ -807,17 +747,18 @@ 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: pixels.size.width, + height: pixels.size.height, format, - self.extension_manager.effective_type(data_type), + 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); @@ -831,13 +772,40 @@ impl WebGLRenderingContext { level: u32, xoffset: i32, yoffset: i32, - width: u32, - height: u32, format: TexFormat, data_type: TexDataType, unpacking_alignment: u32, - pixels: Vec, + tex_source: TexSource, + pixels: TexPixels, ) { + let settings = self.texture_unpacking_settings.get(); + + let alpha_treatment = match ( + pixels.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 buff = self.prepare_pixels( + format, + data_type, + pixels.size, + unpacking_alignment, + alpha_treatment, + y_axis_treatment, + tex_source, + pixels.data, + ); + // We have already validated level let image_info = texture.image_info_for_target(&target, level); @@ -846,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); } @@ -860,30 +828,23 @@ 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( - 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: pixels.size.width, + height: pixels.size.height, + format: format.as_gl_constant(), + data_type: self + .extension_manager + .effective_type(data_type.as_gl_constant()), + unpacking_alignment, receiver, - )); - sender.send(&pixels).unwrap(); + }); + sender.send(&buff).unwrap(); } fn get_gl_extensions(&self) -> String { @@ -3729,22 +3690,13 @@ 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); - let pixels = self.prepare_pixels( - format, - data_type, - width, - height, - unpacking_alignment, - false, - false, - buff, - ); + 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( &texture, @@ -3752,11 +3704,10 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { data_type, format, level, - width, - height, border, unpacking_alignment, - pixels, + TexSource::FromArray, + TexPixels::from_array(buff, Size2D::new(width, height)), ); Ok(()) @@ -3776,8 +3727,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(()), }; @@ -3786,8 +3737,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, @@ -3796,37 +3747,39 @@ 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(()); } - let unpacking_alignment = 1; - let pixels = self.prepare_pixels( - format, - data_type, - width, - height, - unpacking_alignment, - premultiplied, - true, - pixels, - ); - self.tex_image_2d( - &texture, target, data_type, format, level, width, height, border, 1, pixels, + &texture, + target, + data_type, + format, + level, + border, + 1, + TexSource::FromHtmlElement, + pixels, ); Ok(()) } @@ -3949,30 +3902,17 @@ 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, level, xoffset, yoffset, - width, - height, format, data_type, unpacking_alignment, - pixels, + TexSource::FromArray, + TexPixels::from_array(buff, Size2D::new(width, height)), ); Ok(()) } @@ -3988,8 +3928,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(()), }; @@ -3998,8 +3938,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, @@ -4007,8 +3947,6 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { let TexImage2DValidatorResult { texture, target, - width, - height, level, format, data_type, @@ -4018,21 +3956,18 @@ 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( + self.tex_sub_image_2d( + texture, + target, + level, + xoffset, + yoffset, format, data_type, - width, - height, - unpacking_alignment, - premultiplied, - true, + 1, + TexSource::FromHtmlElement, pixels, ); - - self.tex_sub_image_2d( - texture, target, level, xoffset, yoffset, width, height, format, data_type, 1, pixels, - ); Ok(()) } @@ -4313,230 +4248,26 @@ 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; - } +struct TexPixels { + data: Vec, + size: Size2D, + premultiplied: bool, } -/// 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; +impl TexPixels { + fn new(data: Vec, size: Size2D, premultiplied: bool) -> Self { + Self { + data, + size, + premultiplied, + } + } - 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), + fn from_array(data: Vec, size: Size2D) -> Self { + Self { + data, + size, + premultiplied: false, + } } } diff --git a/components/script/dom/webgltexture.rs b/components/script/dom/webgltexture.rs index 2cc42a91f42..c17747a779a 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 a2f6805adf1..834ee59c439 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 6adf31af23b..64ee72f2c8f 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 = [