Fix and implement transforms in the EGL renderer

* 12to11.c (XLMain): Initialize Xlib threads.
* compositor.h: Update prototype of ApplyInverseTransform.
* egl.c (ComputeTransformMatrix): Handle transforms.
(Composite): Ensure textures if none were generated.
(FinishRender): Take callback and data and return NULL key.
(UpdateBuffer): Handle transforms by uploading everything.
Suboptimal!
(IsBufferOpaque): New function.
(egl_buffer_funcs): Add it.
* picture_renderer.c (MaybeApplyTransform): Add some comments.
* subcompositor.c (TransformBufferDamage): Avoid inverting
damage.
(ViewDamageBuffer): Directly apply untransformed buffer damage.
(ApplyUntransformedDamage): New function.
* transform.c (MatrixRotate): Fix minor row ordering error.
(ApplyInverseTransform): Adjust accordingly.
This commit is contained in:
hujianwei 2022-10-30 09:51:54 +00:00
parent b8d26761c1
commit e001d7cf69
6 changed files with 112 additions and 84 deletions

View file

@ -185,6 +185,9 @@ XLMain (int argc, char **argv)
exit (1);
}
/* Initialize Xlib threads. */
XInitThreads ();
/* Call XGetDefault with some dummy values to have the resource
database set up. */
XrmInitialize ();

View file

@ -1711,7 +1711,7 @@ extern void MatrixRotate (Matrix *, float, float, float);
extern void MatrixMirrorHorizontal (Matrix *, float);
extern void ApplyInverseTransform (int, int, Matrix *,
BufferTransform, Bool);
BufferTransform);
extern void TransformBox (pixman_box32_t *, BufferTransform, int, int);
extern BufferTransform InvertTransform (BufferTransform);

56
egl.c
View file

