Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Send an IpcSharedMemory in tex_image_2d and tex_sub_image_2d #22225

Merged
merged 9 commits into from Nov 21, 2018

Send an IpcSharedMemory in tex_image_2d and tex_sub_image_2d

This avoids a copy in the case of textures coming from HTMLImageElement.
  • Loading branch information
nox committed Nov 20, 2018
commit 804d964b7d85c0c4efd0e9e9eb290bd15a24bb9d
@@ -11,6 +11,7 @@ use gleam::gl;
use half::f16;
use offscreen_gl_context::{GLContext, GLContextAttributes, GLLimits, NativeGLContextMethods};
use pixels::{self, PixelFormat};
use std::borrow::Cow;
use std::thread;

/// WebGL Threading API entry point that lives in the constellation.
@@ -1057,7 +1058,7 @@ impl WebGLImpl {
alpha_treatment,
y_axis_treatment,
pixel_format,
ref receiver,
ref data,
} => {
let pixels = prepare_pixels(
format,
@@ -1067,7 +1068,7 @@ impl WebGLImpl {
alpha_treatment,
y_axis_treatment,
pixel_format,
receiver.recv().unwrap(),
Cow::Borrowed(data),
);

ctx.gl()
@@ -1097,7 +1098,7 @@ impl WebGLImpl {
alpha_treatment,
y_axis_treatment,
pixel_format,
ref receiver,
ref data,
} => {
let pixels = prepare_pixels(
format,
@@ -1107,7 +1108,7 @@ impl WebGLImpl {
alpha_treatment,
y_axis_treatment,
pixel_format,
receiver.recv().unwrap(),
Cow::Borrowed(data),
);

ctx.gl()
@@ -1743,29 +1744,35 @@ fn prepare_pixels(
alpha_treatment: Option<AlphaTreatment>,
y_axis_treatment: YAxisTreatment,
pixel_format: Option<PixelFormat>,
mut pixels: Vec<u8>,
) -> Vec<u8> {
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, &mut pixels);
premultiply_inplace(TexFormat::RGBA, TexDataType::UnsignedByte, pixels.to_mut());
} else {
premultiply_inplace(internal_format, data_type, &mut pixels);
premultiply_inplace(internal_format, data_type, pixels.to_mut());
}
},
Some(AlphaTreatment::Unmultiply) => {
assert!(pixel_format.is_some());
unmultiply_inplace(&mut pixels);
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);
pixels = image_to_tex_image_data(
pixel_format,
internal_format,
data_type,
pixels.into_owned(),
)
.into();
}

if y_axis_treatment == YAxisTreatment::Flipped {
@@ -1776,8 +1783,9 @@ fn prepare_pixels(
size.width as usize,
size.height as usize,
unpacking_alignment as usize,
pixels,
);
pixels.into_owned(),
)
.into();
}

pixels
@@ -4,7 +4,7 @@

