Auto merge of #22225 - servo:webgl, r=emilio

Send an IpcSharedMemory in tex_image_2d and tex_sub_image_2d

<!-- Reviewable:start -->
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/22225)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2018-11-21 10:21:41 -05:00 committed by GitHub
commit 2b410acbf9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 602 additions and 563 deletions

10
Cargo.lock generated
View file

@ -348,12 +348,14 @@ name = "canvas"
version = "0.0.1" version = "0.0.1"
dependencies = [ dependencies = [
"azure 0.35.0 (git+https://github.com/servo/rust-azure)", "azure 0.35.0 (git+https://github.com/servo/rust-azure)",
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"canvas_traits 0.0.1", "canvas_traits 0.0.1",
"compositing 0.0.1", "compositing 0.0.1",
"cssparser 0.25.0 (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)", "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)", "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"gleam 0.6.7 (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.2 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.5 (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)", "num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
@ -369,11 +371,9 @@ dependencies = [
name = "canvas_traits" name = "canvas_traits"
version = "0.0.1" version = "0.0.1"
dependencies = [ 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)", "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)", "euclid 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gleam 0.6.7 (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.2 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.0 (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 0.0.1",
@ -544,6 +544,7 @@ dependencies = [
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"msg 0.0.1", "msg 0.0.1",
"net_traits 0.0.1", "net_traits 0.0.1",
"pixels 0.0.1",
"profile_traits 0.0.1", "profile_traits 0.0.1",
"script_traits 0.0.1", "script_traits 0.0.1",
"servo_config 0.0.1", "servo_config 0.0.1",
@ -2874,6 +2875,9 @@ name = "pixels"
version = "0.0.1" version = "0.0.1"
dependencies = [ dependencies = [
"euclid 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
"malloc_size_of 0.0.1",
"malloc_size_of_derive 0.0.1",
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -3357,6 +3361,7 @@ dependencies = [
"malloc_size_of_derive 0.0.1", "malloc_size_of_derive 0.0.1",
"msg 0.0.1", "msg 0.0.1",
"net_traits 0.0.1", "net_traits 0.0.1",
"pixels 0.0.1",
"profile_traits 0.0.1", "profile_traits 0.0.1",
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
"servo_atoms 0.0.1", "servo_atoms 0.0.1",
@ -4501,6 +4506,7 @@ dependencies = [
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"msg 0.0.1", "msg 0.0.1",
"net_traits 0.0.1", "net_traits 0.0.1",
"pixels 0.0.1",
"regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"script_traits 0.0.1", "script_traits 0.0.1",
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",

View file

@ -15,12 +15,14 @@ webgl_backtrace = ["canvas_traits/webgl_backtrace"]
[dependencies] [dependencies]
azure = {git = "https://github.com/servo/rust-azure"} azure = {git = "https://github.com/servo/rust-azure"}
byteorder = "1"
canvas_traits = {path = "../canvas_traits"} canvas_traits = {path = "../canvas_traits"}
compositing = {path = "../compositing"} compositing = {path = "../compositing"}
cssparser = "0.25" cssparser = "0.25"
euclid = "0.19" euclid = "0.19"
fnv = "1.0" fnv = "1.0"
gleam = "0.6.4" gleam = "0.6.4"
half = "1"
ipc-channel = "0.11" ipc-channel = "0.11"
log = "0.4" log = "0.4"
num-traits = "0.2" num-traits = "0.2"

View file

@ -13,9 +13,8 @@ use azure::azure_hl::{ExtendMode, GradientStop, LinearGradientPattern, RadialGra
use canvas_traits::canvas::*; use canvas_traits::canvas::*;
use cssparser::RGBA; use cssparser::RGBA;
use euclid::{Point2D, Rect, Size2D, Transform2D, Vector2D}; use euclid::{Point2D, Rect, Size2D, Transform2D, Vector2D};
use ipc_channel::ipc::IpcSender; use ipc_channel::ipc::{IpcSender, IpcSharedMemory};
use num_traits::ToPrimitive; use num_traits::ToPrimitive;
use serde_bytes::ByteBuf;
use std::mem; use std::mem;
use std::sync::Arc; use std::sync::Arc;
@ -451,15 +450,11 @@ impl<'a> CanvasData<'a> {
} }
#[allow(unsafe_code)] #[allow(unsafe_code)]
pub fn send_pixels(&mut self, chan: IpcSender<Option<ByteBuf>>) { pub fn send_pixels(&mut self, chan: IpcSender<IpcSharedMemory>) {
let data = unsafe { let data = IpcSharedMemory::from_bytes(unsafe {
self.drawtarget self.drawtarget.snapshot().get_data_surface().data()
.snapshot() });
.get_data_surface() chan.send(data).unwrap();
.data()
.to_vec()
};
chan.send(Some(data.into())).unwrap();
} }
#[allow(unsafe_code)] #[allow(unsafe_code)]

View file

@ -3,11 +3,15 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use super::gl_context::{GLContextFactory, GLContextWrapper}; use super::gl_context::{GLContextFactory, GLContextWrapper};
use byteorder::{ByteOrder, NativeEndian, WriteBytesExt};
use canvas_traits::webgl::*; use canvas_traits::webgl::*;
use euclid::Size2D; use euclid::Size2D;
use fnv::FnvHashMap; use fnv::FnvHashMap;
use gleam::gl; use gleam::gl;
use half::f16;
use offscreen_gl_context::{GLContext, GLContextAttributes, GLLimits, NativeGLContextMethods}; use offscreen_gl_context::{GLContext, GLContextAttributes, GLLimits, NativeGLContextMethods};
use pixels::{self, PixelFormat};
use std::borrow::Cow;
use std::thread; use std::thread;
/// WebGL Threading API entry point that lives in the constellation. /// WebGL Threading API entry point that lives in the constellation.
@ -1045,26 +1049,40 @@ impl WebGLImpl {
WebGLCommand::TexImage2D { WebGLCommand::TexImage2D {
target, target,
level, level,
internal_format, effective_internal_format,
width, size,
height,
format, format,
data_type, data_type,
effective_data_type,
unpacking_alignment, unpacking_alignment,
ref receiver, alpha_treatment,
y_axis_treatment,
pixel_format,
ref data,
} => { } => {
let pixels = prepare_pixels(
format,
data_type,
size,
unpacking_alignment,
alpha_treatment,
y_axis_treatment,
pixel_format,
Cow::Borrowed(data),
);
ctx.gl() ctx.gl()
.pixel_store_i(gl::UNPACK_ALIGNMENT, unpacking_alignment as i32); .pixel_store_i(gl::UNPACK_ALIGNMENT, unpacking_alignment as i32);
ctx.gl().tex_image_2d( ctx.gl().tex_image_2d(
target, target,
level as i32, level as i32,
internal_format as i32, effective_internal_format as i32,
width as i32, size.width as i32,
height as i32, size.height as i32,
0, 0,
format, format.as_gl_constant(),
data_type, effective_data_type,
Some(&receiver.recv().unwrap()), Some(&pixels),
); );
}, },
WebGLCommand::TexSubImage2D { WebGLCommand::TexSubImage2D {
@ -1072,13 +1090,27 @@ impl WebGLImpl {
level, level,
xoffset, xoffset,
yoffset, yoffset,
width, size,
height,
format, format,
data_type, data_type,
effective_data_type,
unpacking_alignment, unpacking_alignment,
ref receiver, alpha_treatment,
y_axis_treatment,
pixel_format,
ref data,
} => { } => {
let pixels = prepare_pixels(
format,
data_type,
size,
unpacking_alignment,
alpha_treatment,
y_axis_treatment,
pixel_format,
Cow::Borrowed(data),
);
ctx.gl() ctx.gl()
.pixel_store_i(gl::UNPACK_ALIGNMENT, unpacking_alignment as i32); .pixel_store_i(gl::UNPACK_ALIGNMENT, unpacking_alignment as i32);
ctx.gl().tex_sub_image_2d( ctx.gl().tex_sub_image_2d(
@ -1086,11 +1118,11 @@ impl WebGLImpl {
level as i32, level as i32,
xoffset, xoffset,
yoffset, yoffset,
width as i32, size.width as i32,
height as i32, size.height as i32,
format, format.as_gl_constant(),
data_type, effective_data_type,
&receiver.recv().unwrap(), &pixels,
); );
}, },
WebGLCommand::DrawingBufferWidth(ref sender) => sender WebGLCommand::DrawingBufferWidth(ref sender) => sender
@ -1703,3 +1735,345 @@ fn map_dot_separated<F: Fn(&str, &mut String)>(s: &str, f: F) -> String {
} }
mapped mapped
} }
fn prepare_pixels(
internal_format: TexFormat,
data_type: TexDataType,
size: Size2D<u32>,
unpacking_alignment: u32,
alpha_treatment: Option<AlphaTreatment>,
y_axis_treatment: YAxisTreatment,
pixel_format: Option<PixelFormat>,
mut pixels: Cow<[u8]>,
) -> Cow<[u8]> {
match alpha_treatment {
Some(AlphaTreatment::Premultiply) => {
if let Some(pixel_format) = pixel_format {
match pixel_format {
PixelFormat::BGRA8 | PixelFormat::RGBA8 => {},
_ => unimplemented!("unsupported pixel format ({:?})", pixel_format),
}
premultiply_inplace(TexFormat::RGBA, TexDataType::UnsignedByte, pixels.to_mut());
} else {
premultiply_inplace(internal_format, data_type, pixels.to_mut());
}
},
Some(AlphaTreatment::Unmultiply) => {
assert!(pixel_format.is_some());
unmultiply_inplace(pixels.to_mut());
},
None => {},
}
if let Some(pixel_format) = pixel_format {
pixels = image_to_tex_image_data(
pixel_format,
internal_format,
data_type,
pixels.into_owned(),
)
.into();
}
if y_axis_treatment == YAxisTreatment::Flipped {
// FINISHME: Consider doing premultiply and flip in a single mutable Vec.
pixels = flip_pixels_y(
internal_format,
data_type,
size.width as usize,
size.height as usize,
unpacking_alignment as usize,
pixels.into_owned(),
)
.into();
}
pixels
}
/// Translates an image in rgba8 (red in the first byte) format to
/// the format that was requested of TexImage.
fn image_to_tex_image_data(
pixel_format: PixelFormat,
format: TexFormat,
data_type: TexDataType,
mut pixels: Vec<u8>,
) -> Vec<u8> {
// hint for vector allocation sizing.
let pixel_count = pixels.len() / 4;
match pixel_format {
PixelFormat::BGRA8 => pixels::rgba8_byte_swap_colors_inplace(&mut pixels),
PixelFormat::RGBA8 => {},
_ => unimplemented!("unsupported pixel format ({:?})", pixel_format),
}
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),
}
}
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.
_ => {},
}
}
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.
fn flip_pixels_y(
internal_format: TexFormat,
data_type: TexDataType,
width: usize,
height: usize,
unpacking_alignment: usize,
pixels: Vec<u8>,
) -> Vec<u8> {
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
}

View file

@ -14,12 +14,10 @@ path = "lib.rs"
webgl_backtrace = [] webgl_backtrace = []
[dependencies] [dependencies]
byteorder = "1"
cssparser = "0.25" cssparser = "0.25"
euclid = "0.19" euclid = "0.19"
ipc-channel = "0.11" ipc-channel = "0.11"
gleam = "0.6.7" gleam = "0.6.7"
half = "1"
lazy_static = "1" lazy_static = "1"
malloc_size_of = { path = "../malloc_size_of" } malloc_size_of = { path = "../malloc_size_of" }
malloc_size_of_derive = { path = "../malloc_size_of_derive" } malloc_size_of_derive = { path = "../malloc_size_of_derive" }

View file

@ -4,7 +4,7 @@
use cssparser::RGBA; use cssparser::RGBA;
use euclid::{Point2D, Rect, Size2D, Transform2D}; use euclid::{Point2D, Rect, Size2D, Transform2D};
use ipc_channel::ipc::{IpcBytesReceiver, IpcBytesSender, IpcSender}; use ipc_channel::ipc::{IpcBytesReceiver, IpcBytesSender, IpcSender, IpcSharedMemory};
use serde_bytes::ByteBuf; use serde_bytes::ByteBuf;
use std::default::Default; use std::default::Default;
use std::str::FromStr; use std::str::FromStr;
@ -87,7 +87,7 @@ pub enum FromLayoutMsg {
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug, Deserialize, Serialize)]
pub enum FromScriptMsg { pub enum FromScriptMsg {
SendPixels(IpcSender<Option<ByteBuf>>), SendPixels(IpcSender<IpcSharedMemory>),
} }
#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)] #[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]

View file

@ -2,13 +2,11 @@
* 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 https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use byteorder::{ByteOrder, NativeEndian, WriteBytesExt};
use euclid::{Rect, Size2D}; use euclid::{Rect, Size2D};
use gleam::gl; use gleam::gl;
use half::f16; use ipc_channel::ipc::{IpcBytesReceiver, IpcBytesSender, IpcSharedMemory};
use ipc_channel::ipc::{IpcBytesReceiver, IpcBytesSender};
use offscreen_gl_context::{GLContextAttributes, GLLimits}; use offscreen_gl_context::{GLContextAttributes, GLLimits};
use pixels; use pixels::PixelFormat;
use serde_bytes::ByteBuf; use serde_bytes::ByteBuf;
use std::borrow::Cow; use std::borrow::Cow;
use std::num::NonZeroU32; use std::num::NonZeroU32;
@ -275,25 +273,34 @@ pub enum WebGLCommand {
TexImage2D { TexImage2D {
target: u32, target: u32,
level: u32, level: u32,
internal_format: u32, // FIXME(nox): This should be computed on the WebGL thread.
width: u32, effective_internal_format: u32,
height: u32, size: Size2D<u32>,
format: u32, format: TexFormat,
data_type: u32, data_type: TexDataType,
// FIXME(nox): This should be computed on the WebGL thread.
effective_data_type: u32,
unpacking_alignment: u32, unpacking_alignment: u32,
receiver: IpcBytesReceiver, alpha_treatment: Option<AlphaTreatment>,
y_axis_treatment: YAxisTreatment,
pixel_format: Option<PixelFormat>,
data: IpcSharedMemory,
}, },
TexSubImage2D { TexSubImage2D {
target: u32, target: u32,
level: u32, level: u32,
xoffset: i32, xoffset: i32,
yoffset: i32, yoffset: i32,
width: u32, size: Size2D<u32>,
height: u32, format: TexFormat,
format: u32, data_type: TexDataType,
data_type: u32, // FIXME(nox): This should be computed on the WebGL thread.
effective_data_type: u32,
unpacking_alignment: u32, unpacking_alignment: u32,
receiver: IpcBytesReceiver, alpha_treatment: Option<AlphaTreatment>,
y_axis_treatment: YAxisTreatment,
pixel_format: Option<PixelFormat>,
data: IpcSharedMemory,
}, },
DrawingBufferWidth(WebGLSender<i32>), DrawingBufferWidth(WebGLSender<i32>),
DrawingBufferHeight(WebGLSender<i32>), DrawingBufferHeight(WebGLSender<i32>),
@ -673,7 +680,8 @@ pub fn is_gles() -> bool {
macro_rules! gl_enums { macro_rules! gl_enums {
($(pub enum $name:ident { $($variant:ident = $mod:ident::$constant:ident,)+ })*) => { ($(pub enum $name:ident { $($variant:ident = $mod:ident::$constant:ident,)+ })*) => {
$( $(
#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq)] #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf)]
#[derive(PartialEq, Serialize)]
#[repr(u32)] #[repr(u32)]
pub enum $name { $($variant = $mod::$constant,)+ } pub enum $name { $($variant = $mod::$constant,)+ }
@ -757,300 +765,14 @@ impl TexDataType {
} }
} }
#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq)] #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
pub enum AlphaTreatment { pub enum AlphaTreatment {
Premultiply, Premultiply,
Unmultiply, Unmultiply,
} }
#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq)] #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
pub enum YAxisTreatment { pub enum YAxisTreatment {
AsIs, AsIs,
Flipped, 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<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),
}
}
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<u8>,
) -> Vec<u8> {
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
}

View file

@ -13,6 +13,7 @@ path = "lib.rs"
[features] [features]
default = [] default = []
gl = ["gleam", "pixels"]
[dependencies] [dependencies]
crossbeam-channel = "0.3" crossbeam-channel = "0.3"
@ -27,6 +28,7 @@ keyboard-types = "0.4.3"
log = "0.4" log = "0.4"
msg = {path = "../msg"} msg = {path = "../msg"}
net_traits = {path = "../net_traits"} net_traits = {path = "../net_traits"}
pixels = {path = "../pixels", optional = true}
profile_traits = {path = "../profile_traits"} profile_traits = {path = "../profile_traits"}
script_traits = {path = "../script_traits"} script_traits = {path = "../script_traits"}
servo_config = {path = "../config"} servo_config = {path = "../config"}

View file

@ -4,7 +4,7 @@
use crate::compositor_thread::{CompositorProxy, CompositorReceiver}; use crate::compositor_thread::{CompositorProxy, CompositorReceiver};
use crate::compositor_thread::{InitialCompositorState, Msg}; use crate::compositor_thread::{InitialCompositorState, Msg};
#[cfg(feature = "gleam")] #[cfg(feature = "gl")]
use crate::gl; use crate::gl;
use crate::touch::{TouchAction, TouchHandler}; use crate::touch::{TouchAction, TouchHandler};
use crate::windowing::{ use crate::windowing::{
@ -15,14 +15,14 @@ use crate::SendableFrameTree;
use crossbeam_channel::Sender; use crossbeam_channel::Sender;
use euclid::{TypedPoint2D, TypedScale, TypedVector2D}; use euclid::{TypedPoint2D, TypedScale, TypedVector2D};
use gfx_traits::Epoch; use gfx_traits::Epoch;
#[cfg(feature = "gleam")] #[cfg(feature = "gl")]
use image::{DynamicImage, ImageFormat}; use image::{DynamicImage, ImageFormat};
use ipc_channel::ipc; use ipc_channel::ipc;
use libc::c_void; use libc::c_void;
use msg::constellation_msg::{PipelineId, PipelineIndex, PipelineNamespaceId}; use msg::constellation_msg::{PipelineId, PipelineIndex, PipelineNamespaceId};
use net_traits::image::base::Image; use net_traits::image::base::Image;
#[cfg(feature = "gleam")] #[cfg(feature = "gl")]
use net_traits::image::base::PixelFormat; use pixels::PixelFormat;
use profile_traits::time::{self as profile_time, profile, ProfilerCategory}; use profile_traits::time::{self as profile_time, profile, ProfilerCategory};
use script_traits::CompositorEvent::{MouseButtonEvent, MouseMoveEvent, TouchEvent}; use script_traits::CompositorEvent::{MouseButtonEvent, MouseMoveEvent, TouchEvent};
use script_traits::{AnimationState, AnimationTickType, ConstellationMsg, LayoutControlMsg}; use script_traits::{AnimationState, AnimationTickType, ConstellationMsg, LayoutControlMsg};
@ -1211,13 +1211,13 @@ impl<Window: WindowMethods> IOCompositor<Window> {
} }
let rt_info = match target { let rt_info = match target {
#[cfg(feature = "gleam")] #[cfg(feature = "gl")]
CompositeTarget::Window => gl::RenderTargetInfo::default(), CompositeTarget::Window => gl::RenderTargetInfo::default(),
#[cfg(feature = "gleam")] #[cfg(feature = "gl")]
CompositeTarget::WindowAndPng | CompositeTarget::PngFile => { CompositeTarget::WindowAndPng | CompositeTarget::PngFile => {
gl::initialize_png(&*self.window.gl(), width, height) gl::initialize_png(&*self.window.gl(), width, height)
}, },
#[cfg(not(feature = "gleam"))] #[cfg(not(feature = "gl"))]
_ => (), _ => (),
}; };
@ -1272,7 +1272,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
let rv = match target { let rv = match target {
CompositeTarget::Window => None, CompositeTarget::Window => None,
#[cfg(feature = "gleam")] #[cfg(feature = "gl")]
CompositeTarget::WindowAndPng => { CompositeTarget::WindowAndPng => {
let img = gl::draw_img(&*self.window.gl(), rt_info, width, height); let img = gl::draw_img(&*self.window.gl(), rt_info, width, height);
Some(Image { Some(Image {
@ -1283,7 +1283,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
id: None, id: None,
}) })
}, },
#[cfg(feature = "gleam")] #[cfg(feature = "gl")]
CompositeTarget::PngFile => { CompositeTarget::PngFile => {
let gl = &*self.window.gl(); let gl = &*self.window.gl();
profile( profile(
@ -1307,7 +1307,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
); );
None None
}, },
#[cfg(not(feature = "gleam"))] #[cfg(not(feature = "gl"))]
_ => None, _ => None,
}; };

View file

@ -20,7 +20,7 @@ use style_traits::CSSPixel;
mod compositor; mod compositor;
pub mod compositor_thread; pub mod compositor_thread;
#[cfg(feature = "gleam")] #[cfg(feature = "gl")]
mod gl; mod gl;
mod touch; mod touch;
pub mod windowing; pub mod windowing;

View file

@ -6,7 +6,7 @@
use embedder_traits::EventLoopWaker; use embedder_traits::EventLoopWaker;
use euclid::TypedScale; use euclid::TypedScale;
#[cfg(feature = "gleam")] #[cfg(feature = "gl")]
use gleam::gl; use gleam::gl;
use keyboard_types::KeyboardEvent; use keyboard_types::KeyboardEvent;
use msg::constellation_msg::{TopLevelBrowsingContextId, TraversalDirection}; use msg::constellation_msg::{TopLevelBrowsingContextId, TraversalDirection};
@ -14,7 +14,7 @@ use script_traits::{MouseButton, TouchEventType, TouchId};
use servo_geometry::DeviceIndependentPixel; use servo_geometry::DeviceIndependentPixel;
use servo_url::ServoUrl; use servo_url::ServoUrl;
use std::fmt::{Debug, Error, Formatter}; use std::fmt::{Debug, Error, Formatter};
#[cfg(feature = "gleam")] #[cfg(feature = "gl")]
use std::rc::Rc; use std::rc::Rc;
use style_traits::DevicePixel; use style_traits::DevicePixel;
use webrender_api::{DeviceIntPoint, DevicePoint, DeviceUintRect, DeviceUintSize, ScrollLocation}; use webrender_api::{DeviceIntPoint, DevicePoint, DeviceUintRect, DeviceUintSize, ScrollLocation};
@ -131,7 +131,7 @@ pub trait WindowMethods {
/// proceed and false if it should not. /// proceed and false if it should not.
fn prepare_for_composite(&self) -> bool; fn prepare_for_composite(&self) -> bool;
/// Return the GL function pointer trait. /// Return the GL function pointer trait.
#[cfg(feature = "gleam")] #[cfg(feature = "gl")]
fn gl(&self) -> Rc<dyn gl::Gl>; fn gl(&self) -> Rc<dyn gl::Gl>;
/// Returns a thread-safe object to wake up the window's event loop. /// Returns a thread-safe object to wake up the window's event loop.
fn create_event_loop_waker(&self) -> Box<dyn EventLoopWaker>; fn create_event_loop_waker(&self) -> Box<dyn EventLoopWaker>;

View file

@ -4,11 +4,12 @@
use embedder_traits::resources::{self, Resource}; use embedder_traits::resources::{self, Resource};
use immeta::load_from_buf; use immeta::load_from_buf;
use net_traits::image::base::{load_from_memory, Image, ImageMetadata, PixelFormat}; use net_traits::image::base::{load_from_memory, Image, ImageMetadata};
use net_traits::image_cache::{CanRequestImages, ImageCache, ImageResponder}; use net_traits::image_cache::{CanRequestImages, ImageCache, ImageResponder};
use net_traits::image_cache::{ImageOrMetadataAvailable, ImageResponse, ImageState}; use net_traits::image_cache::{ImageOrMetadataAvailable, ImageResponse, ImageState};
use net_traits::image_cache::{PendingImageId, UsePlaceholder}; use net_traits::image_cache::{PendingImageId, UsePlaceholder};
use net_traits::{FetchMetadata, FetchResponseMsg, NetworkError}; use net_traits::{FetchMetadata, FetchResponseMsg, NetworkError};
use pixels::PixelFormat;
use servo_url::ServoUrl; use servo_url::ServoUrl;
use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::collections::HashMap; use std::collections::HashMap;
@ -66,7 +67,7 @@ fn set_webrender_image_key(webrender_api: &webrender_api::RenderApi, image: &mut
true true
}, },
PixelFormat::K8 | PixelFormat::KA8 => { PixelFormat::K8 | PixelFormat::KA8 | PixelFormat::RGBA8 => {
panic!("Not support by webrender yet"); panic!("Not support by webrender yet");
}, },
}; };

View file

@ -4,20 +4,9 @@
use ipc_channel::ipc::IpcSharedMemory; use ipc_channel::ipc::IpcSharedMemory;
use piston_image::{DynamicImage, ImageFormat}; use piston_image::{DynamicImage, ImageFormat};
use pixels::PixelFormat;
use std::fmt; use std::fmt;
#[derive(Clone, Copy, Debug, Deserialize, Eq, MallocSizeOf, PartialEq, Serialize)]
pub enum PixelFormat {
/// Luminance channel only
K8,
/// Luminance + alpha
KA8,
/// RGB, 8 bits per channel
RGB8,
/// RGB + alpha, 8 bits per channel
BGRA8,
}
#[derive(Clone, Deserialize, MallocSizeOf, Serialize)] #[derive(Clone, Deserialize, MallocSizeOf, Serialize)]
pub struct Image { pub struct Image {
pub width: u32, pub width: u32,

View file

@ -12,3 +12,6 @@ path = "lib.rs"
[dependencies] [dependencies]
euclid = "0.19" euclid = "0.19"
malloc_size_of = {path = "../malloc_size_of"}
malloc_size_of_derive = {path = "../malloc_size_of_derive"}
serde = {version = "1", features = ["derive"]}

View file

@ -2,9 +2,27 @@
* 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 https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
#[macro_use]
extern crate serde;
use euclid::{Point2D, Rect, Size2D}; use euclid::{Point2D, Rect, Size2D};
use malloc_size_of_derive::MallocSizeOf;
use std::borrow::Cow; use std::borrow::Cow;
#[derive(Clone, Copy, Debug, Deserialize, Eq, MallocSizeOf, PartialEq, Serialize)]
pub enum PixelFormat {
/// Luminance channel only
K8,
/// Luminance + alpha
KA8,
/// RGB, 8 bits per channel
RGB8,
/// RGB + alpha, 8 bits per channel
RGBA8,
/// BGR + alpha, 8 bits per channel
BGRA8,
}
pub fn rgba8_get_rect(pixels: &[u8], size: Size2D<u32>, rect: Rect<u32>) -> Cow<[u8]> { pub fn rgba8_get_rect(pixels: &[u8], size: Size2D<u32>, rect: Rect<u32>) -> Cow<[u8]> {
assert!(!rect.is_empty()); assert!(!rect.is_empty());
assert!(Rect::from_size(size).contains_rect(&rect)); assert!(Rect::from_size(size).contains_rect(&rect));

View file

@ -89,7 +89,7 @@ script_layout_interface = {path = "../script_layout_interface"}
script_plugins = {path = "../script_plugins"} script_plugins = {path = "../script_plugins"}
script_traits = {path = "../script_traits"} script_traits = {path = "../script_traits"}
selectors = { path = "../selectors" } selectors = { path = "../selectors" }
serde = "1.0" serde = {version = "1", features = ["derive"]}
serde_bytes = "0.10" serde_bytes = "0.10"
servo_allocator = {path = "../allocator"} servo_allocator = {path = "../allocator"}
servo_arc = {path = "../servo_arc"} servo_arc = {path = "../servo_arc"}

View file

@ -34,13 +34,13 @@ use cssparser::{Parser, ParserInput, RGBA};
use dom_struct::dom_struct; use dom_struct::dom_struct;
use euclid::{vec2, Point2D, Rect, Size2D, Transform2D}; use euclid::{vec2, Point2D, Rect, Size2D, Transform2D};
use ipc_channel::ipc::{self, IpcSender}; use ipc_channel::ipc::{self, IpcSender};
use net_traits::image::base::PixelFormat;
use net_traits::image_cache::CanRequestImages; use net_traits::image_cache::CanRequestImages;
use net_traits::image_cache::ImageCache; use net_traits::image_cache::ImageCache;
use net_traits::image_cache::ImageOrMetadataAvailable; use net_traits::image_cache::ImageOrMetadataAvailable;
use net_traits::image_cache::ImageResponse; use net_traits::image_cache::ImageResponse;
use net_traits::image_cache::ImageState; use net_traits::image_cache::ImageState;
use net_traits::image_cache::UsePlaceholder; use net_traits::image_cache::UsePlaceholder;
use pixels::PixelFormat;
use profile_traits::ipc as profiled_ipc; use profile_traits::ipc as profiled_ipc;
use script_traits::ScriptMsg; use script_traits::ScriptMsg;
use servo_url::ServoUrl; use servo_url::ServoUrl;
@ -444,9 +444,7 @@ impl CanvasRenderingContext2D {
let image_size = Size2D::new(img.width, img.height); let image_size = Size2D::new(img.width, img.height);
let image_data = match img.format { let image_data = match img.format {
PixelFormat::BGRA8 => img.bytes.to_vec(), PixelFormat::BGRA8 => img.bytes.to_vec(),
PixelFormat::K8 => panic!("K8 color type not supported"), pixel_format => unimplemented!("unsupported pixel format ({:?})", pixel_format),
PixelFormat::RGB8 => panic!("RGB8 color type not supported"),
PixelFormat::KA8 => panic!("KA8 color type not supported"),
}; };
Some((image_data, image_size)) Some((image_data, image_size))
@ -1298,7 +1296,11 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
.ok_or(Error::InvalidState)? .ok_or(Error::InvalidState)?
}, },
CanvasImageSource::HTMLCanvasElement(ref canvas) => { CanvasImageSource::HTMLCanvasElement(ref canvas) => {
canvas.fetch_all_data().ok_or(Error::InvalidState)? let (data, size) = canvas.fetch_all_data().ok_or(Error::InvalidState)?;
let data = data
.map(|data| data.to_vec())
.unwrap_or_else(|| vec![0; size.area() as usize * 4]);
(data, size)
}, },
CanvasImageSource::CSSStyleValue(ref value) => value CanvasImageSource::CSSStyleValue(ref value) => value
.get_url(self.base_url.clone()) .get_url(self.base_url.clone())

View file

@ -36,6 +36,7 @@ use euclid::{Rect, Size2D};
use html5ever::{LocalName, Prefix}; use html5ever::{LocalName, Prefix};
use image::png::PNGEncoder; use image::png::PNGEncoder;
use image::ColorType; use image::ColorType;
use ipc_channel::ipc::IpcSharedMemory;
use js::error::throw_type_error; use js::error::throw_type_error;
use js::jsapi::JSContext; use js::jsapi::JSContext;
use js::rust::HandleValue; use js::rust::HandleValue;
@ -280,7 +281,7 @@ impl HTMLCanvasElement {
self.Height() != 0 && self.Width() != 0 self.Height() != 0 && self.Width() != 0
} }
pub fn fetch_all_data(&self) -> Option<(Vec<u8>, Size2D<u32>)> { pub fn fetch_all_data(&self) -> Option<(Option<IpcSharedMemory>, Size2D<u32>)> {
let size = self.get_size(); let size = self.get_size();
if size.width == 0 || size.height == 0 { if size.width == 0 || size.height == 0 {
@ -297,7 +298,7 @@ impl HTMLCanvasElement {
); );
context.get_ipc_renderer().send(msg).unwrap(); context.get_ipc_renderer().send(msg).unwrap();
receiver.recv().unwrap()?.into() Some(receiver.recv().unwrap())
}, },
Some(&CanvasContext::WebGL(_)) => { Some(&CanvasContext::WebGL(_)) => {
// TODO: add a method in WebGLRenderingContext to get the pixels. // TODO: add a method in WebGLRenderingContext to get the pixels.
@ -307,7 +308,7 @@ impl HTMLCanvasElement {
// TODO: add a method in WebGL2RenderingContext to get the pixels. // TODO: add a method in WebGL2RenderingContext to get the pixels.
return None; return None;
}, },
None => vec![0; size.height as usize * size.width as usize * 4], None => None,
}; };
Some((data, size)) Some((data, size))

View file

@ -10,6 +10,7 @@ use crate::dom::bindings::root::DomRoot;
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use euclid::{Rect, Size2D}; use euclid::{Rect, Size2D};
use ipc_channel::ipc::IpcSharedMemory;
use js::jsapi::{Heap, JSContext, JSObject}; use js::jsapi::{Heap, JSContext, JSObject};
use js::rust::Runtime; use js::rust::Runtime;
use js::typedarray::{CreateWith, Uint8ClampedArray}; use js::typedarray::{CreateWith, Uint8ClampedArray};
@ -156,8 +157,8 @@ impl ImageData {
} }
#[allow(unsafe_code)] #[allow(unsafe_code)]
pub fn to_vec(&self) -> Vec<u8> { pub fn to_shared_memory(&self) -> IpcSharedMemory {
unsafe { self.as_slice().into() } IpcSharedMemory::from_bytes(unsafe { self.as_slice() })
} }
#[allow(unsafe_code)] #[allow(unsafe_code)]

View file

@ -44,8 +44,8 @@ use js::rust::wrappers::Construct1;
use js::rust::HandleValue; use js::rust::HandleValue;
use js::rust::Runtime; use js::rust::Runtime;
use msg::constellation_msg::PipelineId; use msg::constellation_msg::PipelineId;
use net_traits::image::base::PixelFormat;
use net_traits::image_cache::ImageCache; use net_traits::image_cache::ImageCache;
use pixels::PixelFormat;
use profile_traits::ipc; use profile_traits::ipc;
use script_traits::Painter; use script_traits::Painter;
use script_traits::{DrawAPaintImageResult, PaintWorkletError}; use script_traits::{DrawAPaintImageResult, PaintWorkletError};

View file

@ -6,10 +6,10 @@
use backtrace::Backtrace; use backtrace::Backtrace;
use canvas_traits::webgl::WebGLError::*; use canvas_traits::webgl::WebGLError::*;
use canvas_traits::webgl::{ use canvas_traits::webgl::{
self, webgl_channel, AlphaTreatment, DOMToTextureCommand, Parameter, TexDataType, TexFormat, webgl_channel, AlphaTreatment, DOMToTextureCommand, Parameter, TexDataType, TexFormat,
TexParameter, TexSource, WebGLCommand, WebGLCommandBacktrace, WebGLContextShareMode, TexParameter, WebGLCommand, WebGLCommandBacktrace, WebGLContextShareMode, WebGLError,
WebGLError, WebGLFramebufferBindingRequest, WebGLMsg, WebGLMsgSender, WebGLProgramId, WebGLFramebufferBindingRequest, WebGLMsg, WebGLMsgSender, WebGLProgramId, WebGLResult,
WebGLResult, WebGLSLVersion, WebGLSender, WebGLVersion, WebVRCommand, YAxisTreatment, WebGLSLVersion, WebGLSender, WebGLVersion, WebVRCommand, YAxisTreatment,
}; };
use crate::dom::bindings::codegen::Bindings::ANGLEInstancedArraysBinding::ANGLEInstancedArraysConstants; use crate::dom::bindings::codegen::Bindings::ANGLEInstancedArraysBinding::ANGLEInstancedArraysConstants;
use crate::dom::bindings::codegen::Bindings::EXTBlendMinmaxBinding::EXTBlendMinmaxConstants; use crate::dom::bindings::codegen::Bindings::EXTBlendMinmaxBinding::EXTBlendMinmaxConstants;
@ -57,7 +57,7 @@ use crate::dom::webglvertexarrayobjectoes::WebGLVertexArrayObjectOES;
use crate::dom::window::Window; use crate::dom::window::Window;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use euclid::{Point2D, Rect, Size2D}; use euclid::{Point2D, Rect, Size2D};
use ipc_channel::ipc; use ipc_channel::ipc::{self, IpcSharedMemory};
use js::jsapi::{JSContext, JSObject, Type}; use js::jsapi::{JSContext, JSObject, Type};
use js::jsval::{BooleanValue, DoubleValue, Int32Value, JSVal, UInt32Value}; use js::jsval::{BooleanValue, DoubleValue, Int32Value, JSVal, UInt32Value};
use js::jsval::{NullValue, ObjectValue, UndefinedValue}; use js::jsval::{NullValue, ObjectValue, UndefinedValue};
@ -66,10 +66,9 @@ use js::typedarray::{
ArrayBufferView, CreateWith, Float32, Float32Array, Int32, Int32Array, Uint32Array, ArrayBufferView, CreateWith, Float32, Float32Array, Int32, Int32Array, Uint32Array,
}; };
use js::typedarray::{TypedArray, TypedArrayElementCreator}; use js::typedarray::{TypedArray, TypedArrayElementCreator};
use net_traits::image::base::PixelFormat;
use net_traits::image_cache::ImageResponse; use net_traits::image_cache::ImageResponse;
use offscreen_gl_context::{GLContextAttributes, GLLimits}; use offscreen_gl_context::{GLContextAttributes, GLLimits};
use pixels; use pixels::{self, PixelFormat};
use script_layout_interface::HTMLCanvasDataSource; use script_layout_interface::HTMLCanvasDataSource;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use servo_config::prefs::PREFS; use servo_config::prefs::PREFS;
@ -505,8 +504,12 @@ impl WebGLRenderingContext {
level, level,
0, 0,
1, 1,
TexSource::FromHtmlElement, TexPixels::new(
TexPixels::new(pixels, size, true), IpcSharedMemory::from_bytes(&pixels),
size,
PixelFormat::RGBA8,
true,
),
); );
false false
@ -528,9 +531,12 @@ impl WebGLRenderingContext {
fn get_image_pixels(&self, source: TexImageSource) -> Fallible<Option<TexPixels>> { fn get_image_pixels(&self, source: TexImageSource) -> Fallible<Option<TexPixels>> {
Ok(Some(match source { Ok(Some(match source {
TexImageSource::ImageData(image_data) => { TexImageSource::ImageData(image_data) => TexPixels::new(
TexPixels::new(image_data.to_vec(), image_data.get_size(), false) image_data.to_shared_memory(),
}, image_data.get_size(),
PixelFormat::RGBA8,
false,
),
TexImageSource::HTMLImageElement(image) => { TexImageSource::HTMLImageElement(image) => {
let document = document_from_node(&*self.canvas); let document = document_from_node(&*self.canvas);
if !image.same_origin(document.origin()) { if !image.same_origin(document.origin()) {
@ -553,15 +559,7 @@ impl WebGLRenderingContext {
let size = Size2D::new(img.width, img.height); let size = Size2D::new(img.width, img.height);
// For now Servo's images are all stored as BGRA8 internally. TexPixels::new(img.bytes.clone(), size, img.format, false)
let mut data = match img.format {
PixelFormat::BGRA8 => img.bytes.to_vec(),
_ => unimplemented!(),
};
pixels::rgba8_byte_swap_colors_inplace(&mut data);
TexPixels::new(data, size, false)
}, },
// TODO(emilio): Getting canvas data is implemented in CanvasRenderingContext2D, // TODO(emilio): Getting canvas data is implemented in CanvasRenderingContext2D,
// but we need to refactor it moving it to `HTMLCanvasElement` and support // but we need to refactor it moving it to `HTMLCanvasElement` and support
@ -570,10 +568,11 @@ impl WebGLRenderingContext {
if !canvas.origin_is_clean() { if !canvas.origin_is_clean() {
return Err(Error::Security); return Err(Error::Security);
} }
if let Some((mut data, size)) = canvas.fetch_all_data() { if let Some((data, size)) = canvas.fetch_all_data() {
// Pixels got from Canvas have already alpha premultiplied let data = data.unwrap_or_else(|| {
pixels::rgba8_byte_swap_colors_inplace(&mut data); IpcSharedMemory::from_bytes(&vec![0; size.area() as usize * 4])
TexPixels::new(data, size, true) });
TexPixels::new(data, size, PixelFormat::BGRA8, true)
} else { } else {
return Ok(None); return Ok(None);
} }
@ -638,67 +637,31 @@ impl WebGLRenderingContext {
} }
} }
fn prepare_pixels(
&self,
internal_format: TexFormat,
data_type: TexDataType,
size: Size2D<u32>,
unpacking_alignment: u32,
alpha_treatment: Option<AlphaTreatment>,
y_axis_treatment: YAxisTreatment,
tex_source: TexSource,
mut pixels: Vec<u8>,
) -> Vec<u8> {
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 tex_source == TexSource::FromHtmlElement {
pixels = webgl::rgba8_image_to_tex_image_data(internal_format, data_type, pixels);
}
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( fn tex_image_2d(
&self, &self,
texture: &WebGLTexture, texture: &WebGLTexture,
target: TexImageTarget, target: TexImageTarget,
data_type: TexDataType, data_type: TexDataType,
internal_format: TexFormat, format: TexFormat,
level: u32, level: u32,
_border: u32, _border: u32,
unpacking_alignment: u32, unpacking_alignment: u32,
tex_source: TexSource,
pixels: TexPixels, pixels: TexPixels,
) { ) {
// TexImage2D depth is always equal to 1.
handle_potential_webgl_error!(
self,
texture.initialize(
target,
pixels.size.width,
pixels.size.height,
1,
format,
level,
Some(data_type)
)
);
let settings = self.texture_unpacking_settings.get(); let settings = self.texture_unpacking_settings.get();
let dest_premultiplied = settings.contains(TextureUnpacking::PREMULTIPLY_ALPHA); let dest_premultiplied = settings.contains(TextureUnpacking::PREMULTIPLY_ALPHA);
@ -714,51 +677,28 @@ impl WebGLRenderingContext {
YAxisTreatment::AsIs YAxisTreatment::AsIs
}; };
let buff = self.prepare_pixels( let effective_internal_format = self
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,
pixels.size.width,
pixels.size.height,
1,
internal_format,
level,
Some(data_type)
)
);
let format = internal_format.as_gl_constant();
let data_type = data_type.as_gl_constant();
let internal_format = self
.extension_manager .extension_manager
.get_effective_tex_internal_format(format, data_type); .get_effective_tex_internal_format(format.as_gl_constant(), data_type.as_gl_constant());
let effective_data_type = self
.extension_manager
.effective_type(data_type.as_gl_constant());
// TODO(emilio): convert colorspace if requested // TODO(emilio): convert colorspace if requested.
let (sender, receiver) = ipc::bytes_channel().unwrap();
self.send_command(WebGLCommand::TexImage2D { self.send_command(WebGLCommand::TexImage2D {
target: target.as_gl_constant(), target: target.as_gl_constant(),
level, level,
internal_format, effective_internal_format,
width: pixels.size.width, size: pixels.size,
height: pixels.size.height,
format, format,
data_type: self.extension_manager.effective_type(data_type), data_type,
effective_data_type,
unpacking_alignment, unpacking_alignment,
receiver, alpha_treatment,
y_axis_treatment,
pixel_format: pixels.pixel_format,
data: pixels.data,
}); });
sender.send(&buff).unwrap();
if let Some(fb) = self.bound_framebuffer.get() { if let Some(fb) = self.bound_framebuffer.get() {
fb.invalidate_texture(&*texture); fb.invalidate_texture(&*texture);
@ -775,37 +715,8 @@ impl WebGLRenderingContext {
format: TexFormat, format: TexFormat,
data_type: TexDataType, data_type: TexDataType,
unpacking_alignment: u32, unpacking_alignment: u32,
tex_source: TexSource,
pixels: TexPixels, 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 // We have already validated level
let image_info = texture.image_info_for_target(&target, level); let image_info = texture.image_info_for_target(&target, level);
@ -828,23 +739,41 @@ impl WebGLRenderingContext {
return self.webgl_error(InvalidOperation); return self.webgl_error(InvalidOperation);
} }
// TODO(emilio): convert colorspace if requested let settings = self.texture_unpacking_settings.get();
let (sender, receiver) = ipc::bytes_channel().unwrap(); 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 effective_data_type = self
.extension_manager
.effective_type(data_type.as_gl_constant());
// TODO(emilio): convert colorspace if requested.
self.send_command(WebGLCommand::TexSubImage2D { self.send_command(WebGLCommand::TexSubImage2D {
target: target.as_gl_constant(), target: target.as_gl_constant(),
level, level,
xoffset, xoffset,
yoffset, yoffset,
width: pixels.size.width, size: pixels.size,
height: pixels.size.height, format,
format: format.as_gl_constant(), data_type,
data_type: self effective_data_type,
.extension_manager
.effective_type(data_type.as_gl_constant()),
unpacking_alignment, unpacking_alignment,
receiver, alpha_treatment,
y_axis_treatment,
pixel_format: pixels.pixel_format,
data: pixels.data,
}); });
sender.send(&buff).unwrap();
} }
fn get_gl_extensions(&self) -> String { fn get_gl_extensions(&self) -> String {
@ -3623,6 +3552,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
} }
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8 // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
#[allow(unsafe_code)]
fn TexImage2D( fn TexImage2D(
&self, &self,
target: u32, target: u32,
@ -3684,8 +3614,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
// If data is null, a buffer of sufficient size // If data is null, a buffer of sufficient size
// initialized to 0 is passed. // initialized to 0 is passed.
let buff = match *pixels { let buff = match *pixels {
None => vec![0u8; expected_byte_length as usize], None => IpcSharedMemory::from_bytes(&vec![0u8; expected_byte_length as usize]),
Some(ref data) => data.to_vec(), Some(ref data) => IpcSharedMemory::from_bytes(unsafe { data.as_slice() }),
}; };
// From the WebGL spec: // From the WebGL spec:
@ -3714,7 +3644,6 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
level, level,
border, border,
unpacking_alignment, unpacking_alignment,
TexSource::FromArray,
TexPixels::from_array(buff, Size2D::new(width, height)), TexPixels::from_array(buff, Size2D::new(width, height)),
); );
@ -3779,15 +3708,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
} }
self.tex_image_2d( self.tex_image_2d(
&texture, &texture, target, data_type, format, level, border, 1, pixels,
target,
data_type,
format,
level,
border,
1,
TexSource::FromHtmlElement,
pixels,
); );
Ok(()) Ok(())
} }
@ -3847,6 +3768,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
} }
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8 // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
#[allow(unsafe_code)]
fn TexSubImage2D( fn TexSubImage2D(
&self, &self,
target: u32, target: u32,
@ -3892,11 +3814,12 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
Err(()) => return Ok(()), Err(()) => return Ok(()),
}; };
// If data is null, a buffer of sufficient size
// initialized to 0 is passed.
let buff = handle_potential_webgl_error!( let buff = handle_potential_webgl_error!(
self, self,
pixels.as_ref().map(|p| p.to_vec()).ok_or(InvalidValue), pixels
.as_ref()
.map(|p| IpcSharedMemory::from_bytes(unsafe { p.as_slice() }))
.ok_or(InvalidValue),
return Ok(()) return Ok(())
); );
@ -3919,7 +3842,6 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
format, format,
data_type, data_type,
unpacking_alignment, unpacking_alignment,
TexSource::FromArray,
TexPixels::from_array(buff, Size2D::new(width, height)), TexPixels::from_array(buff, Size2D::new(width, height)),
); );
Ok(()) Ok(())
@ -3965,16 +3887,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
}; };
self.tex_sub_image_2d( self.tex_sub_image_2d(
texture, texture, target, level, xoffset, yoffset, format, data_type, 1, pixels,
target,
level,
xoffset,
yoffset,
format,
data_type,
1,
TexSource::FromHtmlElement,
pixels,
); );
Ok(()) Ok(())
} }
@ -4257,24 +4170,32 @@ impl TextureUnit {
} }
struct TexPixels { struct TexPixels {
data: Vec<u8>, data: IpcSharedMemory,
size: Size2D<u32>, size: Size2D<u32>,
pixel_format: Option<PixelFormat>,
premultiplied: bool, premultiplied: bool,
} }
impl TexPixels { impl TexPixels {
fn new(data: Vec<u8>, size: Size2D<u32>, premultiplied: bool) -> Self { fn new(
data: IpcSharedMemory,
size: Size2D<u32>,
pixel_format: PixelFormat,
premultiplied: bool,
) -> Self {
Self { Self {
data, data,
size, size,
pixel_format: Some(pixel_format),
premultiplied, premultiplied,
} }
} }
fn from_array(data: Vec<u8>, size: Size2D<u32>) -> Self { fn from_array(data: IpcSharedMemory, size: Size2D<u32>) -> Self {
Self { Self {
data, data,
size, size,
pixel_format: None,
premultiplied: false, premultiplied: false,
} }
} }

View file

@ -44,6 +44,8 @@ extern crate malloc_size_of_derive;
#[macro_use] #[macro_use]
extern crate profile_traits; extern crate profile_traits;
#[macro_use] #[macro_use]
extern crate serde;
#[macro_use]
extern crate servo_atoms; extern crate servo_atoms;
#[macro_use] #[macro_use]
extern crate style; extern crate style;

View file

@ -29,6 +29,7 @@ malloc_size_of = { path = "../malloc_size_of" }
malloc_size_of_derive = { path = "../malloc_size_of_derive" } malloc_size_of_derive = { path = "../malloc_size_of_derive" }
msg = {path = "../msg"} msg = {path = "../msg"}
net_traits = {path = "../net_traits"} net_traits = {path = "../net_traits"}
pixels = {path = "../pixels"}
profile_traits = {path = "../profile_traits"} profile_traits = {path = "../profile_traits"}
serde = "1.0" serde = "1.0"
servo_atoms = {path = "../atoms"} servo_atoms = {path = "../atoms"}

View file

@ -36,10 +36,10 @@ use libc::c_void;
use msg::constellation_msg::{BrowsingContextId, HistoryStateId, PipelineId}; use msg::constellation_msg::{BrowsingContextId, HistoryStateId, PipelineId};
use msg::constellation_msg::{PipelineNamespaceId, TopLevelBrowsingContextId, TraversalDirection}; use msg::constellation_msg::{PipelineNamespaceId, TopLevelBrowsingContextId, TraversalDirection};
use net_traits::image::base::Image; use net_traits::image::base::Image;
use net_traits::image::base::PixelFormat;
use net_traits::image_cache::ImageCache; use net_traits::image_cache::ImageCache;
use net_traits::storage_thread::StorageType; use net_traits::storage_thread::StorageType;
use net_traits::{FetchResponseMsg, ReferrerPolicy, ResourceThreads}; use net_traits::{FetchResponseMsg, ReferrerPolicy, ResourceThreads};
use pixels::PixelFormat;
use profile_traits::mem; use profile_traits::mem;
use profile_traits::time as profile_time; use profile_traits::time as profile_time;
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};

View file

@ -38,7 +38,7 @@ bluetooth_traits = {path = "../bluetooth_traits"}
bluetooth = {path = "../bluetooth"} bluetooth = {path = "../bluetooth"}
canvas = {path = "../canvas"} canvas = {path = "../canvas"}
canvas_traits = {path = "../canvas_traits"} canvas_traits = {path = "../canvas_traits"}
compositing = {path = "../compositing", features = ["gleam"]} compositing = {path = "../compositing", features = ["gl"]}
constellation = {path = "../constellation"} constellation = {path = "../constellation"}
crossbeam-channel = "0.3" crossbeam-channel = "0.3"
debugger = {path = "../debugger"} debugger = {path = "../debugger"}

View file

@ -22,6 +22,7 @@ keyboard-types = "0.4.3"
log = "0.4" log = "0.4"
msg = {path = "../msg"} msg = {path = "../msg"}
net_traits = {path = "../net_traits"} net_traits = {path = "../net_traits"}
pixels = {path = "../pixels"}
regex = "1.0" regex = "1.0"
serde = "1" serde = "1"
serde_json = "1" serde_json = "1"

View file

@ -19,7 +19,7 @@ use image::{DynamicImage, ImageFormat, RgbImage};
use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
use keyboard_types::webdriver::send_keys; use keyboard_types::webdriver::send_keys;
use msg::constellation_msg::{BrowsingContextId, TopLevelBrowsingContextId, TraversalDirection}; use msg::constellation_msg::{BrowsingContextId, TopLevelBrowsingContextId, TraversalDirection};
use net_traits::image::base::PixelFormat; use pixels::PixelFormat;
use regex::Captures; use regex::Captures;
use script_traits::webdriver_msg::{LoadStatus, WebDriverCookieError, WebDriverFrameId}; use script_traits::webdriver_msg::{LoadStatus, WebDriverCookieError, WebDriverFrameId};
use script_traits::webdriver_msg::{ use script_traits::webdriver_msg::{