diff options
author | Anthony Ramine <n.oxyde@gmail.com> | 2018-11-15 10:01:19 +0100 |
---|---|---|
committer | Anthony Ramine <n.oxyde@gmail.com> | 2018-11-16 12:37:31 +0100 |
commit | adf363a2085f8af08a38046fae148131d0cbdd06 (patch) | |
tree | 88e63bdc02984770df7b39c699625a2bdcc53aa1 /components/script/dom/webglrenderingcontext.rs | |
parent | 86987ed75d94ddf8079dccf405073ee3a70bb1e6 (diff) | |
download | servo-adf363a2085f8af08a38046fae148131d0cbdd06.tar.gz servo-adf363a2085f8af08a38046fae148131d0cbdd06.zip |
Move prepare_pixels helper functions to canvas_traits
Diffstat (limited to 'components/script/dom/webglrenderingcontext.rs')
-rw-r--r-- | components/script/dom/webglrenderingcontext.rs | 366 |
1 files changed, 27 insertions, 339 deletions
diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index 346d8905082..b5b22f4f464 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<u8>, - internal_format: TexFormat, - data_type: TexDataType, - width: usize, - height: usize, - unpacking_alignment: usize, - ) -> Vec<u8> { - 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::<u8>::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<u8>, ) -> Vec<u8> { - 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<u8>, -) -> Vec<u8> { - // 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::<u8>::with_capacity(pixel_count * 16); - for rgba8 in pixels.chunks(4) { - rgbaf32.write_f32::<NativeEndian>(rgba8[0] as f32).unwrap(); - rgbaf32.write_f32::<NativeEndian>(rgba8[1] as f32).unwrap(); - rgbaf32.write_f32::<NativeEndian>(rgba8[2] as f32).unwrap(); - rgbaf32.write_f32::<NativeEndian>(rgba8[3] as f32).unwrap(); - } - rgbaf32 - }, - - (TexFormat::RGB, TexDataType::Float) => { - let mut rgbf32 = Vec::<u8>::with_capacity(pixel_count * 12); - for rgba8 in pixels.chunks(4) { - rgbf32.write_f32::<NativeEndian>(rgba8[0] as f32).unwrap(); - rgbf32.write_f32::<NativeEndian>(rgba8[1] as f32).unwrap(); - rgbf32.write_f32::<NativeEndian>(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::<u8>::with_capacity(pixel_count * 8); - for rgba8 in pixels.chunks(4) { - data.write_f32::<NativeEndian>(rgba8[0] as f32).unwrap(); - data.write_f32::<NativeEndian>(rgba8[3] as f32).unwrap(); - } - data - }, - - (TexFormat::RGBA, TexDataType::HalfFloat) => { - let mut rgbaf16 = Vec::<u8>::with_capacity(pixel_count * 8); - for rgba8 in pixels.chunks(4) { - rgbaf16 - .write_u16::<NativeEndian>(f16::from_f32(rgba8[0] as f32).as_bits()) - .unwrap(); - rgbaf16 - .write_u16::<NativeEndian>(f16::from_f32(rgba8[1] as f32).as_bits()) - .unwrap(); - rgbaf16 - .write_u16::<NativeEndian>(f16::from_f32(rgba8[2] as f32).as_bits()) - .unwrap(); - rgbaf16 - .write_u16::<NativeEndian>(f16::from_f32(rgba8[3] as f32).as_bits()) - .unwrap(); - } - rgbaf16 - }, - - (TexFormat::RGB, TexDataType::HalfFloat) => { - let mut rgbf16 = Vec::<u8>::with_capacity(pixel_count * 6); - for rgba8 in pixels.chunks(4) { - rgbf16 - .write_u16::<NativeEndian>(f16::from_f32(rgba8[0] as f32).as_bits()) - .unwrap(); - rgbf16 - .write_u16::<NativeEndian>(f16::from_f32(rgba8[1] as f32).as_bits()) - .unwrap(); - rgbf16 - .write_u16::<NativeEndian>(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<u8>, size: Size2D<u32>, |