From 0135b45c125c603f7ae96941dbeba9a22d75691b Mon Sep 17 00:00:00 2001 From: Jean-Philippe Andre Date: Fri, 17 Jan 2014 11:19:02 +0900 Subject: [PATCH] Evas filters: OpenGL support part 1. Quick and dirty solution to support the OpenGL engine: [1] Allocate CPU buffers [2] Render text and process all effects to these buffers [3] Push final image as an OpenGL texture. This patch implements [1]. --- src/lib/evas/canvas/evas_object_text.c | 20 ++-- src/lib/evas/filters/evas_filter.c | 91 +++++++++++++++---- src/lib/evas/filters/evas_filter_bump.c | 4 + src/lib/evas/filters/evas_filter_private.h | 2 + .../evas/engines/gl_common/evas_gl_image.c | 13 +-- 5 files changed, 98 insertions(+), 32 deletions(-) diff --git a/src/lib/evas/canvas/evas_object_text.c b/src/lib/evas/canvas/evas_object_text.c index fff67503e5..4c48b9088a 100644 --- a/src/lib/evas/canvas/evas_object_text.c +++ b/src/lib/evas/canvas/evas_object_text.c @@ -10,6 +10,10 @@ EAPI Eo_Op EVAS_OBJ_TEXT_BASE_ID = EO_NOOP; #define MY_CLASS_NAME "Evas_Text" +#ifdef EVAS_CSERVE2 +# include "evas_cs2_private.h" +#endif + /* save typing */ #define ENFN obj->layer->evas->engine.func #define ENDT obj->layer->evas->engine.data.output @@ -2131,6 +2135,13 @@ evas_object_text_render(Evas_Object *eo_obj EINA_UNUSED, void *filter_ctx; Eina_Bool ok; + /* NOTE: Font effect rendering is now done ENTIRELY on CPU. + * So we rely on cache/cache2 to allocate a real image buffer, + * that we can draw to. The OpenGL texture will be created only + * after the rendering has been done, as we simply push the output + * image to GL. + */ + W = obj->cur->geometry.w; H = obj->cur->geometry.h; X = obj->cur->geometry.x; @@ -2197,16 +2208,13 @@ evas_object_text_render(Evas_Object *eo_obj EINA_UNUSED, filter_ctx = ENFN->context_new(ENDT); ENFN->context_color_set(ENDT, filter_ctx, 255, 255, 255, 255); - // Alloc input now + // Alloc input now so we can draw text asap evas_filter_buffer_data_set(filter, inbuf, NULL, W, H, EINA_TRUE); input = evas_filter_buffer_backing_get(filter, inbuf); // Allocate output so we can keep it around - outputimg = ENFN->image_new_from_copied_data - (ENDT, W, H, NULL, EINA_TRUE, EVAS_COLORSPACE_ARGB8888); - memset(outputimg->image.data, 0, W * H * sizeof(DATA32)); - evas_filter_buffer_data_set - (filter, outbuf, outputimg->image.data, W, H, EINA_FALSE); + evas_filter_buffer_data_set(filter, outbuf, NULL, W, H, EINA_FALSE); + outputimg = evas_filter_buffer_backing_get(filter, outbuf); o->cur.filter.output = outputimg; // Render text to input buffer diff --git a/src/lib/evas/filters/evas_filter.c b/src/lib/evas/filters/evas_filter.c index 8b2481c882..05f9db21e1 100644 --- a/src/lib/evas/filters/evas_filter.c +++ b/src/lib/evas/filters/evas_filter.c @@ -15,6 +15,10 @@ #include "evas_private.h" #include "evas_filter_private.h" +#ifdef EVAS_CSERVE2 +# include "evas_cs2_private.h" +#endif + static void _buffer_free(Evas_Filter_Buffer *fb); static void _command_del(Evas_Filter_Context *ctx, Evas_Filter_Command *cmd); @@ -43,10 +47,14 @@ evas_filter_context_new(Evas_Public_Data *evas) { Evas_Filter_Context *ctx; + EINA_SAFETY_ON_NULL_RETURN_VAL(evas, NULL); + ctx = calloc(1, sizeof(Evas_Filter_Context)); if (!ctx) return NULL; ctx->evas = evas; + ctx->gl_engine = !!strstr(evas->engine.module->definition->name, "gl"); + return ctx; } @@ -72,6 +80,31 @@ evas_filter_context_clear(Evas_Filter_Context *ctx) // Note: don't reset post_run, as it it set by the client } +static void +_filter_buffer_backing_free(Evas_Filter_Buffer *fb) +{ + void *backing; + if (!fb) return; + + backing = fb->backing; + fb->backing = NULL; + + if (!fb->allocated) return; + fb->allocated = EINA_FALSE; + + if (!backing) return; + + if (!fb->ctx->gl_engine) + fb->ENFN->image_free(fb->ENDT, backing); + else + { + if (!evas_cserve2_use_get()) + evas_cache_image_drop(backing); + else + evas_cache2_image_close(backing); + } +} + /** @hidden private bind proxy to context */ void evas_filter_context_proxy_bind(Evas_Filter_Context *ctx, Evas_Object *eo_proxy, @@ -209,8 +242,7 @@ evas_filter_context_proxy_render_all(Evas_Filter_Context *ctx, Eo *eo_obj, if (source->proxy->surface && !source->proxy->redraw) { INF("Source already rendered"); - if (fb->backing && fb->allocated) - fb->ENFN->image_free(fb->ENDT, fb->backing); + _filter_buffer_backing_free(fb); fb->backing = source->proxy->surface; fb->w = source->cur->geometry.w; fb->h = source->cur->geometry.h; @@ -221,8 +253,7 @@ evas_filter_context_proxy_render_all(Evas_Filter_Context *ctx, Eo *eo_obj, { INF("Source needs to be rendered"); _proxy_subrender(ctx->evas->evas, fb->source, eo_obj, obj, do_async); - if (fb->backing && fb->allocated) - fb->ENFN->image_free(fb->ENDT, fb->backing); + _filter_buffer_backing_free(fb); fb->backing = source->proxy->surface; fb->w = source->cur->geometry.w; fb->h = source->cur->geometry.h; @@ -284,15 +315,42 @@ _rgba_image_alloc(Evas_Filter_Buffer const *fb, void *data) size_t sz; cspace = fb->alpha_only ? EVAS_COLORSPACE_GRY8 : EVAS_COLORSPACE_ARGB8888; - if (!data) + if (!fb->ctx->gl_engine) { - image = fb->ENFN->image_new_from_copied_data - (fb->ENDT, fb->w, fb->h, NULL, EINA_TRUE, cspace); + if (!data) + { + image = fb->ENFN->image_new_from_copied_data + (fb->ENDT, fb->w, fb->h, NULL, EINA_TRUE, cspace); + } + else + { + image = fb->ENFN->image_new_from_data + (fb->ENDT, fb->w, fb->h, data, EINA_TRUE, cspace); + } } else { - image = fb->ENFN->image_new_from_data - (fb->ENDT, fb->w, fb->h, data, EINA_TRUE, cspace); + WRN("EXPERIMENTAL OpenGL support. VERY HACKISH!"); + // FIXME: Directly calling the alloc functions since we want to use sw surfaces. + + if (!data) + { + if (!evas_cserve2_use_get()) + image = (RGBA_Image *) evas_cache_image_copied_data + (evas_common_image_cache_get(), fb->w, fb->h, NULL, EINA_TRUE, cspace); + else + image = (RGBA_Image *) evas_cache2_image_copied_data + (evas_common_image_cache2_get(), fb->w, fb->h, NULL, EINA_TRUE, cspace); + } + else + { + if (!evas_cserve2_use_get()) + image = (RGBA_Image *) evas_cache_image_data + (evas_common_image_cache_get(), fb->w, fb->h, data, EINA_TRUE, cspace); + else + image = (RGBA_Image *) evas_cache2_image_data + (evas_common_image_cache2_get(), fb->w, fb->h, data, EINA_TRUE, cspace); + } } if (!image) return EINA_FALSE; @@ -323,9 +381,7 @@ evas_filter_buffer_alloc(Evas_Filter_Buffer *fb, int w, int h) //return EINA_FALSE; return EINA_TRUE; } - fb->ENFN->image_free(fb->ENDT, fb->backing); - fb->backing = NULL; - fb->allocated = EINA_FALSE; + _filter_buffer_backing_free(fb); } if ((fb->w && (fb->w != w)) || (fb->h && (fb->h != h))) { @@ -367,10 +423,7 @@ evas_filter_buffer_data_set(Evas_Filter_Context *ctx, int bufid, void *data, fb = _filter_buffer_get(ctx, bufid); if (!fb) return EINA_FALSE; - if (fb->allocated) - fb->ENFN->image_free(fb->ENDT, fb->backing); - fb->allocated = EINA_FALSE; - fb->backing = NULL; + _filter_buffer_backing_free(fb); if (w <= 0 || h <= 0) return EINA_FALSE; @@ -436,9 +489,7 @@ evas_filter_buffer_data_new(Evas_Filter_Context *ctx, void *data, int w, int h, static void _buffer_free(Evas_Filter_Buffer *fb) { - if (!fb) return; - if (fb->allocated) - fb->ENFN->image_free(fb->ENDT, fb->backing); + _filter_buffer_backing_free(fb); free(fb); } @@ -1259,7 +1310,7 @@ _filter_command_run(Evas_Filter_Command *cmd) // FIXME: Must call engine function, not CPU directly. if (strncmp(cmd->ctx->evas->engine.module->definition->name, "software", 8)) - CRI("Only the software engine is supported for now."); + WRN("EXPERIMENTAL OpenGL support! ALL HELL WILL BREAK LOOSE!"); switch (cmd->mode) { diff --git a/src/lib/evas/filters/evas_filter_bump.c b/src/lib/evas/filters/evas_filter_bump.c index 1d2a042b2d..c03f628cbc 100644 --- a/src/lib/evas/filters/evas_filter_bump.c +++ b/src/lib/evas/filters/evas_filter_bump.c @@ -16,6 +16,10 @@ #undef ENDT #define ENFN cmd->ctx->evas->engine.func #define ENDT cmd->ctx->evas->engine.data.output + +#ifdef CLAMP +# undef CLAMP +#endif #define CLAMP(a,b,c) MIN(MAX((b),(a)),(c)) #define DEFAULT_ZANGLE 45.f diff --git a/src/lib/evas/filters/evas_filter_private.h b/src/lib/evas/filters/evas_filter_private.h index 6c417e3cb9..8f9be8088e 100644 --- a/src/lib/evas/filters/evas_filter_private.h +++ b/src/lib/evas/filters/evas_filter_private.h @@ -56,6 +56,8 @@ struct _Evas_Filter_Context Evas_Filter_Cb cb; void *data; } post_run; + + Eina_Bool gl_engine : 1; }; struct _Evas_Filter_Command diff --git a/src/modules/evas/engines/gl_common/evas_gl_image.c b/src/modules/evas/engines/gl_common/evas_gl_image.c index 169b48655f..fc70d71283 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_image.c +++ b/src/modules/evas/engines/gl_common/evas_gl_image.c @@ -328,20 +328,21 @@ evas_gl_common_image_new_from_copied_data(Evas_Engine_GL_Context *gc, unsigned i switch (cspace) { case EVAS_COLORSPACE_ARGB8888: - break; + case EVAS_COLORSPACE_GRY8: + break; case EVAS_COLORSPACE_YCBCR422P601_PL: case EVAS_COLORSPACE_YCBCR422P709_PL: if (im->tex) evas_gl_common_texture_free(im->tex, EINA_TRUE); im->tex = NULL; - im->cs.no_free = 0; + im->cs.no_free = 0; if (im->im->cache_entry.h > 0) im->cs.data = calloc(1, im->im->cache_entry.h * sizeof(unsigned char *) * 2); if ((data) && (im->cs.data)) - memcpy(im->cs.data, data, im->im->cache_entry.h * sizeof(unsigned char *) * 2); - break; + memcpy(im->cs.data, data, im->im->cache_entry.h * sizeof(unsigned char *) * 2); + break; default: - abort(); - break; + abort(); + break; } return im; }