12to11/renderer.c
oldosfan 713eb811ea Add support for DRM leasing and significantly rework composition code
* 12to11.c (HandleCmdline): Improve messages printed during
-help.
(XLMain): Initialize DRM leasing.
* 12to11.man: Document changes.
* Imakefile (LOCAL_LIBRARIES): Add xcb-randr, xf86drm and
XPresent.
(SRCS): Add drm_lease.c.
(OBJS): Add drm_lease.o.
* atoms.c (names): Add CONNECTOR_ID.
(CONNECTOR_ID): New atom.
(XLInitAtoms): Intern CONNECTOR_ID.
* compositor.h (struct _RenderFuncs): Require event mask to be
passed to target_from_window.  New functions
`set_standard_event_mask', `present_to_window',
`cancel_presentation_callback', and `cancel_presentation'.
(struct _BufferFuncs): Move buffer release machinery here.
(enum _FrameMode): New enum.
* egl.c (TargetFromWindow, SetStandardEventMask,
egl_render_funcs): Adjust functions accordingly.
* frame_clock.c (struct _FrameClock): New fields
`end_frame_called' and `pending_sync_value'.
(HandleEndFrame, PostEndFrame, StartFrame, EndFrame): Clean up
frame synchronization code.  Do not end upon predicted
presentation time if EndFrame was not called in time.
(FreezeForValue): New function.
(XLFrameClockHandleFrameEvent): Defer actually freezing until
StartFrame happens.
(XLFrameClockGetFrameTime): New function.
* icon_surface.c (ReleaseBuffer): Use RenderWaitForIdle.
(RunFrameCallbacks, AfterFrame): Pass frame clock to callbacks.
Use frame time if available.
(XLGetIconSurface): Require wait_for_idle to work.
* output.c (change_hook): New hook.
(XLHandleOneXEventForOutputs): Run hook if set.
(XLOutputSetChangeFunction): New function.
(XLInitRROutputs): Select for RRResourceChangeNotify if
providers are supported.
* picture_renderer.c (struct _PresentRecord)
(struct _BufferActivityRecord, struct _IdleCallback)
(struct _PictureBuffer, struct _PictureTarget)
(struct _DrmFormatInfo, struct _DmaBufRecord)
(struct _PresentCompletionCallback): New record structures.
(all_formats, SendRoundtripMessage, FindBufferActivityRecord)
(RecordBufferActivity, RunIdleCallbacks, MaybeRunIdleCallbacks)
(UnlinkActivityRecord, HandleActivityEvent, InitRenderFuncs)
(TargetFromDrawable, TargetFromPixmap, TargetFromWindow)
(SetStandardEventMask, NoteTargetSize, PictureFromTarget)
(DestroyRenderTarget, FillBoxesWithTransparency)
(ServerRegionFromRegion, ClearRectangle, Composite)
(FindPresentRecord, AllocateRecord, PresentToWindow)
(CancelPresentationCallback, CancelPresentation)
(picture_render_funcs, FindSupportedModifiers, InitDrmFormats)
(PictFormatIsPresentable, BufferFromDmaBuf, FinishDmaBufRecord)
(BufferFromDmaBufAsync, BufferFromShm, BufferFromSinglePixel)
(FreeShmBuffer, FreeDmabufBuffer, FreeSinglePixelBuffer)
(AddIdleCallback, CancelIdleCallback, IsBufferIdle)
(IdleEventPredicate, WaitForIdle, SetNeedWaitForIdle)
(picture_buffer_funcs, HandlePresentCompleteNotify)
(HandlePresentIdleNotify, HandlePresentationEvent)
(HandleOneXEventForPictureRenderer, InitPictureRenderer): Allow
presenting pixmaps directly, and move buffer release tracking
machinery here.
* renderer.c (RenderTargetFromWindow): Update signature.
(RenderPresentToWindow, RenderCancelPresentationCallback)
(RenderCancelPresentation, RenderAddIdleCallback)
(RegisterStaticRenderer): New wrapper functions.
* run.c (HandleOneXEvent): Handle picture renderer events
earlier.
* seat.c (MaybeCreateCursor): Require wait_for_idle.
(ReleaseBuffer): Wait for buffer to become idle on each target
in the cursor ring.
* subcompositor.c (struct _Subcompositor): New callback
`note_frame'.
(SubcompositorSetNoteFrameCallback, NoViewsAfter)
(PresentCompletedCallback): New functions.
(SubcompositorUpdate): Try to present the buffer if possible,
and run completion callbacks.
(SubcompositorFree): Free presentation key.
* surface.c (XLSurfaceRunFrameCallbacksMs): New function.
* text_input.c: Improve commentary.
* xdg-shell.xml: Update from wayland-protocols.
* xdg_surface.c (struct _XdgRole): New fields `pending_frame',
`last_specified_serial'.
(struct _ReleaseLaterRecord): Replace free function with idle
callback key and xdg role pointers.
(RemoveRecord): Delete function.
(FreeRecords): Stop cancelling buffer destroy listener.
(ReleaseLaterExtBufferFunc): Delete function.
(RunFrameCallbacks): Use frame clock time if it is set.
(HandleReleaseLaterMessage): Delete function.
(BufferIdleCallback): New function.
(ReleaseLater): Delete function.
(XLHandleXEventForXdgSurfaces): Stop handling buffer release
events here.
(AckConfigure): Improve debug code and reject duplicate serials.
(Commit): Unfreeze earlier; also, in general...
(NoteFrame): Move frame handling implementation here.
(ReleaseBuffer, Subframe, EndSubframe, AfterFrame, ResizeForMap)
(SelectExtraEvents): Set standard event mask.
(XLGetXdgSurface, XLXdgRoleSendConfigure): ...Replace frame
clock logic with that in NoteFrame.
2022-10-12 12:53:09 +00:00

485 lines
11 KiB
C

/* Wayland compositor running on top of an X server.
Copyright (C) 2022 to various contributors.
This file is part of 12to11.
12to11 is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
12to11 is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with 12to11. If not, see <https://www.gnu.org/licenses/>. */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "compositor.h"
/* Structure defining a registered renderer. */
typedef struct _Renderer Renderer;
struct _Renderer
{
/* The next renderer in the chain of available renderers. */
Renderer *next;
/* The name of this renderer. */
const char *name;
/* Set of buffer manipulation functions. */
BufferFuncs *buffer_funcs;
/* Set of rendering manipulation functions. */
RenderFuncs *render_funcs;
};
/* Chain of all renderers. */
static Renderer *renderers;
/* The selected buffer functions. */
static BufferFuncs buffer_funcs;
/* The selected render functions. */
static RenderFuncs render_funcs;
/* Flags of the selected renderer. */
int renderer_flags;
static Renderer *
AllocateRenderer (void)
{
static Renderer renderers[2];
static int used;
if (used < ArrayElements (renderers))
return &renderers[used++];
/* When adding a new renderer, make sure to update the number of
renderers in the above array. */
abort ();
}
RenderTarget
RenderTargetFromWindow (Window window, unsigned long standard_event_mask)
{
return render_funcs.target_from_window (window, standard_event_mask);
}
RenderTarget
RenderTargetFromPixmap (Pixmap pixmap)
{
return render_funcs.target_from_pixmap (pixmap);
}
void
RenderSetStandardEventMask (RenderTarget target,
unsigned long standard_event_mask)
{
render_funcs.set_standard_event_mask (target, standard_event_mask);
}
void
RenderNoteTargetSize (RenderTarget target, int width, int height)
{
if (!render_funcs.note_target_size)
/* This function can be NULL. */
return;
render_funcs.note_target_size (target, width, height);
}
Picture
RenderPictureFromTarget (RenderTarget target)
{
return render_funcs.picture_from_target (target);
}
void
RenderFreePictureFromTarget (Picture picture)
{
render_funcs.free_picture_from_target (picture);
}
void
RenderDestroyRenderTarget (RenderTarget target)
{
render_funcs.destroy_render_target (target);
}
void
RenderStartRender (RenderTarget target)
{
if (render_funcs.start_render)
render_funcs.start_render (target);
}
void
RenderFillBoxesWithTransparency (RenderTarget target, pixman_box32_t *boxes,
int nboxes, int min_x, int min_y)
{
render_funcs.fill_boxes_with_transparency (target, boxes,
nboxes, min_x, min_y);
}
void
RenderClearRectangle (RenderTarget target, int x, int y, int width, int height)
{
render_funcs.clear_rectangle (target, x, y, width, height);
}
void
RenderComposite (RenderBuffer source, RenderTarget target, Operation op,
int src_x, int src_y, int x, int y, int width, int height,
DrawParams *draw_params)
{
render_funcs.composite (source, target, op, src_x, src_y, x, y,
width, height, draw_params);
}
void
RenderFinishRender (RenderTarget target, pixman_region32_t *damage)
{
if (render_funcs.finish_render)
render_funcs.finish_render (target, damage);
}
int
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);
}
PresentCompletionKey
RenderPresentToWindow (RenderTarget target, RenderBuffer source,
pixman_region32_t *damage,
PresentCompletionFunc callback, void *data)
{
if (!render_funcs.present_to_window)
return NULL;
return render_funcs.present_to_window (target, source,
damage, callback,
data);
}
void
RenderCancelPresentationCallback (PresentCompletionKey key)
{
if (!render_funcs.cancel_presentation_callback)
return;
render_funcs.cancel_presentation_callback (key);
}
void
RenderCancelPresentation (RenderTarget target)
{
if (!render_funcs.cancel_presentation)
return;
render_funcs.cancel_presentation (target);
}
DrmFormat *
RenderGetDrmFormats (int *n_formats)
{
return buffer_funcs.get_drm_formats (n_formats);
}
dev_t
RenderGetRenderDevice (Bool *error)
{
return buffer_funcs.get_render_device (error);
}
ShmFormat *
RenderGetShmFormats (int *n_formats)
{
return buffer_funcs.get_shm_formats (n_formats);
}
RenderBuffer
RenderBufferFromDmaBuf (DmaBufAttributes *attributes, Bool *error)
{
return buffer_funcs.buffer_from_dma_buf (attributes, error);
}
void
RenderBufferFromDmaBufAsync (DmaBufAttributes *attributes,
DmaBufSuccessFunc success_func,
DmaBufFailureFunc failure_func,
void *callback_data)
{
return buffer_funcs.buffer_from_dma_buf_async (attributes,
success_func,
failure_func,
callback_data);
}
RenderBuffer
RenderBufferFromShm (SharedMemoryAttributes *attributes, Bool *error)
{
return buffer_funcs.buffer_from_shm (attributes, error);
}
Bool
RenderValidateShmParams (uint32_t format, uint32_t width, uint32_t height,
int32_t offset, int32_t stride, size_t pool_size)
{
return buffer_funcs.validate_shm_params (format, width, height,
offset, stride, pool_size);
}
RenderBuffer
RenderBufferFromSinglePixel (uint32_t red, uint32_t green, uint32_t blue,
uint32_t alpha, Bool *error)
{
return buffer_funcs.buffer_from_single_pixel (red, green, blue,
alpha, error);
}
void
RenderFreeShmBuffer (RenderBuffer buffer)
{
return buffer_funcs.free_shm_buffer (buffer);
}
void
RenderFreeDmabufBuffer (RenderBuffer buffer)
{
return buffer_funcs.free_dmabuf_buffer (buffer);
}
void
RenderFreeSinglePixelBuffer (RenderBuffer buffer)
{
return buffer_funcs.free_dmabuf_buffer (buffer);
}
void
RenderUpdateBufferForDamage (RenderBuffer buffer, pixman_region32_t *damage,
DrawParams *params)
{
if (!buffer_funcs.update_buffer_for_damage)
return;
buffer_funcs.update_buffer_for_damage (buffer, damage, params);
}
Bool
RenderCanReleaseNow (RenderBuffer buffer)
{
return buffer_funcs.can_release_now (buffer);
}
IdleCallbackKey
RenderAddIdleCallback (RenderBuffer buffer, RenderTarget target,
BufferIdleFunc function, void *data)
{
return buffer_funcs.add_idle_callback (buffer, target, function, data);
}
void
RenderCancelIdleCallback (IdleCallbackKey key)
{
return buffer_funcs.cancel_idle_callback (key);
}
Bool
RenderIsBufferIdle (RenderBuffer buffer, RenderTarget target)
{
return buffer_funcs.is_buffer_idle (buffer, target);
}
void
RenderWaitForIdle (RenderBuffer buffer, RenderTarget target)
{
if (!buffer_funcs.wait_for_idle)
return;
buffer_funcs.wait_for_idle (buffer, target);
}
void
RenderSetNeedWaitForIdle (RenderTarget target)
{
if (!buffer_funcs.set_need_wait_for_idle)
return;
buffer_funcs.set_need_wait_for_idle (target);
}
void
RegisterStaticRenderer (const char *name,
RenderFuncs *render_funcs,
BufferFuncs *buffer_funcs)
{
Renderer *renderer;
renderer = AllocateRenderer ();
renderer->next = renderers;
renderer->buffer_funcs = buffer_funcs;
renderer->render_funcs = render_funcs;
renderer->name = name;
renderers = renderer;
}
static Bool
InstallRenderer (Renderer *renderer)
{
buffer_funcs = *renderer->buffer_funcs;
render_funcs = *renderer->render_funcs;
/* Now, initialize the renderer by calling its init functions. */
if (!render_funcs.init_render_funcs ())
/* If this returns false, then the renderer cannot be used. */
return False;
/* Next, initialize the colormap before init_buffer_funcs. */
compositor.colormap
= XCreateColormap (compositor.display,
DefaultRootWindow (compositor.display),
compositor.visual, AllocNone);
buffer_funcs.init_buffer_funcs ();
/* Finally, set the flags. The idea is that init_render_funcs
and/or init_buffer_funcs might change this, so we set them from
renderer->render_funcs. */
renderer_flags = renderer->render_funcs->flags;
return True;
}
static const char *
ReadRendererResource (void)
{
XrmDatabase rdb;
XrmName namelist[3];
XrmClass classlist[3];
XrmValue value;
XrmRepresentation type;
rdb = XrmGetDatabase (compositor.display);
if (!rdb)
return NULL;
namelist[1] = XrmStringToQuark ("renderer");
namelist[0] = app_quark;
namelist[2] = NULLQUARK;
classlist[1] = XrmStringToQuark ("Renderer");
classlist[0] = resource_quark;
classlist[2] = NULLQUARK;
if (XrmQGetResource (rdb, namelist, classlist,
&type, &value)
&& type == QString)
return (const char *) value.addr;
return NULL;
}
static void
PickRenderer (void)
{
const char *selected;
Renderer *renderer;
/* Install and initialize the first renderer in the list. */
XLAssert (renderers != NULL);
selected = getenv ("RENDERER");
if (!selected)
selected = ReadRendererResource ();
if (selected)
{
/* If selected is "help", print each renderer and exit. */
if (!strcmp (selected, "help"))
{
fprintf (stderr, "The following rendering backends can be used:\n");
for (renderer = renderers; renderer; renderer = renderer->next)
fprintf (stderr, " %s\n", renderer->name);
exit (0);
}
/* Otherwise, look for a renderer matching the given name and
install it. */
for (renderer = renderers; renderer; renderer = renderer->next)
{
if (!strcmp (renderer->name, selected))
{
if (!InstallRenderer (renderer))
{
fprintf (stderr, "Failed to initialize renderer %s, "
"defaulting to %s instead.\n", selected,
renderers->name);
goto fall_back;
}
return;
}
}
/* Fall back to the default renderer. */
fprintf (stderr, "Defaulting to renderer %s, as %s was not found\n",
renderers->name, selected);
fall_back:
}
if (!InstallRenderer (renderers))
abort ();
}
void
InitRenderers (void)
{
#ifdef HaveEglSupport
InitEgl ();
#endif
InitPictureRenderer ();
PickRenderer ();
}