use euclid::{Rect, Size2D};
use gleam::gl;
use ipc_channel::ipc::{IpcBytesReceiver, IpcBytesSender};
use ipc_channel::ipc::{IpcBytesReceiver, IpcBytesSender, IpcSharedMemory};
use offscreen_gl_context::{GLContextAttributes, GLLimits};
use pixels::PixelFormat;
use serde_bytes::ByteBuf;
@@ -284,7 +284,7 @@ pub enum WebGLCommand {
alpha_treatment: Option<AlphaTreatment>,
y_axis_treatment: YAxisTreatment,
pixel_format: Option<PixelFormat>,
receiver: IpcBytesReceiver,
data: IpcSharedMemory,
},
TexSubImage2D {
target: u32,
@@ -300,7 +300,7 @@ pub enum WebGLCommand {
alpha_treatment: Option<AlphaTreatment>,
y_axis_treatment: YAxisTreatment,
pixel_format: Option<PixelFormat>,
receiver: IpcBytesReceiver,
data: IpcSharedMemory,
},
DrawingBufferWidth(WebGLSender<i32>),
DrawingBufferHeight(WebGLSender<i32>),
@@ -10,6 +10,7 @@ use crate::dom::bindings::root::DomRoot;
use crate::dom::globalscope::GlobalScope;
use dom_struct::dom_struct;
use euclid::{Rect, Size2D};
use ipc_channel::ipc::IpcSharedMemory;
use js::jsapi::{Heap, JSContext, JSObject};
use js::rust::Runtime;
use js::typedarray::{CreateWith, Uint8ClampedArray};
@@ -156,8 +157,8 @@ impl ImageData {
}

#[allow(unsafe_code)]
pub fn to_vec(&self) -> Vec<u8> {
unsafe { self.as_slice().into() }
pub fn to_shared_memory(&self) -> IpcSharedMemory {
IpcSharedMemory::from_bytes(unsafe { self.as_slice() })
}

#[allow(unsafe_code)]
@@ -57,7 +57,7 @@ use crate::dom::webglvertexarrayobjectoes::WebGLVertexArrayObjectOES;
use crate::dom::window::Window;
use dom_struct::dom_struct;
use euclid::{Point2D, Rect, Size2D};
use ipc_channel::ipc;
use ipc_channel::ipc::{self, IpcSharedMemory};
use js::jsapi::{JSContext, JSObject, Type};
use js::jsval::{BooleanValue, DoubleValue, Int32Value, JSVal, UInt32Value};
use js::jsval::{NullValue, ObjectValue, UndefinedValue};
@@ -504,7 +504,12 @@ impl WebGLRenderingContext {
level,
0,
1,
TexPixels::new(pixels, size, PixelFormat::RGBA8, true),
TexPixels::new(
IpcSharedMemory::from_bytes(&pixels),
size,
PixelFormat::RGBA8,
true,
),
);

false
@@ -527,7 +532,7 @@ impl WebGLRenderingContext {
fn get_image_pixels(&self, source: TexImageSource) -> Fallible<Option<TexPixels>> {
Ok(Some(match source {
TexImageSource::ImageData(image_data) => TexPixels::new(
image_data.to_vec(),
image_data.to_shared_memory(),
image_data.get_size(),
PixelFormat::RGBA8,
false,
@@ -554,7 +559,7 @@ impl WebGLRenderingContext {

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,
// but we need to refactor it moving it to `HTMLCanvasElement` and support
@@ -564,7 +569,12 @@ impl WebGLRenderingContext {
return Err(Error::Security);
}
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 {
return Ok(None);
}
@@ -676,8 +686,7 @@ impl WebGLRenderingContext {
.extension_manager
.effective_type(data_type.as_gl_constant());

// TODO(emilio): convert colorspace if requested
let (sender, receiver) = ipc::bytes_channel().unwrap();
// TODO(emilio): convert colorspace if requested.
self.send_command(WebGLCommand::TexImage2D {
target: target.as_gl_constant(),
level,
@@ -690,9 +699,8 @@ impl WebGLRenderingContext {
alpha_treatment,
y_axis_treatment,
pixel_format: pixels.pixel_format,
receiver,
data: pixels.data,
});
sender.send(&pixels.data).unwrap();

if let Some(fb) = self.bound_framebuffer.get() {
fb.invalidate_texture(&*texture);
@@ -752,8 +760,7 @@ impl WebGLRenderingContext {
.extension_manager
.effective_type(data_type.as_gl_constant());

This comment has been minimized.

Copy link
@emilio

emilio Nov 21, 2018

Member

Why doesn't textSubImage2D need to go through the EM in order to get the effective internal format?

This comment has been minimized.

Copy link
@nox

nox Nov 21, 2018

Author Member

It was like that before, and using it makes everything panic on the GL side.


// TODO(emilio): convert colorspace if requested
let (sender, receiver) = ipc::bytes_channel().unwrap();
// TODO(emilio): convert colorspace if requested.
self.send_command(WebGLCommand::TexSubImage2D {
target: target.as_gl_constant(),
level,
@@ -767,9 +774,8 @@ impl WebGLRenderingContext {
alpha_treatment,
y_axis_treatment,
pixel_format: pixels.pixel_format,
receiver,
data: pixels.data,
});
sender.send(&pixels.data).unwrap();
}

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
#[allow(unsafe_code)]
fn TexImage2D(
&self,
target: u32,
@@ -3609,8 +3616,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
// If data is null, a buffer of sufficient size
// initialized to 0 is passed.
let buff = match *pixels {
None => vec![0u8; expected_byte_length as usize],
Some(ref data) => data.to_vec(),
None => IpcSharedMemory::from_bytes(&vec![0u8; expected_byte_length as usize]),
Some(ref data) => IpcSharedMemory::from_bytes(unsafe { data.as_slice() }),
};

// 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
#[allow(unsafe_code)]
fn TexSubImage2D(
&self,
target: u32,
@@ -3808,11 +3816,12 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
Err(()) => return Ok(()),
};

// If data is null, a buffer of sufficient size
// initialized to 0 is passed.
let buff = handle_potential_webgl_error!(
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(())
);

@@ -4163,15 +4172,15 @@ impl TextureUnit {
}

struct TexPixels {
data: Vec<u8>,
data: IpcSharedMemory,
size: Size2D<u32>,
pixel_format: Option<PixelFormat>,
premultiplied: bool,
}

impl TexPixels {
fn new(
data: Vec<u8>,
data: IpcSharedMemory,
size: Size2D<u32>,
pixel_format: PixelFormat,
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 {
data,
size,
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.