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:
Neil Roberts 2013-06-27 14:22:41 +01:00
parent baa398b324
commit 1ad0e81b7b
3 changed files with 232 additions and 148 deletions

View File

@ -259,18 +259,22 @@ _cogl_egl_texture_2d_new_from_image (CoglContext *ctx,
#ifdef COGL_HAS_WAYLAND_EGL_SERVER_SUPPORT #ifdef COGL_HAS_WAYLAND_EGL_SERVER_SUPPORT
CoglTexture2D * CoglTexture2D *
cogl_wayland_texture_2d_new_from_buffer (CoglContext *ctx, cogl_wayland_texture_2d_new_from_buffer (CoglContext *ctx,
struct wl_buffer *buffer, struct wl_resource *buffer_resource,
CoglError **error) 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 format;
CoglPixelFormat internal_format = COGL_PIXEL_FORMAT_ANY; 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 #if G_BYTE_ORDER == G_BIG_ENDIAN
case WL_SHM_FORMAT_ARGB8888: 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, return cogl_texture_2d_new_from_data (ctx,
buffer->width, width, height,
buffer->height,
format, format,
internal_format, internal_format,
stride, stride,
wl_shm_buffer_get_data (buffer), wl_shm_buffer_get_data (shm_buffer),
error); error);
} }
else if (_cogl_egl_query_wayland_buffer (ctx, buffer, else
EGL_TEXTURE_FORMAT,
&format))
{ {
EGLImageKHR image; struct wl_buffer *buffer = (struct wl_buffer *) buffer_resource;
CoglTexture2D *tex = NULL; int format, width, height;
CoglPixelFormat internal_format;
_COGL_RETURN_VAL_IF_FAIL (_cogl_context_get_winsys (ctx)->constraints & if (_cogl_egl_query_wayland_buffer (ctx,
COGL_RENDERER_CONSTRAINT_USES_EGL, buffer,
NULL); EGL_TEXTURE_FORMAT,
&format) &&
switch (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: EGLImageKHR image;
internal_format = COGL_PIXEL_FORMAT_RGB_888; CoglTexture2D *tex = NULL;
break; CoglPixelFormat internal_format;
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, _COGL_RETURN_VAL_IF_FAIL (_cogl_context_get_winsys (ctx)->constraints &
EGL_WAYLAND_BUFFER_WL, COGL_RENDERER_CONSTRAINT_USES_EGL,
buffer, NULL);
NULL);
tex = _cogl_egl_texture_2d_new_from_image (ctx, switch (format)
buffer->width, {
buffer->height, case EGL_TEXTURE_RGB:
internal_format, internal_format = COGL_PIXEL_FORMAT_RGB_888;
image, break;
error); case EGL_TEXTURE_RGBA:
_cogl_egl_destroy_image (ctx, image); internal_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE;
return tex; 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, _cogl_set_error (error,

View File

@ -51,10 +51,12 @@ cogl_wayland_display_set_compositor_display (CoglDisplay *display,
/** /**
* cogl_wayland_texture_2d_new_from_buffer: * cogl_wayland_texture_2d_new_from_buffer:
* @ctx: A #CoglContext * @ctx: A #CoglContext
* @buffer: A Wayland buffer * @buffer: A Wayland resource for a buffer
* @error: A #CoglError for exceptions * @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 * <note>The results are undefined for passing an invalid @buffer
* pointer</note> * pointer</note>
@ -74,7 +76,7 @@ cogl_wayland_display_set_compositor_display (CoglDisplay *display,
*/ */
CoglTexture2D * CoglTexture2D *
cogl_wayland_texture_2d_new_from_buffer (CoglContext *ctx, cogl_wayland_texture_2d_new_from_buffer (CoglContext *ctx,
struct wl_buffer *buffer, struct wl_resource *buffer,
CoglError **error); CoglError **error);
COGL_END_DECLS COGL_END_DECLS

View File

@ -21,6 +21,28 @@ typedef struct
CoglandRegion region; CoglandRegion region;
} CoglandSharedRegion; } 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 typedef struct
{ {
CoglandCompositor *compositor; CoglandCompositor *compositor;
@ -28,8 +50,7 @@ typedef struct
struct wl_resource resource; struct wl_resource resource;
int x; int x;
int y; int y;
struct wl_buffer *buffer; CoglandBufferReference buffer_ref;
struct wl_listener buffer_destroy_listener;
CoglTexture2D *texture; CoglTexture2D *texture;
CoglBool has_shell_surface; CoglBool has_shell_surface;
@ -39,7 +60,7 @@ typedef struct
{ {
/* wl_surface.attach */ /* wl_surface.attach */
CoglBool newly_attached; CoglBool newly_attached;
struct wl_buffer *buffer; CoglandBuffer *buffer;
struct wl_listener buffer_destroy_listener; struct wl_listener buffer_destroy_listener;
int32_t sx; int32_t sx;
int32_t sy; int32_t sy;
@ -268,6 +289,81 @@ wayland_event_source_new (struct wl_display *display)
return &source->source; 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 typedef struct _CoglandFrameCallback
{ {
struct wl_list link; struct wl_list link;
@ -342,45 +438,49 @@ surface_damaged (CoglandSurface *surface,
int32_t width, int32_t width,
int32_t height) int32_t height)
{ {
struct wl_buffer *wayland_buffer = surface->buffer; if (surface->buffer_ref.buffer &&
surface->texture)
if (surface->texture &&
wl_buffer_is_shm (surface->buffer))
{ {
CoglPixelFormat format; struct wl_shm_buffer *shm_buffer =
int stride = wl_shm_buffer_get_stride (wayland_buffer); wl_shm_buffer_get (surface->buffer_ref.buffer->resource);
const uint8_t *data = wl_shm_buffer_get_data (wayland_buffer);
switch (wl_shm_buffer_get_format (wayland_buffer)) if (shm_buffer)
{ {
#if G_BYTE_ORDER == G_BIG_ENDIAN CoglPixelFormat format;
case WL_SHM_FORMAT_ARGB8888: int stride = wl_shm_buffer_get_stride (shm_buffer);
format = COGL_PIXEL_FORMAT_ARGB_8888_PRE; const uint8_t *data = wl_shm_buffer_get_data (shm_buffer);
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), switch (wl_shm_buffer_get_format (shm_buffer))
x, y, /* src_x/y */ {
x, y, /* dst_x/y */ #if G_BYTE_ORDER == G_BIG_ENDIAN
width, height, /* dst_width/height */ case WL_SHM_FORMAT_ARGB8888:
width, height, /* width/height */ format = COGL_PIXEL_FORMAT_ARGB_8888_PRE;
format, break;
stride, case WL_SHM_FORMAT_XRGB8888:
data); 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); cogland_queue_redraw (surface->compositor);
@ -393,52 +493,6 @@ cogland_surface_destroy (struct wl_client *wayland_client,
wl_resource_destroy (wayland_resource); 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 static void
cogland_surface_attach (struct wl_client *wayland_client, cogland_surface_attach (struct wl_client *wayland_client,
struct wl_resource *wayland_surface_resource, struct wl_resource *wayland_surface_resource,
@ -446,8 +500,12 @@ cogland_surface_attach (struct wl_client *wayland_client,
int32_t sx, int32_t sy) int32_t sx, int32_t sy)
{ {
CoglandSurface *surface = wayland_surface_resource->data; CoglandSurface *surface = wayland_surface_resource->data;
struct wl_buffer *buffer = CoglandBuffer *buffer;
wayland_buffer_resource ? wayland_buffer_resource->data : NULL;
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 */ /* Attach without commit in between does not went wl_buffer.release */
if (surface->pending.buffer) if (surface->pending.buffer)
@ -459,7 +517,7 @@ cogland_surface_attach (struct wl_client *wayland_client,
surface->pending.newly_attached = TRUE; surface->pending.newly_attached = TRUE;
if (buffer) if (buffer)
wl_signal_add (&buffer->resource.destroy_signal, wl_signal_add (&buffer->destroy_signal,
&surface->pending.buffer_destroy_listener); &surface->pending.buffer_destroy_listener);
} }
@ -527,17 +585,26 @@ cogland_surface_commit (struct wl_client *client,
/* wl_surface.attach */ /* wl_surface.attach */
if (surface->pending.newly_attached && if (surface->pending.newly_attached &&
surface->buffer != surface->pending.buffer) surface->buffer_ref.buffer != surface->pending.buffer)
{ {
CoglError *error = NULL; 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) if (surface->pending.buffer)
{ {
struct wl_resource *buffer_resource =
surface->pending.buffer->resource;
surface->texture = surface->texture =
cogl_wayland_texture_2d_new_from_buffer (compositor->cogl_context, cogl_wayland_texture_2d_new_from_buffer (compositor->cogl_context,
surface->pending.buffer, buffer_resource,
&error); &error);
if (!surface->texture) if (!surface->texture)
@ -546,11 +613,6 @@ cogland_surface_commit (struct wl_client *client,
error->message); error->message);
cogl_error_free (error); 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) if (surface->pending.buffer)
@ -563,7 +625,7 @@ cogland_surface_commit (struct wl_client *client,
surface->pending.newly_attached = FALSE; surface->pending.newly_attached = FALSE;
/* wl_surface.damage */ /* wl_surface.damage */
if (surface->buffer && if (surface->buffer_ref.buffer &&
surface->texture && surface->texture &&
!region_is_empty (&surface->pending.damage)) !region_is_empty (&surface->pending.damage))
{ {
@ -618,7 +680,10 @@ cogland_surface_free (CoglandSurface *surface)
CoglandFrameCallback *cb, *next; CoglandFrameCallback *cb, *next;
compositor->surfaces = g_list_remove (compositor->surfaces, surface); 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) if (surface->pending.buffer)
wl_list_remove (&surface->pending.buffer_destroy_listener.link); wl_list_remove (&surface->pending.buffer_destroy_listener.link);
@ -628,7 +693,10 @@ cogland_surface_free (CoglandSurface *surface)
wl_resource_destroy (&cb->resource); wl_resource_destroy (&cb->resource);
g_slice_free (CoglandSurface, surface); g_slice_free (CoglandSurface, surface);
cogland_queue_redraw (compositor);
} }
static void static void
cogland_surface_resource_destroy_cb (struct wl_resource *resource) 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; (void (**)(void)) &cogland_surface_interface;
surface->resource.data = surface; surface->resource.data = surface;
surface->buffer_destroy_listener.notify =
surface_handle_buffer_destroy;
surface->pending.buffer_destroy_listener.notify = surface->pending.buffer_destroy_listener.notify =
surface_handle_pending_buffer_destroy; surface_handle_pending_buffer_destroy;
wl_list_init (&surface->pending.frame_callback_list); wl_list_init (&surface->pending.frame_callback_list);