mirror of
https://github.com/brl/mutter.git
synced 2024-12-23 11:32:04 +00:00
wayland-server: Update because wl_shm_buffer is no longer a wl_buffer
The Wayland server API has changed so that wl_shm_buffer is no longer a type of wl_buffer and it instead must be retrieved directly from the resource. cogl_wayland_texture_2d_new_from_buffer now takes a resource pointer instead of directly taking a wl_buffer and it will do different things depending on whether it can get a wl_shm_buffer out of the resource instead of trying to query the buffer type. Cogland has also been updated so that it tracks a resource for buffers of surfaces instead of directly tracking a wl_buffer. This are pointed to by a new CoglandBuffer struct which can be referenced by a CoglandBufferReference. The WL_BUFFER_RELEASE event will be posted when the last reference to the buffer is removed instead of directly whenever a new buffer is attached. This is similar to how Weston works. https://bugzilla.gnome.org/show_bug.cgi?id=702999 Reviewed-by: Robert Bragg <robert@linux.intel.com> (cherry picked from commit 9b35e1651ad0e46ed489893b60563e2c25457701) Conflicts: examples/cogland.c
This commit is contained in:
parent
baa398b324
commit
1ad0e81b7b
@ -259,18 +259,22 @@ _cogl_egl_texture_2d_new_from_image (CoglContext *ctx,
|
||||
#ifdef COGL_HAS_WAYLAND_EGL_SERVER_SUPPORT
|
||||
CoglTexture2D *
|
||||
cogl_wayland_texture_2d_new_from_buffer (CoglContext *ctx,
|
||||
struct wl_buffer *buffer,
|
||||
struct wl_resource *buffer_resource,
|
||||
CoglError **error)
|
||||
{
|
||||
int format;
|
||||
struct wl_shm_buffer *shm_buffer;
|
||||
|
||||
if (wl_buffer_is_shm (buffer))
|
||||
shm_buffer = wl_shm_buffer_get (buffer_resource);
|
||||
|
||||
if (shm_buffer)
|
||||
{
|
||||
int stride = wl_shm_buffer_get_stride (buffer);
|
||||
int stride = wl_shm_buffer_get_stride (shm_buffer);
|
||||
CoglPixelFormat format;
|
||||
CoglPixelFormat internal_format = COGL_PIXEL_FORMAT_ANY;
|
||||
int width = wl_shm_buffer_get_width (shm_buffer);
|
||||
int height = wl_shm_buffer_get_height (shm_buffer);
|
||||
|
||||
switch (wl_shm_buffer_get_format (buffer))
|
||||
switch (wl_shm_buffer_get_format (shm_buffer))
|
||||
{
|
||||
#if G_BYTE_ORDER == G_BIG_ENDIAN
|
||||
case WL_SHM_FORMAT_ARGB8888:
|
||||
@ -295,55 +299,68 @@ cogl_wayland_texture_2d_new_from_buffer (CoglContext *ctx,
|
||||
}
|
||||
|
||||
return cogl_texture_2d_new_from_data (ctx,
|
||||
buffer->width,
|
||||
buffer->height,
|
||||
width, height,
|
||||
format,
|
||||
internal_format,
|
||||
stride,
|
||||
wl_shm_buffer_get_data (buffer),
|
||||
wl_shm_buffer_get_data (shm_buffer),
|
||||
error);
|
||||
}
|
||||
else if (_cogl_egl_query_wayland_buffer (ctx, buffer,
|
||||
EGL_TEXTURE_FORMAT,
|
||||
&format))
|
||||
else
|
||||
{
|
||||
EGLImageKHR image;
|
||||
CoglTexture2D *tex = NULL;
|
||||
CoglPixelFormat internal_format;
|
||||
struct wl_buffer *buffer = (struct wl_buffer *) buffer_resource;
|
||||
int format, width, height;
|
||||
|
||||
_COGL_RETURN_VAL_IF_FAIL (_cogl_context_get_winsys (ctx)->constraints &
|
||||
COGL_RENDERER_CONSTRAINT_USES_EGL,
|
||||
NULL);
|
||||
|
||||
switch (format)
|
||||
if (_cogl_egl_query_wayland_buffer (ctx,
|
||||
buffer,
|
||||
EGL_TEXTURE_FORMAT,
|
||||
&format) &&
|
||||
_cogl_egl_query_wayland_buffer (ctx,
|
||||
buffer,
|
||||
EGL_WIDTH,
|
||||
&width) &&
|
||||
_cogl_egl_query_wayland_buffer (ctx,
|
||||
buffer,
|
||||
EGL_HEIGHT,
|
||||
&height))
|
||||
{
|
||||
case EGL_TEXTURE_RGB:
|
||||
internal_format = COGL_PIXEL_FORMAT_RGB_888;
|
||||
break;
|
||||
case EGL_TEXTURE_RGBA:
|
||||
internal_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE;
|
||||
break;
|
||||
default:
|
||||
_cogl_set_error (error,
|
||||
COGL_SYSTEM_ERROR,
|
||||
COGL_SYSTEM_ERROR_UNSUPPORTED,
|
||||
"Can't create texture from unknown "
|
||||
"wayland buffer format %d\n", format);
|
||||
return NULL;
|
||||
}
|
||||
EGLImageKHR image;
|
||||
CoglTexture2D *tex = NULL;
|
||||
CoglPixelFormat internal_format;
|
||||
|
||||
image = _cogl_egl_create_image (ctx,
|
||||
EGL_WAYLAND_BUFFER_WL,
|
||||
buffer,
|
||||
NULL);
|
||||
tex = _cogl_egl_texture_2d_new_from_image (ctx,
|
||||
buffer->width,
|
||||
buffer->height,
|
||||
internal_format,
|
||||
image,
|
||||
error);
|
||||
_cogl_egl_destroy_image (ctx, image);
|
||||
return tex;
|
||||
_COGL_RETURN_VAL_IF_FAIL (_cogl_context_get_winsys (ctx)->constraints &
|
||||
COGL_RENDERER_CONSTRAINT_USES_EGL,
|
||||
NULL);
|
||||
|
||||
switch (format)
|
||||
{
|
||||
case EGL_TEXTURE_RGB:
|
||||
internal_format = COGL_PIXEL_FORMAT_RGB_888;
|
||||
break;
|
||||
case EGL_TEXTURE_RGBA:
|
||||
internal_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE;
|
||||
break;
|
||||
default:
|
||||
_cogl_set_error (error,
|
||||
COGL_SYSTEM_ERROR,
|
||||
COGL_SYSTEM_ERROR_UNSUPPORTED,
|
||||
"Can't create texture from unknown "
|
||||
"wayland buffer format %d\n", format);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
image = _cogl_egl_create_image (ctx,
|
||||
EGL_WAYLAND_BUFFER_WL,
|
||||
buffer,
|
||||
NULL);
|
||||
tex = _cogl_egl_texture_2d_new_from_image (ctx,
|
||||
width, height,
|
||||
internal_format,
|
||||
image,
|
||||
error);
|
||||
_cogl_egl_destroy_image (ctx, image);
|
||||
return tex;
|
||||
}
|
||||
}
|
||||
|
||||
_cogl_set_error (error,
|
||||
|
@ -51,10 +51,12 @@ cogl_wayland_display_set_compositor_display (CoglDisplay *display,
|
||||
/**
|
||||
* cogl_wayland_texture_2d_new_from_buffer:
|
||||
* @ctx: A #CoglContext
|
||||
* @buffer: A Wayland buffer
|
||||
* @buffer: A Wayland resource for a buffer
|
||||
* @error: A #CoglError for exceptions
|
||||
*
|
||||
* Uploads the given Wayland @buffer to a #CoglTexture2D.
|
||||
* Uploads the @buffer referenced by the given Wayland resource to a
|
||||
* #CoglTexture2D. The buffer resource may refer to a wl_buffer or a
|
||||
* wl_shm_buffer.
|
||||
*
|
||||
* <note>The results are undefined for passing an invalid @buffer
|
||||
* pointer</note>
|
||||
@ -74,7 +76,7 @@ cogl_wayland_display_set_compositor_display (CoglDisplay *display,
|
||||
*/
|
||||
CoglTexture2D *
|
||||
cogl_wayland_texture_2d_new_from_buffer (CoglContext *ctx,
|
||||
struct wl_buffer *buffer,
|
||||
struct wl_resource *buffer,
|
||||
CoglError **error);
|
||||
|
||||
COGL_END_DECLS
|
||||
|
@ -21,6 +21,28 @@ typedef struct
|
||||
CoglandRegion region;
|
||||
} CoglandSharedRegion;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct wl_resource *resource;
|
||||
struct wl_signal destroy_signal;
|
||||
struct wl_listener destroy_listener;
|
||||
|
||||
union
|
||||
{
|
||||
struct wl_shm_buffer *shm_buffer;
|
||||
struct wl_buffer *legacy_buffer;
|
||||
};
|
||||
|
||||
int32_t width, height;
|
||||
uint32_t busy_count;
|
||||
} CoglandBuffer;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CoglandBuffer *buffer;
|
||||
struct wl_listener destroy_listener;
|
||||
} CoglandBufferReference;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CoglandCompositor *compositor;
|
||||
@ -28,8 +50,7 @@ typedef struct
|
||||
struct wl_resource resource;
|
||||
int x;
|
||||
int y;
|
||||
struct wl_buffer *buffer;
|
||||
struct wl_listener buffer_destroy_listener;
|
||||
CoglandBufferReference buffer_ref;
|
||||
CoglTexture2D *texture;
|
||||
|
||||
CoglBool has_shell_surface;
|
||||
@ -39,7 +60,7 @@ typedef struct
|
||||
{
|
||||
/* wl_surface.attach */
|
||||
CoglBool newly_attached;
|
||||
struct wl_buffer *buffer;
|
||||
CoglandBuffer *buffer;
|
||||
struct wl_listener buffer_destroy_listener;
|
||||
int32_t sx;
|
||||
int32_t sy;
|
||||
@ -268,6 +289,81 @@ wayland_event_source_new (struct wl_display *display)
|
||||
return &source->source;
|
||||
}
|
||||
|
||||
static void
|
||||
cogland_buffer_destroy_handler (struct wl_listener *listener,
|
||||
void *data)
|
||||
{
|
||||
CoglandBuffer *buffer = wl_container_of (listener, buffer, destroy_listener);
|
||||
|
||||
wl_signal_emit (&buffer->destroy_signal, buffer);
|
||||
g_slice_free (CoglandBuffer, buffer);
|
||||
}
|
||||
|
||||
static CoglandBuffer *
|
||||
cogland_buffer_from_resource (struct wl_resource *resource)
|
||||
{
|
||||
CoglandBuffer *buffer;
|
||||
struct wl_listener *listener;
|
||||
|
||||
listener = wl_resource_get_destroy_listener (resource,
|
||||
cogland_buffer_destroy_handler);
|
||||
|
||||
if (listener)
|
||||
{
|
||||
buffer = wl_container_of (listener, buffer, destroy_listener);
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer = g_slice_new0 (CoglandBuffer);
|
||||
|
||||
buffer->resource = resource;
|
||||
wl_signal_init (&buffer->destroy_signal);
|
||||
buffer->destroy_listener.notify = cogland_buffer_destroy_handler;
|
||||
wl_resource_add_destroy_listener (resource, &buffer->destroy_listener);
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static void
|
||||
cogland_buffer_reference_handle_destroy (struct wl_listener *listener,
|
||||
void *data)
|
||||
{
|
||||
CoglandBufferReference *ref =
|
||||
wl_container_of (listener, ref, destroy_listener);
|
||||
|
||||
g_assert (data == ref->buffer);
|
||||
|
||||
ref->buffer = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
cogland_buffer_reference (CoglandBufferReference *ref,
|
||||
CoglandBuffer *buffer)
|
||||
{
|
||||
if (ref->buffer && buffer != ref->buffer)
|
||||
{
|
||||
ref->buffer->busy_count--;
|
||||
|
||||
if (ref->buffer->busy_count == 0)
|
||||
{
|
||||
g_assert (wl_resource_get_client (ref->buffer->resource));
|
||||
wl_resource_queue_event (ref->buffer->resource, WL_BUFFER_RELEASE);
|
||||
}
|
||||
|
||||
wl_list_remove (&ref->destroy_listener.link);
|
||||
}
|
||||
|
||||
if (buffer && buffer != ref->buffer)
|
||||
{
|
||||
buffer->busy_count++;
|
||||
wl_signal_add (&buffer->destroy_signal, &ref->destroy_listener);
|
||||
}
|
||||
|
||||
ref->buffer = buffer;
|
||||
ref->destroy_listener.notify = cogland_buffer_reference_handle_destroy;
|
||||
}
|
||||
|
||||
typedef struct _CoglandFrameCallback
|
||||
{
|
||||
struct wl_list link;
|
||||
@ -342,45 +438,49 @@ surface_damaged (CoglandSurface *surface,
|
||||
int32_t width,
|
||||
int32_t height)
|
||||
{
|
||||
struct wl_buffer *wayland_buffer = surface->buffer;
|
||||
|
||||
if (surface->texture &&
|
||||
wl_buffer_is_shm (surface->buffer))
|
||||
if (surface->buffer_ref.buffer &&
|
||||
surface->texture)
|
||||
{
|
||||
CoglPixelFormat format;
|
||||
int stride = wl_shm_buffer_get_stride (wayland_buffer);
|
||||
const uint8_t *data = wl_shm_buffer_get_data (wayland_buffer);
|
||||
struct wl_shm_buffer *shm_buffer =
|
||||
wl_shm_buffer_get (surface->buffer_ref.buffer->resource);
|
||||
|
||||
switch (wl_shm_buffer_get_format (wayland_buffer))
|
||||
if (shm_buffer)
|
||||
{
|
||||
#if G_BYTE_ORDER == G_BIG_ENDIAN
|
||||
case WL_SHM_FORMAT_ARGB8888:
|
||||
format = COGL_PIXEL_FORMAT_ARGB_8888_PRE;
|
||||
break;
|
||||
case WL_SHM_FORMAT_XRGB8888:
|
||||
format = COGL_PIXEL_FORMAT_ARGB_8888;
|
||||
break;
|
||||
#elif G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
case WL_SHM_FORMAT_ARGB8888:
|
||||
format = COGL_PIXEL_FORMAT_BGRA_8888_PRE;
|
||||
break;
|
||||
case WL_SHM_FORMAT_XRGB8888:
|
||||
format = COGL_PIXEL_FORMAT_BGRA_8888;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
g_warn_if_reached ();
|
||||
format = COGL_PIXEL_FORMAT_ARGB_8888;
|
||||
}
|
||||
CoglPixelFormat format;
|
||||
int stride = wl_shm_buffer_get_stride (shm_buffer);
|
||||
const uint8_t *data = wl_shm_buffer_get_data (shm_buffer);
|
||||
|
||||
cogl_texture_set_region (COGL_TEXTURE (surface->texture),
|
||||
x, y, /* src_x/y */
|
||||
x, y, /* dst_x/y */
|
||||
width, height, /* dst_width/height */
|
||||
width, height, /* width/height */
|
||||
format,
|
||||
stride,
|
||||
data);
|
||||
switch (wl_shm_buffer_get_format (shm_buffer))
|
||||
{
|
||||
#if G_BYTE_ORDER == G_BIG_ENDIAN
|
||||
case WL_SHM_FORMAT_ARGB8888:
|
||||
format = COGL_PIXEL_FORMAT_ARGB_8888_PRE;
|
||||
break;
|
||||
case WL_SHM_FORMAT_XRGB8888:
|
||||
format = COGL_PIXEL_FORMAT_ARGB_8888;
|
||||
break;
|
||||
#elif G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
case WL_SHM_FORMAT_ARGB8888:
|
||||
format = COGL_PIXEL_FORMAT_BGRA_8888_PRE;
|
||||
break;
|
||||
case WL_SHM_FORMAT_XRGB8888:
|
||||
format = COGL_PIXEL_FORMAT_BGRA_8888;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
g_warn_if_reached ();
|
||||
format = COGL_PIXEL_FORMAT_ARGB_8888;
|
||||
}
|
||||
|
||||
cogl_texture_set_region (COGL_TEXTURE (surface->texture),
|
||||
x, y, /* src_x/y */
|
||||
x, y, /* dst_x/y */
|
||||
width, height, /* dst_width/height */
|
||||
width, height, /* width/height */
|
||||
format,
|
||||
stride,
|
||||
data);
|
||||
}
|
||||
}
|
||||
|
||||
cogland_queue_redraw (surface->compositor);
|
||||
@ -393,52 +493,6 @@ cogland_surface_destroy (struct wl_client *wayland_client,
|
||||
wl_resource_destroy (wayland_resource);
|
||||
}
|
||||
|
||||
static void
|
||||
cogland_surface_detach_buffer (CoglandSurface *surface)
|
||||
{
|
||||
struct wl_buffer *buffer = surface->buffer;
|
||||
|
||||
if (buffer)
|
||||
{
|
||||
wl_list_remove (&surface->buffer_destroy_listener.link);
|
||||
|
||||
surface->buffer = NULL;
|
||||
|
||||
if (surface->texture)
|
||||
{
|
||||
cogl_object_unref (surface->texture);
|
||||
surface->texture = NULL;
|
||||
}
|
||||
|
||||
cogland_queue_redraw (surface->compositor);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
surface_handle_buffer_destroy (struct wl_listener *listener,
|
||||
void *data)
|
||||
{
|
||||
CoglandSurface *surface =
|
||||
wl_container_of (listener, surface, buffer_destroy_listener);
|
||||
|
||||
cogland_surface_detach_buffer (surface);
|
||||
}
|
||||
|
||||
static void
|
||||
cogland_surface_detach_buffer_and_notify (CoglandSurface *surface)
|
||||
{
|
||||
struct wl_buffer *buffer = surface->buffer;
|
||||
|
||||
if (buffer)
|
||||
{
|
||||
g_assert (buffer->resource.client != NULL);
|
||||
|
||||
wl_resource_queue_event (&buffer->resource, WL_BUFFER_RELEASE);
|
||||
|
||||
cogland_surface_detach_buffer (surface);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
cogland_surface_attach (struct wl_client *wayland_client,
|
||||
struct wl_resource *wayland_surface_resource,
|
||||
@ -446,8 +500,12 @@ cogland_surface_attach (struct wl_client *wayland_client,
|
||||
int32_t sx, int32_t sy)
|
||||
{
|
||||
CoglandSurface *surface = wayland_surface_resource->data;
|
||||
struct wl_buffer *buffer =
|
||||
wayland_buffer_resource ? wayland_buffer_resource->data : NULL;
|
||||
CoglandBuffer *buffer;
|
||||
|
||||
if (wayland_buffer_resource)
|
||||
buffer = cogland_buffer_from_resource (wayland_buffer_resource);
|
||||
else
|
||||
buffer = NULL;
|
||||
|
||||
/* Attach without commit in between does not went wl_buffer.release */
|
||||
if (surface->pending.buffer)
|
||||
@ -459,7 +517,7 @@ cogland_surface_attach (struct wl_client *wayland_client,
|
||||
surface->pending.newly_attached = TRUE;
|
||||
|
||||
if (buffer)
|
||||
wl_signal_add (&buffer->resource.destroy_signal,
|
||||
wl_signal_add (&buffer->destroy_signal,
|
||||
&surface->pending.buffer_destroy_listener);
|
||||
}
|
||||
|
||||
@ -527,17 +585,26 @@ cogland_surface_commit (struct wl_client *client,
|
||||
|
||||
/* wl_surface.attach */
|
||||
if (surface->pending.newly_attached &&
|
||||
surface->buffer != surface->pending.buffer)
|
||||
surface->buffer_ref.buffer != surface->pending.buffer)
|
||||
{
|
||||
CoglError *error = NULL;
|
||||
|
||||
cogland_surface_detach_buffer_and_notify (surface);
|
||||
if (surface->texture)
|
||||
{
|
||||
cogl_object_unref (surface->texture);
|
||||
surface->texture = NULL;
|
||||
}
|
||||
|
||||
cogland_buffer_reference (&surface->buffer_ref, surface->pending.buffer);
|
||||
|
||||
if (surface->pending.buffer)
|
||||
{
|
||||
struct wl_resource *buffer_resource =
|
||||
surface->pending.buffer->resource;
|
||||
|
||||
surface->texture =
|
||||
cogl_wayland_texture_2d_new_from_buffer (compositor->cogl_context,
|
||||
surface->pending.buffer,
|
||||
buffer_resource,
|
||||
&error);
|
||||
|
||||
if (!surface->texture)
|
||||
@ -546,11 +613,6 @@ cogland_surface_commit (struct wl_client *client,
|
||||
error->message);
|
||||
cogl_error_free (error);
|
||||
}
|
||||
|
||||
surface->buffer = surface->pending.buffer;
|
||||
|
||||
wl_signal_add (&surface->buffer->resource.destroy_signal,
|
||||
&surface->buffer_destroy_listener);
|
||||
}
|
||||
}
|
||||
if (surface->pending.buffer)
|
||||
@ -563,7 +625,7 @@ cogland_surface_commit (struct wl_client *client,
|
||||
surface->pending.newly_attached = FALSE;
|
||||
|
||||
/* wl_surface.damage */
|
||||
if (surface->buffer &&
|
||||
if (surface->buffer_ref.buffer &&
|
||||
surface->texture &&
|
||||
!region_is_empty (&surface->pending.damage))
|
||||
{
|
||||
@ -618,7 +680,10 @@ cogland_surface_free (CoglandSurface *surface)
|
||||
CoglandFrameCallback *cb, *next;
|
||||
|
||||
compositor->surfaces = g_list_remove (compositor->surfaces, surface);
|
||||
cogland_surface_detach_buffer_and_notify (surface);
|
||||
|
||||
cogland_buffer_reference (&surface->buffer_ref, NULL);
|
||||
if (surface->texture)
|
||||
cogl_object_unref (surface->texture);
|
||||
|
||||
if (surface->pending.buffer)
|
||||
wl_list_remove (&surface->pending.buffer_destroy_listener.link);
|
||||
@ -628,7 +693,10 @@ cogland_surface_free (CoglandSurface *surface)
|
||||
wl_resource_destroy (&cb->resource);
|
||||
|
||||
g_slice_free (CoglandSurface, surface);
|
||||
|
||||
cogland_queue_redraw (compositor);
|
||||
}
|
||||
|
||||
static void
|
||||
cogland_surface_resource_destroy_cb (struct wl_resource *resource)
|
||||
{
|
||||
@ -664,9 +732,6 @@ cogland_compositor_create_surface (struct wl_client *wayland_client,
|
||||
(void (**)(void)) &cogland_surface_interface;
|
||||
surface->resource.data = surface;
|
||||
|
||||
surface->buffer_destroy_listener.notify =
|
||||
surface_handle_buffer_destroy;
|
||||
|
||||
surface->pending.buffer_destroy_listener.notify =
|
||||
surface_handle_pending_buffer_destroy;
|
||||
wl_list_init (&surface->pending.frame_callback_list);
|
||||
|
Loading…
Reference in New Issue
Block a user