12to11/run.c
oldosfan b4ee06589e Add support for EGL, for YUV image formats
EGL support is still incomplete; stuff like scaling is missing.

* 12to11.c (PickVisual, XLMain): Remove function.  Initialize
renderers, and rely on that to initialize the visuals.
* 12to11.man: Document new environment variables.
* Imakefile (SRCS, OBJS): Add picture_renderer.c and renderer.c
and their associated objects.
(GENHEADERS): New variable for generated headers.
(EGL_SRCS, EGL_OBJS): New variables.
(LOCAL_LIBRARIES, SRCS, OBJS, DEFINES): [HaveEglSupport]: Add
EGL defines, libraries, and objects.:(shaders.h): New rule.
(depend, cleandir): Depend on generated headers and SRCs.
$($(OBJS)): Depend on $(GENHEADERS).
* README: Write how to build with EGL support and update content
descriptions.
* buffer.c (XLPictureFromBuffer): Delete function.
(XLRenderBufferFromBuffer): New function.
(XLPixmapFromBuffer): Delete function.
* compositor.h (enum _Operation, struct _SharedMemoryAttributes)
(struct _DmaBufAttributes, union _RenderTarget)
(union _RenderBuffer, struct _RenderFuncs, struct _DrmFormat)
(struct _ShmFormat, struct _BufferFuncs, struct
_ExtBufferFuncs): New structures.
(Fallthrough): New define.  Define to __attribute__
((fallthrough)) wherever supported.  Replace uses of Picture
with RenderBuffer.
* dmabuf.c (struct _DrmFormatInfo): Remove structures.
(struct _BufferParams): Remove link.
(struct _Buffer): Replace pixmap and picture with render buffer
object.
(dri3_opcode, all_formats, pending_success, next_roundtrip_id)
(round_trip_window): Delete.
(ReleaseBufferParams, HandleParamsResourceDestroy, ForceRoundTrip)
(DepthForFormat, XLHandleErrorForDmabuf, PictFormatForFormat)
(DestroyBacking, GetPictureFunc, GetPixmapFunc, GetBufferFunc)
(CreateBufferFor, ModifierHigh, FinishBufferCreation)
(XLHandleOneXEventForDmabuf, CreateHeader, Create, CreateImmed)
(FindFormatMatching, FindSupportedModifiers, FindSupportedFormats)
(SendSupportedFormats, HandleBind, InitDrmDevice, WriteFormatTable)
(ReallyInitDmabuf, ReadSupportedFormats, XLInitDmabuf): Remove
various functions and reimplement as a wrapper around the
renderer abstraction, instead of DRI3.
* fns.c (struct _Busfault): New structure.
(busfault_tree, bus_handler_installed): New variables.
(GetHeight, FixHeights, RotateLeft, RotateRight, RebalanceBusfault)
(RecordBusfault, DetectBusfault, DeleteMin, RemoveBusfault)
(HandleBusfault, MaybeInstallBusHandler, BlockSigbus)
(UnblockSigbus, XLRecordBusfault, XLRemoveBusfaults): New
functions to store non-overlapping regions of mapped memory in
an AVL tree, and to ignore SIGBUS events that trap within.
* icon_surface.c (struct _IconSurface): Replace picture with
rendering target.
(ReleaseBacking, XLGetIconSurface): Use rendering targets
instead of pictures.
* libraries.def: Add defines for EGL.
* run.c (HandleOneXEvent): Replace old dmabuf code with renderer
code.
* seat.c (CursorFromRole, PictureForCursor, ApplyCursor)
(UpdateCursorFromSubcompositor, Subframe, EndSubframe): Rewrite
cursor code to use rendering targets and not pictures.
* shm.c (Buffer, DereferencePool): Remove SIGBUS protection.
(DereferenceBuffer): Reimplement in terms of renderer functions.
(GetPictureFunc): Delete function.
(GetBufferFunc): New function.
(GetPixmapFunc): Delete function.
(PrintBuffer): Remove now-broken implementation.
(DepthForFormat, PictFormatForFormat): Delete functions, as they
are now part of the rendering backend.
(IsFormatSupported): New function.
(CreateBuffer): Reimplement in terms of renderer functions.
(ResizePool): Change SIGBUS protection for resize.
(CreatePool): Protect buffer data from SIGBUS should a client
truncate the file.
(PostFormats): Reimplement in terms of RenderGetShmFormats.
(XLInitShm): Stop initializing MIT-SHM.
* subcompositor.c (IsTargetAttached): New flag and associated
macros.
(struct _View): Remove useless field.
(struct _Subcompositor): Change target to RenderTarget.  Add
fields for prior damage.
(MakeSubcompositor): Initialize new fields.
(SubcompositorSetTarget): Accept RenderTarget, not picture, and
set target attached flag.
(ViewGetTransform): Delete function.
(ViewApplyTransform): New function.
(FillBoxesWithTransparency): Reimplement in terms of renderer
functions.
(StorePreviousDamage): New function.
(SubcompositorUpdate): Reimplement in terms of renderer
functions.  Also, learn to deal with situations where the buffer
reflects the state 1 to 2 swaps ago.
(SubcompositorExpose): Reimplement in terms of renderer
functions.
(SubcompositorFree): Free new fields.
(SubcompositorInit): Remove no longer required initialization of
identity matrix.
* xdata.c (ReceiveBody): Fix coding style.
* xdg_surface.c (struct _XdgRole, ReleaseBacking,
XLGetXdgSurface): Switch from pictures to RenderTargets.
* xerror.c (ErrorHandler): Handle errors for picture renderer
instead of dmabuf.c.
2022-09-23 08:44:37 +00:00

