forked from 12to11/12to11
Implement buffer transforms on the XRender backend
* 12to11.conf (XSHMFENCELIB): New library. * 12to11.man: Document that surface transforms are now supported. * Imakefile (LOCAL_LIBRARIES): Add XSHMFENCELIB. (SRCS, OBJS): Add fence_ring.c and fence_ring.o. * README: Require xshmfence. * buffer.c: Include stdio.h. * compositor.h (enum _BufferTransform): New enum. (struct _DrawParams): Add TransformSet. (RotatesDimensions): New macro. (struct _State): Add buffer transform. * egl.c: Add TODO for buffer transforms. * fns.c (TransformBox, XLTransformRegion): New functions. * picture_renderer.c (struct _BufferActivityRecord): New field `fence'. (struct _PictureBuffer): Add buffer width and height. (struct _DmaBufRecord, RecordBufferActivity, UnlinkActivityRecord) (DestroyRenderTarget, GetBufferTransform, MaybeApplyTransform) (Composite, FinishRender, BufferFromDmaBuf, FinishDmaBufRecord) (BufferFromDmaBufAsync, BufferFromShm, FreeAnyBuffer): Record width and height, and handle transforms; add some disabled fencing code. * subcompositor.c (struct _View): Add transform. Rearrange fields for alignment. (MakeView): Initialize transform. (InvertTransform): New function. (BufferWidthAfterTransform, BufferHeightAfterTransform) (TransformBufferDamage): New functions. (ViewDamageBuffer): Transform buffer damage if necessary. (ViewWidth, ViewHeight): Use width and height after transform. (ViewComputeTransform): Apply transform. * surface.c (ApplyBufferTransform): New function. (ApplyViewport, CheckViewportValues, SavePendingState) (InternalCommit, GetBufferTransform, SetBufferTransform, InitState): Initialize and handle transforms. (XLStateAttachBuffer, XLStateDetachBuffer): Delete unused functions. * time.c (InitTime): Require a newer version of the Sync extension. * transform.c (MatrixRotate, MatrixMirrorHorizontal): New functions.
This commit is contained in:
parent
65a2e4de5b
commit
768f2d98b5
13 changed files with 596 additions and 64 deletions
|
@ -14,6 +14,7 @@
|
|||
PIXMANINCLUDES = -I$(INCROOT)/pixman-1
|
||||
XPRESENTLIB = -lXpresent
|
||||
WAYLAND_SCANNER = wayland-scanner
|
||||
XSHMFENCELIB = -lxshmfence
|
||||
|
||||
/* Uncomment the following code if building with EGL support. */
|
||||
|
||||
|
|
|
@ -293,9 +293,6 @@ least support the
|
|||
.B _NET_WM_SYNC_REQUEST
|
||||
window manager protocol will result in Wayland programs running badly.
|
||||
.PP
|
||||
In addition, surfaces transforms are not supported nor reported. The
|
||||
vast majority of clients seem not to make use of this feature, and
|
||||
implementing it would be a lot of trouble.
|
||||
.SH "SEE ALSO"
|
||||
X(7), Xorg(1)
|
||||
.SH AUTHORS
|
||||
|
|
|
@ -11,7 +11,7 @@ DEPLIBS = $(DEPXLIB) $(DEPEXTENSIONLIB) $(DEPXRANDRLIB) $(DEPXRENDERLIB) \
|
|||
LOCAL_LIBRARIES = $(XLIB) $(EXTENSIONLIB) $(XCBLIB) $(XCB) $(XCB_SHM) \
|
||||
$(XRANDRLIB) $(PIXMAN) $(XRENDERLIB) $(XILIB) $(XKBFILELIB) $(XFIXESLIB) \
|
||||
$(XCB_DRI3) $(XCB_SHAPE) $(WAYLAND_SERVER) $(XCB_RANDR) $(DRM) \
|
||||
$(XPRESENTLIB)
|
||||
$(XPRESENTLIB) $(XSHMFENCELIB)
|
||||
|
||||
INCLUDES := $(DRMINCLUDES) $(PIXMANINCLUDES)
|
||||
|
||||
|
@ -25,7 +25,7 @@ SRCS = 12to11.c run.c alloc.c fns.c output.c compositor.c \
|
|||
wp_viewporter.c decoration.c text_input.c \
|
||||
single_pixel_buffer.c drm_lease.c pointer_constraints.c \
|
||||
time.c relative_pointer.c keyboard_shortcuts_inhibit.c \
|
||||
idle_inhibit.c process.c
|
||||
idle_inhibit.c process.c fence_ring.c
|
||||
|
||||
OBJS = 12to11.o run.o alloc.o fns.o output.o compositor.o \
|
||||
surface.o region.o shm.o atoms.o subcompositor.o positioner.o \
|
||||
|
@ -37,7 +37,7 @@ OBJS = 12to11.o run.o alloc.o fns.o output.o compositor.o \
|
|||
wp_viewporter.o decoration.o text_input.o \
|
||||
single_pixel_buffer.o drm_lease.o pointer_constraints.o \
|
||||
time.o relative_pointer.o keyboard_shortcuts_inhibit.o \
|
||||
idle_inhibit.o process.o
|
||||
idle_inhibit.o process.o fence_ring.o
|
||||
|
||||
GENHEADERS = transfer_atoms.h
|
||||
|
||||
|
|
4
README
4
README
|
@ -98,8 +98,8 @@ This directory is organized as follows:
|
|||
those containing MIME types or shaders
|
||||
|
||||
Building the source code is simple, provided that you have the
|
||||
necessary libwayland-server library, pixman, XCB, DRM, and X extension
|
||||
libraries installed:
|
||||
necessary libwayland-server library, pixman, XCB, DRM, xshmfence, and
|
||||
X extension libraries installed:
|
||||
|
||||
xmkmf # to generate the Makefile
|
||||
make # to build the binary
|
||||
|
|
2
buffer.c
2
buffer.c
|
@ -17,6 +17,8 @@ for more details.
|
|||
You should have received a copy of the GNU General Public License
|
||||
along with 12to11. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "compositor.h"
|
||||
|
||||
typedef struct _DestroyListener DestroyListener;
|
||||
|
|
78
compositor.h
78
compositor.h
|
@ -157,6 +157,7 @@ typedef struct _DrmFormat DrmFormat;
|
|||
typedef struct _ShmFormat ShmFormat;
|
||||
|
||||
typedef enum _Operation Operation;
|
||||
typedef enum _BufferTransform BufferTransform;
|
||||
|
||||
typedef void *IdleCallbackKey;
|
||||
typedef void *PresentCompletionKey;
|
||||
|
@ -167,6 +168,18 @@ typedef void (*DmaBufFailureFunc) (void *);
|
|||
typedef void (*BufferIdleFunc) (RenderBuffer, void *);
|
||||
typedef void (*PresentCompletionFunc) (void *);
|
||||
|
||||
enum _BufferTransform
|
||||
{
|
||||
Normal,
|
||||
CounterClockwise90,
|
||||
CounterClockwise180,
|
||||
CounterClockwise270,
|
||||
Flipped,
|
||||
Flipped90,
|
||||
Flipped180,
|
||||
Flipped270,
|
||||
};
|
||||
|
||||
enum _Operation
|
||||
{
|
||||
OperationOver,
|
||||
|
@ -176,20 +189,27 @@ enum _Operation
|
|||
enum
|
||||
{
|
||||
/* Scale has been set. */
|
||||
ScaleSet = 1,
|
||||
|
||||
ScaleSet = 1,
|
||||
/* Transform has been set. */
|
||||
TransformSet = (1 << 1),
|
||||
/* Offset has been set. */
|
||||
OffsetSet = (1 << 2),
|
||||
|
||||
OffsetSet = (1 << 2),
|
||||
/* Stretch has been set. */
|
||||
StretchSet = (1 << 3),
|
||||
StretchSet = (1 << 3),
|
||||
};
|
||||
|
||||
/* The transforms specified in the draw parameters are applied in the
|
||||
following order: transform, scale, off_x, off_y, crop_width,
|
||||
crop_height, stretch_width, stretch_height. */
|
||||
|
||||
struct _DrawParams
|
||||
{
|
||||
/* Which fields are set. */
|
||||
int flags;
|
||||
|
||||
/* A transform by which to rotate the buffer. */
|
||||
BufferTransform transform;
|
||||
|
||||
/* A scale factor to apply to the buffer. */
|
||||
double scale;
|
||||
|
||||
|
@ -643,6 +663,8 @@ extern void XLScaleRegion (pixman_region32_t *, pixman_region32_t *,
|
|||
float, float);
|
||||
extern void XLExtendRegion (pixman_region32_t *, pixman_region32_t *,
|
||||
int, int);
|
||||
extern void XLTransformRegion (pixman_region32_t *, pixman_region32_t *,
|
||||
BufferTransform, int, int);
|
||||
extern Time XLGetServerTimeRoundtrip (void);
|
||||
|
||||
extern RootWindowSelection *XLSelectInputFromRootWindow (unsigned long);
|
||||
|
@ -786,6 +808,7 @@ extern void ViewSkip (View *);
|
|||
extern void ViewUnskip (View *);
|
||||
extern void ViewMoveFractional (View *, double, double);
|
||||
|
||||
extern void ViewSetTransform (View *, BufferTransform);
|
||||
extern void ViewSetViewport (View *, double, double, double, double,
|
||||
double, double);
|
||||
extern void ViewClearViewport (View *);
|
||||
|
@ -837,19 +860,26 @@ enum _RoleType
|
|||
DndIconType,
|
||||
};
|
||||
|
||||
#define RotatesDimensions(transform) \
|
||||
((transform) == CounterClockwise90 \
|
||||
|| (transform) == CounterClockwise270 \
|
||||
|| (transform) == Flipped90 \
|
||||
|| (transform) == Flipped270)
|
||||
|
||||
enum
|
||||
{
|
||||
PendingNone = 0,
|
||||
PendingOpaqueRegion = 1,
|
||||
PendingInputRegion = (1 << 2),
|
||||
PendingDamage = (1 << 3),
|
||||
PendingSurfaceDamage = (1 << 4),
|
||||
PendingBuffer = (1 << 5),
|
||||
PendingFrameCallbacks = (1 << 6),
|
||||
PendingBufferScale = (1 << 7),
|
||||
PendingAttachments = (1 << 8),
|
||||
PendingViewportSrc = (1 << 9),
|
||||
PendingViewportDest = (1 << 10),
|
||||
PendingNone = 0,
|
||||
PendingOpaqueRegion = 1,
|
||||
PendingInputRegion = (1 << 2),
|
||||
PendingDamage = (1 << 3),
|
||||
PendingSurfaceDamage = (1 << 4),
|
||||
PendingBuffer = (1 << 5),
|
||||
PendingFrameCallbacks = (1 << 6),
|
||||
PendingBufferScale = (1 << 7),
|
||||
PendingAttachments = (1 << 8),
|
||||
PendingViewportSrc = (1 << 9),
|
||||
PendingViewportDest = (1 << 10),
|
||||
PendingBufferTransform = (1 << 11),
|
||||
|
||||
/* Flags here are stored in `pending' of the current state for
|
||||
space reasons. */
|
||||
|
@ -889,6 +919,9 @@ struct _State
|
|||
/* The scale of this buffer. */
|
||||
int buffer_scale;
|
||||
|
||||
/* The buffer transform. */
|
||||
BufferTransform transform;
|
||||
|
||||
/* List of frame callbacks. */
|
||||
FrameCallback frame_callbacks;
|
||||
|
||||
|
@ -1109,8 +1142,6 @@ extern void XLSurfaceReleaseRole (Surface *, Role *);
|
|||
|
||||
extern void XLDefaultCommit (Surface *);
|
||||
|
||||
extern void XLStateAttachBuffer (State *, ExtBuffer *);
|
||||
extern void XLStateDetachBuffer (State *);
|
||||
extern void XLSurfaceRunFrameCallbacks (Surface *, struct timespec);
|
||||
extern void XLSurfaceRunFrameCallbacksMs (Surface *, uint32_t);
|
||||
extern CommitCallback *XLSurfaceRunAtCommit (Surface *,
|
||||
|
@ -1661,6 +1692,8 @@ extern void MatrixIdentity (Matrix *);
|
|||
extern void MatrixTranslate (Matrix *, float, float);
|
||||
extern void MatrixScale (Matrix *, float, float);
|
||||
extern void MatrixExport (Matrix *, XTransform *);
|
||||
extern void MatrixRotate (Matrix *, float, float, float);
|
||||
extern void MatrixMirrorHorizontal (Matrix *, float);
|
||||
|
||||
/* Defined in wp_viewporter.c. */
|
||||
|
||||
|
@ -1717,6 +1750,15 @@ extern void RunProcess (ProcessQueue *, char **);
|
|||
extern ProcessQueue *MakeProcessQueue (void);
|
||||
extern int ProcessPoll (struct pollfd *, nfds_t, struct timespec *);
|
||||
|
||||
/* Defined in fence_ring.c. */
|
||||
|
||||
typedef struct _Fence Fence;
|
||||
|
||||
extern Fence *GetFence (void);
|
||||
extern void FenceRetain (Fence *);
|
||||
extern void FenceAwait (Fence *);
|
||||
extern XSyncFence FenceToXFence (Fence *);
|
||||
|
||||
/* Utility functions that don't belong in a specific file. */
|
||||
|
||||
#define ArrayElements(arr) (sizeof (arr) / sizeof (arr)[0])
|
||||
|
|
2
egl.c
2
egl.c
|
@ -35,6 +35,8 @@ along with 12to11. If not, see <https://www.gnu.org/licenses/>. */
|
|||
|
||||
#include "linux-dmabuf-unstable-v1.h"
|
||||
|
||||
/* TODO: implement buffer transforms. */
|
||||
|
||||
/* These are flags for the DrmFormats. */
|
||||
|
||||
enum
|
||||
|
|
95
fns.c
95
fns.c
|
@ -403,6 +403,101 @@ XLExtendRegion (pixman_region32_t *dst, pixman_region32_t *src,
|
|||
XLFree (dst_rects);
|
||||
}
|
||||
|
||||
static void
|
||||
TransformBox (pixman_box32_t *box, BufferTransform transform,
|
||||
int width, int height)
|
||||
{
|
||||
pixman_box32_t work;
|
||||
|
||||
switch (transform)
|
||||
{
|
||||
case Normal:
|
||||
work = *box;
|
||||
break;
|
||||
|
||||
case CounterClockwise90:
|
||||
work.x1 = height - box->y2;
|
||||
work.y1 = box->x1;
|
||||
work.x2 = height - box->y1;
|
||||
work.y2 = box->x2;
|
||||
break;
|
||||
|
||||
case CounterClockwise180:
|
||||
work.x1 = width - box->x2;
|
||||
work.y1 = height - box->y2;
|
||||
work.x2 = width - box->x1;
|
||||
work.y2 = height - box->y1;
|
||||
break;
|
||||
|
||||
case CounterClockwise270:
|
||||
work.x1 = box->y1;
|
||||
work.y1 = width - box->x2;
|
||||
work.x2 = box->y2;
|
||||
work.y2 = width - box->x1;
|
||||
break;
|
||||
|
||||
case Flipped:
|
||||
work.x1 = width - box->x2;
|
||||
work.y1 = box->y1;
|
||||
work.x2 = width - box->x1;
|
||||
work.y2 = box->y2;
|
||||
break;
|
||||
|
||||
case Flipped90:
|
||||
work.x1 = box->y1;
|
||||
work.y1 = box->x1;
|
||||
work.x2 = box->y2;
|
||||
work.y2 = box->x2;
|
||||
break;
|
||||
|
||||
case Flipped180:
|
||||
work.x1 = box->x1;
|
||||
work.y1 = height - box->y2;
|
||||
work.x2 = box->x2;
|
||||
work.y2 = height - box->y1;
|
||||
break;
|
||||
|
||||
case Flipped270:
|
||||
work.x1 = height - box->y2;
|
||||
work.y1 = width - box->x2;
|
||||
work.x2 = height - box->y1;
|
||||
work.y2 = width - box->x1;
|
||||
break;
|
||||
}
|
||||
|
||||
*box = work;
|
||||
}
|
||||
|
||||
void
|
||||
XLTransformRegion (pixman_region32_t *dst, pixman_region32_t *src,
|
||||
BufferTransform transform, int width, int height)
|
||||
{
|
||||
int nrects, i;
|
||||
pixman_box32_t *src_rects;
|
||||
pixman_box32_t *dst_rects;
|
||||
|
||||
src_rects = pixman_region32_rectangles (src, &nrects);
|
||||
|
||||
if (nrects < 128)
|
||||
dst_rects = alloca (nrects * sizeof *dst_rects);
|
||||
else
|
||||
dst_rects = XLMalloc (nrects * sizeof *dst_rects);
|
||||
|
||||
for (i = 0; i < nrects; ++i)
|
||||
{
|
||||
dst_rects[i] = src_rects[i];
|
||||
|
||||
/* width and height should be in the transformed space! */
|
||||
TransformBox (&dst_rects[i], transform, width, height);
|
||||
}
|
||||
|
||||
pixman_region32_fini (dst);
|
||||
pixman_region32_init_rects (dst, dst_rects, nrects);
|
||||
|
||||
if (nrects >= 128)
|
||||
XLFree (dst_rects);
|
||||
}
|
||||
|
||||
int
|
||||
XLOpenShm (void)
|
||||
{
|
||||
|
|
|
@ -81,6 +81,9 @@ struct _BufferActivityRecord
|
|||
/* The counter ID. */
|
||||
uint64_t id;
|
||||
|
||||
/* The sync fence. */
|
||||
Fence *fence;
|
||||
|
||||
/* The forward links to the three lists. */
|
||||
BufferActivityRecord *buffer_next, *target_next, *global_next;
|
||||
|
||||
|
@ -127,6 +130,9 @@ struct _PictureBuffer
|
|||
/* Flags. */
|
||||
int flags;
|
||||
|
||||
/* The width and height of the buffer. */
|
||||
short width, height;
|
||||
|
||||
/* The last draw params associated with the picture. */
|
||||
DrawParams params;
|
||||
|
||||
|
@ -138,6 +144,8 @@ struct _PictureBuffer
|
|||
|
||||
/* Ongoing buffer activity. */
|
||||
BufferActivityRecord activity;
|
||||
|
||||
int compositable;
|
||||
};
|
||||
|
||||
enum
|
||||
|
@ -264,6 +272,9 @@ struct _DmaBufRecord
|
|||
|
||||
/* The depth of the pixmap. */
|
||||
int depth;
|
||||
|
||||
/* The width and height. */
|
||||
short width, height;
|
||||
};
|
||||
|
||||
/* Hash table mapping between presentation windows and targets. */
|
||||
|
@ -388,6 +399,9 @@ static PresentCompletionCallback all_completion_callbacks;
|
|||
/* Whether or not direct presentation should be used. */
|
||||
static Bool use_direct_presentation;
|
||||
|
||||
/* Whether or not to use sync fences. Currently never set. */
|
||||
static Bool use_sync_fences;
|
||||
|
||||
/* XRender, DRI3 and XPresent-based renderer. A RenderTarget is just
|
||||
a Picture. Here is a rough explanation of how the buffer release
|
||||
machinery works.
|
||||
|
@ -489,7 +503,7 @@ FindBufferActivityRecord (PictureBuffer *buffer, PictureTarget *target)
|
|||
|
||||
static void
|
||||
RecordBufferActivity (PictureBuffer *buffer, PictureTarget *target,
|
||||
uint64_t roundtrip_id)
|
||||
uint64_t roundtrip_id, Fence *fence)
|
||||
{
|
||||
BufferActivityRecord *record;
|
||||
|
||||
|
@ -530,7 +544,23 @@ RecordBufferActivity (PictureBuffer *buffer, PictureTarget *target,
|
|||
record->target = target;
|
||||
}
|
||||
|
||||
/* If there is already a fence, wait for it to complete. */
|
||||
if (record->fence)
|
||||
{
|
||||
/* Flush any trigger fence request that might have been
|
||||
made. */
|
||||
XFlush (compositor.display);
|
||||
|
||||
/* Start waiting. */
|
||||
FenceAwait (record->fence);
|
||||
}
|
||||
|
||||
if (fence)
|
||||
/* Retain the fence. */
|
||||
FenceRetain (fence);
|
||||
|
||||
record->id = roundtrip_id;
|
||||
record->fence = fence;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -599,6 +629,13 @@ MaybeRunIdleCallbacks (PictureBuffer *buffer, PictureTarget *target)
|
|||
static void
|
||||
UnlinkActivityRecord (BufferActivityRecord *record)
|
||||
{
|
||||
/* Wait for the sync fence. */
|
||||
|
||||
if (record->fence)
|
||||
FenceAwait (record->fence);
|
||||
|
||||
record->fence = NULL;
|
||||
|
||||
record->buffer_last->buffer_next = record->buffer_next;
|
||||
record->buffer_next->buffer_last = record->buffer_last;
|
||||
record->target_last->target_next = record->target_next;
|
||||
|
@ -943,6 +980,11 @@ DestroyRenderTarget (RenderTarget target)
|
|||
activity_last = activity_record;
|
||||
activity_record = activity_record->target_next;
|
||||
|
||||
if (activity_last->fence)
|
||||
/* The TriggerFence request might not have been flushed. So
|
||||
flush it now to avoid hangs. */
|
||||
XFlush (compositor.display);
|
||||
|
||||
UnlinkActivityRecord (activity_last);
|
||||
XLFree (activity_last);
|
||||
}
|
||||
|
@ -1099,6 +1141,15 @@ GetSourceY (DrawParams *params)
|
|||
return 0.0;
|
||||
}
|
||||
|
||||
static BufferTransform
|
||||
GetBufferTransform (DrawParams *params)
|
||||
{
|
||||
if (params->flags & TransformSet)
|
||||
return params->transform;
|
||||
|
||||
return Normal;
|
||||
}
|
||||
|
||||
static Bool
|
||||
CompareStretch (DrawParams *params, DrawParams *other)
|
||||
{
|
||||
|
@ -1115,6 +1166,82 @@ CompareStretch (DrawParams *params, DrawParams *other)
|
|||
return True;
|
||||
}
|
||||
|
||||
static void
|
||||
ApplyInverseTransform (PictureBuffer *buffer, Matrix *matrix,
|
||||
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. */
|
||||
|
||||
width = buffer->width;
|
||||
height = buffer->height;
|
||||
|
||||
switch (transform)
|
||||
{
|
||||
case Normal:
|
||||
break;
|
||||
|
||||
case CounterClockwise90:
|
||||
/* 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);
|
||||
break;
|
||||
|
||||
case CounterClockwise180:
|
||||
/* Apply clockwise 180 degree rotation around the center. */
|
||||
MatrixRotate (matrix, M_PI, width / 2.0f, height / 2.0f);
|
||||
break;
|
||||
|
||||
case CounterClockwise270:
|
||||
/* Apply clockwise 90 degree rotation around the origin. */
|
||||
MatrixRotate (matrix, M_PI * 0.5, 0, 0);
|
||||
|
||||
/* Translate by the height. */
|
||||
MatrixTranslate (matrix, -height, 0);
|
||||
break;
|
||||
|
||||
case 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. */
|
||||
MatrixTranslate (matrix, -height, 0);
|
||||
break;
|
||||
|
||||
case Flipped180:
|
||||
/* Apply horizontal flip. */
|
||||
MatrixMirrorHorizontal (matrix, width);
|
||||
|
||||
/* Apply clockwise 180 degree rotation around the center. */
|
||||
MatrixRotate (matrix, M_PI, width / 2.0f, height / 2.0f);
|
||||
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. */
|
||||
MatrixTranslate (matrix, 0, -width);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
MaybeApplyTransform (PictureBuffer *buffer, DrawParams *params)
|
||||
{
|
||||
|
@ -1124,6 +1251,8 @@ MaybeApplyTransform (PictureBuffer *buffer, DrawParams *params)
|
|||
if (GetScale (params) == GetScale (&buffer->params)
|
||||
&& GetSourceX (params) == GetSourceX (&buffer->params)
|
||||
&& GetSourceY (params) == GetSourceY (&buffer->params)
|
||||
&& (GetBufferTransform (params)
|
||||
== GetBufferTransform (&buffer->params))
|
||||
&& CompareStretch (params, &buffer->params))
|
||||
/* Nothing changed. */
|
||||
return;
|
||||
|
@ -1138,6 +1267,10 @@ MaybeApplyTransform (PictureBuffer *buffer, DrawParams *params)
|
|||
{
|
||||
MatrixIdentity (&ftransform);
|
||||
|
||||
if (params->flags & TransformSet)
|
||||
ApplyInverseTransform (buffer, &ftransform,
|
||||
params->transform);
|
||||
|
||||
/* Note that these must be applied in the right order. First,
|
||||
the scale is applied. Then, the offset, and finally the
|
||||
stretch. */
|
||||
|
@ -1173,6 +1306,7 @@ Composite (RenderBuffer buffer, RenderTarget target,
|
|||
{
|
||||
PictureBuffer *picture_buffer;
|
||||
PictureTarget *picture_target;
|
||||
XLList *tem;
|
||||
|
||||
picture_buffer = buffer.pointer;
|
||||
picture_target = target.pointer;
|
||||
|
@ -1191,8 +1325,19 @@ Composite (RenderBuffer buffer, RenderTarget target,
|
|||
/* dst-x, dst-y, width, height. */
|
||||
x, y, width, height);
|
||||
|
||||
for (tem = picture_target->buffers_used; tem; tem = tem->next)
|
||||
{
|
||||
/* Return if the buffer is already in the buffers_used list.
|
||||
Otherwise, FinishRender will try to wait for a fence that has
|
||||
not yet been triggered. */
|
||||
|
||||
if (tem->data == picture_buffer)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Record pending buffer activity; the roundtrip message is then
|
||||
sent later. */
|
||||
|
||||
picture_target->buffers_used
|
||||
= XLListPrepend (picture_target->buffers_used, picture_buffer);
|
||||
}
|
||||
|
@ -1203,22 +1348,41 @@ FinishRender (RenderTarget target, pixman_region32_t *damage)
|
|||
XLList *tem, *last;
|
||||
PictureTarget *pict_target;
|
||||
uint64_t roundtrip_id;
|
||||
Fence *fence;
|
||||
|
||||
pict_target = target.pointer;
|
||||
|
||||
if (!pict_target->buffers_used)
|
||||
/* No buffers were used. */
|
||||
return;
|
||||
|
||||
/* Finish rendering. This function then sends a single roundtrip
|
||||
message and records buffer activity for each buffer involved in
|
||||
the update based on that. */
|
||||
|
||||
roundtrip_id = SendRoundtripMessage ();
|
||||
pict_target = target.pointer;
|
||||
tem = pict_target->buffers_used;
|
||||
|
||||
if (use_sync_fences)
|
||||
{
|
||||
/* Get a sync fence, then trigger it. */
|
||||
fence = GetFence ();
|
||||
|
||||
/* Trigger the fence. */
|
||||
XSyncTriggerFence (compositor.display, FenceToXFence (fence));
|
||||
}
|
||||
else
|
||||
fence = NULL;
|
||||
|
||||
while (tem)
|
||||
{
|
||||
last = tem;
|
||||
tem = tem->next;
|
||||
|
||||
/* Record buffer activity on this one buffer. */
|
||||
/* Record buffer activity on this one buffer. A reference to
|
||||
the fence will be held. */
|
||||
RecordBufferActivity (last->data, pict_target,
|
||||
roundtrip_id);
|
||||
roundtrip_id, fence);
|
||||
|
||||
/* Free the list element. */
|
||||
XLFree (last);
|
||||
|
@ -1933,6 +2097,8 @@ BufferFromDmaBuf (DmaBufAttributes *attributes, Bool *error)
|
|||
buffer->picture = picture;
|
||||
buffer->pixmap = pixmap;
|
||||
buffer->depth = depth;
|
||||
buffer->width = attributes->width;
|
||||
buffer->height = attributes->height;
|
||||
|
||||
/* Initialize the list of release records. */
|
||||
buffer->pending.buffer_next = &buffer->pending;
|
||||
|
@ -2008,6 +2174,8 @@ FinishDmaBufRecord (DmaBufRecord *pending, Bool success)
|
|||
buffer->picture = picture;
|
||||
buffer->pixmap = pending->pixmap;
|
||||
buffer->depth = pending->depth;
|
||||
buffer->width = pending->width;
|
||||
buffer->height = pending->height;
|
||||
|
||||
/* Initialize the list of release records. */
|
||||
buffer->pending.buffer_next = &buffer->pending;
|
||||
|
@ -2110,6 +2278,9 @@ BufferFromDmaBufAsync (DmaBufAttributes *attributes,
|
|||
= PictFormatForDmabufFormat (attributes->drm_format);
|
||||
record->pixmap = pixmap;
|
||||
record->depth = depth;
|
||||
record->width = attributes->width;
|
||||
record->height = attributes->height;
|
||||
|
||||
XLAssert (record->format != NULL);
|
||||
|
||||
record->next = pending_success.next;
|
||||
|
@ -2218,6 +2389,8 @@ BufferFromShm (SharedMemoryAttributes *attributes, Bool *error)
|
|||
buffer->picture = picture;
|
||||
buffer->pixmap = pixmap;
|
||||
buffer->depth = depth;
|
||||
buffer->width = attributes->width;
|
||||
buffer->height = attributes->height;
|
||||
|
||||
/* Initialize the list of release records. */
|
||||
buffer->pending.buffer_next = &buffer->pending;
|
||||
|
@ -2380,6 +2553,11 @@ FreeAnyBuffer (RenderBuffer buffer)
|
|||
activity_last = activity_record;
|
||||
activity_record = activity_record->buffer_next;
|
||||
|
||||
if (activity_last->fence)
|
||||
/* The TriggerFence request might not have been flushed. So
|
||||
flush it now to avoid hangs. */
|
||||
XFlush (compositor.display);
|
||||
|
||||
UnlinkActivityRecord (activity_last);
|
||||
XLFree (activity_last);
|
||||
}
|
||||
|
|
122
subcompositor.c
122
subcompositor.c
|
@ -276,6 +276,10 @@ struct _View
|
|||
/* Function called upon the view potentially being resized. */
|
||||
void (*maybe_resized) (View *);
|
||||
|
||||
/* Some data associated with this view. Can be a surface or
|
||||
something else. */
|
||||
void *data;
|
||||
|
||||
/* The damaged and opaque regions. */
|
||||
pixman_region32_t damage, opaque;
|
||||
|
||||
|
@ -289,16 +293,15 @@ struct _View
|
|||
(or topmost parent if the view hierarchy is detached). */
|
||||
int abs_x, abs_y;
|
||||
|
||||
/* Some data associated with this view. Can be a surface or
|
||||
something else. */
|
||||
void *data;
|
||||
|
||||
/* The scale of this view. */
|
||||
int scale;
|
||||
|
||||
/* Flags; whether or not this view is unmapped, etc. */
|
||||
int flags;
|
||||
|
||||
/* Any transform associated with this view. */
|
||||
BufferTransform transform;
|
||||
|
||||
/* The viewport data. */
|
||||
double src_x, src_y, crop_width, crop_height, dest_width, dest_height;
|
||||
|
||||
|
@ -495,6 +498,8 @@ MakeView (void)
|
|||
pixman_region32_init (&view->damage);
|
||||
pixman_region32_init (&view->opaque);
|
||||
pixman_region32_init (&view->input);
|
||||
|
||||
view->transform = Normal;
|
||||
#endif
|
||||
|
||||
return view;
|
||||
|
@ -1627,6 +1632,60 @@ GetContentScale (int scale)
|
|||
return -scale + 1;
|
||||
}
|
||||
|
||||
static BufferTransform
|
||||
InvertTransform (BufferTransform transform)
|
||||
{
|
||||
switch (transform)
|
||||
{
|
||||
case CounterClockwise270:
|
||||
return CounterClockwise90;
|
||||
|
||||
case CounterClockwise90:
|
||||
return CounterClockwise270;
|
||||
|
||||
default:
|
||||
return transform;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
BufferWidthAfterTransform (View *view)
|
||||
{
|
||||
if (RotatesDimensions (view->transform))
|
||||
return XLBufferHeight (view->buffer);
|
||||
|
||||
return XLBufferWidth (view->buffer);
|
||||
}
|
||||
|
||||
static int
|
||||
BufferHeightAfterTransform (View *view)
|
||||
{
|
||||
if (RotatesDimensions (view->transform))
|
||||
return XLBufferWidth (view->buffer);
|
||||
|
||||
return XLBufferHeight (view->buffer);
|
||||
}
|
||||
|
||||
static void
|
||||
TransformBufferDamage (pixman_region32_t *damage,
|
||||
pixman_region32_t *source,
|
||||
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. */
|
||||
width = XLBufferWidth (view->buffer);
|
||||
height = XLBufferHeight (view->buffer);
|
||||
|
||||
/* Transform the damage. */
|
||||
XLTransformRegion (damage, source, inverse, width, height);
|
||||
}
|
||||
|
||||
void
|
||||
ViewDamageBuffer (View *view, pixman_region32_t *damage)
|
||||
{
|
||||
|
@ -1638,9 +1697,10 @@ ViewDamageBuffer (View *view, pixman_region32_t *damage)
|
|||
if (!view->buffer)
|
||||
return;
|
||||
|
||||
if (!view->scale && !IsViewported (view))
|
||||
/* There is no scale nor viewport. Just damage the view
|
||||
directly. */
|
||||
if (view->transform == Normal
|
||||
&& !view->scale && !IsViewported (view))
|
||||
/* There is no scale, transform, nor viewport. Just damage the
|
||||
view directly. */
|
||||
ViewDamage (view, damage);
|
||||
else
|
||||
{
|
||||
|
@ -1651,8 +1711,17 @@ ViewDamageBuffer (View *view, pixman_region32_t *damage)
|
|||
x_factor = GetContentScale (view->scale);
|
||||
y_factor = GetContentScale (view->scale);
|
||||
|
||||
/* Scale the region. */
|
||||
XLScaleRegion (&temp, damage, x_factor, y_factor);
|
||||
if (view->transform != Normal)
|
||||
{
|
||||
/* Transform the given buffer damage if need be. */
|
||||
TransformBufferDamage (&temp, damage, view);
|
||||
|
||||
/* Scale the region. */
|
||||
XLScaleRegion (&temp, &temp, x_factor, y_factor);
|
||||
}
|
||||
else
|
||||
/* Scale the region. */
|
||||
XLScaleRegion (&temp, damage, x_factor, y_factor);
|
||||
|
||||
/* Next, apply the viewport. */
|
||||
if (IsViewported (view))
|
||||
|
@ -1671,9 +1740,9 @@ ViewDamageBuffer (View *view, pixman_region32_t *damage)
|
|||
current buffer width/height. */
|
||||
if (crop_width == -1)
|
||||
{
|
||||
crop_width = (XLBufferWidth (view->buffer)
|
||||
crop_width = (BufferWidthAfterTransform (view)
|
||||
* GetContentScale (view->scale));
|
||||
crop_height = (XLBufferHeight (view->buffer)
|
||||
crop_height = (BufferHeightAfterTransform (view)
|
||||
* GetContentScale (view->scale));
|
||||
}
|
||||
|
||||
|
@ -1738,7 +1807,7 @@ ViewWidth (View *view)
|
|||
scaling. */
|
||||
return ceil (view->dest_width);
|
||||
|
||||
width = XLBufferWidth (view->buffer);
|
||||
width = BufferWidthAfterTransform (view);
|
||||
|
||||
if (view->scale < 0)
|
||||
return ceil (width * (abs (view->scale) + 1));
|
||||
|
@ -1761,7 +1830,7 @@ ViewHeight (View *view)
|
|||
scaling. */
|
||||
return ceil (view->dest_height);
|
||||
|
||||
height = XLBufferHeight (view->buffer);
|
||||
height = BufferHeightAfterTransform (view);
|
||||
|
||||
if (view->scale < 0)
|
||||
return ceil (height * (abs (view->scale) + 1));
|
||||
|
@ -1781,6 +1850,23 @@ ViewSetScale (View *view, int scale)
|
|||
ViewAfterSizeUpdate (view);
|
||||
}
|
||||
|
||||
void
|
||||
ViewSetTransform (View *view, BufferTransform transform)
|
||||
{
|
||||
BufferTransform old_transform;
|
||||
|
||||
if (view->transform == transform)
|
||||
return;
|
||||
|
||||
old_transform = view->transform;
|
||||
view->transform = transform;
|
||||
|
||||
if (RotatesDimensions (transform)
|
||||
!= RotatesDimensions (old_transform))
|
||||
/* Subcompositor bounds may have changed. */
|
||||
ViewAfterSizeUpdate (view);
|
||||
}
|
||||
|
||||
void
|
||||
ViewSetViewport (View *view, double src_x, double src_y,
|
||||
double crop_width, double crop_height,
|
||||
|
@ -1829,6 +1915,12 @@ ViewComputeTransform (View *view, DrawParams *params, Bool draw)
|
|||
params->off_x = 0.0;
|
||||
params->off_y = 0.0;
|
||||
|
||||
if (view->transform != Normal)
|
||||
{
|
||||
params->flags |= TransformSet;
|
||||
params->transform = view->transform;
|
||||
}
|
||||
|
||||
if (view->scale)
|
||||
{
|
||||
/* There is a scale, so set it. */
|
||||
|
@ -1856,9 +1948,9 @@ ViewComputeTransform (View *view, DrawParams *params, Bool draw)
|
|||
|
||||
if (params->crop_width == -1)
|
||||
{
|
||||
params->crop_width = (XLBufferWidth (view->buffer)
|
||||
params->crop_width = (BufferWidthAfterTransform (view)
|
||||
* GetContentScale (view->scale));
|
||||
params->crop_height = (XLBufferHeight (view->buffer)
|
||||
params->crop_height = (BufferHeightAfterTransform (view)
|
||||
* GetContentScale (view->scale));
|
||||
}
|
||||
}
|
||||
|
|
103
surface.c
103
surface.c
|
@ -506,6 +506,13 @@ GetEffectiveScale (int scale)
|
|||
return scale;
|
||||
}
|
||||
|
||||
static void
|
||||
ApplyBufferTransform (Surface *surface)
|
||||
{
|
||||
ViewSetTransform (surface->view,
|
||||
surface->current_state.transform);
|
||||
}
|
||||
|
||||
static void
|
||||
ApplyScale (Surface *surface)
|
||||
{
|
||||
|
@ -665,8 +672,12 @@ ApplyViewport (Surface *surface)
|
|||
|
||||
if (state->buffer)
|
||||
{
|
||||
max_width = XLBufferWidth (state->buffer);
|
||||
max_height = XLBufferHeight (state->buffer);
|
||||
max_width = (RotatesDimensions (state->transform)
|
||||
? XLBufferHeight (state->buffer)
|
||||
: XLBufferWidth (state->buffer));
|
||||
max_height = (RotatesDimensions (state->transform)
|
||||
? XLBufferWidth (state->buffer)
|
||||
: XLBufferHeight (state->buffer));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -787,8 +798,16 @@ CheckViewportValues (Surface *surface)
|
|||
/* A buffer is attached and a viewport source rectangle is set;
|
||||
check that it remains in bounds. */
|
||||
|
||||
width = XLBufferWidth (state->buffer);
|
||||
height = XLBufferHeight (state->buffer);
|
||||
if (RotatesDimensions (state->transform))
|
||||
{
|
||||
width = XLBufferHeight (state->buffer);
|
||||
height = XLBufferWidth (state->buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
width = XLBufferWidth (state->buffer);
|
||||
height = XLBufferHeight (state->buffer);
|
||||
}
|
||||
|
||||
if (state->src_x + state->src_width - 1 >= width / state->buffer_scale
|
||||
|| state->src_y + state->src_height - 1 >= height / state->buffer_scale)
|
||||
|
@ -897,6 +916,9 @@ SavePendingState (Surface *surface)
|
|||
surface->cached_state.buffer_scale
|
||||
= surface->pending_state.buffer_scale;
|
||||
|
||||
if (surface->pending_state.pending & PendingBufferTransform)
|
||||
surface->cached_state.transform = surface->pending_state.transform;
|
||||
|
||||
if (surface->pending_state.pending & PendingViewportDest)
|
||||
{
|
||||
surface->cached_state.dest_width
|
||||
|
@ -1029,6 +1051,12 @@ InternalCommit (Surface *surface, State *pending)
|
|||
ApplyScale (surface);
|
||||
}
|
||||
|
||||
if (pending->pending & PendingBufferTransform)
|
||||
{
|
||||
surface->current_state.transform = pending->transform;
|
||||
ApplyBufferTransform (surface);
|
||||
}
|
||||
|
||||
if (pending->pending & PendingInputRegion)
|
||||
{
|
||||
pixman_region32_copy (&surface->current_state.input,
|
||||
|
@ -1173,13 +1201,61 @@ Commit (struct wl_client *client, struct wl_resource *resource)
|
|||
InternalCommit (surface, &surface->pending_state);
|
||||
}
|
||||
|
||||
static Bool
|
||||
GetBufferTransform (int32_t wayland_transform,
|
||||
BufferTransform *transform)
|
||||
{
|
||||
switch (wayland_transform)
|
||||
{
|
||||
case WL_OUTPUT_TRANSFORM_NORMAL:
|
||||
*transform = Normal;
|
||||
return True;
|
||||
|
||||
case WL_OUTPUT_TRANSFORM_90:
|
||||
*transform = CounterClockwise90;
|
||||
return True;
|
||||
|
||||
case WL_OUTPUT_TRANSFORM_180:
|
||||
*transform = CounterClockwise180;
|
||||
return True;
|
||||
|
||||
case WL_OUTPUT_TRANSFORM_270:
|
||||
*transform = CounterClockwise270;
|
||||
return True;
|
||||
|
||||
case WL_OUTPUT_TRANSFORM_FLIPPED:
|
||||
*transform = Flipped;
|
||||
return True;
|
||||
|
||||
case WL_OUTPUT_TRANSFORM_FLIPPED_90:
|
||||
*transform = Flipped90;
|
||||
return True;
|
||||
|
||||
case WL_OUTPUT_TRANSFORM_FLIPPED_180:
|
||||
*transform = Flipped180;
|
||||
return True;
|
||||
|
||||
case WL_OUTPUT_TRANSFORM_FLIPPED_270:
|
||||
*transform = Flipped270;
|
||||
return True;
|
||||
}
|
||||
|
||||
return False;
|
||||
}
|
||||
|
||||
static void
|
||||
SetBufferTransform (struct wl_client *client, struct wl_resource *resource,
|
||||
int32_t transform)
|
||||
{
|
||||
if (transform != WL_OUTPUT_TRANSFORM_NORMAL)
|
||||
wl_resource_post_error (resource, WL_DISPLAY_ERROR_IMPLEMENTATION,
|
||||
"this compositor does not support buffer transforms");
|
||||
Surface *surface;
|
||||
|
||||
surface = wl_resource_get_user_data (resource);
|
||||
|
||||
if (!GetBufferTransform (transform, &surface->pending_state.transform))
|
||||
wl_resource_post_error (resource, WL_SURFACE_ERROR_INVALID_TRANSFORM,
|
||||
"invalid transform specified");
|
||||
else
|
||||
surface->pending_state.pending |= PendingBufferTransform;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1249,6 +1325,7 @@ InitState (State *state)
|
|||
state->pending = PendingNone;
|
||||
state->buffer = NULL;
|
||||
state->buffer_scale = 1;
|
||||
state->transform = Normal;
|
||||
|
||||
/* Initialize the sentinel node. */
|
||||
state->frame_callbacks.next = &state->frame_callbacks;
|
||||
|
@ -1508,18 +1585,6 @@ XLSurfaceReleaseRole (Surface *surface, Role *role)
|
|||
RunUnmapCallbacks (surface);
|
||||
}
|
||||
|
||||
void
|
||||
XLStateAttachBuffer (State *state, ExtBuffer *buffer)
|
||||
{
|
||||
AttachBuffer (state, buffer);
|
||||
}
|
||||
|
||||
void
|
||||
XLStateDetachBuffer (State *state)
|
||||
{
|
||||
ClearBuffer (state);
|
||||
}
|
||||
|
||||
|
||||
/* Various other functions exported for roles. */
|
||||
|
||||
|
|
6
time.c
6
time.c
|
@ -303,6 +303,12 @@ InitTime (void)
|
|||
supported = XSyncInitialize (compositor.display,
|
||||
&xsync_major, &xsync_minor);
|
||||
|
||||
if (xsync_major < 3 || (xsync_major == 3 && xsync_minor < 1))
|
||||
{
|
||||
fprintf (stderr, "Sync fences are not supported by this X server\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (!supported)
|
||||
{
|
||||
fprintf (stderr, "A compatible version of the synchronization"
|
||||
|
|
52
transform.c
52
transform.c
|
@ -132,6 +132,58 @@ MatrixScale (Matrix *transform, float sx, float sy)
|
|||
MatrixMultiply (copy, temp, transform);
|
||||
}
|
||||
|
||||
void
|
||||
MatrixRotate (Matrix *transform, float theta, float x, float y)
|
||||
{
|
||||
Matrix temp, copy;
|
||||
|
||||
/* Translate the matrix to x, y, and then perform rotation by the
|
||||
given angle in radians and translate back. As the transform is
|
||||
being performed in the X coordinate system, the given angle
|
||||
describes a clockwise rotation. */
|
||||
|
||||
MatrixIdentity (&temp);
|
||||
memcpy (copy, transform, sizeof copy);
|
||||
|
||||
Index (temp, 0, 2) = x;
|
||||
Index (temp, 1, 2) = y;
|
||||
|
||||
MatrixMultiply (copy, temp, transform);
|
||||
MatrixIdentity (&temp);
|
||||
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, 1, 1) = cosf (theta);
|
||||
|
||||
MatrixMultiply (copy, temp, transform);
|
||||
MatrixIdentity (&temp);
|
||||
memcpy (copy, transform, sizeof copy);
|
||||
|
||||
Index (temp, 0, 2) = -x;
|
||||
Index (temp, 1, 2) = -y;
|
||||
|
||||
MatrixMultiply (copy, temp, transform);
|
||||
}
|
||||
|
||||
void
|
||||
MatrixMirrorHorizontal (Matrix *transform, float width)
|
||||
{
|
||||
Matrix temp, copy;
|
||||
|
||||
/* Scale the matrix by -1, and then apply a tx of width, in effect
|
||||
flipping the image horizontally. */
|
||||
|
||||
MatrixIdentity (&temp);
|
||||
memcpy (copy, transform, sizeof copy);
|
||||
|
||||
Index (temp, 0, 0) = -1.0f;
|
||||
Index (temp, 0, 2) = width;
|
||||
|
||||
MatrixMultiply (copy, temp, transform);
|
||||
}
|
||||
|
||||
void
|
||||
MatrixExport (Matrix *transform, XTransform *xtransform)
|
||||
{
|
||||
|
|
Loading…
Add table
Reference in a new issue