/* 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 . */
#include
#include
#include "compositor.h"
#include
#include
#include
#define FenceFree (1U << 31)
struct _Fence
{
/* The next and last fences on this list. */
Fence *next;
/* The xshmfence. */
struct xshmfence *fence;
/* The sync fence. High bit is a flag meaning that the fence is on
the free list. */
XSyncFence fence_id;
/* The number of references to this fence. Incremented by
FenceRetain, decremented by FenceAwait. */
int refcount;
};
/* Chain of all free fences. */
static Fence *all_fences;
Fence *
GetFence (void)
{
Fence *fence;
int fd;
Window drawable;
drawable = DefaultRootWindow (compositor.display);
/* Get one free fence. */
for (fence = all_fences; fence; fence = fence->next)
{
/* Unlink this fence. */
all_fences = fence->next;
fence->next = NULL;
/* Mark the fence as used. */
fence->fence_id &= ~FenceFree;
/* Return it. */
return fence;
}
/* Otherwise, allocate a new fence. */
fence = XLCalloc (1, sizeof *fence);
fd = xshmfence_alloc_shm ();
if (fd < 0)
{
perror ("xshmfence_alloc_shm");
abort ();
}
/* Map it. */
fence->fence = xshmfence_map_shm (fd);
if (!fence->fence)
{
perror ("xshmfence_map_shm");
abort ();
}
/* Upload the fence to the X server. XCB will close the file
descriptor. */
fence->fence_id = xcb_generate_id (compositor.conn);
/* Make the file descriptor CLOEXEC, since it isn't closed
immediately. */
XLAddFdFlag (fd, FD_CLOEXEC, False);
xcb_dri3_fence_from_fd (compositor.conn, drawable,
fence->fence_id, 0, fd);
/* Return the fence. */
return fence;
}
void
FenceAwait (Fence *fence)
{
XLAssert (fence->refcount);
fence->refcount -= 1;
if (!(fence->fence_id & FenceFree))
{
/* Wait for the fence to be triggered. */
xshmfence_await (fence->fence);
/* Reset the fence. */
xshmfence_reset (fence->fence);
fence->fence_id |= FenceFree;
}
if (fence->refcount)
return;
/* Now that the fence is no longer referenced, it can be put back on
the list of free fences. */
fence->next = all_fences;
all_fences = fence;
}
void
FenceRetain (Fence *fence)
{
fence->refcount++;
}
XSyncFence
FenceToXFence (Fence *fence)
{
return fence->fence_id & ~FenceFree;
}