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
|
||||
(the OpenGL ES 2.0 based compositor).
|
||||
.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)
|
||||
Comma-separated list of window manager protocols, similar to
|
||||
\fBinputStyles\fP, that the protocol translator should enable or
|
||||
|
|
|
@ -18,8 +18,8 @@ MakeSubdirs($(SUBDIRS))
|
|||
DependSubdirs($(SUBDIRS))
|
||||
#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
|
||||
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
|
||||
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 sync_source.o
|
||||
GENHEADERS = transfer_atoms.h drm_modifiers.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 _BufferTransform BufferTransform;
|
||||
typedef enum _RenderMode RenderMode;
|
||||
|
||||
typedef void *IdleCallbackKey;
|
||||
typedef void *PresentCompletionKey;
|
||||
|
@ -169,8 +170,8 @@ typedef void (*DmaBufSuccessFunc) (RenderBuffer, void *);
|
|||
typedef void (*DmaBufFailureFunc) (void *);
|
||||
|
||||
typedef void (*BufferIdleFunc) (RenderBuffer, void *);
|
||||
typedef void (*PresentCompletionFunc) (void *);
|
||||
typedef void (*RenderCompletionFunc) (void *);
|
||||
typedef void (*PresentCompletionFunc) (void *, uint64_t, uint64_t);
|
||||
typedef void (*RenderCompletionFunc) (void *, uint64_t, uint64_t);
|
||||
|
||||
enum _BufferTransform
|
||||
{
|
||||
|
@ -314,6 +315,14 @@ enum
|
|||
SupportsDirectPresent = 1 << 4,
|
||||
};
|
||||
|
||||
enum _RenderMode
|
||||
{
|
||||
/* Do not synchronize rendering. */
|
||||
RenderModeAsync,
|
||||
/* Synchronize rendering with the vertical refresh. */
|
||||
RenderModeVsync,
|
||||
};
|
||||
|
||||
struct _RenderFuncs
|
||||
{
|
||||
/* Initialize the visual and depth. */
|
||||
|
@ -325,6 +334,12 @@ struct _RenderFuncs
|
|||
/* Create a rendering target for the given 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
|
||||
extra pixmap memory allocation tracking to be done. */
|
||||
void (*set_client) (RenderTarget, struct wl_client *);
|
||||
|
@ -423,6 +438,11 @@ struct _RenderFuncs
|
|||
pixman_region32_t *,
|
||||
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. */
|
||||
void (*cancel_presentation_callback) (PresentCompletionKey);
|
||||
|
||||
|
@ -542,6 +562,7 @@ extern void InitRenderers (void);
|
|||
|
||||
extern RenderTarget RenderTargetFromWindow (Window, unsigned long);
|
||||
extern RenderTarget RenderTargetFromPixmap (Pixmap);
|
||||
extern Bool RenderSetRenderMode (RenderTarget, RenderMode, uint64_t);
|
||||
extern void RenderSetClient (RenderTarget, struct wl_client *);
|
||||
extern void RenderSetStandardEventMask (RenderTarget, unsigned long);
|
||||
extern void RenderNoteTargetSize (RenderTarget, int, int);
|
||||
|
@ -568,6 +589,8 @@ extern PresentCompletionKey RenderPresentToWindow (RenderTarget, RenderBuffer,
|
|||
pixman_region32_t *,
|
||||
PresentCompletionFunc,
|
||||
void *);
|
||||
extern RenderCompletionKey RenderNotifyMsc (RenderTarget, RenderCompletionFunc,
|
||||
void *);
|
||||
extern void RenderCancelPresentationCallback (PresentCompletionKey);
|
||||
|
||||
extern DrmFormat *RenderGetDrmFormats (int *);
|
||||
|
@ -767,7 +790,6 @@ typedef enum _FrameMode FrameMode;
|
|||
enum _FrameMode
|
||||
{
|
||||
ModeStarted,
|
||||
ModeNotifyDisablePresent,
|
||||
ModeComplete,
|
||||
ModePresented,
|
||||
};
|
||||
|
@ -798,7 +820,8 @@ extern void SubcompositorSetBoundsCallback (Subcompositor *,
|
|||
void *);
|
||||
extern void SubcompositorSetNoteFrameCallback (Subcompositor *,
|
||||
void (*) (FrameMode, uint64_t,
|
||||
void *),
|
||||
void *, uint64_t,
|
||||
uint64_t),
|
||||
void *);
|
||||
extern void SubcompositorBounds (Subcompositor *, int *, int *, int *, int *);
|
||||
extern void SubcompositorSetProjectiveTransform (Subcompositor *, int, int);
|
||||
|
@ -1304,24 +1327,20 @@ typedef struct _FrameClock FrameClock;
|
|||
extern FrameClock *XLMakeFrameClockForWindow (Window);
|
||||
extern Bool XLFrameClockFrameInProgress (FrameClock *);
|
||||
extern void XLFrameClockAfterFrame (FrameClock *, void (*) (FrameClock *,
|
||||
void *),
|
||||
void *,
|
||||
uint64_t),
|
||||
void *);
|
||||
extern void XLFrameClockHandleFrameEvent (FrameClock *, XEvent *);
|
||||
extern Bool XLFrameClockStartFrame (FrameClock *, Bool);
|
||||
extern void XLFrameClockEndFrame (FrameClock *);
|
||||
extern Bool XLFrameClockIsFrozen (FrameClock *);
|
||||
extern Bool XLFrameClockCanBatch (FrameClock *);
|
||||
extern Bool XLFrameClockNeedConfigure (FrameClock *);
|
||||
extern void XLFrameClockFreeze (FrameClock *);
|
||||
extern void XLFrameClockUnfreeze (FrameClock *);
|
||||
extern void XLFreeFrameClock (FrameClock *);
|
||||
extern Bool XLFrameClockSyncSupported (void);
|
||||
extern Bool XLFrameClockCanRunFrame (FrameClock *);
|
||||
extern void XLFrameClockSetPredictRefresh (FrameClock *);
|
||||
extern void XLFrameClockDisablePredictRefresh (FrameClock *);
|
||||
extern void XLFrameClockSetFreezeCallback (FrameClock *, void (*) (void *),
|
||||
void *);
|
||||
extern uint64_t XLFrameClockGetFrameTime (FrameClock *);
|
||||
extern void XLFrameClockSetFreezeCallback (FrameClock *, void (*) (void *,
|
||||
Bool),
|
||||
Bool (*) (void *), void *);
|
||||
extern void XLFrameClockNoteConfigure (FrameClock *);
|
||||
extern void *XLAddCursorClockCallback (void (*) (void *, struct timespec),
|
||||
void *);
|
||||
|
@ -1905,6 +1924,25 @@ extern void XLInitXdgActivation (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. */
|
||||
|
||||
#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. */
|
||||
|
||||
static Bool frame_sync_supported;
|
||||
|
||||
/* Timer used for cursor animations. */
|
||||
|
||||
static Timer *cursor_clock;
|
||||
|
||||
/* How many cursors want cursor animations. */
|
||||
|
||||
static int cursor_count;
|
||||
|
||||
struct _FrameClockCallback
|
||||
{
|
||||
/* Function called once a frame is completely written to display and
|
||||
(ideally, whether or not this actually works depends on various
|
||||
different factors) enters vblank. */
|
||||
void (*frame) (FrameClock *, void *);
|
||||
/* Function called once a frame is completely written to display.
|
||||
The last arg is the time at which the frame was written, or
|
||||
(uint64_t) -1. */
|
||||
void (*frame) (FrameClock *, void *, uint64_t);
|
||||
|
||||
/* Data that function is called with. */
|
||||
void *data;
|
||||
|
@ -60,28 +57,12 @@ struct _FrameClockCallback
|
|||
|
||||
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,
|
||||
and the value of the last frame that was marked as complete. */
|
||||
uint64_t next_frame_id, finished_frame_id;
|
||||
|
||||
/* 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. */
|
||||
void (*freeze_callback) (void *);
|
||||
|
||||
/* Data for that callback. */
|
||||
void *freeze_callback_data;
|
||||
/* List of frame clock callbacks. */
|
||||
FrameClockCallback callbacks;
|
||||
|
||||
/* The wanted configure value. */
|
||||
uint64_t configure_id;
|
||||
|
@ -103,6 +84,28 @@ struct _FrameClock
|
|||
/* The last known 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. */
|
||||
uint32_t refresh_interval;
|
||||
|
||||
|
@ -114,10 +117,8 @@ struct _FrameClock
|
|||
is put in place. */
|
||||
uint32_t got_configure_count, pending_configure_count;
|
||||
|
||||
/* Whether or not configury is in progress, and whether or not this
|
||||
is frozen, and whether or not the frame shouldn't actually be
|
||||
unfrozen until EndFrame. */
|
||||
Bool need_configure, frozen, frozen_until_end_frame;
|
||||
/* Whether or not configury is in progress. */
|
||||
Bool need_configure;
|
||||
|
||||
/* Whether or not EndFrame was called after StartFrame. */
|
||||
Bool end_frame_called;
|
||||
|
@ -246,9 +247,16 @@ HandleEndFrame (Timer *timer, void *data, struct timespec time)
|
|||
|
||||
/* Forward declarations. */
|
||||
|
||||
static void RunFrameCallbacks (FrameClock *);
|
||||
static void RunFrameCallbacks (FrameClock *, uint64_t);
|
||||
static Bool StartFrame (FrameClock *, Bool, Bool);
|
||||
|
||||
static void
|
||||
BumpFrame (FrameClock *clock)
|
||||
{
|
||||
StartFrame (clock, True, False);
|
||||
EndFrame (clock);
|
||||
}
|
||||
|
||||
static void
|
||||
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
|
||||
by the time the freeze itself. Start a new frame to bring up to
|
||||
date contents to the display. */
|
||||
|
||||
if (clock->pending_configure_count <= clock->got_configure_count)
|
||||
need_empty_frame = True;
|
||||
|
||||
|
@ -282,14 +291,6 @@ FreezeForValue (FrameClock *clock, uint64_t counter_value)
|
|||
EndFrame (clock);
|
||||
}
|
||||
|
||||
/* counter_value - 240 is the value seen by the compositor when the
|
||||
frame contents were frozen in response to a resize. If it is
|
||||
less than finished_frame_id, run frame callbacks now, or clients
|
||||
like Chromium are confused and hang waiting for frame callbacks
|
||||
to be called. */
|
||||
if (counter_value - 240 <= clock->finished_frame_id)
|
||||
RunFrameCallbacks (clock);
|
||||
|
||||
/* The reason for clearing in_frame is that otherwise a future
|
||||
Commit after the configuration is acknowledged will not be able
|
||||
to start a new frame and restart the frame clock. */
|
||||
|
@ -297,17 +298,23 @@ FreezeForValue (FrameClock *clock, uint64_t counter_value)
|
|||
clock->need_configure = True;
|
||||
clock->configure_id = counter_value;
|
||||
|
||||
if (need_empty_frame)
|
||||
{
|
||||
/* Request a new frame and don't allow starting frames until it
|
||||
finishes. See above for why. clock->in_frame is False for
|
||||
now to really force the frame to happen. */
|
||||
if (need_empty_frame
|
||||
/* If the surface has not yet ack_configure'd, don't fast
|
||||
forward the frame. The sync counter will be set at the next
|
||||
commit after ack_configure. */
|
||||
&& 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);
|
||||
EndFrame (clock);
|
||||
}
|
||||
else
|
||||
clock->frozen = True;
|
||||
clock->freeze_callback (clock->freeze_callback_data,
|
||||
/* Only run the freeze callback if this
|
||||
freeze is up to date. If it is not,
|
||||
frame callbacks still have to be run,
|
||||
which is what the following parameter
|
||||
means. */
|
||||
need_empty_frame);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -410,12 +417,6 @@ PostEndFrame (FrameClock *clock)
|
|||
static Bool
|
||||
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->end_frame_timer
|
||||
|
@ -487,11 +488,6 @@ StartFrame (FrameClock *clock, Bool urgent, Bool predict)
|
|||
static void
|
||||
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
|
||||
frame from the timer. */
|
||||
clock->end_frame_called = True;
|
||||
|
@ -521,8 +517,10 @@ EndFrame (FrameClock *clock)
|
|||
|
||||
/* The frame has ended. Freeze the frame clock if there is a
|
||||
pending sync value. */
|
||||
|
||||
if (clock->pending_sync_value)
|
||||
FreezeForValue (clock, clock->pending_sync_value);
|
||||
|
||||
clock->pending_sync_value = 0;
|
||||
|
||||
if (!frame_sync_supported)
|
||||
|
@ -551,7 +549,7 @@ FreeFrameCallbacks (FrameClock *clock)
|
|||
}
|
||||
|
||||
static void
|
||||
RunFrameCallbacks (FrameClock *clock)
|
||||
RunFrameCallbacks (FrameClock *clock, uint64_t frame_drawn_time)
|
||||
{
|
||||
FrameClockCallback *callback;
|
||||
|
||||
|
@ -559,7 +557,8 @@ RunFrameCallbacks (FrameClock *clock)
|
|||
|
||||
while (callback != &clock->callbacks)
|
||||
{
|
||||
callback->frame (clock, callback->data);
|
||||
callback->frame (clock, callback->data,
|
||||
frame_drawn_time);
|
||||
callback = callback->next;
|
||||
}
|
||||
}
|
||||
|
@ -575,13 +574,14 @@ NoteFakeFrame (Timer *timer, void *data, struct timespec time)
|
|||
&& (clock->finished_frame_id == clock->next_frame_id))
|
||||
{
|
||||
clock->in_frame = False;
|
||||
RunFrameCallbacks (clock);
|
||||
RunFrameCallbacks (clock, (uint64_t) -1);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
XLFrameClockAfterFrame (FrameClock *clock,
|
||||
void (*frame_func) (FrameClock *, void *),
|
||||
void (*frame_func) (FrameClock *, void *,
|
||||
uint64_t),
|
||||
void *data)
|
||||
{
|
||||
FrameClockCallback *callback;
|
||||
|
@ -613,36 +613,9 @@ XLFrameClockEndFrame (FrameClock *clock)
|
|||
Bool
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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
|
||||
XLFrameClockHandleFrameEvent (FrameClock *clock, XEvent *event)
|
||||
{
|
||||
|
@ -671,9 +644,11 @@ XLFrameClockHandleFrameEvent (FrameClock *clock, XEvent *event)
|
|||
/* Actually compute the time and save it. */
|
||||
clock->last_frame_time = low | (high << 32);
|
||||
|
||||
/* Run any frame callbacks, since drawing has finished. */
|
||||
/* Clear the in_frame flag. */
|
||||
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)
|
||||
{
|
||||
|
@ -742,14 +717,11 @@ XLFrameClockHandleFrameEvent (FrameClock *clock, XEvent *event)
|
|||
|
||||
/* If a frame is in progress, postpone this frame
|
||||
synchronization message. */
|
||||
|
||||
if (clock->in_frame && !clock->end_frame_called)
|
||||
clock->pending_sync_value = value;
|
||||
else
|
||||
FreezeForValue (clock, value);
|
||||
|
||||
if (clock->freeze_callback)
|
||||
/* Call the freeze callback in any case. */
|
||||
clock->freeze_callback (clock->freeze_callback_data);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -821,30 +793,12 @@ XLMakeFrameClockForWindow (Window window)
|
|||
return clock;
|
||||
}
|
||||
|
||||
void
|
||||
XLFrameClockUnfreeze (FrameClock *clock)
|
||||
{
|
||||
clock->frozen = False;
|
||||
}
|
||||
|
||||
Bool
|
||||
XLFrameClockNeedConfigure (FrameClock *clock)
|
||||
{
|
||||
return clock->need_configure;
|
||||
}
|
||||
|
||||
Bool
|
||||
XLFrameClockSyncSupported (void)
|
||||
{
|
||||
return frame_sync_supported;
|
||||
}
|
||||
|
||||
Bool
|
||||
XLFrameClockIsFrozen (FrameClock *clock)
|
||||
{
|
||||
return clock->frozen;
|
||||
}
|
||||
|
||||
Bool
|
||||
XLFrameClockCanBatch (FrameClock *clock)
|
||||
{
|
||||
|
@ -884,21 +838,14 @@ XLFrameClockDisablePredictRefresh (FrameClock *clock)
|
|||
}
|
||||
|
||||
void
|
||||
XLFrameClockSetFreezeCallback (FrameClock *clock, void (*callback) (void *),
|
||||
XLFrameClockSetFreezeCallback (FrameClock *clock, void (*callback) (void *,
|
||||
Bool),
|
||||
Bool (*fast_forward_callback) (void *),
|
||||
void *data)
|
||||
{
|
||||
clock->freeze_callback = callback;
|
||||
clock->freeze_callback_data = data;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
XLFrameClockGetFrameTime (FrameClock *clock)
|
||||
{
|
||||
/* Only return the time if it is actually a valid clock time. */
|
||||
if (!compositor.server_time_monotonic)
|
||||
return 0;
|
||||
|
||||
return clock->last_frame_time;
|
||||
clock->can_forward_sync_counter = fast_forward_callback;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
160
icon_surface.c
160
icon_surface.c
|
@ -29,9 +29,10 @@ along with 12to11. If not, see <https://www.gnu.org/licenses/>. */
|
|||
|
||||
enum
|
||||
{
|
||||
StateLateFrame = 1,
|
||||
StateIsMapped = (1 << 1),
|
||||
StateIsReleased = (1 << 2),
|
||||
StateIsMapped = 1,
|
||||
StateIsReleased = (1 << 1),
|
||||
StatePendingBufferRelease = (1 << 2),
|
||||
StatePendingFrameCallback = (1 << 3),
|
||||
};
|
||||
|
||||
struct _IconSurface
|
||||
|
@ -48,8 +49,11 @@ struct _IconSurface
|
|||
/* The subcompositor associated with this role. */
|
||||
Subcompositor *subcompositor;
|
||||
|
||||
/* The frame clock associated with this role. */
|
||||
FrameClock *clock;
|
||||
/* The associated buffer release helper. */
|
||||
BufferReleaseHelper *release_helper;
|
||||
|
||||
/* The sync source associated with this role. */
|
||||
SyncHelper *sync_helper;
|
||||
|
||||
/* The number of references to this role. */
|
||||
int refcount;
|
||||
|
@ -63,6 +67,9 @@ struct _IconSurface
|
|||
|
||||
/* The last known bounds of this icon surface. */
|
||||
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. */
|
||||
|
@ -90,16 +97,19 @@ ReleaseBacking (IconSurface *icon)
|
|||
RenderDestroyRenderTarget (icon->target);
|
||||
XDestroyWindow (compositor.display, icon->window);
|
||||
|
||||
/* And the buffer release helper. */
|
||||
FreeBufferReleaseHelper (icon->release_helper);
|
||||
|
||||
/* And the association. */
|
||||
XLDeleteAssoc (surfaces, icon->window);
|
||||
|
||||
/* Free the sync helper. */
|
||||
FreeSyncHelper (icon->sync_helper);
|
||||
|
||||
/* There shouldn't be any children of the subcompositor at this
|
||||
point. */
|
||||
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
|
||||
anymore, it can be freed. */
|
||||
XLFree (icon);
|
||||
|
@ -155,17 +165,22 @@ Setup (Surface *surface, Role *role)
|
|||
static void
|
||||
ReleaseBuffer (Surface *surface, Role *role, ExtBuffer *buffer)
|
||||
{
|
||||
RenderBuffer render_buffer;
|
||||
IconSurface *icon;
|
||||
|
||||
icon = IconSurfaceFromRole (role);
|
||||
render_buffer = XLRenderBufferFromBuffer (buffer);
|
||||
|
||||
/* Icon surfaces are not supposed to change much, so doing an XSync
|
||||
(or XIfEvent) here is okay. */
|
||||
RenderWaitForIdle (XLRenderBufferFromBuffer (buffer),
|
||||
icon->target);
|
||||
|
||||
/* Now really release the buffer. */
|
||||
XLReleaseBuffer (buffer);
|
||||
if (RenderIsBufferIdle (render_buffer, icon->target))
|
||||
/* If the buffer is already idle, release it now. */
|
||||
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
|
||||
|
@ -218,48 +233,61 @@ NoteBounds (void *data, int min_x, int min_y, int max_x, int max_y)
|
|||
}
|
||||
|
||||
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
|
||||
arriving after the icon surface is detached. */
|
||||
if (!surface)
|
||||
return;
|
||||
|
||||
last_drawn_time = XLFrameClockGetFrameTime (clock);
|
||||
|
||||
if (!last_drawn_time)
|
||||
{
|
||||
clock_gettime (CLOCK_MONOTONIC, &time);
|
||||
XLSurfaceRunFrameCallbacks (surface, time);
|
||||
}
|
||||
else
|
||||
XLSurfaceRunFrameCallbacksMs (surface, last_drawn_time / 1000);
|
||||
XLSurfaceRunFrameCallbacksMs (surface, ms_time);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
icon = data;
|
||||
|
||||
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);
|
||||
RunFrameCallbacksConditionally (icon, ms_time);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -316,20 +344,6 @@ Commit (Surface *surface, Role *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. */
|
||||
if (surface->pending_state.pending & PendingAttachments)
|
||||
MoveWindowTo (icon, icon->x, icon->y);
|
||||
|
@ -340,6 +354,9 @@ Commit (Surface *surface, Role *role)
|
|||
MaybeMapWindow (icon);
|
||||
else
|
||||
MaybeUnmapWindow (icon);
|
||||
|
||||
/* Update via the sync helper. */
|
||||
SyncHelperUpdate (icon->sync_helper);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -348,19 +365,7 @@ SubsurfaceUpdate (Surface *surface, Role *role)
|
|||
IconSurface *icon;
|
||||
|
||||
icon = IconSurfaceFromRole (role);
|
||||
|
||||
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);
|
||||
SyncHelperUpdate (icon->sync_helper);
|
||||
}
|
||||
|
||||
static Window
|
||||
|
@ -415,6 +420,8 @@ XLGetIconSurface (Surface *surface)
|
|||
|
||||
/* Create a target associated with the window. */
|
||||
role->target = RenderTargetFromWindow (role->window, None);
|
||||
role->release_helper = MakeBufferReleaseHelper (AllBuffersReleased,
|
||||
role);
|
||||
|
||||
/* Set the client. */
|
||||
if (surface->resource)
|
||||
|
@ -427,7 +434,11 @@ XLGetIconSurface (Surface *surface)
|
|||
|
||||
/* Create a subcompositor associated with the window. */
|
||||
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. */
|
||||
SubcompositorSetTarget (role->subcompositor, &role->target);
|
||||
|
@ -445,9 +456,6 @@ XLGetIconSurface (Surface *surface)
|
|||
If it does, frame synchronization will not work. */
|
||||
WriteRedirectProperty (role);
|
||||
|
||||
/* Initialize frame callbacks. */
|
||||
XLFrameClockAfterFrame (role->clock, AfterFrame, role);
|
||||
|
||||
if (!XLSurfaceAttachRole (surface, &role->role))
|
||||
abort ();
|
||||
|
||||
|
@ -469,7 +477,7 @@ XLHandleOneXEventForIconSurfaces (XEvent *event)
|
|||
|
||||
if (icon)
|
||||
{
|
||||
XLFrameClockHandleFrameEvent (icon->clock, event);
|
||||
SyncHelperHandleFrameEvent (icon->sync_helper, event);
|
||||
return True;
|
||||
}
|
||||
|
||||
|
|
|
@ -220,6 +220,9 @@ enum
|
|||
|
||||
struct _PictureTarget
|
||||
{
|
||||
/* The next frame number. */
|
||||
uint64_t next_msc;
|
||||
|
||||
/* The XID of the picture. */
|
||||
Picture picture;
|
||||
|
||||
|
@ -265,6 +268,9 @@ struct _PictureTarget
|
|||
|
||||
/* List of buffers that were used in the course of an update. */
|
||||
XLList *buffers_used;
|
||||
|
||||
/* What rendering mode should be used. */
|
||||
RenderMode render_mode;
|
||||
};
|
||||
|
||||
struct _DrmFormatInfo
|
||||
|
@ -451,9 +457,6 @@ static BufferActivityRecord all_activity;
|
|||
/* List of all presentations that have not yet been completed. */
|
||||
static PresentCompletionCallback all_completion_callbacks;
|
||||
|
||||
/* Whether or not direct presentation should be used. */
|
||||
static Bool use_direct_presentation;
|
||||
|
||||
/* The device nodes of each provider. */
|
||||
static dev_t *render_devices;
|
||||
|
||||
|
@ -839,10 +842,18 @@ SwapBackBuffers (PictureTarget *target, pixman_region32_t *damage)
|
|||
if (!present_serial)
|
||||
present_serial++;
|
||||
|
||||
XPresentPixmap (compositor.display, target->window,
|
||||
back_buffer->pixmap, present_serial,
|
||||
None, region, 0, 0, None, None, fence,
|
||||
PresentOptionAsync, 0, 0, 0, NULL, 0);
|
||||
if (target->render_mode == RenderModeAsync)
|
||||
XPresentPixmap (compositor.display, target->window,
|
||||
back_buffer->pixmap, present_serial,
|
||||
None, region, 0, 0, None, None, fence,
|
||||
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
|
||||
been released. */
|
||||
|
@ -1024,42 +1035,6 @@ PickVisual (int *depth)
|
|||
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
|
||||
AddAdditionalModifier (const char *name)
|
||||
{
|
||||
|
@ -1154,12 +1129,6 @@ InitAdditionalModifiers (void)
|
|||
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)
|
||||
|
@ -1190,15 +1159,11 @@ InitRenderFuncs (void)
|
|||
return False;
|
||||
}
|
||||
|
||||
/* Figure out whether or not the user wants synchronized
|
||||
presentation. */
|
||||
InitSynchronizedPresentation ();
|
||||
|
||||
/* Find out what additional modifiers the user wants. */
|
||||
InitAdditionalModifiers ();
|
||||
|
||||
if (use_direct_presentation)
|
||||
AddRenderFlag (SupportsDirectPresent);
|
||||
/* Add the direct presentation support flag. */
|
||||
AddRenderFlag (SupportsDirectPresent);
|
||||
|
||||
/* Create an unmapped, InputOnly window, that is used to receive
|
||||
roundtrip events. */
|
||||
|
@ -1276,16 +1241,32 @@ TargetFromDrawable (Drawable drawable, Window window,
|
|||
return (RenderTarget) (void *) target;
|
||||
}
|
||||
|
||||
static RenderTarget
|
||||
TargetFromWindow (Window window, unsigned long event_mask)
|
||||
{
|
||||
return TargetFromDrawable (window, window, event_mask);
|
||||
}
|
||||
|
||||
static RenderTarget
|
||||
TargetFromPixmap (Pixmap pixmap)
|
||||
{
|
||||
return TargetFromDrawable (pixmap, None, NoEventMask);
|
||||
}
|
||||
|
||||
static RenderTarget
|
||||
TargetFromWindow (Window window, unsigned long event_mask)
|
||||
static Bool
|
||||
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
|
||||
|
@ -1941,21 +1922,16 @@ PresentToWindow (RenderTarget target, RenderBuffer source,
|
|||
else
|
||||
region = None;
|
||||
|
||||
if (use_direct_presentation)
|
||||
{
|
||||
/* 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. */
|
||||
if (pict_target->render_mode == RenderModeAsync)
|
||||
/* Present the pixmap asynchronously at an msc of 0. */
|
||||
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);
|
||||
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)
|
||||
XFixesDestroyRegion (compositor.display, region);
|
||||
|
@ -1987,6 +1963,30 @@ PresentToWindow (RenderTarget target, RenderBuffer source,
|
|||
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. */
|
||||
|
||||
static void
|
||||
|
@ -2006,6 +2006,7 @@ static RenderFuncs picture_render_funcs =
|
|||
.init_render_funcs = InitRenderFuncs,
|
||||
.target_from_window = TargetFromWindow,
|
||||
.target_from_pixmap = TargetFromPixmap,
|
||||
.set_render_mode = SetRenderMode,
|
||||
.set_client = SetClient,
|
||||
.set_standard_event_mask = SetStandardEventMask,
|
||||
.note_target_size = NoteTargetSize,
|
||||
|
@ -2023,6 +2024,7 @@ static RenderFuncs picture_render_funcs =
|
|||
.delete_fence = DeleteFence,
|
||||
.get_finish_fence = GetFinishFence,
|
||||
.present_to_window = PresentToWindow,
|
||||
.notify_msc = NotifyMsc,
|
||||
.cancel_presentation_callback = CancelPresentationCallback,
|
||||
};
|
||||
|
||||
|
@ -3379,7 +3381,7 @@ HandlePresentCompleteNotify (XPresentCompleteNotifyEvent *complete)
|
|||
{
|
||||
/* The presentation is complete. Run and unlink the
|
||||
callback. */
|
||||
last->function (last->data);
|
||||
last->function (last->data, complete->msc, complete->ust);
|
||||
last->next->last = last->last;
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
RenderSetClient (RenderTarget target, struct wl_client *client)
|
||||
{
|
||||
|
@ -215,6 +225,16 @@ RenderPresentToWindow (RenderTarget target, RenderBuffer source,
|
|||
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
|
||||
RenderCancelPresentationCallback (PresentCompletionKey key)
|
||||
{
|
||||
|
|
|
@ -329,8 +329,10 @@ struct _Subcompositor
|
|||
/* Function called with the bounds before each update. */
|
||||
void (*note_bounds) (void *, int, int, int, int);
|
||||
|
||||
/* Function called with the frame counter on each update. */
|
||||
void (*note_frame) (FrameMode, uint64_t, void *);
|
||||
/* Function called with the frame counter on each update. Counter 3
|
||||
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. */
|
||||
uint64_t frame_counter;
|
||||
|
@ -2105,7 +2107,8 @@ SubcompositorSetBoundsCallback (Subcompositor *subcompositor,
|
|||
void
|
||||
SubcompositorSetNoteFrameCallback (Subcompositor *subcompositor,
|
||||
void (*note_frame) (FrameMode, uint64_t,
|
||||
void *),
|
||||
void *, uint64_t,
|
||||
uint64_t),
|
||||
void *data)
|
||||
{
|
||||
subcompositor->note_frame = note_frame;
|
||||
|
@ -2176,7 +2179,7 @@ StorePreviousDamage (Subcompositor *subcompositor,
|
|||
}
|
||||
|
||||
static void
|
||||
PresentCompletedCallback (void *data)
|
||||
PresentCompletedCallback (void *data, uint64_t msc, uint64_t ust)
|
||||
{
|
||||
Subcompositor *subcompositor;
|
||||
|
||||
|
@ -2190,11 +2193,12 @@ PresentCompletedCallback (void *data)
|
|||
if (subcompositor->note_frame)
|
||||
subcompositor->note_frame (ModePresented,
|
||||
subcompositor->frame_counter,
|
||||
subcompositor->note_frame_data);
|
||||
subcompositor->note_frame_data,
|
||||
msc, ust);
|
||||
}
|
||||
|
||||
static void
|
||||
RenderCompletedCallback (void *data)
|
||||
RenderCompletedCallback (void *data, uint64_t msc, uint64_t ust)
|
||||
{
|
||||
Subcompositor *subcompositor;
|
||||
|
||||
|
@ -2206,9 +2210,10 @@ RenderCompletedCallback (void *data)
|
|||
|
||||
/* Call the frame function if it s still set. */
|
||||
if (subcompositor->note_frame)
|
||||
subcompositor->note_frame (ModeComplete,
|
||||
subcompositor->note_frame (ModePresented,
|
||||
subcompositor->frame_counter,
|
||||
subcompositor->note_frame_data);
|
||||
subcompositor->note_frame_data,
|
||||
msc, ust);
|
||||
}
|
||||
|
||||
/* Update ancillary data upon commit. This includes the input and
|
||||
|
@ -2974,22 +2979,25 @@ static void
|
|||
BeginFrame (Subcompositor *subcompositor)
|
||||
{
|
||||
if (!subcompositor->note_frame)
|
||||
return;
|
||||
{
|
||||
/* Cancel any presentation callback that is currently in
|
||||
progress. */
|
||||
if (subcompositor->present_key)
|
||||
RenderCancelPresentationCallback (subcompositor->present_key);
|
||||
subcompositor->present_key = NULL;
|
||||
|
||||
/* Cancel any render callback that is currently in progress. */
|
||||
if (subcompositor->render_key)
|
||||
RenderCancelCompletionCallback (subcompositor->render_key);
|
||||
subcompositor->render_key = NULL;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
subcompositor->note_frame (ModeStarted,
|
||||
++subcompositor->frame_counter,
|
||||
subcompositor->note_frame_data);
|
||||
|
||||
/* Cancel any presentation callback that is currently in
|
||||
progress. */
|
||||
if (subcompositor->present_key)
|
||||
RenderCancelPresentationCallback (subcompositor->present_key);
|
||||
subcompositor->present_key = NULL;
|
||||
|
||||
/* Cancel any render callback that is currently in progress. */
|
||||
if (subcompositor->render_key)
|
||||
RenderCancelCompletionCallback (subcompositor->render_key);
|
||||
subcompositor->render_key = NULL;
|
||||
subcompositor->note_frame_data,
|
||||
-1, -1);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -2999,12 +3007,22 @@ EndFrame (Subcompositor *subcompositor)
|
|||
return;
|
||||
|
||||
/* 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)
|
||||
subcompositor->note_frame (ModeComplete,
|
||||
subcompositor->frame_counter,
|
||||
subcompositor->note_frame_data);
|
||||
{
|
||||
subcompositor->render_key
|
||||
= RenderNotifyMsc (subcompositor->target,
|
||||
RenderCompletedCallback,
|
||||
subcompositor);
|
||||
|
||||
if (!subcompositor->render_key)
|
||||
subcompositor->note_frame (ModeComplete,
|
||||
subcompositor->frame_counter,
|
||||
subcompositor->note_frame_data,
|
||||
-1, -1);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
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)
|
||||
return;
|
||||
|
|
|
@ -442,7 +442,6 @@ static void
|
|||
InternalReposition (XdgPopup *popup)
|
||||
{
|
||||
int x, y, width, height;
|
||||
FrameClock *clock;
|
||||
|
||||
/* No parent was specified or the role is detached. */
|
||||
if (!popup->role || !popup->parent)
|
||||
|
@ -458,11 +457,6 @@ InternalReposition (XdgPopup *popup)
|
|||
SendConfigure (popup, popup->pending_x, popup->pending_y,
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
465
xdg_surface.c
465
xdg_surface.c
|
@ -36,17 +36,13 @@ along with 12to11. If not, see <https://www.gnu.org/licenses/>. */
|
|||
enum
|
||||
{
|
||||
StatePendingFrameCallback = 1,
|
||||
StateLateFrame = (1 << 1),
|
||||
StatePendingWindowGeometry = (1 << 2),
|
||||
StateWaitingForAckConfigure = (1 << 3),
|
||||
StateWaitingForAckCommit = (1 << 4),
|
||||
StateLateFrameAcked = (1 << 5),
|
||||
StateMaybeConfigure = (1 << 6),
|
||||
StateDirtyFrameExtents = (1 << 7),
|
||||
StateTemporaryBounds = (1 << 8),
|
||||
StateFrameStarted = (1 << 9),
|
||||
StateAllowUnredirection = (1 << 10),
|
||||
StatePendingBufferRelease = (1 << 11),
|
||||
StateMaybeConfigure = (1 << 5),
|
||||
StateDirtyFrameExtents = (1 << 6),
|
||||
StateTemporaryBounds = (1 << 7),
|
||||
StatePendingBufferRelease = (1 << 8),
|
||||
};
|
||||
|
||||
typedef struct _XdgRole XdgRole;
|
||||
|
@ -128,8 +124,8 @@ struct _XdgRole
|
|||
/* Buffer release helper. */
|
||||
BufferReleaseHelper *release_helper;
|
||||
|
||||
/* The frame clock. */
|
||||
FrameClock *clock;
|
||||
/* The synchronization helper. */
|
||||
SyncHelper *sync_helper;
|
||||
|
||||
/* The pending xdg_surface state. */
|
||||
XdgState pending_state;
|
||||
|
@ -156,6 +152,9 @@ struct _XdgRole
|
|||
events to wait for before ignoring those coordinates. */
|
||||
int pending_synth_configure;
|
||||
|
||||
/* The pending frame time. */
|
||||
uint32_t pending_frame_time;
|
||||
|
||||
/* The input region of the attached subsurface. */
|
||||
pixman_region32_t input_region;
|
||||
|
||||
|
@ -244,63 +243,29 @@ FreeReconstrainCallbacks (XdgRole *role)
|
|||
}
|
||||
|
||||
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
|
||||
arriving after the shell surface is detached. */
|
||||
|
||||
if (!surface)
|
||||
return;
|
||||
|
||||
last_drawn_time = XLFrameClockGetFrameTime (role->clock);
|
||||
|
||||
if (!last_drawn_time)
|
||||
{
|
||||
clock_gettime (CLOCK_MONOTONIC, &time);
|
||||
XLSurfaceRunFrameCallbacks (surface, time);
|
||||
}
|
||||
else
|
||||
XLSurfaceRunFrameCallbacksMs (surface, last_drawn_time / 1000);
|
||||
XLSurfaceRunFrameCallbacksMs (surface, frame_time);
|
||||
}
|
||||
|
||||
static void
|
||||
RunFrameCallbacksConditionally (XdgRole *role)
|
||||
RunFrameCallbacksConditionally (XdgRole *role, uint32_t frame_time)
|
||||
{
|
||||
if (!(role->state & StatePendingBufferRelease))
|
||||
RunFrameCallbacks (role->role.surface, role);
|
||||
RunFrameCallbacks (role->role.surface, role, frame_time);
|
||||
else if (role->role.surface)
|
||||
/* weston-simple-shm seems to assume that a frame callback can
|
||||
only arrive after all buffers have been released. */
|
||||
role->state |= StatePendingFrameCallback;
|
||||
}
|
||||
|
||||
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;
|
||||
/* weston-simple-shm seems to assume that a frame callback can
|
||||
only arrive after all buffers have been released. */
|
||||
role->state |= StatePendingFrameCallback;
|
||||
role->pending_frame_time = frame_time;
|
||||
}
|
||||
|
||||
return False;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -319,7 +284,8 @@ AllBuffersReleased (void *data)
|
|||
released. */
|
||||
if (surface && role->state & StatePendingFrameCallback)
|
||||
{
|
||||
RunFrameCallbacks (surface, role);
|
||||
RunFrameCallbacks (surface, role,
|
||||
role->pending_frame_time);
|
||||
|
||||
role->state &= ~StatePendingFrameCallback;
|
||||
}
|
||||
|
@ -341,7 +307,7 @@ XLHandleXEventForXdgSurfaces (XEvent *event)
|
|||
|
||||
if (role)
|
||||
{
|
||||
XLFrameClockHandleFrameEvent (role->clock, event);
|
||||
SyncHelperHandleFrameEvent (role->sync_helper, event);
|
||||
return True;
|
||||
}
|
||||
|
||||
|
@ -354,11 +320,7 @@ XLHandleXEventForXdgSurfaces (XEvent *event)
|
|||
|
||||
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;
|
||||
}
|
||||
|
@ -535,11 +497,6 @@ AckConfigure (struct wl_client *client, struct wl_resource *resource,
|
|||
exposed due to changes in bounds. */
|
||||
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
|
||||
fprintf (stderr, "Client acknowledged configuration\n");
|
||||
#endif
|
||||
|
@ -560,51 +517,6 @@ static const struct xdg_surface_interface xdg_surface_impl =
|
|||
.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
|
||||
Commit (Surface *surface, Role *role)
|
||||
{
|
||||
|
@ -627,11 +539,13 @@ Commit (Surface *surface, Role *role)
|
|||
= xdg_role->pending_state.window_geometry_height;
|
||||
|
||||
#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_y,
|
||||
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
|
||||
|
||||
/* Now, clear the "pending window geometry" flag. */
|
||||
|
@ -657,35 +571,40 @@ Commit (Surface *surface, Role *role)
|
|||
xdg_role->state &= ~StateWaitingForAckCommit;
|
||||
}
|
||||
|
||||
/* If the frame clock is frozen but we are no longer waiting for the
|
||||
configure event to be acknowledged by the client, unfreeze the
|
||||
frame clock. */
|
||||
if (!(xdg_role->state & StateWaitingForAckConfigure))
|
||||
Unfreeze (xdg_role);
|
||||
if (!(xdg_role->state & StateWaitingForAckCommit))
|
||||
{
|
||||
/* Tell the sync helper to update the frame. This will also
|
||||
complete any resize if necessary. */
|
||||
SyncHelperUpdate (xdg_role->sync_helper);
|
||||
|
||||
/* Now, check if a frame can be drawn, or schedule a frame to be
|
||||
drawn after this one completes. */
|
||||
/* Run the after_commit function of the role implementation,
|
||||
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;
|
||||
if (xdg_role->impl->funcs.after_commit)
|
||||
xdg_role->impl->funcs.after_commit (role, surface,
|
||||
xdg_role->impl);
|
||||
}
|
||||
else
|
||||
/* Now, tell the sync helper to generate a frame.
|
||||
Many clients do this:
|
||||
|
||||
/* The frame can be drawn, so update the window contents now. */
|
||||
SubcompositorUpdate (xdg_role->subcompositor);
|
||||
wl_surface@1.frame (new id wl_callback@2)
|
||||
wl_surface@1.commit ()
|
||||
|
||||
/* Do not end frames explicitly. Instead, wait for the
|
||||
NoteFrameCallback to end the frame. */
|
||||
and upon receiving a configure event, potentially call:
|
||||
|
||||
after_commit:
|
||||
xdg_surface@3.ack_configure (1)
|
||||
|
||||
/* Run the after_commit function of the role implementation, which
|
||||
peforms actions such as posting pending configure events for
|
||||
built-in resize. */
|
||||
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);
|
||||
|
||||
if (xdg_role->impl->funcs.after_commit)
|
||||
xdg_role->impl->funcs.after_commit (role, surface,
|
||||
xdg_role->impl);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -753,13 +672,13 @@ ReleaseBacking (XdgRole *role)
|
|||
/* And the association. */
|
||||
XLDeleteAssoc (surfaces, role->window);
|
||||
|
||||
/* Destroy the sync helper. */
|
||||
FreeSyncHelper (role->sync_helper);
|
||||
|
||||
/* There shouldn't be any children of the subcompositor at this
|
||||
point. */
|
||||
SubcompositorFree (role->subcompositor);
|
||||
|
||||
/* The frame clock is no longer useful. */
|
||||
XLFreeFrameClock (role->clock);
|
||||
|
||||
/* Free the input region. */
|
||||
pixman_region32_fini (&role->input_region);
|
||||
|
||||
|
@ -822,19 +741,34 @@ SubsurfaceUpdate (Surface *surface, Role *role)
|
|||
|
||||
xdg_role = XdgRoleFromRole (role);
|
||||
|
||||
/* If the frame clock is frozen, don't update anything. */
|
||||
if (XLFrameClockIsFrozen (xdg_role->clock))
|
||||
return;
|
||||
if (xdg_role->state & StateWaitingForAckCommit)
|
||||
{
|
||||
/* Updates are being postponed until the next commit after
|
||||
ack_configure.
|
||||
|
||||
/* If a frame is already in progress, return, but schedule a frame
|
||||
to be drawn later. */
|
||||
Now, tell the sync helper to generate a frame.
|
||||
Many clients do this:
|
||||
|
||||
if (!CheckFrame (xdg_role))
|
||||
/* The frame cannot be drawn. */
|
||||
return;
|
||||
wl_surface@1.frame (new id wl_callback@2)
|
||||
wl_surface@1.commit ()
|
||||
|
||||
/* The frame can be drawn, so update the window contents. */
|
||||
SubcompositorUpdate (xdg_role->subcompositor);
|
||||
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;
|
||||
}
|
||||
|
||||
/* Tell the sync helper to do an update. */
|
||||
SyncHelperUpdate (xdg_role->sync_helper);
|
||||
}
|
||||
|
||||
static Window
|
||||
|
@ -858,48 +792,6 @@ HandleResourceDestroy (struct wl_resource *resource)
|
|||
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
|
||||
OpaqueRegionChanged (Subcompositor *subcompositor,
|
||||
void *client_data,
|
||||
|
@ -1004,7 +896,7 @@ NoteConfigure (XdgRole *role, XEvent *event)
|
|||
|
||||
/* Tell the frame clock how many WM-generated configure events have
|
||||
arrived. */
|
||||
XLFrameClockNoteConfigure (role->clock);
|
||||
SyncHelperNoteConfigureEvent (role->sync_helper);
|
||||
|
||||
/* Run reconstrain callbacks. */
|
||||
RunReconstrainCallbacksForXEvent (role, event);
|
||||
|
@ -1040,11 +932,6 @@ NoteBounds (void *data, int min_x, int min_y,
|
|||
run_reconstrain_callbacks = 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)
|
||||
/* Don't resize the window until all configure events are
|
||||
acknowledged. We wait for a commit on the xdg_toplevel to do
|
||||
|
@ -1160,12 +1047,7 @@ WriteRedirectProperty (XdgRole *role)
|
|||
{
|
||||
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,
|
||||
_NET_WM_BYPASS_COMPOSITOR, XA_CARDINAL,
|
||||
|
@ -1173,113 +1055,6 @@ WriteRedirectProperty (XdgRole *role)
|
|||
(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
|
||||
ResizeForMap (XdgRole *role)
|
||||
{
|
||||
|
@ -1373,21 +1148,52 @@ Rescale (Surface *surface, Role *role)
|
|||
}
|
||||
|
||||
static void
|
||||
HandleFreeze (void *data)
|
||||
HandleResize (void *data, Bool only_frame)
|
||||
{
|
||||
XdgRole *role;
|
||||
|
||||
role = data;
|
||||
|
||||
if (only_frame)
|
||||
{
|
||||
SyncHelperCheckFrameCallback (role->sync_helper);
|
||||
return;
|
||||
}
|
||||
|
||||
/* _NET_WM_SYNC_REQUEST events should be succeeded by a
|
||||
ConfigureNotify event. */
|
||||
role->state |= StateWaitingForAckConfigure;
|
||||
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
|
||||
_NET_WM_SYNC_REQUEST, and the following ConfigureNotify event
|
||||
might not lead to a configure event being sent. */
|
||||
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
|
||||
|
@ -1445,6 +1251,15 @@ Activate (Surface *surface, Role *role, int deviceid,
|
|||
activator_surface);
|
||||
}
|
||||
|
||||
static void
|
||||
HandleFrameCallback (void *data, uint32_t frame_time)
|
||||
{
|
||||
XdgRole *role;
|
||||
|
||||
role = data;
|
||||
RunFrameCallbacksConditionally (role, frame_time);
|
||||
}
|
||||
|
||||
void
|
||||
XLGetXdgSurface (struct wl_client *client, struct wl_resource *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);
|
||||
|
||||
role->subcompositor = MakeSubcompositor ();
|
||||
role->clock = XLMakeFrameClockForWindow (role->window);
|
||||
XLFrameClockSetFreezeCallback (role->clock, HandleFreeze, role);
|
||||
role->sync_helper = MakeSyncHelper (role->subcompositor,
|
||||
role->window,
|
||||
role->target,
|
||||
HandleFrameCallback,
|
||||
&role->role);
|
||||
SyncHelperSetResizeCallback (role->sync_helper, HandleResize,
|
||||
CheckFastForward);
|
||||
|
||||
SubcompositorSetTarget (role->subcompositor, &role->target);
|
||||
SubcompositorSetInputCallback (role->subcompositor,
|
||||
|
@ -1548,8 +1368,6 @@ XLGetXdgSurface (struct wl_client *client, struct wl_resource *resource,
|
|||
OpaqueRegionChanged, role);
|
||||
SubcompositorSetBoundsCallback (role->subcompositor,
|
||||
NoteBounds, role);
|
||||
SubcompositorSetNoteFrameCallback (role->subcompositor,
|
||||
NoteFrame, role);
|
||||
XLSelectStandardEvents (role->window);
|
||||
XLMakeAssoc (surfaces, role->window, role);
|
||||
|
||||
|
@ -1557,9 +1375,6 @@ XLGetXdgSurface (struct wl_client *client, struct wl_resource *resource,
|
|||
If it does, frame synchronization will not work. */
|
||||
WriteRedirectProperty (role);
|
||||
|
||||
/* Initialize frame callbacks. */
|
||||
XLFrameClockAfterFrame (role->clock, AfterFrame, role);
|
||||
|
||||
if (!XLSurfaceAttachRole (surface, &role->role))
|
||||
abort ();
|
||||
|
||||
|
@ -1626,6 +1441,10 @@ XLXdgRoleSendConfigure (Role *role, uint32_t serial)
|
|||
xdg_role->state |= StateWaitingForAckConfigure;
|
||||
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. */
|
||||
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->type == ConfigureNotify)
|
||||
XLFrameClockNoteConfigure (xdg_role->clock);
|
||||
SyncHelperNoteConfigureEvent (xdg_role->sync_helper);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1938,15 +1757,6 @@ XLXdgRoleMoveBy (Role *role, int west, int north)
|
|||
xdg_role->pending_synth_configure++;
|
||||
}
|
||||
|
||||
FrameClock *
|
||||
XLXdgRoleGetFrameClock (Role *role)
|
||||
{
|
||||
XdgRole *xdg_role;
|
||||
|
||||
xdg_role = XdgRoleFromRole (role);
|
||||
return xdg_role->clock;
|
||||
}
|
||||
|
||||
void
|
||||
XLInitXdgSurfaces (void)
|
||||
{
|
||||
|
@ -2043,9 +1853,6 @@ XLXdgRoleNoteRejectedConfigure (Role *role)
|
|||
xdg_role->state &= ~StateWaitingForAckConfigure;
|
||||
xdg_role->state &= ~StateWaitingForAckCommit;
|
||||
xdg_role->state &= ~StateMaybeConfigure;
|
||||
|
||||
/* Unfreeze the frame clock now. */
|
||||
XLFrameClockUnfreeze (xdg_role->clock);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue