mirror of
https://github.com/servo/servo.git
synced 2025-07-23 07:13:52 +01:00
webgl: Convert non-raw TexImage sources to the requested format.
The code was returning RGBA8 data from the non-raw sources (HTML canvas elements, JS ImageData, etc.), but we then validated and passed that rgba8 data as if it was whatever format/datatype was specified in TexImage2D/TexSubImage2D, so the pixels would come out as garbage. It would seem like we could just rewrite the passed in format/datatype for the TexImage call to be RGBA/UNSIGNED_BYTE, but that would leave incorrect levels of precision if the internalformat didn't match the format/datatype (and older desktop implementations often ignore the internalformat in choosing their internal format, anyway).
This commit is contained in:
parent
2e6eb547a8
commit
57ba1646bc
10 changed files with 70 additions and 34 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -2268,6 +2268,7 @@ dependencies = [
|
||||||
"audio-video-metadata 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"audio-video-metadata 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"bluetooth_traits 0.0.1",
|
"bluetooth_traits 0.0.1",
|
||||||
|
"byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"canvas_traits 0.0.1",
|
"canvas_traits 0.0.1",
|
||||||
"caseless 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"caseless 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"cmake 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cmake 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|
|
@ -30,6 +30,7 @@ audio-video-metadata = "0.1.2"
|
||||||
atomic_refcell = "0.1"
|
atomic_refcell = "0.1"
|
||||||
bitflags = "0.7"
|
bitflags = "0.7"
|
||||||
bluetooth_traits = {path = "../bluetooth_traits"}
|
bluetooth_traits = {path = "../bluetooth_traits"}
|
||||||
|
byteorder = "0.5"
|
||||||
canvas_traits = {path = "../canvas_traits"}
|
canvas_traits = {path = "../canvas_traits"}
|
||||||
caseless = "0.1.0"
|
caseless = "0.1.0"
|
||||||
cookie = {version = "0.2.5", features = ["serialize-rustc"]}
|
cookie = {version = "0.2.5", features = ["serialize-rustc"]}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use byteorder::{NativeEndian, WriteBytesExt};
|
||||||
use canvas_traits::{CanvasCommonMsg, CanvasMsg, byte_swap};
|
use canvas_traits::{CanvasCommonMsg, CanvasMsg, byte_swap};
|
||||||
use core::nonzero::NonZero;
|
use core::nonzero::NonZero;
|
||||||
use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::{self, WebGLContextAttributes};
|
use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::{self, WebGLContextAttributes};
|
||||||
|
@ -364,6 +365,67 @@ impl WebGLRenderingContext {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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) => pixels,
|
||||||
|
|
||||||
|
(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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get_image_pixels(&self,
|
fn get_image_pixels(&self,
|
||||||
source: Option<ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement>)
|
source: Option<ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement>)
|
||||||
-> ImagePixelResult {
|
-> ImagePixelResult {
|
||||||
|
@ -398,10 +460,7 @@ impl WebGLRenderingContext {
|
||||||
|
|
||||||
let size = Size2D::new(img.width as i32, img.height as i32);
|
let size = Size2D::new(img.width as i32, img.height as i32);
|
||||||
|
|
||||||
// TODO(emilio): Validate that the format argument
|
// For now Servo's images are all stored as RGBA8 internally.
|
||||||
// is coherent with the image.
|
|
||||||
//
|
|
||||||
// RGB8 should be easy to support too
|
|
||||||
let mut data = match img.format {
|
let mut data = match img.format {
|
||||||
PixelFormat::RGBA8 => img.bytes.to_vec(),
|
PixelFormat::RGBA8 => img.bytes.to_vec(),
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
|
@ -2690,6 +2749,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
||||||
Err(_) => return Ok(()), // NB: The validator sets the correct error for us.
|
Err(_) => return Ok(()), // NB: The validator sets the correct error for us.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let pixels = self.rgba8_image_to_tex_image_data(format, data_type, pixels);
|
||||||
|
|
||||||
self.tex_image_2d(texture, target, data_type, format,
|
self.tex_image_2d(texture, target, data_type, format,
|
||||||
level, width, height, border, pixels);
|
level, width, height, border, pixels);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -2794,6 +2855,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
||||||
Err(_) => return Ok(()), // NB: The validator sets the correct error for us.
|
Err(_) => return Ok(()), // NB: The validator sets the correct error for us.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let pixels = self.rgba8_image_to_tex_image_data(format, data_type, pixels);
|
||||||
|
|
||||||
self.tex_sub_image_2d(texture, target, level, xoffset, yoffset,
|
self.tex_sub_image_2d(texture, target, level, xoffset, yoffset,
|
||||||
width, height, format, data_type, pixels);
|
width, height, format, data_type, pixels);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -32,6 +32,7 @@ extern crate audio_video_metadata;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate bitflags;
|
extern crate bitflags;
|
||||||
extern crate bluetooth_traits;
|
extern crate bluetooth_traits;
|
||||||
|
extern crate byteorder;
|
||||||
extern crate canvas_traits;
|
extern crate canvas_traits;
|
||||||
extern crate caseless;
|
extern crate caseless;
|
||||||
extern crate cookie as cookie_rs;
|
extern crate cookie as cookie_rs;
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[tex-image-and-sub-image-2d-with-image-data-rgb565.html]
|
|
||||||
type: testharness
|
|
||||||
[WebGL test #0: at (0, 0) expected: 0,255,0,255 was 255,227,0,255]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[tex-image-and-sub-image-2d-with-image-data-rgba4444.html]
|
|
||||||
type: testharness
|
|
||||||
[WebGL test #0: at (0, 0) expected: 0,255,0,255 was 255,255,0,255]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[tex-image-and-sub-image-2d-with-image-data-rgba5551.html]
|
|
||||||
type: testharness
|
|
||||||
[WebGL test #0: at (0, 0) expected: 0,255,0,255 was 255,231,0,255]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[tex-image-and-sub-image-2d-with-image-rgb565.html]
|
|
||||||
type: testharness
|
|
||||||
[WebGL test #0: at (4, 4) expected: 0,255,0 was 255,227,0]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[tex-image-and-sub-image-2d-with-image-rgba4444.html]
|
|
||||||
type: testharness
|
|
||||||
[WebGL test #0: at (4, 4) expected: 0,255,0 was 255,255,0]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[tex-image-and-sub-image-2d-with-image-rgba5551.html]
|
|
||||||
type: testharness
|
|
||||||
[WebGL test #0: at (4, 4) expected: 0,255,0 was 255,231,0]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue