[cairo] [PATCH 39/39] [OpenVG] Added egl support to cairo-openvg
tardyp at gmail.com
tardyp at gmail.com
Fri Jul 10 10:02:41 PDT 2009
From: Pierre Tardy <tardyp at gmail.com>
This patch adds openvg acceleration for offscreen rendering using egl.
Use cairo_openvg_image_surface_create to create a image like surface
The application has nothing else to do than using cairo_openvg_image_surface_create
instead of cairo_image_surface_create to get openvg acceleration.
---
src/cairo-openvg-surface.c | 293 +++++++++++++++++++++++++++++++++++++++++---
src/cairo-openvg.h | 6 +
2 files changed, 283 insertions(+), 16 deletions(-)
diff --git a/src/cairo-openvg-surface.c b/src/cairo-openvg-surface.c
index fe18225..b14e0e2 100644
--- a/src/cairo-openvg-surface.c
+++ b/src/cairo-openvg-surface.c
@@ -27,6 +27,7 @@
* the specific language governing rights and limitations.
*
* Contributor(s):
+ * Pierre Tardy <tardyp at gmail.com> egl pbuffers support
* Ãyvind KolÃ¥s <pippin at gimp.org>
* Vladimi Vukicevic <vladimir at mozilla.com> (stubbed out base backend)
*/
@@ -39,6 +40,15 @@
#define MAX_OPACITIES 32
+//#define OPENVG_DEBUG
+#define EGL_SUPPORT
+
+// we make this a define, because egl is not mandatory for every openvg implementation.
+// FIXME: this option should be autodetected in the build plumbing
+#ifdef EGL_SUPPORT
+#include <egl/egl.h>
+#endif
+
typedef struct cached_image_t {
VGImage vg_image; /*< set to 0 when entry not used */
void *cairo_image;
@@ -61,8 +71,38 @@ typedef struct cairo_openvg_surface {
int opacity_level;
cached_image_t images[MAX_IMAGES];
+
+#ifdef EGL_SUPPORT
+ VGImage targetImage;
+ EGLSurface eglImageSurface;
+ VGImageFormat vgformat;
+
+#endif
} cairo_openvg_surface_t;
+#ifdef EGL_SUPPORT
+static EGLContext eglContext = 0;
+static EGLDisplay eglDisplay = 0;
+static EGLConfig eglConfig = 0;
+/* OpenVg needs a valid context on a valid surface for VgImage operations */
+static EGLSurface eglDummySurface = 0;
+#endif
+
+#ifdef OPENVG_DEBUG
+static void check_vg_errors(const char*function,int line)
+{
+ int err = vgGetError();
+ if (err != VG_NO_ERROR){
+ printf("%s+%d:vgError detected: 0x%08x.\n",function, line,err);
+ assert(err == VG_NO_ERROR);
+ }
+
+}
+#define CHECK_VG_ERRORS() check_vg_errors(__FILE__,__LINE__)
+#else
+#define CHECK_VG_ERRORS() do{}while(0)
+#endif //OPENVG_DEBUG
+
static void
_cairo_openvg_cairo_matrix_to_openvg (const cairo_matrix_t *src,
VGfloat *dst);
@@ -114,6 +154,7 @@ _cairo_openvg_surface_intersect_clip_path (void *asurface,
{
vgMask (VG_INVALID_HANDLE, VG_FILL_MASK, 0, 0, vgsurface->width, vgsurface->height);
vgSeti (VG_MASKING, VG_FALSE);
+ CHECK_VG_ERRORS();
return CAIRO_STATUS_SUCCESS;
}
@@ -166,6 +207,7 @@ _cairo_openvg_surface_intersect_clip_path (void *asurface,
cairo_destroy (cr);
cairo_surface_destroy (image);
+ CHECK_VG_ERRORS();
return status;
}
@@ -173,10 +215,11 @@ static cairo_int_status_t
_cairo_openvg_surface_get_extents (void *asurface,
cairo_rectangle_int_t *extents)
{
+ cairo_openvg_surface_t *vgsurface = asurface;
extents->x = 0;
extents->y = 0;
- extents->width = 0;
- extents->height = 0;
+ extents->width = vgsurface->width;
+ extents->height = vgsurface->height;
return CAIRO_STATUS_SUCCESS;
}
@@ -215,6 +258,7 @@ _cairo_path_to_openvg_path_move_to (void *closure,
stroke->dcount = 0;
}
+ CHECK_VG_ERRORS();
return CAIRO_STATUS_SUCCESS;
}
@@ -240,6 +284,7 @@ _cairo_path_to_openvg_path_line_to (void *closure,
stroke->dcount = 0;
}
+ CHECK_VG_ERRORS();
return CAIRO_STATUS_SUCCESS;
}
@@ -278,6 +323,7 @@ _cairo_path_to_openvg_path_curve_to (void *closure,
stroke->scount = 0;
stroke->dcount = 0;
}
+ CHECK_VG_ERRORS();
return CAIRO_STATUS_SUCCESS;
}
@@ -293,6 +339,7 @@ _cairo_path_to_openvg_path_close_path (void *closure)
stroke->scount = 0;
stroke->dcount = 0;
}
+ CHECK_VG_ERRORS();
return CAIRO_STATUS_SUCCESS;
}
@@ -312,6 +359,7 @@ _cairo_openvg_cairo_path_to_openvg_path (cairo_path_fixed_t *path,
_cairo_path_to_openvg_path_close_path,
stroke);
vgAppendPathData(stroke->path, stroke->scount, stroke->gseg, stroke->gdata);
+ CHECK_VG_ERRORS();
return status;
}
@@ -347,6 +395,7 @@ _cairo_openvg_cairo_operator_to_openvg (cairo_operator_t op)
return VG_BLEND_SRC_OVER;
}
+ CHECK_VG_ERRORS();
return VG_BLEND_SRC_OVER;
}
@@ -371,6 +420,7 @@ _cairo_openvg_cairo_line_join_to_openvg (cairo_line_join_t cjoin)
case CAIRO_LINE_JOIN_BEVEL: return VG_JOIN_BEVEL; break;
}
+ CHECK_VG_ERRORS();
return VG_JOIN_MITER;
}
@@ -387,6 +437,7 @@ _cairo_openvg_cairo_matrix_to_openvg (const cairo_matrix_t *src,
dst[6] = /* tx */ src->x0;
dst[7] = /* ty */ src->y0;
dst[8] = /* w2 */ 0;
+ CHECK_VG_ERRORS();
}
static cairo_status_t
@@ -414,6 +465,7 @@ _cairo_openvg_setup_gradient_stops (cairo_openvg_surface_t *vgsurface,
vgSetParameterfv (vgsurface->source_paint,
VG_PAINT_COLOR_RAMP_STOPS, numstops * 5, stops);
free (stops);
+ CHECK_VG_ERRORS();
return CAIRO_STATUS_SUCCESS;
}
@@ -433,6 +485,7 @@ static void setup_paint_matrix (cairo_pattern_t *pat)
vgLoadMatrix(vmat);
vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
+ CHECK_VG_ERRORS();
}
static cairo_status_t
@@ -453,6 +506,7 @@ _cairo_openvg_setup_linear_source (cairo_openvg_surface_t *vgsurface,
vgSetParameterfv (vgsurface->source_paint, VG_PAINT_LINEAR_GRADIENT, 4, linear);
setup_paint_matrix ((cairo_pattern_t*) lpat);
+ CHECK_VG_ERRORS();
return _cairo_openvg_setup_gradient_stops (vgsurface,
(cairo_gradient_pattern_t *) &lpat->base);
@@ -481,6 +535,7 @@ _cairo_openvg_setup_radial_source (cairo_openvg_surface_t *vgsurface,
/* FIXME: copy/adapt fixes from SVG backend to add inner radius */
+ CHECK_VG_ERRORS();
return _cairo_openvg_setup_gradient_stops (vgsurface,
(cairo_gradient_pattern_t *) rpat);
}
@@ -493,9 +548,10 @@ _cairo_openvg_setup_solid_source (cairo_openvg_surface_t *vgsurface,
spat->color.green,
spat->color.blue,
spat->color.alpha * vgsurface->alpha};
-
+
vgSetParameteri(vgsurface->source_paint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
vgSetParameterfv (vgsurface->source_paint, VG_PAINT_COLOR, 4, color);
+ CHECK_VG_ERRORS();
return CAIRO_STATUS_SUCCESS;
}
@@ -537,7 +593,7 @@ _cairo_openvg_setup_surface_source (cairo_openvg_surface_t *vgsurface,
}
}
- vgsurface->source_image = vgCreateImage (VG_sRGBA_8888,
+ vgsurface->source_image = vgCreateImage (VG_sARGB_8888,
image->width, image->height, VG_IMAGE_QUALITY_FASTER);
/* NONALIASED, FASTER, BETTER */
@@ -587,7 +643,7 @@ _cairo_openvg_setup_surface_source (cairo_openvg_surface_t *vgsurface,
} */
vgImageSubData (vgsurface->source_image, image->data, image->width*4,
- VG_sARGB_8888, 0, 0, image->width, image->height);
+ VG_sXRGB_8888, 0, 0, image->width, image->height);
/*free (data);*/
@@ -629,6 +685,7 @@ USED_CACHE:
setup_paint_matrix ((cairo_pattern_t*) spat);
+ CHECK_VG_ERRORS();
return status;
}
@@ -639,7 +696,7 @@ setup_source (cairo_openvg_surface_t *vgsurface,
/* this will bomb if one of the prior paint ops have failed to
* clean up after itself
*/
-
+
assert (vgsurface->source_image == 0);
if (source->type == CAIRO_PATTERN_TYPE_SOLID)
@@ -666,6 +723,7 @@ setup_source (cairo_openvg_surface_t *vgsurface,
{
printf ("not handling source of type: %i\n", source->type);
}
+ CHECK_VG_ERRORS();
return CAIRO_INT_STATUS_UNSUPPORTED;
}
@@ -735,6 +793,7 @@ _cairo_openvg_surface_stroke (void *asurface,
BAIL:
vgLoadMatrix (state);
+ CHECK_VG_ERRORS();
return rv;
}
@@ -772,10 +831,12 @@ _cairo_openvg_surface_fill (void *asurface,
vgSetPaint(vgsurface->source_paint, VG_FILL_PATH);
vgDrawPath (vg_path.path, VG_FILL_PATH);
vgDestroyPath (vg_path.path);
+ CHECK_VG_ERRORS();
teardown_source (vgsurface, source);
BAIL:
+ CHECK_VG_ERRORS();
return rv;
}
@@ -832,6 +893,7 @@ _cairo_openvg_surface_paint (void *asurface,
teardown_source (vgsurface, source);
BAIL:
+ CHECK_VG_ERRORS();
return rv;
}
@@ -864,6 +926,7 @@ _cairo_openvg_surface_mask (void *asurface,
vgsurface->opacity_level--;
vgsurface->alpha = vgsurface->opacity[vgsurface->opacity_level];
assert (vgsurface->opacity_level>=0);
+ CHECK_VG_ERRORS();
return status;
}
@@ -904,6 +967,14 @@ _cairo_openvg_surface_mask (void *asurface,
return status;
}
+static void
+_cairo_openvg_surface_get_font_options (void *abstract_surface,
+ cairo_font_options_t *options)
+{
+ _cairo_font_options_init_default (options);
+
+ cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_ON);
+}
@@ -935,15 +1006,56 @@ _cairo_openvg_surface_show_glyphs (void *asurface,
status = _cairo_openvg_surface_fill (asurface, op, source, &path, CAIRO_FILL_RULE_WINDING, 0.0, CAIRO_ANTIALIAS_SUBPIXEL, extents);
_cairo_path_fixed_fini (&path);
+ CHECK_VG_ERRORS();
return status;
}
+#ifdef EGL_SUPPORT
+static cairo_status_t
+_cairo_openvg_surface_acquire_source_image (void *abstract_surface,
+ cairo_image_surface_t **image_out,
+ void **image_extra)
+{
+ cairo_openvg_surface_t *s = (cairo_openvg_surface_t*) abstract_surface;
+ cairo_image_surface_t *i = (cairo_image_surface_t *)
+ cairo_image_surface_create (CAIRO_FORMAT_RGB24, // FIXME RGBA gives bad results.
+ s->width, /* Width */
+ s->height); /* Height */
+ vgFinish();
+ CHECK_VG_ERRORS();
+ /* we need to change context to the dummy surface in order to make openvg happy to give its pixels */
+ eglMakeCurrent(eglDisplay, eglDummySurface, eglDummySurface, eglContext);
+ vgGetImageSubData(s->targetImage,
+ i->data, i->stride,
+ s->vgformat,
+ 0, 0, s->width, s->height);
+ eglMakeCurrent(eglDisplay, s->eglImageSurface, s->eglImageSurface, eglContext);
+ CHECK_VG_ERRORS();
+ *image_out = i;
+ return CAIRO_STATUS_SUCCESS;
+}
+static void
+_cairo_openvg_surface_release_source_image (void *abstract_surface,
+ cairo_image_surface_t *image,
+ void *image_extra)
+{
+ cairo_surface_finish((cairo_surface_t *)image);
+}
+#endif // EGL_SUPPORT
static cairo_status_t
_cairo_openvg_surface_finish (void *abstract_surface)
{
cairo_openvg_surface_t *vgsurface = (cairo_openvg_surface_t*) abstract_surface;
if (vgsurface->source_paint != VG_INVALID_HANDLE)
- vgDestroyPaint (vgsurface->source_paint);
+ vgDestroyPaint (vgsurface->source_paint);
+
+#ifdef EGL_SUPPORT
+ eglMakeCurrent(eglDisplay, eglDummySurface, eglDummySurface, eglContext);
+ eglDestroySurface(eglDisplay, vgsurface->eglImageSurface);
+ vgDestroyImage(vgsurface->targetImage);
+#endif
+
+ CHECK_VG_ERRORS();
return CAIRO_STATUS_SUCCESS;
}
@@ -952,8 +1064,13 @@ cairo_openvg_surface_backend = {
CAIRO_SURFACE_TYPE_OPENVG,
_cairo_openvg_surface_create_similar,
_cairo_openvg_surface_finish,
+#ifdef EGL_SUPPORT
+ _cairo_openvg_surface_acquire_source_image,
+ _cairo_openvg_surface_release_source_image,
+#else
NULL, /* acquire_source_image */
NULL, /* release_source_image */
+#endif
NULL, /* acquire_dest_image */
NULL, /* release_dest_image */
_cairo_openvg_surface_clone_similar,
@@ -968,7 +1085,7 @@ cairo_openvg_surface_backend = {
_cairo_openvg_surface_intersect_clip_path,
_cairo_openvg_surface_get_extents,
NULL, /* old_show_glyphs */
- NULL, /* get_font_options */
+ _cairo_openvg_surface_get_font_options, /* get_font_options */
NULL, /* flush */
NULL, /* mark_dirty_rectangle */
NULL, /* scaled_font_fini */
@@ -984,31 +1101,175 @@ cairo_openvg_surface_backend = {
NULL, /* is_similar */
NULL, /* reset */
};
+#ifdef EGL_SUPPORT
+/* FIXME static configuration of the pixel format! */
+static const int ai32ARGB32ConfigAttribs[] =
+{
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_ALPHA_SIZE, 8,
+ EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
+ EGL_RENDERABLE_TYPE, EGL_OPENVG_BIT,
+ EGL_NONE
+};
+static const int ai32RGB24ConfigAttribs[] =
+{
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_ALPHA_SIZE, 8,
+ EGL_VG_ALPHA_FORMAT,EGL_VG_ALPHA_FORMAT_PRE,
+ EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
+ EGL_RENDERABLE_TYPE, EGL_OPENVG_BIT,
+ EGL_NONE
+};
+#define ai32ConfigAttribs ai32RGB24ConfigAttribs
+static const int ai32PBufferAttribs[] =
+{
+ EGL_WIDTH, 8, EGL_HEIGHT, 8, /* small non zero aligned stub values (just in case) */
+ EGL_NONE /* other attribs are default ones */
+};
-cairo_surface_t *
-cairo_openvg_surface_create (int width, int height)
+static void initEGL(void)
+{
+ int i32NumConfigs, i32MajorVersion, i32MinorVersion;
+ unsigned int err;
+
+ eglDisplay = (NativeDisplayType)eglGetDisplay(EGL_DEFAULT_DISPLAY);
+
+ if(!eglInitialize(eglDisplay, &i32MajorVersion, &i32MinorVersion))
+ {
+ printf("Error: eglInitialize() failed.\n");
+ exit(0);
+ }
+ printf("eglversion %d.%d\n",i32MajorVersion, i32MinorVersion);
+
+ eglBindAPI(EGL_OPENVG_API);
+
+ if(!eglChooseConfig(eglDisplay, ai32ARGB32ConfigAttribs, &eglConfig, 1, &i32NumConfigs) || (i32NumConfigs != 1))
+ {
+ printf("Error: eglChooseConfig() failed.\n");
+ exit(0);
+ }
+
+ eglContext = eglCreateContext(eglDisplay, eglConfig, NULL, NULL);
+ err = eglGetError();
+ if((err != EGL_SUCCESS) || (eglContext == EGL_NO_CONTEXT))
+ {
+ printf("Error: eglCreateContext() failed: 0x%08x.\n", err);
+ exit(0);
+ }
+ /* it seems we cannot create a vgImage without a valid eglContext, so make a dummy one*/
+
+ eglDummySurface = eglCreatePbufferSurface(eglDisplay, eglConfig,ai32PBufferAttribs);
+ err = eglGetError();
+ if( err != EGL_SUCCESS){
+ printf("Error: eglCreatePbufferSurface() failed: 0x%08x. %p\n", eglGetError(),eglDummySurface);
+ exit(1);
+ }
+ eglMakeCurrent(eglDisplay, eglDummySurface, eglDummySurface, eglContext);
+ err = eglGetError();
+ if( err != EGL_SUCCESS){
+ printf("Error: vgMakeCurrent() failed: 0x%08x. %p\n", eglGetError(),eglContext);
+ exit(1);
+ }
+
+}
+#if 0 /* not sure when to call this... */
+void destroyEGL(void)
+{
+ eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ eglTerminate(eglDisplay);
+}
+#endif // destroyegl not used
+#endif //EGL_SUPPORT
+
+static cairo_surface_t *
+_cairo_openvg_surface_create_internal (int width, int height, cairo_openvg_surface_t *s)
{
- cairo_openvg_surface_t *s = malloc(sizeof(cairo_openvg_surface_t));
- memset(s, 0, sizeof(cairo_openvg_surface_t));
_cairo_surface_init(&s->base, &cairo_openvg_surface_backend, CAIRO_CONTENT_COLOR_ALPHA);
s->width = width;
s->height = height;
-
s->alpha = 1.0;
s->opacity_level = 0;
s->opacity[s->opacity_level] = 1.0;
s->source_paint = vgCreatePaint();
vgLoadIdentity();
- /* The default transform of cairo and OpenVG differ, (cairo has the
+ /* pippin: The default transform of cairo and OpenVG differ, (cairo has the
* y axis pointing downwards while openvg has it pointing upwards,
* let's swap that around
*/
- vgTranslate (0.0, height);
- vgScale (1.0, -1.0);
+ /* FIXME tardyp: dont needed on my openvg implementation ?! */
+ //vgTranslate (0.0, height);
+ //vgScale (1.0, -1.0);
/* Force an initial "clip", that resets the mask */
_cairo_openvg_surface_intersect_clip_path (s, NULL, 0, 0.0, 0);
+ CHECK_VG_ERRORS();
return (cairo_surface_t *) s;
}
+
+cairo_surface_t *
+cairo_openvg_image_surface_create (cairo_format_t format,int width, int height)
+{
+#ifdef EGL_SUPPORT
+ cairo_openvg_surface_t *s = calloc(1,sizeof(cairo_openvg_surface_t));
+ static int egl_init=0;
+ int err;
+ if (! egl_init)
+ {
+ initEGL();
+ egl_init = 1;
+ }
+ switch (format){
+ case CAIRO_FORMAT_ARGB32:
+ s->vgformat = VG_sARGB_8888;
+ break;
+ case CAIRO_FORMAT_RGB24:
+ s->vgformat = VG_sARGB_8888;
+ break;
+ case CAIRO_FORMAT_A8:
+ case CAIRO_FORMAT_A1:
+ default:
+ printf("Error: for now cairo-openvg only supports CAIRO_FORMAT_ARGB32 and CAIRO_FORMAT_RGB24\n");
+ return NULL;
+ }
+ s->targetImage = vgCreateImage(s->vgformat,
+ width, height,
+ VG_IMAGE_QUALITY_BETTER);
+ if(s->targetImage == VG_INVALID_HANDLE)
+ {
+ printf("Error: vgCreateImage() failed: 0x%08x.\n", vgGetError());
+ return NULL;
+ }
+ eglMakeCurrent(eglDisplay, eglDummySurface, eglDummySurface, eglContext);
+ err = eglGetError();
+ if( err != EGL_SUCCESS){
+ printf("Error: vgMakeCurrent() failed: 0x%08x. %p\n", eglGetError(),eglContext);
+ return NULL;
+ }
+
+ s->eglImageSurface = eglCreatePbufferFromClientBuffer(eglDisplay, EGL_OPENVG_IMAGE, (EGLClientBuffer)s->targetImage, eglConfig, NULL);
+
+ eglMakeCurrent(eglDisplay, s->eglImageSurface, s->eglImageSurface, eglContext);
+
+ err = eglGetError();
+ if(err != EGL_SUCCESS)
+ {
+ printf("Error: eglCreatePbufferFromClientBuffer() failed: 0x%08x.\n", err);
+ return NULL;
+ }
+ return _cairo_openvg_surface_create_internal(width,height,s);
+#else
+ return NULL;
+#endif
+}
+cairo_surface_t *
+cairo_openvg_surface_create (int width, int height)
+{
+ cairo_openvg_surface_t *s = calloc(1,sizeof(cairo_openvg_surface_t));
+ return _cairo_openvg_surface_create_internal(width,height,s);
+}
diff --git a/src/cairo-openvg.h b/src/cairo-openvg.h
index 24f0844..0c152c5 100644
--- a/src/cairo-openvg.h
+++ b/src/cairo-openvg.h
@@ -42,6 +42,12 @@ CAIRO_BEGIN_DECLS
cairo_public cairo_surface_t *
cairo_openvg_surface_create (int width, int height);
+/* this API makes a egl pbuffer context and draws to it
+ this surface can then be used with APIs like cairo_surface_write_to_png()
+*/
+cairo_public cairo_surface_t *
+cairo_openvg_image_surface_create (cairo_format_t format,int width, int height);
+
CAIRO_END_DECLS
#endif /* CAIRO_OPENVG_H */
--
1.6.0.4
More information about the cairo
mailing list