Merge remote-tracking branch 'nobled/wayland-fixes2'

* nobled/wayland-fixes2:
  wayland: fix shm buffers
  wayland: set renderable type on dummy surface
  wayland: check for egl extensions explicitly
  wayland: fall back to shm buffers if drm fails
  wayland: add shm buffer code
  wayland: make buffer handling generic
  wayland: really fix buffer format selection
  wayland: fix pixel format
  wayland: clean up buffer creation code
  wayland: don't require the surfaceless extensions
  wayland: check for API-specific surfaceless extension
  wayland: fix GLES context creation
  wayland: use EGL_NO_SURFACE
  wayland: update to new api
  wayland: fix connecting to default socket
  fix ClutterContainer docs
This commit is contained in:
Emmanuele Bassi 2011-02-11 16:45:45 +00:00
commit 2abf56fe92
5 changed files with 375 additions and 103 deletions

View File

@ -80,8 +80,8 @@ typedef struct _ClutterContainerIface ClutterContainerIface;
* @destroy_child_meta: virtual function that gets called when a child is * @destroy_child_meta: virtual function that gets called when a child is
* removed; it shuld release all resources held by the record * removed; it shuld release all resources held by the record
* @get_child_meta: return the record for a container child * @get_child_meta: return the record for a container child
* @actor_added: class handler for #ClutterContainer::actor_added * @actor_added: class handler for #ClutterContainer::actor-added
* @actor_removed: class handler for #ClutterContainer::actor_removed * @actor_removed: class handler for #ClutterContainer::actor-removed
* @child_notify: class handler for #ClutterContainer::child-notify * @child_notify: class handler for #ClutterContainer::child-notify
* *
* Base interface for container actors. The @add, @remove and @foreach * Base interface for container actors. The @add, @remove and @foreach

View File

