mirror of
https://github.com/brl/mutter.git
synced 2025-03-28 06:03:47 +00:00
clutter-cairo-texture: Use the new cogl_pixel_buffer API
ClutterCairoTexture now stores the surface image data in a Cogl pixel buffer object. When clutter_cairo_texture_create is called the buffer is mapped and a new Cairo surface is created to render directly to the PBO. When the surface is destroyed the buffer is unmapped and a Cogl texture is recreated from the buffer. This should enable slightly faster uploads when using Cairo because it avoids having to copy the surface data to the texture. http://bugzilla.openedhand.com/show_bug.cgi?id=1982 Signed-off-by: Emmanuele Bassi <ebassi@linux.intel.com>
This commit is contained in:
parent
1a1e7d3573
commit
716ec82db8
@ -81,6 +81,8 @@
|
|||||||
#include "clutter-cairo-texture.h"
|
#include "clutter-cairo-texture.h"
|
||||||
#include "clutter-debug.h"
|
#include "clutter-debug.h"
|
||||||
#include "clutter-private.h"
|
#include "clutter-private.h"
|
||||||
|
#include "cogl/cogl-pixel-buffer.h"
|
||||||
|
#include "cogl/cogl-buffer.h"
|
||||||
|
|
||||||
G_DEFINE_TYPE (ClutterCairoTexture,
|
G_DEFINE_TYPE (ClutterCairoTexture,
|
||||||
clutter_cairo_texture,
|
clutter_cairo_texture,
|
||||||
@ -118,14 +120,15 @@ enum
|
|||||||
|
|
||||||
struct _ClutterCairoTexturePrivate
|
struct _ClutterCairoTexturePrivate
|
||||||
{
|
{
|
||||||
cairo_format_t format;
|
cairo_format_t format;
|
||||||
|
|
||||||
cairo_surface_t *cr_surface;
|
CoglHandle buffer;
|
||||||
guchar *cr_surface_data;
|
guint buffer_width;
|
||||||
|
guint buffer_height;
|
||||||
|
|
||||||
guint width;
|
guint width;
|
||||||
guint height;
|
guint height;
|
||||||
guint rowstride;
|
guint rowstride;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
@ -143,15 +146,6 @@ typedef struct
|
|||||||
} ClutterCairoTextureContext;
|
} ClutterCairoTextureContext;
|
||||||
|
|
||||||
static const cairo_user_data_key_t clutter_cairo_texture_surface_key;
|
static const cairo_user_data_key_t clutter_cairo_texture_surface_key;
|
||||||
static const cairo_user_data_key_t clutter_cairo_texture_context_key;
|
|
||||||
|
|
||||||
static void
|
|
||||||
clutter_cairo_texture_surface_destroy (void *data)
|
|
||||||
{
|
|
||||||
ClutterCairoTexture *cairo = data;
|
|
||||||
|
|
||||||
cairo->priv->cr_surface = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
clutter_cairo_texture_set_property (GObject *object,
|
clutter_cairo_texture_set_property (GObject *object,
|
||||||
@ -210,23 +204,10 @@ clutter_cairo_texture_finalize (GObject *object)
|
|||||||
{
|
{
|
||||||
ClutterCairoTexturePrivate *priv = CLUTTER_CAIRO_TEXTURE (object)->priv;
|
ClutterCairoTexturePrivate *priv = CLUTTER_CAIRO_TEXTURE (object)->priv;
|
||||||
|
|
||||||
if (priv->cr_surface)
|
if (priv->buffer)
|
||||||
{
|
{
|
||||||
cairo_surface_t *surface = priv->cr_surface;
|
cogl_handle_unref (priv->buffer);
|
||||||
|
priv->buffer = NULL;
|
||||||
cairo_surface_finish (priv->cr_surface);
|
|
||||||
cairo_surface_set_user_data (priv->cr_surface,
|
|
||||||
&clutter_cairo_texture_surface_key,
|
|
||||||
NULL, NULL);
|
|
||||||
cairo_surface_destroy (surface);
|
|
||||||
|
|
||||||
priv->cr_surface = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (priv->cr_surface_data)
|
|
||||||
{
|
|
||||||
g_free (priv->cr_surface_data);
|
|
||||||
priv->cr_surface_data = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
G_OBJECT_CLASS (clutter_cairo_texture_parent_class)->finalize (object);
|
G_OBJECT_CLASS (clutter_cairo_texture_parent_class)->finalize (object);
|
||||||
@ -236,80 +217,30 @@ static inline void
|
|||||||
clutter_cairo_texture_surface_resize_internal (ClutterCairoTexture *cairo)
|
clutter_cairo_texture_surface_resize_internal (ClutterCairoTexture *cairo)
|
||||||
{
|
{
|
||||||
ClutterCairoTexturePrivate *priv = cairo->priv;
|
ClutterCairoTexturePrivate *priv = cairo->priv;
|
||||||
CoglHandle cogl_texture;
|
|
||||||
|
|
||||||
if (priv->cr_surface)
|
if (priv->buffer)
|
||||||
{
|
{
|
||||||
cairo_surface_t *surface = priv->cr_surface;
|
/* If the buffer is already the right size then don't bother
|
||||||
|
|
||||||
/* If the surface is already the right size then don't bother
|
|
||||||
doing anything */
|
doing anything */
|
||||||
if (priv->width == cairo_image_surface_get_width (priv->cr_surface)
|
if (priv->buffer_width == priv->width &&
|
||||||
&& priv->height == cairo_image_surface_get_height (priv->cr_surface))
|
priv->buffer_height == priv->height)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
cairo_surface_finish (surface);
|
cogl_handle_unref (priv->buffer);
|
||||||
cairo_surface_set_user_data (surface,
|
priv->buffer = COGL_INVALID_HANDLE;
|
||||||
&clutter_cairo_texture_surface_key,
|
|
||||||
NULL, NULL);
|
|
||||||
cairo_surface_destroy (surface);
|
|
||||||
|
|
||||||
priv->cr_surface = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (priv->cr_surface_data)
|
|
||||||
{
|
|
||||||
g_free (priv->cr_surface_data);
|
|
||||||
priv->cr_surface_data = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (priv->width == 0 || priv->height == 0)
|
if (priv->width == 0 || priv->height == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
#if CAIRO_VERSION > 106000
|
priv->buffer =
|
||||||
priv->rowstride = cairo_format_stride_for_width (priv->format, priv->width);
|
cogl_pixel_buffer_new_for_size (priv->width,
|
||||||
#else
|
priv->height,
|
||||||
/* poor man's version of cairo_format_stride_for_width() */
|
CLUTTER_CAIRO_TEXTURE_PIXEL_FORMAT,
|
||||||
switch (priv->format)
|
&priv->rowstride);
|
||||||
{
|
|
||||||
case CAIRO_FORMAT_ARGB32:
|
|
||||||
case CAIRO_FORMAT_RGB24:
|
|
||||||
priv->rowstride = priv->width * 4;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CAIRO_FORMAT_A8:
|
priv->buffer_width = priv->width;
|
||||||
case CAIRO_FORMAT_A1:
|
priv->buffer_height = priv->height;
|
||||||
priv->rowstride = priv->width;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
g_assert_not_reached ();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#endif /* CAIRO_VERSION > 106000 */
|
|
||||||
|
|
||||||
priv->cr_surface_data = g_malloc0 (priv->height * priv->rowstride);
|
|
||||||
priv->cr_surface =
|
|
||||||
cairo_image_surface_create_for_data (priv->cr_surface_data,
|
|
||||||
priv->format,
|
|
||||||
priv->width, priv->height,
|
|
||||||
priv->rowstride);
|
|
||||||
|
|
||||||
cairo_surface_set_user_data (priv->cr_surface,
|
|
||||||
&clutter_cairo_texture_surface_key,
|
|
||||||
cairo,
|
|
||||||
clutter_cairo_texture_surface_destroy);
|
|
||||||
|
|
||||||
/* Create a blank Cogl texture
|
|
||||||
*/
|
|
||||||
cogl_texture = cogl_texture_new_from_data (priv->width, priv->height,
|
|
||||||
COGL_TEXTURE_NONE,
|
|
||||||
CLUTTER_CAIRO_TEXTURE_PIXEL_FORMAT,
|
|
||||||
COGL_PIXEL_FORMAT_ANY,
|
|
||||||
priv->rowstride,
|
|
||||||
priv->cr_surface_data);
|
|
||||||
clutter_texture_set_cogl_texture (CLUTTER_TEXTURE (cairo), cogl_texture);
|
|
||||||
cogl_handle_unref (cogl_texture);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -321,8 +252,8 @@ clutter_cairo_texture_notify (GObject *object,
|
|||||||
that if both the width and height properties are set using a
|
that if both the width and height properties are set using a
|
||||||
single call to g_object_set then the surface will only be resized
|
single call to g_object_set then the surface will only be resized
|
||||||
once because the notifications will be frozen in between */
|
once because the notifications will be frozen in between */
|
||||||
if (!strcmp ("surface-width", pspec->name)
|
if (!strcmp ("surface-width", pspec->name) ||
|
||||||
|| !strcmp ("surface-height", pspec->name))
|
!strcmp ("surface-height", pspec->name))
|
||||||
{
|
{
|
||||||
ClutterCairoTexture *cairo = CLUTTER_CAIRO_TEXTURE (object);
|
ClutterCairoTexture *cairo = CLUTTER_CAIRO_TEXTURE (object);
|
||||||
|
|
||||||
@ -453,46 +384,31 @@ clutter_cairo_texture_new (guint width,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
clutter_cairo_texture_context_destroy (void *data)
|
clutter_cairo_texture_surface_destroy (void *data)
|
||||||
{
|
{
|
||||||
ClutterCairoTextureContext *ctxt = data;
|
ClutterCairoTextureContext *ctxt = data;
|
||||||
ClutterCairoTexture *cairo = ctxt->cairo;
|
ClutterCairoTexture *cairo = ctxt->cairo;
|
||||||
ClutterCairoTexturePrivate *priv = cairo->priv;
|
ClutterCairoTexturePrivate *priv = cairo->priv;
|
||||||
guchar *cairo_data;
|
|
||||||
gint cairo_width, cairo_height;
|
|
||||||
gint surface_width, surface_height;
|
|
||||||
CoglHandle cogl_texture;
|
CoglHandle cogl_texture;
|
||||||
|
|
||||||
if (!priv->cr_surface)
|
if (!priv->buffer)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
surface_width = cairo_image_surface_get_width (priv->cr_surface);
|
cogl_buffer_unmap (priv->buffer);
|
||||||
surface_height = cairo_image_surface_get_height (priv->cr_surface);
|
|
||||||
|
|
||||||
cairo_width = MIN (ctxt->rect.width, surface_width);
|
cogl_texture =
|
||||||
cairo_height = MIN (ctxt->rect.height, surface_height);
|
cogl_texture_new_from_buffer (priv->buffer,
|
||||||
|
priv->buffer_width,
|
||||||
|
priv->buffer_height,
|
||||||
|
COGL_TEXTURE_NONE,
|
||||||
|
CLUTTER_CAIRO_TEXTURE_PIXEL_FORMAT,
|
||||||
|
COGL_PIXEL_FORMAT_ANY,
|
||||||
|
priv->rowstride,
|
||||||
|
0);
|
||||||
|
|
||||||
cogl_texture = clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (cairo));
|
clutter_texture_set_cogl_texture (CLUTTER_TEXTURE (cairo), cogl_texture);
|
||||||
|
|
||||||
if (!cairo_width || !cairo_height || cogl_texture == COGL_INVALID_HANDLE)
|
cogl_handle_unref (cogl_texture);
|
||||||
{
|
|
||||||
g_free (ctxt);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
cairo_data = (priv->cr_surface_data
|
|
||||||
+ (ctxt->rect.y * priv->rowstride)
|
|
||||||
+ (ctxt->rect.x * 4));
|
|
||||||
|
|
||||||
cogl_texture_set_region (cogl_texture,
|
|
||||||
0, 0,
|
|
||||||
ctxt->rect.x, ctxt->rect.y,
|
|
||||||
cairo_width, cairo_height,
|
|
||||||
cairo_width, cairo_height,
|
|
||||||
CLUTTER_CAIRO_TEXTURE_PIXEL_FORMAT,
|
|
||||||
priv->rowstride,
|
|
||||||
cairo_data);
|
|
||||||
|
|
||||||
g_free (ctxt);
|
g_free (ctxt);
|
||||||
|
|
||||||
@ -559,6 +475,8 @@ clutter_cairo_texture_create_region (ClutterCairoTexture *self,
|
|||||||
ClutterCairoTextureContext *ctxt;
|
ClutterCairoTextureContext *ctxt;
|
||||||
ClutterCairoTextureRectangle region, area, inter;
|
ClutterCairoTextureRectangle region, area, inter;
|
||||||
cairo_t *cr;
|
cairo_t *cr;
|
||||||
|
cairo_surface_t *surface;
|
||||||
|
CoglHandle material;
|
||||||
|
|
||||||
g_return_val_if_fail (CLUTTER_IS_CAIRO_TEXTURE (self), NULL);
|
g_return_val_if_fail (CLUTTER_IS_CAIRO_TEXTURE (self), NULL);
|
||||||
|
|
||||||
@ -581,7 +499,7 @@ clutter_cairo_texture_create_region (ClutterCairoTexture *self,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!priv->cr_surface)
|
if (!priv->buffer)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
ctxt = g_new0 (ClutterCairoTextureContext, 1);
|
ctxt = g_new0 (ClutterCairoTextureContext, 1);
|
||||||
@ -605,9 +523,34 @@ clutter_cairo_texture_create_region (ClutterCairoTexture *self,
|
|||||||
ctxt->rect.width = inter.width;
|
ctxt->rect.width = inter.width;
|
||||||
ctxt->rect.height = inter.height;
|
ctxt->rect.height = inter.height;
|
||||||
|
|
||||||
cr = cairo_create (priv->cr_surface);
|
/* Destroy the existing texture so that the GL driver won't have to
|
||||||
cairo_set_user_data (cr, &clutter_cairo_texture_context_key,
|
copy it when we map the PBO */
|
||||||
ctxt, clutter_cairo_texture_context_destroy);
|
if ((material = clutter_texture_get_cogl_material (CLUTTER_TEXTURE (self))))
|
||||||
|
{
|
||||||
|
const GList *layers = cogl_material_get_layers (material);
|
||||||
|
if (layers)
|
||||||
|
cogl_material_set_layer (layers->data, 0, COGL_INVALID_HANDLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a surface to render directly to the PBO */
|
||||||
|
surface =
|
||||||
|
cairo_image_surface_create_for_data (cogl_buffer_map (priv->buffer,
|
||||||
|
COGL_BUFFER_ACCESS_READ |
|
||||||
|
COGL_BUFFER_ACCESS_WRITE),
|
||||||
|
priv->format,
|
||||||
|
priv->buffer_width,
|
||||||
|
priv->buffer_height,
|
||||||
|
priv->rowstride);
|
||||||
|
|
||||||
|
/* Set a key so that we can recreate the texture when the surface is
|
||||||
|
destroyed */
|
||||||
|
cairo_surface_set_user_data (surface, &clutter_cairo_texture_surface_key,
|
||||||
|
ctxt, clutter_cairo_texture_surface_destroy);
|
||||||
|
|
||||||
|
cr = cairo_create (surface);
|
||||||
|
/* Remove the reference we have on the surface so that it will be
|
||||||
|
destroyed when the context is destroyed */
|
||||||
|
cairo_surface_destroy (surface);
|
||||||
|
|
||||||
return cr;
|
return cr;
|
||||||
}
|
}
|
||||||
@ -751,13 +694,16 @@ void
|
|||||||
clutter_cairo_texture_clear (ClutterCairoTexture *self)
|
clutter_cairo_texture_clear (ClutterCairoTexture *self)
|
||||||
{
|
{
|
||||||
ClutterCairoTexturePrivate *priv;
|
ClutterCairoTexturePrivate *priv;
|
||||||
|
guint8 *data;
|
||||||
|
|
||||||
g_return_if_fail (CLUTTER_IS_CAIRO_TEXTURE (self));
|
g_return_if_fail (CLUTTER_IS_CAIRO_TEXTURE (self));
|
||||||
|
|
||||||
priv = self->priv;
|
priv = self->priv;
|
||||||
|
|
||||||
if (!priv->cr_surface_data)
|
if (!priv->buffer)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
memset (priv->cr_surface_data, 0, priv->height * priv->rowstride);
|
data = cogl_buffer_map (priv->buffer, COGL_BUFFER_ACCESS_WRITE);
|
||||||
|
memset (data, 0, priv->buffer_height * priv->rowstride);
|
||||||
|
cogl_buffer_unmap (priv->buffer);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user