diff --git a/12to11.c b/12to11.c index 47f4197..28240fb 100644 --- a/12to11.c +++ b/12to11.c @@ -121,6 +121,7 @@ XLMain (int argc, char **argv) XLInitXSettings (); XLInitIconSurfaces (); XLInitPrimarySelection (); + XLInitExplicitSynchronization (); /* This has to come after the rest of the initialization. */ DetermineServerTime (); XLRunCompositor (); diff --git a/Imakefile b/Imakefile index a17b35e..c557feb 100644 --- a/Imakefile +++ b/Imakefile @@ -17,25 +17,24 @@ LOCAL_LIBRARIES = $(XLIB) $(EXTENSIONLIB) $(XCBLIB) $(XCB) $(XCB_SHM) \ INCLUDES := $(DRMINCLUDES) $(PIXMANINCLUDES) SRCS = 12to11.c run.c alloc.c fns.c output.c compositor.c \ - xdg-shell.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 linux-dmabuf-unstable-v1.c dmabuf.c \ - buffer.c select.c xdata.c xsettings.c dnd.c icon_surface.c \ - primary-selection-unstable-v1.c primary_selection.c \ - renderer.c picture_renderer.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 OBJS = 12to11.o run.o alloc.o fns.o output.o compositor.o \ - xdg-shell.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 linux-dmabuf-unstable-v1.o dmabuf.o \ - buffer.o select.o xdata.o xsettings.o dnd.o icon_surface.o \ - primary-selection-unstable-v1.o primary_selection.o \ - renderer.o picture_renderer.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 GENHEADERS = transfer_atoms.h primary-selection-unstable-v1.h \ - linux-dmabuf-unstable-v1.h xdg-shell.h + linux-dmabuf-unstable-v1.h xdg-shell.h \ + linux-explicit-synchronization-unstable-v1.h #ifdef HaveEglSupport @@ -94,37 +93,34 @@ transfer_atoms.h: short_types.txt mime0.awk mime1.awk mime2.awk mime3.awk \ awk -f mime3.awk short_types.txt >> $@ awk -f mime4.awk short_types.txt >> $@ +/* Now, define generated files. */ + +#define ScannerTarget(name) @@\ +name.h: name.xml @@\ + $(WAYLAND_SCANNER) server-header $< $@ @@\ + @@\ +name.c: name.xml name.h @@\ + $(WAYLAND_SCANNER) private-code $< $@ @@\ + @@\ +GENHEADERS := $(GENHEADERS) name.h @@\ + OBJS := $(OBJS) name.o @@\ + SRCS := $(SRCS) name.c @@\ + GENSRCS := $(GENSRCS) name.c @@\ + +ScannerTarget(linux-dmabuf-unstable-v1) +ScannerTarget(xdg-shell) +ScannerTarget(primary-selection-unstable-v1) +ScannerTarget(linux-explicit-synchronization-unstable-v1) + +/* Make OBJS depend on scanner headers, and depend on both them and SRCS. */ $(OBJS): $(GENHEADERS) /* depend somehow does not depend on SRCS, even though some of OBJS are generated. */ depend:: $(GENHEADERS) $(SRCS) -linux-dmabuf-unstable-v1.h: linux-dmabuf-unstable-v1.xml - $(WAYLAND_SCANNER) server-header $< $@ - -linux-dmabuf-unstable-v1.c: linux-dmabuf-unstable-v1.xml \ - linux-dmabuf-unstable-v1.h - $(WAYLAND_SCANNER) private-code $< $@ - -xdg-shell.h: xdg-shell.xml - $(WAYLAND_SCANNER) server-header $< $@ - -xdg-shell.c: xdg-shell.xml xdg-shell.h - $(WAYLAND_SCANNER) private-code $< $@ - -primary-selection-unstable-v1.h: primary-selection-unstable-v1.xml - $(WAYLAND_SCANNER) server-header $< $@ - -primary-selection-unstable-v1.c: primary-selection-unstable-v1.xml \ - primary-selection-unstable-v1.h - $(WAYLAND_SCANNER) private-code $< $@ - cleandir:: - $(RM) linux-dmabuf-unstable-v1.c linux-dmabuf-unstable-v1.h \ - xdg-shell.c xdg-shell.h primary-selection-unstable-v1.c \ - primary-selection-unstable-v1.h - $(RM) transfer_atoms.h short_types.txt + $(RM) $(GENHEADERS) $(GENSRCS) transfer_atoms.h short_types.txt /* Undefine _BSD_SOURCE and _SVID_SOURCE, since both are deprecated and are also superseeded by _GNU_SOURCE. */ diff --git a/README b/README index 982b78a..e391716 100644 --- a/README +++ b/README @@ -65,6 +65,10 @@ complete degree: 'zwp_linux_dmabuf_v1', version: 4 'zwp_primary_selection_device_manager_v1', version: 1 +When built with EGL, the following Wayland protocol is also supported: + + 'zwp_linux_explicit_synchronization_v1', version: 2 + With the main caveat being that zwp_linux_dmabuf_v1 has no real support for multiple-provider setups (help wanted). diff --git a/compositor.h b/compositor.h index 5fe1d48..78a4a6a 100644 --- a/compositor.h +++ b/compositor.h @@ -101,6 +101,7 @@ typedef struct _BufferFuncs BufferFuncs; typedef union _RenderTarget RenderTarget; typedef union _RenderBuffer RenderBuffer; +typedef union _RenderFence RenderFence; typedef struct _DmaBufAttributes DmaBufAttributes; typedef struct _SharedMemoryAttributes SharedMemoryAttributes; @@ -183,13 +184,24 @@ union _RenderBuffer void *pointer; }; +union _RenderFence +{ + /* The XID of the fence resource, if that is what it is. */ + XID xid; + + /* The pointer to the fence, if that is what it is. */ + void *pointer; +}; + enum { /* The render target always preserves previously drawn contents; IOW, target_age always returns 0. */ - NeverAges = 1, + NeverAges = 1, /* Buffers attached can always be immediately released. */ - ImmediateRelease = 1 << 2, + ImmediateRelease = 1 << 2, + /* The render target supports explicit synchronization. */ + SupportsExplicitSync = 1 << 3, }; struct _RenderFuncs @@ -258,6 +270,25 @@ struct _RenderFuncs may chose to return 0 instead of 1. */ int (*target_age) (RenderTarget); + /* Create a rendering "fence" object, that serves to explicitly + specify the order of rendering requests between different + programs. Fence-related functions must only be defined if + SupportsExplicitSync is set. */ + RenderFence (*import_fd_fence) (int, Bool *); + + /* Wait for the given fence object. This is guaranteed to make all + drawing commands execute after the fence has been triggered, but + does not typically block. */ + void (*wait_fence) (RenderFence); + + /* Delete the given fence object. */ + void (*delete_fence) (RenderFence); + + /* Get a file descriptor describing a fence that is triggered upon + the completion of all drawing commands made before it is + called. */ + int (*get_finish_fence) (Bool *); + /* Some flags. NeverAges means targets always preserve contents that were previously drawn. */ int flags; @@ -351,6 +382,10 @@ extern void RenderComposite (RenderBuffer, RenderTarget, Operation, int, extern void RenderResetTransform (RenderBuffer); extern void RenderFinishRender (RenderTarget); extern int RenderTargetAge (RenderTarget); +extern RenderFence RenderImportFdFence (int, Bool *); +extern void RenderWaitFence (RenderFence); +extern void RenderDeleteFence (RenderFence); +extern int RenderGetFinishFence (Bool *); extern DrmFormat *RenderGetDrmFormats (int *); extern dev_t RenderGetRenderDevice (Bool *); @@ -372,8 +407,8 @@ typedef struct _PollFd WriteFd; typedef struct _PollFd ReadFd; extern void XLRunCompositor (void); -extern WriteFd *XLAddWriteFd (int, void *, void (*) (int, void *)); -extern ReadFd *XLAddReadFd (int, void *, void (*) (int, void *)); +extern WriteFd *XLAddWriteFd (int, void *, void (*) (int, void *, ReadFd *)); +extern ReadFd *XLAddReadFd (int, void *, void (*) (int, void *, ReadFd *)); extern void XLRemoveWriteFd (WriteFd *); extern void XLRemoveReadFd (ReadFd *); @@ -595,6 +630,11 @@ extern void ViewSetScale (View *, int); extern Subcompositor *ViewGetSubcompositor (View *); +/* Forward declarations from explicit_synchronization.c. */ + +typedef struct _Synchronization Synchronization; +typedef struct _SyncRelease SyncRelease; + /* Defined in surface.c. */ typedef struct _State State; @@ -783,6 +823,15 @@ struct _Surface /* X, Y of the last coordinates that were used to update this surface's entered outputs. */ int output_x, output_y; + + /* The associated explicit synchronization resource, if any. */ + Synchronization *synchronization; + + /* The associated sync release resource, if any. */ + SyncRelease *release; + + /* The associated sync acquire fd, or -1. */ + int acquire_fence; }; struct _RoleFuncs @@ -1275,6 +1324,14 @@ extern void InitEgl (void); #endif +/* Defined in explicit_synchronization.c. */ + +extern void XLDestroyRelease (SyncRelease *); +extern void XLSyncCommit (Synchronization *); +extern void XLSyncRelease (SyncRelease *); +extern void XLWaitFence (Surface *); +extern void XLInitExplicitSynchronization (void); + /* Utility functions that don't belong in a specific file. */ #define ArrayElements(arr) (sizeof (arr) / sizeof (arr)[0]) diff --git a/egl.c b/egl.c index 83df4d0..875c5fc 100644 --- a/egl.c +++ b/egl.c @@ -321,6 +321,12 @@ static PFNEGLQUERYDISPLAYATTRIBEXTPROC IQueryDisplayAttrib; static PFNEGLQUERYDEVICESTRINGEXTPROC IQueryDeviceString; static PFNEGLQUERYDMABUFFORMATSEXTPROC IQueryDmaBufFormats; static PFNEGLQUERYDMABUFMODIFIERSEXTPROC IQueryDmaBufModifiers; +static PFNEGLCREATESYNCKHRPROC ICreateSync; +static PFNEGLDESTROYSYNCKHRPROC IDestroySync; +static PFNEGLCLIENTWAITSYNCKHRPROC IClientWaitSync; +static PFNEGLGETSYNCATTRIBKHRPROC IGetSyncAttrib; +static PFNEGLWAITSYNCKHRPROC IWaitSync; +static PFNEGLDUPNATIVEFENCEFDANDROIDPROC IDupNativeFenceFD; /* The EGL display handle. */ static EGLDisplay egl_display; @@ -507,12 +513,24 @@ EglInitFuncs (void) "EGL_EXT_image_dma_buf_import_modifiers"); LoadProc (QueryDmaBufModifiers, "EXT", "EGL_EXT_image_dma_buf_import_modifiers"); + + LoadProc (CreateSync, "KHR", "EGL_KHR_fence_sync"); + LoadProc (DestroySync, "KHR", "EGL_KHR_fence_sync"); + LoadProc (ClientWaitSync, "KHR", "EGL_KHR_fence_sync"); + LoadProc (GetSyncAttrib, "KHR", "EGL_KHR_fence_sync"); + LoadProc (WaitSync, "KHR", "EGL_KHR_wait_sync"); + LoadProc (DupNativeFenceFD, "ANDROID", "EGL_ANDROID_native_fence_sync"); } static void EglInitGlFuncs (void) { LoadProcGl (EGLImageTargetTexture2D, "OES", "GL_OES_EGL_image"); + + /* We treat eglWaitSyncKHR specially, since it only works if the + server client API also supports GL_OES_EGL_sync. */ + if (!HaveGlExtension ("GL_OES_EGL_sync")) + IWaitSync = NULL; } static Visual * @@ -768,6 +786,9 @@ EglCompileShaders (void) composite_rectangle_fragment_shader_external); } +/* Forward declaration. */ +static void AddRenderFlag (int); + static Bool EglInitDisplay (void) { @@ -816,6 +837,11 @@ EglInitDisplay (void) CheckExtension (ICreateImage); CheckExtension (IDestroyImage); + /* If both EGL fences and EGL_ANDROID_native_fence_sync are + supported, enable explicit sync. */ + if (ICreateSync && IDupNativeFenceFD) + AddRenderFlag (SupportsExplicitSync); + /* Otherwise, the display has been initialized. */ egl_major = major; egl_minor = minor; @@ -1275,6 +1301,105 @@ TargetAge (RenderTarget target) return -1; } +static RenderFence +ImportFdFence (int fd, Bool *error) +{ + EGLSyncKHR *fence; + EGLint attribs[3]; + + attribs[0] = EGL_SYNC_NATIVE_FENCE_FD_ANDROID; + attribs[1] = fd; + attribs[2] = EGL_NONE; + + /* This fence is supposed to assume ownership over the given file + descriptor. */ + fence = ICreateSync (egl_display, EGL_SYNC_NATIVE_FENCE_ANDROID, + attribs); + + if (fence == EGL_NO_SYNC_KHR) + { + *error = True; + return (RenderFence) NULL; + } + + return (RenderFence) (void *) fence; +} + +static void +WaitFence (RenderFence fence) +{ + /* N.B. that here egl_context must be current, which should always + be true. */ + + if (IWaitSync) + /* This is more asynchronous, as it doesn't wait for the fence + on the CPU. */ + IWaitSync (egl_display, fence.pointer, 0); + else + /* But eglWaitSyncKHR isn't available everywhere. */ + IClientWaitSync (egl_display, fence.pointer, 0, + EGL_FOREVER_KHR); + + /* If either of these requests fail, simply proceed to read from the + protected data. */ +} + +static void +DeleteFence (RenderFence fence) +{ + if (!IDestroySync (egl_display, fence.pointer)) + /* There is no way to continue without leaking memory, and this + shouldn't happen. */ + abort (); +} + +static void +HandleFenceReadable (int fd, void *data, ReadFd *readfd) +{ + XLRemoveReadFd (readfd); + + /* Now destroy the native fence. */ + if (!IDestroySync (egl_display, data)) + abort (); + + /* And close the file descriptor. */ + close (fd); +} + +static int +GetFinishFence (Bool *error) +{ + EGLint attribs; + EGLSyncKHR *fence; + EGLint fd; + + attribs = EGL_NONE; + + /* Create the fence. EGL_SYNC_CONDITION_KHR should default to + EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR, meaning it will signal once + all prior drawing commands complete. */ + fence = ICreateSync (egl_display, EGL_SYNC_NATIVE_FENCE_ANDROID, + &attribs); + + if (fence == EGL_NO_SYNC_KHR) + { + *error = True; + return -1; + } + + /* Obtain the file descriptor. */ + fd = IDupNativeFenceFD (egl_display, fence); + + if (fd == -1) + *error = True; + else + /* Delete the fence after it is signalled. Duplicate the fd, as + it will be closed by the caller. */ + XLAddReadFd (dup (fd), fence, HandleFenceReadable); + + return fd; +} + static RenderFuncs egl_render_funcs = { .init_render_funcs = InitRenderFuncs, @@ -1292,9 +1417,19 @@ static RenderFuncs egl_render_funcs = .reset_transform = ResetTransform, .finish_render = FinishRender, .target_age = TargetAge, + .import_fd_fence = ImportFdFence, + .wait_fence = WaitFence, + .delete_fence = DeleteFence, + .get_finish_fence = GetFinishFence, .flags = ImmediateRelease, }; +static void +AddRenderFlag (int flags) +{ + egl_render_funcs.flags |= flags; +} + static DrmFormat * GetDrmFormats (int *num_formats) { diff --git a/fns.c b/fns.c index 32634fd..d105750 100644 --- a/fns.c +++ b/fns.c @@ -726,7 +726,7 @@ MaybeInstallBusHandler (void) if (bus_handler_installed) return; - bus_handler_installed = 1; + bus_handler_installed = True; memset (&act, 0, sizeof act); /* Install a SIGBUS handler. When a client truncates the file diff --git a/picture_renderer.c b/picture_renderer.c index 895dbc1..1f90fb1 100644 --- a/picture_renderer.c +++ b/picture_renderer.c @@ -340,6 +340,38 @@ TargetAge (RenderTarget target) return 0; } +/* At first glance, it seems like this should be easy to support using + DRI3 and synchronization extension fences. Unfortunately, the + "fences" used by DRI3 are userspace fences implemented by the + xshmfence library, and not Android dma-fences, so there is no + straightforward implementation. */ + +static RenderFence +ImportFdFence (int fd, Bool *error) +{ + *error = True; + return (RenderFence) (XID) None; +} + +static void +WaitFence (RenderFence fence) +{ + /* Unsupported. */ +} + +static void +DeleteFence (RenderFence fence) +{ + /* Unsupported. */ +} + +static int +GetFinishFence (Bool *error) +{ + *error = True; + return -1; +} + static RenderFuncs picture_render_funcs = { .init_render_funcs = InitRenderFuncs, @@ -354,6 +386,10 @@ static RenderFuncs picture_render_funcs = .composite = Composite, .reset_transform = ResetTransform, .target_age = TargetAge, + .import_fd_fence = ImportFdFence, + .wait_fence = WaitFence, + .delete_fence = DeleteFence, + .get_finish_fence = GetFinishFence, .flags = NeverAges, }; diff --git a/renderer.c b/renderer.c index 110b68c..0a74a0e 100644 --- a/renderer.c +++ b/renderer.c @@ -162,6 +162,32 @@ RenderTargetAge (RenderTarget target) return render_funcs.target_age (target); } +RenderFence +RenderImportFdFence (int fd, Bool *error) +{ + /* Fence-related functions must be defined if + SupportExplicitSync is in flags. */ + return render_funcs.import_fd_fence (fd, error); +} + +void +RenderWaitFence (RenderFence fence) +{ + return render_funcs.wait_fence (fence); +} + +void +RenderDeleteFence (RenderFence fence) +{ + return render_funcs.delete_fence (fence); +} + +int +RenderGetFinishFence (Bool *error) +{ + return render_funcs.get_finish_fence (error); +} + DrmFormat * RenderGetDrmFormats (int *n_formats) { diff --git a/run.c b/run.c index 5a897b1..7a282c9 100644 --- a/run.c +++ b/run.c @@ -37,7 +37,7 @@ struct _PollFd /* Callback run with the fd number and data when the fd becomes writable or readable. */ - void (*poll_callback) (int, void *); + void (*poll_callback) (int, void *, PollFd *); /* Data for the callback. */ void *data; @@ -54,7 +54,8 @@ static int num_poll_fd; static PollFd poll_fds; WriteFd * -XLAddWriteFd (int fd, void *data, void (*poll_callback) (int, void *)) +XLAddWriteFd (int fd, void *data, void (*poll_callback) (int, void *, + WriteFd *)) { WriteFd *record; @@ -75,7 +76,8 @@ XLAddWriteFd (int fd, void *data, void (*poll_callback) (int, void *)) } ReadFd * -XLAddReadFd (int fd, void *data, void (*poll_callback) (int, void *)) +XLAddReadFd (int fd, void *data, void (*poll_callback) (int, void *, + ReadFd *)) { WriteFd *record; @@ -278,9 +280,9 @@ RunStep (void) /* Check that pollfds[j] is still valid, and wasn't removed while handling X events. */ && pollfds[j]->write_fd != -1) - /* Then call the write callback. */ + /* Then call the poll callback. */ pollfds[j]->poll_callback (pollfds[j]->write_fd, - pollfds[j]->data); + pollfds[j]->data, pollfds[j]); } } } diff --git a/surface.c b/surface.c index 507bb8b..e5d118a 100644 --- a/surface.c +++ b/surface.c @@ -299,6 +299,16 @@ ClearBuffer (State *state) state->buffer = NULL; } +static void +DoRelease (Surface *surface, ExtBuffer *buffer) +{ + /* Release the buffer now. */ + if (surface->role && !(renderer_flags & ImmediateRelease)) + surface->role->funcs.release_buffer (surface, surface->role, buffer); + else + XLReleaseBuffer (buffer); +} + static void DestroySurface (struct wl_client *client, struct wl_resource *resource) @@ -652,13 +662,7 @@ SavePendingState (Surface *surface) it is a mistake! */ && (surface->cached_state.buffer != surface->current_state.buffer)) - { - if (surface->role && !(renderer_flags & ImmediateRelease)) - surface->role->funcs.release_buffer (surface, surface->role, - surface->cached_state.buffer); - else - XLReleaseBuffer (surface->cached_state.buffer); - } + DoRelease (surface, surface->cached_state.buffer); if (surface->pending_state.buffer) { @@ -745,11 +749,7 @@ TryEarlyRelease (Surface *surface) if (!RenderCanReleaseNow (render_buffer)) return; - /* Release the buffer now. */ - if (surface->role && !(renderer_flags & ImmediateRelease)) - surface->role->funcs.release_buffer (surface, surface->role, buffer); - else - XLReleaseBuffer (buffer); + DoRelease (surface, buffer); /* Set the flag saying that the buffer has been released. */ surface->current_state.pending |= BufferAlreadyReleased; @@ -762,18 +762,12 @@ InternalCommit (Surface *surface, State *pending) if (pending->pending & PendingBuffer) { - if ((surface->current_state.buffer != pending->buffer) - /* The buffer may already released if its contents were - copied, i.e. uploaded to a texture, during updates. */ - && !(surface->current_state.pending & BufferAlreadyReleased) - && surface->current_state.buffer) - { - if (surface->role && !(renderer_flags & ImmediateRelease)) - surface->role->funcs.release_buffer (surface, surface->role, - surface->current_state.buffer); - else - XLReleaseBuffer (surface->current_state.buffer); - } + /* The buffer may already released if its contents were + copied, i.e. uploaded to a texture, during updates. */ + if (!(surface->current_state.pending & BufferAlreadyReleased) + && surface->current_state.buffer + && surface->current_state.buffer != pending->buffer) + DoRelease (surface, surface->current_state.buffer); /* Clear this flag now, since the attached buffer has changed. */ @@ -855,7 +849,8 @@ InternalCommit (Surface *surface, State *pending) } /* Run commit callbacks. This tells synchronous subsurfaces to - update. */ + update, and tells explicit synchronization to wait for any sync + fence. */ RunCommitCallbacks (surface); if (surface->subsurfaces) @@ -863,6 +858,9 @@ InternalCommit (Surface *surface, State *pending) they run in the right order. */ XLSubsurfaceHandleParentCommit (surface); + /* Wait for any sync fence to be triggered before proceeding. */ + XLWaitFence (surface); + if (!surface->role) { XLDefaultCommit (surface); @@ -887,6 +885,24 @@ Commit (struct wl_client *client, struct wl_resource *resource) surface = wl_resource_get_user_data (resource); + /* First, clear the acquire fence if it is set. If a + synchronization object is attached, the following call will then + attach any new fence specified. */ + + if (surface->acquire_fence != -1) + close (surface->acquire_fence); + + /* Release any attached explicit synchronization release callback. + XXX: this is not right with synchronous subsurfaces? */ + + if (surface->release) + XLSyncRelease (surface->release); + + if (surface->synchronization) + /* This is done here so early commit hooks can be run for + i.e. synchronous subsurfaces. */ + XLSyncCommit (surface->synchronization); + if (surface->role && surface->role->funcs.early_commit /* The role chose to postpone the commit for a later time. */ && !surface->role->funcs.early_commit (surface, surface->role)) @@ -1056,6 +1072,14 @@ HandleSurfaceDestroy (struct wl_resource *resource) /* Free the window scaling factor callback. */ XLRemoveScaleChangeCallback (surface->scale_callback_key); + /* If a release is attached, destroy it and its resource. */ + if (surface->release) + XLDestroyRelease (surface->release); + + /* Likewise if a fence is attached. */ + if (surface->acquire_fence != -1) + close (surface->acquire_fence); + FinalizeState (&surface->pending_state); FinalizeState (&surface->current_state); FinalizeState (&surface->cached_state); @@ -1153,6 +1177,9 @@ XLCreateSurface (struct wl_client *client, /* Clear surface output coordinates. */ surface->output_x = INT_MIN; surface->output_y = INT_MIN; + + /* Set the acquire fence fd to -1. */ + surface->acquire_fence = -1; } void diff --git a/xdata.c b/xdata.c index 13a15de..46491b8 100644 --- a/xdata.c +++ b/xdata.c @@ -431,7 +431,7 @@ MaybeFinishDelayedTransfer (ReadTransfer *transfer, } static void -NoticeTransferWritable (int fd, void *data) +NoticeTransferWritable (int fd, void *data, WriteFd *writefd) { ReadTransfer *transfer; TransferInfo *info; @@ -1260,7 +1260,7 @@ TypeFromTarget (Atom target, Bool primary) } static void -NoticeTransferReadable (int fd, void *data) +NoticeTransferReadable (int fd, void *data, ReadFd *readfd) { WriteTransfer *transfer; WriteInfo *info; @@ -1460,7 +1460,7 @@ GetClipboardCallback (WriteTransfer *transfer, Atom target, static void -NoticeConversionTransferReadable (int fd, void *data) +NoticeConversionTransferReadable (int fd, void *data, ReadFd *readfd) { WriteTransfer *transfer; ConversionWriteInfo *info; @@ -1726,7 +1726,7 @@ FinishConversionTransfer (ReadTransfer *transfer, ConversionTransferInfo *info) } static void -NoticeConversionTransferWritable (int fd, void *data) +NoticeConversionTransferWritable (int fd, void *data, WriteFd *writefd) { ConversionTransferInfo *info; ssize_t written;