aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom/webglrenderingcontext.rs
diff options
context:
space:
mode:
authorAnthony Ramine <n.oxyde@gmail.com>2018-09-08 13:26:06 +0200
committerAnthony Ramine <n.oxyde@gmail.com>2018-09-08 13:42:06 +0200
commit145086e150b997bb0bbe9d558f31ebc91dd1757d (patch)
tree49200c80cf9766a06521edd7093f6d1d47f06b5f /components/script/dom/webglrenderingcontext.rs
parenta5f9d03229c992f68866611ec97a70204dccb990 (diff)
downloadservo-145086e150b997bb0bbe9d558f31ebc91dd1757d.tar.gz
servo-145086e150b997bb0bbe9d558f31ebc91dd1757d.zip
Make rgba8_image_to_tex_image_data a free-standing function
Diffstat (limited to 'components/script/dom/webglrenderingcontext.rs')
-rw-r--r--components/script/dom/webglrenderingcontext.rs403
1 files changed, 202 insertions, 201 deletions
diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs
index c3868327261..b985ea71a15 100644
--- a/components/script/dom/webglrenderingcontext.rs
+++ b/components/script/dom/webglrenderingcontext.rs
@@ -481,206 +481,6 @@ impl WebGLRenderingContext {
}
}
- // https://en.wikipedia.org/wiki/Relative_luminance
- #[inline]
- fn luminance(r: u8, g: u8, b: u8) -> u8 {
- (0.2126 * (r as f32) +
- 0.7152 * (g as f32) +
- 0.0722 * (b as f32)) 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(&self,
- format: TexFormat,
- data_type: TexDataType,
- 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) => {
- // Remove alpha channel
- let mut rgb8 = Vec::<u8>::with_capacity(pixel_count * 3);
- for rgba8 in pixels.chunks(4) {
- rgb8.push(rgba8[0]);
- rgb8.push(rgba8[1]);
- rgb8.push(rgba8[2]);
- }
- rgb8
- },
-
- (TexFormat::Alpha, TexDataType::UnsignedByte) => {
- let mut alpha = Vec::<u8>::with_capacity(pixel_count);
- for rgba8 in pixels.chunks(4) {
- alpha.push(rgba8[3]);
- }
- alpha
- },
-
- (TexFormat::Luminance, TexDataType::UnsignedByte) => {
- let mut luminance = Vec::<u8>::with_capacity(pixel_count);
- for rgba8 in pixels.chunks(4) {
- luminance.push(Self::luminance(rgba8[0], rgba8[1], rgba8[2]));
- }
- luminance
- },
-
- (TexFormat::LuminanceAlpha, TexDataType::UnsignedByte) => {
- let mut data = Vec::<u8>::with_capacity(pixel_count * 2);
- for rgba8 in pixels.chunks(4) {
- data.push(Self::luminance(rgba8[0], rgba8[1], rgba8[2]));
- data.push(rgba8[3]);
- }
- data
- },
-
- (TexFormat::RGBA, TexDataType::UnsignedShort4444) => {
- let mut rgba4 = Vec::<u8>::with_capacity(pixel_count * 2);
- for rgba8 in pixels.chunks(4) {
- rgba4.write_u16::<NativeEndian>((rgba8[0] as u16 & 0xf0) << 8 |
- (rgba8[1] as u16 & 0xf0) << 4 |
- (rgba8[2] as u16 & 0xf0) |
- (rgba8[3] as u16 & 0xf0) >> 4).unwrap();
- }
- rgba4
- }
-
- (TexFormat::RGBA, TexDataType::UnsignedShort5551) => {
- let mut rgba5551 = Vec::<u8>::with_capacity(pixel_count * 2);
- for rgba8 in pixels.chunks(4) {
- rgba5551.write_u16::<NativeEndian>((rgba8[0] as u16 & 0xf8) << 8 |
- (rgba8[1] as u16 & 0xf8) << 3 |
- (rgba8[2] as u16 & 0xf8) >> 2 |
- (rgba8[3] as u16) >> 7).unwrap();
- }
- rgba5551
- }
-
- (TexFormat::RGB, TexDataType::UnsignedShort565) => {
- let mut rgb565 = Vec::<u8>::with_capacity(pixel_count * 2);
- for rgba8 in pixels.chunks(4) {
- rgb565.write_u16::<NativeEndian>((rgba8[0] as u16 & 0xf8) << 8 |
- (rgba8[1] as u16 & 0xfc) << 3 |
- (rgba8[2] as u16 & 0xf8) >> 3).unwrap();
- }
- rgb565
- }
-
-
- (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) => {
- let mut alpha = Vec::<u8>::with_capacity(pixel_count * 4);
- for rgba8 in pixels.chunks(4) {
- alpha.write_f32::<NativeEndian>(rgba8[0] as f32).unwrap();
- }
- alpha
- },
-
- (TexFormat::Luminance, TexDataType::Float) => {
- let mut luminance = Vec::<u8>::with_capacity(pixel_count * 4);
- for rgba8 in pixels.chunks(4) {
- let p = Self::luminance(rgba8[0], rgba8[1], rgba8[2]);
- luminance.write_f32::<NativeEndian>(p as f32).unwrap();
- }
- luminance
- },
-
- (TexFormat::LuminanceAlpha, TexDataType::Float) => {
- let mut data = Vec::<u8>::with_capacity(pixel_count * 8);
- for rgba8 in pixels.chunks(4) {
- let p = Self::luminance(rgba8[0], rgba8[1], rgba8[2]);
- data.write_f32::<NativeEndian>(p 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) => {
- let mut alpha = Vec::<u8>::with_capacity(pixel_count * 2);
- for rgba8 in pixels.chunks(4) {
- alpha.write_u16::<NativeEndian>(f16::from_f32(rgba8[3] as f32).as_bits()).unwrap();
- }
- alpha
- },
-
- (TexFormat::Luminance, TexDataType::HalfFloat) => {
- let mut luminance = Vec::<u8>::with_capacity(pixel_count * 4);
- for rgba8 in pixels.chunks(4) {
- let p = Self::luminance(rgba8[0], rgba8[1], rgba8[2]);
- luminance.write_u16::<NativeEndian>(f16::from_f32(p as f32).as_bits()).unwrap();
- }
- luminance
- },
-
- (TexFormat::LuminanceAlpha, TexDataType::HalfFloat) => {
- let mut data = Vec::<u8>::with_capacity(pixel_count * 8);
- for rgba8 in pixels.chunks(4) {
- let p = Self::luminance(rgba8[0], rgba8[1], rgba8[2]);
- data.write_u16::<NativeEndian>(f16::from_f32(p as f32).as_bits()).unwrap();
- data.write_u16::<NativeEndian>(f16::from_f32(rgba8[3] as f32).as_bits()).unwrap();
- }
- data
- },
-
- // 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 get_image_pixels(
&self,
source: ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement,
@@ -893,7 +693,7 @@ impl WebGLRenderingContext {
}
if source_from_image_or_canvas {
- pixels = self.rgba8_image_to_tex_image_data(internal_format, data_type, pixels);
+ pixels = rgba8_image_to_tex_image_data(internal_format, data_type, pixels);
}
// FINISHME: Consider doing premultiply and flip in a single mutable Vec.
@@ -4193,3 +3993,204 @@ fn remove_premultiplied_alpha(pixels: &mut [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,
+ 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) => {
+ // Remove alpha channel
+ let mut rgb8 = Vec::<u8>::with_capacity(pixel_count * 3);
+ for rgba8 in pixels.chunks(4) {
+ rgb8.push(rgba8[0]);
+ rgb8.push(rgba8[1]);
+ rgb8.push(rgba8[2]);
+ }
+ rgb8
+ },
+
+ (TexFormat::Alpha, TexDataType::UnsignedByte) => {
+ let mut alpha = Vec::<u8>::with_capacity(pixel_count);
+ for rgba8 in pixels.chunks(4) {
+ alpha.push(rgba8[3]);
+ }
+ alpha
+ },
+
+ (TexFormat::Luminance, TexDataType::UnsignedByte) => {
+ let mut lum = Vec::<u8>::with_capacity(pixel_count);
+ for rgba8 in pixels.chunks(4) {
+ lum.push(luminance(rgba8[0], rgba8[1], rgba8[2]));
+ }
+ lum
+ },
+
+ (TexFormat::LuminanceAlpha, TexDataType::UnsignedByte) => {
+ let mut data = Vec::<u8>::with_capacity(pixel_count * 2);
+ for rgba8 in pixels.chunks(4) {
+ data.push(luminance(rgba8[0], rgba8[1], rgba8[2]));
+ data.push(rgba8[3]);
+ }
+ data
+ },
+
+ (TexFormat::RGBA, TexDataType::UnsignedShort4444) => {
+ let mut rgba4 = Vec::<u8>::with_capacity(pixel_count * 2);
+ for rgba8 in pixels.chunks(4) {
+ rgba4.write_u16::<NativeEndian>((rgba8[0] as u16 & 0xf0) << 8 |
+ (rgba8[1] as u16 & 0xf0) << 4 |
+ (rgba8[2] as u16 & 0xf0) |
+ (rgba8[3] as u16 & 0xf0) >> 4).unwrap();
+ }
+ rgba4
+ }
+
+ (TexFormat::RGBA, TexDataType::UnsignedShort5551) => {
+ let mut rgba5551 = Vec::<u8>::with_capacity(pixel_count * 2);
+ for rgba8 in pixels.chunks(4) {
+ rgba5551.write_u16::<NativeEndian>((rgba8[0] as u16 & 0xf8) << 8 |
+ (rgba8[1] as u16 & 0xf8) << 3 |
+ (rgba8[2] as u16 & 0xf8) >> 2 |
+ (rgba8[3] as u16) >> 7).unwrap();
+ }
+ rgba5551
+ }
+
+ (TexFormat::RGB, TexDataType::UnsignedShort565) => {
+ let mut rgb565 = Vec::<u8>::with_capacity(pixel_count * 2);
+ for rgba8 in pixels.chunks(4) {
+ rgb565.write_u16::<NativeEndian>((rgba8[0] as u16 & 0xf8) << 8 |
+ (rgba8[1] as u16 & 0xfc) << 3 |
+ (rgba8[2] as u16 & 0xf8) >> 3).unwrap();
+ }
+ rgb565
+ }
+
+
+ (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) => {
+ let mut alpha = Vec::<u8>::with_capacity(pixel_count * 4);
+ for rgba8 in pixels.chunks(4) {
+ alpha.write_f32::<NativeEndian>(rgba8[0] as f32).unwrap();
+ }
+ alpha
+ },
+
+ (TexFormat::Luminance, TexDataType::Float) => {
+ let mut lum = Vec::<u8>::with_capacity(pixel_count * 4);
+ for rgba8 in pixels.chunks(4) {
+ let p = luminance(rgba8[0], rgba8[1], rgba8[2]);
+ luminance.write_f32::<NativeEndian>(p as f32).unwrap();
+ }
+ luminance
+ },
+
+ (TexFormat::LuminanceAlpha, TexDataType::Float) => {
+ let mut data = Vec::<u8>::with_capacity(pixel_count * 8);
+ for rgba8 in pixels.chunks(4) {
+ let p = luminance(rgba8[0], rgba8[1], rgba8[2]);
+ data.write_f32::<NativeEndian>(p 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) => {
+ let mut alpha = Vec::<u8>::with_capacity(pixel_count * 2);
+ for rgba8 in pixels.chunks(4) {
+ alpha.write_u16::<NativeEndian>(f16::from_f32(rgba8[3] as f32).as_bits()).unwrap();
+ }
+ alpha
+ },
+
+ (TexFormat::Luminance, TexDataType::HalfFloat) => {
+ let mut lum = Vec::<u8>::with_capacity(pixel_count * 4);
+ for rgba8 in pixels.chunks(4) {
+ let p = luminance(rgba8[0], rgba8[1], rgba8[2]);
+ lum.write_u16::<NativeEndian>(f16::from_f32(p as f32).as_bits()).unwrap();
+ }
+ lum
+ },
+
+ (TexFormat::LuminanceAlpha, TexDataType::HalfFloat) => {
+ let mut data = Vec::<u8>::with_capacity(pixel_count * 8);
+ for rgba8 in pixels.chunks(4) {
+ let p = luminance(rgba8[0], rgba8[1], rgba8[2]);
+ data.write_u16::<NativeEndian>(f16::from_f32(p as f32).as_bits()).unwrap();
+ data.write_u16::<NativeEndian>(f16::from_f32(rgba8[3] as f32).as_bits()).unwrap();
+ }
+ data
+ },
+
+ // 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)
+ }
+}
+
+// https://en.wikipedia.org/wiki/Relative_luminance
+#[inline]
+fn luminance(r: u8, g: u8, b: u8) -> u8 {
+ (0.2126 * (r as f32) +
+ 0.7152 * (g as f32) +
+ 0.0722 * (b as f32)) as u8
+}