12to11/shm.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

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);
}