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
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,

View File

@ -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

View File

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