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:
|
||||
fprintf (stderr,
|
||||
"usage: %s [-name name] [-class class] [-xrm resourcestring]...\n",
|
||||
"usage: %s [-name name] [-class class] [-xrm resourcestring...]\n",
|
||||
argv[0]);
|
||||
exit (!strcmp (argv[i], "-help") ? 0 : 1);
|
||||
}
|
||||
|
@ -224,6 +224,7 @@ XLMain (int argc, char **argv)
|
|||
XLInitDecoration ();
|
||||
XLInitTextInput ();
|
||||
XLInitSinglePixelBuffer ();
|
||||
XLInitDrmLease ();
|
||||
|
||||
/* This has to come after the rest of the initialization. */
|
||||
DetermineServerTime ();
|
||||
|
|
14
12to11.man
14
12to11.man
|
@ -3,7 +3,7 @@
|
|||
12to11 - Wayland to X protocol translator
|
||||
.SH SYNOPSIS
|
||||
.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
|
||||
.I 12to11
|
||||
starts a Wayland compositor on the next available socket;
|
||||
|
@ -212,6 +212,16 @@ Protocol Version
|
|||
zwp_linux_explicit_synchronization_v1 2
|
||||
.TE
|
||||
.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
|
||||
the \fBCLIPBOARD\fP and \fBPRIMARY\fP selections even when they do not
|
||||
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.
|
||||
.SH "SEE ALSO"
|
||||
X(7), Xorg(1)
|
||||
.SH AUTHOR
|
||||
.SH AUTHORS
|
||||
Various contributors.
|
||||
|
|
10
Imakefile
10
Imakefile
|
@ -1,4 +1,4 @@
|
|||
#include "libraries.def"
|
||||
#include "12to11.conf"
|
||||
|
||||
#ifndef HasPosixThreads
|
||||
#error "Posix threads are required"
|
||||
|
@ -10,7 +10,8 @@ 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_DRI3) $(XCB_SHAPE) $(WAYLAND_SERVER) $(XCB_RANDR) $(DRM) \
|
||||
$(XPRESENTLIB)
|
||||
|
||||
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 \
|
||||
picture_renderer.c explicit_synchronization.c transform.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 \
|
||||
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 \
|
||||
picture_renderer.o explicit_synchronization.o transform.o \
|
||||
wp_viewporter.o decoration.o text_input.o \
|
||||
single_pixel_buffer.o
|
||||
single_pixel_buffer.o drm_lease.o
|
||||
|
||||
GENHEADERS = transfer_atoms.h
|
||||
|
||||
|
@ -115,6 +116,7 @@ ScannerTarget(viewporter)
|
|||
ScannerTarget(xdg-decoration-unstable-v1)
|
||||
ScannerTarget(text-input-unstable-v3)
|
||||
ScannerTarget(single-pixel-buffer-v1)
|
||||
ScannerTarget(drm-lease-v1)
|
||||
|
||||
/* Make OBJS depend on scanner headers, and depend on both them and SRCS. */
|
||||
$(OBJS): $(GENHEADERS)
|
||||
|
|
7
atoms.c
7
atoms.c
|
@ -108,6 +108,7 @@ static const char *names[] =
|
|||
"_NET_WM_WINDOW_TYPE",
|
||||
"_NET_WM_WINDOW_TYPE_MENU",
|
||||
"_NET_WM_WINDOW_TYPE_DND",
|
||||
"CONNECTOR_ID",
|
||||
|
||||
/* These are automatically generated from mime.txt. */
|
||||
DirectTransferAtomNames
|
||||
|
@ -129,7 +130,8 @@ Atom _NET_WM_OPAQUE_REGION, _XL_BUFFER_RELEASE, _NET_WM_SYNC_REQUEST_COUNTER,
|
|||
XdndActionPrivate, XdndActionList, XdndActionDescription, XdndProxy,
|
||||
XdndEnter, XdndPosition, XdndStatus, XdndLeave, XdndDrop, 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;
|
||||
|
||||
XrmQuark resource_quark, app_quark, QString;
|
||||
|
||||
|
@ -283,9 +285,10 @@ XLInitAtoms (void)
|
|||
_NET_WM_WINDOW_TYPE = atoms[58];
|
||||
_NET_WM_WINDOW_TYPE_MENU = atoms[59];
|
||||
_NET_WM_WINDOW_TYPE_DND = atoms[60];
|
||||
CONNECTOR_ID = atoms[61];
|
||||
|
||||
/* This is automatically generated. */
|
||||
DirectTransferAtomInit (atoms, 61);
|
||||
DirectTransferAtomInit (atoms, 62);
|
||||
|
||||
/* Now, initialize quarks. */
|
||||
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 void *IdleCallbackKey;
|
||||
typedef void *PresentCompletionKey;
|
||||
|
||||
typedef void (*DmaBufSuccessFunc) (RenderBuffer, void *);
|
||||
typedef void (*DmaBufFailureFunc) (void *);
|
||||
|
||||
typedef void (*BufferIdleFunc) (RenderBuffer, void *);
|
||||
typedef void (*PresentCompletionFunc) (void *);
|
||||
|
||||
enum _Operation
|
||||
{
|
||||
OperationOver,
|
||||
|
@ -250,11 +256,14 @@ struct _RenderFuncs
|
|||
Bool (*init_render_funcs) (void);
|
||||
|
||||
/* 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. */
|
||||
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. */
|
||||
void (*note_target_size) (RenderTarget, int, int);
|
||||
|
||||
|
@ -327,6 +336,22 @@ struct _RenderFuncs
|
|||
called. */
|
||||
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
|
||||
that were previously drawn. */
|
||||
int flags;
|
||||
|
@ -404,6 +429,28 @@ struct _BufferFuncs
|
|||
by being copied to an offscreen buffer. */
|
||||
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. */
|
||||
void (*init_buffer_funcs) (void);
|
||||
};
|
||||
|
@ -414,8 +461,9 @@ extern void RegisterStaticRenderer (const char *, RenderFuncs *,
|
|||
BufferFuncs *);
|
||||
extern void InitRenderers (void);
|
||||
|
||||
extern RenderTarget RenderTargetFromWindow (Window);
|
||||
extern RenderTarget RenderTargetFromWindow (Window, unsigned long);
|
||||
extern RenderTarget RenderTargetFromPixmap (Pixmap);
|
||||
extern void RenderSetStandardEventMask (RenderTarget, unsigned long);
|
||||
extern void RenderNoteTargetSize (RenderTarget, int, int);
|
||||
extern Picture RenderPictureFromTarget (RenderTarget);
|
||||
extern void RenderFreePictureFromTarget (Picture);
|
||||
|
@ -432,6 +480,12 @@ extern RenderFence RenderImportFdFence (int, Bool *);
|
|||
extern void RenderWaitFence (RenderFence);
|
||||
extern void RenderDeleteFence (RenderFence);
|
||||
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 dev_t RenderGetRenderDevice (Bool *);
|
||||
|
@ -450,6 +504,12 @@ extern void RenderFreeSinglePixelBuffer (RenderBuffer);
|
|||
extern void RenderUpdateBufferForDamage (RenderBuffer, pixman_region32_t *,
|
||||
DrawParams *);
|
||||
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. */
|
||||
|
||||
|
@ -610,6 +670,15 @@ typedef struct _View View;
|
|||
typedef struct _List List;
|
||||
typedef struct _Subcompositor Subcompositor;
|
||||
|
||||
typedef enum _FrameMode FrameMode;
|
||||
|
||||
enum _FrameMode
|
||||
{
|
||||
ModeStarted,
|
||||
ModeComplete,
|
||||
ModePresented,
|
||||
};
|
||||
|
||||
extern void SubcompositorInit (void);
|
||||
|
||||
extern Subcompositor *MakeSubcompositor (void);
|
||||
|
@ -634,6 +703,10 @@ extern void SubcompositorSetBoundsCallback (Subcompositor *,
|
|||
void (*) (void *, int, int,
|
||||
int, int),
|
||||
void *);
|
||||
extern void SubcompositorSetNoteFrameCallback (Subcompositor *,
|
||||
void (*) (FrameMode, uint64_t,
|
||||
void *),
|
||||
void *);
|
||||
extern void SubcompositorBounds (Subcompositor *, int *, int *, int *, int *);
|
||||
extern void SubcompositorSetProjectiveTransform (Subcompositor *, int, int);
|
||||
|
||||
|
@ -964,6 +1037,7 @@ 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 *,
|
||||
void (*) (Surface *, void *),
|
||||
void *);
|
||||
|
@ -1004,6 +1078,7 @@ extern Bool XLGetOutputRectAt (int, int, int *, int *, int *, int *);
|
|||
extern void *XLAddScaleChangeCallback (void *, void (*) (void *, int));
|
||||
extern void XLRemoveScaleChangeCallback (void *);
|
||||
extern void XLClearOutputs (Surface *);
|
||||
extern void XLOutputSetChangeFunction (void (*) (Time));
|
||||
|
||||
/* Defined in atoms.c. */
|
||||
|
||||
|
@ -1022,7 +1097,8 @@ extern Atom _NET_WM_OPAQUE_REGION, _XL_BUFFER_RELEASE,
|
|||
XdndActionAsk, XdndActionPrivate, XdndActionList, XdndActionDescription,
|
||||
XdndProxy, XdndEnter, XdndPosition, XdndStatus, XdndLeave, XdndDrop,
|
||||
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;
|
||||
|
||||
|
@ -1062,6 +1138,7 @@ extern void XLFrameClockSetPredictRefresh (FrameClock *);
|
|||
extern void XLFrameClockDisablePredictRefresh (FrameClock *);
|
||||
extern void XLFrameClockSetFreezeCallback (FrameClock *, void (*) (void *),
|
||||
void *);
|
||||
extern uint64_t XLFrameClockGetFrameTime (FrameClock *);
|
||||
extern void *XLAddCursorClockCallback (void (*) (void *, struct timespec),
|
||||
void *);
|
||||
extern void XLStopCursorClockCallback (void *);
|
||||
|
@ -1477,6 +1554,10 @@ extern void XLInitDecoration (void);
|
|||
|
||||
extern void XLInitSinglePixelBuffer (void);
|
||||
|
||||
/* Defined in drm_lease.h. */
|
||||
|
||||
extern void XLInitDrmLease (void);
|
||||
|
||||
/* Utility functions that don't belong in a specific file. */
|
||||
|
||||
#define ArrayElements(arr) (sizeof (arr) / sizeof (arr)[0])
|
||||
|
|
9
egl.c
9
egl.c
|
@ -1077,7 +1077,7 @@ TryPreserveOnSwap (EGLSurface *surface)
|
|||
}
|
||||
|
||||
static RenderTarget
|
||||
TargetFromWindow (Window window)
|
||||
TargetFromWindow (Window window, unsigned long standard_event_mask)
|
||||
{
|
||||
EglTarget *target;
|
||||
|
||||
|
@ -1125,6 +1125,12 @@ TargetFromPixmap (Pixmap pixmap)
|
|||
return (RenderTarget) (void *) target;
|
||||
}
|
||||
|
||||
static void
|
||||
SetStandardEventMask (RenderTarget target, unsigned long standard_event_mask)
|
||||
{
|
||||
/* Ignored. */
|
||||
}
|
||||
|
||||
static void
|
||||
NoteTargetSize (RenderTarget target, int width, int height)
|
||||
{
|
||||
|
@ -1659,6 +1665,7 @@ static RenderFuncs egl_render_funcs =
|
|||
.init_render_funcs = InitRenderFuncs,
|
||||
.target_from_window = TargetFromWindow,
|
||||
.target_from_pixmap = TargetFromPixmap,
|
||||
.set_standard_event_mask = SetStandardEventMask,
|
||||
.note_target_size = NoteTargetSize,
|
||||
.picture_from_target = PictureFromTarget,
|
||||
.free_picture_from_target = FreePictureFromTarget,
|
||||
|
|
103
frame_clock.c
103
frame_clock.c
|
@ -90,6 +90,9 @@ struct _FrameClock
|
|||
unfrozen until EndFrame. */
|
||||
Bool need_configure, frozen, frozen_until_end_frame;
|
||||
|
||||
/* Whether or not EndFrame was called after StartFrame. */
|
||||
Bool end_frame_called;
|
||||
|
||||
/* The wanted configure value. */
|
||||
uint64_t configure_id;
|
||||
|
||||
|
@ -111,6 +114,9 @@ struct _FrameClock
|
|||
|
||||
/* Data for that callback. */
|
||||
void *freeze_callback_data;
|
||||
|
||||
/* Any pending frame synchronization counter value, or 0. */
|
||||
uint64_t pending_sync_value;
|
||||
};
|
||||
|
||||
struct _CursorClockCallback
|
||||
|
@ -221,7 +227,51 @@ HandleEndFrame (Timer *timer, void *data, struct timespec time)
|
|||
the frame. */
|
||||
RemoveTimer (timer);
|
||||
clock->end_frame_timer = NULL;
|
||||
EndFrame (clock);
|
||||
|
||||
if (clock->end_frame_called)
|
||||
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
|
||||
|
@ -320,6 +370,9 @@ StartFrame (FrameClock *clock, Bool urgent, Bool predict)
|
|||
if (clock->frozen_until_end_frame)
|
||||
return;
|
||||
|
||||
if (clock->in_frame)
|
||||
return;
|
||||
|
||||
if (clock->need_configure)
|
||||
{
|
||||
clock->next_frame_id = clock->configure_id;
|
||||
|
@ -327,6 +380,7 @@ StartFrame (FrameClock *clock, Bool urgent, Bool predict)
|
|||
}
|
||||
|
||||
clock->in_frame = True;
|
||||
clock->end_frame_called = False;
|
||||
|
||||
/* Set the clock to an odd value; if we want the compositor to
|
||||
redraw this frame immediately (since it is running late), make it
|
||||
|
@ -371,6 +425,10 @@ EndFrame (FrameClock *clock)
|
|||
|
||||
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 the end of the frame has already been signalled, this
|
||||
function should just return instead of increasing the counter
|
||||
|
@ -389,6 +447,12 @@ EndFrame (FrameClock *clock)
|
|||
clock->next_frame_id += 1;
|
||||
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)
|
||||
return;
|
||||
|
||||
|
@ -570,28 +634,15 @@ XLFrameClockHandleFrameEvent (FrameClock *clock, XEvent *event)
|
|||
if (value % 2)
|
||||
value += 1;
|
||||
|
||||
/* 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;
|
||||
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 a frame is in progress, postpone this frame
|
||||
synchronization message. */
|
||||
if (clock->in_frame && !clock->end_frame_called)
|
||||
clock->pending_sync_value = value;
|
||||
else
|
||||
FreezeForValue (clock, value);
|
||||
|
||||
if (clock->freeze_callback)
|
||||
/* Call the freeze callback in any case. */
|
||||
clock->freeze_callback (clock->freeze_callback_data);
|
||||
}
|
||||
}
|
||||
|
@ -731,6 +782,16 @@ XLFrameClockSetFreezeCallback (FrameClock *clock, void (*callback) (void *),
|
|||
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. */
|
||||
|
||||
|
|
|
@ -155,9 +155,14 @@ Setup (Surface *surface, Role *role)
|
|||
static void
|
||||
ReleaseBuffer (Surface *surface, Role *role, ExtBuffer *buffer)
|
||||
{
|
||||
IconSurface *icon;
|
||||
|
||||
icon = IconSurfaceFromRole (role);
|
||||
|
||||
/* Icon surfaces are not supposed to change much, so doing an XSync
|
||||
here is okay. */
|
||||
XSync (compositor.display, False);
|
||||
(or XIfEvent) here is okay. */
|
||||
RenderWaitForIdle (XLRenderBufferFromBuffer (buffer),
|
||||
icon->target);
|
||||
|
||||
/* Now really release the buffer. */
|
||||
XLReleaseBuffer (buffer);
|
||||
|
@ -213,17 +218,25 @@ NoteBounds (void *data, int min_x, int min_y, int max_x, int max_y)
|
|||
}
|
||||
|
||||
static void
|
||||
RunFrameCallbacks (Surface *surface)
|
||||
RunFrameCallbacks (Surface *surface, FrameClock *clock)
|
||||
{
|
||||
struct timespec time;
|
||||
uint64_t last_drawn_time;
|
||||
|
||||
/* Surface can be NULL for various reasons, especially events
|
||||
arriving after the icon surface is detached. */
|
||||
if (!surface)
|
||||
return;
|
||||
|
||||
clock_gettime (CLOCK_MONOTONIC, &time);
|
||||
XLSurfaceRunFrameCallbacks (surface, time);
|
||||
last_drawn_time = XLFrameClockGetFrameTime (clock);
|
||||
|
||||
if (!last_drawn_time)
|
||||
{
|
||||
clock_gettime (CLOCK_MONOTONIC, &time);
|
||||
XLSurfaceRunFrameCallbacks (surface, time);
|
||||
}
|
||||
else
|
||||
XLSurfaceRunFrameCallbacksMs (surface, last_drawn_time / 1000);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -246,7 +259,7 @@ AfterFrame (FrameClock *clock, void *data)
|
|||
return;
|
||||
}
|
||||
|
||||
RunFrameCallbacks (icon->role.surface);
|
||||
RunFrameCallbacks (icon->role.surface, clock);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -410,7 +423,11 @@ XLGetIconSurface (Surface *surface)
|
|||
(unsigned char *) &_NET_WM_WINDOW_TYPE_DND, 1);
|
||||
|
||||
/* 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. */
|
||||
role->subcompositor = MakeSubcompositor ();
|
||||
|
|
58
output.c
58
output.c
|
@ -98,6 +98,9 @@ static ScaleChangeCallback scale_callbacks;
|
|||
/* The scale factor currently applied on a global basis. */
|
||||
int global_scale_factor;
|
||||
|
||||
/* Function run upon any kind of XRandR notify event. */
|
||||
static void (*change_hook) (Time);
|
||||
|
||||
static Bool
|
||||
ApplyEnvironment (const char *name, int *variable)
|
||||
{
|
||||
|
@ -903,9 +906,38 @@ XLGetOutputRectAt (int x, int y, int *x_out, int *y_out,
|
|||
Bool
|
||||
XLHandleOneXEventForOutputs (XEvent *event)
|
||||
{
|
||||
XRRNotifyEvent *notify;
|
||||
XRROutputPropertyNotifyEvent *property;
|
||||
XRRResourceChangeNotifyEvent *resource;
|
||||
Time time;
|
||||
|
||||
notify = (XRRNotifyEvent *) event;
|
||||
|
||||
if (event->type == compositor.rr_event_base + RRNotify)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1053,6 +1085,12 @@ XLClearOutputs (Surface *surface)
|
|||
surface->n_outputs = 0;
|
||||
}
|
||||
|
||||
void
|
||||
XLOutputSetChangeFunction (void (*change_func) (Time))
|
||||
{
|
||||
change_hook = change_func;
|
||||
}
|
||||
|
||||
void
|
||||
XLInitRROutputs (void)
|
||||
{
|
||||
|
@ -1096,11 +1134,21 @@ XLInitRROutputs (void)
|
|||
scale_callbacks.next = &scale_callbacks;
|
||||
scale_callbacks.last = &scale_callbacks;
|
||||
|
||||
XRRSelectInput (compositor.display,
|
||||
DefaultRootWindow (compositor.display),
|
||||
(RRCrtcChangeNotifyMask
|
||||
| RROutputChangeNotifyMask
|
||||
| RROutputPropertyNotifyMask));
|
||||
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,
|
||||
DefaultRootWindow (compositor.display),
|
||||
(RRCrtcChangeNotifyMask
|
||||
| RROutputChangeNotifyMask
|
||||
| RROutputPropertyNotifyMask));
|
||||
|
||||
all_outputs = BuildOutputTree ();
|
||||
MakeGlobalsForOutputTree (all_outputs);
|
||||
|
|
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
|
||||
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
|
||||
|
@ -80,6 +80,13 @@ RenderTargetFromPixmap (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
|
||||
RenderNoteTargetSize (RenderTarget target, int width, int height)
|
||||
{
|
||||
|
@ -177,6 +184,37 @@ RenderGetFinishFence (Bool *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 *
|
||||
RenderGetDrmFormats (int *n_formats)
|
||||
{
|
||||
|
@ -269,6 +307,43 @@ RenderCanReleaseNow (RenderBuffer 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
|
||||
RegisterStaticRenderer (const char *name,
|
||||
RenderFuncs *render_funcs,
|
||||
|
|
6
run.c
6
run.c
|
@ -139,6 +139,9 @@ HandleOneXEvent (XEvent *event)
|
|||
if (XLHandleXEventForXdgSurfaces (event))
|
||||
return;
|
||||
|
||||
if (HandleOneXEventForPictureRenderer (event))
|
||||
return;
|
||||
|
||||
if (XLHandleXEventForXdgToplevels (event))
|
||||
return;
|
||||
|
||||
|
@ -156,9 +159,6 @@ HandleOneXEvent (XEvent *event)
|
|||
return;
|
||||
#endif
|
||||
|
||||
if (HandleOneXEventForPictureRenderer (event))
|
||||
return;
|
||||
|
||||
if (XLHandleOneXEventForXData (event))
|
||||
return;
|
||||
|
||||
|
|
17
seat.c
17
seat.c
|
@ -711,6 +711,10 @@ MaybeCreateCursor (CursorRing *ring, int index)
|
|||
compositor.n_planes);
|
||||
ring->targets[index]
|
||||
= RenderTargetFromPixmap (ring->pixmaps[index]);
|
||||
|
||||
/* For simplicity reasons we do not handle idle notifications
|
||||
asynchronously. */
|
||||
RenderSetNeedWaitForIdle (ring->targets[index]);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -1208,9 +1212,20 @@ Setup (Surface *surface, Role *role)
|
|||
static void
|
||||
ReleaseBuffer (Surface *surface, Role *role, ExtBuffer *buffer)
|
||||
{
|
||||
SeatCursor *cursor;
|
||||
int i;
|
||||
|
||||
cursor = CursorFromRole (role);
|
||||
|
||||
/* Cursors are generally committed only once, so syncing here is
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
222
subcompositor.c
222
subcompositor.c
|
@ -310,9 +310,6 @@ struct _View
|
|||
|
||||
struct _Subcompositor
|
||||
{
|
||||
/* Various flags describing the state of this subcompositor. */
|
||||
int state;
|
||||
|
||||
/* List of all inferiors in compositing order. */
|
||||
List *inferiors, *last;
|
||||
|
||||
|
@ -334,9 +331,29 @@ struct _Subcompositor
|
|||
/* Function called with the bounds before each update. */
|
||||
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. */
|
||||
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
|
||||
compute the actual size of the subcompositor. */
|
||||
int min_x, min_y;
|
||||
|
@ -347,15 +364,10 @@ struct _Subcompositor
|
|||
|
||||
/* An additional offset to apply when drawing to the target. */
|
||||
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
|
||||
|
||||
/* Various flags describing the state of this subcompositor. */
|
||||
int state;
|
||||
};
|
||||
|
||||
#ifndef TEST
|
||||
|
@ -1807,6 +1819,16 @@ SubcompositorSetBoundsCallback (Subcompositor *subcompositor,
|
|||
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
|
||||
FillBoxesWithTransparency (Subcompositor *subcompositor,
|
||||
pixman_box32_t *boxes, int nboxes)
|
||||
|
@ -1917,6 +1939,69 @@ IntersectBoxes (pixman_box32_t *in, pixman_box32_t *other,
|
|||
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
|
||||
SubcompositorUpdate (Subcompositor *subcompositor)
|
||||
{
|
||||
|
@ -1928,9 +2013,10 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
|||
int nboxes, i, tx, ty, view_width, view_height;
|
||||
Operation op;
|
||||
RenderBuffer buffer;
|
||||
int min_x, min_y;
|
||||
int age;
|
||||
int min_x, min_y, age, n_seen;
|
||||
DrawParams draw_params;
|
||||
Bool presented;
|
||||
PresentCompletionKey key;
|
||||
|
||||
/* Just return if no target was specified. */
|
||||
if (!IsTargetAttached (subcompositor))
|
||||
|
@ -1940,6 +2026,13 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
|||
if (IsFrozen (subcompositor))
|
||||
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;
|
||||
min_x = subcompositor->min_x;
|
||||
min_y = subcompositor->min_y;
|
||||
|
@ -1949,6 +2042,8 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
|||
original_start = NULL;
|
||||
pixman_region32_init (&temp);
|
||||
pixman_region32_init (&update_region);
|
||||
n_seen = 0;
|
||||
presented = False;
|
||||
|
||||
start = subcompositor->inferiors->next->view;
|
||||
original_start = subcompositor->inferiors->next->view;
|
||||
|
@ -2042,6 +2137,9 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
|||
if (!view->buffer)
|
||||
goto next;
|
||||
|
||||
/* Increase the number of views seen count. */
|
||||
n_seen++;
|
||||
|
||||
/* Obtain the view width and height here. */
|
||||
view_width = ViewWidth (view);
|
||||
view_height = ViewHeight (view);
|
||||
|
@ -2265,8 +2363,16 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
|||
/* If there's nothing to do, return. */
|
||||
|
||||
if (!start)
|
||||
/* There is no starting view. Presentation is not cancelled in
|
||||
this case, because the surface should now be unmapped. */
|
||||
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. */
|
||||
|
||||
list = start->link;
|
||||
|
@ -2311,6 +2417,7 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
|||
view_width = ViewWidth (view);
|
||||
view_height = ViewHeight (view);
|
||||
|
||||
/* And the buffer. */
|
||||
buffer = XLRenderBufferFromBuffer (view->buffer);
|
||||
|
||||
if (IsGarbaged (subcompositor))
|
||||
|
@ -2337,8 +2444,67 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
|||
&draw_params);
|
||||
}
|
||||
|
||||
/* Compute the transform and put it in draw_params. */
|
||||
ViewComputeTransform (view, &draw_params, True);
|
||||
|
||||
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
|
||||
with PictOpSrc so that transparency is applied correctly,
|
||||
if it contains the entire update region. */
|
||||
|
@ -2388,10 +2554,11 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
|||
else
|
||||
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. */
|
||||
ViewComputeTransform (view, &draw_params, True);
|
||||
first = view;
|
||||
|
||||
if (!IsGarbaged (subcompositor) && (age >= 0 && age < 3))
|
||||
{
|
||||
|
@ -2428,11 +2595,6 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
|||
}
|
||||
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
|
||||
view to the right location. */
|
||||
RenderComposite (buffer, subcompositor->target, op,
|
||||
|
@ -2447,6 +2609,12 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
|||
/* 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. */
|
||||
|
||||
if (pixman_region32_not_empty (&view->opaque)
|
||||
|
@ -2501,6 +2669,8 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
|||
}
|
||||
while (list != subcompositor->inferiors);
|
||||
|
||||
present_success:
|
||||
|
||||
/* Swap changes to display. */
|
||||
|
||||
if (IsGarbaged (subcompositor) || age < 0 || age >= 3)
|
||||
|
@ -2561,6 +2731,12 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
|||
subcompositor->state &= ~SubcompositorIsGarbaged;
|
||||
subcompositor->state &= ~SubcompositorIsOpaqueDirty;
|
||||
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
|
||||
|
@ -2735,6 +2911,10 @@ SubcompositorFree (Subcompositor *subcompositor)
|
|||
pixman_region32_fini (&subcompositor->prior_damage[0]);
|
||||
pixman_region32_fini (&subcompositor->prior_damage[1]);
|
||||
|
||||
/* Remove the presentation key. */
|
||||
if (subcompositor->present_key)
|
||||
RenderCancelPresentationCallback (subcompositor->present_key);
|
||||
|
||||
XLFree (subcompositor);
|
||||
}
|
||||
|
||||
|
|
13
surface.c
13
surface.c
|
@ -1599,6 +1599,19 @@ XLSurfaceRunFrameCallbacks (Surface *surface, struct timespec 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 *
|
||||
XLSurfaceRunAtCommit (Surface *surface,
|
||||
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
|
||||
committed text to the correct XIC, and thus it is impossible to
|
||||
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
|
||||
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.
|
||||
|
||||
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. */
|
||||
|
||||
typedef struct _TextInputClientInfo TextInputClientInfo;
|
||||
|
|
|
@ -454,6 +454,7 @@
|
|||
<entry name="not_constructed" value="1"/>
|
||||
<entry name="already_constructed" value="2"/>
|
||||
<entry name="unconfigured_buffer" value="3"/>
|
||||
<entry name="invalid_serial" value="4"/>
|
||||
</enum>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
|
@ -549,6 +550,17 @@
|
|||
A client may send multiple ack_configure requests before committing, but
|
||||
only the last request sent before a commit indicates which configure
|
||||
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>
|
||||
<arg name="serial" type="uint" summary="the serial from the configure event"/>
|
||||
</request>
|
||||
|
|
323
xdg_surface.c
323
xdg_surface.c
|
@ -44,6 +44,7 @@ enum
|
|||
StateMaybeConfigure = (1 << 6),
|
||||
StateDirtyFrameExtents = (1 << 7),
|
||||
StateTemporaryBounds = (1 << 8),
|
||||
StateFrameStarted = (1 << 9),
|
||||
};
|
||||
|
||||
typedef struct _XdgRole XdgRole;
|
||||
|
@ -106,6 +107,9 @@ struct _XdgRole
|
|||
/* The implementation of this role. */
|
||||
XdgRoleImplementation *impl;
|
||||
|
||||
/* The pending frame ID. */
|
||||
uint64_t pending_frame;
|
||||
|
||||
/* Various role state. */
|
||||
int state;
|
||||
|
||||
|
@ -123,7 +127,7 @@ struct _XdgRole
|
|||
XdgState current_state;
|
||||
|
||||
/* Configure event serial. */
|
||||
uint32_t conf_serial;
|
||||
uint32_t conf_serial, last_specified_serial;
|
||||
|
||||
/* The current bounds of the subcompositor. */
|
||||
int min_x, min_y, max_x, max_y;
|
||||
|
@ -156,13 +160,16 @@ struct _ReleaseLaterRecord
|
|||
/* A monotonically (overflow aside) increasing identifier. */
|
||||
uint64_t id;
|
||||
|
||||
/* Key for the free func. */
|
||||
void *free_func_key;
|
||||
|
||||
/* The buffer that should be released upon receiving this
|
||||
message. */
|
||||
ExtBuffer *buffer;
|
||||
|
||||
/* The idle callback. */
|
||||
IdleCallbackKey key;
|
||||
|
||||
/* The XdgRole. */
|
||||
XdgRole *role;
|
||||
|
||||
/* The next and last records. */
|
||||
ReleaseLaterRecord *next, *last;
|
||||
};
|
||||
|
@ -170,24 +177,6 @@ struct _ReleaseLaterRecord
|
|||
/* Event base of the XShape extension. */
|
||||
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
|
||||
DeleteRecord (ReleaseLaterRecord *record)
|
||||
{
|
||||
|
@ -217,10 +206,6 @@ FreeRecords (ReleaseLaterRecord *records)
|
|||
/* Release the buffer now. */
|
||||
XLReleaseBuffer (last->buffer);
|
||||
|
||||
/* And cancel the destroy listener. */
|
||||
XLBufferCancelRunOnFree (last->buffer,
|
||||
last->free_func_key);
|
||||
|
||||
/* Before freeing the record itself. */
|
||||
XLFree (last);
|
||||
}
|
||||
|
@ -311,24 +296,26 @@ FreeReconstrainCallbacks (XdgRole *role)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ReleaseLaterExtBufferFunc (ExtBuffer *buffer, void *data)
|
||||
{
|
||||
DeleteRecord (data);
|
||||
}
|
||||
|
||||
static void
|
||||
RunFrameCallbacks (Surface *surface, XdgRole *role)
|
||||
{
|
||||
struct timespec time;
|
||||
uint64_t last_drawn_time;
|
||||
|
||||
/* Surface can be NULL for various reasons, especially events
|
||||
arriving after the shell surface is detached. */
|
||||
if (!surface)
|
||||
return;
|
||||
|
||||
clock_gettime (CLOCK_MONOTONIC, &time);
|
||||
XLSurfaceRunFrameCallbacks (surface, time);
|
||||
last_drawn_time = XLFrameClockGetFrameTime (role->clock);
|
||||
|
||||
if (!last_drawn_time)
|
||||
{
|
||||
clock_gettime (CLOCK_MONOTONIC, &time);
|
||||
XLSurfaceRunFrameCallbacks (surface, time);
|
||||
}
|
||||
else
|
||||
XLSurfaceRunFrameCallbacksMs (surface, last_drawn_time / 1000);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -344,25 +331,18 @@ RunFrameCallbacksConditionally (XdgRole *role)
|
|||
}
|
||||
|
||||
static void
|
||||
HandleReleaseLaterMessage (XdgRole *role, uint64_t id)
|
||||
BufferIdleCallback (RenderBuffer buffer, void *data)
|
||||
{
|
||||
ReleaseLaterRecord *record;
|
||||
XdgRole *role;
|
||||
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);
|
||||
RemoveRecord (record);
|
||||
}
|
||||
XLReleaseBuffer (record->buffer);
|
||||
DeleteRecord (record);
|
||||
|
||||
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
|
||||
XLHandleXEventForXdgSurfaces (XEvent *event)
|
||||
{
|
||||
XdgRole *role;
|
||||
uint64_t id, low, high;
|
||||
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
|
||||
&& ((event->xclient.message_type == _NET_WM_FRAME_DRAWN
|
||||
|| 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)
|
||||
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)
|
||||
{
|
||||
xdg_role->last_specified_serial = serial;
|
||||
xdg_role->state &= ~StateWaitingForAckConfigure;
|
||||
|
||||
/* Garbage the subcompositor too, since contents could be
|
||||
|
@ -720,6 +663,12 @@ Commit (Surface *surface, Role *role)
|
|||
if (!IsRoleMapped (xdg_role))
|
||||
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
|
||||
update is needed immediately after the frame completes. In any
|
||||
case, don't run frame callbacks upon buffer release anymore. */
|
||||
|
@ -727,8 +676,9 @@ Commit (Surface *surface, Role *role)
|
|||
{
|
||||
if (XLFrameClockCanBatch (xdg_role->clock))
|
||||
/* But if we can squeeze the frame inside the vertical
|
||||
blanking period, go ahead. */
|
||||
goto just_draw_then_return;
|
||||
blanking period, or a frame is in progress but EndFrame has
|
||||
not yet been called, go ahead. */
|
||||
goto start_drawing;
|
||||
|
||||
xdg_role->state |= StateLateFrame;
|
||||
xdg_role->state &= ~StatePendingFrameCallback;
|
||||
|
@ -743,38 +693,12 @@ Commit (Surface *surface, Role *role)
|
|||
|
||||
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);
|
||||
|
||||
/* Also run role "commit inside frame" hook. */
|
||||
if (xdg_role->impl && xdg_role->impl->funcs.commit_inside_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);
|
||||
/* Do not end frames explicitly. Instead, wait for the
|
||||
NoteFrameCallback to end the frame. */
|
||||
|
||||
return;
|
||||
|
||||
just_draw_then_return:
|
||||
SubcompositorUpdate (xdg_role->subcompositor);
|
||||
}
|
||||
|
||||
static Bool
|
||||
|
@ -887,7 +811,27 @@ Teardown (Surface *surface, Role *role)
|
|||
static void
|
||||
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
|
||||
|
@ -915,7 +859,8 @@ Subframe (Surface *surface, Role *role)
|
|||
{
|
||||
if (XLFrameClockCanBatch (xdg_role->clock))
|
||||
/* 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;
|
||||
|
||||
xdg_role->state |= StateLateFrame;
|
||||
|
@ -927,18 +872,14 @@ Subframe (Surface *surface, Role *role)
|
|||
return False;
|
||||
}
|
||||
|
||||
/* I guess subsurface updates don't count as urgent frames? */
|
||||
XLFrameClockStartFrame (xdg_role->clock, False);
|
||||
return True;
|
||||
}
|
||||
|
||||
static void
|
||||
EndSubframe (Surface *surface, Role *role)
|
||||
{
|
||||
XdgRole *xdg_role;
|
||||
|
||||
xdg_role = XdgRoleFromRole (role);
|
||||
XLFrameClockEndFrame (xdg_role->clock);
|
||||
/* Don't end the frame here; instead, wait for the frame callback to
|
||||
note that drawing the frame has finished. */
|
||||
}
|
||||
|
||||
static Window
|
||||
|
@ -969,34 +910,6 @@ AfterFrame (FrameClock *clock, void *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.
|
||||
Unless some buffers have not yet been released, in which case the
|
||||
callbacks will be run when they are. */
|
||||
|
@ -1234,6 +1147,63 @@ NoteBounds (void *data, int min_x, int min_y,
|
|||
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
|
||||
ResizeForMap (XdgRole *role)
|
||||
{
|
||||
|
@ -1387,6 +1357,10 @@ SelectExtraEvents (Surface *surface, Role *role,
|
|||
/* Select extra events for the input method. */
|
||||
XSelectInput (compositor.display, xdg_role->window,
|
||||
DefaultEventMask | event_mask);
|
||||
|
||||
/* Set the target standard event mask. */
|
||||
RenderSetStandardEventMask (xdg_role->target,
|
||||
DefaultEventMask | event_mask);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1482,7 +1456,7 @@ XLGetXdgSurface (struct wl_client *client, struct wl_resource *resource,
|
|||
0, 0, 20, 20, 0, compositor.n_planes,
|
||||
InputOutput, compositor.visual, flags,
|
||||
&attrs);
|
||||
role->target = RenderTargetFromWindow (role->window);
|
||||
role->target = RenderTargetFromWindow (role->window, DefaultEventMask);
|
||||
|
||||
role->subcompositor = MakeSubcompositor ();
|
||||
role->clock = XLMakeFrameClockForWindow (role->window);
|
||||
|
@ -1496,6 +1470,8 @@ XLGetXdgSurface (struct wl_client *client, struct wl_resource *resource,
|
|||
OpaqueRegionChanged, role);
|
||||
SubcompositorSetBoundsCallback (role->subcompositor,
|
||||
NoteBounds, role);
|
||||
SubcompositorSetNoteFrameCallback (role->subcompositor,
|
||||
NoteFrame, role);
|
||||
XLSelectStandardEvents (role->window);
|
||||
XLMakeAssoc (surfaces, role->window, role);
|
||||
|
||||
|
@ -1581,7 +1557,8 @@ XLXdgRoleSendConfigure (Role *role, uint32_t serial)
|
|||
xdg_role->state &= ~StateMaybeConfigure;
|
||||
|
||||
#ifdef DEBUG_GEOMETRY_CALCULATION
|
||||
fprintf (stderr, "Waiting for ack_configure...\n");
|
||||
fprintf (stderr, "Waiting for ack_configure (%"PRIu32")...\n",
|
||||
xdg_role->conf_serial);
|
||||
#endif
|
||||
|
||||
xdg_surface_send_configure (role->resource, serial);
|
||||
|
|
Loading…
Add table
Reference in a new issue