forked from 12to11/12to11
Add support for DRM leasing and significantly rework composition code
* 12to11.c (HandleCmdline): Improve messages printed during -help. (XLMain): Initialize DRM leasing. * 12to11.man: Document changes. * Imakefile (LOCAL_LIBRARIES): Add xcb-randr, xf86drm and XPresent. (SRCS): Add drm_lease.c. (OBJS): Add drm_lease.o. * atoms.c (names): Add CONNECTOR_ID. (CONNECTOR_ID): New atom. (XLInitAtoms): Intern CONNECTOR_ID. * compositor.h (struct _RenderFuncs): Require event mask to be passed to target_from_window. New functions `set_standard_event_mask', `present_to_window', `cancel_presentation_callback', and `cancel_presentation'. (struct _BufferFuncs): Move buffer release machinery here. (enum _FrameMode): New enum. * egl.c (TargetFromWindow, SetStandardEventMask, egl_render_funcs): Adjust functions accordingly. * frame_clock.c (struct _FrameClock): New fields `end_frame_called' and `pending_sync_value'. (HandleEndFrame, PostEndFrame, StartFrame, EndFrame): Clean up frame synchronization code. Do not end upon predicted presentation time if EndFrame was not called in time. (FreezeForValue): New function. (XLFrameClockHandleFrameEvent): Defer actually freezing until StartFrame happens. (XLFrameClockGetFrameTime): New function. * icon_surface.c (ReleaseBuffer): Use RenderWaitForIdle. (RunFrameCallbacks, AfterFrame): Pass frame clock to callbacks. Use frame time if available. (XLGetIconSurface): Require wait_for_idle to work. * output.c (change_hook): New hook. (XLHandleOneXEventForOutputs): Run hook if set. (XLOutputSetChangeFunction): New function. (XLInitRROutputs): Select for RRResourceChangeNotify if providers are supported. * picture_renderer.c (struct _PresentRecord) (struct _BufferActivityRecord, struct _IdleCallback) (struct _PictureBuffer, struct _PictureTarget) (struct _DrmFormatInfo, struct _DmaBufRecord) (struct _PresentCompletionCallback): New record structures. (all_formats, SendRoundtripMessage, FindBufferActivityRecord) (RecordBufferActivity, RunIdleCallbacks, MaybeRunIdleCallbacks) (UnlinkActivityRecord, HandleActivityEvent, InitRenderFuncs) (TargetFromDrawable, TargetFromPixmap, TargetFromWindow) (SetStandardEventMask, NoteTargetSize, PictureFromTarget) (DestroyRenderTarget, FillBoxesWithTransparency) (ServerRegionFromRegion, ClearRectangle, Composite) (FindPresentRecord, AllocateRecord, PresentToWindow) (CancelPresentationCallback, CancelPresentation) (picture_render_funcs, FindSupportedModifiers, InitDrmFormats) (PictFormatIsPresentable, BufferFromDmaBuf, FinishDmaBufRecord) (BufferFromDmaBufAsync, BufferFromShm, BufferFromSinglePixel) (FreeShmBuffer, FreeDmabufBuffer, FreeSinglePixelBuffer) (AddIdleCallback, CancelIdleCallback, IsBufferIdle) (IdleEventPredicate, WaitForIdle, SetNeedWaitForIdle) (picture_buffer_funcs, HandlePresentCompleteNotify) (HandlePresentIdleNotify, HandlePresentationEvent) (HandleOneXEventForPictureRenderer, InitPictureRenderer): Allow presenting pixmaps directly, and move buffer release tracking machinery here. * renderer.c (RenderTargetFromWindow): Update signature. (RenderPresentToWindow, RenderCancelPresentationCallback) (RenderCancelPresentation, RenderAddIdleCallback) (RegisterStaticRenderer): New wrapper functions. * run.c (HandleOneXEvent): Handle picture renderer events earlier. * seat.c (MaybeCreateCursor): Require wait_for_idle. (ReleaseBuffer): Wait for buffer to become idle on each target in the cursor ring. * subcompositor.c (struct _Subcompositor): New callback `note_frame'. (SubcompositorSetNoteFrameCallback, NoViewsAfter) (PresentCompletedCallback): New functions. (SubcompositorUpdate): Try to present the buffer if possible, and run completion callbacks. (SubcompositorFree): Free presentation key. * surface.c (XLSurfaceRunFrameCallbacksMs): New function. * text_input.c: Improve commentary. * xdg-shell.xml: Update from wayland-protocols. * xdg_surface.c (struct _XdgRole): New fields `pending_frame', `last_specified_serial'. (struct _ReleaseLaterRecord): Replace free function with idle callback key and xdg role pointers. (RemoveRecord): Delete function. (FreeRecords): Stop cancelling buffer destroy listener. (ReleaseLaterExtBufferFunc): Delete function. (RunFrameCallbacks): Use frame clock time if it is set. (HandleReleaseLaterMessage): Delete function. (BufferIdleCallback): New function. (ReleaseLater): Delete function. (XLHandleXEventForXdgSurfaces): Stop handling buffer release events here. (AckConfigure): Improve debug code and reject duplicate serials. (Commit): Unfreeze earlier; also, in general... (NoteFrame): Move frame handling implementation here. (ReleaseBuffer, Subframe, EndSubframe, AfterFrame, ResizeForMap) (SelectExtraEvents): Set standard event mask. (XLGetXdgSurface, XLXdgRoleSendConfigure): ...Replace frame clock logic with that in NoteFrame.
This commit is contained in:
parent
de26ffa123
commit
713eb811ea
18 changed files with 2046 additions and 311 deletions
3
12to11.c
3
12to11.c
|
@ -98,7 +98,7 @@ HandleCmdline (Display *dpy, int argc, char **argv)
|
||||||
{
|
{
|
||||||
print_usage:
|
print_usage:
|
||||||
fprintf (stderr,
|
fprintf (stderr,
|
||||||
"usage: %s [-name name] [-class class] [-xrm resourcestring]...\n",
|
"usage: %s [-name name] [-class class] [-xrm resourcestring...]\n",
|
||||||
argv[0]);
|
argv[0]);
|
||||||
exit (!strcmp (argv[i], "-help") ? 0 : 1);
|
exit (!strcmp (argv[i], "-help") ? 0 : 1);
|
||||||
}
|
}
|
||||||
|
@ -224,6 +224,7 @@ XLMain (int argc, char **argv)
|
||||||
XLInitDecoration ();
|
XLInitDecoration ();
|
||||||
XLInitTextInput ();
|
XLInitTextInput ();
|
||||||
XLInitSinglePixelBuffer ();
|
XLInitSinglePixelBuffer ();
|
||||||
|
XLInitDrmLease ();
|
||||||
|
|
||||||
/* This has to come after the rest of the initialization. */
|
/* This has to come after the rest of the initialization. */
|
||||||
DetermineServerTime ();
|
DetermineServerTime ();
|
||||||
|
|
14
12to11.man
14
12to11.man
|
@ -3,7 +3,7 @@
|
||||||
12to11 - Wayland to X protocol translator
|
12to11 - Wayland to X protocol translator
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.B 12to11
|
.B 12to11
|
||||||
[\-\fBclass\fP \fIclass\fP] [\-\fBname\fP \fIname\fP] [\-\fBxrm\fP \fIresourcestring\fP]...
|
[\-\fBclass\fP \fIclass\fP] [\-\fBname\fP \fIname\fP] [\-\fBxrm\fP \fIresourcestring\fP...]
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
.I 12to11
|
.I 12to11
|
||||||
starts a Wayland compositor on the next available socket;
|
starts a Wayland compositor on the next available socket;
|
||||||
|
@ -212,6 +212,16 @@ Protocol Version
|
||||||
zwp_linux_explicit_synchronization_v1 2
|
zwp_linux_explicit_synchronization_v1 2
|
||||||
.TE
|
.TE
|
||||||
.PP
|
.PP
|
||||||
|
When the X server supports version 1.6 or later of the X Resize,
|
||||||
|
Rotate and Reflect Extension, the following Wayland protocol is also
|
||||||
|
supported:
|
||||||
|
.TS H
|
||||||
|
lb lb
|
||||||
|
lb n .
|
||||||
|
Protocol Version
|
||||||
|
wp_drm_lease_device_v1 1
|
||||||
|
.TE
|
||||||
|
.PP
|
||||||
However, Wayland clients are allowed to continue to access data from
|
However, Wayland clients are allowed to continue to access data from
|
||||||
the \fBCLIPBOARD\fP and \fBPRIMARY\fP selections even when they do not
|
the \fBCLIPBOARD\fP and \fBPRIMARY\fP selections even when they do not
|
||||||
have the keyboard focus, against the restrictions put out in the
|
have the keyboard focus, against the restrictions put out in the
|
||||||
|
@ -242,5 +252,5 @@ vast majority of clients seem not to make use of this feature, and
|
||||||
implementing it would be a lot of trouble.
|
implementing it would be a lot of trouble.
|
||||||
.SH "SEE ALSO"
|
.SH "SEE ALSO"
|
||||||
X(7), Xorg(1)
|
X(7), Xorg(1)
|
||||||
.SH AUTHOR
|
.SH AUTHORS
|
||||||
Various contributors.
|
Various contributors.
|
||||||
|
|
10
Imakefile
10
Imakefile
|
@ -1,4 +1,4 @@
|
||||||
#include "libraries.def"
|
#include "12to11.conf"
|
||||||
|
|
||||||
#ifndef HasPosixThreads
|
#ifndef HasPosixThreads
|
||||||
#error "Posix threads are required"
|
#error "Posix threads are required"
|
||||||
|
@ -10,7 +10,8 @@ DEPLIBS = $(DEPXLIB) $(DEPEXTENSIONLIB) $(DEPXRANDRLIB) $(DEPXRENDERLIB) \
|
||||||
|
|
||||||
LOCAL_LIBRARIES = $(XLIB) $(EXTENSIONLIB) $(XCBLIB) $(XCB) $(XCB_SHM) \
|
LOCAL_LIBRARIES = $(XLIB) $(EXTENSIONLIB) $(XCBLIB) $(XCB) $(XCB_SHM) \
|
||||||
$(XRANDRLIB) $(PIXMAN) $(XRENDERLIB) $(XILIB) $(XKBFILELIB) $(XFIXESLIB) \
|
$(XRANDRLIB) $(PIXMAN) $(XRENDERLIB) $(XILIB) $(XKBFILELIB) $(XFIXESLIB) \
|
||||||
$(XCB_DRI3) $(XCB_SHAPE) $(WAYLAND_SERVER)
|
$(XCB_DRI3) $(XCB_SHAPE) $(WAYLAND_SERVER) $(XCB_RANDR) $(DRM) \
|
||||||
|
$(XPRESENTLIB)
|
||||||
|
|
||||||
INCLUDES := $(DRMINCLUDES) $(PIXMANINCLUDES)
|
INCLUDES := $(DRMINCLUDES) $(PIXMANINCLUDES)
|
||||||
|
|
||||||
|
@ -22,7 +23,7 @@ SRCS = 12to11.c run.c alloc.c fns.c output.c compositor.c \
|
||||||
icon_surface.c primary_selection.c renderer.c \
|
icon_surface.c primary_selection.c renderer.c \
|
||||||
picture_renderer.c explicit_synchronization.c transform.c \
|
picture_renderer.c explicit_synchronization.c transform.c \
|
||||||
wp_viewporter.c decoration.c text_input.c \
|
wp_viewporter.c decoration.c text_input.c \
|
||||||
single_pixel_buffer.c
|
single_pixel_buffer.c drm_lease.c
|
||||||
|
|
||||||
OBJS = 12to11.o run.o alloc.o fns.o output.o compositor.o \
|
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 \
|
surface.o region.o shm.o atoms.o subcompositor.o positioner.o \
|
||||||
|
@ -32,7 +33,7 @@ OBJS = 12to11.o run.o alloc.o fns.o output.o compositor.o \
|
||||||
icon_surface.o primary_selection.o renderer.o \
|
icon_surface.o primary_selection.o renderer.o \
|
||||||
picture_renderer.o explicit_synchronization.o transform.o \
|
picture_renderer.o explicit_synchronization.o transform.o \
|
||||||
wp_viewporter.o decoration.o text_input.o \
|
wp_viewporter.o decoration.o text_input.o \
|
||||||
single_pixel_buffer.o
|
single_pixel_buffer.o drm_lease.o
|
||||||
|
|
||||||
GENHEADERS = transfer_atoms.h
|
GENHEADERS = transfer_atoms.h
|
||||||
|
|
||||||
|
@ -115,6 +116,7 @@ ScannerTarget(viewporter)
|
||||||
ScannerTarget(xdg-decoration-unstable-v1)
|
ScannerTarget(xdg-decoration-unstable-v1)
|
||||||
ScannerTarget(text-input-unstable-v3)
|
ScannerTarget(text-input-unstable-v3)
|
||||||
ScannerTarget(single-pixel-buffer-v1)
|
ScannerTarget(single-pixel-buffer-v1)
|
||||||
|
ScannerTarget(drm-lease-v1)
|
||||||
|
|
||||||
/* Make OBJS depend on scanner headers, and depend on both them and SRCS. */
|
/* Make OBJS depend on scanner headers, and depend on both them and SRCS. */
|
||||||
$(OBJS): $(GENHEADERS)
|
$(OBJS): $(GENHEADERS)
|
||||||
|
|
7
atoms.c
7
atoms.c
|
@ -108,6 +108,7 @@ static const char *names[] =
|
||||||
"_NET_WM_WINDOW_TYPE",
|
"_NET_WM_WINDOW_TYPE",
|
||||||
"_NET_WM_WINDOW_TYPE_MENU",
|
"_NET_WM_WINDOW_TYPE_MENU",
|
||||||
"_NET_WM_WINDOW_TYPE_DND",
|
"_NET_WM_WINDOW_TYPE_DND",
|
||||||
|
"CONNECTOR_ID",
|
||||||
|
|
||||||
/* These are automatically generated from mime.txt. */
|
/* These are automatically generated from mime.txt. */
|
||||||
DirectTransferAtomNames
|
DirectTransferAtomNames
|
||||||
|
@ -129,7 +130,8 @@ Atom _NET_WM_OPAQUE_REGION, _XL_BUFFER_RELEASE, _NET_WM_SYNC_REQUEST_COUNTER,
|
||||||
XdndActionPrivate, XdndActionList, XdndActionDescription, XdndProxy,
|
XdndActionPrivate, XdndActionList, XdndActionDescription, XdndProxy,
|
||||||
XdndEnter, XdndPosition, XdndStatus, XdndLeave, XdndDrop, XdndFinished,
|
XdndEnter, XdndPosition, XdndStatus, XdndLeave, XdndDrop, XdndFinished,
|
||||||
_NET_WM_FRAME_TIMINGS, _NET_WM_BYPASS_COMPOSITOR, WM_STATE,
|
_NET_WM_FRAME_TIMINGS, _NET_WM_BYPASS_COMPOSITOR, WM_STATE,
|
||||||
_NET_WM_WINDOW_TYPE, _NET_WM_WINDOW_TYPE_MENU, _NET_WM_WINDOW_TYPE_DND;
|
_NET_WM_WINDOW_TYPE, _NET_WM_WINDOW_TYPE_MENU, _NET_WM_WINDOW_TYPE_DND,
|
||||||
|
CONNECTOR_ID;
|
||||||
|
|
||||||
XrmQuark resource_quark, app_quark, QString;
|
XrmQuark resource_quark, app_quark, QString;
|
||||||
|
|
||||||
|
@ -283,9 +285,10 @@ XLInitAtoms (void)
|
||||||
_NET_WM_WINDOW_TYPE = atoms[58];
|
_NET_WM_WINDOW_TYPE = atoms[58];
|
||||||
_NET_WM_WINDOW_TYPE_MENU = atoms[59];
|
_NET_WM_WINDOW_TYPE_MENU = atoms[59];
|
||||||
_NET_WM_WINDOW_TYPE_DND = atoms[60];
|
_NET_WM_WINDOW_TYPE_DND = atoms[60];
|
||||||
|
CONNECTOR_ID = atoms[61];
|
||||||
|
|
||||||
/* This is automatically generated. */
|
/* This is automatically generated. */
|
||||||
DirectTransferAtomInit (atoms, 61);
|
DirectTransferAtomInit (atoms, 62);
|
||||||
|
|
||||||
/* Now, initialize quarks. */
|
/* Now, initialize quarks. */
|
||||||
resource_quark = XrmPermStringToQuark (compositor.resource_name);
|
resource_quark = XrmPermStringToQuark (compositor.resource_name);
|
||||||
|
|
87
compositor.h
87
compositor.h
|
@ -121,9 +121,15 @@ typedef struct _ShmFormat ShmFormat;
|
||||||
|
|
||||||
typedef enum _Operation Operation;
|
typedef enum _Operation Operation;
|
||||||
|
|
||||||
|
typedef void *IdleCallbackKey;
|
||||||
|
typedef void *PresentCompletionKey;
|
||||||
|
|
||||||
typedef void (*DmaBufSuccessFunc) (RenderBuffer, void *);
|
typedef void (*DmaBufSuccessFunc) (RenderBuffer, void *);
|
||||||
typedef void (*DmaBufFailureFunc) (void *);
|
typedef void (*DmaBufFailureFunc) (void *);
|
||||||
|
|
||||||
|
typedef void (*BufferIdleFunc) (RenderBuffer, void *);
|
||||||
|
typedef void (*PresentCompletionFunc) (void *);
|
||||||
|
|
||||||
enum _Operation
|
enum _Operation
|
||||||
{
|
{
|
||||||
OperationOver,
|
OperationOver,
|
||||||
|
@ -250,11 +256,14 @@ struct _RenderFuncs
|
||||||
Bool (*init_render_funcs) (void);
|
Bool (*init_render_funcs) (void);
|
||||||
|
|
||||||
/* Create a rendering target for the given window. */
|
/* Create a rendering target for the given window. */
|
||||||
RenderTarget (*target_from_window) (Window);
|
RenderTarget (*target_from_window) (Window, unsigned long);
|
||||||
|
|
||||||
/* Create a rendering target for the given pixmap. */
|
/* Create a rendering target for the given pixmap. */
|
||||||
RenderTarget (*target_from_pixmap) (Pixmap);
|
RenderTarget (*target_from_pixmap) (Pixmap);
|
||||||
|
|
||||||
|
/* Set the standard event mask of the target. */
|
||||||
|
void (*set_standard_event_mask) (RenderTarget, unsigned long);
|
||||||
|
|
||||||
/* Set the target width and height. This can be NULL. */
|
/* Set the target width and height. This can be NULL. */
|
||||||
void (*note_target_size) (RenderTarget, int, int);
|
void (*note_target_size) (RenderTarget, int, int);
|
||||||
|
|
||||||
|
@ -327,6 +336,22 @@ struct _RenderFuncs
|
||||||
called. */
|
called. */
|
||||||
int (*get_finish_fence) (Bool *);
|
int (*get_finish_fence) (Bool *);
|
||||||
|
|
||||||
|
/* Directly present the given buffer to the window, without copying,
|
||||||
|
and possibly flip the buffer contents to the screen, all while
|
||||||
|
possibly being synchronized with the vertical refresh. Call the
|
||||||
|
supplied callback when the presentation completes. May be
|
||||||
|
NULL. */
|
||||||
|
PresentCompletionKey (*present_to_window) (RenderTarget, RenderBuffer,
|
||||||
|
pixman_region32_t *,
|
||||||
|
PresentCompletionFunc, void *);
|
||||||
|
|
||||||
|
/* Cancel the given presentation callback. */
|
||||||
|
void (*cancel_presentation_callback) (PresentCompletionKey);
|
||||||
|
|
||||||
|
/* Cancel any presentation that might have happened to the window
|
||||||
|
backing the given target. */
|
||||||
|
void (*cancel_presentation) (RenderTarget);
|
||||||
|
|
||||||
/* Some flags. NeverAges means targets always preserve contents
|
/* Some flags. NeverAges means targets always preserve contents
|
||||||
that were previously drawn. */
|
that were previously drawn. */
|
||||||
int flags;
|
int flags;
|
||||||
|
@ -404,6 +429,28 @@ struct _BufferFuncs
|
||||||
by being copied to an offscreen buffer. */
|
by being copied to an offscreen buffer. */
|
||||||
Bool (*can_release_now) (RenderBuffer);
|
Bool (*can_release_now) (RenderBuffer);
|
||||||
|
|
||||||
|
/* Run a callback once the buffer contents become idle on the given
|
||||||
|
target. NULL if flags contains ImmediateRelease. The callback
|
||||||
|
is also run when the buffer is destroyed, but not when the target
|
||||||
|
is destroyed; in that case, the callback key simply becomes
|
||||||
|
invalid. */
|
||||||
|
IdleCallbackKey (*add_idle_callback) (RenderBuffer, RenderTarget,
|
||||||
|
BufferIdleFunc, void *);
|
||||||
|
|
||||||
|
/* Cancel the given idle callback. */
|
||||||
|
void (*cancel_idle_callback) (IdleCallbackKey);
|
||||||
|
|
||||||
|
/* Return whether or not the buffer is idle. NULL if flags contains
|
||||||
|
ImmediateRelease. */
|
||||||
|
Bool (*is_buffer_idle) (RenderBuffer, RenderTarget);
|
||||||
|
|
||||||
|
/* Wait for a buffer to become idle on the given target. May be
|
||||||
|
NULL. */
|
||||||
|
void (*wait_for_idle) (RenderBuffer, RenderTarget);
|
||||||
|
|
||||||
|
/* Ensure wait_for_idle can be called. May be NULL. */
|
||||||
|
void (*set_need_wait_for_idle) (RenderTarget);
|
||||||
|
|
||||||
/* Called during renderer initialization. */
|
/* Called during renderer initialization. */
|
||||||
void (*init_buffer_funcs) (void);
|
void (*init_buffer_funcs) (void);
|
||||||
};
|
};
|
||||||
|
@ -414,8 +461,9 @@ extern void RegisterStaticRenderer (const char *, RenderFuncs *,
|
||||||
BufferFuncs *);
|
BufferFuncs *);
|
||||||
extern void InitRenderers (void);
|
extern void InitRenderers (void);
|
||||||
|
|
||||||
extern RenderTarget RenderTargetFromWindow (Window);
|
extern RenderTarget RenderTargetFromWindow (Window, unsigned long);
|
||||||
extern RenderTarget RenderTargetFromPixmap (Pixmap);
|
extern RenderTarget RenderTargetFromPixmap (Pixmap);
|
||||||
|
extern void RenderSetStandardEventMask (RenderTarget, unsigned long);
|
||||||
extern void RenderNoteTargetSize (RenderTarget, int, int);
|
extern void RenderNoteTargetSize (RenderTarget, int, int);
|
||||||
extern Picture RenderPictureFromTarget (RenderTarget);
|
extern Picture RenderPictureFromTarget (RenderTarget);
|
||||||
extern void RenderFreePictureFromTarget (Picture);
|
extern void RenderFreePictureFromTarget (Picture);
|
||||||
|
@ -432,6 +480,12 @@ extern RenderFence RenderImportFdFence (int, Bool *);
|
||||||
extern void RenderWaitFence (RenderFence);
|
extern void RenderWaitFence (RenderFence);
|
||||||
extern void RenderDeleteFence (RenderFence);
|
extern void RenderDeleteFence (RenderFence);
|
||||||
extern int RenderGetFinishFence (Bool *);
|
extern int RenderGetFinishFence (Bool *);
|
||||||
|
extern PresentCompletionKey RenderPresentToWindow (RenderTarget, RenderBuffer,
|
||||||
|
pixman_region32_t *,
|
||||||
|
PresentCompletionFunc,
|
||||||
|
void *);
|
||||||
|
extern void RenderCancelPresentationCallback (PresentCompletionKey);
|
||||||
|
extern void RenderCancelPresentation (RenderTarget);
|
||||||
|
|
||||||
extern DrmFormat *RenderGetDrmFormats (int *);
|
extern DrmFormat *RenderGetDrmFormats (int *);
|
||||||
extern dev_t RenderGetRenderDevice (Bool *);
|
extern dev_t RenderGetRenderDevice (Bool *);
|
||||||
|
@ -450,6 +504,12 @@ extern void RenderFreeSinglePixelBuffer (RenderBuffer);
|
||||||
extern void RenderUpdateBufferForDamage (RenderBuffer, pixman_region32_t *,
|
extern void RenderUpdateBufferForDamage (RenderBuffer, pixman_region32_t *,
|
||||||
DrawParams *);
|
DrawParams *);
|
||||||
extern Bool RenderCanReleaseNow (RenderBuffer);
|
extern Bool RenderCanReleaseNow (RenderBuffer);
|
||||||
|
extern IdleCallbackKey RenderAddIdleCallback (RenderBuffer, RenderTarget,
|
||||||
|
BufferIdleFunc, void *);
|
||||||
|
extern void RenderCancelIdleCallback (IdleCallbackKey);
|
||||||
|
extern Bool RenderIsBufferIdle (RenderBuffer, RenderTarget);
|
||||||
|
extern void RenderWaitForIdle (RenderBuffer, RenderTarget);
|
||||||
|
extern void RenderSetNeedWaitForIdle (RenderTarget);
|
||||||
|
|
||||||
/* Defined in run.c. */
|
/* Defined in run.c. */
|
||||||
|
|
||||||
|
@ -610,6 +670,15 @@ typedef struct _View View;
|
||||||
typedef struct _List List;
|
typedef struct _List List;
|
||||||
typedef struct _Subcompositor Subcompositor;
|
typedef struct _Subcompositor Subcompositor;
|
||||||
|
|
||||||
|
typedef enum _FrameMode FrameMode;
|
||||||
|
|
||||||
|
enum _FrameMode
|
||||||
|
{
|
||||||
|
ModeStarted,
|
||||||
|
ModeComplete,
|
||||||
|
ModePresented,
|
||||||
|
};
|
||||||
|
|
||||||
extern void SubcompositorInit (void);
|
extern void SubcompositorInit (void);
|
||||||
|
|
||||||
extern Subcompositor *MakeSubcompositor (void);
|
extern Subcompositor *MakeSubcompositor (void);
|
||||||
|
@ -634,6 +703,10 @@ extern void SubcompositorSetBoundsCallback (Subcompositor *,
|
||||||
void (*) (void *, int, int,
|
void (*) (void *, int, int,
|
||||||
int, int),
|
int, int),
|
||||||
void *);
|
void *);
|
||||||
|
extern void SubcompositorSetNoteFrameCallback (Subcompositor *,
|
||||||
|
void (*) (FrameMode, uint64_t,
|
||||||
|
void *),
|
||||||
|
void *);
|
||||||
extern void SubcompositorBounds (Subcompositor *, int *, int *, int *, int *);
|
extern void SubcompositorBounds (Subcompositor *, int *, int *, int *, int *);
|
||||||
extern void SubcompositorSetProjectiveTransform (Subcompositor *, int, int);
|
extern void SubcompositorSetProjectiveTransform (Subcompositor *, int, int);
|
||||||
|
|
||||||
|
@ -964,6 +1037,7 @@ extern void XLDefaultCommit (Surface *);
|
||||||
extern void XLStateAttachBuffer (State *, ExtBuffer *);
|
extern void XLStateAttachBuffer (State *, ExtBuffer *);
|
||||||
extern void XLStateDetachBuffer (State *);
|
extern void XLStateDetachBuffer (State *);
|
||||||
extern void XLSurfaceRunFrameCallbacks (Surface *, struct timespec);
|
extern void XLSurfaceRunFrameCallbacks (Surface *, struct timespec);
|
||||||
|
extern void XLSurfaceRunFrameCallbacksMs (Surface *, uint32_t);
|
||||||
extern CommitCallback *XLSurfaceRunAtCommit (Surface *,
|
extern CommitCallback *XLSurfaceRunAtCommit (Surface *,
|
||||||
void (*) (Surface *, void *),
|
void (*) (Surface *, void *),
|
||||||
void *);
|
void *);
|
||||||
|
@ -1004,6 +1078,7 @@ extern Bool XLGetOutputRectAt (int, int, int *, int *, int *, int *);
|
||||||
extern void *XLAddScaleChangeCallback (void *, void (*) (void *, int));
|
extern void *XLAddScaleChangeCallback (void *, void (*) (void *, int));
|
||||||
extern void XLRemoveScaleChangeCallback (void *);
|
extern void XLRemoveScaleChangeCallback (void *);
|
||||||
extern void XLClearOutputs (Surface *);
|
extern void XLClearOutputs (Surface *);
|
||||||
|
extern void XLOutputSetChangeFunction (void (*) (Time));
|
||||||
|
|
||||||
/* Defined in atoms.c. */
|
/* Defined in atoms.c. */
|
||||||
|
|
||||||
|
@ -1022,7 +1097,8 @@ extern Atom _NET_WM_OPAQUE_REGION, _XL_BUFFER_RELEASE,
|
||||||
XdndActionAsk, XdndActionPrivate, XdndActionList, XdndActionDescription,
|
XdndActionAsk, XdndActionPrivate, XdndActionList, XdndActionDescription,
|
||||||
XdndProxy, XdndEnter, XdndPosition, XdndStatus, XdndLeave, XdndDrop,
|
XdndProxy, XdndEnter, XdndPosition, XdndStatus, XdndLeave, XdndDrop,
|
||||||
XdndFinished, _NET_WM_FRAME_TIMINGS, _NET_WM_BYPASS_COMPOSITOR, WM_STATE,
|
XdndFinished, _NET_WM_FRAME_TIMINGS, _NET_WM_BYPASS_COMPOSITOR, WM_STATE,
|
||||||
_NET_WM_WINDOW_TYPE, _NET_WM_WINDOW_TYPE_MENU, _NET_WM_WINDOW_TYPE_DND;
|
_NET_WM_WINDOW_TYPE, _NET_WM_WINDOW_TYPE_MENU, _NET_WM_WINDOW_TYPE_DND,
|
||||||
|
CONNECTOR_ID;
|
||||||
|
|
||||||
extern XrmQuark resource_quark, app_quark, QString;
|
extern XrmQuark resource_quark, app_quark, QString;
|
||||||
|
|
||||||
|
@ -1062,6 +1138,7 @@ extern void XLFrameClockSetPredictRefresh (FrameClock *);
|
||||||
extern void XLFrameClockDisablePredictRefresh (FrameClock *);
|
extern void XLFrameClockDisablePredictRefresh (FrameClock *);
|
||||||
extern void XLFrameClockSetFreezeCallback (FrameClock *, void (*) (void *),
|
extern void XLFrameClockSetFreezeCallback (FrameClock *, void (*) (void *),
|
||||||
void *);
|
void *);
|
||||||
|
extern uint64_t XLFrameClockGetFrameTime (FrameClock *);
|
||||||
extern void *XLAddCursorClockCallback (void (*) (void *, struct timespec),
|
extern void *XLAddCursorClockCallback (void (*) (void *, struct timespec),
|
||||||
void *);
|
void *);
|
||||||
extern void XLStopCursorClockCallback (void *);
|
extern void XLStopCursorClockCallback (void *);
|
||||||
|
@ -1477,6 +1554,10 @@ extern void XLInitDecoration (void);
|
||||||
|
|
||||||
extern void XLInitSinglePixelBuffer (void);
|
extern void XLInitSinglePixelBuffer (void);
|
||||||
|
|
||||||
|
/* Defined in drm_lease.h. */
|
||||||
|
|
||||||
|
extern void XLInitDrmLease (void);
|
||||||
|
|
||||||
/* Utility functions that don't belong in a specific file. */
|
/* Utility functions that don't belong in a specific file. */
|
||||||
|
|
||||||
#define ArrayElements(arr) (sizeof (arr) / sizeof (arr)[0])
|
#define ArrayElements(arr) (sizeof (arr) / sizeof (arr)[0])
|
||||||
|
|
9
egl.c
9
egl.c
|
@ -1077,7 +1077,7 @@ TryPreserveOnSwap (EGLSurface *surface)
|
||||||
}
|
}
|
||||||
|
|
||||||
static RenderTarget
|
static RenderTarget
|
||||||
TargetFromWindow (Window window)
|
TargetFromWindow (Window window, unsigned long standard_event_mask)
|
||||||
{
|
{
|
||||||
EglTarget *target;
|
EglTarget *target;
|
||||||
|
|
||||||
|
@ -1125,6 +1125,12 @@ TargetFromPixmap (Pixmap pixmap)
|
||||||
return (RenderTarget) (void *) target;
|
return (RenderTarget) (void *) target;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
SetStandardEventMask (RenderTarget target, unsigned long standard_event_mask)
|
||||||
|
{
|
||||||
|
/* Ignored. */
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
NoteTargetSize (RenderTarget target, int width, int height)
|
NoteTargetSize (RenderTarget target, int width, int height)
|
||||||
{
|
{
|
||||||
|
@ -1659,6 +1665,7 @@ static RenderFuncs egl_render_funcs =
|
||||||
.init_render_funcs = InitRenderFuncs,
|
.init_render_funcs = InitRenderFuncs,
|
||||||
.target_from_window = TargetFromWindow,
|
.target_from_window = TargetFromWindow,
|
||||||
.target_from_pixmap = TargetFromPixmap,
|
.target_from_pixmap = TargetFromPixmap,
|
||||||
|
.set_standard_event_mask = SetStandardEventMask,
|
||||||
.note_target_size = NoteTargetSize,
|
.note_target_size = NoteTargetSize,
|
||||||
.picture_from_target = PictureFromTarget,
|
.picture_from_target = PictureFromTarget,
|
||||||
.free_picture_from_target = FreePictureFromTarget,
|
.free_picture_from_target = FreePictureFromTarget,
|
||||||
|
|
101
frame_clock.c
101
frame_clock.c
|
@ -90,6 +90,9 @@ struct _FrameClock
|
||||||
unfrozen until EndFrame. */
|
unfrozen until EndFrame. */
|
||||||
Bool need_configure, frozen, frozen_until_end_frame;
|
Bool need_configure, frozen, frozen_until_end_frame;
|
||||||
|
|
||||||
|
/* Whether or not EndFrame was called after StartFrame. */
|
||||||
|
Bool end_frame_called;
|
||||||
|
|
||||||
/* The wanted configure value. */
|
/* The wanted configure value. */
|
||||||
uint64_t configure_id;
|
uint64_t configure_id;
|
||||||
|
|
||||||
|
@ -111,6 +114,9 @@ struct _FrameClock
|
||||||
|
|
||||||
/* Data for that callback. */
|
/* Data for that callback. */
|
||||||
void *freeze_callback_data;
|
void *freeze_callback_data;
|
||||||
|
|
||||||
|
/* Any pending frame synchronization counter value, or 0. */
|
||||||
|
uint64_t pending_sync_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _CursorClockCallback
|
struct _CursorClockCallback
|
||||||
|
@ -221,9 +227,53 @@ HandleEndFrame (Timer *timer, void *data, struct timespec time)
|
||||||
the frame. */
|
the frame. */
|
||||||
RemoveTimer (timer);
|
RemoveTimer (timer);
|
||||||
clock->end_frame_timer = NULL;
|
clock->end_frame_timer = NULL;
|
||||||
|
|
||||||
|
if (clock->end_frame_called)
|
||||||
EndFrame (clock);
|
EndFrame (clock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Forward declaration. */
|
||||||
|
static void RunFrameCallbacks (FrameClock *);
|
||||||
|
|
||||||
|
static void
|
||||||
|
FreezeForValue (FrameClock *clock, uint64_t counter_value)
|
||||||
|
{
|
||||||
|
/* If it took too long (1 second at 60fps) to obtain the counter
|
||||||
|
value, and said value is now out of date, don't do anything. */
|
||||||
|
|
||||||
|
if (clock->next_frame_id > counter_value)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* The frame clock is now frozen, and we will have to wait for a
|
||||||
|
client to ack_configure and then commit something. */
|
||||||
|
|
||||||
|
if (clock->end_frame_timer)
|
||||||
|
{
|
||||||
|
/* End the frame now, and clear in_frame early. */
|
||||||
|
RemoveTimer (clock->end_frame_timer);
|
||||||
|
clock->end_frame_timer = NULL;
|
||||||
|
|
||||||
|
if (clock->end_frame_called)
|
||||||
|
EndFrame (clock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* counter_value - 240 is the value seen by the compositor when the
|
||||||
|
frame contents were frozen in response to a resize. If it is
|
||||||
|
less than finished_frame_id, run frame callbacks now, or clients
|
||||||
|
like Chromium are confused and hang waiting for frame callbacks
|
||||||
|
to be called. */
|
||||||
|
if (counter_value - 240 <= clock->finished_frame_id)
|
||||||
|
RunFrameCallbacks (clock);
|
||||||
|
|
||||||
|
/* The reason for clearing in_frame is that otherwise a future
|
||||||
|
Commit after the configuration is acknowledged will not be able
|
||||||
|
to start a new frame and restart the frame clock. */
|
||||||
|
clock->in_frame = False;
|
||||||
|
clock->need_configure = True;
|
||||||
|
clock->configure_id = counter_value;
|
||||||
|
clock->frozen = True;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
PostEndFrame (FrameClock *clock)
|
PostEndFrame (FrameClock *clock)
|
||||||
{
|
{
|
||||||
|
@ -320,6 +370,9 @@ StartFrame (FrameClock *clock, Bool urgent, Bool predict)
|
||||||
if (clock->frozen_until_end_frame)
|
if (clock->frozen_until_end_frame)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (clock->in_frame)
|
||||||
|
return;
|
||||||
|
|
||||||
if (clock->need_configure)
|
if (clock->need_configure)
|
||||||
{
|
{
|
||||||
clock->next_frame_id = clock->configure_id;
|
clock->next_frame_id = clock->configure_id;
|
||||||
|
@ -327,6 +380,7 @@ StartFrame (FrameClock *clock, Bool urgent, Bool predict)
|
||||||
}
|
}
|
||||||
|
|
||||||
clock->in_frame = True;
|
clock->in_frame = True;
|
||||||
|
clock->end_frame_called = False;
|
||||||
|
|
||||||
/* Set the clock to an odd value; if we want the compositor to
|
/* Set the clock to an odd value; if we want the compositor to
|
||||||
redraw this frame immediately (since it is running late), make it
|
redraw this frame immediately (since it is running late), make it
|
||||||
|
@ -371,6 +425,10 @@ EndFrame (FrameClock *clock)
|
||||||
|
|
||||||
clock->frozen_until_end_frame = False;
|
clock->frozen_until_end_frame = False;
|
||||||
|
|
||||||
|
/* Signal that end_frame was called and it is now safe to finish the
|
||||||
|
frame from the timer. */
|
||||||
|
clock->end_frame_called = True;
|
||||||
|
|
||||||
if (!clock->in_frame
|
if (!clock->in_frame
|
||||||
/* If the end of the frame has already been signalled, this
|
/* If the end of the frame has already been signalled, this
|
||||||
function should just return instead of increasing the counter
|
function should just return instead of increasing the counter
|
||||||
|
@ -389,6 +447,12 @@ EndFrame (FrameClock *clock)
|
||||||
clock->next_frame_id += 1;
|
clock->next_frame_id += 1;
|
||||||
clock->finished_frame_id = clock->next_frame_id;
|
clock->finished_frame_id = clock->next_frame_id;
|
||||||
|
|
||||||
|
/* The frame has ended. Freeze the frame clock if there is a
|
||||||
|
pending sync value. */
|
||||||
|
if (clock->pending_sync_value)
|
||||||
|
FreezeForValue (clock, clock->pending_sync_value);
|
||||||
|
clock->pending_sync_value = 0;
|
||||||
|
|
||||||
if (!frame_sync_supported)
|
if (!frame_sync_supported)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -570,28 +634,15 @@ XLFrameClockHandleFrameEvent (FrameClock *clock, XEvent *event)
|
||||||
if (value % 2)
|
if (value % 2)
|
||||||
value += 1;
|
value += 1;
|
||||||
|
|
||||||
/* The frame clock is now frozen, and we will have to wait for a
|
/* If a frame is in progress, postpone this frame
|
||||||
client to ack_configure and then commit something. */
|
synchronization message. */
|
||||||
|
if (clock->in_frame && !clock->end_frame_called)
|
||||||
if (clock->end_frame_timer)
|
clock->pending_sync_value = value;
|
||||||
{
|
else
|
||||||
/* End the frame now, and clear in_frame early. */
|
FreezeForValue (clock, value);
|
||||||
RemoveTimer (clock->end_frame_timer);
|
|
||||||
clock->end_frame_timer = NULL;
|
|
||||||
EndFrame (clock);
|
|
||||||
|
|
||||||
/* The reason for clearing in_frame is that otherwise a
|
|
||||||
future Commit after the configuration is acknowledged
|
|
||||||
will not be able to start a new frame and restart the
|
|
||||||
frame clock. */
|
|
||||||
clock->in_frame = False;
|
|
||||||
}
|
|
||||||
|
|
||||||
clock->need_configure = True;
|
|
||||||
clock->configure_id = value;
|
|
||||||
clock->frozen = True;
|
|
||||||
|
|
||||||
if (clock->freeze_callback)
|
if (clock->freeze_callback)
|
||||||
|
/* Call the freeze callback in any case. */
|
||||||
clock->freeze_callback (clock->freeze_callback_data);
|
clock->freeze_callback (clock->freeze_callback_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -731,6 +782,16 @@ XLFrameClockSetFreezeCallback (FrameClock *clock, void (*callback) (void *),
|
||||||
clock->freeze_callback_data = data;
|
clock->freeze_callback_data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
XLFrameClockGetFrameTime (FrameClock *clock)
|
||||||
|
{
|
||||||
|
/* Only return the time if it is actually a valid clock time. */
|
||||||
|
if (!compositor.server_time_monotonic)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return clock->last_frame_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Cursor animation clock-related functions. */
|
/* Cursor animation clock-related functions. */
|
||||||
|
|
||||||
|
|
|
@ -155,9 +155,14 @@ Setup (Surface *surface, Role *role)
|
||||||
static void
|
static void
|
||||||
ReleaseBuffer (Surface *surface, Role *role, ExtBuffer *buffer)
|
ReleaseBuffer (Surface *surface, Role *role, ExtBuffer *buffer)
|
||||||
{
|
{
|
||||||
|
IconSurface *icon;
|
||||||
|
|
||||||
|
icon = IconSurfaceFromRole (role);
|
||||||
|
|
||||||
/* Icon surfaces are not supposed to change much, so doing an XSync
|
/* Icon surfaces are not supposed to change much, so doing an XSync
|
||||||
here is okay. */
|
(or XIfEvent) here is okay. */
|
||||||
XSync (compositor.display, False);
|
RenderWaitForIdle (XLRenderBufferFromBuffer (buffer),
|
||||||
|
icon->target);
|
||||||
|
|
||||||
/* Now really release the buffer. */
|
/* Now really release the buffer. */
|
||||||
XLReleaseBuffer (buffer);
|
XLReleaseBuffer (buffer);
|
||||||
|
@ -213,18 +218,26 @@ NoteBounds (void *data, int min_x, int min_y, int max_x, int max_y)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
RunFrameCallbacks (Surface *surface)
|
RunFrameCallbacks (Surface *surface, FrameClock *clock)
|
||||||
{
|
{
|
||||||
struct timespec time;
|
struct timespec time;
|
||||||
|
uint64_t last_drawn_time;
|
||||||
|
|
||||||
/* Surface can be NULL for various reasons, especially events
|
/* Surface can be NULL for various reasons, especially events
|
||||||
arriving after the icon surface is detached. */
|
arriving after the icon surface is detached. */
|
||||||
if (!surface)
|
if (!surface)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
last_drawn_time = XLFrameClockGetFrameTime (clock);
|
||||||
|
|
||||||
|
if (!last_drawn_time)
|
||||||
|
{
|
||||||
clock_gettime (CLOCK_MONOTONIC, &time);
|
clock_gettime (CLOCK_MONOTONIC, &time);
|
||||||
XLSurfaceRunFrameCallbacks (surface, time);
|
XLSurfaceRunFrameCallbacks (surface, time);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
XLSurfaceRunFrameCallbacksMs (surface, last_drawn_time / 1000);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
AfterFrame (FrameClock *clock, void *data)
|
AfterFrame (FrameClock *clock, void *data)
|
||||||
|
@ -246,7 +259,7 @@ AfterFrame (FrameClock *clock, void *data)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
RunFrameCallbacks (icon->role.surface);
|
RunFrameCallbacks (icon->role.surface, clock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -410,7 +423,11 @@ XLGetIconSurface (Surface *surface)
|
||||||
(unsigned char *) &_NET_WM_WINDOW_TYPE_DND, 1);
|
(unsigned char *) &_NET_WM_WINDOW_TYPE_DND, 1);
|
||||||
|
|
||||||
/* Create a target associated with the window. */
|
/* Create a target associated with the window. */
|
||||||
role->target = RenderTargetFromWindow (role->window);
|
role->target = RenderTargetFromWindow (role->window, None);
|
||||||
|
|
||||||
|
/* For simplicity reasons we do not handle idle notifications
|
||||||
|
asynchronously. */
|
||||||
|
RenderSetNeedWaitForIdle (role->target);
|
||||||
|
|
||||||
/* Create a subcompositor associated with the window. */
|
/* Create a subcompositor associated with the window. */
|
||||||
role->subcompositor = MakeSubcompositor ();
|
role->subcompositor = MakeSubcompositor ();
|
||||||
|
|
48
output.c
48
output.c
|
@ -98,6 +98,9 @@ static ScaleChangeCallback scale_callbacks;
|
||||||
/* The scale factor currently applied on a global basis. */
|
/* The scale factor currently applied on a global basis. */
|
||||||
int global_scale_factor;
|
int global_scale_factor;
|
||||||
|
|
||||||
|
/* Function run upon any kind of XRandR notify event. */
|
||||||
|
static void (*change_hook) (Time);
|
||||||
|
|
||||||
static Bool
|
static Bool
|
||||||
ApplyEnvironment (const char *name, int *variable)
|
ApplyEnvironment (const char *name, int *variable)
|
||||||
{
|
{
|
||||||
|
@ -903,9 +906,38 @@ XLGetOutputRectAt (int x, int y, int *x_out, int *y_out,
|
||||||
Bool
|
Bool
|
||||||
XLHandleOneXEventForOutputs (XEvent *event)
|
XLHandleOneXEventForOutputs (XEvent *event)
|
||||||
{
|
{
|
||||||
|
XRRNotifyEvent *notify;
|
||||||
|
XRROutputPropertyNotifyEvent *property;
|
||||||
|
XRRResourceChangeNotifyEvent *resource;
|
||||||
|
Time time;
|
||||||
|
|
||||||
|
notify = (XRRNotifyEvent *) event;
|
||||||
|
|
||||||
if (event->type == compositor.rr_event_base + RRNotify)
|
if (event->type == compositor.rr_event_base + RRNotify)
|
||||||
{
|
{
|
||||||
NoticeOutputsMaybeChanged ();
|
NoticeOutputsMaybeChanged ();
|
||||||
|
|
||||||
|
if (change_hook)
|
||||||
|
{
|
||||||
|
time = CurrentTime;
|
||||||
|
|
||||||
|
/* See if a timestamp of some sort can be extracted. */
|
||||||
|
switch (notify->subtype)
|
||||||
|
{
|
||||||
|
case RRNotify_OutputProperty:
|
||||||
|
property = (XRROutputPropertyNotifyEvent *) notify;
|
||||||
|
time = property->timestamp;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RRNotify_ResourceChange:
|
||||||
|
resource = (XRRResourceChangeNotifyEvent *) notify;
|
||||||
|
time = resource->timestamp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
change_hook (time);
|
||||||
|
}
|
||||||
|
|
||||||
return True;
|
return True;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1053,6 +1085,12 @@ XLClearOutputs (Surface *surface)
|
||||||
surface->n_outputs = 0;
|
surface->n_outputs = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
XLOutputSetChangeFunction (void (*change_func) (Time))
|
||||||
|
{
|
||||||
|
change_hook = change_func;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
XLInitRROutputs (void)
|
XLInitRROutputs (void)
|
||||||
{
|
{
|
||||||
|
@ -1096,6 +1134,16 @@ XLInitRROutputs (void)
|
||||||
scale_callbacks.next = &scale_callbacks;
|
scale_callbacks.next = &scale_callbacks;
|
||||||
scale_callbacks.last = &scale_callbacks;
|
scale_callbacks.last = &scale_callbacks;
|
||||||
|
|
||||||
|
if (compositor.rr_major > 1
|
||||||
|
&& (compositor.rr_major == 1
|
||||||
|
&& compositor.rr_minor >= 4))
|
||||||
|
XRRSelectInput (compositor.display,
|
||||||
|
DefaultRootWindow (compositor.display),
|
||||||
|
(RRCrtcChangeNotifyMask
|
||||||
|
| RROutputChangeNotifyMask
|
||||||
|
| RROutputPropertyNotifyMask
|
||||||
|
| RRResourceChangeNotifyMask));
|
||||||
|
else
|
||||||
XRRSelectInput (compositor.display,
|
XRRSelectInput (compositor.display,
|
||||||
DefaultRootWindow (compositor.display),
|
DefaultRootWindow (compositor.display),
|
||||||
(RRCrtcChangeNotifyMask
|
(RRCrtcChangeNotifyMask
|
||||||
|
|
1359
picture_renderer.c
1359
picture_renderer.c
File diff suppressed because it is too large
Load diff
79
renderer.c
79
renderer.c
|
@ -69,9 +69,9 @@ AllocateRenderer (void)
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderTarget
|
RenderTarget
|
||||||
RenderTargetFromWindow (Window window)
|
RenderTargetFromWindow (Window window, unsigned long standard_event_mask)
|
||||||
{
|
{
|
||||||
return render_funcs.target_from_window (window);
|
return render_funcs.target_from_window (window, standard_event_mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderTarget
|
RenderTarget
|
||||||
|
@ -80,6 +80,13 @@ RenderTargetFromPixmap (Pixmap pixmap)
|
||||||
return render_funcs.target_from_pixmap (pixmap);
|
return render_funcs.target_from_pixmap (pixmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RenderSetStandardEventMask (RenderTarget target,
|
||||||
|
unsigned long standard_event_mask)
|
||||||
|
{
|
||||||
|
render_funcs.set_standard_event_mask (target, standard_event_mask);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
RenderNoteTargetSize (RenderTarget target, int width, int height)
|
RenderNoteTargetSize (RenderTarget target, int width, int height)
|
||||||
{
|
{
|
||||||
|
@ -177,6 +184,37 @@ RenderGetFinishFence (Bool *error)
|
||||||
return render_funcs.get_finish_fence (error);
|
return render_funcs.get_finish_fence (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PresentCompletionKey
|
||||||
|
RenderPresentToWindow (RenderTarget target, RenderBuffer source,
|
||||||
|
pixman_region32_t *damage,
|
||||||
|
PresentCompletionFunc callback, void *data)
|
||||||
|
{
|
||||||
|
if (!render_funcs.present_to_window)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return render_funcs.present_to_window (target, source,
|
||||||
|
damage, callback,
|
||||||
|
data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RenderCancelPresentationCallback (PresentCompletionKey key)
|
||||||
|
{
|
||||||
|
if (!render_funcs.cancel_presentation_callback)
|
||||||
|
return;
|
||||||
|
|
||||||
|
render_funcs.cancel_presentation_callback (key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RenderCancelPresentation (RenderTarget target)
|
||||||
|
{
|
||||||
|
if (!render_funcs.cancel_presentation)
|
||||||
|
return;
|
||||||
|
|
||||||
|
render_funcs.cancel_presentation (target);
|
||||||
|
}
|
||||||
|
|
||||||
DrmFormat *
|
DrmFormat *
|
||||||
RenderGetDrmFormats (int *n_formats)
|
RenderGetDrmFormats (int *n_formats)
|
||||||
{
|
{
|
||||||
|
@ -269,6 +307,43 @@ RenderCanReleaseNow (RenderBuffer buffer)
|
||||||
return buffer_funcs.can_release_now (buffer);
|
return buffer_funcs.can_release_now (buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IdleCallbackKey
|
||||||
|
RenderAddIdleCallback (RenderBuffer buffer, RenderTarget target,
|
||||||
|
BufferIdleFunc function, void *data)
|
||||||
|
{
|
||||||
|
return buffer_funcs.add_idle_callback (buffer, target, function, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RenderCancelIdleCallback (IdleCallbackKey key)
|
||||||
|
{
|
||||||
|
return buffer_funcs.cancel_idle_callback (key);
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool
|
||||||
|
RenderIsBufferIdle (RenderBuffer buffer, RenderTarget target)
|
||||||
|
{
|
||||||
|
return buffer_funcs.is_buffer_idle (buffer, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RenderWaitForIdle (RenderBuffer buffer, RenderTarget target)
|
||||||
|
{
|
||||||
|
if (!buffer_funcs.wait_for_idle)
|
||||||
|
return;
|
||||||
|
|
||||||
|
buffer_funcs.wait_for_idle (buffer, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RenderSetNeedWaitForIdle (RenderTarget target)
|
||||||
|
{
|
||||||
|
if (!buffer_funcs.set_need_wait_for_idle)
|
||||||
|
return;
|
||||||
|
|
||||||
|
buffer_funcs.set_need_wait_for_idle (target);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
RegisterStaticRenderer (const char *name,
|
RegisterStaticRenderer (const char *name,
|
||||||
RenderFuncs *render_funcs,
|
RenderFuncs *render_funcs,
|
||||||
|
|
6
run.c
6
run.c
|
@ -139,6 +139,9 @@ HandleOneXEvent (XEvent *event)
|
||||||
if (XLHandleXEventForXdgSurfaces (event))
|
if (XLHandleXEventForXdgSurfaces (event))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (HandleOneXEventForPictureRenderer (event))
|
||||||
|
return;
|
||||||
|
|
||||||
if (XLHandleXEventForXdgToplevels (event))
|
if (XLHandleXEventForXdgToplevels (event))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -156,9 +159,6 @@ HandleOneXEvent (XEvent *event)
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (HandleOneXEventForPictureRenderer (event))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (XLHandleOneXEventForXData (event))
|
if (XLHandleOneXEventForXData (event))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
17
seat.c
17
seat.c
|
@ -711,6 +711,10 @@ MaybeCreateCursor (CursorRing *ring, int index)
|
||||||
compositor.n_planes);
|
compositor.n_planes);
|
||||||
ring->targets[index]
|
ring->targets[index]
|
||||||
= RenderTargetFromPixmap (ring->pixmaps[index]);
|
= RenderTargetFromPixmap (ring->pixmaps[index]);
|
||||||
|
|
||||||
|
/* For simplicity reasons we do not handle idle notifications
|
||||||
|
asynchronously. */
|
||||||
|
RenderSetNeedWaitForIdle (ring->targets[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -1208,9 +1212,20 @@ Setup (Surface *surface, Role *role)
|
||||||
static void
|
static void
|
||||||
ReleaseBuffer (Surface *surface, Role *role, ExtBuffer *buffer)
|
ReleaseBuffer (Surface *surface, Role *role, ExtBuffer *buffer)
|
||||||
{
|
{
|
||||||
|
SeatCursor *cursor;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
cursor = CursorFromRole (role);
|
||||||
|
|
||||||
/* Cursors are generally committed only once, so syncing here is
|
/* Cursors are generally committed only once, so syncing here is
|
||||||
OK in terms of efficiency. */
|
OK in terms of efficiency. */
|
||||||
XSync (compositor.display, False);
|
for (i = 0; i < CursorRingElements; ++i)
|
||||||
|
{
|
||||||
|
if (cursor->cursor_ring->pixmaps[i])
|
||||||
|
RenderWaitForIdle (XLRenderBufferFromBuffer (buffer),
|
||||||
|
cursor->cursor_ring->targets[i]);
|
||||||
|
}
|
||||||
|
|
||||||
XLReleaseBuffer (buffer);
|
XLReleaseBuffer (buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
222
subcompositor.c
222
subcompositor.c
|
@ -310,9 +310,6 @@ struct _View
|
||||||
|
|
||||||
struct _Subcompositor
|
struct _Subcompositor
|
||||||
{
|
{
|
||||||
/* Various flags describing the state of this subcompositor. */
|
|
||||||
int state;
|
|
||||||
|
|
||||||
/* List of all inferiors in compositing order. */
|
/* List of all inferiors in compositing order. */
|
||||||
List *inferiors, *last;
|
List *inferiors, *last;
|
||||||
|
|
||||||
|
@ -334,9 +331,29 @@ struct _Subcompositor
|
||||||
/* Function called with the bounds before each update. */
|
/* Function called with the bounds before each update. */
|
||||||
void (*note_bounds) (void *, int, int, int, int);
|
void (*note_bounds) (void *, int, int, int, int);
|
||||||
|
|
||||||
|
/* Function called with the frame counter on each update. */
|
||||||
|
void (*note_frame) (FrameMode, uint64_t, void *);
|
||||||
|
|
||||||
|
/* The current frame counter, incremented with each frame. */
|
||||||
|
uint64_t frame_counter;
|
||||||
|
|
||||||
/* Data for those three functions. */
|
/* Data for those three functions. */
|
||||||
void *opaque_change_data, *input_change_data, *note_bounds_data;
|
void *opaque_change_data, *input_change_data, *note_bounds_data;
|
||||||
|
|
||||||
|
/* Data for the fourth. */
|
||||||
|
void *note_frame_data;
|
||||||
|
|
||||||
|
/* Buffers used to store that damage. */
|
||||||
|
pixman_region32_t prior_damage[2];
|
||||||
|
|
||||||
|
/* The damage region of previous updates. last_damage is what the
|
||||||
|
damage region was 1 update ago, and before_damage is what the
|
||||||
|
damage region was 2 updates ago. */
|
||||||
|
pixman_region32_t *last_damage, *before_damage;
|
||||||
|
|
||||||
|
/* The last attached presentation callback, if any. */
|
||||||
|
PresentCompletionKey present_key;
|
||||||
|
|
||||||
/* The minimum origin of any surface in this subcompositor. Used to
|
/* The minimum origin of any surface in this subcompositor. Used to
|
||||||
compute the actual size of the subcompositor. */
|
compute the actual size of the subcompositor. */
|
||||||
int min_x, min_y;
|
int min_x, min_y;
|
||||||
|
@ -347,15 +364,10 @@ struct _Subcompositor
|
||||||
|
|
||||||
/* An additional offset to apply when drawing to the target. */
|
/* An additional offset to apply when drawing to the target. */
|
||||||
int tx, ty;
|
int tx, ty;
|
||||||
|
|
||||||
/* Buffers used to store that damage. */
|
|
||||||
pixman_region32_t prior_damage[2];
|
|
||||||
|
|
||||||
/* The damage region of previous updates. last_damage is what the
|
|
||||||
damage region was 1 update ago, and before_damage is what the
|
|
||||||
damage region was 2 updates ago. */
|
|
||||||
pixman_region32_t *last_damage, *before_damage;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Various flags describing the state of this subcompositor. */
|
||||||
|
int state;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifndef TEST
|
#ifndef TEST
|
||||||
|
@ -1807,6 +1819,16 @@ SubcompositorSetBoundsCallback (Subcompositor *subcompositor,
|
||||||
subcompositor->note_bounds_data = data;
|
subcompositor->note_bounds_data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SubcompositorSetNoteFrameCallback (Subcompositor *subcompositor,
|
||||||
|
void (*note_frame) (FrameMode, uint64_t,
|
||||||
|
void *),
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
subcompositor->note_frame = note_frame;
|
||||||
|
subcompositor->note_frame_data = data;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
FillBoxesWithTransparency (Subcompositor *subcompositor,
|
FillBoxesWithTransparency (Subcompositor *subcompositor,
|
||||||
pixman_box32_t *boxes, int nboxes)
|
pixman_box32_t *boxes, int nboxes)
|
||||||
|
@ -1917,6 +1939,69 @@ IntersectBoxes (pixman_box32_t *in, pixman_box32_t *other,
|
||||||
return True;
|
return True;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Bool
|
||||||
|
NoViewsAfter (View *first_view)
|
||||||
|
{
|
||||||
|
List *list;
|
||||||
|
View *view;
|
||||||
|
|
||||||
|
list = first_view->link->next;
|
||||||
|
|
||||||
|
while (list != first_view->link)
|
||||||
|
{
|
||||||
|
view = list->view;
|
||||||
|
|
||||||
|
if (!view)
|
||||||
|
goto next_1;
|
||||||
|
|
||||||
|
if (IsViewUnmapped (view))
|
||||||
|
{
|
||||||
|
/* Skip the unmapped view. */
|
||||||
|
list = view->inferior;
|
||||||
|
goto next_1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsSkipped (view))
|
||||||
|
{
|
||||||
|
/* We must skip this view, as it represents (for
|
||||||
|
instance) a subsurface that has been added, but not
|
||||||
|
committed. */
|
||||||
|
goto next_1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!view->buffer)
|
||||||
|
goto next_1;
|
||||||
|
|
||||||
|
/* There is view in front of view that potentially obscures it.
|
||||||
|
Bail out! */
|
||||||
|
return False;
|
||||||
|
|
||||||
|
next_1:
|
||||||
|
list = list->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return True;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
PresentCompletedCallback (void *data)
|
||||||
|
{
|
||||||
|
Subcompositor *subcompositor;
|
||||||
|
|
||||||
|
subcompositor = data;
|
||||||
|
|
||||||
|
/* The presentation callback should still be set here. */
|
||||||
|
XLAssert (subcompositor->present_key != NULL);
|
||||||
|
|
||||||
|
subcompositor->present_key = NULL;
|
||||||
|
|
||||||
|
/* Call the presentation callback if it is still set. */
|
||||||
|
if (subcompositor->note_frame)
|
||||||
|
subcompositor->note_frame (ModePresented,
|
||||||
|
subcompositor->frame_counter,
|
||||||
|
subcompositor->note_frame_data);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SubcompositorUpdate (Subcompositor *subcompositor)
|
SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
{
|
{
|
||||||
|
@ -1928,9 +2013,10 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
int nboxes, i, tx, ty, view_width, view_height;
|
int nboxes, i, tx, ty, view_width, view_height;
|
||||||
Operation op;
|
Operation op;
|
||||||
RenderBuffer buffer;
|
RenderBuffer buffer;
|
||||||
int min_x, min_y;
|
int min_x, min_y, age, n_seen;
|
||||||
int age;
|
|
||||||
DrawParams draw_params;
|
DrawParams draw_params;
|
||||||
|
Bool presented;
|
||||||
|
PresentCompletionKey key;
|
||||||
|
|
||||||
/* Just return if no target was specified. */
|
/* Just return if no target was specified. */
|
||||||
if (!IsTargetAttached (subcompositor))
|
if (!IsTargetAttached (subcompositor))
|
||||||
|
@ -1940,6 +2026,13 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
if (IsFrozen (subcompositor))
|
if (IsFrozen (subcompositor))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (subcompositor->present_key)
|
||||||
|
/* Cancel the presentation callback. The next presentation will
|
||||||
|
either be to an unmapped window, cancel the presentation, or
|
||||||
|
start a new one. */
|
||||||
|
RenderCancelPresentationCallback (subcompositor->present_key);
|
||||||
|
subcompositor->present_key = NULL;
|
||||||
|
|
||||||
list = subcompositor->inferiors;
|
list = subcompositor->inferiors;
|
||||||
min_x = subcompositor->min_x;
|
min_x = subcompositor->min_x;
|
||||||
min_y = subcompositor->min_y;
|
min_y = subcompositor->min_y;
|
||||||
|
@ -1949,6 +2042,8 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
original_start = NULL;
|
original_start = NULL;
|
||||||
pixman_region32_init (&temp);
|
pixman_region32_init (&temp);
|
||||||
pixman_region32_init (&update_region);
|
pixman_region32_init (&update_region);
|
||||||
|
n_seen = 0;
|
||||||
|
presented = False;
|
||||||
|
|
||||||
start = subcompositor->inferiors->next->view;
|
start = subcompositor->inferiors->next->view;
|
||||||
original_start = subcompositor->inferiors->next->view;
|
original_start = subcompositor->inferiors->next->view;
|
||||||
|
@ -2042,6 +2137,9 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
if (!view->buffer)
|
if (!view->buffer)
|
||||||
goto next;
|
goto next;
|
||||||
|
|
||||||
|
/* Increase the number of views seen count. */
|
||||||
|
n_seen++;
|
||||||
|
|
||||||
/* Obtain the view width and height here. */
|
/* Obtain the view width and height here. */
|
||||||
view_width = ViewWidth (view);
|
view_width = ViewWidth (view);
|
||||||
view_height = ViewHeight (view);
|
view_height = ViewHeight (view);
|
||||||
|
@ -2265,8 +2363,16 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
/* If there's nothing to do, return. */
|
/* If there's nothing to do, return. */
|
||||||
|
|
||||||
if (!start)
|
if (!start)
|
||||||
|
/* There is no starting view. Presentation is not cancelled in
|
||||||
|
this case, because the surface should now be unmapped. */
|
||||||
goto complete;
|
goto complete;
|
||||||
|
|
||||||
|
/* Increase the frame count and announce the new frame number. */
|
||||||
|
if (subcompositor->note_frame)
|
||||||
|
subcompositor->note_frame (ModeStarted,
|
||||||
|
++subcompositor->frame_counter,
|
||||||
|
subcompositor->note_frame_data);
|
||||||
|
|
||||||
/* Now update all views from start onwards. */
|
/* Now update all views from start onwards. */
|
||||||
|
|
||||||
list = start->link;
|
list = start->link;
|
||||||
|
@ -2311,6 +2417,7 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
view_width = ViewWidth (view);
|
view_width = ViewWidth (view);
|
||||||
view_height = ViewHeight (view);
|
view_height = ViewHeight (view);
|
||||||
|
|
||||||
|
/* And the buffer. */
|
||||||
buffer = XLRenderBufferFromBuffer (view->buffer);
|
buffer = XLRenderBufferFromBuffer (view->buffer);
|
||||||
|
|
||||||
if (IsGarbaged (subcompositor))
|
if (IsGarbaged (subcompositor))
|
||||||
|
@ -2337,8 +2444,67 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
&draw_params);
|
&draw_params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Compute the transform and put it in draw_params. */
|
||||||
|
ViewComputeTransform (view, &draw_params, True);
|
||||||
|
|
||||||
if (!first)
|
if (!first)
|
||||||
{
|
{
|
||||||
|
/* See if the first mapped and visible view after start is eligible
|
||||||
|
for direct presentation. It is considered eligible if:
|
||||||
|
|
||||||
|
- its bounds match that of the subcompositor.
|
||||||
|
- its depth and masks match that of the subcompositor.
|
||||||
|
- it is not occluded by any other view, above or below.
|
||||||
|
- it has no transform whatsoever.
|
||||||
|
|
||||||
|
Also, presentation is done asynchronously, so we only
|
||||||
|
consider the view as eligible for presentation if
|
||||||
|
completion callbacks are attached. */
|
||||||
|
|
||||||
|
if (!draw_params.flags
|
||||||
|
&& view->abs_x == subcompositor->min_x
|
||||||
|
&& view->abs_y == subcompositor->min_y
|
||||||
|
&& view_width == SubcompositorWidth (subcompositor)
|
||||||
|
&& view_height == SubcompositorHeight (subcompositor)
|
||||||
|
/* N.B. that n_seen is not set (0) if the view is
|
||||||
|
garbaged. */
|
||||||
|
&& (n_seen == 1 || (!n_seen && NoViewsAfter (view)))
|
||||||
|
&& subcompositor->note_frame)
|
||||||
|
{
|
||||||
|
/* Direct presentation is okay. Present the pixmap to
|
||||||
|
the drawable. */
|
||||||
|
if (IsGarbaged (subcompositor))
|
||||||
|
key = RenderPresentToWindow (subcompositor->target, buffer,
|
||||||
|
NULL, PresentCompletedCallback,
|
||||||
|
subcompositor);
|
||||||
|
else
|
||||||
|
key = RenderPresentToWindow (subcompositor->target, buffer,
|
||||||
|
&update_region,
|
||||||
|
PresentCompletedCallback,
|
||||||
|
subcompositor);
|
||||||
|
|
||||||
|
/* Now set presented to whether or not key is non-NULL. */
|
||||||
|
presented = key != NULL;
|
||||||
|
|
||||||
|
/* And set the presentation callback. */
|
||||||
|
subcompositor->present_key = key;
|
||||||
|
|
||||||
|
if (presented)
|
||||||
|
{
|
||||||
|
/* If presentation succeeded, don't composite.
|
||||||
|
Instead, just continue looping to set the input
|
||||||
|
region if garbaged. */
|
||||||
|
|
||||||
|
if (!IsGarbaged (subcompositor) && (age >= 0 && age < 3))
|
||||||
|
/* And if not garbaged, skip everything. */
|
||||||
|
goto present_success;
|
||||||
|
else
|
||||||
|
goto present_success_garbaged;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
RenderCancelPresentation (subcompositor->target);
|
||||||
|
|
||||||
/* The first view with an attached buffer should be drawn
|
/* The first view with an attached buffer should be drawn
|
||||||
with PictOpSrc so that transparency is applied correctly,
|
with PictOpSrc so that transparency is applied correctly,
|
||||||
if it contains the entire update region. */
|
if it contains the entire update region. */
|
||||||
|
@ -2388,10 +2554,11 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
else
|
else
|
||||||
op = OperationOver;
|
op = OperationOver;
|
||||||
|
|
||||||
first = view;
|
if (presented && (IsGarbaged (subcompositor)
|
||||||
|
|| age < 0 || age >= 3))
|
||||||
|
goto present_success_garbaged;
|
||||||
|
|
||||||
/* Compute the transform and put it in draw_params. */
|
first = view;
|
||||||
ViewComputeTransform (view, &draw_params, True);
|
|
||||||
|
|
||||||
if (!IsGarbaged (subcompositor) && (age >= 0 && age < 3))
|
if (!IsGarbaged (subcompositor) && (age >= 0 && age < 3))
|
||||||
{
|
{
|
||||||
|
@ -2428,11 +2595,6 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Clear the damaged area, since it will either be drawn or
|
|
||||||
be obscured. We didn't get a chance to clear the damage
|
|
||||||
earlier, since the compositor was garbaged. */
|
|
||||||
pixman_region32_clear (&view->damage);
|
|
||||||
|
|
||||||
/* If the subcompositor is garbaged, composite the entire
|
/* If the subcompositor is garbaged, composite the entire
|
||||||
view to the right location. */
|
view to the right location. */
|
||||||
RenderComposite (buffer, subcompositor->target, op,
|
RenderComposite (buffer, subcompositor->target, op,
|
||||||
|
@ -2447,6 +2609,12 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
/* height, draw-params. */
|
/* height, draw-params. */
|
||||||
view_height, &draw_params);
|
view_height, &draw_params);
|
||||||
|
|
||||||
|
present_success_garbaged:
|
||||||
|
/* Clear the damaged area, since it will either be drawn or
|
||||||
|
be obscured. We didn't get a chance to clear the damage
|
||||||
|
earlier, since the compositor was garbaged. */
|
||||||
|
pixman_region32_clear (&view->damage);
|
||||||
|
|
||||||
/* Also adjust the opaque and input regions here. */
|
/* Also adjust the opaque and input regions here. */
|
||||||
|
|
||||||
if (pixman_region32_not_empty (&view->opaque)
|
if (pixman_region32_not_empty (&view->opaque)
|
||||||
|
@ -2501,6 +2669,8 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
}
|
}
|
||||||
while (list != subcompositor->inferiors);
|
while (list != subcompositor->inferiors);
|
||||||
|
|
||||||
|
present_success:
|
||||||
|
|
||||||
/* Swap changes to display. */
|
/* Swap changes to display. */
|
||||||
|
|
||||||
if (IsGarbaged (subcompositor) || age < 0 || age >= 3)
|
if (IsGarbaged (subcompositor) || age < 0 || age >= 3)
|
||||||
|
@ -2561,6 +2731,12 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
subcompositor->state &= ~SubcompositorIsGarbaged;
|
subcompositor->state &= ~SubcompositorIsGarbaged;
|
||||||
subcompositor->state &= ~SubcompositorIsOpaqueDirty;
|
subcompositor->state &= ~SubcompositorIsOpaqueDirty;
|
||||||
subcompositor->state &= ~SubcompositorIsInputDirty;
|
subcompositor->state &= ~SubcompositorIsInputDirty;
|
||||||
|
|
||||||
|
/* Call the frame complete function if presentation did not happen. */
|
||||||
|
if (subcompositor->note_frame && !presented)
|
||||||
|
subcompositor->note_frame (ModeComplete,
|
||||||
|
subcompositor->frame_counter,
|
||||||
|
subcompositor->note_frame_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -2735,6 +2911,10 @@ SubcompositorFree (Subcompositor *subcompositor)
|
||||||
pixman_region32_fini (&subcompositor->prior_damage[0]);
|
pixman_region32_fini (&subcompositor->prior_damage[0]);
|
||||||
pixman_region32_fini (&subcompositor->prior_damage[1]);
|
pixman_region32_fini (&subcompositor->prior_damage[1]);
|
||||||
|
|
||||||
|
/* Remove the presentation key. */
|
||||||
|
if (subcompositor->present_key)
|
||||||
|
RenderCancelPresentationCallback (subcompositor->present_key);
|
||||||
|
|
||||||
XLFree (subcompositor);
|
XLFree (subcompositor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
13
surface.c
13
surface.c
|
@ -1599,6 +1599,19 @@ XLSurfaceRunFrameCallbacks (Surface *surface, struct timespec time)
|
||||||
XLSurfaceRunFrameCallbacks (list->data, time);
|
XLSurfaceRunFrameCallbacks (list->data, time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
XLSurfaceRunFrameCallbacksMs (Surface *surface, uint32_t ms_time)
|
||||||
|
{
|
||||||
|
XLList *list;
|
||||||
|
|
||||||
|
RunFrameCallbacks (&surface->current_state.frame_callbacks,
|
||||||
|
ms_time);
|
||||||
|
|
||||||
|
/* Run frame callbacks for each attached subsurface as well. */
|
||||||
|
for (list = surface->subsurfaces; list; list = list->next)
|
||||||
|
XLSurfaceRunFrameCallbacksMs (list->data, ms_time);
|
||||||
|
}
|
||||||
|
|
||||||
CommitCallback *
|
CommitCallback *
|
||||||
XLSurfaceRunAtCommit (Surface *surface,
|
XLSurfaceRunAtCommit (Surface *surface,
|
||||||
void (*commit_func) (Surface *, void *),
|
void (*commit_func) (Surface *, void *),
|
||||||
|
|
|
@ -72,7 +72,7 @@ along with 12to11. If not, see <https://www.gnu.org/licenses/>. */
|
||||||
That means it is impossible to attribute forwarded events or
|
That means it is impossible to attribute forwarded events or
|
||||||
committed text to the correct XIC, and thus it is impossible to
|
committed text to the correct XIC, and thus it is impossible to
|
||||||
look up which seat's TextInput resource an event is actually bound
|
look up which seat's TextInput resource an event is actually bound
|
||||||
for. If one day we move to our own implementation of the XIC
|
for. If one day we move to our own implementation of the XIM
|
||||||
protocol, then it will become possible to properly support
|
protocol, then it will become possible to properly support
|
||||||
multi-seat setups, with one XIC per-client and per-seat.
|
multi-seat setups, with one XIC per-client and per-seat.
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ along with 12to11. If not, see <https://www.gnu.org/licenses/>. */
|
||||||
converted string before being sent to the client.
|
converted string before being sent to the client.
|
||||||
|
|
||||||
This code has many inherent race conditions, just like the
|
This code has many inherent race conditions, just like the
|
||||||
zwp_text_input_v3 protocol itself. As described above, it only
|
zwp_text_input_v3 protocol itself. And as described above, it only
|
||||||
supports one seat due to limitations of the Xlib XIM wrapper. */
|
supports one seat due to limitations of the Xlib XIM wrapper. */
|
||||||
|
|
||||||
typedef struct _TextInputClientInfo TextInputClientInfo;
|
typedef struct _TextInputClientInfo TextInputClientInfo;
|
||||||
|
|
|
@ -454,6 +454,7 @@
|
||||||
<entry name="not_constructed" value="1"/>
|
<entry name="not_constructed" value="1"/>
|
||||||
<entry name="already_constructed" value="2"/>
|
<entry name="already_constructed" value="2"/>
|
||||||
<entry name="unconfigured_buffer" value="3"/>
|
<entry name="unconfigured_buffer" value="3"/>
|
||||||
|
<entry name="invalid_serial" value="4"/>
|
||||||
</enum>
|
</enum>
|
||||||
|
|
||||||
<request name="destroy" type="destructor">
|
<request name="destroy" type="destructor">
|
||||||
|
@ -549,6 +550,17 @@
|
||||||
A client may send multiple ack_configure requests before committing, but
|
A client may send multiple ack_configure requests before committing, but
|
||||||
only the last request sent before a commit indicates which configure
|
only the last request sent before a commit indicates which configure
|
||||||
event the client really is responding to.
|
event the client really is responding to.
|
||||||
|
|
||||||
|
Sending an ack_configure request consumes the serial number sent with
|
||||||
|
the request, as well as serial numbers sent by all configure events
|
||||||
|
sent on this xdg_surface prior to the configure event referenced by
|
||||||
|
the committed serial.
|
||||||
|
|
||||||
|
It is an error to issue multiple ack_configure requests referencing a
|
||||||
|
serial from the same configure event, or to issue an ack_configure
|
||||||
|
request referencing a serial from a configure event issued before the
|
||||||
|
event identified by the last ack_configure request for the same
|
||||||
|
xdg_surface. Doing so will raise an invalid_serial error.
|
||||||
</description>
|
</description>
|
||||||
<arg name="serial" type="uint" summary="the serial from the configure event"/>
|
<arg name="serial" type="uint" summary="the serial from the configure event"/>
|
||||||
</request>
|
</request>
|
||||||
|
|
317
xdg_surface.c
317
xdg_surface.c
|
@ -44,6 +44,7 @@ enum
|
||||||
StateMaybeConfigure = (1 << 6),
|
StateMaybeConfigure = (1 << 6),
|
||||||
StateDirtyFrameExtents = (1 << 7),
|
StateDirtyFrameExtents = (1 << 7),
|
||||||
StateTemporaryBounds = (1 << 8),
|
StateTemporaryBounds = (1 << 8),
|
||||||
|
StateFrameStarted = (1 << 9),
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct _XdgRole XdgRole;
|
typedef struct _XdgRole XdgRole;
|
||||||
|
@ -106,6 +107,9 @@ struct _XdgRole
|
||||||
/* The implementation of this role. */
|
/* The implementation of this role. */
|
||||||
XdgRoleImplementation *impl;
|
XdgRoleImplementation *impl;
|
||||||
|
|
||||||
|
/* The pending frame ID. */
|
||||||
|
uint64_t pending_frame;
|
||||||
|
|
||||||
/* Various role state. */
|
/* Various role state. */
|
||||||
int state;
|
int state;
|
||||||
|
|
||||||
|
@ -123,7 +127,7 @@ struct _XdgRole
|
||||||
XdgState current_state;
|
XdgState current_state;
|
||||||
|
|
||||||
/* Configure event serial. */
|
/* Configure event serial. */
|
||||||
uint32_t conf_serial;
|
uint32_t conf_serial, last_specified_serial;
|
||||||
|
|
||||||
/* The current bounds of the subcompositor. */
|
/* The current bounds of the subcompositor. */
|
||||||
int min_x, min_y, max_x, max_y;
|
int min_x, min_y, max_x, max_y;
|
||||||
|
@ -156,13 +160,16 @@ struct _ReleaseLaterRecord
|
||||||
/* A monotonically (overflow aside) increasing identifier. */
|
/* A monotonically (overflow aside) increasing identifier. */
|
||||||
uint64_t id;
|
uint64_t id;
|
||||||
|
|
||||||
/* Key for the free func. */
|
|
||||||
void *free_func_key;
|
|
||||||
|
|
||||||
/* The buffer that should be released upon receiving this
|
/* The buffer that should be released upon receiving this
|
||||||
message. */
|
message. */
|
||||||
ExtBuffer *buffer;
|
ExtBuffer *buffer;
|
||||||
|
|
||||||
|
/* The idle callback. */
|
||||||
|
IdleCallbackKey key;
|
||||||
|
|
||||||
|
/* The XdgRole. */
|
||||||
|
XdgRole *role;
|
||||||
|
|
||||||
/* The next and last records. */
|
/* The next and last records. */
|
||||||
ReleaseLaterRecord *next, *last;
|
ReleaseLaterRecord *next, *last;
|
||||||
};
|
};
|
||||||
|
@ -170,24 +177,6 @@ struct _ReleaseLaterRecord
|
||||||
/* Event base of the XShape extension. */
|
/* Event base of the XShape extension. */
|
||||||
int shape_base;
|
int shape_base;
|
||||||
|
|
||||||
static void
|
|
||||||
RemoveRecord (ReleaseLaterRecord *record)
|
|
||||||
{
|
|
||||||
/* Removing the sentinel record is invalid. */
|
|
||||||
XLAssert (record->buffer != NULL);
|
|
||||||
|
|
||||||
/* First, make the rest of the list skip RECORD. */
|
|
||||||
record->last->next = record->next;
|
|
||||||
record->next->last = record->last;
|
|
||||||
|
|
||||||
/* Next, remove the buffer listener. */
|
|
||||||
XLBufferCancelRunOnFree (record->buffer,
|
|
||||||
record->free_func_key);
|
|
||||||
|
|
||||||
/* Finally, free RECORD. */
|
|
||||||
XLFree (record);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
DeleteRecord (ReleaseLaterRecord *record)
|
DeleteRecord (ReleaseLaterRecord *record)
|
||||||
{
|
{
|
||||||
|
@ -217,10 +206,6 @@ FreeRecords (ReleaseLaterRecord *records)
|
||||||
/* Release the buffer now. */
|
/* Release the buffer now. */
|
||||||
XLReleaseBuffer (last->buffer);
|
XLReleaseBuffer (last->buffer);
|
||||||
|
|
||||||
/* And cancel the destroy listener. */
|
|
||||||
XLBufferCancelRunOnFree (last->buffer,
|
|
||||||
last->free_func_key);
|
|
||||||
|
|
||||||
/* Before freeing the record itself. */
|
/* Before freeing the record itself. */
|
||||||
XLFree (last);
|
XLFree (last);
|
||||||
}
|
}
|
||||||
|
@ -311,25 +296,27 @@ FreeReconstrainCallbacks (XdgRole *role)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
ReleaseLaterExtBufferFunc (ExtBuffer *buffer, void *data)
|
|
||||||
{
|
|
||||||
DeleteRecord (data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
RunFrameCallbacks (Surface *surface, XdgRole *role)
|
RunFrameCallbacks (Surface *surface, XdgRole *role)
|
||||||
{
|
{
|
||||||
struct timespec time;
|
struct timespec time;
|
||||||
|
uint64_t last_drawn_time;
|
||||||
|
|
||||||
/* Surface can be NULL for various reasons, especially events
|
/* Surface can be NULL for various reasons, especially events
|
||||||
arriving after the shell surface is detached. */
|
arriving after the shell surface is detached. */
|
||||||
if (!surface)
|
if (!surface)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
last_drawn_time = XLFrameClockGetFrameTime (role->clock);
|
||||||
|
|
||||||
|
if (!last_drawn_time)
|
||||||
|
{
|
||||||
clock_gettime (CLOCK_MONOTONIC, &time);
|
clock_gettime (CLOCK_MONOTONIC, &time);
|
||||||
XLSurfaceRunFrameCallbacks (surface, time);
|
XLSurfaceRunFrameCallbacks (surface, time);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
XLSurfaceRunFrameCallbacksMs (surface, last_drawn_time / 1000);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
RunFrameCallbacksConditionally (XdgRole *role)
|
RunFrameCallbacksConditionally (XdgRole *role)
|
||||||
|
@ -344,25 +331,18 @@ RunFrameCallbacksConditionally (XdgRole *role)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
HandleReleaseLaterMessage (XdgRole *role, uint64_t id)
|
BufferIdleCallback (RenderBuffer buffer, void *data)
|
||||||
{
|
{
|
||||||
ReleaseLaterRecord *record;
|
ReleaseLaterRecord *record;
|
||||||
|
XdgRole *role;
|
||||||
Surface *surface;
|
Surface *surface;
|
||||||
|
|
||||||
record = role->release_records->last;
|
record = data;
|
||||||
|
role = record->role;
|
||||||
|
|
||||||
if (record == role->release_records)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Since the list of release records is a (circular) queue, ID will
|
|
||||||
either be the last element or invalid as the buffer has been
|
|
||||||
destroyed. */
|
|
||||||
|
|
||||||
if (record->id == id)
|
|
||||||
{
|
|
||||||
XLReleaseBuffer (record->buffer);
|
XLReleaseBuffer (record->buffer);
|
||||||
RemoveRecord (record);
|
DeleteRecord (record);
|
||||||
}
|
|
||||||
|
|
||||||
surface = role->role.surface;
|
surface = role->role.surface;
|
||||||
|
|
||||||
|
@ -377,70 +357,12 @@ HandleReleaseLaterMessage (XdgRole *role, uint64_t id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* It shouldn't be possible for billions of frames to pile up without
|
|
||||||
a response from the X server, so relying on wraparound to handle id
|
|
||||||
overflow should be fine. */
|
|
||||||
|
|
||||||
static void
|
|
||||||
ReleaseLater (XdgRole *role, ExtBuffer *buffer)
|
|
||||||
{
|
|
||||||
ReleaseLaterRecord *record;
|
|
||||||
XEvent event;
|
|
||||||
static uint64_t id;
|
|
||||||
|
|
||||||
/* Send a message to the X server; once it is received, release the
|
|
||||||
given buffer. This is necessary because the connection to the X
|
|
||||||
server does not behave synchronously, and receiving the message
|
|
||||||
tells us that the X server has finished processing all requests
|
|
||||||
that access the buffer. */
|
|
||||||
|
|
||||||
record = AddRecordAfter (role->release_records);
|
|
||||||
record->id = ++id;
|
|
||||||
record->buffer = buffer;
|
|
||||||
record->free_func_key
|
|
||||||
= XLBufferRunOnFree (buffer, ReleaseLaterExtBufferFunc,
|
|
||||||
record);
|
|
||||||
|
|
||||||
memset (&event, 0, sizeof event);
|
|
||||||
|
|
||||||
event.xclient.type = ClientMessage;
|
|
||||||
event.xclient.window = role->window;
|
|
||||||
event.xclient.message_type = _XL_BUFFER_RELEASE;
|
|
||||||
event.xclient.format = 32;
|
|
||||||
|
|
||||||
event.xclient.data.l[0] = id >> 31 >> 1;
|
|
||||||
event.xclient.data.l[1] = id & 0xffffffff;
|
|
||||||
|
|
||||||
XSendEvent (compositor.display, role->window, False,
|
|
||||||
NoEventMask, &event);
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool
|
Bool
|
||||||
XLHandleXEventForXdgSurfaces (XEvent *event)
|
XLHandleXEventForXdgSurfaces (XEvent *event)
|
||||||
{
|
{
|
||||||
XdgRole *role;
|
XdgRole *role;
|
||||||
uint64_t id, low, high;
|
|
||||||
Window window;
|
Window window;
|
||||||
|
|
||||||
if (event->type == ClientMessage
|
|
||||||
&& event->xclient.message_type == _XL_BUFFER_RELEASE)
|
|
||||||
{
|
|
||||||
role = XLLookUpAssoc (surfaces, event->xclient.window);
|
|
||||||
|
|
||||||
if (role)
|
|
||||||
{
|
|
||||||
/* These values are masked because Xlib sign-extends 32-bit
|
|
||||||
values to fit potentially 64-bit long. */
|
|
||||||
low = event->xclient.data.l[0] & 0xffffffff;
|
|
||||||
high = event->xclient.data.l[1] & 0xffffffff;
|
|
||||||
|
|
||||||
id = (low << 32) | high;
|
|
||||||
HandleReleaseLaterMessage (role, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event->type == ClientMessage
|
if (event->type == ClientMessage
|
||||||
&& ((event->xclient.message_type == _NET_WM_FRAME_DRAWN
|
&& ((event->xclient.message_type == _NET_WM_FRAME_DRAWN
|
||||||
|| event->xclient.message_type == _NET_WM_FRAME_TIMINGS)
|
|| event->xclient.message_type == _NET_WM_FRAME_TIMINGS)
|
||||||
|
@ -611,8 +533,29 @@ AckConfigure (struct wl_client *client, struct wl_resource *resource,
|
||||||
if (!xdg_role->role.surface)
|
if (!xdg_role->role.surface)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
#ifdef DEBUG_GEOMETRY_CALCULATION
|
||||||
|
fprintf (stderr, "ack_configure: %"PRIu32"\n", serial);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (serial < xdg_role->conf_serial)
|
||||||
|
{
|
||||||
|
/* The client specified an outdated serial. */
|
||||||
|
wl_resource_post_error (resource, XDG_SURFACE_ERROR_INVALID_SERIAL,
|
||||||
|
"serial specified not monotonic");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serial && serial == xdg_role->last_specified_serial)
|
||||||
|
{
|
||||||
|
/* The client specified the same serial twice. */
|
||||||
|
wl_resource_post_error (resource, XDG_SURFACE_ERROR_INVALID_SERIAL,
|
||||||
|
"same serial specified twice");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (serial == xdg_role->conf_serial)
|
if (serial == xdg_role->conf_serial)
|
||||||
{
|
{
|
||||||
|
xdg_role->last_specified_serial = serial;
|
||||||
xdg_role->state &= ~StateWaitingForAckConfigure;
|
xdg_role->state &= ~StateWaitingForAckConfigure;
|
||||||
|
|
||||||
/* Garbage the subcompositor too, since contents could be
|
/* Garbage the subcompositor too, since contents could be
|
||||||
|
@ -720,6 +663,12 @@ Commit (Surface *surface, Role *role)
|
||||||
if (!IsRoleMapped (xdg_role))
|
if (!IsRoleMapped (xdg_role))
|
||||||
goto start_drawing;
|
goto start_drawing;
|
||||||
|
|
||||||
|
/* If the frame clock is frozen but we are no longer waiting for the
|
||||||
|
configure event to be acknowledged by the client, unfreeze the
|
||||||
|
frame clock. */
|
||||||
|
if (!(xdg_role->state & StateWaitingForAckConfigure))
|
||||||
|
Unfreeze (xdg_role);
|
||||||
|
|
||||||
/* A frame is already in progress, so instead say that an urgent
|
/* A frame is already in progress, so instead say that an urgent
|
||||||
update is needed immediately after the frame completes. In any
|
update is needed immediately after the frame completes. In any
|
||||||
case, don't run frame callbacks upon buffer release anymore. */
|
case, don't run frame callbacks upon buffer release anymore. */
|
||||||
|
@ -727,8 +676,9 @@ Commit (Surface *surface, Role *role)
|
||||||
{
|
{
|
||||||
if (XLFrameClockCanBatch (xdg_role->clock))
|
if (XLFrameClockCanBatch (xdg_role->clock))
|
||||||
/* But if we can squeeze the frame inside the vertical
|
/* But if we can squeeze the frame inside the vertical
|
||||||
blanking period, go ahead. */
|
blanking period, or a frame is in progress but EndFrame has
|
||||||
goto just_draw_then_return;
|
not yet been called, go ahead. */
|
||||||
|
goto start_drawing;
|
||||||
|
|
||||||
xdg_role->state |= StateLateFrame;
|
xdg_role->state |= StateLateFrame;
|
||||||
xdg_role->state &= ~StatePendingFrameCallback;
|
xdg_role->state &= ~StatePendingFrameCallback;
|
||||||
|
@ -743,38 +693,12 @@ Commit (Surface *surface, Role *role)
|
||||||
|
|
||||||
start_drawing:
|
start_drawing:
|
||||||
|
|
||||||
/* If the frame clock is frozen but we are no longer waiting for the
|
|
||||||
configure event to be acknowledged by the client, unfreeze the
|
|
||||||
frame clock. */
|
|
||||||
if (!(xdg_role->state & StateWaitingForAckConfigure))
|
|
||||||
Unfreeze (xdg_role);
|
|
||||||
|
|
||||||
XLFrameClockStartFrame (xdg_role->clock, False);
|
|
||||||
SubcompositorUpdate (xdg_role->subcompositor);
|
SubcompositorUpdate (xdg_role->subcompositor);
|
||||||
|
|
||||||
/* Also run role "commit inside frame" hook. */
|
/* Do not end frames explicitly. Instead, wait for the
|
||||||
if (xdg_role->impl && xdg_role->impl->funcs.commit_inside_frame)
|
NoteFrameCallback to end the frame. */
|
||||||
xdg_role->impl->funcs.commit_inside_frame (role, xdg_role->impl);
|
|
||||||
XLFrameClockEndFrame (xdg_role->clock);
|
|
||||||
|
|
||||||
/* Clients which commit when a configure event that has not yet been
|
|
||||||
acked still expect frame callbacks to be called; however, frame
|
|
||||||
callbacks are not provided by the frame clock while it is frozen.
|
|
||||||
|
|
||||||
If that happens, just run the frame callback immediately. */
|
|
||||||
if (XLFrameClockIsFrozen (xdg_role->clock)
|
|
||||||
/* If the window is not mapped, then the native frame clock will
|
|
||||||
not draw frames. Some clients do commit before the initial
|
|
||||||
configure event and wait for the frame callback to be called
|
|
||||||
after or before ack_configure, leading to the mapping commit
|
|
||||||
never being performed. */
|
|
||||||
|| !IsRoleMapped (xdg_role))
|
|
||||||
RunFrameCallbacksConditionally (xdg_role);
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
just_draw_then_return:
|
|
||||||
SubcompositorUpdate (xdg_role->subcompositor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Bool
|
static Bool
|
||||||
|
@ -887,7 +811,27 @@ Teardown (Surface *surface, Role *role)
|
||||||
static void
|
static void
|
||||||
ReleaseBuffer (Surface *surface, Role *role, ExtBuffer *buffer)
|
ReleaseBuffer (Surface *surface, Role *role, ExtBuffer *buffer)
|
||||||
{
|
{
|
||||||
ReleaseLater (XdgRoleFromRole (role), buffer);
|
RenderBuffer render_buffer;
|
||||||
|
ReleaseLaterRecord *record;
|
||||||
|
XdgRole *xdg_role;
|
||||||
|
|
||||||
|
render_buffer = XLRenderBufferFromBuffer (buffer);
|
||||||
|
xdg_role = XdgRoleFromRole (role);
|
||||||
|
|
||||||
|
if (RenderIsBufferIdle (render_buffer, xdg_role->target))
|
||||||
|
/* If the buffer is already idle, release it now. */
|
||||||
|
XLReleaseBuffer (buffer);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Release the buffer once it is destroyed or becomes idle. */
|
||||||
|
record = AddRecordAfter (xdg_role->release_records);
|
||||||
|
record->buffer = buffer;
|
||||||
|
record->key = RenderAddIdleCallback (render_buffer,
|
||||||
|
xdg_role->target,
|
||||||
|
BufferIdleCallback,
|
||||||
|
record);
|
||||||
|
record->role = xdg_role;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Bool
|
static Bool
|
||||||
|
@ -915,7 +859,8 @@ Subframe (Surface *surface, Role *role)
|
||||||
{
|
{
|
||||||
if (XLFrameClockCanBatch (xdg_role->clock))
|
if (XLFrameClockCanBatch (xdg_role->clock))
|
||||||
/* But if we can squeeze the frame inside the vertical
|
/* But if we can squeeze the frame inside the vertical
|
||||||
blanking period, go ahead. */
|
blanking period, or a frame is in progress but EndFrame has
|
||||||
|
not yet been called, go ahead. */
|
||||||
return True;
|
return True;
|
||||||
|
|
||||||
xdg_role->state |= StateLateFrame;
|
xdg_role->state |= StateLateFrame;
|
||||||
|
@ -927,18 +872,14 @@ Subframe (Surface *surface, Role *role)
|
||||||
return False;
|
return False;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* I guess subsurface updates don't count as urgent frames? */
|
|
||||||
XLFrameClockStartFrame (xdg_role->clock, False);
|
|
||||||
return True;
|
return True;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
EndSubframe (Surface *surface, Role *role)
|
EndSubframe (Surface *surface, Role *role)
|
||||||
{
|
{
|
||||||
XdgRole *xdg_role;
|
/* Don't end the frame here; instead, wait for the frame callback to
|
||||||
|
note that drawing the frame has finished. */
|
||||||
xdg_role = XdgRoleFromRole (role);
|
|
||||||
XLFrameClockEndFrame (xdg_role->clock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Window
|
static Window
|
||||||
|
@ -969,34 +910,6 @@ AfterFrame (FrameClock *clock, void *data)
|
||||||
|
|
||||||
role = data;
|
role = data;
|
||||||
|
|
||||||
if (role->state & StateLateFrame)
|
|
||||||
{
|
|
||||||
role->state &= ~StateLateFrame;
|
|
||||||
|
|
||||||
if (role->state & StateLateFrameAcked)
|
|
||||||
XLFrameClockUnfreeze (role->clock);
|
|
||||||
|
|
||||||
/* Since we are running late, make the compositor draw the frame
|
|
||||||
now. */
|
|
||||||
XLFrameClockStartFrame (clock, True);
|
|
||||||
SubcompositorUpdate (role->subcompositor);
|
|
||||||
|
|
||||||
/* Also run role "commit inside frame" hook. */
|
|
||||||
if (role->impl
|
|
||||||
&& role->impl->funcs.commit_inside_frame)
|
|
||||||
role->impl->funcs.commit_inside_frame (&role->role,
|
|
||||||
role->impl);
|
|
||||||
XLFrameClockEndFrame (clock);
|
|
||||||
|
|
||||||
/* See the comment in Commit about frame callbacks being
|
|
||||||
attached while the frame clock is frozen. */
|
|
||||||
if (XLFrameClockIsFrozen (role->clock)
|
|
||||||
&& role->role.surface)
|
|
||||||
RunFrameCallbacksConditionally (role);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If all pending frames have been drawn, run frame callbacks.
|
/* If all pending frames have been drawn, run frame callbacks.
|
||||||
Unless some buffers have not yet been released, in which case the
|
Unless some buffers have not yet been released, in which case the
|
||||||
callbacks will be run when they are. */
|
callbacks will be run when they are. */
|
||||||
|
@ -1234,6 +1147,63 @@ NoteBounds (void *data, int min_x, int min_y,
|
||||||
RunReconstrainCallbacks (role);
|
RunReconstrainCallbacks (role);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
NoteFrame (FrameMode mode, uint64_t id, void *data)
|
||||||
|
{
|
||||||
|
XdgRole *role;
|
||||||
|
|
||||||
|
role = data;
|
||||||
|
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case ModeStarted:
|
||||||
|
/* Record this frame counter as the pending frame. */
|
||||||
|
role->pending_frame = id;
|
||||||
|
|
||||||
|
if (!(role->state & StateFrameStarted))
|
||||||
|
{
|
||||||
|
role->state |= StateFrameStarted;
|
||||||
|
XLFrameClockStartFrame (role->clock, False);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Also run role "commit inside frame" hook. */
|
||||||
|
if (role->impl && role->impl->funcs.commit_inside_frame)
|
||||||
|
role->impl->funcs.commit_inside_frame (&role->role,
|
||||||
|
role->impl);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ModePresented:
|
||||||
|
case ModeComplete:
|
||||||
|
/* The frame was completed. */
|
||||||
|
if (id == role->pending_frame)
|
||||||
|
{
|
||||||
|
/* End the frame. */
|
||||||
|
XLFrameClockEndFrame (role->clock);
|
||||||
|
|
||||||
|
/* Clear the frame completed flag. */
|
||||||
|
role->state &= ~StateFrameStarted;
|
||||||
|
|
||||||
|
/* Clients which commit when a configure event that has not
|
||||||
|
yet been acked still expect frame callbacks to be called;
|
||||||
|
however, frame callbacks are not provided by the frame
|
||||||
|
clock while it is frozen.
|
||||||
|
|
||||||
|
If that happens, just run the frame callback
|
||||||
|
immediately. */
|
||||||
|
if (XLFrameClockIsFrozen (role->clock)
|
||||||
|
/* If the window is not mapped, then the native frame
|
||||||
|
clock will not draw frames. Some clients do commit
|
||||||
|
before the initial configure event and wait for the
|
||||||
|
frame callback to be called after or before
|
||||||
|
ack_configure, leading to the mapping commit never
|
||||||
|
being performed. */
|
||||||
|
|| !IsRoleMapped (role))
|
||||||
|
RunFrameCallbacksConditionally (role);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ResizeForMap (XdgRole *role)
|
ResizeForMap (XdgRole *role)
|
||||||
{
|
{
|
||||||
|
@ -1387,6 +1357,10 @@ SelectExtraEvents (Surface *surface, Role *role,
|
||||||
/* Select extra events for the input method. */
|
/* Select extra events for the input method. */
|
||||||
XSelectInput (compositor.display, xdg_role->window,
|
XSelectInput (compositor.display, xdg_role->window,
|
||||||
DefaultEventMask | event_mask);
|
DefaultEventMask | event_mask);
|
||||||
|
|
||||||
|
/* Set the target standard event mask. */
|
||||||
|
RenderSetStandardEventMask (xdg_role->target,
|
||||||
|
DefaultEventMask | event_mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -1482,7 +1456,7 @@ XLGetXdgSurface (struct wl_client *client, struct wl_resource *resource,
|
||||||
0, 0, 20, 20, 0, compositor.n_planes,
|
0, 0, 20, 20, 0, compositor.n_planes,
|
||||||
InputOutput, compositor.visual, flags,
|
InputOutput, compositor.visual, flags,
|
||||||
&attrs);
|
&attrs);
|
||||||
role->target = RenderTargetFromWindow (role->window);
|
role->target = RenderTargetFromWindow (role->window, DefaultEventMask);
|
||||||
|
|
||||||
role->subcompositor = MakeSubcompositor ();
|
role->subcompositor = MakeSubcompositor ();
|
||||||
role->clock = XLMakeFrameClockForWindow (role->window);
|
role->clock = XLMakeFrameClockForWindow (role->window);
|
||||||
|
@ -1496,6 +1470,8 @@ XLGetXdgSurface (struct wl_client *client, struct wl_resource *resource,
|
||||||
OpaqueRegionChanged, role);
|
OpaqueRegionChanged, role);
|
||||||
SubcompositorSetBoundsCallback (role->subcompositor,
|
SubcompositorSetBoundsCallback (role->subcompositor,
|
||||||
NoteBounds, role);
|
NoteBounds, role);
|
||||||
|
SubcompositorSetNoteFrameCallback (role->subcompositor,
|
||||||
|
NoteFrame, role);
|
||||||
XLSelectStandardEvents (role->window);
|
XLSelectStandardEvents (role->window);
|
||||||
XLMakeAssoc (surfaces, role->window, role);
|
XLMakeAssoc (surfaces, role->window, role);
|
||||||
|
|
||||||
|
@ -1581,7 +1557,8 @@ XLXdgRoleSendConfigure (Role *role, uint32_t serial)
|
||||||
xdg_role->state &= ~StateMaybeConfigure;
|
xdg_role->state &= ~StateMaybeConfigure;
|
||||||
|
|
||||||
#ifdef DEBUG_GEOMETRY_CALCULATION
|
#ifdef DEBUG_GEOMETRY_CALCULATION
|
||||||
fprintf (stderr, "Waiting for ack_configure...\n");
|
fprintf (stderr, "Waiting for ack_configure (%"PRIu32")...\n",
|
||||||
|
xdg_role->conf_serial);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
xdg_surface_send_configure (role->resource, serial);
|
xdg_surface_send_configure (role->resource, serial);
|
||||||
|
|
Loading…
Add table
Reference in a new issue