298 lines
6.8 KiB
C

/* Wayland compositor running on top of an X serer.
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 <sys/param.h>
#include <stdio.h>
#include <poll.h>
#include <alloca.h>
#include "compositor.h"
typedef struct _PollFd PollFd;
struct _PollFd
{
/* The next and last writable fd in this chain. */
PollFd *next, *last;
/* The file descriptor itself. */
int write_fd;
/* Callback run with the fd number and data when the fd becomes
writable or readable. */
void (*poll_callback) (int, void *);
/* Data for the callback. */
void *data;
/* The direction; 1 means write, 0 means read. */
int direction;
};
/* Number of file descriptors for which we are waiting for something
to be written. */
static int num_poll_fd;
/* Linked list of file descriptors and write callbacks. */
static PollFd poll_fds;
WriteFd *
XLAddWriteFd (int fd, void *data, void (*poll_callback) (int, void *))
{
WriteFd *record;
record = XLMalloc (sizeof *record);
record->next = poll_fds.next;
record->last = &poll_fds;
record->write_fd = fd;
record->poll_callback = poll_callback;
record->data = data;
record->direction = 1;
poll_fds.next->last = record;
poll_fds.next = record;
num_poll_fd++;
return record;
}
ReadFd *
XLAddReadFd (int fd, void *data, void (*poll_callback) (int, void *))
{
WriteFd *record;
record = XLMalloc (sizeof *record);
record->next = poll_fds.next;
record->last = &poll_fds;
record->write_fd = fd;
record->poll_callback = poll_callback;
record->data = data;
record->direction = 0;
poll_fds.next->last = record;
poll_fds.next = record;
num_poll_fd++;
return record;
}
void
XLRemoveWriteFd (WriteFd *fd)
{
/* Mark this record as invalid. Records cannot safely change while
the event loop is in progress, so we remove all invalid records
immediately before polling. */
fd->write_fd = -1;
}
void
XLRemoveReadFd (ReadFd *fd)
{
/* Mark this record as invalid. Records cannot safely change while
the event loop is in progress, so we remove all invalid records
immediately before polling. */
fd->write_fd = -1;
}
static void
RemoveWriteFd (WriteFd *fd)
{
fd->next->last = fd->last;
fd->last->next = fd->next;
num_poll_fd--;
XLFree (fd);
}
static void
HandleOneXEvent (XEvent *event)
{
XLHandleOneXEventForDnd (event);
if (XLHandleXEventForXdgSurfaces (event))
return;
if (XLHandleXEventForXdgToplevels (event))
return;
if (XLHandleXEventForXdgPopups (event))
return;
if (XLHandleOneXEventForSeats (event))
return;
if (XLHandleOneXEventForIconSurfaces (event))
return;
#if 0
if (XLHandleOneXEventForDmabuf (event))
return;
#endif
if (HandleOneXEventForPictureRenderer (event))
return;
if (XLHandleOneXEventForXData (event))
return;
if (XLHandleOneXEventForOutputs (event))
return;
if (XLHandleOneXEventForXSettings (event))
return;
}
static void
ReadXEvents (void)
{
XEvent event;
while (XPending (compositor.display))
{
XNextEvent (compositor.display, &event);
/* We failed to get event data for a generic event, so there's
no point in continuing. */
if (event.type == GenericEvent
&& !XGetEventData (compositor.display, &event.xcookie))
continue;
if (!HookSelectionEvent (&event))
HandleOneXEvent (&event);
if (event.type == GenericEvent)
XFreeEventData (compositor.display, &event.xcookie);
}
}
static void
RunStep (void)
{
int x_connection, wl_connection, rc, i, j;
struct timespec timeout;
struct pollfd *fds;
PollFd **pollfds, *item, *last;
XFlush (compositor.display);
wl_display_flush_clients (compositor.wl_display);
fds = alloca (sizeof fds * (num_poll_fd + 2));
/* This is used as an optimization to not have to loop over the
entire descriptor list twice. */
pollfds = alloca (sizeof *pollfds * num_poll_fd);
/* Run timers. This, and draining selection transfers, must be done
before setting up poll file descriptors, since timer callbacks
can change the write fd list. */
timeout = TimerCheck ();
/* Drain complete selection transfers. */
FinishTransfers ();
x_connection = ConnectionNumber (compositor.display);
wl_connection = wl_event_loop_get_fd (compositor.wl_event_loop);
fds[0].fd = x_connection;
fds[1].fd = wl_connection;
fds[0].events = POLLIN;
fds[1].events = POLLIN;
fds[0].revents = 0;
fds[1].revents = 0;
/* Copy valid write file descriptors into the pollfd array, while
removing invalid ones. */
item = poll_fds.next;
i = 0;
while (item != &poll_fds)
{
last = item;
item = item->next;
if (last->write_fd == -1)
{
/* Remove this invalid pollfd. */
RemoveWriteFd (last);
continue;
}
/* Otherwise, add the fd and bump i. */
fds[2 + i].fd = last->write_fd;
fds[2 + i].events = POLLOUT;
fds[2 + i].revents = 0;
pollfds[i] = last;
if (!last->direction)
/* See https://www.greenend.org.uk/rjk/tech/poll.html for why
POLLHUP. */
fds[2 + i].events = POLLIN | POLLHUP;
i += 1;
}
/* Handle any events already in the queue, which can happen if
something inside ReadXEvents synced. */
if (XEventsQueued (compositor.display, QueuedAlready))
{
ReadXEvents ();
XFlush (compositor.display);
wl_display_flush_clients (compositor.wl_display);
}
rc = ppoll (fds, 2 + i, &timeout, NULL);
if (rc > 0)
{
if (fds[0].revents & POLLIN)
ReadXEvents ();
if (fds[1].revents & POLLIN)
wl_event_loop_dispatch (compositor.wl_event_loop, -1);
/* Now see how many write fds are set. */
for (j = 0; j < i; ++j)
{
if (fds[2 + j].revents & (POLLOUT | POLLIN | POLLHUP)
/* 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. */
pollfds[j]->poll_callback (pollfds[j]->write_fd,
pollfds[j]->data);
}
}
}
void __attribute__ ((noreturn))
XLRunCompositor (void)
{
/* Set up the sentinel node for file descriptors that are being
polled from. */
poll_fds.next = &poll_fds;
poll_fds.last = &poll_fds;
while (true)
RunStep ();
}