forked from 12to11/12to11
Major refactoring of the frame clock code
This is in preparation for a migration to the Present extension on systems that do not support frame synchronization. * 12to11.man: Remove option that is no longer useful. * Imakefile (SRCS, OBJS): Add `sync_source.c.'. * compositor.h (enum _RenderMode): New enum. (struct _RenderFuncs): Add some new functions. (enum _FrameMode): Remove ModeNotifyDisablePresent. * frame_clock.c (struct _FrameClockCallback): Add draw time to frame callback. (struct _FrameClock): Rearrange for alignment and remove many unused members. (BumpFrame): New function. (FreezeForValue): Remove code that is no longer useful, as clock->frozen no longer exists. (StartFrame, EndFrame): Remove clock "freezing" logic. Only `need_configure' remains. (RunFrameCallbacks, NoteFakeFrame): Add frame drawn time. (XLFrameClockAfterFrame): Adjust for new type of callback. (XLFrameClockFreeze): Remove function. (XLFrameClockFrameInProgress): Remove test for `frozen_until_end_frame'. (XLFrameClockHandleFrameEvent): Improve code in accordance with above changes. (XLFrameClockUnfreeze, XLFrameClockNeedConfigure): Remove functions. (XLFrameClockIsFrozen): Remove function. (XLFrameClockSetFreezeCallback): Accept new callback `fast_forward_callback'. (XLFrameClockGetFrameTime): Remove unused function. * icon_surface.c (struct _IconSurface, ReleaseBacking) (ReleaseBuffer, RunFrameCallbacks, AfterFrame, Commit) (SubsurfaceUpdate, XLGetIconSurface) (XLHandleOneXEventForIconSurfaces): Switch the icon surface to the sync helper abstraction, and allow asynch buffer release from inside. * picture_renderer.c (struct _PictureTarget): New field `next_msc' and `render_mode'. (SwapBackBuffers): Respect the render mode. (InitSynchronizedPresentation): Delete function. (InitAdditionalModifiers): Remove incorrect comment. (InitRenderFuncs): Stop initializing obsolete option. (SetRenderMode): New function. (PresentToWindow): Respect the render mode. (NotifyMsc): New function. (picture_render_funcs): Add notify_msc. (HandlePresentCompleteNotify): Call completion callback with the fraame counter. * renderer.c (RenderSetRenderMode): (RenderNotifyMsc): New functions. * subcompositor.c (struct _Subcompositor) (SubcompositorSetNoteFrameCallback): Add msc and ust to note frame callback. (PresentCompletedCallback, RenderCompletedCallback): Call with msc and ust. (BeginFrame): When presentation is being synchronized and there is no existing presentation callback, ask for an event to be sent on the next frame. (EndFrame): Do not clear the presentation callbacks, as the update might not touch anything. * test.c (NoteFrame): Update prototype. * xdg_popup.c (InternalReposition): Stop "freezing" the frame clock. * xdg_surface.c (struct _XdgRole): Replace the frame clock with the sync helper abstraction. (RunFrameCallbacks): Run with the frame time. (RunFrameCallbacksConditionally): Save the pending frame time. (UpdateFrameRefreshPrediction): Delete function. (XLHandleXEventForXdgSurfaces): Give events to the sync helper instead. (Unfreeze, IsRoleMapped, CheckFrame): Remove functions. (Commit, SubsurfaceUpdate): Update using the sync helper instead, only if not pending ack commit. (MaybeRunLateFrame, AfterFrame): Delete functions. (NoteConfigure, NoteBounds): Update for the sync helper. (WriteRedirectProperty): Always require redirection for now. Disabling redirection requires sorting out some Present problems on the X server side. (WasFrameQueued, NoteFrame): Delete functions. (HandleFreeze): Delete function. (HandleResize, CheckFastForward, HandleFrameCallback): New functions. (XLGetXdgSurface): Use the sync helper for most things. (XLXdgRoleSendConfigure, XLXdgRoleReconstrain) (XLXdgRoleGetFrameClock): Delete function. (XLXdgRoleNoteRejectedConfigure): Clean up for using the sync clock instead.
This commit is contained in:
parent
ed9a704e69
commit
1ce5081dfa
11 changed files with 484 additions and 654 deletions
|
@ -115,11 +115,6 @@ composite the contents of Wayland surfaces onto X windows. This can
|
||||||
either be \fBpicture\fP (the XRender based compositor) or \fBegl\fP
|
either be \fBpicture\fP (the XRender based compositor) or \fBegl\fP
|
||||||
(the OpenGL ES 2.0 based compositor).
|
(the OpenGL ES 2.0 based compositor).
|
||||||
.TP
|
.TP
|
||||||
.B useDirectPresentation\fP (class \fBUseDirectPresentation\fP)
|
|
||||||
If ``True'' or ``true'', this resource enables the use of direct
|
|
||||||
presentation on unredirected windows. This is not yet complete
|
|
||||||
pending the installation of required functionality in the X server.
|
|
||||||
.TP
|
|
||||||
.B wmProtocols\fP (class \fBWmProtocols\fP)
|
.B wmProtocols\fP (class \fBWmProtocols\fP)
|
||||||
Comma-separated list of window manager protocols, similar to
|
Comma-separated list of window manager protocols, similar to
|
||||||
\fBinputStyles\fP, that the protocol translator should enable or
|
\fBinputStyles\fP, that the protocol translator should enable or
|
||||||
|
|
|
@ -18,8 +18,8 @@ MakeSubdirs($(SUBDIRS))
|
||||||
DependSubdirs($(SUBDIRS))
|
DependSubdirs($(SUBDIRS))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
SRCS = 12to11.c run.c alloc.c fns.c output.c compositor.c surface.c region.c shm.c atoms.c subcompositor.c positioner.c xdg_wm.c xdg_surface.c xdg_toplevel.c frame_clock.c xerror.c ewmh.c timer.c subsurface.c seat.c data_device.c xdg_popup.c dmabuf.c buffer.c select.c xdata.c xsettings.c dnd.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 drm_lease.c pointer_constraints.c time.c relative_pointer.c keyboard_shortcuts_inhibit.c idle_inhibit.c process.c fence_ring.c pointer_gestures.c test.c buffer_release.c xdg_activation.c tearing_control.c
|
SRCS = 12to11.c run.c alloc.c fns.c output.c compositor.c surface.c region.c shm.c atoms.c subcompositor.c positioner.c xdg_wm.c xdg_surface.c xdg_toplevel.c frame_clock.c xerror.c ewmh.c timer.c subsurface.c seat.c data_device.c xdg_popup.c dmabuf.c buffer.c select.c xdata.c xsettings.c dnd.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 drm_lease.c pointer_constraints.c time.c relative_pointer.c keyboard_shortcuts_inhibit.c idle_inhibit.c process.c fence_ring.c pointer_gestures.c test.c buffer_release.c xdg_activation.c tearing_control.c sync_source.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 xdg_wm.o xdg_surface.o xdg_toplevel.o frame_clock.o xerror.o ewmh.o timer.o subsurface.o seat.o data_device.o xdg_popup.o dmabuf.o buffer.o select.o xdata.o xsettings.o dnd.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 drm_lease.o pointer_constraints.o time.o relative_pointer.o keyboard_shortcuts_inhibit.o idle_inhibit.o process.o fence_ring.o pointer_gestures.o test.o buffer_release.o xdg_activation.o tearing_control.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 xdg_wm.o xdg_surface.o xdg_toplevel.o frame_clock.o xerror.o ewmh.o timer.o subsurface.o seat.o data_device.o xdg_popup.o dmabuf.o buffer.o select.o xdata.o xsettings.o dnd.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 drm_lease.o pointer_constraints.o time.o relative_pointer.o keyboard_shortcuts_inhibit.o idle_inhibit.o process.o fence_ring.o pointer_gestures.o test.o buffer_release.o xdg_activation.o tearing_control.o sync_source.o
|
||||||
GENHEADERS = transfer_atoms.h drm_modifiers.h
|
GENHEADERS = transfer_atoms.h drm_modifiers.h
|
||||||
HEADER = $(GENHEADERS) compositor.h
|
HEADER = $(GENHEADERS) compositor.h
|
||||||
|
|
||||||
|
|
64
compositor.h
64
compositor.h
|
@ -160,6 +160,7 @@ typedef struct _ShmFormat ShmFormat;
|
||||||
|
|
||||||
typedef enum _Operation Operation;
|
typedef enum _Operation Operation;
|
||||||
typedef enum _BufferTransform BufferTransform;
|
typedef enum _BufferTransform BufferTransform;
|
||||||
|
typedef enum _RenderMode RenderMode;
|
||||||
|
|
||||||
typedef void *IdleCallbackKey;
|
typedef void *IdleCallbackKey;
|
||||||
typedef void *PresentCompletionKey;
|
typedef void *PresentCompletionKey;
|
||||||
|
@ -169,8 +170,8 @@ typedef void (*DmaBufSuccessFunc) (RenderBuffer, void *);
|
||||||
typedef void (*DmaBufFailureFunc) (void *);
|
typedef void (*DmaBufFailureFunc) (void *);
|
||||||
|
|
||||||
typedef void (*BufferIdleFunc) (RenderBuffer, void *);
|
typedef void (*BufferIdleFunc) (RenderBuffer, void *);
|
||||||
typedef void (*PresentCompletionFunc) (void *);
|
typedef void (*PresentCompletionFunc) (void *, uint64_t, uint64_t);
|
||||||
typedef void (*RenderCompletionFunc) (void *);
|
typedef void (*RenderCompletionFunc) (void *, uint64_t, uint64_t);
|
||||||
|
|
||||||
enum _BufferTransform
|
enum _BufferTransform
|
||||||
{
|
{
|
||||||
|
@ -314,6 +315,14 @@ enum
|
||||||
SupportsDirectPresent = 1 << 4,
|
SupportsDirectPresent = 1 << 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum _RenderMode
|
||||||
|
{
|
||||||
|
/* Do not synchronize rendering. */
|
||||||
|
RenderModeAsync,
|
||||||
|
/* Synchronize rendering with the vertical refresh. */
|
||||||
|
RenderModeVsync,
|
||||||
|
};
|
||||||
|
|
||||||
struct _RenderFuncs
|
struct _RenderFuncs
|
||||||
{
|
{
|
||||||
/* Initialize the visual and depth. */
|
/* Initialize the visual and depth. */
|
||||||
|
@ -325,6 +334,12 @@ struct _RenderFuncs
|
||||||
/* 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 rendering mode for the render target. Return whether or
|
||||||
|
not the mode was successfully set. The default rendering mode is
|
||||||
|
RenderModeAsync. The last argument is the number of the next
|
||||||
|
frame as known to the caller. */
|
||||||
|
Bool (*set_render_mode) (RenderTarget, RenderMode, uint64_t);
|
||||||
|
|
||||||
/* Set the client associated with the target. This allows some
|
/* Set the client associated with the target. This allows some
|
||||||
extra pixmap memory allocation tracking to be done. */
|
extra pixmap memory allocation tracking to be done. */
|
||||||
void (*set_client) (RenderTarget, struct wl_client *);
|
void (*set_client) (RenderTarget, struct wl_client *);
|
||||||
|
@ -423,6 +438,11 @@ struct _RenderFuncs
|
||||||
pixman_region32_t *,
|
pixman_region32_t *,
|
||||||
PresentCompletionFunc, void *);
|
PresentCompletionFunc, void *);
|
||||||
|
|
||||||
|
/* Call the specified render callback once it is time to display the
|
||||||
|
next frame. May be NULL. */
|
||||||
|
RenderCompletionKey (*notify_msc) (RenderTarget, RenderCompletionFunc,
|
||||||
|
void *);
|
||||||
|
|
||||||
/* Cancel the given presentation callback. */
|
/* Cancel the given presentation callback. */
|
||||||
void (*cancel_presentation_callback) (PresentCompletionKey);
|
void (*cancel_presentation_callback) (PresentCompletionKey);
|
||||||
|
|
||||||
|
@ -542,6 +562,7 @@ extern void InitRenderers (void);
|
||||||
|
|
||||||
extern RenderTarget RenderTargetFromWindow (Window, unsigned long);
|
extern RenderTarget RenderTargetFromWindow (Window, unsigned long);
|
||||||
extern RenderTarget RenderTargetFromPixmap (Pixmap);
|
extern RenderTarget RenderTargetFromPixmap (Pixmap);
|
||||||
|
extern Bool RenderSetRenderMode (RenderTarget, RenderMode, uint64_t);
|
||||||
extern void RenderSetClient (RenderTarget, struct wl_client *);
|
extern void RenderSetClient (RenderTarget, struct wl_client *);
|
||||||
extern void RenderSetStandardEventMask (RenderTarget, unsigned long);
|
extern void RenderSetStandardEventMask (RenderTarget, unsigned long);
|
||||||
extern void RenderNoteTargetSize (RenderTarget, int, int);
|
extern void RenderNoteTargetSize (RenderTarget, int, int);
|
||||||
|
@ -568,6 +589,8 @@ extern PresentCompletionKey RenderPresentToWindow (RenderTarget, RenderBuffer,
|
||||||
pixman_region32_t *,
|
pixman_region32_t *,
|
||||||
PresentCompletionFunc,
|
PresentCompletionFunc,
|
||||||
void *);
|
void *);
|
||||||
|
extern RenderCompletionKey RenderNotifyMsc (RenderTarget, RenderCompletionFunc,
|
||||||
|
void *);
|
||||||
extern void RenderCancelPresentationCallback (PresentCompletionKey);
|
extern void RenderCancelPresentationCallback (PresentCompletionKey);
|
||||||
|
|
||||||
extern DrmFormat *RenderGetDrmFormats (int *);
|
extern DrmFormat *RenderGetDrmFormats (int *);
|
||||||
|
@ -767,7 +790,6 @@ typedef enum _FrameMode FrameMode;
|
||||||
enum _FrameMode
|
enum _FrameMode
|
||||||
{
|
{
|
||||||
ModeStarted,
|
ModeStarted,
|
||||||
ModeNotifyDisablePresent,
|
|
||||||
ModeComplete,
|
ModeComplete,
|
||||||
ModePresented,
|
ModePresented,
|
||||||
};
|
};
|
||||||
|
@ -798,7 +820,8 @@ extern void SubcompositorSetBoundsCallback (Subcompositor *,
|
||||||
void *);
|
void *);
|
||||||
extern void SubcompositorSetNoteFrameCallback (Subcompositor *,
|
extern void SubcompositorSetNoteFrameCallback (Subcompositor *,
|
||||||
void (*) (FrameMode, uint64_t,
|
void (*) (FrameMode, uint64_t,
|
||||||
void *),
|
void *, uint64_t,
|
||||||
|
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);
|
||||||
|
@ -1304,24 +1327,20 @@ typedef struct _FrameClock FrameClock;
|
||||||
extern FrameClock *XLMakeFrameClockForWindow (Window);
|
extern FrameClock *XLMakeFrameClockForWindow (Window);
|
||||||
extern Bool XLFrameClockFrameInProgress (FrameClock *);
|
extern Bool XLFrameClockFrameInProgress (FrameClock *);
|
||||||
extern void XLFrameClockAfterFrame (FrameClock *, void (*) (FrameClock *,
|
extern void XLFrameClockAfterFrame (FrameClock *, void (*) (FrameClock *,
|
||||||
void *),
|
void *,
|
||||||
|
uint64_t),
|
||||||
void *);
|
void *);
|
||||||
extern void XLFrameClockHandleFrameEvent (FrameClock *, XEvent *);
|
extern void XLFrameClockHandleFrameEvent (FrameClock *, XEvent *);
|
||||||
extern Bool XLFrameClockStartFrame (FrameClock *, Bool);
|
extern Bool XLFrameClockStartFrame (FrameClock *, Bool);
|
||||||
extern void XLFrameClockEndFrame (FrameClock *);
|
extern void XLFrameClockEndFrame (FrameClock *);
|
||||||
extern Bool XLFrameClockIsFrozen (FrameClock *);
|
|
||||||
extern Bool XLFrameClockCanBatch (FrameClock *);
|
extern Bool XLFrameClockCanBatch (FrameClock *);
|
||||||
extern Bool XLFrameClockNeedConfigure (FrameClock *);
|
|
||||||
extern void XLFrameClockFreeze (FrameClock *);
|
|
||||||
extern void XLFrameClockUnfreeze (FrameClock *);
|
|
||||||
extern void XLFreeFrameClock (FrameClock *);
|
extern void XLFreeFrameClock (FrameClock *);
|
||||||
extern Bool XLFrameClockSyncSupported (void);
|
extern Bool XLFrameClockSyncSupported (void);
|
||||||
extern Bool XLFrameClockCanRunFrame (FrameClock *);
|
|
||||||
extern void XLFrameClockSetPredictRefresh (FrameClock *);
|
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 *);
|
Bool),
|
||||||
extern uint64_t XLFrameClockGetFrameTime (FrameClock *);
|
Bool (*) (void *), void *);
|
||||||
extern void XLFrameClockNoteConfigure (FrameClock *);
|
extern void XLFrameClockNoteConfigure (FrameClock *);
|
||||||
extern void *XLAddCursorClockCallback (void (*) (void *, struct timespec),
|
extern void *XLAddCursorClockCallback (void (*) (void *, struct timespec),
|
||||||
void *);
|
void *);
|
||||||
|
@ -1905,6 +1924,25 @@ extern void XLInitXdgActivation (void);
|
||||||
|
|
||||||
extern void XLInitTearingControl (void);
|
extern void XLInitTearingControl (void);
|
||||||
|
|
||||||
|
/* Defined in sync_source.h. */
|
||||||
|
|
||||||
|
typedef struct _SyncHelper SyncHelper;
|
||||||
|
typedef enum _SynchronizationType SynchronizationType;
|
||||||
|
|
||||||
|
extern SyncHelper *MakeSyncHelper (Subcompositor *, Window,
|
||||||
|
RenderTarget,
|
||||||
|
void (*) (void *, uint32_t),
|
||||||
|
Role *);
|
||||||
|
extern void SyncHelperUpdate (SyncHelper *);
|
||||||
|
extern void FreeSyncHelper (SyncHelper *);
|
||||||
|
extern void SyncHelperHandleFrameEvent (SyncHelper *, XEvent *);
|
||||||
|
extern void SyncHelperSetResizeCallback (SyncHelper *, void (*) (void *,
|
||||||
|
Bool),
|
||||||
|
Bool (*) (void *));
|
||||||
|
extern void SyncHelperNoteConfigureEvent (SyncHelper *);
|
||||||
|
extern void SyncHelperCheckFrameCallback (SyncHelper *);
|
||||||
|
extern void SyncHelperClearPendingFrame (SyncHelper *);
|
||||||
|
|
||||||
/* 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])
|
||||||
|
|
197
frame_clock.c
197
frame_clock.c
|
@ -33,23 +33,20 @@ enum
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Whether or not the compositor supports frame synchronization. */
|
/* Whether or not the compositor supports frame synchronization. */
|
||||||
|
|
||||||
static Bool frame_sync_supported;
|
static Bool frame_sync_supported;
|
||||||
|
|
||||||
/* Timer used for cursor animations. */
|
/* Timer used for cursor animations. */
|
||||||
|
|
||||||
static Timer *cursor_clock;
|
static Timer *cursor_clock;
|
||||||
|
|
||||||
/* How many cursors want cursor animations. */
|
/* How many cursors want cursor animations. */
|
||||||
|
|
||||||
static int cursor_count;
|
static int cursor_count;
|
||||||
|
|
||||||
struct _FrameClockCallback
|
struct _FrameClockCallback
|
||||||
{
|
{
|
||||||
/* Function called once a frame is completely written to display and
|
/* Function called once a frame is completely written to display.
|
||||||
(ideally, whether or not this actually works depends on various
|
The last arg is the time at which the frame was written, or
|
||||||
different factors) enters vblank. */
|
(uint64_t) -1. */
|
||||||
void (*frame) (FrameClock *, void *);
|
void (*frame) (FrameClock *, void *, uint64_t);
|
||||||
|
|
||||||
/* Data that function is called with. */
|
/* Data that function is called with. */
|
||||||
void *data;
|
void *data;
|
||||||
|
@ -60,28 +57,12 @@ struct _FrameClockCallback
|
||||||
|
|
||||||
struct _FrameClock
|
struct _FrameClock
|
||||||
{
|
{
|
||||||
/* List of frame clock callbacks. */
|
|
||||||
FrameClockCallback callbacks;
|
|
||||||
|
|
||||||
/* Two sync counters. */
|
|
||||||
XSyncCounter primary_counter, secondary_counter;
|
|
||||||
|
|
||||||
/* The value of the frame currently being drawn in this frame clock,
|
/* The value of the frame currently being drawn in this frame clock,
|
||||||
and the value of the last frame that was marked as complete. */
|
and the value of the last frame that was marked as complete. */
|
||||||
uint64_t next_frame_id, finished_frame_id;
|
uint64_t next_frame_id, finished_frame_id;
|
||||||
|
|
||||||
/* A timer used as a fake synchronization source if frame
|
/* List of frame clock callbacks. */
|
||||||
synchronization is not supported. */
|
FrameClockCallback callbacks;
|
||||||
Timer *static_frame_timer;
|
|
||||||
|
|
||||||
/* A timer used to end the next frame. */
|
|
||||||
Timer *end_frame_timer;
|
|
||||||
|
|
||||||
/* Callback run when the frame is frozen. */
|
|
||||||
void (*freeze_callback) (void *);
|
|
||||||
|
|
||||||
/* Data for that callback. */
|
|
||||||
void *freeze_callback_data;
|
|
||||||
|
|
||||||
/* The wanted configure value. */
|
/* The wanted configure value. */
|
||||||
uint64_t configure_id;
|
uint64_t configure_id;
|
||||||
|
@ -103,6 +84,28 @@ struct _FrameClock
|
||||||
/* The last known presentation time. */
|
/* The last known presentation time. */
|
||||||
uint64_t last_presentation_time;
|
uint64_t last_presentation_time;
|
||||||
|
|
||||||
|
/* Two sync counters. */
|
||||||
|
XSyncCounter primary_counter, secondary_counter;
|
||||||
|
|
||||||
|
/* A timer used as a fake synchronization source if frame
|
||||||
|
synchronization is not supported. */
|
||||||
|
Timer *static_frame_timer;
|
||||||
|
|
||||||
|
/* A timer used to end the next frame. */
|
||||||
|
Timer *end_frame_timer;
|
||||||
|
|
||||||
|
/* Callback run when the frame is frozen. The second arg means
|
||||||
|
whether or not the freeze should not result in more waiting for
|
||||||
|
ack_configure. */
|
||||||
|
void (*freeze_callback) (void *, Bool);
|
||||||
|
|
||||||
|
/* Callback run to determine whether or not the frame clock can be
|
||||||
|
fast forwarded. */
|
||||||
|
Bool (*can_forward_sync_counter) (void *);
|
||||||
|
|
||||||
|
/* Data for the above two callbacks. */
|
||||||
|
void *freeze_callback_data;
|
||||||
|
|
||||||
/* The refresh interval. */
|
/* The refresh interval. */
|
||||||
uint32_t refresh_interval;
|
uint32_t refresh_interval;
|
||||||
|
|
||||||
|
@ -114,10 +117,8 @@ struct _FrameClock
|
||||||
is put in place. */
|
is put in place. */
|
||||||
uint32_t got_configure_count, pending_configure_count;
|
uint32_t got_configure_count, pending_configure_count;
|
||||||
|
|
||||||
/* Whether or not configury is in progress, and whether or not this
|
/* Whether or not configury is in progress. */
|
||||||
is frozen, and whether or not the frame shouldn't actually be
|
Bool need_configure;
|
||||||
unfrozen until EndFrame. */
|
|
||||||
Bool need_configure, frozen, frozen_until_end_frame;
|
|
||||||
|
|
||||||
/* Whether or not EndFrame was called after StartFrame. */
|
/* Whether or not EndFrame was called after StartFrame. */
|
||||||
Bool end_frame_called;
|
Bool end_frame_called;
|
||||||
|
@ -246,9 +247,16 @@ HandleEndFrame (Timer *timer, void *data, struct timespec time)
|
||||||
|
|
||||||
/* Forward declarations. */
|
/* Forward declarations. */
|
||||||
|
|
||||||
static void RunFrameCallbacks (FrameClock *);
|
static void RunFrameCallbacks (FrameClock *, uint64_t);
|
||||||
static Bool StartFrame (FrameClock *, Bool, Bool);
|
static Bool StartFrame (FrameClock *, Bool, Bool);
|
||||||
|
|
||||||
|
static void
|
||||||
|
BumpFrame (FrameClock *clock)
|
||||||
|
{
|
||||||
|
StartFrame (clock, True, False);
|
||||||
|
EndFrame (clock);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
FreezeForValue (FrameClock *clock, uint64_t counter_value)
|
FreezeForValue (FrameClock *clock, uint64_t counter_value)
|
||||||
{
|
{
|
||||||
|
@ -266,6 +274,7 @@ FreezeForValue (FrameClock *clock, uint64_t counter_value)
|
||||||
configure event after this freeze may have been put into effect
|
configure event after this freeze may have been put into effect
|
||||||
by the time the freeze itself. Start a new frame to bring up to
|
by the time the freeze itself. Start a new frame to bring up to
|
||||||
date contents to the display. */
|
date contents to the display. */
|
||||||
|
|
||||||
if (clock->pending_configure_count <= clock->got_configure_count)
|
if (clock->pending_configure_count <= clock->got_configure_count)
|
||||||
need_empty_frame = True;
|
need_empty_frame = True;
|
||||||
|
|
||||||
|
@ -282,14 +291,6 @@ FreezeForValue (FrameClock *clock, uint64_t counter_value)
|
||||||
EndFrame (clock);
|
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
|
/* The reason for clearing in_frame is that otherwise a future
|
||||||
Commit after the configuration is acknowledged will not be able
|
Commit after the configuration is acknowledged will not be able
|
||||||
to start a new frame and restart the frame clock. */
|
to start a new frame and restart the frame clock. */
|
||||||
|
@ -297,17 +298,23 @@ FreezeForValue (FrameClock *clock, uint64_t counter_value)
|
||||||
clock->need_configure = True;
|
clock->need_configure = True;
|
||||||
clock->configure_id = counter_value;
|
clock->configure_id = counter_value;
|
||||||
|
|
||||||
if (need_empty_frame)
|
if (need_empty_frame
|
||||||
{
|
/* If the surface has not yet ack_configure'd, don't fast
|
||||||
/* Request a new frame and don't allow starting frames until it
|
forward the frame. The sync counter will be set at the next
|
||||||
finishes. See above for why. clock->in_frame is False for
|
commit after ack_configure. */
|
||||||
now to really force the frame to happen. */
|
&& clock->can_forward_sync_counter
|
||||||
|
&& clock->can_forward_sync_counter (clock->freeze_callback_data))
|
||||||
|
/* If this event is already out of date, just fast forward the
|
||||||
|
sync counter. */
|
||||||
|
BumpFrame (clock);
|
||||||
|
|
||||||
StartFrame (clock, True, False);
|
clock->freeze_callback (clock->freeze_callback_data,
|
||||||
EndFrame (clock);
|
/* Only run the freeze callback if this
|
||||||
}
|
freeze is up to date. If it is not,
|
||||||
else
|
frame callbacks still have to be run,
|
||||||
clock->frozen = True;
|
which is what the following parameter
|
||||||
|
means. */
|
||||||
|
need_empty_frame);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -410,12 +417,6 @@ PostEndFrame (FrameClock *clock)
|
||||||
static Bool
|
static Bool
|
||||||
StartFrame (FrameClock *clock, Bool urgent, Bool predict)
|
StartFrame (FrameClock *clock, Bool urgent, Bool predict)
|
||||||
{
|
{
|
||||||
if (clock->frozen)
|
|
||||||
return False;
|
|
||||||
|
|
||||||
if (clock->frozen_until_end_frame)
|
|
||||||
return False;
|
|
||||||
|
|
||||||
if (clock->in_frame)
|
if (clock->in_frame)
|
||||||
{
|
{
|
||||||
if (clock->end_frame_timer
|
if (clock->end_frame_timer
|
||||||
|
@ -487,11 +488,6 @@ StartFrame (FrameClock *clock, Bool urgent, Bool predict)
|
||||||
static void
|
static void
|
||||||
EndFrame (FrameClock *clock)
|
EndFrame (FrameClock *clock)
|
||||||
{
|
{
|
||||||
if (clock->frozen)
|
|
||||||
return;
|
|
||||||
|
|
||||||
clock->frozen_until_end_frame = False;
|
|
||||||
|
|
||||||
/* Signal that end_frame was called and it is now safe to finish the
|
/* Signal that end_frame was called and it is now safe to finish the
|
||||||
frame from the timer. */
|
frame from the timer. */
|
||||||
clock->end_frame_called = True;
|
clock->end_frame_called = True;
|
||||||
|
@ -521,8 +517,10 @@ EndFrame (FrameClock *clock)
|
||||||
|
|
||||||
/* The frame has ended. Freeze the frame clock if there is a
|
/* The frame has ended. Freeze the frame clock if there is a
|
||||||
pending sync value. */
|
pending sync value. */
|
||||||
|
|
||||||
if (clock->pending_sync_value)
|
if (clock->pending_sync_value)
|
||||||
FreezeForValue (clock, clock->pending_sync_value);
|
FreezeForValue (clock, clock->pending_sync_value);
|
||||||
|
|
||||||
clock->pending_sync_value = 0;
|
clock->pending_sync_value = 0;
|
||||||
|
|
||||||
if (!frame_sync_supported)
|
if (!frame_sync_supported)
|
||||||
|
@ -551,7 +549,7 @@ FreeFrameCallbacks (FrameClock *clock)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
RunFrameCallbacks (FrameClock *clock)
|
RunFrameCallbacks (FrameClock *clock, uint64_t frame_drawn_time)
|
||||||
{
|
{
|
||||||
FrameClockCallback *callback;
|
FrameClockCallback *callback;
|
||||||
|
|
||||||
|
@ -559,7 +557,8 @@ RunFrameCallbacks (FrameClock *clock)
|
||||||
|
|
||||||
while (callback != &clock->callbacks)
|
while (callback != &clock->callbacks)
|
||||||
{
|
{
|
||||||
callback->frame (clock, callback->data);
|
callback->frame (clock, callback->data,
|
||||||
|
frame_drawn_time);
|
||||||
callback = callback->next;
|
callback = callback->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -575,13 +574,14 @@ NoteFakeFrame (Timer *timer, void *data, struct timespec time)
|
||||||
&& (clock->finished_frame_id == clock->next_frame_id))
|
&& (clock->finished_frame_id == clock->next_frame_id))
|
||||||
{
|
{
|
||||||
clock->in_frame = False;
|
clock->in_frame = False;
|
||||||
RunFrameCallbacks (clock);
|
RunFrameCallbacks (clock, (uint64_t) -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
XLFrameClockAfterFrame (FrameClock *clock,
|
XLFrameClockAfterFrame (FrameClock *clock,
|
||||||
void (*frame_func) (FrameClock *, void *),
|
void (*frame_func) (FrameClock *, void *,
|
||||||
|
uint64_t),
|
||||||
void *data)
|
void *data)
|
||||||
{
|
{
|
||||||
FrameClockCallback *callback;
|
FrameClockCallback *callback;
|
||||||
|
@ -613,36 +613,9 @@ XLFrameClockEndFrame (FrameClock *clock)
|
||||||
Bool
|
Bool
|
||||||
XLFrameClockFrameInProgress (FrameClock *clock)
|
XLFrameClockFrameInProgress (FrameClock *clock)
|
||||||
{
|
{
|
||||||
if (clock->frozen_until_end_frame)
|
|
||||||
/* Don't consider a frame as being in progress, since the frame
|
|
||||||
counter has been incremented to freeze the display. */
|
|
||||||
return False;
|
|
||||||
|
|
||||||
return clock->in_frame;
|
return clock->in_frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* N.B. that this function is called from popups, where normal
|
|
||||||
freezing does not work, as the window manager does not
|
|
||||||
cooperate. */
|
|
||||||
|
|
||||||
void
|
|
||||||
XLFrameClockFreeze (FrameClock *clock)
|
|
||||||
{
|
|
||||||
/* Start a frame now, unless one is already in progress, in which
|
|
||||||
case it suffices to get rid of the timer. */
|
|
||||||
if (!clock->end_frame_timer)
|
|
||||||
StartFrame (clock, False, False);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
RemoveTimer (clock->end_frame_timer);
|
|
||||||
clock->end_frame_timer = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Don't unfreeze until the next EndFrame. */
|
|
||||||
clock->frozen_until_end_frame = True;
|
|
||||||
clock->frozen = True;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
XLFrameClockHandleFrameEvent (FrameClock *clock, XEvent *event)
|
XLFrameClockHandleFrameEvent (FrameClock *clock, XEvent *event)
|
||||||
{
|
{
|
||||||
|
@ -671,9 +644,11 @@ XLFrameClockHandleFrameEvent (FrameClock *clock, XEvent *event)
|
||||||
/* Actually compute the time and save it. */
|
/* Actually compute the time and save it. */
|
||||||
clock->last_frame_time = low | (high << 32);
|
clock->last_frame_time = low | (high << 32);
|
||||||
|
|
||||||
/* Run any frame callbacks, since drawing has finished. */
|
/* Clear the in_frame flag. */
|
||||||
clock->in_frame = False;
|
clock->in_frame = False;
|
||||||
RunFrameCallbacks (clock);
|
|
||||||
|
/* Run any frame callbacks, since drawing has finished. */
|
||||||
|
RunFrameCallbacks (clock, clock->last_frame_time);
|
||||||
|
|
||||||
if (clock->frame_timings_id == -1)
|
if (clock->frame_timings_id == -1)
|
||||||
{
|
{
|
||||||
|
@ -742,14 +717,11 @@ XLFrameClockHandleFrameEvent (FrameClock *clock, XEvent *event)
|
||||||
|
|
||||||
/* If a frame is in progress, postpone this frame
|
/* If a frame is in progress, postpone this frame
|
||||||
synchronization message. */
|
synchronization message. */
|
||||||
|
|
||||||
if (clock->in_frame && !clock->end_frame_called)
|
if (clock->in_frame && !clock->end_frame_called)
|
||||||
clock->pending_sync_value = value;
|
clock->pending_sync_value = value;
|
||||||
else
|
else
|
||||||
FreezeForValue (clock, value);
|
FreezeForValue (clock, value);
|
||||||
|
|
||||||
if (clock->freeze_callback)
|
|
||||||
/* Call the freeze callback in any case. */
|
|
||||||
clock->freeze_callback (clock->freeze_callback_data);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -821,30 +793,12 @@ XLMakeFrameClockForWindow (Window window)
|
||||||
return clock;
|
return clock;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
XLFrameClockUnfreeze (FrameClock *clock)
|
|
||||||
{
|
|
||||||
clock->frozen = False;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool
|
|
||||||
XLFrameClockNeedConfigure (FrameClock *clock)
|
|
||||||
{
|
|
||||||
return clock->need_configure;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool
|
Bool
|
||||||
XLFrameClockSyncSupported (void)
|
XLFrameClockSyncSupported (void)
|
||||||
{
|
{
|
||||||
return frame_sync_supported;
|
return frame_sync_supported;
|
||||||
}
|
}
|
||||||
|
|
||||||
Bool
|
|
||||||
XLFrameClockIsFrozen (FrameClock *clock)
|
|
||||||
{
|
|
||||||
return clock->frozen;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool
|
Bool
|
||||||
XLFrameClockCanBatch (FrameClock *clock)
|
XLFrameClockCanBatch (FrameClock *clock)
|
||||||
{
|
{
|
||||||
|
@ -884,21 +838,14 @@ XLFrameClockDisablePredictRefresh (FrameClock *clock)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
XLFrameClockSetFreezeCallback (FrameClock *clock, void (*callback) (void *),
|
XLFrameClockSetFreezeCallback (FrameClock *clock, void (*callback) (void *,
|
||||||
|
Bool),
|
||||||
|
Bool (*fast_forward_callback) (void *),
|
||||||
void *data)
|
void *data)
|
||||||
{
|
{
|
||||||
clock->freeze_callback = callback;
|
clock->freeze_callback = callback;
|
||||||
clock->freeze_callback_data = data;
|
clock->freeze_callback_data = data;
|
||||||
}
|
clock->can_forward_sync_counter = fast_forward_callback;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
158
icon_surface.c
158
icon_surface.c
|
@ -29,9 +29,10 @@ along with 12to11. If not, see <https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
StateLateFrame = 1,
|
StateIsMapped = 1,
|
||||||
StateIsMapped = (1 << 1),
|
StateIsReleased = (1 << 1),
|
||||||
StateIsReleased = (1 << 2),
|
StatePendingBufferRelease = (1 << 2),
|
||||||
|
StatePendingFrameCallback = (1 << 3),
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _IconSurface
|
struct _IconSurface
|
||||||
|
@ -48,8 +49,11 @@ struct _IconSurface
|
||||||
/* The subcompositor associated with this role. */
|
/* The subcompositor associated with this role. */
|
||||||
Subcompositor *subcompositor;
|
Subcompositor *subcompositor;
|
||||||
|
|
||||||
/* The frame clock associated with this role. */
|
/* The associated buffer release helper. */
|
||||||
FrameClock *clock;
|
BufferReleaseHelper *release_helper;
|
||||||
|
|
||||||
|
/* The sync source associated with this role. */
|
||||||
|
SyncHelper *sync_helper;
|
||||||
|
|
||||||
/* The number of references to this role. */
|
/* The number of references to this role. */
|
||||||
int refcount;
|
int refcount;
|
||||||
|
@ -63,6 +67,9 @@ struct _IconSurface
|
||||||
|
|
||||||
/* The last known bounds of this icon surface. */
|
/* The last known bounds of this icon surface. */
|
||||||
int min_x, min_y, max_x, max_y;
|
int min_x, min_y, max_x, max_y;
|
||||||
|
|
||||||
|
/* The time of any pending frame. */
|
||||||
|
uint32_t pending_frame_time;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Hash table of all icon surfaces. */
|
/* Hash table of all icon surfaces. */
|
||||||
|
@ -90,16 +97,19 @@ ReleaseBacking (IconSurface *icon)
|
||||||
RenderDestroyRenderTarget (icon->target);
|
RenderDestroyRenderTarget (icon->target);
|
||||||
XDestroyWindow (compositor.display, icon->window);
|
XDestroyWindow (compositor.display, icon->window);
|
||||||
|
|
||||||
|
/* And the buffer release helper. */
|
||||||
|
FreeBufferReleaseHelper (icon->release_helper);
|
||||||
|
|
||||||
/* And the association. */
|
/* And the association. */
|
||||||
XLDeleteAssoc (surfaces, icon->window);
|
XLDeleteAssoc (surfaces, icon->window);
|
||||||
|
|
||||||
|
/* Free the sync helper. */
|
||||||
|
FreeSyncHelper (icon->sync_helper);
|
||||||
|
|
||||||
/* There shouldn't be any children of the subcompositor at this
|
/* There shouldn't be any children of the subcompositor at this
|
||||||
point. */
|
point. */
|
||||||
SubcompositorFree (icon->subcompositor);
|
SubcompositorFree (icon->subcompositor);
|
||||||
|
|
||||||
/* The frame clock is no longer useful. */
|
|
||||||
XLFreeFrameClock (icon->clock);
|
|
||||||
|
|
||||||
/* And since there are no C level references to the icon surface
|
/* And since there are no C level references to the icon surface
|
||||||
anymore, it can be freed. */
|
anymore, it can be freed. */
|
||||||
XLFree (icon);
|
XLFree (icon);
|
||||||
|
@ -155,17 +165,22 @@ Setup (Surface *surface, Role *role)
|
||||||
static void
|
static void
|
||||||
ReleaseBuffer (Surface *surface, Role *role, ExtBuffer *buffer)
|
ReleaseBuffer (Surface *surface, Role *role, ExtBuffer *buffer)
|
||||||
{
|
{
|
||||||
|
RenderBuffer render_buffer;
|
||||||
IconSurface *icon;
|
IconSurface *icon;
|
||||||
|
|
||||||
icon = IconSurfaceFromRole (role);
|
icon = IconSurfaceFromRole (role);
|
||||||
|
render_buffer = XLRenderBufferFromBuffer (buffer);
|
||||||
|
|
||||||
/* Icon surfaces are not supposed to change much, so doing an XSync
|
if (RenderIsBufferIdle (render_buffer, icon->target))
|
||||||
(or XIfEvent) here is okay. */
|
/* If the buffer is already idle, release it now. */
|
||||||
RenderWaitForIdle (XLRenderBufferFromBuffer (buffer),
|
|
||||||
icon->target);
|
|
||||||
|
|
||||||
/* Now really release the buffer. */
|
|
||||||
XLReleaseBuffer (buffer);
|
XLReleaseBuffer (buffer);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Release the buffer once it is destroyed or becomes idle. */
|
||||||
|
ReleaseBufferWithHelper (icon->release_helper,
|
||||||
|
buffer, icon->target);
|
||||||
|
icon->state |= StatePendingBufferRelease;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -218,48 +233,61 @@ NoteBounds (void *data, int min_x, int min_y, int max_x, int max_y)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
RunFrameCallbacks (Surface *surface, FrameClock *clock)
|
RunFrameCallbacks (Surface *surface, uint32_t ms_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);
|
XLSurfaceRunFrameCallbacksMs (surface, ms_time);
|
||||||
|
|
||||||
if (!last_drawn_time)
|
|
||||||
{
|
|
||||||
clock_gettime (CLOCK_MONOTONIC, &time);
|
|
||||||
XLSurfaceRunFrameCallbacks (surface, time);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
XLSurfaceRunFrameCallbacksMs (surface, last_drawn_time / 1000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
AfterFrame (FrameClock *clock, void *data)
|
RunFrameCallbacksConditionally (IconSurface *icon, uint32_t ms_time)
|
||||||
|
{
|
||||||
|
if (!icon->role.surface)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (icon->state & StatePendingBufferRelease)
|
||||||
|
{
|
||||||
|
/* Wait for all buffers to be released first. */
|
||||||
|
icon->state |= StatePendingFrameCallback;
|
||||||
|
icon->pending_frame_time = ms_time;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
RunFrameCallbacks (icon->role.surface, ms_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
AllBuffersReleased (void *data)
|
||||||
|
{
|
||||||
|
IconSurface *icon;
|
||||||
|
Surface *surface;
|
||||||
|
|
||||||
|
icon = data;
|
||||||
|
surface = icon->role.surface;
|
||||||
|
|
||||||
|
/* Clear the buffer release flag. */
|
||||||
|
icon->state = ~StatePendingBufferRelease;
|
||||||
|
|
||||||
|
if (surface && icon->state & StatePendingFrameCallback)
|
||||||
|
{
|
||||||
|
/* Run frame callbacks now, as no more buffers are waiting to be
|
||||||
|
released. */
|
||||||
|
RunFrameCallbacks (surface, icon->pending_frame_time);
|
||||||
|
|
||||||
|
icon->state &= ~StatePendingFrameCallback;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
HandleFrameCallback (void *data, uint32_t ms_time)
|
||||||
{
|
{
|
||||||
IconSurface *icon;
|
IconSurface *icon;
|
||||||
|
|
||||||
icon = data;
|
icon = data;
|
||||||
|
RunFrameCallbacksConditionally (icon, ms_time);
|
||||||
if (icon->state & StateLateFrame)
|
|
||||||
{
|
|
||||||
icon->state &= ~StateLateFrame;
|
|
||||||
|
|
||||||
/* Since we are running late, make the compositor draw the frame
|
|
||||||
now. */
|
|
||||||
XLFrameClockStartFrame (clock, True);
|
|
||||||
SubcompositorUpdate (icon->subcompositor);
|
|
||||||
XLFrameClockEndFrame (clock);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
RunFrameCallbacks (icon->role.surface, clock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -316,20 +344,6 @@ Commit (Surface *surface, Role *role)
|
||||||
|
|
||||||
icon = IconSurfaceFromRole (role);
|
icon = IconSurfaceFromRole (role);
|
||||||
|
|
||||||
if (XLFrameClockFrameInProgress (icon->clock))
|
|
||||||
{
|
|
||||||
/* A frame is already in progress; schedule another one for
|
|
||||||
later. */
|
|
||||||
icon->state |= StateLateFrame;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Start a frame and update the icon surface now. */
|
|
||||||
XLFrameClockStartFrame (icon->clock, False);
|
|
||||||
SubcompositorUpdate (icon->subcompositor);
|
|
||||||
XLFrameClockEndFrame (icon->clock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Move the window if any offset was specified. */
|
/* Move the window if any offset was specified. */
|
||||||
if (surface->pending_state.pending & PendingAttachments)
|
if (surface->pending_state.pending & PendingAttachments)
|
||||||
MoveWindowTo (icon, icon->x, icon->y);
|
MoveWindowTo (icon, icon->x, icon->y);
|
||||||
|
@ -340,6 +354,9 @@ Commit (Surface *surface, Role *role)
|
||||||
MaybeMapWindow (icon);
|
MaybeMapWindow (icon);
|
||||||
else
|
else
|
||||||
MaybeUnmapWindow (icon);
|
MaybeUnmapWindow (icon);
|
||||||
|
|
||||||
|
/* Update via the sync helper. */
|
||||||
|
SyncHelperUpdate (icon->sync_helper);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -348,19 +365,7 @@ SubsurfaceUpdate (Surface *surface, Role *role)
|
||||||
IconSurface *icon;
|
IconSurface *icon;
|
||||||
|
|
||||||
icon = IconSurfaceFromRole (role);
|
icon = IconSurfaceFromRole (role);
|
||||||
|
SyncHelperUpdate (icon->sync_helper);
|
||||||
if (XLFrameClockFrameInProgress (icon->clock))
|
|
||||||
{
|
|
||||||
/* A frame is already in progress; schedule another one for
|
|
||||||
later. */
|
|
||||||
icon->state |= StateLateFrame;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* I guess subsurface updates don't count as urgent frames? */
|
|
||||||
XLFrameClockStartFrame (icon->clock, False);
|
|
||||||
SubcompositorUpdate (icon->subcompositor);
|
|
||||||
XLFrameClockEndFrame (icon->clock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Window
|
static Window
|
||||||
|
@ -415,6 +420,8 @@ XLGetIconSurface (Surface *surface)
|
||||||
|
|
||||||
/* Create a target associated with the window. */
|
/* Create a target associated with the window. */
|
||||||
role->target = RenderTargetFromWindow (role->window, None);
|
role->target = RenderTargetFromWindow (role->window, None);
|
||||||
|
role->release_helper = MakeBufferReleaseHelper (AllBuffersReleased,
|
||||||
|
role);
|
||||||
|
|
||||||
/* Set the client. */
|
/* Set the client. */
|
||||||
if (surface->resource)
|
if (surface->resource)
|
||||||
|
@ -427,7 +434,11 @@ XLGetIconSurface (Surface *surface)
|
||||||
|
|
||||||
/* Create a subcompositor associated with the window. */
|
/* Create a subcompositor associated with the window. */
|
||||||
role->subcompositor = MakeSubcompositor ();
|
role->subcompositor = MakeSubcompositor ();
|
||||||
role->clock = XLMakeFrameClockForWindow (role->window);
|
role->sync_helper = MakeSyncHelper (role->subcompositor,
|
||||||
|
role->window,
|
||||||
|
role->target,
|
||||||
|
HandleFrameCallback,
|
||||||
|
&role->role);
|
||||||
|
|
||||||
/* Set the subcompositor target and some callbacks. */
|
/* Set the subcompositor target and some callbacks. */
|
||||||
SubcompositorSetTarget (role->subcompositor, &role->target);
|
SubcompositorSetTarget (role->subcompositor, &role->target);
|
||||||
|
@ -445,9 +456,6 @@ XLGetIconSurface (Surface *surface)
|
||||||
If it does, frame synchronization will not work. */
|
If it does, frame synchronization will not work. */
|
||||||
WriteRedirectProperty (role);
|
WriteRedirectProperty (role);
|
||||||
|
|
||||||
/* Initialize frame callbacks. */
|
|
||||||
XLFrameClockAfterFrame (role->clock, AfterFrame, role);
|
|
||||||
|
|
||||||
if (!XLSurfaceAttachRole (surface, &role->role))
|
if (!XLSurfaceAttachRole (surface, &role->role))
|
||||||
abort ();
|
abort ();
|
||||||
|
|
||||||
|
@ -469,7 +477,7 @@ XLHandleOneXEventForIconSurfaces (XEvent *event)
|
||||||
|
|
||||||
if (icon)
|
if (icon)
|
||||||
{
|
{
|
||||||
XLFrameClockHandleFrameEvent (icon->clock, event);
|
SyncHelperHandleFrameEvent (icon->sync_helper, event);
|
||||||
return True;
|
return True;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -220,6 +220,9 @@ enum
|
||||||
|
|
||||||
struct _PictureTarget
|
struct _PictureTarget
|
||||||
{
|
{
|
||||||
|
/* The next frame number. */
|
||||||
|
uint64_t next_msc;
|
||||||
|
|
||||||
/* The XID of the picture. */
|
/* The XID of the picture. */
|
||||||
Picture picture;
|
Picture picture;
|
||||||
|
|
||||||
|
@ -265,6 +268,9 @@ struct _PictureTarget
|
||||||
|
|
||||||
/* List of buffers that were used in the course of an update. */
|
/* List of buffers that were used in the course of an update. */
|
||||||
XLList *buffers_used;
|
XLList *buffers_used;
|
||||||
|
|
||||||
|
/* What rendering mode should be used. */
|
||||||
|
RenderMode render_mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _DrmFormatInfo
|
struct _DrmFormatInfo
|
||||||
|
@ -451,9 +457,6 @@ static BufferActivityRecord all_activity;
|
||||||
/* List of all presentations that have not yet been completed. */
|
/* List of all presentations that have not yet been completed. */
|
||||||
static PresentCompletionCallback all_completion_callbacks;
|
static PresentCompletionCallback all_completion_callbacks;
|
||||||
|
|
||||||
/* Whether or not direct presentation should be used. */
|
|
||||||
static Bool use_direct_presentation;
|
|
||||||
|
|
||||||
/* The device nodes of each provider. */
|
/* The device nodes of each provider. */
|
||||||
static dev_t *render_devices;
|
static dev_t *render_devices;
|
||||||
|
|
||||||
|
@ -839,10 +842,18 @@ SwapBackBuffers (PictureTarget *target, pixman_region32_t *damage)
|
||||||
if (!present_serial)
|
if (!present_serial)
|
||||||
present_serial++;
|
present_serial++;
|
||||||
|
|
||||||
|
if (target->render_mode == RenderModeAsync)
|
||||||
XPresentPixmap (compositor.display, target->window,
|
XPresentPixmap (compositor.display, target->window,
|
||||||
back_buffer->pixmap, present_serial,
|
back_buffer->pixmap, present_serial,
|
||||||
None, region, 0, 0, None, None, fence,
|
None, region, 0, 0, None, None, fence,
|
||||||
PresentOptionAsync, 0, 0, 0, NULL, 0);
|
PresentOptionAsync, 0, 0, 0, NULL, 0);
|
||||||
|
else
|
||||||
|
/* Present the pixmap synchronously at the next frame. */
|
||||||
|
XPresentPixmap (compositor.display, target->window,
|
||||||
|
back_buffer->pixmap, present_serial,
|
||||||
|
None, region, 0, 0, None, None, fence,
|
||||||
|
PresentOptionNone, target->next_msc,
|
||||||
|
1, 0, NULL, 0);
|
||||||
|
|
||||||
/* Mark the back buffer as busy, and the other back buffer as having
|
/* Mark the back buffer as busy, and the other back buffer as having
|
||||||
been released. */
|
been released. */
|
||||||
|
@ -1024,42 +1035,6 @@ PickVisual (int *depth)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
InitSynchronizedPresentation (void)
|
|
||||||
{
|
|
||||||
XrmDatabase rdb;
|
|
||||||
XrmName namelist[3];
|
|
||||||
XrmClass classlist[3];
|
|
||||||
XrmValue value;
|
|
||||||
XrmRepresentation type;
|
|
||||||
|
|
||||||
rdb = XrmGetDatabase (compositor.display);
|
|
||||||
|
|
||||||
if (!rdb)
|
|
||||||
return;
|
|
||||||
|
|
||||||
namelist[1] = XrmStringToQuark ("useDirectPresentation");
|
|
||||||
namelist[0] = app_quark;
|
|
||||||
namelist[2] = NULLQUARK;
|
|
||||||
|
|
||||||
classlist[1] = XrmStringToQuark ("UseDirectPresentation");
|
|
||||||
classlist[0] = resource_quark;
|
|
||||||
classlist[2] = NULLQUARK;
|
|
||||||
|
|
||||||
/* Enable the use of direct presentation if
|
|
||||||
*.UseDirectPresentation.*.useDirectPresentation is true. This is
|
|
||||||
still incomplete, as the features necessary for it to play nice
|
|
||||||
with frame synchronization have not yet been implemented in the X
|
|
||||||
server. */
|
|
||||||
|
|
||||||
if (XrmQGetResource (rdb, namelist, classlist,
|
|
||||||
&type, &value)
|
|
||||||
&& type == QString
|
|
||||||
&& (!strcmp (value.addr, "True")
|
|
||||||
|| !strcmp (value.addr, "true")))
|
|
||||||
use_direct_presentation = True;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
AddAdditionalModifier (const char *name)
|
AddAdditionalModifier (const char *name)
|
||||||
{
|
{
|
||||||
|
@ -1154,12 +1129,6 @@ InitAdditionalModifiers (void)
|
||||||
classlist[0] = resource_quark;
|
classlist[0] = resource_quark;
|
||||||
classlist[2] = NULLQUARK;
|
classlist[2] = NULLQUARK;
|
||||||
|
|
||||||
/* Enable the use of direct presentation if
|
|
||||||
*.UseDirectPresentation.*.useDirectPresentation is true. This is
|
|
||||||
still incomplete, as the features necessary for it to play nice
|
|
||||||
with frame synchronization have not yet been implemented in the X
|
|
||||||
server. */
|
|
||||||
|
|
||||||
if (XrmQGetResource (rdb, namelist, classlist,
|
if (XrmQGetResource (rdb, namelist, classlist,
|
||||||
&type, &value)
|
&type, &value)
|
||||||
&& type == QString)
|
&& type == QString)
|
||||||
|
@ -1190,14 +1159,10 @@ InitRenderFuncs (void)
|
||||||
return False;
|
return False;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Figure out whether or not the user wants synchronized
|
|
||||||
presentation. */
|
|
||||||
InitSynchronizedPresentation ();
|
|
||||||
|
|
||||||
/* Find out what additional modifiers the user wants. */
|
/* Find out what additional modifiers the user wants. */
|
||||||
InitAdditionalModifiers ();
|
InitAdditionalModifiers ();
|
||||||
|
|
||||||
if (use_direct_presentation)
|
/* Add the direct presentation support flag. */
|
||||||
AddRenderFlag (SupportsDirectPresent);
|
AddRenderFlag (SupportsDirectPresent);
|
||||||
|
|
||||||
/* Create an unmapped, InputOnly window, that is used to receive
|
/* Create an unmapped, InputOnly window, that is used to receive
|
||||||
|
@ -1276,16 +1241,32 @@ TargetFromDrawable (Drawable drawable, Window window,
|
||||||
return (RenderTarget) (void *) target;
|
return (RenderTarget) (void *) target;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static RenderTarget
|
||||||
|
TargetFromWindow (Window window, unsigned long event_mask)
|
||||||
|
{
|
||||||
|
return TargetFromDrawable (window, window, event_mask);
|
||||||
|
}
|
||||||
|
|
||||||
static RenderTarget
|
static RenderTarget
|
||||||
TargetFromPixmap (Pixmap pixmap)
|
TargetFromPixmap (Pixmap pixmap)
|
||||||
{
|
{
|
||||||
return TargetFromDrawable (pixmap, None, NoEventMask);
|
return TargetFromDrawable (pixmap, None, NoEventMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
static RenderTarget
|
static Bool
|
||||||
TargetFromWindow (Window window, unsigned long event_mask)
|
SetRenderMode (RenderTarget target, RenderMode mode,
|
||||||
|
uint64_t target_msc)
|
||||||
{
|
{
|
||||||
return TargetFromDrawable (window, window, event_mask);
|
PictureTarget *pict_target;
|
||||||
|
|
||||||
|
pict_target = target.pointer;
|
||||||
|
|
||||||
|
/* Set the rendering mode to use with target. */
|
||||||
|
pict_target->render_mode = mode;
|
||||||
|
|
||||||
|
/* And set the target msc. */
|
||||||
|
pict_target->next_msc = target_msc;
|
||||||
|
return True;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1941,21 +1922,16 @@ PresentToWindow (RenderTarget target, RenderBuffer source,
|
||||||
else
|
else
|
||||||
region = None;
|
region = None;
|
||||||
|
|
||||||
if (use_direct_presentation)
|
if (pict_target->render_mode == RenderModeAsync)
|
||||||
{
|
/* Present the pixmap asynchronously at an msc of 0. */
|
||||||
/* Present the pixmap now from the damage; it will complete upon
|
|
||||||
the next vblank if direct presentation is enabled, or
|
|
||||||
immediately if it is not. */
|
|
||||||
XPresentPixmap (compositor.display, pict_target->window, buffer->pixmap,
|
|
||||||
++present_serial, None, region, 0, 0, None, None, None,
|
|
||||||
PresentOptionNone, 0, 1, 0, NULL, 0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
/* Direct presentation is off; present the pixmap asynchronously
|
|
||||||
at an msc of 0. */
|
|
||||||
XPresentPixmap (compositor.display, pict_target->window, buffer->pixmap,
|
XPresentPixmap (compositor.display, pict_target->window, buffer->pixmap,
|
||||||
++present_serial, None, region, 0, 0, None, None, None,
|
++present_serial, None, region, 0, 0, None, None, None,
|
||||||
PresentOptionAsync, 0, 0, 0, NULL, 0);
|
PresentOptionAsync, 0, 0, 0, NULL, 0);
|
||||||
|
else
|
||||||
|
/* Present the pixmap at the next msc. */
|
||||||
|
XPresentPixmap (compositor.display, pict_target->window, buffer->pixmap,
|
||||||
|
++present_serial, None, region, 0, 0, None, None, None,
|
||||||
|
PresentOptionNone, pict_target->next_msc, 1, 0, NULL, 0);
|
||||||
|
|
||||||
if (region)
|
if (region)
|
||||||
XFixesDestroyRegion (compositor.display, region);
|
XFixesDestroyRegion (compositor.display, region);
|
||||||
|
@ -1987,6 +1963,30 @@ PresentToWindow (RenderTarget target, RenderBuffer source,
|
||||||
return callback_rec;
|
return callback_rec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static RenderCompletionKey
|
||||||
|
NotifyMsc (RenderTarget target, RenderCompletionFunc callback,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
PictureTarget *pict_target;
|
||||||
|
PresentCompletionCallback *callback_rec;
|
||||||
|
|
||||||
|
pict_target = target.pointer;
|
||||||
|
|
||||||
|
if (pict_target->render_mode != RenderModeVsync)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Allocate a presentation completion callback. */
|
||||||
|
callback_rec = MakePresentationCallback ();
|
||||||
|
callback_rec->function = callback;
|
||||||
|
callback_rec->data = data;
|
||||||
|
callback_rec->id = ++present_serial;
|
||||||
|
|
||||||
|
/* Ask for a notification. */
|
||||||
|
XPresentNotifyMSC (compositor.display, pict_target->window,
|
||||||
|
present_serial, 0, 1, 0);
|
||||||
|
return callback_rec;
|
||||||
|
}
|
||||||
|
|
||||||
/* Cancel the given presentation callback. */
|
/* Cancel the given presentation callback. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -2006,6 +2006,7 @@ static RenderFuncs picture_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_render_mode = SetRenderMode,
|
||||||
.set_client = SetClient,
|
.set_client = SetClient,
|
||||||
.set_standard_event_mask = SetStandardEventMask,
|
.set_standard_event_mask = SetStandardEventMask,
|
||||||
.note_target_size = NoteTargetSize,
|
.note_target_size = NoteTargetSize,
|
||||||
|
@ -2023,6 +2024,7 @@ static RenderFuncs picture_render_funcs =
|
||||||
.delete_fence = DeleteFence,
|
.delete_fence = DeleteFence,
|
||||||
.get_finish_fence = GetFinishFence,
|
.get_finish_fence = GetFinishFence,
|
||||||
.present_to_window = PresentToWindow,
|
.present_to_window = PresentToWindow,
|
||||||
|
.notify_msc = NotifyMsc,
|
||||||
.cancel_presentation_callback = CancelPresentationCallback,
|
.cancel_presentation_callback = CancelPresentationCallback,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3379,7 +3381,7 @@ HandlePresentCompleteNotify (XPresentCompleteNotifyEvent *complete)
|
||||||
{
|
{
|
||||||
/* The presentation is complete. Run and unlink the
|
/* The presentation is complete. Run and unlink the
|
||||||
callback. */
|
callback. */
|
||||||
last->function (last->data);
|
last->function (last->data, complete->msc, complete->ust);
|
||||||
last->next->last = last->last;
|
last->next->last = last->last;
|
||||||
last->last->next = last->next;
|
last->last->next = last->next;
|
||||||
|
|
||||||
|
|
20
renderer.c
20
renderer.c
|
@ -80,6 +80,16 @@ RenderTargetFromPixmap (Pixmap pixmap)
|
||||||
return render_funcs.target_from_pixmap (pixmap);
|
return render_funcs.target_from_pixmap (pixmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Bool
|
||||||
|
RenderSetRenderMode (RenderTarget target, RenderMode mode,
|
||||||
|
uint64_t target_msc)
|
||||||
|
{
|
||||||
|
if (!render_funcs.set_render_mode)
|
||||||
|
return False;
|
||||||
|
|
||||||
|
return render_funcs.set_render_mode (target, mode, target_msc);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
RenderSetClient (RenderTarget target, struct wl_client *client)
|
RenderSetClient (RenderTarget target, struct wl_client *client)
|
||||||
{
|
{
|
||||||
|
@ -215,6 +225,16 @@ RenderPresentToWindow (RenderTarget target, RenderBuffer source,
|
||||||
data);
|
data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RenderCompletionKey
|
||||||
|
RenderNotifyMsc (RenderTarget target, RenderCompletionFunc callback,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
if (!render_funcs.notify_msc)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return render_funcs.notify_msc (target, callback, data);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
RenderCancelPresentationCallback (PresentCompletionKey key)
|
RenderCancelPresentationCallback (PresentCompletionKey key)
|
||||||
{
|
{
|
||||||
|
|
|
@ -329,8 +329,10 @@ 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. */
|
/* Function called with the frame counter on each update. Counter 3
|
||||||
void (*note_frame) (FrameMode, uint64_t, void *);
|
is the msc and counter 4 is the ust. */
|
||||||
|
void (*note_frame) (FrameMode, uint64_t, void *, uint64_t,
|
||||||
|
uint64_t);
|
||||||
|
|
||||||
/* The current frame counter, incremented with each frame. */
|
/* The current frame counter, incremented with each frame. */
|
||||||
uint64_t frame_counter;
|
uint64_t frame_counter;
|
||||||
|
@ -2105,7 +2107,8 @@ SubcompositorSetBoundsCallback (Subcompositor *subcompositor,
|
||||||
void
|
void
|
||||||
SubcompositorSetNoteFrameCallback (Subcompositor *subcompositor,
|
SubcompositorSetNoteFrameCallback (Subcompositor *subcompositor,
|
||||||
void (*note_frame) (FrameMode, uint64_t,
|
void (*note_frame) (FrameMode, uint64_t,
|
||||||
void *),
|
void *, uint64_t,
|
||||||
|
uint64_t),
|
||||||
void *data)
|
void *data)
|
||||||
{
|
{
|
||||||
subcompositor->note_frame = note_frame;
|
subcompositor->note_frame = note_frame;
|
||||||
|
@ -2176,7 +2179,7 @@ StorePreviousDamage (Subcompositor *subcompositor,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
PresentCompletedCallback (void *data)
|
PresentCompletedCallback (void *data, uint64_t msc, uint64_t ust)
|
||||||
{
|
{
|
||||||
Subcompositor *subcompositor;
|
Subcompositor *subcompositor;
|
||||||
|
|
||||||
|
@ -2190,11 +2193,12 @@ PresentCompletedCallback (void *data)
|
||||||
if (subcompositor->note_frame)
|
if (subcompositor->note_frame)
|
||||||
subcompositor->note_frame (ModePresented,
|
subcompositor->note_frame (ModePresented,
|
||||||
subcompositor->frame_counter,
|
subcompositor->frame_counter,
|
||||||
subcompositor->note_frame_data);
|
subcompositor->note_frame_data,
|
||||||
|
msc, ust);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
RenderCompletedCallback (void *data)
|
RenderCompletedCallback (void *data, uint64_t msc, uint64_t ust)
|
||||||
{
|
{
|
||||||
Subcompositor *subcompositor;
|
Subcompositor *subcompositor;
|
||||||
|
|
||||||
|
@ -2206,9 +2210,10 @@ RenderCompletedCallback (void *data)
|
||||||
|
|
||||||
/* Call the frame function if it s still set. */
|
/* Call the frame function if it s still set. */
|
||||||
if (subcompositor->note_frame)
|
if (subcompositor->note_frame)
|
||||||
subcompositor->note_frame (ModeComplete,
|
subcompositor->note_frame (ModePresented,
|
||||||
subcompositor->frame_counter,
|
subcompositor->frame_counter,
|
||||||
subcompositor->note_frame_data);
|
subcompositor->note_frame_data,
|
||||||
|
msc, ust);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update ancillary data upon commit. This includes the input and
|
/* Update ancillary data upon commit. This includes the input and
|
||||||
|
@ -2974,12 +2979,7 @@ static void
|
||||||
BeginFrame (Subcompositor *subcompositor)
|
BeginFrame (Subcompositor *subcompositor)
|
||||||
{
|
{
|
||||||
if (!subcompositor->note_frame)
|
if (!subcompositor->note_frame)
|
||||||
return;
|
{
|
||||||
|
|
||||||
subcompositor->note_frame (ModeStarted,
|
|
||||||
++subcompositor->frame_counter,
|
|
||||||
subcompositor->note_frame_data);
|
|
||||||
|
|
||||||
/* Cancel any presentation callback that is currently in
|
/* Cancel any presentation callback that is currently in
|
||||||
progress. */
|
progress. */
|
||||||
if (subcompositor->present_key)
|
if (subcompositor->present_key)
|
||||||
|
@ -2990,6 +2990,14 @@ BeginFrame (Subcompositor *subcompositor)
|
||||||
if (subcompositor->render_key)
|
if (subcompositor->render_key)
|
||||||
RenderCancelCompletionCallback (subcompositor->render_key);
|
RenderCancelCompletionCallback (subcompositor->render_key);
|
||||||
subcompositor->render_key = NULL;
|
subcompositor->render_key = NULL;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
subcompositor->note_frame (ModeStarted,
|
||||||
|
++subcompositor->frame_counter,
|
||||||
|
subcompositor->note_frame_data,
|
||||||
|
-1, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -2999,12 +3007,22 @@ EndFrame (Subcompositor *subcompositor)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Make sure that we wait for the presentation callback or render
|
/* Make sure that we wait for the presentation callback or render
|
||||||
callback if they are attached. */
|
callback if they are attached. If not, ask for a
|
||||||
|
notification. */
|
||||||
|
|
||||||
if (!subcompositor->present_key && !subcompositor->render_key)
|
if (!subcompositor->present_key && !subcompositor->render_key)
|
||||||
|
{
|
||||||
|
subcompositor->render_key
|
||||||
|
= RenderNotifyMsc (subcompositor->target,
|
||||||
|
RenderCompletedCallback,
|
||||||
|
subcompositor);
|
||||||
|
|
||||||
|
if (!subcompositor->render_key)
|
||||||
subcompositor->note_frame (ModeComplete,
|
subcompositor->note_frame (ModeComplete,
|
||||||
subcompositor->frame_counter,
|
subcompositor->frame_counter,
|
||||||
subcompositor->note_frame_data);
|
subcompositor->note_frame_data,
|
||||||
|
-1, -1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
3
test.c
3
test.c
|
@ -165,7 +165,8 @@ NoteBounds (void *data, int min_x, int min_y, int max_x, int max_y)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
NoteFrame (FrameMode mode, uint64_t id, void *data)
|
NoteFrame (FrameMode mode, uint64_t id, void *data,
|
||||||
|
uint64_t msc, uint64_t ust)
|
||||||
{
|
{
|
||||||
if (mode != ModeComplete && mode != ModePresented)
|
if (mode != ModeComplete && mode != ModePresented)
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -442,7 +442,6 @@ static void
|
||||||
InternalReposition (XdgPopup *popup)
|
InternalReposition (XdgPopup *popup)
|
||||||
{
|
{
|
||||||
int x, y, width, height;
|
int x, y, width, height;
|
||||||
FrameClock *clock;
|
|
||||||
|
|
||||||
/* No parent was specified or the role is detached. */
|
/* No parent was specified or the role is detached. */
|
||||||
if (!popup->role || !popup->parent)
|
if (!popup->role || !popup->parent)
|
||||||
|
@ -458,11 +457,6 @@ InternalReposition (XdgPopup *popup)
|
||||||
SendConfigure (popup, popup->pending_x, popup->pending_y,
|
SendConfigure (popup, popup->pending_x, popup->pending_y,
|
||||||
width, height);
|
width, height);
|
||||||
|
|
||||||
/* Now, freeze the frame clock, to avoid flicker when the client
|
|
||||||
commits before ack_configure. */
|
|
||||||
clock = XLXdgRoleGetFrameClock (popup->role);
|
|
||||||
XLFrameClockFreeze (clock);
|
|
||||||
|
|
||||||
popup->state |= StateAckPosition;
|
popup->state |= StateAckPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
463
xdg_surface.c
463
xdg_surface.c
|
@ -36,17 +36,13 @@ along with 12to11. If not, see <https://www.gnu.org/licenses/>. */
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
StatePendingFrameCallback = 1,
|
StatePendingFrameCallback = 1,
|
||||||
StateLateFrame = (1 << 1),
|
|
||||||
StatePendingWindowGeometry = (1 << 2),
|
StatePendingWindowGeometry = (1 << 2),
|
||||||
StateWaitingForAckConfigure = (1 << 3),
|
StateWaitingForAckConfigure = (1 << 3),
|
||||||
StateWaitingForAckCommit = (1 << 4),
|
StateWaitingForAckCommit = (1 << 4),
|
||||||
StateLateFrameAcked = (1 << 5),
|
StateMaybeConfigure = (1 << 5),
|
||||||
StateMaybeConfigure = (1 << 6),
|
StateDirtyFrameExtents = (1 << 6),
|
||||||
StateDirtyFrameExtents = (1 << 7),
|
StateTemporaryBounds = (1 << 7),
|
||||||
StateTemporaryBounds = (1 << 8),
|
StatePendingBufferRelease = (1 << 8),
|
||||||
StateFrameStarted = (1 << 9),
|
|
||||||
StateAllowUnredirection = (1 << 10),
|
|
||||||
StatePendingBufferRelease = (1 << 11),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct _XdgRole XdgRole;
|
typedef struct _XdgRole XdgRole;
|
||||||
|
@ -128,8 +124,8 @@ struct _XdgRole
|
||||||
/* Buffer release helper. */
|
/* Buffer release helper. */
|
||||||
BufferReleaseHelper *release_helper;
|
BufferReleaseHelper *release_helper;
|
||||||
|
|
||||||
/* The frame clock. */
|
/* The synchronization helper. */
|
||||||
FrameClock *clock;
|
SyncHelper *sync_helper;
|
||||||
|
|
||||||
/* The pending xdg_surface state. */
|
/* The pending xdg_surface state. */
|
||||||
XdgState pending_state;
|
XdgState pending_state;
|
||||||
|
@ -156,6 +152,9 @@ struct _XdgRole
|
||||||
events to wait for before ignoring those coordinates. */
|
events to wait for before ignoring those coordinates. */
|
||||||
int pending_synth_configure;
|
int pending_synth_configure;
|
||||||
|
|
||||||
|
/* The pending frame time. */
|
||||||
|
uint32_t pending_frame_time;
|
||||||
|
|
||||||
/* The input region of the attached subsurface. */
|
/* The input region of the attached subsurface. */
|
||||||
pixman_region32_t input_region;
|
pixman_region32_t input_region;
|
||||||
|
|
||||||
|
@ -244,63 +243,29 @@ FreeReconstrainCallbacks (XdgRole *role)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
RunFrameCallbacks (Surface *surface, XdgRole *role)
|
RunFrameCallbacks (Surface *surface, XdgRole *role, uint32_t frame_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);
|
XLSurfaceRunFrameCallbacksMs (surface, frame_time);
|
||||||
|
|
||||||
if (!last_drawn_time)
|
|
||||||
{
|
|
||||||
clock_gettime (CLOCK_MONOTONIC, &time);
|
|
||||||
XLSurfaceRunFrameCallbacks (surface, time);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
XLSurfaceRunFrameCallbacksMs (surface, last_drawn_time / 1000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
RunFrameCallbacksConditionally (XdgRole *role)
|
RunFrameCallbacksConditionally (XdgRole *role, uint32_t frame_time)
|
||||||
{
|
{
|
||||||
if (!(role->state & StatePendingBufferRelease))
|
if (!(role->state & StatePendingBufferRelease))
|
||||||
RunFrameCallbacks (role->role.surface, role);
|
RunFrameCallbacks (role->role.surface, role, frame_time);
|
||||||
else if (role->role.surface)
|
else if (role->role.surface)
|
||||||
|
{
|
||||||
/* weston-simple-shm seems to assume that a frame callback can
|
/* weston-simple-shm seems to assume that a frame callback can
|
||||||
only arrive after all buffers have been released. */
|
only arrive after all buffers have been released. */
|
||||||
role->state |= StatePendingFrameCallback;
|
role->state |= StatePendingFrameCallback;
|
||||||
|
role->pending_frame_time = frame_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Bool
|
|
||||||
UpdateFrameRefreshPrediction (XdgRole *role)
|
|
||||||
{
|
|
||||||
int desync_children;
|
|
||||||
|
|
||||||
/* Count the number of desynchronous children attached to this
|
|
||||||
surface, directly or indirectly. When this number is more than
|
|
||||||
1, enable frame refresh prediction, which allows separate frames
|
|
||||||
from subsurfaces to be batched together. */
|
|
||||||
|
|
||||||
if (role->role.surface)
|
|
||||||
{
|
|
||||||
desync_children = 0;
|
|
||||||
XLUpdateDesynchronousChildren (role->role.surface,
|
|
||||||
&desync_children);
|
|
||||||
|
|
||||||
if (desync_children)
|
|
||||||
XLFrameClockSetPredictRefresh (role->clock);
|
|
||||||
else
|
|
||||||
XLFrameClockDisablePredictRefresh (role->clock);
|
|
||||||
|
|
||||||
return desync_children > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return False;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -319,7 +284,8 @@ AllBuffersReleased (void *data)
|
||||||
released. */
|
released. */
|
||||||
if (surface && role->state & StatePendingFrameCallback)
|
if (surface && role->state & StatePendingFrameCallback)
|
||||||
{
|
{
|
||||||
RunFrameCallbacks (surface, role);
|
RunFrameCallbacks (surface, role,
|
||||||
|
role->pending_frame_time);
|
||||||
|
|
||||||
role->state &= ~StatePendingFrameCallback;
|
role->state &= ~StatePendingFrameCallback;
|
||||||
}
|
}
|
||||||
|
@ -341,7 +307,7 @@ XLHandleXEventForXdgSurfaces (XEvent *event)
|
||||||
|
|
||||||
if (role)
|
if (role)
|
||||||
{
|
{
|
||||||
XLFrameClockHandleFrameEvent (role->clock, event);
|
SyncHelperHandleFrameEvent (role->sync_helper, event);
|
||||||
return True;
|
return True;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -354,10 +320,6 @@ XLHandleXEventForXdgSurfaces (XEvent *event)
|
||||||
|
|
||||||
if (role)
|
if (role)
|
||||||
{
|
{
|
||||||
/* If resizing is in progress with WM synchronization, don't
|
|
||||||
handle exposure events, since that causes updates outside
|
|
||||||
a frame. */
|
|
||||||
if (!XLFrameClockNeedConfigure (role->clock))
|
|
||||||
SubcompositorExpose (role->subcompositor, event);
|
SubcompositorExpose (role->subcompositor, event);
|
||||||
|
|
||||||
return True;
|
return True;
|
||||||
|
@ -535,11 +497,6 @@ AckConfigure (struct wl_client *client, struct wl_resource *resource,
|
||||||
exposed due to changes in bounds. */
|
exposed due to changes in bounds. */
|
||||||
SubcompositorGarbage (xdg_role->subcompositor);
|
SubcompositorGarbage (xdg_role->subcompositor);
|
||||||
|
|
||||||
/* Also run frame callbacks if the frame clock is frozen. */
|
|
||||||
if (XLFrameClockIsFrozen (xdg_role->clock)
|
|
||||||
&& xdg_role->role.surface)
|
|
||||||
RunFrameCallbacksConditionally (xdg_role);
|
|
||||||
|
|
||||||
#ifdef DEBUG_GEOMETRY_CALCULATION
|
#ifdef DEBUG_GEOMETRY_CALCULATION
|
||||||
fprintf (stderr, "Client acknowledged configuration\n");
|
fprintf (stderr, "Client acknowledged configuration\n");
|
||||||
#endif
|
#endif
|
||||||
|
@ -560,51 +517,6 @@ static const struct xdg_surface_interface xdg_surface_impl =
|
||||||
.ack_configure = AckConfigure,
|
.ack_configure = AckConfigure,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
|
||||||
Unfreeze (XdgRole *role)
|
|
||||||
{
|
|
||||||
XLFrameClockUnfreeze (role->clock);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Bool
|
|
||||||
IsRoleMapped (XdgRole *role)
|
|
||||||
{
|
|
||||||
if (!role->impl)
|
|
||||||
/* This can happen when destroying subsurfaces as part of client
|
|
||||||
cleanup. */
|
|
||||||
return False;
|
|
||||||
|
|
||||||
return role->impl->funcs.is_window_mapped (&role->role,
|
|
||||||
role->impl);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check if a frame can be drawn. Return True if it is okay to call
|
|
||||||
SubcompositorUpdate, or schedule a frame after the current frame is
|
|
||||||
drawn and return False. */
|
|
||||||
|
|
||||||
static Bool
|
|
||||||
CheckFrame (XdgRole *role)
|
|
||||||
{
|
|
||||||
if (XLFrameClockFrameInProgress (role->clock))
|
|
||||||
{
|
|
||||||
if (XLFrameClockCanBatch (role->clock))
|
|
||||||
/* But if we can squeeze the frame inside the vertical
|
|
||||||
blanking period, or a frame is in progress but EndFrame has
|
|
||||||
not yet been called, go ahead. */
|
|
||||||
return True;
|
|
||||||
|
|
||||||
role->state |= StateLateFrame;
|
|
||||||
role->state &= ~StatePendingFrameCallback;
|
|
||||||
|
|
||||||
if (role->state & StateWaitingForAckConfigure)
|
|
||||||
role->state &= ~StateLateFrameAcked;
|
|
||||||
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
Commit (Surface *surface, Role *role)
|
Commit (Surface *surface, Role *role)
|
||||||
{
|
{
|
||||||
|
@ -627,11 +539,13 @@ Commit (Surface *surface, Role *role)
|
||||||
= xdg_role->pending_state.window_geometry_height;
|
= xdg_role->pending_state.window_geometry_height;
|
||||||
|
|
||||||
#ifdef DEBUG_GEOMETRY_CALCULATION
|
#ifdef DEBUG_GEOMETRY_CALCULATION
|
||||||
fprintf (stderr, "Client set window geometry to: [%d %d %d %d]\n",
|
fprintf (stderr, "Client set window geometry to: [%d %d %d %d]\n"
|
||||||
|
"State is: %d\n",
|
||||||
xdg_role->current_state.window_geometry_x,
|
xdg_role->current_state.window_geometry_x,
|
||||||
xdg_role->current_state.window_geometry_y,
|
xdg_role->current_state.window_geometry_y,
|
||||||
xdg_role->current_state.window_geometry_width,
|
xdg_role->current_state.window_geometry_width,
|
||||||
xdg_role->current_state.window_geometry_height);
|
xdg_role->current_state.window_geometry_height,
|
||||||
|
xdg_role->state & StateWaitingForAckConfigure);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Now, clear the "pending window geometry" flag. */
|
/* Now, clear the "pending window geometry" flag. */
|
||||||
|
@ -657,35 +571,40 @@ Commit (Surface *surface, Role *role)
|
||||||
xdg_role->state &= ~StateWaitingForAckCommit;
|
xdg_role->state &= ~StateWaitingForAckCommit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the frame clock is frozen but we are no longer waiting for the
|
if (!(xdg_role->state & StateWaitingForAckCommit))
|
||||||
configure event to be acknowledged by the client, unfreeze the
|
{
|
||||||
frame clock. */
|
/* Tell the sync helper to update the frame. This will also
|
||||||
if (!(xdg_role->state & StateWaitingForAckConfigure))
|
complete any resize if necessary. */
|
||||||
Unfreeze (xdg_role);
|
SyncHelperUpdate (xdg_role->sync_helper);
|
||||||
|
|
||||||
/* Now, check if a frame can be drawn, or schedule a frame to be
|
/* Run the after_commit function of the role implementation,
|
||||||
drawn after this one completes. */
|
which peforms actions such as posting pending configure
|
||||||
|
events for built-in resize. */
|
||||||
if (!CheckFrame (xdg_role))
|
|
||||||
/* The frame cannot be drawn, because the compositor has not yet
|
|
||||||
drawn a previous frame. */
|
|
||||||
goto after_commit;
|
|
||||||
|
|
||||||
/* The frame can be drawn, so update the window contents now. */
|
|
||||||
SubcompositorUpdate (xdg_role->subcompositor);
|
|
||||||
|
|
||||||
/* Do not end frames explicitly. Instead, wait for the
|
|
||||||
NoteFrameCallback to end the frame. */
|
|
||||||
|
|
||||||
after_commit:
|
|
||||||
|
|
||||||
/* Run the after_commit function of the role implementation, which
|
|
||||||
peforms actions such as posting pending configure events for
|
|
||||||
built-in resize. */
|
|
||||||
|
|
||||||
if (xdg_role->impl->funcs.after_commit)
|
if (xdg_role->impl->funcs.after_commit)
|
||||||
xdg_role->impl->funcs.after_commit (role, surface,
|
xdg_role->impl->funcs.after_commit (role, surface,
|
||||||
xdg_role->impl);
|
xdg_role->impl);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
/* Now, tell the sync helper to generate a frame.
|
||||||
|
Many clients do this:
|
||||||
|
|
||||||
|
wl_surface@1.frame (new id wl_callback@2)
|
||||||
|
wl_surface@1.commit ()
|
||||||
|
|
||||||
|
and upon receiving a configure event, potentially call:
|
||||||
|
|
||||||
|
xdg_surface@3.ack_configure (1)
|
||||||
|
|
||||||
|
but do not commit (or even ack_configure) until the frame
|
||||||
|
callback is triggered.
|
||||||
|
|
||||||
|
That is problematic because the frame clock is not unfrozen
|
||||||
|
until the commit happens. To work around the problem, tell the
|
||||||
|
sync helper to check for this situation, and run frame
|
||||||
|
callbacks if necessary. */
|
||||||
|
SyncHelperCheckFrameCallback (xdg_role->sync_helper);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -753,13 +672,13 @@ ReleaseBacking (XdgRole *role)
|
||||||
/* And the association. */
|
/* And the association. */
|
||||||
XLDeleteAssoc (surfaces, role->window);
|
XLDeleteAssoc (surfaces, role->window);
|
||||||
|
|
||||||
|
/* Destroy the sync helper. */
|
||||||
|
FreeSyncHelper (role->sync_helper);
|
||||||
|
|
||||||
/* There shouldn't be any children of the subcompositor at this
|
/* There shouldn't be any children of the subcompositor at this
|
||||||
point. */
|
point. */
|
||||||
SubcompositorFree (role->subcompositor);
|
SubcompositorFree (role->subcompositor);
|
||||||
|
|
||||||
/* The frame clock is no longer useful. */
|
|
||||||
XLFreeFrameClock (role->clock);
|
|
||||||
|
|
||||||
/* Free the input region. */
|
/* Free the input region. */
|
||||||
pixman_region32_fini (&role->input_region);
|
pixman_region32_fini (&role->input_region);
|
||||||
|
|
||||||
|
@ -822,19 +741,34 @@ SubsurfaceUpdate (Surface *surface, Role *role)
|
||||||
|
|
||||||
xdg_role = XdgRoleFromRole (role);
|
xdg_role = XdgRoleFromRole (role);
|
||||||
|
|
||||||
/* If the frame clock is frozen, don't update anything. */
|
if (xdg_role->state & StateWaitingForAckCommit)
|
||||||
if (XLFrameClockIsFrozen (xdg_role->clock))
|
{
|
||||||
|
/* Updates are being postponed until the next commit after
|
||||||
|
ack_configure.
|
||||||
|
|
||||||
|
Now, tell the sync helper to generate a frame.
|
||||||
|
Many clients do this:
|
||||||
|
|
||||||
|
wl_surface@1.frame (new id wl_callback@2)
|
||||||
|
wl_surface@1.commit ()
|
||||||
|
|
||||||
|
and upon receiving a configure event, potentially call:
|
||||||
|
|
||||||
|
xdg_surface@3.ack_configure (1)
|
||||||
|
|
||||||
|
but do not commit (or even ack_configure) until the frame
|
||||||
|
callback is triggered.
|
||||||
|
|
||||||
|
That is problematic because the frame clock is not unfrozen
|
||||||
|
until the commit happens. To work around the problem, tell
|
||||||
|
the sync helper to check for this situation, and run frame
|
||||||
|
callbacks if necessary. */
|
||||||
|
SyncHelperCheckFrameCallback (xdg_role->sync_helper);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* If a frame is already in progress, return, but schedule a frame
|
/* Tell the sync helper to do an update. */
|
||||||
to be drawn later. */
|
SyncHelperUpdate (xdg_role->sync_helper);
|
||||||
|
|
||||||
if (!CheckFrame (xdg_role))
|
|
||||||
/* The frame cannot be drawn. */
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* The frame can be drawn, so update the window contents. */
|
|
||||||
SubcompositorUpdate (xdg_role->subcompositor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Window
|
static Window
|
||||||
|
@ -858,48 +792,6 @@ HandleResourceDestroy (struct wl_resource *resource)
|
||||||
ReleaseBacking (role);
|
ReleaseBacking (role);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Bool
|
|
||||||
MaybeRunLateFrame (XdgRole *role)
|
|
||||||
{
|
|
||||||
/* If there is a late frame, run it now. Return whether or not a
|
|
||||||
late frame was run. */
|
|
||||||
|
|
||||||
if (role->state & StateLateFrame)
|
|
||||||
{
|
|
||||||
if (role->state & StateLateFrameAcked)
|
|
||||||
XLFrameClockUnfreeze (role->clock);
|
|
||||||
|
|
||||||
/* Now apply the state in the late frame. */
|
|
||||||
SubcompositorUpdate (role->subcompositor);
|
|
||||||
|
|
||||||
/* Clear the late frame flag. */
|
|
||||||
role->state &= ~StateLateFrame;
|
|
||||||
|
|
||||||
/* Return True, as a new update has started. */
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
AfterFrame (FrameClock *clock, void *data)
|
|
||||||
{
|
|
||||||
XdgRole *role;
|
|
||||||
|
|
||||||
role = data;
|
|
||||||
|
|
||||||
/* Run any late frame. */
|
|
||||||
if (MaybeRunLateFrame (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. */
|
|
||||||
|
|
||||||
RunFrameCallbacksConditionally (role);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
OpaqueRegionChanged (Subcompositor *subcompositor,
|
OpaqueRegionChanged (Subcompositor *subcompositor,
|
||||||
void *client_data,
|
void *client_data,
|
||||||
|
@ -1004,7 +896,7 @@ NoteConfigure (XdgRole *role, XEvent *event)
|
||||||
|
|
||||||
/* Tell the frame clock how many WM-generated configure events have
|
/* Tell the frame clock how many WM-generated configure events have
|
||||||
arrived. */
|
arrived. */
|
||||||
XLFrameClockNoteConfigure (role->clock);
|
SyncHelperNoteConfigureEvent (role->sync_helper);
|
||||||
|
|
||||||
/* Run reconstrain callbacks. */
|
/* Run reconstrain callbacks. */
|
||||||
RunReconstrainCallbacksForXEvent (role, event);
|
RunReconstrainCallbacksForXEvent (role, event);
|
||||||
|
@ -1040,11 +932,6 @@ NoteBounds (void *data, int min_x, int min_y,
|
||||||
run_reconstrain_callbacks = False;
|
run_reconstrain_callbacks = False;
|
||||||
root_position_initialized = False;
|
root_position_initialized = False;
|
||||||
|
|
||||||
if (XLFrameClockIsFrozen (role->clock))
|
|
||||||
/* We are waiting for the acknowledgement of a configure event.
|
|
||||||
Don't resize the window until it's acknowledged. */
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (role->state & StateWaitingForAckCommit)
|
if (role->state & StateWaitingForAckCommit)
|
||||||
/* Don't resize the window until all configure events are
|
/* Don't resize the window until all configure events are
|
||||||
acknowledged. We wait for a commit on the xdg_toplevel to do
|
acknowledged. We wait for a commit on the xdg_toplevel to do
|
||||||
|
@ -1160,11 +1047,6 @@ WriteRedirectProperty (XdgRole *role)
|
||||||
{
|
{
|
||||||
unsigned long bypass_compositor;
|
unsigned long bypass_compositor;
|
||||||
|
|
||||||
if (role->state & StateAllowUnredirection)
|
|
||||||
/* The subcompositor determined that the window should be
|
|
||||||
uncomposited to allow for direct buffer flipping. */
|
|
||||||
bypass_compositor = 0;
|
|
||||||
else
|
|
||||||
bypass_compositor = 2;
|
bypass_compositor = 2;
|
||||||
|
|
||||||
XChangeProperty (compositor.display, role->window,
|
XChangeProperty (compositor.display, role->window,
|
||||||
|
@ -1173,113 +1055,6 @@ WriteRedirectProperty (XdgRole *role)
|
||||||
(unsigned char *) &bypass_compositor, 1);
|
(unsigned char *) &bypass_compositor, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Bool
|
|
||||||
WasFrameQueued (XdgRole *role)
|
|
||||||
{
|
|
||||||
/* Return whether or not the translator slept before displaying this
|
|
||||||
frame in response to a frame drawn event. */
|
|
||||||
|
|
||||||
return (role->state & StateLateFrame) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
NoteFrame (FrameMode mode, uint64_t id, void *data)
|
|
||||||
{
|
|
||||||
XdgRole *role;
|
|
||||||
Bool predict_refresh, urgent;
|
|
||||||
|
|
||||||
role = data;
|
|
||||||
|
|
||||||
switch (mode)
|
|
||||||
{
|
|
||||||
case ModeStarted:
|
|
||||||
/* Record this frame counter as the pending frame. */
|
|
||||||
role->pending_frame = id;
|
|
||||||
|
|
||||||
if (!(role->state & StateFrameStarted))
|
|
||||||
{
|
|
||||||
/* Update whether or not frame refresh prediction is to be
|
|
||||||
used. */
|
|
||||||
predict_refresh = UpdateFrameRefreshPrediction (role);
|
|
||||||
|
|
||||||
/* A rule of thumb is to never let the compositing manager
|
|
||||||
read or try to scan out incomplete buffer contents.
|
|
||||||
Thus, if the client asked for async presentation, Commit
|
|
||||||
will still wait for the compositor to finish drawing the
|
|
||||||
last frame.
|
|
||||||
|
|
||||||
In addition, how subsurfaces fit into all of this is
|
|
||||||
unclear. At present, the presentation hint of
|
|
||||||
subsurfaces is simply discarded, and the hint of the
|
|
||||||
topmost surface used instead. In addition, asynchronous
|
|
||||||
subsurfaces will prevent async presentation from taking
|
|
||||||
place at all. */
|
|
||||||
|
|
||||||
urgent = (WasFrameQueued (role)
|
|
||||||
&& !predict_refresh
|
|
||||||
&& role->role.surface
|
|
||||||
&& (role->role.surface->current_state.presentation_hint
|
|
||||||
== PresentationHintAsync));
|
|
||||||
|
|
||||||
if (XLFrameClockStartFrame (role->clock, urgent))
|
|
||||||
role->state |= StateFrameStarted;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ModeNotifyDisablePresent:
|
|
||||||
/* The subcompositor will draw to the frame directly, so make
|
|
||||||
the compositing manager redirect the frame again. */
|
|
||||||
|
|
||||||
if (role->state & StateAllowUnredirection)
|
|
||||||
{
|
|
||||||
role->state &= ~StateAllowUnredirection;
|
|
||||||
WriteRedirectProperty (role);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ModePresented:
|
|
||||||
case ModeComplete:
|
|
||||||
/* The frame was completed. */
|
|
||||||
if (id == role->pending_frame)
|
|
||||||
{
|
|
||||||
/* End the frame. */
|
|
||||||
XLFrameClockEndFrame (role->clock);
|
|
||||||
|
|
||||||
/* No frame was started clock-side for this frame. That
|
|
||||||
means programs waiting for frame callbacks will not get
|
|
||||||
any, so the frame callbacks must be run by hand. */
|
|
||||||
if (!(role->state & StateFrameStarted)
|
|
||||||
|| !IsRoleMapped (role))
|
|
||||||
{
|
|
||||||
if (MaybeRunLateFrame (role))
|
|
||||||
return;
|
|
||||||
|
|
||||||
RunFrameCallbacksConditionally (role);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Clear the frame completed flag. */
|
|
||||||
role->state &= ~StateFrameStarted;
|
|
||||||
|
|
||||||
if (mode == ModePresented
|
|
||||||
&& renderer_flags & SupportsDirectPresent)
|
|
||||||
{
|
|
||||||
/* Since a presentation was successful, assume future
|
|
||||||
frames will be presented as well. In that case, let
|
|
||||||
the compositing manager unredirect the window, so
|
|
||||||
buffers can be directly flipped to the screen. */
|
|
||||||
|
|
||||||
if (!(role->state & StateAllowUnredirection))
|
|
||||||
{
|
|
||||||
role->state |= StateAllowUnredirection;
|
|
||||||
WriteRedirectProperty (role);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ResizeForMap (XdgRole *role)
|
ResizeForMap (XdgRole *role)
|
||||||
{
|
{
|
||||||
|
@ -1373,21 +1148,52 @@ Rescale (Surface *surface, Role *role)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
HandleFreeze (void *data)
|
HandleResize (void *data, Bool only_frame)
|
||||||
{
|
{
|
||||||
XdgRole *role;
|
XdgRole *role;
|
||||||
|
|
||||||
role = data;
|
role = data;
|
||||||
|
|
||||||
|
if (only_frame)
|
||||||
|
{
|
||||||
|
SyncHelperCheckFrameCallback (role->sync_helper);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* _NET_WM_SYNC_REQUEST events should be succeeded by a
|
/* _NET_WM_SYNC_REQUEST events should be succeeded by a
|
||||||
ConfigureNotify event. */
|
ConfigureNotify event. */
|
||||||
role->state |= StateWaitingForAckConfigure;
|
role->state |= StateWaitingForAckConfigure;
|
||||||
role->state |= StateWaitingForAckCommit;
|
role->state |= StateWaitingForAckCommit;
|
||||||
|
|
||||||
|
/* Cancel any pending frame. Nothing should be displayed while an
|
||||||
|
ack_configure is pending. */
|
||||||
|
SyncHelperClearPendingFrame (role->sync_helper);
|
||||||
|
|
||||||
/* This flag means the WaitingForAckConfigure was caused by a
|
/* This flag means the WaitingForAckConfigure was caused by a
|
||||||
_NET_WM_SYNC_REQUEST, and the following ConfigureNotify event
|
_NET_WM_SYNC_REQUEST, and the following ConfigureNotify event
|
||||||
might not lead to a configure event being sent. */
|
might not lead to a configure event being sent. */
|
||||||
role->state |= StateMaybeConfigure;
|
role->state |= StateMaybeConfigure;
|
||||||
|
|
||||||
|
/* If a freeze comes between commit and configure, then clients will
|
||||||
|
hang indefinitely waiting for _NET_WM_FRAME_DRAWN. Make the sync
|
||||||
|
helper check for this situation. */
|
||||||
|
SyncHelperCheckFrameCallback (role->sync_helper);
|
||||||
|
|
||||||
|
#ifdef DEBUG_GEOMETRY_CALCULATION
|
||||||
|
fprintf (stderr, "Waiting for ack_configure (?)...\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static Bool
|
||||||
|
CheckFastForward (void *data)
|
||||||
|
{
|
||||||
|
XdgRole *role;
|
||||||
|
|
||||||
|
/* Return whether or not it is ok to fast forward the frame
|
||||||
|
counter while ending a frame. */
|
||||||
|
|
||||||
|
role = data;
|
||||||
|
return !(role->state & StateWaitingForAckCommit);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1445,6 +1251,15 @@ Activate (Surface *surface, Role *role, int deviceid,
|
||||||
activator_surface);
|
activator_surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
HandleFrameCallback (void *data, uint32_t frame_time)
|
||||||
|
{
|
||||||
|
XdgRole *role;
|
||||||
|
|
||||||
|
role = data;
|
||||||
|
RunFrameCallbacksConditionally (role, frame_time);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
XLGetXdgSurface (struct wl_client *client, struct wl_resource *resource,
|
XLGetXdgSurface (struct wl_client *client, struct wl_resource *resource,
|
||||||
uint32_t id, struct wl_resource *surface_resource)
|
uint32_t id, struct wl_resource *surface_resource)
|
||||||
|
@ -1538,8 +1353,13 @@ XLGetXdgSurface (struct wl_client *client, struct wl_resource *resource,
|
||||||
RenderSetClient (role->target, client);
|
RenderSetClient (role->target, client);
|
||||||
|
|
||||||
role->subcompositor = MakeSubcompositor ();
|
role->subcompositor = MakeSubcompositor ();
|
||||||
role->clock = XLMakeFrameClockForWindow (role->window);
|
role->sync_helper = MakeSyncHelper (role->subcompositor,
|
||||||
XLFrameClockSetFreezeCallback (role->clock, HandleFreeze, role);
|
role->window,
|
||||||
|
role->target,
|
||||||
|
HandleFrameCallback,
|
||||||
|
&role->role);
|
||||||
|
SyncHelperSetResizeCallback (role->sync_helper, HandleResize,
|
||||||
|
CheckFastForward);
|
||||||
|
|
||||||
SubcompositorSetTarget (role->subcompositor, &role->target);
|
SubcompositorSetTarget (role->subcompositor, &role->target);
|
||||||
SubcompositorSetInputCallback (role->subcompositor,
|
SubcompositorSetInputCallback (role->subcompositor,
|
||||||
|
@ -1548,8 +1368,6 @@ 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);
|
||||||
|
|
||||||
|
@ -1557,9 +1375,6 @@ XLGetXdgSurface (struct wl_client *client, struct wl_resource *resource,
|
||||||
If it does, frame synchronization will not work. */
|
If it does, frame synchronization will not work. */
|
||||||
WriteRedirectProperty (role);
|
WriteRedirectProperty (role);
|
||||||
|
|
||||||
/* Initialize frame callbacks. */
|
|
||||||
XLFrameClockAfterFrame (role->clock, AfterFrame, role);
|
|
||||||
|
|
||||||
if (!XLSurfaceAttachRole (surface, &role->role))
|
if (!XLSurfaceAttachRole (surface, &role->role))
|
||||||
abort ();
|
abort ();
|
||||||
|
|
||||||
|
@ -1626,6 +1441,10 @@ XLXdgRoleSendConfigure (Role *role, uint32_t serial)
|
||||||
xdg_role->state |= StateWaitingForAckConfigure;
|
xdg_role->state |= StateWaitingForAckConfigure;
|
||||||
xdg_role->state |= StateWaitingForAckCommit;
|
xdg_role->state |= StateWaitingForAckCommit;
|
||||||
|
|
||||||
|
/* Cancel any pending frame. Nothing should be displayed while an
|
||||||
|
ack_configure is pending. */
|
||||||
|
SyncHelperClearPendingFrame (xdg_role->sync_helper);
|
||||||
|
|
||||||
/* See the comment under XLXdgRoleSetBoundsSize. */
|
/* See the comment under XLXdgRoleSetBoundsSize. */
|
||||||
xdg_role->state &= ~StateTemporaryBounds;
|
xdg_role->state &= ~StateTemporaryBounds;
|
||||||
|
|
||||||
|
@ -1912,7 +1731,7 @@ XLXdgRoleReconstrain (Role *role, XEvent *event)
|
||||||
|
|
||||||
/* If event is a configure event, tell the frame clock about it. */
|
/* If event is a configure event, tell the frame clock about it. */
|
||||||
if (event->type == ConfigureNotify)
|
if (event->type == ConfigureNotify)
|
||||||
XLFrameClockNoteConfigure (xdg_role->clock);
|
SyncHelperNoteConfigureEvent (xdg_role->sync_helper);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -1938,15 +1757,6 @@ XLXdgRoleMoveBy (Role *role, int west, int north)
|
||||||
xdg_role->pending_synth_configure++;
|
xdg_role->pending_synth_configure++;
|
||||||
}
|
}
|
||||||
|
|
||||||
FrameClock *
|
|
||||||
XLXdgRoleGetFrameClock (Role *role)
|
|
||||||
{
|
|
||||||
XdgRole *xdg_role;
|
|
||||||
|
|
||||||
xdg_role = XdgRoleFromRole (role);
|
|
||||||
return xdg_role->clock;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
XLInitXdgSurfaces (void)
|
XLInitXdgSurfaces (void)
|
||||||
{
|
{
|
||||||
|
@ -2043,9 +1853,6 @@ XLXdgRoleNoteRejectedConfigure (Role *role)
|
||||||
xdg_role->state &= ~StateWaitingForAckConfigure;
|
xdg_role->state &= ~StateWaitingForAckConfigure;
|
||||||
xdg_role->state &= ~StateWaitingForAckCommit;
|
xdg_role->state &= ~StateWaitingForAckCommit;
|
||||||
xdg_role->state &= ~StateMaybeConfigure;
|
xdg_role->state &= ~StateMaybeConfigure;
|
||||||
|
|
||||||
/* Unfreeze the frame clock now. */
|
|
||||||
XLFrameClockUnfreeze (xdg_role->clock);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue