Revert "clutter-cairo-texture: Use the new cogl_pixel_buffer API"

This reverts commit 716ec82db8.

The Cogl pixel buffer API currently has problems if an atlas texture
is created or the format needs to be converted. The atlas problem
doesn't currently show because the atlas rejects BGR textures anyway
but we may want to change this soon. The problem with format
conversion would happen under GLES because that does not support BGR
textures at all so Cogl has to do the conversion. However it doesn't
currently show either because GLES has no support for buffer objects
anyway.

It's also questionable whether the patch would give any performance
benefit because Cairo needs read/write access which implies the buffer
can't be put in write-optimised memory.

Conflicts:

	clutter/clutter-cairo-texture.c

http://bugzilla.openedhand.com/show_bug.cgi?id=1982
This commit is contained in:
Neil Roberts 2010-05-10 15:33:05 +01:00
parent af37a1029f
commit 16680c74f3

View File

@ -81,8 +81,6 @@
#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,
@ -120,15 +118,14 @@ enum
struct _ClutterCairoTexturePrivate struct _ClutterCairoTexturePrivate
{ {
cairo_format_t format; cairo_format_t format;
CoglHandle buffer; cairo_surface_t *cr_surface;
guint buffer_width; guchar *cr_surface_data;
guint buffer_height;
guint width; guint width;
guint height; guint height;
guint rowstride; guint rowstride;
}; };
typedef struct typedef struct
@ -146,6 +143,15 @@ 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,
@ -204,10 +210,23 @@ clutter_cairo_texture_finalize (GObject *object)
{ {
ClutterCairoTexturePrivate *priv = CLUTTER_CAIRO_TEXTURE (object)->priv; ClutterCairoTexturePrivate *priv = CLUTTER_CAIRO_TEXTURE (object)->priv;
if (priv->buffer) if (priv->cr_surface)
{ {
cogl_handle_unref (priv->buffer); cairo_surface_t *surface = priv->cr_surface;
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);
@ -217,30 +236,80 @@ 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->buffer) if (priv->cr_surface)
{ {
/* If the buffer is already the right size then don't bother cairo_surface_t *surface = priv->cr_surface;
/* If the surface is already the right size then don't bother
doing anything */ doing anything */
if (priv->buffer_width == priv->width && if (priv->width == cairo_image_surface_get_width (priv->cr_surface)
priv->buffer_height == priv->height) && priv->height == cairo_image_surface_get_height (priv->cr_surface))
return; return;
cogl_handle_unref (priv->buffer); cairo_surface_finish (surface);
priv->buffer = COGL_INVALID_HANDLE; cairo_surface_set_user_data (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;
} }
if (priv->width == 0 || priv->height == 0) if (priv->width == 0 || priv->height == 0)
return; return;
priv->buffer = #if CAIRO_VERSION > 106000
cogl_pixel_buffer_new_for_size (priv->width, priv->rowstride = cairo_format_stride_for_width (priv->format, priv->width);
priv->height, #else
CLUTTER_CAIRO_TEXTURE_PIXEL_FORMAT, /* poor man's version of cairo_format_stride_for_width() */
&priv->rowstride); switch (priv->format)
{
case CAIRO_FORMAT_ARGB32:
case CAIRO_FORMAT_RGB24:
priv->rowstride = priv->width * 4;
break;
priv->buffer_width = priv->width; case CAIRO_FORMAT_A8:
priv->buffer_height = priv->height; case CAIRO_FORMAT_A1:
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
@ -252,8 +321,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);
@ -384,31 +453,46 @@ clutter_cairo_texture_new (guint width,
} }
static void static void
clutter_cairo_texture_surface_destroy (void *data) clutter_cairo_texture_context_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->buffer) if (!priv->cr_surface)
return; return;
cogl_buffer_unmap (priv->buffer); surface_width = cairo_image_surface_get_width (priv->cr_surface);
surface_height = cairo_image_surface_get_height (priv->cr_surface);
cogl_texture = cairo_width = MIN (ctxt->rect.width, surface_width);
cogl_texture_new_from_buffer (priv->buffer, cairo_height = MIN (ctxt->rect.height, surface_height);
priv->buffer_width,
priv->buffer_height,
COGL_TEXTURE_NONE,
CLUTTER_CAIRO_TEXTURE_PIXEL_FORMAT,
COGL_PIXEL_FORMAT_ANY,
priv->rowstride,
0);
clutter_texture_set_cogl_texture (CLUTTER_TEXTURE (cairo), cogl_texture); cogl_texture = clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (cairo));
cogl_handle_unref (cogl_texture); if (!cairo_width || !cairo_height || cogl_texture == COGL_INVALID_HANDLE)
{
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);
@ -475,8 +559,6 @@ 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);
@ -499,7 +581,7 @@ clutter_cairo_texture_create_region (ClutterCairoTexture *self,
return NULL; return NULL;
} }
if (!priv->buffer) if (!priv->cr_surface)
return NULL; return NULL;
ctxt = g_new0 (ClutterCairoTextureContext, 1); ctxt = g_new0 (ClutterCairoTextureContext, 1);
@ -523,30 +605,9 @@ 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;
/* Destroy the existing texture so that the GL driver won't have to cr = cairo_create (priv->cr_surface);
copy it when we map the PBO */ cairo_set_user_data (cr, &clutter_cairo_texture_context_key,
if ((material = clutter_texture_get_cogl_material (CLUTTER_TEXTURE (self)))) ctxt, clutter_cairo_texture_context_destroy);
cogl_material_set_layer (material, 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;
} }
@ -690,16 +751,13 @@ 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->buffer) if (!priv->cr_surface_data)
return; return;
data = cogl_buffer_map (priv->buffer, COGL_BUFFER_ACCESS_WRITE); memset (priv->cr_surface_data, 0, priv->height * priv->rowstride);
memset (data, 0, priv->buffer_height * priv->rowstride);
cogl_buffer_unmap (priv->buffer);
} }