@ -35,9 +35,6 @@ along with 12to11. If not, see <https://www.gnu.org/licenses/>. */
#include "linux-dmabuf-unstable-v1.h"
/* TODO: implement buffer transforms. This renderer is currently
broken. */
/* These are flags for the DrmFormats. */
enum
@ -1365,6 +1362,24 @@ ComputeTransformMatrix (EglBuffer *buffer, DrawParams *params)
= (float) (1.0 / params->scale);
}
/* Set the rotation. */
if (params->flags & TransformSet)
{
/* Apply the inverse transform. */
ApplyInverseTransform (1, 1, &buffer->matrix,
params->transform);
/* Since the rotation happened inside the texture coordinate
system, scale u and v correctly if dimensions changed. */
if (RotatesDimensions (params->transform))
MatrixScale (&buffer->matrix, ((float) buffer->width
/ (float) buffer->height),
((float) buffer->height
/ (float) buffer->width));
}
/* Set the offsets. */
if (params->flags & OffsetSet)
MatrixTranslate (&buffer->matrix,
@ -1379,6 +1394,10 @@ ComputeTransformMatrix (EglBuffer *buffer, DrawParams *params)
(float) (params->crop_height / params->stretch_height));
}
/* Forward declaration. */
static void EnsureTexture (EglBuffer *);
static void
Composite (RenderBuffer buffer, RenderTarget target,
Operation op, int src_x, int src_y, int x, int y,
@ -1396,9 +1415,10 @@ Composite (RenderBuffer buffer, RenderTarget target,
if (egl_buffer->u.type != SinglePixelBuffer)
{
/* Assert that a texture was generated, since UpdateBuffer should
be called before the buffer is ever used. */
XLAssert (egl_buffer->flags & IsTextureGenerated);
/* If no texture was generated, upload the buffer contents
now. */
if (!(egl_buffer->flags & IsTextureGenerated))
EnsureTexture (egl_buffer);
/* Get the texturing target. */
tex_target = GetTextureTarget (egl_buffer);
@ -1504,8 +1524,9 @@ Composite (RenderBuffer buffer, RenderTarget target,
glBindTexture (tex_target, 0);
}
static void
FinishRender (RenderTarget target, pixman_region32_t *damage)
static RenderCompletionKey
FinishRender (RenderTarget target, pixman_region32_t *damage,
RenderCompletionFunc callback, void *data)
{
EglTarget *egl_target;
EGLint *rects;
@ -1538,6 +1559,8 @@ FinishRender (RenderTarget target, pixman_region32_t *damage)
ISwapBuffersWithDamage (egl_display, egl_target->surface,
rects, nboxes);
}
return NULL;
}
static int
@ -1965,7 +1988,8 @@ BufferFromSinglePixel (uint32_t red, uint32_t green, uint32_t blue,
buffer->u.single_pixel.a = alpha / (float) 0xffffffff;
/* An alpha channel is present. */
buffer->flags |= HasAlpha;
if (buffer->u.single_pixel.a < 1)
buffer->flags |= HasAlpha;
/* Return the buffer. */
return (RenderBuffer) (void *) buffer;
@ -2465,7 +2489,7 @@ UpdateBuffer (RenderBuffer buffer, pixman_region32_t *damage,
/* No texture has been generated, so just create one and maybe
upload the contents. */
EnsureTexture (egl_buffer);
else if (!damage)
else if (!damage || params->flags & TransformSet)
/* Upload all the contents to the buffer's texture if the buffer
type requires manual updates. Buffers backed by EGLImages do
not appear to need updates, since updates to the EGLImage are
@ -2522,6 +2546,17 @@ CanReleaseNow (RenderBuffer buffer)
return rc;
}
static Bool
IsBufferOpaque (RenderBuffer buffer)
{
EglBuffer *egl_buffer;
egl_buffer = buffer.pointer;
/* Return whether or not the buffer has no alpha channel. */
return !(egl_buffer->flags & HasAlpha);
}
static BufferFuncs egl_buffer_funcs =
{
.get_drm_formats = GetDrmFormats,
@ -2537,6 +2572,7 @@ static BufferFuncs egl_buffer_funcs =
.free_single_pixel_buffer = FreeSinglePixelBuffer,
.update_buffer_for_damage = UpdateBufferForDamage,
.can_release_now = CanReleaseNow,
.is_buffer_opaque = IsBufferOpaque,
.init_buffer_funcs = InitBufferFuncs,
};

View file

@ -1549,6 +1549,8 @@ MaybeApplyTransform (PictureBuffer *buffer, DrawParams *params)
{
MatrixIdentity (&ftransform);
/* The buffer transform must always be applied first. */
if (params->flags & TransformSet)
ApplyInverseTransform (buffer->width, buffer->height,
&ftransform, params->transform,
@ -1557,6 +1559,7 @@ MaybeApplyTransform (PictureBuffer *buffer, DrawParams *params)
/* Note that these must be applied in the right order. First,
the scale is applied. Then, the offset, and finally the
stretch. */
if (params->flags & ScaleSet)
MatrixScale (&ftransform, 1.0 / GetScale (params),
1.0 / GetScale (params));

View file

@ -1775,8 +1775,10 @@ ViewFree (View *view)
XLFree (view);
}
/* Forward declaration. */
/* Forward declarations. */
static void ApplyBufferDamage (View *, pixman_region32_t *);
static void ApplyUntransformedDamage (View *, pixman_region32_t *);
void
ViewDamage (View *view, pixman_region32_t *damage)
@ -1823,10 +1825,6 @@ TransformBufferDamage (pixman_region32_t *damage,
View *view)
{
int width, height;
BufferTransform inverse;
/* Invert the transform. */
inverse = InvertTransform (view->transform);
/* Calculate the width and height of the buffer after the
transform. */
@ -1834,7 +1832,8 @@ TransformBufferDamage (pixman_region32_t *damage,
height = XLBufferHeight (view->buffer);
/* Transform the damage. */
XLTransformRegion (damage, source, inverse, width, height);
XLTransformRegion (damage, source, view->transform,
width, height);
}
void
@ -1905,8 +1904,11 @@ ViewDamageBuffer (View *view, pixman_region32_t *damage)
}
/* Damage the view. */
ViewDamage (view, &temp);
pixman_region32_union (&view->damage, &view->damage, &temp);
pixman_region32_fini (&temp);
/* Apply the untransformed damage directly. */
ApplyUntransformedDamage (view, damage);
}
}
@ -2145,6 +2147,19 @@ ApplyBufferDamage (View *view, pixman_region32_t *damage)
RenderUpdateBufferForDamage (buffer, damage, &params);
}
static void
ApplyUntransformedDamage (View *view, pixman_region32_t *buffer_damage)
{
RenderBuffer buffer;
DrawParams params;
buffer = XLRenderBufferFromBuffer (view->buffer);
params.flags = 0;
/* Upload the buffer contents. */
RenderUpdateBufferForDamage (buffer, buffer_damage, &params);
}
void
SubcompositorSetOpaqueCallback (Subcompositor *subcompositor,
void (*opaque_changed) (Subcompositor *,

View file

@ -153,8 +153,8 @@ MatrixRotate (Matrix *transform, float theta, float x, float y)
memcpy (copy, transform, sizeof copy);
Index (temp, 0, 0) = cosf (theta);
Index (temp, 0, 1) = sinf (theta);
Index (temp, 1, 0) = -sinf (theta);
Index (temp, 0, 1) = -sinf (theta);
Index (temp, 1, 0) = sinf (theta);
Index (temp, 1, 1) = cosf (theta);
MatrixMultiply (copy, temp, transform);
@ -232,15 +232,18 @@ MatrixExport (Matrix *transform, XTransform *xtransform)
void
ApplyInverseTransform (int buffer_width, int buffer_height, Matrix *matrix,
BufferTransform transform, Bool cartesian)
BufferTransform transform)
{
float width, height;
/* Note that the transform is applied in reverse, meaning that a
counterclockwise rotation is done clockwise, etc, as TRANSFORM
transforms destination coordinates to source ones. CARTESIAN
specifies whether or not an actual cartesian coordinate system is
being used. */
/* Wayland buffer transforms are somewhat confusing. They are
actually applied in reverse, so a counterclockwise rotation would
actually be applied clockwise, and so on.
The fact that matrix maps from destination coordinates to buffer
coordinates makes things easier: as the inverse of the inverse of
a transform is itself, transforms are just applied in that
order. */
width = buffer_width;
height = buffer_height;
@ -251,89 +254,57 @@ ApplyInverseTransform (int buffer_width, int buffer_height, Matrix *matrix,
break;
case CounterClockwise90:
if (!cartesian)
{
/* Apply clockwise 270 degree rotation around the
origin. */
MatrixRotate (matrix, M_PI * 1.5, 0, 0);
/* Translate y by the width. */
MatrixTranslate (matrix, 0, -width);
}
else
{
/* Apply clockwise 270 degree rotation around the
origin. */
MatrixRotate (matrix, M_PI * 0.5, 0, 1);
/* Translate by the width. */
MatrixTranslate (matrix, 0, width);
}
/* CounterClockwise90. Rotate the buffer contents 90 degrees
clockwise. IOW, rotate the destination by 90 degrees
counterclockwise, which is 270 degrees clockwise. */
MatrixRotate (matrix, M_PI * 1.5, 0, 0);
MatrixTranslate (matrix, -height, 0);
break;
case CounterClockwise180:
/* Apply clockwise 180 degree rotation around the center. */
/* CounterClockwise180. It's 180 degrees. Apply clockwise 180
degree rotation around the center. */
MatrixRotate (matrix, M_PI, width / 2.0f, height / 2.0f);
break;
case CounterClockwise270:
if (!cartesian)
{
/* Apply clockwise 90 degree rotation around the origin. */
MatrixRotate (matrix, M_PI * 0.5, 0, 0);
/* Translate by the height. */
MatrixTranslate (matrix, -height, 0);
}
else
{
/* Apply clockwise 90 degree rotation around the origin. */
MatrixRotate (matrix, M_PI * 1.5, 0, 1);
/* Translate by the height. */
MatrixTranslate (matrix, -height, 0);
}
/* CounterClockwise270. Rotate the buffer contents 270 degrees
clockwise. IOW, rotate the destination by 270 degrees
counterclockwise, which is 90 degrees clockwise. */
MatrixRotate (matrix, M_PI * 0.5, 0, 0);
MatrixTranslate (matrix, 0, -width);
break;
case Flipped:
/* Apply horizontal flip. */
/* Flipped. Apply horizontal flip. */
MatrixMirrorHorizontal (matrix, width);
break;
case Flipped90:
/* Apply horizontal flip. */
MatrixMirrorHorizontal (matrix, width);
/* Apply clockwise 90 degree rotation around the origin. */
MatrixRotate (matrix, M_PI * 0.5, 0, 0);
/* Translate by the height. */
/* Flipped90. Apply a flip but otherwise treat this the same as
CounterClockwise90. */
MatrixRotate (matrix, M_PI * 1.5, 0, 0);
MatrixTranslate (matrix, -height, 0);
MatrixMirrorHorizontal (matrix, height);
break;
case Flipped180:
/* Apply horizontal flip. */
MatrixMirrorHorizontal (matrix, width);
/* Apply clockwise 180 degree rotation around the center. */
/* Flipped180. Apply a flip and treat this the same as
CounterClockwise180. */
MatrixRotate (matrix, M_PI, width / 2.0f, height / 2.0f);
MatrixMirrorHorizontal (matrix, width);
break;
case Flipped270:
/* Apply horizontal flip. */
MatrixMirrorHorizontal (matrix, width);
/* Apply clockwise 270 degree rotation around the origin. */
MatrixRotate (matrix, M_PI * 1.5, 0, 0);
/* Translate y by the width. */
/* Flipped270. Apply a flip and treat this the same as
CounterClockwise270. */
MatrixRotate (matrix, M_PI * 0.5, 0, 0);
MatrixTranslate (matrix, 0, -width);
MatrixMirrorHorizontal (matrix, height);
break;
}
return;
}
void