forked from 12to11/12to11

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.
534 lines
12 KiB
C
534 lines
12 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 <stdio.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
|
|
#include <sys/mman.h>
|
|
|
|
#include "compositor.h"
|
|
|
|
typedef struct _Pool
|
|
{
|
|
/* The file descriptor corresponding to this pool. */
|
|
int fd;
|
|
|
|
/* The size of this pool. */
|
|
size_t size;
|
|
|
|
/* The number of references to this pool. */
|
|
int refcount;
|
|
|
|
/* Pointer to the raw data in this pool. */
|
|
void *data;
|
|
|
|
/* The wl_resource corresponding to this pool. */
|
|
struct wl_resource *resource;
|
|
} Pool;
|
|
|
|
typedef struct _Buffer
|
|
{
|
|
/* The ExtBuffer associated with this buffer. */
|
|
ExtBuffer buffer;
|
|
|
|
/* The rendering buffer associated with this buffer. */
|
|
RenderBuffer render_buffer;
|
|
|
|
/* The width and height of this buffer. */
|
|
unsigned int width, height;
|
|
|
|
/* The wl_resource corresponding to this buffer. */
|
|
struct wl_resource *resource;
|
|
|
|
/* The pool corresponding to this buffer. */
|
|
Pool *pool;
|
|
|
|
/* The number of references to this buffer. */
|
|
int refcount;
|
|
} Buffer;
|
|
|
|
/* List of all resources for our shared memory global. */
|
|
static XLList *all_shms;
|
|
|
|
/* The shared memory global. */
|
|
static struct wl_global *global_shm;
|
|
|
|
static void
|
|
DereferencePool (Pool *pool)
|
|
{
|
|
if (--pool->refcount)
|
|
return;
|
|
|
|
munmap (pool->data, pool->size);
|
|
|
|
/* Cancel the busfault trap. */
|
|
|
|
if (pool->data != (void *) -1
|
|
/* If the pool is of size 0, no busfault was installed. */
|
|
&& pool->size)
|
|
XLRemoveBusfault (pool->data);
|
|
|
|
close (pool->fd);
|
|
XLFree (pool);
|
|
}
|
|
|
|
static void
|
|
RetainPool (Pool *pool)
|
|
{
|
|
pool->refcount++;
|
|
}
|
|
|
|
static void
|
|
RetainBuffer (Buffer *buffer)
|
|
{
|
|
buffer->refcount++;
|
|
}
|
|
|
|
static void
|
|
DereferenceBuffer (Buffer *buffer)
|
|
{
|
|
if (--buffer->refcount)
|
|
return;
|
|
|
|
RenderFreeShmBuffer (buffer->render_buffer);
|
|
DereferencePool (buffer->pool);
|
|
|
|
ExtBufferDestroy (&buffer->buffer);
|
|
XLFree (buffer);
|
|
}
|
|
|
|
static void
|
|
ReleaseBufferFunc (ExtBuffer *buffer)
|
|
{
|
|
if (((Buffer *) buffer)->resource)
|
|
wl_buffer_send_release (((Buffer *) buffer)->resource);
|
|
}
|
|
|
|
static void
|
|
RetainBufferFunc (ExtBuffer *buffer)
|
|
{
|
|
RetainBuffer ((Buffer *) buffer);
|
|
}
|
|
|
|
static void
|
|
DereferenceBufferFunc (ExtBuffer *buffer)
|
|
{
|
|
DereferenceBuffer ((Buffer *) buffer);
|
|
}
|
|
|
|
static RenderBuffer
|
|
GetBufferFunc (ExtBuffer *buffer)
|
|
{
|
|
return ((Buffer *) buffer)->render_buffer;
|
|
}
|
|
|
|
static unsigned int
|
|
WidthFunc (ExtBuffer *buffer)
|
|
{
|
|
return ((Buffer *) buffer)->width;
|
|
}
|
|
|
|
static unsigned int
|
|
HeightFunc (ExtBuffer *buffer)
|
|
{
|
|
return ((Buffer *) buffer)->height;
|
|
}
|
|
|
|
static void
|
|
DestroyBuffer (struct wl_client *client, struct wl_resource *resource)
|
|
{
|
|
wl_resource_destroy (resource);
|
|
}
|
|
|
|
static void
|
|
PrintBuffer (Buffer *buffer)
|
|
{
|
|
/* Not implemented. */
|
|
}
|
|
|
|
static void
|
|
PrintBufferFunc (ExtBuffer *buffer)
|
|
{
|
|
PrintBuffer ((Buffer *) buffer);
|
|
}
|
|
|
|
|
|
static void
|
|
HandleBufferResourceDestroy (struct wl_resource *resource)
|
|
{
|
|
Buffer *buffer;
|
|
|
|
buffer = wl_resource_get_user_data (resource);
|
|
buffer->resource = NULL;
|
|
|
|
DereferenceBuffer (buffer);
|
|
}
|
|
|
|
static const struct wl_buffer_interface wl_shm_buffer_impl =
|
|
{
|
|
.destroy = DestroyBuffer,
|
|
};
|
|
|
|
static Bool
|
|
IsFormatSupported (uint32_t format)
|
|
{
|
|
ShmFormat *formats;
|
|
int nformats, i;
|
|
|
|
formats = RenderGetShmFormats (&nformats);
|
|
|
|
for (i = 0; i < nformats; ++i)
|
|
{
|
|
if (formats[i].format == format)
|
|
return True;
|
|
}
|
|
|
|
return False;
|
|
}
|
|
|
|
static void
|
|
CreateBuffer (struct wl_client *client, struct wl_resource *resource,
|
|
uint32_t id, int32_t offset, int32_t width, int32_t height,
|
|
int32_t stride, uint32_t format)
|
|
{
|
|
Pool *pool;
|
|
Buffer *buffer;
|
|
RenderBuffer render_buffer;
|
|
SharedMemoryAttributes attrs;
|
|
Bool failure;
|
|
|
|
if (!IsFormatSupported (format))
|
|
{
|
|
wl_resource_post_error (resource, WL_SHM_ERROR_INVALID_FORMAT,
|
|
"the specified format is not supported");
|
|
return;
|
|
}
|
|
|
|
pool = wl_resource_get_user_data (resource);
|
|
|
|
if (!RenderValidateShmParams (format, width, height,
|
|
offset, stride, pool->size))
|
|
{
|
|
wl_resource_post_error (resource, WL_SHM_ERROR_INVALID_STRIDE,
|
|
"invalid offset or stride, or pool too small");
|
|
return;
|
|
}
|
|
|
|
if (width > 32768 || height > 32768)
|
|
{
|
|
/* X doesn't support larger drawables. */
|
|
wl_resource_post_no_memory (resource);
|
|
return;
|
|
}
|
|
|
|
if (width < 1 || height < 1)
|
|
{
|
|
/* X doesn't support smaller drawables. */
|
|
wl_resource_post_error (resource, WL_SHM_ERROR_INVALID_STRIDE,
|
|
"invalid size, this server does not support"
|
|
" zero-width drawables");
|
|
return;
|
|
}
|
|
|
|
buffer = XLSafeMalloc (sizeof *buffer);
|
|
|
|
if (!buffer)
|
|
{
|
|
wl_resource_post_no_memory (resource);
|
|
return;
|
|
}
|
|
|
|
memset (buffer, 0, sizeof *buffer);
|
|
buffer->resource = wl_resource_create (client, &wl_buffer_interface,
|
|
wl_resource_get_version (resource),
|
|
id);
|
|
|
|
if (!buffer->resource)
|
|
{
|
|
wl_resource_post_no_memory (resource);
|
|
XLFree (buffer);
|
|
return;
|
|
}
|
|
|
|
attrs.format = format;
|
|
attrs.offset = offset;
|
|
attrs.width = width;
|
|
attrs.height = height;
|
|
attrs.stride = stride;
|
|
attrs.fd = pool->fd;
|
|
|
|
/* Pass a reference instead of the pointer itself. The pool will
|
|
stay valid as long as the buffer is still alive, and the data
|
|
pointer can change if the client resizes the pool. */
|
|
attrs.data = &pool->data;
|
|
attrs.pool_size = pool->size;
|
|
|
|
/* Now, create the renderer buffer. */
|
|
failure = False;
|
|
render_buffer = RenderBufferFromShm (&attrs, &failure);
|
|
|
|
/* If a platform specific error happened, fail now. */
|
|
if (failure)
|
|
{
|
|
wl_resource_destroy (buffer->resource);
|
|
XLFree (buffer);
|
|
wl_resource_post_error (resource, WL_SHM_ERROR_INVALID_FD,
|
|
"unknown error creating buffer");
|
|
return;
|
|
}
|
|
|
|
buffer->render_buffer = render_buffer;
|
|
buffer->width = width;
|
|
buffer->height = height;
|
|
buffer->pool = pool;
|
|
buffer->refcount = 1;
|
|
|
|
/* Initialize function pointers. */
|
|
buffer->buffer.funcs.retain = RetainBufferFunc;
|
|
buffer->buffer.funcs.dereference = DereferenceBufferFunc;
|
|
buffer->buffer.funcs.get_buffer = GetBufferFunc;
|
|
buffer->buffer.funcs.width = WidthFunc;
|
|
buffer->buffer.funcs.height = HeightFunc;
|
|
buffer->buffer.funcs.release = ReleaseBufferFunc;
|
|
buffer->buffer.funcs.print_buffer = PrintBufferFunc;
|
|
|
|
RetainPool (pool);
|
|
|
|
wl_resource_set_implementation (buffer->resource,
|
|
&wl_shm_buffer_impl,
|
|
buffer,
|
|
HandleBufferResourceDestroy);
|
|
}
|
|
|
|
static void
|
|
HandlePoolResourceDestroy (struct wl_resource *resource)
|
|
{
|
|
Pool *pool;
|
|
|
|
pool = wl_resource_get_user_data (resource);
|
|
DereferencePool (pool);
|
|
}
|
|
|
|
static void
|
|
DestroyPool (struct wl_client *client, struct wl_resource *resource)
|
|
{
|
|
wl_resource_destroy (resource);
|
|
}
|
|
|
|
static void
|
|
ResizePool (struct wl_client *client, struct wl_resource *resource,
|
|
int32_t size)
|
|
{
|
|
Pool *pool;
|
|
void *data;
|
|
|
|
pool = wl_resource_get_user_data (resource);
|
|
|
|
if (size == pool->size)
|
|
/* There is no need to do anything, since the pool is still the
|
|
same size. */
|
|
return;
|
|
|
|
if (size < pool->size)
|
|
{
|
|
wl_resource_post_error (resource, WL_SHM_ERROR_INVALID_FD,
|
|
"shared memory pools cannot be shrunk");
|
|
return;
|
|
}
|
|
|
|
data = mremap (pool->data, pool->size, size, MREMAP_MAYMOVE);
|
|
|
|
if (data == MAP_FAILED)
|
|
{
|
|
wl_resource_post_error (resource, WL_SHM_ERROR_INVALID_FD,
|
|
"mremap: %s", strerror (errno));
|
|
return;
|
|
}
|
|
|
|
/* Now cancel the existing bus fault handler, should it have been
|
|
installed. */
|
|
if (pool->size)
|
|
XLRemoveBusfault (pool->data);
|
|
|
|
pool->size = size;
|
|
pool->data = data;
|
|
|
|
/* And add a new handler. */
|
|
if (pool->size)
|
|
XLRecordBusfault (pool->data, pool->size);
|
|
}
|
|
|
|
static const struct wl_shm_pool_interface wl_shm_pool_impl =
|
|
{
|
|
.destroy = DestroyPool,
|
|
.resize = ResizePool,
|
|
.create_buffer = CreateBuffer,
|
|
};
|
|
|
|
static void
|
|
HandleResourceDestroy (struct wl_resource *resource)
|
|
{
|
|
all_shms = XLListRemove (all_shms, resource);
|
|
}
|
|
|
|
static void
|
|
CreatePool (struct wl_client *client, struct wl_resource *resource,
|
|
uint32_t id, int32_t fd, int32_t size)
|
|
{
|
|
Pool *pool;
|
|
|
|
pool = XLSafeMalloc (sizeof *pool);
|
|
|
|
if (!pool)
|
|
wl_resource_post_no_memory (resource);
|
|
|
|
memset (pool, 0, sizeof *pool);
|
|
|
|
pool->resource = wl_resource_create (client, &wl_shm_pool_interface,
|
|
wl_resource_get_version (resource),
|
|
id);
|
|
|
|
/* There are no references to this pool yet. */
|
|
if (!pool->resource)
|
|
{
|
|
XLFree (pool);
|
|
wl_resource_post_no_memory (resource);
|
|
|
|
return;
|
|
}
|
|
|
|
pool->data = mmap (NULL, size, PROT_READ, MAP_SHARED, fd, 0);
|
|
|
|
if (pool->data == (void *) -1)
|
|
{
|
|
wl_resource_destroy (pool->resource);
|
|
XLFree (pool);
|
|
wl_resource_post_error (resource, WL_SHM_ERROR_INVALID_FD,
|
|
"mmap: %s", strerror (errno));
|
|
|
|
return;
|
|
}
|
|
|
|
wl_resource_set_implementation (pool->resource, &wl_shm_pool_impl,
|
|
pool, HandlePoolResourceDestroy);
|
|
|
|
pool->size = size;
|
|
|
|
/* Begin trapping SIGBUS from this pool. The client may truncate
|
|
the file without telling us, in which case accessing its contents
|
|
will cause crashes. */
|
|
if (pool->size)
|
|
XLRecordBusfault (pool->data, pool->size);
|
|
|
|
pool->fd = fd;
|
|
pool->refcount = 1;
|
|
|
|
return;
|
|
}
|
|
|
|
static const struct wl_shm_interface wl_shm_impl =
|
|
{
|
|
.create_pool = CreatePool,
|
|
};
|
|
|
|
static void
|
|
PostFormats (struct wl_resource *resource)
|
|
{
|
|
ShmFormat *formats;
|
|
int nformats, i;
|
|
|
|
formats = RenderGetShmFormats (&nformats);
|
|
|
|
for (i = 0; i < nformats; ++i)
|
|
wl_shm_send_format (resource, formats[i].format);
|
|
}
|
|
|
|
static void
|
|
HandleBind (struct wl_client *client, void *data,
|
|
uint32_t version, uint32_t id)
|
|
{
|
|
struct wl_resource *resource;
|
|
|
|
resource = wl_resource_create (client, &wl_shm_interface,
|
|
version, id);
|
|
|
|
if (!resource)
|
|
{
|
|
wl_client_post_no_memory (client);
|
|
return;
|
|
}
|
|
|
|
wl_resource_set_implementation (resource, &wl_shm_impl,
|
|
NULL, HandleResourceDestroy);
|
|
all_shms = XLListPrepend (all_shms, resource);
|
|
|
|
PostFormats (resource);
|
|
}
|
|
|
|
static void
|
|
InitRender (void)
|
|
{
|
|
int major, minor, base, dummy;
|
|
|
|
if (!XRenderQueryExtension (compositor.display,
|
|
&base, &dummy))
|
|
{
|
|
fprintf (stderr, "XRender is not supported by this X server\n");
|
|
exit (1);
|
|
}
|
|
|
|
if (!XRenderQueryVersion (compositor.display,
|
|
&major, &minor)
|
|
|| (!major && minor < 2))
|
|
{
|
|
fprintf (stderr, "XRender is not supported by this X server\n");
|
|
exit (1);
|
|
}
|
|
|
|
compositor.argb_format
|
|
= XRenderFindStandardFormat (compositor.display,
|
|
PictStandardARGB32);
|
|
compositor.xrgb_format
|
|
= XRenderFindStandardFormat (compositor.display,
|
|
PictStandardRGB24);
|
|
|
|
if (!compositor.argb_format)
|
|
{
|
|
fprintf (stderr, "Failed to find standard format PictStandardARGB32\n");
|
|
exit (1);
|
|
}
|
|
|
|
if (!compositor.xrgb_format)
|
|
{
|
|
fprintf (stderr, "Failed to find standard format PictStandardRGB24\n");
|
|
exit (1);
|
|
}
|
|
}
|
|
|
|
void
|
|
XLInitShm (void)
|
|
{
|
|
InitRender ();
|
|
|
|
global_shm = wl_global_create (compositor.wl_display,
|
|
&wl_shm_interface, 1,
|
|
NULL, HandleBind);
|
|
}
|