@ -111,7 +111,7 @@ static void
handle_configure (void *data, struct wl_shell *shell, handle_configure (void *data, struct wl_shell *shell,
uint32_t timestamp, uint32_t edges, uint32_t timestamp, uint32_t edges,
struct wl_surface *surface, struct wl_surface *surface,
int32_t x, int32_t y, int32_t width, int32_t height) int32_t width, int32_t height)
{ {
ClutterStageWayland *stage_wayland; ClutterStageWayland *stage_wayland;
@ -123,8 +123,6 @@ handle_configure (void *data, struct wl_shell *shell,
clutter_actor_queue_relayout (CLUTTER_ACTOR (stage_wayland->wrapper)); clutter_actor_queue_relayout (CLUTTER_ACTOR (stage_wayland->wrapper));
} }
stage_wayland->pending_allocation.x = x;
stage_wayland->pending_allocation.y = y;
stage_wayland->pending_allocation.width = width; stage_wayland->pending_allocation.width = width;
stage_wayland->pending_allocation.height = height; stage_wayland->pending_allocation.height = height;
stage_wayland->allocation = stage_wayland->pending_allocation; stage_wayland->allocation = stage_wayland->pending_allocation;
@ -177,7 +175,105 @@ display_handle_global (struct wl_display *display,
wl_drm_add_listener (backend_wayland->wayland_drm, wl_drm_add_listener (backend_wayland->wayland_drm,
&drm_listener, backend_wayland); &drm_listener, backend_wayland);
} }
else if (strcmp (interface, "shm") == 0)
{
backend_wayland->wayland_shm = wl_shm_create (display, id);
} }
}
static gboolean
try_get_display (ClutterBackendWayland *backend_wayland, GError **error)
{
EGLDisplay edpy = EGL_NO_DISPLAY;
int drm_fd;
drm_fd = open (backend_wayland->device_name, O_RDWR);
backend_wayland->get_drm_display =
(PFNEGLGETDRMDISPLAYMESA) eglGetProcAddress ("eglGetDRMDisplayMESA");
if (backend_wayland->get_drm_display != NULL && drm_fd >= 0)
edpy = backend_wayland->get_drm_display (drm_fd);
if (edpy == EGL_NO_DISPLAY)
edpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (edpy == EGL_NO_DISPLAY)
{
g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_BACKEND,
"Failed to open EGLDisplay");
return FALSE;
}
backend_wayland->edpy = edpy;
backend_wayland->drm_fd = drm_fd;
return TRUE;
}
static gboolean
try_enable_drm (ClutterBackendWayland *backend_wayland, GError **error)
{
drm_magic_t magic;
const gchar *exts, *glexts;
if (backend_wayland->drm_fd < 0)
{
g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_BACKEND,
"Failed to open drm device");
return FALSE;
}
glexts = glGetString(GL_EXTENSIONS);
exts = eglQueryString (backend_wayland->edpy, EGL_EXTENSIONS);
if (!_cogl_check_extension ("EGL_KHR_image_base", exts) ||
!_cogl_check_extension ("EGL_MESA_drm_image", exts) ||
!_cogl_check_extension ("GL_OES_EGL_image", glexts))
{
g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_BACKEND,
"Missing EGL extensions");
return FALSE;
}
backend_wayland->create_drm_image =
(PFNEGLCREATEDRMIMAGEMESA) eglGetProcAddress ("eglCreateDRMImageMESA");
backend_wayland->destroy_image =
(PFNEGLDESTROYIMAGEKHRPROC) eglGetProcAddress ("eglDestroyImageKHR");
backend_wayland->export_drm_image =
(PFNEGLEXPORTDRMIMAGEMESA) eglGetProcAddress ("eglExportDRMImageMESA");
backend_wayland->image_target_texture_2d =
(PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) eglGetProcAddress ("glEGLImageTargetTexture2DOES");
if (backend_wayland->create_drm_image == NULL ||
backend_wayland->destroy_image == NULL ||
backend_wayland->export_drm_image == NULL ||
backend_wayland->image_target_texture_2d == NULL)
{
g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_BACKEND,
"Missing EGL extensions");
return FALSE;
}
if (drmGetMagic (backend_wayland->drm_fd, &magic))
{
g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_BACKEND,
"Failed to get drm magic");
return FALSE;
}
wl_drm_authenticate (backend_wayland->wayland_drm, magic);
wl_display_iterate (backend_wayland->wayland_display, WL_DISPLAY_WRITABLE);
while (!backend_wayland->authenticated)
wl_display_iterate (backend_wayland->wayland_display, WL_DISPLAY_READABLE);
return TRUE;
};
static gboolean static gboolean
clutter_backend_wayland_post_parse (ClutterBackend *backend, clutter_backend_wayland_post_parse (ClutterBackend *backend,
@ -185,12 +281,11 @@ clutter_backend_wayland_post_parse (ClutterBackend *backend,
{ {
ClutterBackendWayland *backend_wayland = CLUTTER_BACKEND_WAYLAND (backend); ClutterBackendWayland *backend_wayland = CLUTTER_BACKEND_WAYLAND (backend);
EGLBoolean status; EGLBoolean status;
drm_magic_t magic;
g_atexit (clutter_backend_at_exit); g_atexit (clutter_backend_at_exit);
/* TODO: expose environment variable/commandline option for this... */ /* TODO: expose environment variable/commandline option for this... */
backend_wayland->wayland_display = wl_display_connect ("\0wayland"); backend_wayland->wayland_display = wl_display_connect (NULL);
if (!backend_wayland->wayland_display) if (!backend_wayland->wayland_display)
{ {
g_set_error (error, CLUTTER_INIT_ERROR, g_set_error (error, CLUTTER_INIT_ERROR,
@ -211,53 +306,8 @@ clutter_backend_wayland_post_parse (ClutterBackend *backend,
/* Process connection events. */ /* Process connection events. */
wl_display_iterate (backend_wayland->wayland_display, WL_DISPLAY_READABLE); wl_display_iterate (backend_wayland->wayland_display, WL_DISPLAY_READABLE);
backend_wayland->drm_fd = open (backend_wayland->device_name, O_RDWR); if (!try_get_display(backend_wayland, error))
if (backend_wayland->drm_fd < 0)
{
g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_BACKEND,
"Failed to open drm device");
return FALSE; return FALSE;
}
if (drmGetMagic (backend_wayland->drm_fd, &magic))
{
g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_BACKEND,
"Failed to get drm magic");
return FALSE;
}
wl_drm_authenticate (backend_wayland->wayland_drm, magic);
wl_display_iterate (backend_wayland->wayland_display, WL_DISPLAY_WRITABLE);
while (!backend_wayland->authenticated)
wl_display_iterate (backend_wayland->wayland_display, WL_DISPLAY_READABLE);
backend_wayland->get_drm_display =
(PFNEGLGETDRMDISPLAYMESA) eglGetProcAddress ("eglGetDRMDisplayMESA");
backend_wayland->create_drm_image =
(PFNEGLCREATEDRMIMAGEMESA) eglGetProcAddress ("eglCreateDRMImageMESA");
backend_wayland->destroy_image =
(PFNEGLDESTROYIMAGEKHRPROC) eglGetProcAddress ("eglDestroyImageKHR");
backend_wayland->export_drm_image =
(PFNEGLEXPORTDRMIMAGEMESA) eglGetProcAddress ("eglExportDRMImageMESA");
backend_wayland->image_target_texture_2d =
(PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) eglGetProcAddress ("glEGLImageTargetTexture2DOES");
if (backend_wayland->get_drm_display == NULL ||
backend_wayland->create_drm_image == NULL ||
backend_wayland->destroy_image == NULL ||
backend_wayland->export_drm_image == NULL ||
backend_wayland->image_target_texture_2d == NULL)
{
g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_BACKEND,
"Missing EGL extensions");
return FALSE;
}
backend_wayland->edpy =
backend_wayland->get_drm_display (backend_wayland->drm_fd);
status = eglInitialize (backend_wayland->edpy, status = eglInitialize (backend_wayland->edpy,
&backend_wayland->egl_version_major, &backend_wayland->egl_version_major,
@ -274,6 +324,52 @@ clutter_backend_wayland_post_parse (ClutterBackend *backend,
backend_wayland->egl_version_major, backend_wayland->egl_version_major,
backend_wayland->egl_version_minor); backend_wayland->egl_version_minor);
backend_wayland->drm_enabled = try_enable_drm(backend_wayland, error);
if (!backend_wayland->drm_enabled) {
if (backend_wayland->wayland_shm == NULL)
return FALSE;
g_debug("Could not enable DRM buffers, falling back to SHM buffers");
g_clear_error(error);
}
return TRUE;
}
#if defined(HAVE_COGL_GL)
#define _COGL_RENDERABLE_BIT EGL_OPENGL_BIT
#elif defined(HAVE_COGL_GLES2)
#define _COGL_GLES_VERSION 2
#define _COGL_RENDERABLE_BIT EGL_OPENGL_ES2_BIT
#elif defined(HAVE_COGL_GLES)
#define _COGL_GLES_VERSION 1
#define _COGL_RENDERABLE_BIT EGL_OPENGL_ES_BIT
#endif
static gboolean
make_dummy_surface (ClutterBackendWayland *backend_wayland)
{
static const EGLint attrs[] = {
EGL_WIDTH, 1,
EGL_HEIGHT, 1,
EGL_RENDERABLE_TYPE, _COGL_RENDERABLE_BIT,
EGL_NONE };
EGLint num_configs;
eglGetConfigs(backend_wayland->edpy,
&backend_wayland->egl_config, 1, &num_configs);
if (num_configs < 1)
return FALSE;
backend_wayland->egl_surface =
eglCreatePbufferSurface(backend_wayland->edpy,
backend_wayland->egl_config,
attrs);
if (backend_wayland->egl_surface == EGL_NO_SURFACE)
return FALSE;
return TRUE; return TRUE;
} }
@ -286,20 +382,18 @@ try_create_context (ClutterBackend *backend,
ClutterBackendWayland *backend_wayland = CLUTTER_BACKEND_WAYLAND (backend); ClutterBackendWayland *backend_wayland = CLUTTER_BACKEND_WAYLAND (backend);
const char *error_message; const char *error_message;
eglBindAPI (EGL_OPENGL_API);
if (backend_wayland->egl_context == EGL_NO_CONTEXT) if (backend_wayland->egl_context == EGL_NO_CONTEXT)
{ {
#if defined (HAVE_COGL_GLES2) #if defined(HAVE_COGL_GL)
static const EGLint attribs[] =
{ EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
#else
static const EGLint *attribs = NULL; static const EGLint *attribs = NULL;
#else
static const EGLint attribs[] =
{ EGL_CONTEXT_CLIENT_VERSION, _COGL_GLES_VERSION, EGL_NONE };
#endif #endif
backend_wayland->egl_context = backend_wayland->egl_context =
eglCreateContext (backend_wayland->edpy, eglCreateContext (backend_wayland->edpy,
NULL, backend_wayland->egl_config,
EGL_NO_CONTEXT, EGL_NO_CONTEXT,
attribs); attribs);
if (backend_wayland->egl_context == EGL_NO_CONTEXT) if (backend_wayland->egl_context == EGL_NO_CONTEXT)
@ -312,13 +406,13 @@ try_create_context (ClutterBackend *backend,
} }
if (!eglMakeCurrent (backend_wayland->edpy, if (!eglMakeCurrent (backend_wayland->edpy,
NULL, backend_wayland->egl_surface,
NULL, backend_wayland->egl_surface,
backend_wayland->egl_context)) backend_wayland->egl_context))
{ {
g_set_error (error, CLUTTER_INIT_ERROR, g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_BACKEND, CLUTTER_INIT_ERROR_BACKEND,
"Unable to MakeCurrent with NULL drawables"); "Unable to MakeCurrent");
return FALSE; return FALSE;
} }
@ -334,6 +428,14 @@ fail:
} }
} }
#if defined(HAVE_COGL_GL)
#define _COGL_SURFACELESS_EXTENSION "EGL_KHR_surfaceless_opengl"
#elif defined(HAVE_COGL_GLES)
#define _COGL_SURFACELESS_EXTENSION "EGL_KHR_surfaceless_gles1"
#elif defined(HAVE_COGL_GLES2)
#define _COGL_SURFACELESS_EXTENSION "EGL_KHR_surfaceless_gles2"
#endif
static gboolean static gboolean
clutter_backend_wayland_create_context (ClutterBackend *backend, clutter_backend_wayland_create_context (ClutterBackend *backend,
GError **error) GError **error)
@ -348,16 +450,30 @@ clutter_backend_wayland_create_context (ClutterBackend *backend,
if (backend_wayland->egl_context != EGL_NO_CONTEXT) if (backend_wayland->egl_context != EGL_NO_CONTEXT)
return TRUE; return TRUE;
#if defined(HAVE_COGL_GL)
eglBindAPI (EGL_OPENGL_API);
#else
eglBindAPI (EGL_OPENGL_ES_API);
#endif
egl_extensions = eglQueryString (backend_wayland->edpy, EGL_EXTENSIONS); egl_extensions = eglQueryString (backend_wayland->edpy, EGL_EXTENSIONS);
if (!_cogl_check_extension ("EGL_KHR_surfaceless_opengl", egl_extensions)) if (!_cogl_check_extension (_COGL_SURFACELESS_EXTENSION, egl_extensions))
{
g_debug("Could not find the " _COGL_SURFACELESS_EXTENSION
" extension; falling back to binding a dummy surface");
if (!make_dummy_surface(backend_wayland))
{ {
g_set_error (error, CLUTTER_INIT_ERROR, g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_BACKEND, CLUTTER_INIT_ERROR_BACKEND,
"Wayland clients require the " "Could not create dummy surface");
"EGL_KHR_surfaceless_opengl extension");
return FALSE; return FALSE;
} }
}
else
{
backend_wayland->egl_config = NULL;
backend_wayland->egl_surface = EGL_NO_SURFACE;
}
retry_cookie = 0; retry_cookie = 0;
while (!(status = try_create_context (backend, while (!(status = try_create_context (backend,
@ -541,6 +657,7 @@ _clutter_backend_wayland_class_init (ClutterBackendWaylandClass *klass)
static void static void
_clutter_backend_wayland_init (ClutterBackendWayland *backend_wayland) _clutter_backend_wayland_init (ClutterBackendWayland *backend_wayland)
{ {
backend_wayland->edpy = EGL_NO_DISPLAY;
backend_wayland->egl_context = EGL_NO_CONTEXT; backend_wayland->egl_context = EGL_NO_CONTEXT;
backend_wayland->drm_fd = -1; backend_wayland->drm_fd = -1;

View File

@ -57,6 +57,7 @@ struct _ClutterBackendWayland
EGLDisplay edpy; EGLDisplay edpy;
EGLContext egl_context; EGLContext egl_context;
EGLConfig egl_config; EGLConfig egl_config;
EGLSurface egl_surface;
gint egl_version_major; gint egl_version_major;
gint egl_version_minor; gint egl_version_minor;
@ -66,11 +67,13 @@ struct _ClutterBackendWayland
struct wl_compositor *wayland_compositor; struct wl_compositor *wayland_compositor;
struct wl_shell *wayland_shell; struct wl_shell *wayland_shell;
struct wl_drm *wayland_drm; struct wl_drm *wayland_drm;
struct wl_shm *wayland_shm;
char *device_name; char *device_name;
int authenticated; int authenticated;
struct wl_output *wayland_output; struct wl_output *wayland_output;
ClutterGeometry screen_allocation; ClutterGeometry screen_allocation;
int drm_fd; int drm_fd;
gboolean drm_enabled;
PFNEGLGETDRMDISPLAYMESA get_drm_display; PFNEGLGETDRMDISPLAYMESA get_drm_display;
PFNEGLCREATEDRMIMAGEMESA create_drm_image; PFNEGLCREATEDRMIMAGEMESA create_drm_image;

View File

@ -28,7 +28,12 @@
#include "config.h" #include "config.h"
#endif #endif
#include <fcntl.h>
#include <glib.h>
#include <glib/gstdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>
#include <wayland-util.h> #include <wayland-util.h>
#include <wayland-client.h> #include <wayland-client.h>
#include <xf86drm.h> #include <xf86drm.h>
@ -59,14 +64,82 @@ G_DEFINE_TYPE_WITH_CODE (ClutterStageWayland,
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_STAGE_WINDOW, G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_STAGE_WINDOW,
clutter_stage_window_iface_init)); clutter_stage_window_iface_init));
#if G_BYTE_ORDER == G_BIG_ENDIAN
#define VISUAL_ARGB_PRE COGL_PIXEL_FORMAT_ARGB_8888_PRE
#define VISUAL_ARGB COGL_PIXEL_FORMAT_ARGB_8888
#define VISUAL_RGB COGL_PIXEL_FORMAT_RGB_888
#elif G_BYTE_ORDER == G_LITTLE_ENDIAN
#define VISUAL_ARGB_PRE COGL_PIXEL_FORMAT_BGRA_8888_PRE
#define VISUAL_ARGB COGL_PIXEL_FORMAT_BGRA_8888
#define VISUAL_RGB COGL_PIXEL_FORMAT_BGR_888
#endif
static struct wl_visual *
get_visual (struct wl_display *display, CoglPixelFormat format)
{
switch (format)
{
case VISUAL_ARGB_PRE:
return wl_display_get_premultiplied_argb_visual (display);
case VISUAL_ARGB:
return wl_display_get_argb_visual (display);
case VISUAL_RGB:
return wl_display_get_rgb_visual (display);
default:
return NULL;
}
}
static ClutterStageWaylandWaylandBuffer * static ClutterStageWaylandWaylandBuffer *
wayland_create_buffer (ClutterStageWayland *stage_wayland, wayland_create_shm_buffer (ClutterBackendWayland *backend_wayland,
ClutterGeometry *geom)
{
ClutterStageWaylandWaylandBufferSHM *buffer;
struct wl_visual *visual;
CoglHandle tex;
CoglTextureFlags flags = COGL_TEXTURE_NONE; /* XXX: tweak flags? */
CoglPixelFormat format = VISUAL_ARGB_PRE;
int fd;
gchar tmp[] = "/tmp/clutter-wayland-shm-XXXXXX";
buffer = g_slice_new (ClutterStageWaylandWaylandBufferSHM);
buffer->buffer.type = BUFFER_TYPE_SHM;
tex = cogl_texture_new_with_size ((unsigned int)geom->width,
(unsigned int)geom->height,
flags, format);
buffer->format = format;
buffer->stride = cogl_texture_get_rowstride(tex);
buffer->size = cogl_texture_get_data(tex, format, buffer->stride, NULL);
buffer->buffer.tex = tex;
fd = g_mkstemp_full(tmp, O_RDWR, 0600);
ftruncate(fd, buffer->size);
buffer->data = mmap(NULL, buffer->size, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
g_unlink(tmp);
visual = get_visual (backend_wayland->wayland_display, format);
buffer->buffer.wayland_buffer =
wl_shm_create_buffer (backend_wayland->wayland_shm,
fd,
geom->width,
geom->height,
buffer->stride, visual);
close(fd);
return &buffer->buffer;
}
static ClutterStageWaylandWaylandBuffer *
wayland_create_drm_buffer (ClutterBackendWayland *backend_wayland,
ClutterGeometry *geom) ClutterGeometry *geom)
{ {
ClutterBackend *backend = clutter_get_default_backend ();
ClutterBackendWayland *backend_wayland = CLUTTER_BACKEND_WAYLAND (backend);
EGLDisplay edpy = clutter_wayland_get_egl_display (); EGLDisplay edpy = clutter_wayland_get_egl_display ();
ClutterStageWaylandWaylandBuffer *buffer; struct wl_visual *visual;
EGLint name, stride;
ClutterStageWaylandWaylandBufferDRM *buffer;
EGLint image_attribs[] = { EGLint image_attribs[] = {
EGL_WIDTH, 0, EGL_WIDTH, 0,
EGL_HEIGHT, 0, EGL_HEIGHT, 0,
@ -74,12 +147,10 @@ wayland_create_buffer (ClutterStageWayland *stage_wayland,
EGL_DRM_BUFFER_USE_MESA, EGL_DRM_BUFFER_USE_SCANOUT_MESA, EGL_DRM_BUFFER_USE_MESA, EGL_DRM_BUFFER_USE_SCANOUT_MESA,
EGL_NONE EGL_NONE
}; };
struct wl_visual *visual;
EGLint name;
EGLint stride;
cairo_rectangle_int_t rect;
buffer = g_slice_new (ClutterStageWaylandWaylandBuffer); buffer = g_slice_new (ClutterStageWaylandWaylandBufferDRM);
buffer->buffer.type = BUFFER_TYPE_DRM;
image_attribs[1] = geom->width; image_attribs[1] = geom->width;
image_attribs[3] = geom->height; image_attribs[3] = geom->height;
@ -88,26 +159,45 @@ wayland_create_buffer (ClutterStageWayland *stage_wayland,
glBindTexture (GL_TEXTURE_2D, buffer->texture); glBindTexture (GL_TEXTURE_2D, buffer->texture);
backend_wayland->image_target_texture_2d (GL_TEXTURE_2D, buffer->drm_image); backend_wayland->image_target_texture_2d (GL_TEXTURE_2D, buffer->drm_image);
buffer->tex = cogl_texture_new_from_foreign (buffer->texture, buffer->buffer.tex = cogl_texture_new_from_foreign (buffer->texture,
GL_TEXTURE_2D, GL_TEXTURE_2D,
geom->width, geom->width,
geom->height, geom->height,
0, 0,
0, 0,
COGL_PIXEL_FORMAT_ARGB_8888); VISUAL_ARGB_PRE);
buffer->offscreen = cogl_offscreen_new_to_texture (buffer->tex);
backend_wayland->export_drm_image (edpy, buffer->drm_image, backend_wayland->export_drm_image (edpy, buffer->drm_image,
&name, NULL, &stride); &name, NULL, &stride);
visual = visual = get_visual (backend_wayland->wayland_display, VISUAL_ARGB_PRE);
wl_display_get_premultiplied_argb_visual (backend_wayland->wayland_display); buffer->buffer.wayland_buffer =
buffer->wayland_buffer =
wl_drm_create_buffer (backend_wayland->wayland_drm, wl_drm_create_buffer (backend_wayland->wayland_drm,
name, name,
stage_wayland->allocation.width, geom->width,
stage_wayland->allocation.height, geom->height,
stride, visual); stride, visual);
return &buffer->buffer;
}
static ClutterStageWaylandWaylandBuffer *
wayland_create_buffer (ClutterGeometry *geom)
{
ClutterBackend *backend = clutter_get_default_backend ();
ClutterBackendWayland *backend_wayland = CLUTTER_BACKEND_WAYLAND (backend);
ClutterStageWaylandWaylandBuffer *buffer;
cairo_rectangle_int_t rect;
if (backend_wayland->drm_enabled &&
backend_wayland->wayland_drm != NULL)
buffer = wayland_create_drm_buffer (backend_wayland, geom);
else if (backend_wayland->wayland_shm != NULL)
buffer = wayland_create_shm_buffer (backend_wayland, geom);
else
return NULL;
buffer->offscreen = cogl_offscreen_new_to_texture (buffer->tex);
rect.x = geom->x; rect.x = geom->x;
rect.y = geom->y; rect.y = geom->y;
rect.width = geom->width; rect.width = geom->width;
@ -118,18 +208,42 @@ wayland_create_buffer (ClutterStageWayland *stage_wayland,
} }
static void static void
wayland_free_buffer (ClutterStageWaylandWaylandBuffer *buffer) wayland_free_shm_buffer (ClutterStageWaylandWaylandBuffer *generic_buffer)
{
ClutterStageWaylandWaylandBufferSHM *buffer;
buffer = (ClutterStageWaylandWaylandBufferSHM *)generic_buffer;
munmap(buffer->data, buffer->size);
g_slice_free (ClutterStageWaylandWaylandBufferSHM, buffer);
}
static void
wayland_free_drm_buffer (ClutterStageWaylandWaylandBuffer *generic_buffer)
{ {
ClutterBackend *backend = clutter_get_default_backend (); ClutterBackend *backend = clutter_get_default_backend ();
ClutterBackendWayland *backend_wayland = CLUTTER_BACKEND_WAYLAND (backend); ClutterBackendWayland *backend_wayland = CLUTTER_BACKEND_WAYLAND (backend);
EGLDisplay edpy = clutter_wayland_get_egl_display (); EGLDisplay edpy = clutter_wayland_get_egl_display ();
ClutterStageWaylandWaylandBufferDRM *buffer;
buffer = (ClutterStageWaylandWaylandBufferDRM *)generic_buffer;
glDeleteTextures (1, &buffer->texture);
backend_wayland->destroy_image (edpy, buffer->drm_image);
g_slice_free (ClutterStageWaylandWaylandBufferDRM, buffer);
}
static void
wayland_free_buffer (ClutterStageWaylandWaylandBuffer *buffer)
{
cogl_handle_unref (buffer->tex); cogl_handle_unref (buffer->tex);
wl_buffer_destroy (buffer->wayland_buffer); wl_buffer_destroy (buffer->wayland_buffer);
cogl_handle_unref (buffer->offscreen); cogl_handle_unref (buffer->offscreen);
glDeleteTextures (1, &buffer->texture);
backend_wayland->destroy_image (edpy, buffer->drm_image); if (buffer->type == BUFFER_TYPE_DRM)
g_slice_free (ClutterStageWaylandWaylandBuffer, buffer); wayland_free_drm_buffer(buffer);
else if (buffer->type == BUFFER_TYPE_SHM)
wayland_free_shm_buffer(buffer);
} }
static void static void
@ -171,7 +285,7 @@ clutter_stage_wayland_realize (ClutterStageWindow *stage_window)
wl_surface_set_user_data (stage_wayland->wayland_surface, stage_wayland); wl_surface_set_user_data (stage_wayland->wayland_surface, stage_wayland);
stage_wayland->pick_buffer = stage_wayland->pick_buffer =
wayland_create_buffer (stage_wayland, &stage_wayland->allocation); wayland_create_buffer (&stage_wayland->allocation);
return TRUE; return TRUE;
} }
@ -349,6 +463,26 @@ wayland_frame_callback (void *data, uint32_t _time)
stage_wayland->pending_swaps--; stage_wayland->pending_swaps--;
} }
static void
wayland_damage_buffer(ClutterStageWaylandWaylandBuffer *generic_buffer)
{
ClutterStageWaylandWaylandBufferSHM *buffer;
int size;
if (generic_buffer->type != BUFFER_TYPE_SHM)
return;
buffer = (ClutterStageWaylandWaylandBufferSHM *)generic_buffer;
size = cogl_texture_get_data(buffer->buffer.tex, buffer->format,
buffer->stride, NULL);
g_assert(size == (int)buffer->size);
(void) cogl_texture_get_data(buffer->buffer.tex, buffer->format,
buffer->stride, buffer->data);
}
static void static void
wayland_swap_buffers (ClutterStageWayland *stage_wayland) wayland_swap_buffers (ClutterStageWayland *stage_wayland)
{ {
@ -360,13 +494,13 @@ wayland_swap_buffers (ClutterStageWayland *stage_wayland)
stage_wayland->front_buffer = stage_wayland->back_buffer; stage_wayland->front_buffer = stage_wayland->back_buffer;
stage_wayland->back_buffer = buffer; stage_wayland->back_buffer = buffer;
wayland_damage_buffer(stage_wayland->front_buffer);
wl_surface_attach (stage_wayland->wayland_surface, wl_surface_attach (stage_wayland->wayland_surface,
stage_wayland->front_buffer->wayland_buffer); stage_wayland->front_buffer->wayland_buffer,
wl_surface_map (stage_wayland->wayland_surface, /* 0,0 here is "relative to the old buffer," not absolute */
stage_wayland->allocation.x, 0, 0);
stage_wayland->allocation.y, wl_surface_map_toplevel (stage_wayland->wayland_surface);
stage_wayland->allocation.width,
stage_wayland->allocation.height);
stage_wayland->pending_swaps++; stage_wayland->pending_swaps++;
wl_display_frame_callback (backend_wayland->wayland_display, wl_display_frame_callback (backend_wayland->wayland_display,
@ -506,7 +640,7 @@ _clutter_stage_wayland_redraw (ClutterStageWayland *stage_wayland,
if (!stage_wayland->back_buffer) if (!stage_wayland->back_buffer)
stage_wayland->back_buffer = stage_wayland->back_buffer =
wayland_create_buffer (stage_wayland, &stage_wayland->allocation); wayland_create_buffer (&stage_wayland->allocation);
cogl_set_framebuffer (stage_wayland->back_buffer->offscreen); cogl_set_framebuffer (stage_wayland->back_buffer->offscreen);
_clutter_stage_maybe_setup_viewport (stage_wayland->wrapper); _clutter_stage_maybe_setup_viewport (stage_wayland->wrapper);

View File

@ -51,16 +51,34 @@
typedef struct _ClutterStageWayland ClutterStageWayland; typedef struct _ClutterStageWayland ClutterStageWayland;
typedef struct _ClutterStageWaylandClass ClutterStageWaylandClass; typedef struct _ClutterStageWaylandClass ClutterStageWaylandClass;
#define BUFFER_TYPE_DRM 1
#define BUFFER_TYPE_SHM 2
typedef struct _ClutterStageWaylandWaylandBuffer typedef struct _ClutterStageWaylandWaylandBuffer
{ {
EGLImageKHR drm_image;
GLuint texture;
CoglHandle offscreen; CoglHandle offscreen;
struct wl_buffer *wayland_buffer; struct wl_buffer *wayland_buffer;
cairo_region_t *dirty_region; cairo_region_t *dirty_region;
CoglHandle tex; CoglHandle tex;
guint type;
} ClutterStageWaylandWaylandBuffer; } ClutterStageWaylandWaylandBuffer;
typedef struct _ClutterStageWaylandWaylandBufferDRM
{
ClutterStageWaylandWaylandBuffer buffer;
EGLImageKHR drm_image;
GLuint texture;
} ClutterStageWaylandWaylandBufferDRM;
typedef struct _ClutterStageWaylandWaylandBufferSHM
{
ClutterStageWaylandWaylandBuffer buffer;
CoglPixelFormat format;
guint8 *data;
size_t size;
unsigned int stride;
} ClutterStageWaylandWaylandBufferSHM;
struct _ClutterStageWayland struct _ClutterStageWayland
{ {
GObject parent_instance; GObject parent_instance;