mirror of
https://github.com/servo/servo.git
synced 2025-08-02 20:20:14 +01:00
Send an IpcSharedMemory in tex_image_2d and tex_sub_image_2d
This avoids a copy in the case of textures coming from HTMLImageElement.
This commit is contained in:
parent
cfca906ee2
commit
804d964b7d
4 changed files with 56 additions and 38 deletions
|
@ -11,6 +11,7 @@ use gleam::gl;
|
||||||
use half::f16;
|
use half::f16;
|
||||||
use offscreen_gl_context::{GLContext, GLContextAttributes, GLLimits, NativeGLContextMethods};
|
use offscreen_gl_context::{GLContext, GLContextAttributes, GLLimits, NativeGLContextMethods};
|
||||||
use pixels::{self, PixelFormat};
|
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.
|
||||||
|
@ -1057,7 +1058,7 @@ impl WebGLImpl {
|
||||||
alpha_treatment,
|
alpha_treatment,
|
||||||
y_axis_treatment,
|
y_axis_treatment,
|
||||||
pixel_format,
|
pixel_format,
|
||||||
ref receiver,
|
ref data,
|
||||||
} => {
|
} => {
|
||||||
let pixels = prepare_pixels(
|
let pixels = prepare_pixels(
|
||||||
format,
|
format,
|
||||||
|
@ -1067,7 +1068,7 @@ impl WebGLImpl {
|
||||||
alpha_treatment,
|
alpha_treatment,
|
||||||
y_axis_treatment,
|
y_axis_treatment,
|
||||||
pixel_format,
|
pixel_format,
|
||||||
receiver.recv().unwrap(),
|
Cow::Borrowed(data),
|
||||||
);
|
);
|
||||||
|
|
||||||
ctx.gl()
|
ctx.gl()
|
||||||
|
@ -1097,7 +1098,7 @@ impl WebGLImpl {
|
||||||
alpha_treatment,
|
alpha_treatment,
|
||||||
y_axis_treatment,
|
y_axis_treatment,
|
||||||
pixel_format,
|
pixel_format,
|
||||||
ref receiver,
|
ref data,
|
||||||
} => {
|
} => {
|
||||||
let pixels = prepare_pixels(
|
let pixels = prepare_pixels(
|
||||||
format,
|
format,
|
||||||
|
@ -1107,7 +1108,7 @@ impl WebGLImpl {
|
||||||
alpha_treatment,
|
alpha_treatment,
|
||||||
y_axis_treatment,
|
y_axis_treatment,
|
||||||
pixel_format,
|
pixel_format,
|
||||||
receiver.recv().unwrap(),
|
Cow::Borrowed(data),
|
||||||
);
|
);
|
||||||
|
|
||||||
ctx.gl()
|
ctx.gl()
|
||||||
|
@ -1743,8 +1744,8 @@ fn prepare_pixels(
|
||||||
alpha_treatment: Option<AlphaTreatment>,
|
alpha_treatment: Option<AlphaTreatment>,
|
||||||
y_axis_treatment: YAxisTreatment,
|
y_axis_treatment: YAxisTreatment,
|
||||||
pixel_format: Option<PixelFormat>,
|
pixel_format: Option<PixelFormat>,
|
||||||
mut pixels: Vec<u8>,
|
mut pixels: Cow<[u8]>,
|
||||||
) -> Vec<u8> {
|
) -> Cow<[u8]> {
|
||||||
match alpha_treatment {
|
match alpha_treatment {
|
||||||
Some(AlphaTreatment::Premultiply) => {
|
Some(AlphaTreatment::Premultiply) => {
|
||||||
if let Some(pixel_format) = pixel_format {
|
if let Some(pixel_format) = pixel_format {
|
||||||
|
@ -1752,20 +1753,26 @@ fn prepare_pixels(
|
||||||
PixelFormat::BGRA8 | PixelFormat::RGBA8 => {},
|
PixelFormat::BGRA8 | PixelFormat::RGBA8 => {},
|
||||||
_ => unimplemented!("unsupported pixel format ({:?})", pixel_format),
|
_ => unimplemented!("unsupported pixel format ({:?})", pixel_format),
|
||||||
}
|
}
|
||||||
premultiply_inplace(TexFormat::RGBA, TexDataType::UnsignedByte, &mut pixels);
|
premultiply_inplace(TexFormat::RGBA, TexDataType::UnsignedByte, pixels.to_mut());
|
||||||
} else {
|
} else {
|
||||||
premultiply_inplace(internal_format, data_type, &mut pixels);
|
premultiply_inplace(internal_format, data_type, pixels.to_mut());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Some(AlphaTreatment::Unmultiply) => {
|
Some(AlphaTreatment::Unmultiply) => {
|
||||||
assert!(pixel_format.is_some());
|
assert!(pixel_format.is_some());
|
||||||
unmultiply_inplace(&mut pixels);
|
unmultiply_inplace(pixels.to_mut());
|
||||||
},
|
},
|
||||||
None => {},
|
None => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(pixel_format) = pixel_format {
|
if let Some(pixel_format) = pixel_format {
|
||||||
pixels = image_to_tex_image_data(pixel_format, internal_format, data_type, pixels);
|
pixels = image_to_tex_image_data(
|
||||||
|
pixel_format,
|
||||||
|
internal_format,
|
||||||
|
data_type,
|
||||||
|
pixels.into_owned(),
|
||||||
|
)
|
||||||
|
.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
if y_axis_treatment == YAxisTreatment::Flipped {
|
if y_axis_treatment == YAxisTreatment::Flipped {
|
||||||
|
@ -1776,8 +1783,9 @@ fn prepare_pixels(
|
||||||
size.width as usize,
|
size.width as usize,
|
||||||
size.height as usize,
|
size.height as usize,
|
||||||
unpacking_alignment as usize,
|
unpacking_alignment as usize,
|
||||||
pixels,
|
pixels.into_owned(),
|
||||||
);
|
)
|
||||||
|
.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
pixels
|
pixels
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
use euclid::{Rect, Size2D};
|
use euclid::{Rect, Size2D};
|
||||||
use gleam::gl;
|
use gleam::gl;
|
||||||
use ipc_channel::ipc::{IpcBytesReceiver, IpcBytesSender};
|
use ipc_channel::ipc::{IpcBytesReceiver, IpcBytesSender, IpcSharedMemory};
|
||||||
use offscreen_gl_context::{GLContextAttributes, GLLimits};
|
use offscreen_gl_context::{GLContextAttributes, GLLimits};
|
||||||
use pixels::PixelFormat;
|
use pixels::PixelFormat;
|
||||||
use serde_bytes::ByteBuf;
|
use serde_bytes::ByteBuf;
|
||||||
|
@ -284,7 +284,7 @@ pub enum WebGLCommand {
|
||||||
alpha_treatment: Option<AlphaTreatment>,
|
alpha_treatment: Option<AlphaTreatment>,
|
||||||
y_axis_treatment: YAxisTreatment,
|
y_axis_treatment: YAxisTreatment,
|
||||||
pixel_format: Option<PixelFormat>,
|
pixel_format: Option<PixelFormat>,
|
||||||
receiver: IpcBytesReceiver,
|
data: IpcSharedMemory,
|
||||||
},
|
},
|
||||||
TexSubImage2D {
|
TexSubImage2D {
|
||||||
target: u32,
|
target: u32,
|
||||||
|
@ -300,7 +300,7 @@ pub enum WebGLCommand {
|
||||||
alpha_treatment: Option<AlphaTreatment>,
|
alpha_treatment: Option<AlphaTreatment>,
|
||||||
y_axis_treatment: YAxisTreatment,
|
y_axis_treatment: YAxisTreatment,
|
||||||
pixel_format: Option<PixelFormat>,
|
pixel_format: Option<PixelFormat>,
|
||||||
receiver: IpcBytesReceiver,
|
data: IpcSharedMemory,
|
||||||
},
|
},
|
||||||
DrawingBufferWidth(WebGLSender<i32>),
|
DrawingBufferWidth(WebGLSender<i32>),
|
||||||
DrawingBufferHeight(WebGLSender<i32>),
|
DrawingBufferHeight(WebGLSender<i32>),
|
||||||
|
|
|
@ -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)]
|
||||||
|
|
|
@ -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};
|
||||||
|
@ -504,7 +504,12 @@ impl WebGLRenderingContext {
|
||||||
level,
|
level,
|
||||||
0,
|
0,
|
||||||
1,
|
1,
|
||||||
TexPixels::new(pixels, size, PixelFormat::RGBA8, true),
|
TexPixels::new(
|
||||||
|
IpcSharedMemory::from_bytes(&pixels),
|
||||||
|
size,
|
||||||
|
PixelFormat::RGBA8,
|
||||||
|
true,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
false
|
false
|
||||||
|
@ -527,7 +532,7 @@ 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) => TexPixels::new(
|
TexImageSource::ImageData(image_data) => TexPixels::new(
|
||||||
image_data.to_vec(),
|
image_data.to_shared_memory(),
|
||||||
image_data.get_size(),
|
image_data.get_size(),
|
||||||
PixelFormat::RGBA8,
|
PixelFormat::RGBA8,
|
||||||
false,
|
false,
|
||||||
|
@ -554,7 +559,7 @@ impl WebGLRenderingContext {
|
||||||
|
|
||||||
let size = Size2D::new(img.width, img.height);
|
let size = Size2D::new(img.width, img.height);
|
||||||
|
|
||||||
TexPixels::new(img.bytes.to_vec(), size, img.format, false)
|
TexPixels::new(img.bytes.clone(), size, img.format, 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
|
||||||
|
@ -564,7 +569,12 @@ impl WebGLRenderingContext {
|
||||||
return Err(Error::Security);
|
return Err(Error::Security);
|
||||||
}
|
}
|
||||||
if let Some((data, size)) = canvas.fetch_all_data() {
|
if let Some((data, size)) = canvas.fetch_all_data() {
|
||||||
TexPixels::new(data, size, PixelFormat::BGRA8, true)
|
TexPixels::new(
|
||||||
|
IpcSharedMemory::from_bytes(&data),
|
||||||
|
size,
|
||||||
|
PixelFormat::BGRA8,
|
||||||
|
true,
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
@ -676,8 +686,7 @@ impl WebGLRenderingContext {
|
||||||
.extension_manager
|
.extension_manager
|
||||||
.effective_type(data_type.as_gl_constant());
|
.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,
|
||||||
|
@ -690,9 +699,8 @@ impl WebGLRenderingContext {
|
||||||
alpha_treatment,
|
alpha_treatment,
|
||||||
y_axis_treatment,
|
y_axis_treatment,
|
||||||
pixel_format: pixels.pixel_format,
|
pixel_format: pixels.pixel_format,
|
||||||
receiver,
|
data: pixels.data,
|
||||||
});
|
});
|
||||||
sender.send(&pixels.data).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);
|
||||||
|
@ -752,8 +760,7 @@ impl WebGLRenderingContext {
|
||||||
.extension_manager
|
.extension_manager
|
||||||
.effective_type(data_type.as_gl_constant());
|
.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::TexSubImage2D {
|
self.send_command(WebGLCommand::TexSubImage2D {
|
||||||
target: target.as_gl_constant(),
|
target: target.as_gl_constant(),
|
||||||
level,
|
level,
|
||||||
|
@ -767,9 +774,8 @@ impl WebGLRenderingContext {
|
||||||
alpha_treatment,
|
alpha_treatment,
|
||||||
y_axis_treatment,
|
y_axis_treatment,
|
||||||
pixel_format: pixels.pixel_format,
|
pixel_format: pixels.pixel_format,
|
||||||
receiver,
|
data: pixels.data,
|
||||||
});
|
});
|
||||||
sender.send(&pixels.data).unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_gl_extensions(&self) -> String {
|
fn get_gl_extensions(&self) -> String {
|
||||||
|
@ -3548,6 +3554,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,
|
||||||
|
@ -3609,8 +3616,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:
|
||||||
|
@ -3763,6 +3770,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,
|
||||||
|
@ -3808,11 +3816,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(())
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -4163,7 +4172,7 @@ impl TextureUnit {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TexPixels {
|
struct TexPixels {
|
||||||
data: Vec<u8>,
|
data: IpcSharedMemory,
|
||||||
size: Size2D<u32>,
|
size: Size2D<u32>,
|
||||||
pixel_format: Option<PixelFormat>,
|
pixel_format: Option<PixelFormat>,
|
||||||
premultiplied: bool,
|
premultiplied: bool,
|
||||||
|
@ -4171,7 +4180,7 @@ struct TexPixels {
|
||||||
|
|
||||||
impl TexPixels {
|
impl TexPixels {
|
||||||
fn new(
|
fn new(
|
||||||
data: Vec<u8>,
|
data: IpcSharedMemory,
|
||||||
size: Size2D<u32>,
|
size: Size2D<u32>,
|
||||||
pixel_format: PixelFormat,
|
pixel_format: PixelFormat,
|
||||||
premultiplied: bool,
|
premultiplied: bool,
|
||||||
|
@ -4184,7 +4193,7 @@ impl TexPixels {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue