Replace wlr_client_buffer with wlr_surface_texture

wlr_client_buffer has a bad design: just because it needs some
ref'counting functionality, it's implemented as a wlr_buffer.
Its purpose is to allow compositors to obtain a frozen wlr_texture
to keep painting an old representation of the surface for an
arbitrary amount of time (e.g. during layout reconfigurations).

However a wlr_buffer lock means something else entirely, and abusing
it for ref'counting a texture leads to various issues. In particular,
wlr_surface checks the wlr_client_buffer lock count to decide whether
to mutate a texture on commit. This falls apart if the buffer is
locked for another purpose than freezing a surface texture (e.g.
locked by another wlroots helper). Additionally, wlr_client_buffer
forces backends to re-import and re-check the buffer each time the
client commits, since DMA-BUF wlr_client_buffers are destroyed and
re-created on each commit. wlr_client_buffer also doesn't properly
forward all wlr_buffer operations to the source buffer: some are
unimplemented, and the source buffer is not locked by wlr_client_buffer
thus may be destroyed anytime.

To fix all of this mess, introduce a new struct wlr_surface_texture
whose purpose is just to track whether a wlr_texture is frozen.
Compositors can lock the texture to freeze it. The wlr_buffer can be
accessed from wlr_surface_texture.buffer, or at surface commit time
from wlr_surface.current.buffer.
This commit is contained in:
Simon Ser 2024-03-06 16:48:33 +01:00
parent 119c634d94
commit 5f6b9e5620
3 changed files with 107 additions and 53 deletions

View file

@ -119,16 +119,29 @@ struct wlr_surface_output {
struct wl_listener destroy;
};
struct wlr_surface_texture {
struct wlr_texture *texture;
// The buffer this surface texture was created from. NULL if released.
struct wlr_buffer *buffer;
// True if the texture won't be mutated by client surface commits.
bool locked;
// private state
struct wl_listener buffer_release;
bool dropped;
};
struct wlr_surface {
struct wl_resource *resource;
struct wlr_renderer *renderer; // may be NULL
/**
* The surface's buffer, if any. A surface has an attached buffer when it
* The surface's texture, if any. A surface has an attached buffer when it
* commits with a non-null buffer in its pending state. A surface will not
* have a buffer if it has never committed one, has committed a null buffer,
* or something went wrong with uploading the buffer.
* have a texture if it has never committed one, has committed a null
* buffer, or something went wrong with uploading the buffer.
*/
struct wlr_client_buffer *buffer;
struct wlr_surface_texture *texture;
/**
* The last commit's buffer damage, in buffer-local coordinates. This
* contains both the damage accumulated by the client via
@ -257,6 +270,9 @@ struct wlr_compositor {
typedef void (*wlr_surface_iterator_func_t)(struct wlr_surface *surface,
int sx, int sy, void *data);
void wlr_surface_texture_lock(struct wlr_surface_texture *surf_tex);
void wlr_surface_texture_unlock(struct wlr_surface_texture *surf_tex);
/**
* Set the lifetime role for this surface.
*