mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
webgl: Ignore pixel storage parameters for ImageBitmap source (#37635)
Follow the WebGL specification and ignore the values of UNPACK_FLIP_Y, UNPACK_PREMULTIPLY_ALPHA, and UNPACK_COLORSPACE_CONVERSION if the TexImageSource is an ImageBitmap. https://registry.khronos.org/webgl/specs/latest/1.0/#6.10 Testing: There are no dedicated test results changes without the PR #37634 which unblocks new testing scenarios with premultiplied ImageBitmap from Blob/Canvas/Image sources. Signed-off-by: Andrei Volykhin <andrei.volykhin@gmail.com>
This commit is contained in:
parent
3f496f8225
commit
9487f66eaa
2 changed files with 130 additions and 72 deletions
|
@ -507,6 +507,28 @@ impl WebGLRenderingContext {
|
|||
self.texture_packing_alignment.get()
|
||||
}
|
||||
|
||||
pub(crate) fn get_current_unpack_state(
|
||||
&self,
|
||||
premultiplied: bool,
|
||||
) -> (Option<AlphaTreatment>, YAxisTreatment) {
|
||||
let settings = self.texture_unpacking_settings.get();
|
||||
let dest_premultiplied = settings.contains(TextureUnpacking::PREMULTIPLY_ALPHA);
|
||||
|
||||
let alpha_treatment = match (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
|
||||
};
|
||||
|
||||
(alpha_treatment, y_axis_treatment)
|
||||
}
|
||||
|
||||
// LINEAR filtering may be forbidden when using WebGL extensions.
|
||||
// https://www.khronos.org/registry/webgl/extensions/OES_texture_float_linear/
|
||||
fn validate_filterable_texture(
|
||||
|
@ -552,7 +574,8 @@ impl WebGLRenderingContext {
|
|||
IpcSharedMemory::from_bytes(&pixels),
|
||||
size,
|
||||
PixelFormat::RGBA8,
|
||||
true,
|
||||
None,
|
||||
YAxisTreatment::AsIs,
|
||||
)),
|
||||
);
|
||||
|
||||
|
@ -578,6 +601,7 @@ impl WebGLRenderingContext {
|
|||
if !bitmap.origin_is_clean() {
|
||||
return Err(Error::Security);
|
||||
}
|
||||
|
||||
let Some(snapshot) = bitmap.bitmap_data().clone() else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
@ -588,15 +612,32 @@ impl WebGLRenderingContext {
|
|||
SnapshotPixelFormat::RGBA => PixelFormat::RGBA8,
|
||||
SnapshotPixelFormat::BGRA => PixelFormat::BGRA8,
|
||||
};
|
||||
let premultiply = snapshot.alpha_mode().is_premultiplied();
|
||||
TexPixels::new(snapshot.to_ipc_shared_memory(), size, format, premultiply)
|
||||
|
||||
// If the TexImageSource is an ImageBitmap, the values of
|
||||
// UNPACK_FLIP_Y, UNPACK_PREMULTIPLY_ALPHA, and
|
||||
// UNPACK_COLORSPACE_CONVERSION are to be ignored.
|
||||
// Set alpha and y_axis treatment parameters such that no
|
||||
// conversions will be made.
|
||||
// <https://registry.khronos.org/webgl/specs/latest/1.0/#6.10>
|
||||
TexPixels::new(
|
||||
snapshot.to_ipc_shared_memory(),
|
||||
size,
|
||||
format,
|
||||
None,
|
||||
YAxisTreatment::AsIs,
|
||||
)
|
||||
},
|
||||
TexImageSource::ImageData(image_data) => {
|
||||
let (alpha_treatment, y_axis_treatment) = self.get_current_unpack_state(false);
|
||||
|
||||
TexPixels::new(
|
||||
image_data.to_shared_memory(),
|
||||
image_data.get_size(),
|
||||
PixelFormat::RGBA8,
|
||||
alpha_treatment,
|
||||
y_axis_treatment,
|
||||
)
|
||||
},
|
||||
TexImageSource::ImageData(image_data) => TexPixels::new(
|
||||
image_data.to_shared_memory(),
|
||||
image_data.get_size(),
|
||||
PixelFormat::RGBA8,
|
||||
false,
|
||||
),
|
||||
TexImageSource::HTMLImageElement(image) => {
|
||||
let document = match self.canvas {
|
||||
HTMLCanvasElementOrOffscreenCanvas::HTMLCanvasElement(ref canvas) => {
|
||||
|
@ -650,9 +691,11 @@ impl WebGLRenderingContext {
|
|||
};
|
||||
|
||||
let size = Size2D::new(img.metadata.width, img.metadata.height);
|
||||
|
||||
let data = IpcSharedMemory::from_bytes(img.first_frame().bytes);
|
||||
TexPixels::new(data, size, img.format, false)
|
||||
|
||||
let (alpha_treatment, y_axis_treatment) = self.get_current_unpack_state(false);
|
||||
|
||||
TexPixels::new(data, size, img.format, alpha_treatment, y_axis_treatment)
|
||||
},
|
||||
// TODO(emilio): Getting canvas data is implemented in CanvasRenderingContext2D,
|
||||
// but we need to refactor it moving it to `HTMLCanvasElement` and support
|
||||
|
@ -661,18 +704,28 @@ impl WebGLRenderingContext {
|
|||
if !canvas.origin_is_clean() {
|
||||
return Err(Error::Security);
|
||||
}
|
||||
if let Some(snapshot) = canvas.get_image_data() {
|
||||
let snapshot = snapshot.as_ipc();
|
||||
let size = snapshot.size().cast();
|
||||
let format = match snapshot.format() {
|
||||
SnapshotPixelFormat::RGBA => PixelFormat::RGBA8,
|
||||
SnapshotPixelFormat::BGRA => PixelFormat::BGRA8,
|
||||
};
|
||||
let premultiply = snapshot.alpha_mode().is_premultiplied();
|
||||
TexPixels::new(snapshot.to_ipc_shared_memory(), size, format, premultiply)
|
||||
} else {
|
||||
|
||||
let Some(snapshot) = canvas.get_image_data() else {
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
|
||||
let snapshot = snapshot.as_ipc();
|
||||
let size = snapshot.size().cast();
|
||||
let format = match snapshot.format() {
|
||||
SnapshotPixelFormat::RGBA => PixelFormat::RGBA8,
|
||||
SnapshotPixelFormat::BGRA => PixelFormat::BGRA8,
|
||||
};
|
||||
|
||||
let (alpha_treatment, y_axis_treatment) =
|
||||
self.get_current_unpack_state(snapshot.alpha_mode().is_premultiplied());
|
||||
|
||||
TexPixels::new(
|
||||
snapshot.to_ipc_shared_memory(),
|
||||
size,
|
||||
format,
|
||||
alpha_treatment,
|
||||
y_axis_treatment,
|
||||
)
|
||||
},
|
||||
TexImageSource::HTMLVideoElement(video) => {
|
||||
if !video.origin_is_clean() {
|
||||
|
@ -689,8 +742,17 @@ impl WebGLRenderingContext {
|
|||
SnapshotPixelFormat::RGBA => PixelFormat::RGBA8,
|
||||
SnapshotPixelFormat::BGRA => PixelFormat::BGRA8,
|
||||
};
|
||||
let premultiply = snapshot.alpha_mode().is_premultiplied();
|
||||
TexPixels::new(snapshot.to_ipc_shared_memory(), size, format, premultiply)
|
||||
|
||||
let (alpha_treatment, y_axis_treatment) =
|
||||
self.get_current_unpack_state(snapshot.alpha_mode().is_premultiplied());
|
||||
|
||||
TexPixels::new(
|
||||
snapshot.to_ipc_shared_memory(),
|
||||
size,
|
||||
format,
|
||||
alpha_treatment,
|
||||
y_axis_treatment,
|
||||
)
|
||||
},
|
||||
}))
|
||||
}
|
||||
|
@ -769,15 +831,6 @@ impl WebGLRenderingContext {
|
|||
)
|
||||
);
|
||||
|
||||
let settings = self.texture_unpacking_settings.get();
|
||||
let dest_premultiplied = settings.contains(TextureUnpacking::PREMULTIPLY_ALPHA);
|
||||
|
||||
let y_axis_treatment = if settings.contains(TextureUnpacking::FLIP_Y_AXIS) {
|
||||
YAxisTreatment::Flipped
|
||||
} else {
|
||||
YAxisTreatment::AsIs
|
||||
};
|
||||
|
||||
let internal_format = self
|
||||
.extension_manager
|
||||
.get_effective_tex_internal_format(internal_format, data_type.as_gl_constant());
|
||||
|
@ -788,12 +841,6 @@ impl WebGLRenderingContext {
|
|||
|
||||
match source {
|
||||
TexSource::Pixels(pixels) => {
|
||||
let alpha_treatment = match (pixels.premultiplied, dest_premultiplied) {
|
||||
(true, false) => Some(AlphaTreatment::Unmultiply),
|
||||
(false, true) => Some(AlphaTreatment::Premultiply),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
// TODO(emilio): convert colorspace if requested.
|
||||
self.send_command(WebGLCommand::TexImage2D {
|
||||
target: target.as_gl_constant(),
|
||||
|
@ -804,8 +851,8 @@ impl WebGLRenderingContext {
|
|||
data_type,
|
||||
effective_data_type,
|
||||
unpacking_alignment,
|
||||
alpha_treatment,
|
||||
y_axis_treatment,
|
||||
alpha_treatment: pixels.alpha_treatment,
|
||||
y_axis_treatment: pixels.y_axis_treatment,
|
||||
pixel_format: pixels.pixel_format,
|
||||
data: pixels.data.into(),
|
||||
});
|
||||
|
@ -873,21 +920,6 @@ impl WebGLRenderingContext {
|
|||
return self.webgl_error(InvalidOperation);
|
||||
}
|
||||
|
||||
let settings = self.texture_unpacking_settings.get();
|
||||
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());
|
||||
|
@ -903,8 +935,8 @@ impl WebGLRenderingContext {
|
|||
data_type,
|
||||
effective_data_type,
|
||||
unpacking_alignment,
|
||||
alpha_treatment,
|
||||
y_axis_treatment,
|
||||
alpha_treatment: pixels.alpha_treatment,
|
||||
y_axis_treatment: pixels.y_axis_treatment,
|
||||
pixel_format: pixels.pixel_format,
|
||||
data: pixels.data.into(),
|
||||
});
|
||||
|
@ -1581,9 +1613,7 @@ impl WebGLRenderingContext {
|
|||
}
|
||||
|
||||
let size = Size2D::new(width, height);
|
||||
let buff = IpcSharedMemory::from_bytes(data);
|
||||
let pixels = TexPixels::from_array(buff, size);
|
||||
let data = pixels.data;
|
||||
let data = IpcSharedMemory::from_bytes(data);
|
||||
|
||||
handle_potential_webgl_error!(
|
||||
self,
|
||||
|
@ -1646,9 +1676,7 @@ impl WebGLRenderingContext {
|
|||
Err(_) => return,
|
||||
};
|
||||
|
||||
let buff = IpcSharedMemory::from_bytes(data);
|
||||
let pixels = TexPixels::from_array(buff, Size2D::new(width, height));
|
||||
let data = pixels.data;
|
||||
let data = IpcSharedMemory::from_bytes(data);
|
||||
|
||||
self.send_command(WebGLCommand::CompressedTexSubImage2D {
|
||||
target: target.as_gl_constant(),
|
||||
|
@ -4533,6 +4561,8 @@ impl WebGLRenderingContextMethods<crate::DomTypeHolder> for WebGLRenderingContex
|
|||
|
||||
let size = Size2D::new(width, height);
|
||||
|
||||
let (alpha_treatment, y_axis_treatment) = self.get_current_unpack_state(false);
|
||||
|
||||
self.tex_image_2d(
|
||||
&texture,
|
||||
target,
|
||||
|
@ -4543,7 +4573,12 @@ impl WebGLRenderingContextMethods<crate::DomTypeHolder> for WebGLRenderingContex
|
|||
border,
|
||||
unpacking_alignment,
|
||||
size,
|
||||
TexSource::Pixels(TexPixels::from_array(buff, size)),
|
||||
TexSource::Pixels(TexPixels::from_array(
|
||||
buff,
|
||||
size,
|
||||
alpha_treatment,
|
||||
y_axis_treatment,
|
||||
)),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
|
@ -4703,6 +4738,8 @@ impl WebGLRenderingContextMethods<crate::DomTypeHolder> for WebGLRenderingContex
|
|||
};
|
||||
}
|
||||
|
||||
let (alpha_treatment, y_axis_treatment) = self.get_current_unpack_state(false);
|
||||
|
||||
self.tex_sub_image_2d(
|
||||
texture,
|
||||
target,
|
||||
|
@ -4712,7 +4749,12 @@ impl WebGLRenderingContextMethods<crate::DomTypeHolder> for WebGLRenderingContex
|
|||
format,
|
||||
data_type,
|
||||
unpacking_alignment,
|
||||
TexPixels::from_array(buff, Size2D::new(width, height)),
|
||||
TexPixels::from_array(
|
||||
buff,
|
||||
Size2D::new(width, height),
|
||||
alpha_treatment,
|
||||
y_axis_treatment,
|
||||
),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
@ -5056,7 +5098,8 @@ pub(crate) struct TexPixels {
|
|||
data: IpcSharedMemory,
|
||||
size: Size2D<u32>,
|
||||
pixel_format: Option<PixelFormat>,
|
||||
premultiplied: bool,
|
||||
alpha_treatment: Option<AlphaTreatment>,
|
||||
y_axis_treatment: YAxisTreatment,
|
||||
}
|
||||
|
||||
impl TexPixels {
|
||||
|
@ -5064,22 +5107,30 @@ impl TexPixels {
|
|||
data: IpcSharedMemory,
|
||||
size: Size2D<u32>,
|
||||
pixel_format: PixelFormat,
|
||||
premultiplied: bool,
|
||||
alpha_treatment: Option<AlphaTreatment>,
|
||||
y_axis_treatment: YAxisTreatment,
|
||||
) -> Self {
|
||||
Self {
|
||||
data,
|
||||
size,
|
||||
pixel_format: Some(pixel_format),
|
||||
premultiplied,
|
||||
alpha_treatment,
|
||||
y_axis_treatment,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn from_array(data: IpcSharedMemory, size: Size2D<u32>) -> Self {
|
||||
pub(crate) fn from_array(
|
||||
data: IpcSharedMemory,
|
||||
size: Size2D<u32>,
|
||||
alpha_treatment: Option<AlphaTreatment>,
|
||||
y_axis_treatment: YAxisTreatment,
|
||||
) -> Self {
|
||||
Self {
|
||||
data,
|
||||
size,
|
||||
pixel_format: None,
|
||||
premultiplied: false,
|
||||
alpha_treatment,
|
||||
y_axis_treatment,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue