forked from enlightenment/efl
Evas filters: Implement proxy rendering for GL
Make use of glReadPixel to access the source's pixel data. Use all classic CPU functions to blend and use that data. Save pointer to the GL image and update it with the latest data during target render. Use ENFN's surface_lock, read_pixels, unlock. Also, add some more error checks to make sure the images are valid, or return an error at runtime.
This commit is contained in:
parent
2225587e5e
commit
7690e33b49
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
static void _buffer_free(Evas_Filter_Buffer *fb);
|
static void _buffer_free(Evas_Filter_Buffer *fb);
|
||||||
static void _command_del(Evas_Filter_Context *ctx, Evas_Filter_Command *cmd);
|
static void _command_del(Evas_Filter_Context *ctx, Evas_Filter_Command *cmd);
|
||||||
|
static RGBA_Image *_rgba_image_alloc(Evas_Filter_Buffer const *fb, void *data);
|
||||||
|
|
||||||
#ifdef CLAMP
|
#ifdef CLAMP
|
||||||
# undef CLAMP
|
# undef CLAMP
|
||||||
|
@ -85,55 +86,102 @@ evas_filter_context_clear(Evas_Filter_Context *ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_backing_free(Evas_Filter_Context *ctx, Image_Entry *ie)
|
_backing_free(Evas_Filter_Context *ctx, RGBA_Image *im)
|
||||||
{
|
{
|
||||||
if (!ie) return;
|
if (!im) return;
|
||||||
|
|
||||||
if (!ctx->gl_engine)
|
if (!ctx->gl_engine)
|
||||||
{
|
{
|
||||||
if (!ctx->async)
|
if (!ctx->async)
|
||||||
ENFN->image_free(ENDT, ie);
|
ENFN->image_free(ENDT, im);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
#ifdef EVAS_CSERVE2
|
#ifdef EVAS_CSERVE2
|
||||||
if (evas_cserve2_use_get())
|
if (evas_cserve2_use_get())
|
||||||
evas_cache2_image_close(ie);
|
evas_cache2_image_close(&im->cache_entry);
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
evas_cache_image_drop(ie);
|
evas_cache_image_drop(&im->cache_entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_filter_buffer_backing_free(Evas_Filter_Buffer *fb)
|
_filter_buffer_backing_free(Evas_Filter_Buffer *fb)
|
||||||
{
|
{
|
||||||
void *backing;
|
|
||||||
if (!fb) return;
|
if (!fb) return;
|
||||||
|
|
||||||
if (fb->stolen)
|
if (!fb->stolen)
|
||||||
{
|
{
|
||||||
if (eina_list_data_find(fb->ctx->buffers, fb))
|
if (fb->allocated)
|
||||||
|
_backing_free(fb->ctx, fb->backing);
|
||||||
|
if (fb->glimage && fb->allocated_gl)
|
||||||
|
fb->ENFN->image_free(fb->ENDT, fb->glimage);
|
||||||
|
fb->backing = NULL;
|
||||||
|
fb->glimage = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!fb->ctx->gl_engine)
|
||||||
{
|
{
|
||||||
fb->delete_me = EINA_TRUE;
|
fb->delete_me = fb->allocated;
|
||||||
return;
|
}
|
||||||
|
else if (fb->glimage && fb->allocated)
|
||||||
|
{
|
||||||
|
_backing_free(fb->ctx, fb->backing);
|
||||||
|
fb->backing = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
INF("Free backing of buffer %d fb @ %p backing @ %p alloc %d", fb->id, fb, fb->backing, fb->allocated);
|
/* GL engine stuff: read-back from texture */
|
||||||
backing = fb->backing;
|
static Eina_Bool
|
||||||
fb->backing = NULL;
|
_filter_buffer_glimage_pixels_read(Evas_Filter_Buffer *fb)
|
||||||
|
{
|
||||||
|
Eina_Bool ok;
|
||||||
|
|
||||||
if (!fb->allocated) return;
|
EINA_SAFETY_ON_NULL_RETURN_VAL(fb, EINA_FALSE);
|
||||||
_backing_free(fb->ctx, backing);
|
EINA_SAFETY_ON_FALSE_RETURN_VAL(fb->ctx->gl_engine, EINA_FALSE);
|
||||||
|
EINA_SAFETY_ON_NULL_RETURN_VAL(fb->glimage, EINA_FALSE);
|
||||||
|
|
||||||
|
if (fb->backing)
|
||||||
|
return EINA_TRUE;
|
||||||
|
|
||||||
|
EINA_SAFETY_ON_NULL_RETURN_VAL(fb->ENFN->gl_surface_lock, EINA_FALSE);
|
||||||
|
EINA_SAFETY_ON_NULL_RETURN_VAL(fb->ENFN->gl_surface_read_pixels, EINA_FALSE);
|
||||||
|
EINA_SAFETY_ON_NULL_RETURN_VAL(fb->ENFN->gl_surface_unlock, EINA_FALSE);
|
||||||
|
|
||||||
|
fb->backing = _rgba_image_alloc(fb, NULL);
|
||||||
|
fb->allocated = EINA_TRUE;
|
||||||
|
EINA_SAFETY_ON_NULL_RETURN_VAL(fb->backing, EINA_FALSE);
|
||||||
|
|
||||||
|
ok = fb->ENFN->gl_surface_lock(fb->ENDT, fb->glimage);
|
||||||
|
if (!ok)
|
||||||
|
{
|
||||||
|
ERR("Failed to lock the image pixels");
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = fb->ENFN->gl_surface_read_pixels(fb->ENDT, fb->glimage,
|
||||||
|
0, 0, fb->w, fb->h, fb->alpha_only
|
||||||
|
? EVAS_COLORSPACE_GRY8
|
||||||
|
: EVAS_COLORSPACE_ARGB8888,
|
||||||
|
fb->backing->image.data);
|
||||||
|
if (!ok)
|
||||||
|
ERR("Could not read the image pixels!");
|
||||||
|
|
||||||
|
ok &= fb->ENFN->gl_surface_unlock(fb->ENDT, fb->glimage);
|
||||||
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @internal
|
||||||
* Render the source object when a proxy is set.
|
* Render the source object when a proxy is set.
|
||||||
*
|
*
|
||||||
* Used to force a draw if necessary, else just makes sure it's available.
|
* Used to force a draw if necessary, else just makes sure it's available.
|
||||||
* @note This comes direcly from evas_object_image.c. A common function is desirable here :)
|
* @note This comes direcly from evas_object_image.c.
|
||||||
|
* A common function is desirable here :)
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
_proxy_subrender(Evas *eo_e, Evas_Object *eo_source, Evas_Object *eo_proxy,
|
_proxy_subrender(Evas *eo_e, Evas_Object *eo_source, Evas_Object *eo_proxy,
|
||||||
|
@ -151,7 +199,8 @@ _proxy_subrender(Evas *eo_e, Evas_Object *eo_source, Evas_Object *eo_proxy,
|
||||||
w = source->cur->geometry.w;
|
w = source->cur->geometry.w;
|
||||||
h = source->cur->geometry.h;
|
h = source->cur->geometry.h;
|
||||||
|
|
||||||
EINA_COW_WRITE_BEGIN(evas_object_proxy_cow, source->proxy, Evas_Object_Proxy_Data, proxy_write)
|
EINA_COW_WRITE_BEGIN(evas_object_proxy_cow, source->proxy,
|
||||||
|
Evas_Object_Proxy_Data, proxy_write)
|
||||||
{
|
{
|
||||||
proxy_write->redraw = EINA_FALSE;
|
proxy_write->redraw = EINA_FALSE;
|
||||||
|
|
||||||
|
@ -227,13 +276,6 @@ evas_filter_context_proxy_render_all(Evas_Filter_Context *ctx, Eo *eo_obj,
|
||||||
obj = eo_data_scope_get(eo_obj, EVAS_OBJ_CLASS);
|
obj = eo_data_scope_get(eo_obj, EVAS_OBJ_CLASS);
|
||||||
|
|
||||||
if (!ctx->has_proxies) return;
|
if (!ctx->has_proxies) return;
|
||||||
if (ctx->gl_engine)
|
|
||||||
{
|
|
||||||
// FIXME: We need to call glReadPixels (yeah, no other way around...)
|
|
||||||
ERR("Proxy subrender is not supported in the GL engine (yet)");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
EINA_LIST_FOREACH(ctx->buffers, li, fb)
|
EINA_LIST_FOREACH(ctx->buffers, li, fb)
|
||||||
if (fb->source)
|
if (fb->source)
|
||||||
{
|
{
|
||||||
|
@ -243,10 +285,19 @@ evas_filter_context_proxy_render_all(Evas_Filter_Context *ctx, Eo *eo_obj,
|
||||||
{
|
{
|
||||||
INF("Source already rendered");
|
INF("Source already rendered");
|
||||||
_filter_buffer_backing_free(fb);
|
_filter_buffer_backing_free(fb);
|
||||||
fb->backing = source->proxy->surface;
|
|
||||||
fb->w = source->cur->geometry.w;
|
fb->w = source->cur->geometry.w;
|
||||||
fb->h = source->cur->geometry.h;
|
fb->h = source->cur->geometry.h;
|
||||||
fb->allocated = EINA_FALSE;
|
if (!ctx->gl_engine)
|
||||||
|
{
|
||||||
|
fb->backing = source->proxy->surface;
|
||||||
|
fb->allocated = EINA_FALSE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fb->glimage = source->proxy->surface;
|
||||||
|
fb->allocated_gl = EINA_FALSE;
|
||||||
|
_filter_buffer_glimage_pixels_read(fb);
|
||||||
|
}
|
||||||
fb->alpha_only = EINA_FALSE;
|
fb->alpha_only = EINA_FALSE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -254,10 +305,19 @@ evas_filter_context_proxy_render_all(Evas_Filter_Context *ctx, Eo *eo_obj,
|
||||||
INF("Source needs to be rendered");
|
INF("Source needs to be rendered");
|
||||||
_proxy_subrender(ctx->evas->evas, fb->source, eo_obj, obj, do_async);
|
_proxy_subrender(ctx->evas->evas, fb->source, eo_obj, obj, do_async);
|
||||||
_filter_buffer_backing_free(fb);
|
_filter_buffer_backing_free(fb);
|
||||||
fb->backing = source->proxy->surface;
|
|
||||||
fb->w = source->cur->geometry.w;
|
fb->w = source->cur->geometry.w;
|
||||||
fb->h = source->cur->geometry.h;
|
fb->h = source->cur->geometry.h;
|
||||||
fb->allocated = EINA_FALSE;
|
if (!ctx->gl_engine)
|
||||||
|
{
|
||||||
|
fb->backing = source->proxy->surface;
|
||||||
|
fb->allocated = EINA_FALSE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fb->glimage = source->proxy->surface;
|
||||||
|
fb->allocated_gl = EINA_FALSE;
|
||||||
|
_filter_buffer_glimage_pixels_read(fb);
|
||||||
|
}
|
||||||
fb->alpha_only = EINA_FALSE;
|
fb->alpha_only = EINA_FALSE;
|
||||||
}
|
}
|
||||||
DBG("Source has dimensions %dx%d (buffer %d)", fb->w, fb->h, fb->id);
|
DBG("Source has dimensions %dx%d (buffer %d)", fb->w, fb->h, fb->id);
|
||||||
|
@ -373,7 +433,6 @@ evas_filter_context_buffers_allocate_all(Evas_Filter_Context *ctx,
|
||||||
{
|
{
|
||||||
Evas_Filter_Command *cmd;
|
Evas_Filter_Command *cmd;
|
||||||
Evas_Filter_Buffer *fb;
|
Evas_Filter_Buffer *fb;
|
||||||
Image_Entry *ie;
|
|
||||||
Eina_List *li;
|
Eina_List *li;
|
||||||
|
|
||||||
EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, EINA_FALSE);
|
EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, EINA_FALSE);
|
||||||
|
@ -452,13 +511,14 @@ evas_filter_context_buffers_allocate_all(Evas_Filter_Context *ctx,
|
||||||
|
|
||||||
EINA_LIST_FOREACH(ctx->buffers, li, fb)
|
EINA_LIST_FOREACH(ctx->buffers, li, fb)
|
||||||
{
|
{
|
||||||
ie = fb->backing;
|
RGBA_Image *im;
|
||||||
if (ie)
|
im = fb->backing;
|
||||||
|
if (im)
|
||||||
{
|
{
|
||||||
if (ctx->async)
|
if (ctx->async)
|
||||||
{
|
{
|
||||||
ie->references++;
|
im->cache_entry.references++;
|
||||||
evas_unref_queue_image_put(ctx->evas, ie);
|
evas_unref_queue_image_put(ctx->evas, &im->cache_entry);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -471,22 +531,22 @@ evas_filter_context_buffers_allocate_all(Evas_Filter_Context *ctx,
|
||||||
|
|
||||||
if (!fb->w && !fb->h)
|
if (!fb->w && !fb->h)
|
||||||
{
|
{
|
||||||
ERR("Size should be known at this point. Is this a dangling buffer?");
|
ERR("Size of buffer %d should be known at this point. Is this a dangling buffer?", fb->id);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
//DBG("Allocating buffer of size %ux%u alpha %d", fb->w, fb->h, fb->alpha_only);
|
//DBG("Allocating buffer of size %ux%u alpha %d", fb->w, fb->h, fb->alpha_only);
|
||||||
ie = (Image_Entry *) _rgba_image_alloc(fb, NULL);
|
im = _rgba_image_alloc(fb, NULL);
|
||||||
if (!ie)
|
if (!im)
|
||||||
{
|
{
|
||||||
ERR("Buffer %d allocation failed!", fb->id);
|
ERR("Buffer %d allocation failed!", fb->id);
|
||||||
return EINA_FALSE;
|
return EINA_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
fb->backing = ie;
|
fb->backing = im;
|
||||||
fb->allocated = (ie != NULL);
|
fb->allocated = (im != NULL);
|
||||||
if (ctx->async && fb->allocated)
|
if (ctx->async && fb->allocated)
|
||||||
evas_unref_queue_image_put(ctx->evas, ie);
|
evas_unref_queue_image_put(ctx->evas, &im->cache_entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
return EINA_TRUE;
|
return EINA_TRUE;
|
||||||
|
@ -536,7 +596,7 @@ _filter_buffer_data_set(Evas_Filter_Context *ctx, int bufid, void *data,
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
evas_filter_buffer_image_new(Evas_Filter_Context *ctx, RGBA_Image *image)
|
evas_filter_buffer_image_new(Evas_Filter_Context *ctx, void *image)
|
||||||
{
|
{
|
||||||
Evas_Filter_Buffer *fb;
|
Evas_Filter_Buffer *fb;
|
||||||
|
|
||||||
|
@ -548,10 +608,19 @@ evas_filter_buffer_image_new(Evas_Filter_Context *ctx, RGBA_Image *image)
|
||||||
|
|
||||||
fb->id = ++(ctx->last_buffer_id);
|
fb->id = ++(ctx->last_buffer_id);
|
||||||
fb->ctx = ctx;
|
fb->ctx = ctx;
|
||||||
fb->backing = image;
|
if (!fb->ctx->gl_engine)
|
||||||
fb->w = image->cache_entry.w;
|
{
|
||||||
fb->h = image->cache_entry.h;
|
fb->backing = image;
|
||||||
fb->alpha_only = (image->cache_entry.space == EVAS_COLORSPACE_GRY8);
|
fb->allocated = EINA_FALSE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fb->glimage = image;
|
||||||
|
fb->allocated_gl = EINA_FALSE;
|
||||||
|
}
|
||||||
|
ENFN->image_size_get(ENDT, image, &fb->w, &fb->h);
|
||||||
|
fb->alpha_only = (ENFN->image_colorspace_get(ENDT, image)
|
||||||
|
== EVAS_COLORSPACE_GRY8);
|
||||||
|
|
||||||
ctx->buffers = eina_list_append(ctx->buffers, fb);
|
ctx->buffers = eina_list_append(ctx->buffers, fb);
|
||||||
return fb->id;
|
return fb->id;
|
||||||
|
@ -626,23 +695,20 @@ evas_filter_buffer_backing_steal(Evas_Filter_Context *ctx, int bufid)
|
||||||
if (!buffer) return NULL;
|
if (!buffer) return NULL;
|
||||||
|
|
||||||
buffer->stolen = EINA_TRUE;
|
buffer->stolen = EINA_TRUE;
|
||||||
if (buffer->glimage)
|
|
||||||
|
if (ctx->gl_engine)
|
||||||
return buffer->glimage;
|
return buffer->glimage;
|
||||||
else
|
|
||||||
{
|
if (ctx->async && buffer->backing)
|
||||||
if (ctx->async)
|
buffer->backing->cache_entry.references++;
|
||||||
{
|
|
||||||
Image_Entry *ie = buffer->backing;
|
return buffer->backing;
|
||||||
if (ie) ie->references++;
|
|
||||||
}
|
|
||||||
return buffer->backing;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Eina_Bool
|
Eina_Bool
|
||||||
evas_filter_buffer_backing_release(Evas_Filter_Context *ctx, void *stolen_buffer)
|
evas_filter_buffer_backing_release(Evas_Filter_Context *ctx,
|
||||||
|
void *stolen_buffer)
|
||||||
{
|
{
|
||||||
Image_Entry *ie = stolen_buffer;
|
|
||||||
Evas_Filter_Buffer *fb;
|
Evas_Filter_Buffer *fb;
|
||||||
Eina_List *li;
|
Eina_List *li;
|
||||||
|
|
||||||
|
@ -651,7 +717,7 @@ evas_filter_buffer_backing_release(Evas_Filter_Context *ctx, void *stolen_buffer
|
||||||
|
|
||||||
EINA_LIST_FOREACH(ctx->buffers, li, fb)
|
EINA_LIST_FOREACH(ctx->buffers, li, fb)
|
||||||
{
|
{
|
||||||
if (fb->backing == ie)
|
if (fb->backing == stolen_buffer)
|
||||||
{
|
{
|
||||||
fb->stolen = EINA_FALSE;
|
fb->stolen = EINA_FALSE;
|
||||||
if (fb->delete_me)
|
if (fb->delete_me)
|
||||||
|
@ -660,7 +726,7 @@ evas_filter_buffer_backing_release(Evas_Filter_Context *ctx, void *stolen_buffer
|
||||||
if (ctx->async)
|
if (ctx->async)
|
||||||
{
|
{
|
||||||
if (fb->allocated)
|
if (fb->allocated)
|
||||||
evas_unref_queue_image_put(ctx->evas, ie);
|
evas_unref_queue_image_put(ctx->evas, stolen_buffer);
|
||||||
free(fb);
|
free(fb);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -675,20 +741,19 @@ evas_filter_buffer_backing_release(Evas_Filter_Context *ctx, void *stolen_buffer
|
||||||
if (fb->delete_me)
|
if (fb->delete_me)
|
||||||
{
|
{
|
||||||
ctx->buffers = eina_list_remove_list(ctx->buffers, li);
|
ctx->buffers = eina_list_remove_list(ctx->buffers, li);
|
||||||
ENFN->image_free(ENDT, stolen_buffer);
|
_buffer_free(fb);
|
||||||
free(fb);
|
|
||||||
}
|
}
|
||||||
return EINA_TRUE;
|
return EINA_TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx->async)
|
if (ctx->async)
|
||||||
evas_unref_queue_image_put(ctx->evas, ie);
|
evas_unref_queue_image_put(ctx->evas, stolen_buffer);
|
||||||
else if (ctx->gl_engine)
|
else if (ctx->gl_engine)
|
||||||
ctx->post_run.buffers_to_free =
|
ctx->post_run.buffers_to_free =
|
||||||
eina_list_append(ctx->post_run.buffers_to_free, stolen_buffer);
|
eina_list_append(ctx->post_run.buffers_to_free, stolen_buffer);
|
||||||
else
|
else
|
||||||
_backing_free(ctx, ie);
|
_backing_free(ctx, stolen_buffer);
|
||||||
|
|
||||||
return EINA_TRUE;
|
return EINA_TRUE;
|
||||||
}
|
}
|
||||||
|
@ -1435,18 +1500,19 @@ evas_filter_target_set(Evas_Filter_Context *ctx, void *draw_context,
|
||||||
if (ctx->gl_engine)
|
if (ctx->gl_engine)
|
||||||
{
|
{
|
||||||
// Since GL has sync rendering, draw_context is safe to keep around
|
// Since GL has sync rendering, draw_context is safe to keep around
|
||||||
Evas_Filter_Buffer *target, *image;
|
Evas_Filter_Buffer *fb;
|
||||||
RGBA_Image *im;
|
|
||||||
|
|
||||||
ctx->target.context = draw_context;
|
ctx->target.context = draw_context;
|
||||||
target = _filter_buffer_get(ctx, ctx->target.bufid);
|
|
||||||
target->glimage = target->backing;
|
|
||||||
target->backing = NULL;
|
|
||||||
|
|
||||||
image = _filter_buffer_get(ctx, EVAS_FILTER_BUFFER_OUTPUT_ID);
|
fb = _filter_buffer_get(ctx, EVAS_FILTER_BUFFER_OUTPUT_ID);
|
||||||
im = image->backing;
|
EINA_SAFETY_ON_NULL_RETURN_VAL(fb, EINA_FALSE);
|
||||||
image->glimage = ENFN->image_new_from_data
|
|
||||||
(ENDT, image->w, image->h, im->image.data, EINA_TRUE, im->cache_entry.space);
|
fb->glimage = ENFN->image_new_from_data
|
||||||
|
(ENDT, fb->w, fb->h, fb->backing->image.data, EINA_TRUE,
|
||||||
|
fb->backing->cache_entry.space);
|
||||||
|
|
||||||
|
DBG("Set target as #%d (%p) and output #%d (%p, gl %p)",
|
||||||
|
ctx->target.bufid, surface, fb->id, fb->backing, fb->glimage);
|
||||||
}
|
}
|
||||||
|
|
||||||
return EINA_TRUE;
|
return EINA_TRUE;
|
||||||
|
@ -1477,6 +1543,21 @@ _filter_target_render(Evas_Filter_Context *ctx)
|
||||||
{
|
{
|
||||||
drawctx = ctx->target.context;
|
drawctx = ctx->target.context;
|
||||||
surface = dst->glimage;
|
surface = dst->glimage;
|
||||||
|
if (src->glimage)
|
||||||
|
{
|
||||||
|
DBG("Using glimage from output buffer.");
|
||||||
|
if (src->backing)
|
||||||
|
ENFN->image_data_put(ENDT, src->glimage, src->backing->image.data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RGBA_Image *im = src->backing;
|
||||||
|
|
||||||
|
DBG("Creating glimage from output buffer.");
|
||||||
|
src->glimage = ENFN->image_new_from_data(ENDT, src->w, src->h,
|
||||||
|
im->image.data, EINA_TRUE,
|
||||||
|
EVAS_COLORSPACE_ARGB8888);
|
||||||
|
}
|
||||||
image = src->glimage;
|
image = src->glimage;
|
||||||
}
|
}
|
||||||
EINA_SAFETY_ON_NULL_RETURN_VAL(image, EINA_FALSE);
|
EINA_SAFETY_ON_NULL_RETURN_VAL(image, EINA_FALSE);
|
||||||
|
|
|
@ -25,9 +25,9 @@ _smallest_pow2_larger_than(int val)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef Eina_Bool (*image_draw_func) (void *data, void *context, void *surface, void *image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int dst_w, int dst_h, int smooth, Eina_Bool do_async);
|
typedef Eina_Bool (*image_draw_func) (void *data, void *context, void *surface, void *image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int dst_w, int dst_h, int smooth, Eina_Bool do_async);
|
||||||
static void _mapped_blend_cpu(void *data, void *drawctx, RGBA_Image *in, RGBA_Image *out, Evas_Filter_Fill_Mode fillmode, int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh, image_draw_func image_draw);
|
static Eina_Bool _mapped_blend(void *data, void *drawctx, void *in, void *out, Evas_Filter_Fill_Mode fillmode, int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh, image_draw_func image_draw);
|
||||||
|
|
||||||
struct Alpha_Blend_Draw_Context
|
struct Filter_Blend_Draw_Context
|
||||||
{
|
{
|
||||||
int render_op;
|
int render_op;
|
||||||
DATA32 color;
|
DATA32 color;
|
||||||
|
@ -41,7 +41,7 @@ _image_draw_cpu_alpha2alpha(void *data EINA_UNUSED, void *context,
|
||||||
int smooth EINA_UNUSED,
|
int smooth EINA_UNUSED,
|
||||||
Eina_Bool do_async EINA_UNUSED)
|
Eina_Bool do_async EINA_UNUSED)
|
||||||
{
|
{
|
||||||
struct Alpha_Blend_Draw_Context *dc = context;
|
struct Filter_Blend_Draw_Context *dc = context;
|
||||||
RGBA_Image *src = image;
|
RGBA_Image *src = image;
|
||||||
RGBA_Image *dst = surface;
|
RGBA_Image *dst = surface;
|
||||||
DATA8* srcdata = src->image.data8;
|
DATA8* srcdata = src->image.data8;
|
||||||
|
@ -77,7 +77,7 @@ _image_draw_cpu_alpha2rgba(void *data EINA_UNUSED, void *context,
|
||||||
int smooth EINA_UNUSED,
|
int smooth EINA_UNUSED,
|
||||||
Eina_Bool do_async EINA_UNUSED)
|
Eina_Bool do_async EINA_UNUSED)
|
||||||
{
|
{
|
||||||
struct Alpha_Blend_Draw_Context *dc = context;
|
struct Filter_Blend_Draw_Context *dc = context;
|
||||||
RGBA_Image *src = image;
|
RGBA_Image *src = image;
|
||||||
RGBA_Image *dst = surface;
|
RGBA_Image *dst = surface;
|
||||||
DATA8* srcdata = src->image.data8;
|
DATA8* srcdata = src->image.data8;
|
||||||
|
@ -112,7 +112,7 @@ _filter_blend_cpu_generic_do(Evas_Filter_Command *cmd,
|
||||||
{
|
{
|
||||||
RGBA_Image *in, *out;
|
RGBA_Image *in, *out;
|
||||||
int sw, sh, dx, dy, dw, dh, sx, sy;
|
int sw, sh, dx, dy, dw, dh, sx, sy;
|
||||||
struct Alpha_Blend_Draw_Context dc;
|
struct Filter_Blend_Draw_Context dc;
|
||||||
|
|
||||||
in = cmd->input->backing;
|
in = cmd->input->backing;
|
||||||
out = cmd->output->backing;
|
out = cmd->output->backing;
|
||||||
|
@ -161,10 +161,8 @@ _filter_blend_cpu_generic_do(Evas_Filter_Command *cmd,
|
||||||
|
|
||||||
dc.render_op = cmd->draw.render_op;
|
dc.render_op = cmd->draw.render_op;
|
||||||
dc.color = ARGB_JOIN(cmd->draw.A, cmd->draw.R, cmd->draw.G, cmd->draw.B);
|
dc.color = ARGB_JOIN(cmd->draw.A, cmd->draw.R, cmd->draw.G, cmd->draw.B);
|
||||||
_mapped_blend_cpu(cmd->ENDT, &dc, in, out, cmd->draw.fillmode,
|
return _mapped_blend(cmd->ENDT, &dc, in, out, cmd->draw.fillmode,
|
||||||
sx, sy, sw, sh, dx, dy, dw, dh, image_draw);
|
sx, sy, sw, sh, dx, dy, dw, dh, image_draw);
|
||||||
|
|
||||||
return EINA_TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Eina_Bool
|
static Eina_Bool
|
||||||
|
@ -211,6 +209,42 @@ _image_draw_cpu_rgba2alpha(void *data EINA_UNUSED, void *context EINA_UNUSED,
|
||||||
return EINA_TRUE;
|
return EINA_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Eina_Bool
|
||||||
|
_image_draw_cpu_rgba2rgba(void *data EINA_UNUSED, void *context,
|
||||||
|
void *surface, void *image,
|
||||||
|
int src_x, int src_y, int src_w, int src_h,
|
||||||
|
int dst_x, int dst_y, int dst_w, int dst_h,
|
||||||
|
int smooth EINA_UNUSED,
|
||||||
|
Eina_Bool do_async EINA_UNUSED)
|
||||||
|
{
|
||||||
|
struct Filter_Blend_Draw_Context *dc = context;
|
||||||
|
RGBA_Image *src = image;
|
||||||
|
RGBA_Image *dst = surface;
|
||||||
|
DATA32* srcdata = src->image.data;
|
||||||
|
DATA32* dstdata = dst->image.data;
|
||||||
|
RGBA_Gfx_Func func;
|
||||||
|
int y, sw, dw;
|
||||||
|
|
||||||
|
EINA_SAFETY_ON_FALSE_RETURN_VAL((src_w == dst_w) && (src_h == dst_h), EINA_FALSE);
|
||||||
|
|
||||||
|
func = evas_common_gfx_func_composite_pixel_span_get(image, surface, 1, dc->render_op);
|
||||||
|
EINA_SAFETY_ON_NULL_RETURN_VAL(func, EINA_FALSE);
|
||||||
|
|
||||||
|
sw = src->cache_entry.w;
|
||||||
|
dw = dst->cache_entry.w;
|
||||||
|
|
||||||
|
srcdata += src_y * sw;
|
||||||
|
dstdata += dst_y * dw;
|
||||||
|
for (y = src_h; y; y--)
|
||||||
|
{
|
||||||
|
func(srcdata + src_x, NULL, dc->color, dstdata + dst_x, src_w);
|
||||||
|
srcdata += sw;
|
||||||
|
dstdata += dw;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static Eina_Bool
|
static Eina_Bool
|
||||||
_filter_blend_cpu_alpha(Evas_Filter_Command *cmd)
|
_filter_blend_cpu_alpha(Evas_Filter_Command *cmd)
|
||||||
{
|
{
|
||||||
|
@ -235,6 +269,7 @@ _filter_blend_cpu_rgba(Evas_Filter_Command *cmd)
|
||||||
RGBA_Image *in, *out;
|
RGBA_Image *in, *out;
|
||||||
RGBA_Draw_Context *drawctx;
|
RGBA_Draw_Context *drawctx;
|
||||||
int sw, sh, dx, dy, dw, dh, sx, sy;
|
int sw, sh, dx, dy, dw, dh, sx, sy;
|
||||||
|
Eina_Bool ret;
|
||||||
|
|
||||||
in = cmd->input->backing;
|
in = cmd->input->backing;
|
||||||
out = cmd->output->backing;
|
out = cmd->output->backing;
|
||||||
|
@ -243,6 +278,9 @@ _filter_blend_cpu_rgba(Evas_Filter_Command *cmd)
|
||||||
EINA_SAFETY_ON_NULL_RETURN_VAL(in->image.data, EINA_FALSE);
|
EINA_SAFETY_ON_NULL_RETURN_VAL(in->image.data, EINA_FALSE);
|
||||||
EINA_SAFETY_ON_NULL_RETURN_VAL(out->image.data, EINA_FALSE);
|
EINA_SAFETY_ON_NULL_RETURN_VAL(out->image.data, EINA_FALSE);
|
||||||
|
|
||||||
|
if (cmd->ctx->gl_engine)
|
||||||
|
return _filter_blend_cpu_generic_do(cmd, _image_draw_cpu_rgba2rgba);
|
||||||
|
|
||||||
sx = 0;
|
sx = 0;
|
||||||
sy = 0;
|
sy = 0;
|
||||||
sw = in->cache_entry.w;
|
sw = in->cache_entry.w;
|
||||||
|
@ -275,43 +313,42 @@ _filter_blend_cpu_rgba(Evas_Filter_Command *cmd)
|
||||||
out->cache_entry.w, out->cache_entry.h);
|
out->cache_entry.w, out->cache_entry.h);
|
||||||
}
|
}
|
||||||
|
|
||||||
_mapped_blend_cpu(cmd->ENDT, drawctx, in, out, cmd->draw.fillmode,
|
ret = _mapped_blend(cmd->ENDT, drawctx, in, out, cmd->draw.fillmode,
|
||||||
sx, sy, sw, sh, dx, dy, dw, dh,
|
sx, sy, sw, sh, dx, dy, dw, dh,
|
||||||
cmd->ENFN->image_draw);
|
cmd->ENFN->image_draw);
|
||||||
|
|
||||||
cmd->ENFN->context_free(cmd->ENDT, drawctx);
|
cmd->ENFN->context_free(cmd->ENDT, drawctx);
|
||||||
return EINA_TRUE;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static Eina_Bool
|
||||||
_mapped_blend_cpu(void *data, void *drawctx,
|
_mapped_blend(void *data, void *drawctx,
|
||||||
RGBA_Image *in, RGBA_Image *out,
|
void *in, void *out,
|
||||||
Evas_Filter_Fill_Mode fillmode,
|
Evas_Filter_Fill_Mode fillmode,
|
||||||
int sx, int sy,
|
int sx, int sy,
|
||||||
int sw, int sh,
|
int sw, int sh,
|
||||||
int dx, int dy,
|
int dx, int dy,
|
||||||
int dw, int dh,
|
int dw, int dh,
|
||||||
image_draw_func image_draw)
|
image_draw_func image_draw)
|
||||||
{
|
{
|
||||||
int right = 0, bottom = 0, left = 0, top = 0;
|
int right = 0, bottom = 0, left = 0, top = 0;
|
||||||
int row, col, rows, cols;
|
int row, col, rows, cols;
|
||||||
|
Eina_Bool ret = EINA_TRUE;
|
||||||
|
|
||||||
|
EINA_SAFETY_ON_FALSE_RETURN_VAL((sx == 0) && (sy == 0), EINA_FALSE);
|
||||||
|
|
||||||
if (fillmode == EVAS_FILTER_FILL_MODE_NONE)
|
if (fillmode == EVAS_FILTER_FILL_MODE_NONE)
|
||||||
{
|
{
|
||||||
_clip_to_target(&sx, &sy, sw, sh, dx, dy, out->cache_entry.w,
|
_clip_to_target(&sx, &sy, sw, sh, dx, dy, dw, dh, &dx, &dy, &rows, &cols);
|
||||||
out->cache_entry.h, &dx, &dy, &rows, &cols);
|
|
||||||
|
|
||||||
DBG("blend: %d,%d,%d,%d --> %d,%d,%d,%d (from %dx%d to %dx%d +%d,%d)",
|
DBG("blend: %d,%d,%d,%d --> %d,%d,%d,%d (from %dx%d to %dx%d +%d,%d)",
|
||||||
0, 0, sw, sh, dx, dy, cols, rows,
|
0, 0, sw, sh, dx, dy, cols, rows, sw, sh, dw, dh, dx, dy);
|
||||||
in->cache_entry.w, in->cache_entry.h,
|
|
||||||
out->cache_entry.w, out->cache_entry.h,
|
ret = image_draw(data, drawctx, out, in,
|
||||||
dx, dy);
|
sx, sy, cols, rows, // src
|
||||||
image_draw(data, drawctx, out, in,
|
dx, dy, cols, rows, // dst
|
||||||
sx, sy, cols, rows, // src
|
EINA_TRUE, // smooth
|
||||||
dx, dy, cols, rows, // dst
|
EINA_FALSE); // Not async
|
||||||
EINA_TRUE, // smooth
|
return ret;
|
||||||
EINA_FALSE); // Not async
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fillmode & EVAS_FILTER_FILL_MODE_REPEAT_X)
|
if (fillmode & EVAS_FILTER_FILL_MODE_REPEAT_X)
|
||||||
|
@ -328,13 +365,13 @@ _mapped_blend_cpu(void *data, void *drawctx,
|
||||||
else if (fillmode & EVAS_FILTER_FILL_MODE_STRETCH_X)
|
else if (fillmode & EVAS_FILTER_FILL_MODE_STRETCH_X)
|
||||||
{
|
{
|
||||||
cols = 0;
|
cols = 0;
|
||||||
dw = out->cache_entry.w;
|
|
||||||
dx = 0;
|
dx = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// FIXME: Probably wrong if dx != 0
|
||||||
cols = 0;
|
cols = 0;
|
||||||
dw = out->cache_entry.w - dx;
|
dw -= dx;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fillmode & EVAS_FILTER_FILL_MODE_REPEAT_Y)
|
if (fillmode & EVAS_FILTER_FILL_MODE_REPEAT_Y)
|
||||||
|
@ -351,13 +388,13 @@ _mapped_blend_cpu(void *data, void *drawctx,
|
||||||
else if (fillmode & EVAS_FILTER_FILL_MODE_STRETCH_Y)
|
else if (fillmode & EVAS_FILTER_FILL_MODE_STRETCH_Y)
|
||||||
{
|
{
|
||||||
rows = 0;
|
rows = 0;
|
||||||
dh = out->cache_entry.h;
|
|
||||||
dy = 0;
|
dy = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// FIXME: Probably wrong if dy != 0
|
||||||
rows = 0;
|
rows = 0;
|
||||||
dh = out->cache_entry.h - dy;
|
dh -= dy;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (top > 0) row = -1;
|
if (top > 0) row = -1;
|
||||||
|
@ -444,12 +481,14 @@ _mapped_blend_cpu(void *data, void *drawctx,
|
||||||
col, row, src_x, src_y, src_w, src_h,
|
col, row, src_x, src_y, src_w, src_h,
|
||||||
dst_x, dst_y, dst_w, dst_h,
|
dst_x, dst_y, dst_w, dst_h,
|
||||||
sw, sh, dw, dh);
|
sw, sh, dw, dh);
|
||||||
image_draw(data, drawctx, out, in,
|
ret = image_draw(data, drawctx, out, in,
|
||||||
src_x, src_y, src_w, src_h,
|
src_x, src_y, src_w, src_h,
|
||||||
dst_x, dst_y, dst_w, dst_h,
|
dst_x, dst_y, dst_w, dst_h,
|
||||||
EINA_TRUE, EINA_FALSE);
|
EINA_TRUE, EINA_FALSE);
|
||||||
|
if (!ret) return EINA_FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Evas_Filter_Apply_Func
|
Evas_Filter_Apply_Func
|
||||||
|
@ -459,18 +498,27 @@ evas_filter_blend_cpu_func_get(Evas_Filter_Command *cmd)
|
||||||
EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->output, NULL);
|
EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->output, NULL);
|
||||||
EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->input, NULL);
|
EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->input, NULL);
|
||||||
|
|
||||||
if (cmd->input->alpha_only)
|
if (!cmd->ctx->gl_engine || !cmd->output->glimage || cmd->output->backing)
|
||||||
{
|
{
|
||||||
if (cmd->output->alpha_only)
|
if (cmd->input->alpha_only)
|
||||||
return _filter_blend_cpu_alpha;
|
{
|
||||||
|
if (cmd->output->alpha_only)
|
||||||
|
return _filter_blend_cpu_alpha;
|
||||||
|
else
|
||||||
|
return _filter_blend_cpu_mask_rgba;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return _filter_blend_cpu_mask_rgba;
|
{
|
||||||
|
if (cmd->output->alpha_only)
|
||||||
|
return _filter_blend_cpu_rgba2alpha;
|
||||||
|
else
|
||||||
|
return _filter_blend_cpu_rgba;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (cmd->output->alpha_only)
|
CRI("Can't render to GL image for the moment!");
|
||||||
return _filter_blend_cpu_rgba2alpha;
|
//return _filter_blend_opengl_generic;
|
||||||
else
|
return NULL;
|
||||||
return _filter_blend_cpu_rgba;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -352,6 +352,7 @@ _mask_cpu_rgba_rgba_rgba(Evas_Filter_Command *cmd)
|
||||||
Evas_Filter_Command fake_cmd;
|
Evas_Filter_Command fake_cmd;
|
||||||
Evas_Filter_Apply_Func blend;
|
Evas_Filter_Apply_Func blend;
|
||||||
Evas_Filter_Buffer *fb;
|
Evas_Filter_Buffer *fb;
|
||||||
|
Eina_Bool ret;
|
||||||
int w, h;
|
int w, h;
|
||||||
|
|
||||||
fake_cmd = *cmd;
|
fake_cmd = *cmd;
|
||||||
|
@ -379,7 +380,8 @@ _mask_cpu_rgba_rgba_rgba(Evas_Filter_Command *cmd)
|
||||||
fake_cmd.draw.render_op = EVAS_RENDER_MUL;
|
fake_cmd.draw.render_op = EVAS_RENDER_MUL;
|
||||||
blend = evas_filter_blend_cpu_func_get(&fake_cmd);
|
blend = evas_filter_blend_cpu_func_get(&fake_cmd);
|
||||||
EINA_SAFETY_ON_NULL_RETURN_VAL(blend, EINA_FALSE);
|
EINA_SAFETY_ON_NULL_RETURN_VAL(blend, EINA_FALSE);
|
||||||
blend(&fake_cmd);
|
ret = blend(&fake_cmd);
|
||||||
|
if (!ret) goto finish;
|
||||||
|
|
||||||
// Temp --> Output
|
// Temp --> Output
|
||||||
fake_cmd.draw.render_op = EVAS_RENDER_BLEND;
|
fake_cmd.draw.render_op = EVAS_RENDER_BLEND;
|
||||||
|
@ -387,8 +389,9 @@ _mask_cpu_rgba_rgba_rgba(Evas_Filter_Command *cmd)
|
||||||
fake_cmd.output = cmd->output;
|
fake_cmd.output = cmd->output;
|
||||||
blend = evas_filter_blend_cpu_func_get(&fake_cmd);
|
blend = evas_filter_blend_cpu_func_get(&fake_cmd);
|
||||||
EINA_SAFETY_ON_NULL_RETURN_VAL(blend, EINA_FALSE);
|
EINA_SAFETY_ON_NULL_RETURN_VAL(blend, EINA_FALSE);
|
||||||
blend(&fake_cmd);
|
ret = blend(&fake_cmd);
|
||||||
|
|
||||||
|
finish:
|
||||||
fb->locked = EINA_FALSE;
|
fb->locked = EINA_FALSE;
|
||||||
return EINA_TRUE;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -153,7 +153,7 @@ struct _Evas_Filter_Buffer
|
||||||
|
|
||||||
Evas_Object *source;
|
Evas_Object *source;
|
||||||
Eina_Stringshare *source_name;
|
Eina_Stringshare *source_name;
|
||||||
void *backing;
|
RGBA_Image *backing;
|
||||||
void *glimage;
|
void *glimage;
|
||||||
int w, h;
|
int w, h;
|
||||||
|
|
||||||
|
@ -161,6 +161,7 @@ struct _Evas_Filter_Buffer
|
||||||
|
|
||||||
Eina_Bool alpha_only : 1; // 1 channel (A) instead of 4 (RGBA)
|
Eina_Bool alpha_only : 1; // 1 channel (A) instead of 4 (RGBA)
|
||||||
Eina_Bool allocated : 1; // allocated on demand, belongs to this context
|
Eina_Bool allocated : 1; // allocated on demand, belongs to this context
|
||||||
|
Eina_Bool allocated_gl : 1; // allocated on demand the glimage
|
||||||
Eina_Bool transient : 1; // temporary buffer (automatic allocation)
|
Eina_Bool transient : 1; // temporary buffer (automatic allocation)
|
||||||
Eina_Bool locked : 1; // internal flag
|
Eina_Bool locked : 1; // internal flag
|
||||||
Eina_Bool stolen : 1; // stolen by the client
|
Eina_Bool stolen : 1; // stolen by the client
|
||||||
|
|
|
@ -107,7 +107,7 @@ void evas_filter_context_post_run_callback_set(Evas_Filter_C
|
||||||
Eina_Bool evas_filter_context_buffers_allocate_all(Evas_Filter_Context *ctx, unsigned w, unsigned h);
|
Eina_Bool evas_filter_context_buffers_allocate_all(Evas_Filter_Context *ctx, unsigned w, unsigned h);
|
||||||
|
|
||||||
int evas_filter_buffer_empty_new(Evas_Filter_Context *ctx, Eina_Bool alpha_only);
|
int evas_filter_buffer_empty_new(Evas_Filter_Context *ctx, Eina_Bool alpha_only);
|
||||||
int evas_filter_buffer_image_new(Evas_Filter_Context *ctx, RGBA_Image *image);
|
int evas_filter_buffer_image_new(Evas_Filter_Context *ctx, void *image);
|
||||||
void *evas_filter_buffer_backing_get(Evas_Filter_Context *ctx, int bufid);
|
void *evas_filter_buffer_backing_get(Evas_Filter_Context *ctx, int bufid);
|
||||||
void *evas_filter_buffer_backing_steal(Evas_Filter_Context *ctx, int bufid);
|
void *evas_filter_buffer_backing_steal(Evas_Filter_Context *ctx, int bufid);
|
||||||
Eina_Bool evas_filter_buffer_backing_release(Evas_Filter_Context *ctx, void *stolen_buffer);
|
Eina_Bool evas_filter_buffer_backing_release(Evas_Filter_Context *ctx, void *stolen_buffer);
|
||||||
|
|
Loading…
Reference in New Issue