Bug 1750146 - Support SWGL x-flipped composites via linear path. r=jrmuizel

Differential Revision: https://phabricator.services.mozilla.com/D136159
This commit is contained in:
Lee Salzman 2022-01-17 20:14:49 +00:00
Родитель 9b9347d03c
Коммит eaf24f8a03
6 изменённых файлов: 85 добавлений и 27 удалений

Просмотреть файл

@ -248,7 +248,8 @@ static void linear_row_blit(uint16_t* dest, int span, const vec2_scalar& srcUV,
template <bool COMPOSITE = false>
static NO_INLINE void linear_blit(Texture& srctex, const IntRect& srcReq,
Texture& dsttex, const IntRect& dstReq,
bool invertY, const IntRect& clipRect) {
bool invertX, bool invertY,
const IntRect& clipRect) {
assert(srctex.internal_format == GL_RGBA8 ||
srctex.internal_format == GL_R8 || srctex.internal_format == GL_RG8);
assert(!COMPOSITE || (srctex.internal_format == GL_RGBA8 &&
@ -268,6 +269,11 @@ static NO_INLINE void linear_blit(Texture& srctex, const IntRect& srcReq,
vec2_scalar srcUV(srcReq.x0, srcReq.y0);
vec2_scalar srcDUV(float(srcReq.width()) / dstReq.width(),
float(srcReq.height()) / dstReq.height());
if (invertX) {
// Advance to the end of the row and flip the step.
srcUV.x += srcReq.width();
srcDUV.x = -srcDUV.x;
}
// Inverted Y must step downward along source rows
if (invertY) {
srcUV.y += srcReq.height();
@ -345,7 +351,7 @@ void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
if (!srcReq.same_size(dstReq) && srctex.width >= 2 && filter == GL_LINEAR &&
(srctex.internal_format == GL_RGBA8 || srctex.internal_format == GL_R8 ||
srctex.internal_format == GL_RG8)) {
linear_blit(srctex, srcReq, dsttex, dstReq, invertY, dstReq);
linear_blit(srctex, srcReq, dsttex, dstReq, false, invertY, dstReq);
} else {
scale_blit(srctex, srcReq, dsttex, dstReq, invertY, clipRect);
}
@ -414,8 +420,9 @@ void* GetResourceBuffer(LockedTexture* resource, int32_t* width,
void Composite(LockedTexture* lockedDst, LockedTexture* lockedSrc, GLint srcX,
GLint srcY, GLsizei srcWidth, GLsizei srcHeight, GLint dstX,
GLint dstY, GLsizei dstWidth, GLsizei dstHeight,
GLboolean opaque, GLboolean flip, GLenum filter, GLint clipX,
GLint clipY, GLsizei clipWidth, GLsizei clipHeight) {
GLboolean opaque, GLboolean flipX, GLboolean flipY,
GLenum filter, GLint clipX, GLint clipY, GLsizei clipWidth,
GLsizei clipHeight) {
if (!lockedDst || !lockedSrc) {
return;
}
@ -432,20 +439,25 @@ void Composite(LockedTexture* lockedDst, LockedTexture* lockedSrc, GLint srcX,
// as used for the sampling bounds.
IntRect clipRect = {clipX - dstX, clipY - dstY, clipX - dstX + clipWidth,
clipY - dstY + clipHeight};
// Ensure we have rows of at least 2 pixels when using the linear filter to
// avoid overreading the row. Force X flips onto the linear filter for now
// until scale_blit supports it.
bool useLinear =
srctex.width >= 2 &&
(flipX || (!srcReq.same_size(dstReq) && filter == GL_LINEAR));
if (opaque) {
// Ensure we have rows of at least 2 pixels when using the linear filter
// to avoid overreading the row.
if (!srcReq.same_size(dstReq) && srctex.width >= 2 && filter == GL_LINEAR) {
linear_blit<false>(srctex, srcReq, dsttex, dstReq, flip, clipRect);
if (useLinear) {
linear_blit<false>(srctex, srcReq, dsttex, dstReq, flipX, flipY,
clipRect);
} else {
scale_blit<false>(srctex, srcReq, dsttex, dstReq, flip, clipRect);
scale_blit<false>(srctex, srcReq, dsttex, dstReq, flipY, clipRect);
}
} else {
if (!srcReq.same_size(dstReq) && srctex.width >= 2 && filter == GL_LINEAR) {
linear_blit<true>(srctex, srcReq, dsttex, dstReq, flip, clipRect);
if (useLinear) {
linear_blit<true>(srctex, srcReq, dsttex, dstReq, flipX, flipY, clipRect);
} else {
scale_blit<true>(srctex, srcReq, dsttex, dstReq, flip, clipRect);
scale_blit<true>(srctex, srcReq, dsttex, dstReq, flipY, clipRect);
}
}
}
@ -996,10 +1008,10 @@ static void linear_row_yuv(uint32_t* dest, int span, sampler2DRect samplerY,
static void linear_convert_yuv(Texture& ytex, Texture& utex, Texture& vtex,
const YUVMatrix& rgbFromYcbcr, int colorDepth,
const IntRect& srcReq, Texture& dsttex,
const IntRect& dstReq, bool invertY,
const IntRect& clipRect) {
const IntRect& dstReq, bool invertX,
bool invertY, const IntRect& clipRect) {
// Compute valid dest bounds
IntRect dstBounds = dsttex.sample_bounds(dstReq, invertY);
IntRect dstBounds = dsttex.sample_bounds(dstReq);
dstBounds.intersect(clipRect);
// Check if sampling bounds are empty
if (dstBounds.is_empty()) {
@ -1015,6 +1027,11 @@ static void linear_convert_yuv(Texture& ytex, Texture& utex, Texture& vtex,
vec2_scalar srcUV(srcReq.x0, srcReq.y0);
vec2_scalar srcDUV(float(srcReq.width()) / dstReq.width(),
float(srcReq.height()) / dstReq.height());
if (invertX) {
// Advance to the end of the row and flip the step.
srcUV.x += srcReq.width();
srcDUV.x = -srcDUV.x;
}
// Inverted Y must step downward along source rows
if (invertY) {
srcUV.y += srcReq.height();
@ -1182,8 +1199,8 @@ void CompositeYUV(LockedTexture* lockedDst, LockedTexture* lockedY,
YUVRangedColorSpace colorSpace, GLuint colorDepth, GLint srcX,
GLint srcY, GLsizei srcWidth, GLsizei srcHeight, GLint dstX,
GLint dstY, GLsizei dstWidth, GLsizei dstHeight,
GLboolean flip, GLint clipX, GLint clipY, GLsizei clipWidth,
GLsizei clipHeight) {
GLboolean flipX, GLboolean flipY, GLint clipX, GLint clipY,
GLsizei clipWidth, GLsizei clipHeight) {
if (!lockedDst || !lockedY || !lockedU || !lockedV) {
return;
}
@ -1221,7 +1238,7 @@ void CompositeYUV(LockedTexture* lockedDst, LockedTexture* lockedY,
// scaling. Further fast-paths for non-scaled video might be desirable in the
// future.
linear_convert_yuv(ytex, utex, vtex, rgbFromYcbcr, colorDepth, srcReq, dsttex,
dstReq, flip, clipRect);
dstReq, flipX, flipY, clipRect);
}
} // extern "C"

Просмотреть файл

@ -284,7 +284,8 @@ extern "C" {
dst_width: GLsizei,
dst_height: GLsizei,
opaque: GLboolean,
flip: GLboolean,
flip_x: GLboolean,
flip_y: GLboolean,
filter: GLenum,
clip_x: GLint,
clip_y: GLint,
@ -306,7 +307,8 @@ extern "C" {
dst_y: GLint,
dst_width: GLsizei,
dst_height: GLsizei,
flip: GLboolean,
flip_x: GLboolean,
flip_y: GLboolean,
clip_x: GLint,
clip_y: GLint,
clip_width: GLsizei,
@ -2322,7 +2324,8 @@ impl LockedResource {
dst_width: GLsizei,
dst_height: GLsizei,
opaque: bool,
flip: bool,
flip_x: bool,
flip_y: bool,
filter: GLenum,
clip_x: GLint,
clip_y: GLint,
@ -2342,7 +2345,8 @@ impl LockedResource {
dst_width,
dst_height,
opaque as GLboolean,
flip as GLboolean,
flip_x as GLboolean,
flip_y as GLboolean,
filter,
clip_x,
clip_y,
@ -2368,7 +2372,8 @@ impl LockedResource {
dst_y: GLint,
dst_width: GLsizei,
dst_height: GLsizei,
flip: bool,
flip_x: bool,
flip_y: bool,
clip_x: GLint,
clip_y: GLint,
clip_width: GLsizei,
@ -2390,7 +2395,8 @@ impl LockedResource {
dst_y,
dst_width,
dst_height,
flip as GLboolean,
flip_x as GLboolean,
flip_y as GLboolean,
clip_x,
clip_y,
clip_width,

Просмотреть файл

@ -97,7 +97,7 @@ impl SwTile {
surface: &SwSurface,
transform: &CompositorSurfaceTransform,
clip_rect: &DeviceIntRect,
) -> Option<(DeviceIntRect, DeviceIntRect, bool)> {
) -> Option<(DeviceIntRect, DeviceIntRect, bool, bool)> {
// Offset the valid rect to the appropriate surface origin.
let valid = self.local_bounds(surface);
// The destination rect is the valid rect transformed and then clipped.
@ -120,7 +120,7 @@ impl SwTile {
dest_rect.size().try_cast::<i32>().is_none() {
return None;
}
Some((src_rect.try_cast()?, dest_rect.try_cast()?, transform.m22 < 0.0))
Some((src_rect.try_cast()?, dest_rect.try_cast()?, transform.m11 < 0.0, transform.m22 < 0.0))
}
}
@ -204,6 +204,7 @@ struct SwCompositeJob {
dst_rect: DeviceIntRect,
clipped_dst: DeviceIntRect,
opaque: bool,
flip_x: bool,
flip_y: bool,
filter: ImageRendering,
/// The total number of bands for this job
@ -238,6 +239,7 @@ impl SwCompositeJob {
self.dst_rect.width(),
self.dst_rect.height(),
self.opaque,
self.flip_x,
self.flip_y,
image_rendering_to_gl_filter(self.filter),
band_clip.min.x,
@ -270,6 +272,7 @@ impl SwCompositeJob {
self.dst_rect.min.y,
self.dst_rect.width(),
self.dst_rect.height(),
self.flip_x,
self.flip_y,
band_clip.min.x,
band_clip.min.y,
@ -525,6 +528,7 @@ impl SwCompositeThread {
dst_rect: DeviceIntRect,
clip_rect: DeviceIntRect,
opaque: bool,
flip_x: bool,
flip_y: bool,
filter: ImageRendering,
mut graph_node: SwCompositeGraphNodeRef,
@ -549,6 +553,7 @@ impl SwCompositeThread {
dst_rect,
clipped_dst,
opaque,
flip_x,
flip_y,
filter,
num_bands,
@ -956,7 +961,7 @@ impl SwCompositor {
job_queue: &mut SwCompositeJobQueue,
) {
if let Some(ref composite_thread) = self.composite_thread {
if let Some((src_rect, dst_rect, flip_y)) = tile.composite_rects(surface, transform, clip_rect) {
if let Some((src_rect, dst_rect, flip_x, flip_y)) = tile.composite_rects(surface, transform, clip_rect) {
let source = if surface.external_image.is_some() {
// If the surface has an attached external image, lock any textures supplied in the descriptor.
match surface.composite_surface {
@ -997,6 +1002,7 @@ impl SwCompositor {
dst_rect,
*clip_rect,
surface.is_opaque,
flip_x,
flip_y,
filter,
tile.graph_node.clone(),

Просмотреть файл

@ -0,0 +1,14 @@
<!DOCTYPE html>
<meta charset="utf-8">
<div style="width: 100px; height: 100px;">
<canvas id="c" width="100" height="100"></canvas>
</div>
<script>
var ctx = document.getElementById('c').getContext('2d', { alpha: false });
ctx.fillStyle = 'red';
ctx.fillRect(0, 0, 50, 100);
ctx.fillStyle = 'green';
ctx.fillRect(50, 0, 50, 100);
</script>

Просмотреть файл

@ -0,0 +1,14 @@
<!DOCTYPE html>
<meta charset="utf-8">
<div style="width: 100px; height: 100px; transform: scaleX(-1);">
<canvas id="c" width="100" height="100"></canvas>
</div>
<script>
var ctx = document.getElementById('c').getContext('2d', { alpha: false });
ctx.fillStyle = 'green';
ctx.fillRect(0, 0, 50, 100);
ctx.fillStyle = 'red';
ctx.fillRect(50, 0, 50, 100);
</script>

Просмотреть файл

@ -2112,3 +2112,4 @@ skip-if(Android||!browserIsFission) fuzzy(255-255,171000-171000) HTTP == 1743533
== 1743560-1.html 1743560-1-ref.html
== 1743851-1.html 1743851-1-ref.html
pref(image.downscale-during-decode.enabled,true) == 1744468-1.html 1744468-1-ref.html # do not increase fuzz without looking, the test should be smoothly downscaled, not pixelated
== 1750146-1.html 1750146-1-ref.html