Evas filters: Final fix after the ector refactor

This implements a generic way of scaling buffers, using fake
RGBA_Image wrapping ector buffer maps. The underlying algo is
still the good old linear sw scaler.

Now the filters *should* be back to their previous level of
usability. Performance will probably be even worse than it was
before, for GL, as more glReadPixels may be involved. Optimization
now consists in actually implementing the filters with GL shaders.
This commit is contained in:
Jean-Philippe Andre 2016-01-04 21:46:56 +09:00
parent 13f66f8887
commit c1b4728487
9 changed files with 122 additions and 47 deletions

View File

@ -778,6 +778,8 @@ CLEANFILES += \
$(evas_gl_generic_eolian_c) \
$(evas_gl_generic_eolian_h)
EXTRA_DIST += $(evas_gl_generic_eolian_files)
#evaseolianfilesdir = $(datadir)/eolian/include/evas-@VMAJ@
#evaseolianfiles_DATA += $(evas_gl_generic_eolian_files)

View File

@ -11,6 +11,9 @@
#define ENFN obj->layer->evas->engine.func
#define ENDT obj->layer->evas->engine.data.output
#define FCOW_BEGIN(_pd) eina_cow_write(evas_object_filter_cow, (const Eina_Cow_Data**)&(_pd->data))
#define FCOW_END(_fcow, _pd) eina_cow_done(evas_object_filter_cow, (const Eina_Cow_Data**)&(_pd->data), _fcow, EINA_TRUE)
typedef struct _Evas_Filter_Data Evas_Filter_Data;
struct _Evas_Filter_Data
{
@ -21,9 +24,9 @@ static void
_filter_cb(Evas_Filter_Context *ctx, void *data, Eina_Bool success)
{
Eo *eo_obj = data;
Evas_Filter_Data *pd = eo_data_scope_get(eo_obj, MY_CLASS);
// Destroy context as we won't reuse it.
evas_filter_context_destroy(ctx);
// FIXME: This needs to run in the main loop
// Redraw text with normal styles in case of failure
if (!success)
@ -39,6 +42,18 @@ _filter_cb(Evas_Filter_Context *ctx, void *data, Eina_Bool success)
evas_object_coords_recalc(eo_obj, obj);
evas_object_inform_call_resize(eo_obj);
}
else
{
Evas_Object_Filter_Data *fcow;
void *output = evas_filter_buffer_backing_steal(ctx, EVAS_FILTER_BUFFER_OUTPUT_ID);
fcow = FCOW_BEGIN(pd);
fcow->output = output;
FCOW_END(fcow, pd);
}
// Destroy context as we won't reuse it.
evas_filter_context_destroy(ctx);
}
static void
@ -76,9 +91,6 @@ _filter_source_hash_free_cb(void *data)
free(pb);
}
#define FCOW_BEGIN(_pd) eina_cow_write(evas_object_filter_cow, (const Eina_Cow_Data**)&(_pd->data))
#define FCOW_END(_fcow, _pd) eina_cow_done(evas_object_filter_cow, (const Eina_Cow_Data**)&(_pd->data), _fcow, EINA_TRUE)
Eina_Bool
evas_filter_object_render(Eo *eo_obj, Evas_Object_Protected_Data *obj,
void *output, void *context, void *surface,
@ -86,6 +98,10 @@ evas_filter_object_render(Eo *eo_obj, Evas_Object_Protected_Data *obj,
{
Evas_Filter_Data *pd = eo_data_scope_get(eo_obj, MY_CLASS);
// FIXME: Forcing sync render for all engines! (cb needs the main loop)
if (do_async) WRN("Disarding async render flag!");
do_async = EINA_FALSE;
if (!pd->data->invalid && (pd->data->chain || pd->data->code))
{
int X, Y, W, H, l = 0, r = 0, t = 0, b = 0;
@ -94,7 +110,6 @@ evas_filter_object_render(Eo *eo_obj, Evas_Object_Protected_Data *obj,
Eina_Bool ok;
void *previous = pd->data->output;
Evas_Object_Filter_Data *fcow;
void *filter_output;
/* NOTE: Filter rendering is now done ENTIRELY on CPU.
* So we rely on cache/cache2 to allocate a real image buffer,
@ -236,8 +251,7 @@ evas_filter_object_render(Eo *eo_obj, Evas_Object_Protected_Data *obj,
evas_filter_context_buffers_allocate_all(filter);
evas_filter_target_set(filter, context, surface, X + x, Y + y);
// Steal output and release previous
filter_output = evas_filter_buffer_backing_steal(filter, EVAS_FILTER_BUFFER_OUTPUT_ID);
// Release previous output
evas_filter_buffer_backing_release(filter, previous);
// Request rendering from the object itself (child class)
@ -252,7 +266,7 @@ evas_filter_object_render(Eo *eo_obj, Evas_Object_Protected_Data *obj,
ok = evas_filter_run(filter);
fcow = FCOW_BEGIN(pd);
fcow->output = filter_output;
fcow->output = NULL;
fcow->changed = EINA_FALSE;
fcow->async = do_async;
if (!ok) fcow->invalid = EINA_TRUE;

View File

@ -209,6 +209,8 @@ _ector_buffer_create(Evas_Filter_Buffer const *fb, void *data)
flags = ECTOR_BUFFER_FLAG_CPU_READABLE | ECTOR_BUFFER_FLAG_CPU_WRITABLE;
if (fb->id == EVAS_FILTER_BUFFER_INPUT_ID)
flags |= ECTOR_BUFFER_FLAG_RENDERABLE;
else if (fb->id == EVAS_FILTER_BUFFER_OUTPUT_ID)
flags |= ECTOR_BUFFER_FLAG_DRAWABLE;
cspace = fb->alpha_only ? EVAS_COLORSPACE_GRY8 : EVAS_COLORSPACE_ARGB8888;
return fb->ENFN->ector_buffer_new(fb->ENDT, fb->ctx->evas->evas,

View File

@ -64,7 +64,7 @@ evas_filter_mask_cpu_func_get(Evas_Filter_Command *cmd)
static Eina_Bool
_mask_cpu_alpha_alpha_alpha(Evas_Filter_Command *cmd)
{
unsigned int src_len, src_stride, msk_len, msk_stride, dst_len, dst_stride;
unsigned int src_len = 0, src_stride, msk_len = 0, msk_stride, dst_len = 0, dst_stride;
Efl_Gfx_Render_Op render_op = cmd->draw.rop;
Evas_Filter_Buffer *msk_fb;
Alpha_Gfx_Func func;
@ -225,7 +225,7 @@ _mask_cpu_alpha_rgba_rgba(Evas_Filter_Command *cmd)
}
else msk_fb = cmd->mask;
src_map = _buffer_map_all(cmd->input->buffer, &src_len, E_WRITE, E_ALPHA, &src_stride);
src_map = _buffer_map_all(cmd->input->buffer, &src_len, E_READ, E_ALPHA, &src_stride);
msk_map = _buffer_map_all(msk_fb->buffer, &msk_len, E_READ, E_ARGB, &msk_stride);
dst_map = _buffer_map_all(cmd->output->buffer, &dst_len, E_WRITE, E_ARGB, &dst_stride);
EINA_SAFETY_ON_FALSE_GOTO(src_map && dst_map && msk_map, end);
@ -316,8 +316,8 @@ _mask_cpu_alpha_alpha_rgba(Evas_Filter_Command *cmd)
}
else msk_fb = cmd->mask;
src_map = _buffer_map_all(cmd->input->buffer, &src_len, E_WRITE, E_ALPHA, &src_stride);
msk_map = _buffer_map_all(msk_fb->buffer, &msk_len, E_READ, E_ARGB, &msk_stride);
src_map = _buffer_map_all(cmd->input->buffer, &src_len, E_READ, E_ALPHA, &src_stride);
msk_map = _buffer_map_all(msk_fb->buffer, &msk_len, E_READ, E_ALPHA, &msk_stride);
dst_map = _buffer_map_all(cmd->output->buffer, &dst_len, E_WRITE, E_ARGB, &dst_stride);
EINA_SAFETY_ON_FALSE_GOTO(src_map && dst_map && msk_map, end);
@ -400,7 +400,7 @@ _mask_cpu_rgba_rgba_rgba(Evas_Filter_Command *cmd)
}
else msk_fb = cmd->mask;
src_map = _buffer_map_all(cmd->input->buffer, &src_len, E_WRITE, E_ARGB, &src_stride);
src_map = _buffer_map_all(cmd->input->buffer, &src_len, E_READ, E_ARGB, &src_stride);
msk_map = _buffer_map_all(msk_fb->buffer, &msk_len, E_READ, E_ARGB, &msk_stride);
dst_map = _buffer_map_all(cmd->output->buffer, &dst_len, E_WRITE, E_ARGB, &dst_stride);
EINA_SAFETY_ON_FALSE_GOTO(src_map && dst_map && msk_map, end);

View File

@ -7,39 +7,65 @@ evas_filter_buffer_scaled_get(Evas_Filter_Context *ctx,
Evas_Filter_Buffer *src,
unsigned w, unsigned h)
{
Evas_Filter_Buffer *fb;
RGBA_Image *dstim, *srcim;
unsigned int src_len = 0, src_stride, dst_len = 0, dst_stride;
uint8_t *src_map = NULL, *dst_map = NULL;
Evas_Filter_Buffer *dst;
RGBA_Image dstim, srcim;
RGBA_Draw_Context dc;
Eina_Bool ok;
// only for RGBA
EINA_SAFETY_ON_FALSE_RETURN_VAL(!src->alpha_only, NULL);
DBG("Scaling buffer from %dx%d to %dx%d, this is a slow operation!",
src->w, src->h, w, h);
DEBUG_TIME_BEGIN();
srcim = evas_filter_buffer_backing_get(ctx, src->id);
EINA_SAFETY_ON_NULL_RETURN_VAL(srcim, NULL);
// Get destination buffer
dst = evas_filter_temporary_buffer_get(ctx, w, h, src->alpha_only);
EINA_SAFETY_ON_NULL_RETURN_VAL(dst, NULL);
fb = evas_filter_temporary_buffer_get(ctx, w, h, src->alpha_only);
EINA_SAFETY_ON_NULL_RETURN_VAL(fb, NULL);
// Map input and output
src_map = _buffer_map_all(src->buffer, &src_len, E_READ, E_ARGB, &src_stride);
dst_map = _buffer_map_all(dst->buffer, &dst_len, E_WRITE, E_ARGB, &dst_stride);
EINA_SAFETY_ON_FALSE_GOTO(src_map && dst_map, end);
EINA_SAFETY_ON_FALSE_GOTO((src_stride == ((unsigned) src->w * 4)) &&
(dst_stride == (w * 4)), end);
dstim = evas_filter_buffer_backing_get(ctx, fb->id);
EINA_SAFETY_ON_NULL_RETURN_VAL(dstim, NULL);
EINA_SAFETY_ON_FALSE_RETURN_VAL((dstim->cache_entry.w == w) &&
(dstim->cache_entry.h == h), NULL);
// Wrap as basic RGBA_Images
memset(&dstim, 0, sizeof(dstim));
dstim.cache_entry.w = w;
dstim.cache_entry.h = h;
dstim.cache_entry.flags.alpha = 1;
dstim.cache_entry.flags.alpha_sparse = 0;
dstim.cache_entry.space = EVAS_COLORSPACE_ARGB8888;
dstim.image.data8 = dst_map;
memset(&srcim, 0, sizeof(srcim));
srcim.cache_entry.w = src->w;
srcim.cache_entry.h = src->h;
srcim.cache_entry.flags.alpha = 1;
srcim.cache_entry.flags.alpha_sparse = 0;
srcim.cache_entry.space = EVAS_COLORSPACE_ARGB8888;
srcim.image.data8 = src_map;
// Basic draw context
memset(&dc, 0, sizeof(dc));
dc.sli.h = 1;
dc.render_op = EVAS_RENDER_COPY;
// Do the scale
ok = evas_common_scale_rgba_in_to_out_clip_smooth
(srcim, dstim, &dc, 0, 0, src->w, src->h, 0, 0, w, h);
(&srcim, &dstim, &dc, 0, 0, src->w, src->h, 0, 0, w, h);
if (!ok)
{
ERR("RGBA Image scaling failed.");
return NULL;
dst = NULL;
}
return fb;
end:
if (src_map) eo_do(src->buffer, ector_buffer_unmap(src_map, src_len));
if (dst_map) eo_do(dst->buffer, ector_buffer_unmap(dst_map, dst_len));
DEBUG_TIME_END();
return dst;
}
static Eina_Bool

View File

@ -54,17 +54,6 @@ _pixels_argb_to_gry8_convert(uint8_t *dst, const uint32_t *src, int len)
}
}
static inline void
_pixels_gry8_to_argb_convert(uint32_t *dst, const uint8_t *src, int len)
{
int k;
for (k = 0; k < len; k++)
{
uint8_t s = *src++;
*dst++ = ARGB_JOIN(s, s, s, s);
}
}
EOLIAN static void
_evas_ector_gl_image_buffer_evas_ector_buffer_engine_image_set(Eo *obj, Evas_Ector_GL_Image_Buffer_Data *pd,
Evas *evas, void *image)
@ -175,7 +164,7 @@ _evas_ector_gl_image_buffer_ector_generic_buffer_map(Eo *obj EINA_UNUSED, Evas_E
if (tofree)
map->im = im;
else
map->im = ENFN->image_ref(ENDT, im);
map->im = NULL;
len = w * h;
if (cspace == EFL_GFX_COLORSPACE_GRY8)
@ -218,7 +207,8 @@ _evas_ector_gl_image_buffer_ector_generic_buffer_unmap(Eo *obj EINA_UNUSED, Evas
{
CRI("Not implemented yet. Dropping pixel changes.");
}
ENFN->image_free(ENDT, map->im);
if (map->im)
ENFN->image_free(ENDT, map->im);
if (map->allocated)
free(map->ptr);
return;

View File

@ -73,6 +73,12 @@ _evas_ector_gl_rgbaimage_buffer_evas_ector_buffer_engine_image_get(Eo *obj EINA_
goto end;
gc = re->window_gl_context_get(re->software.ob);
#ifdef EVAS_CSERVE2
if (evas_cache2_image_cached(&pd->image->cache_entry))
evas_cache2_image_ref(&pd->image->cache_entry);
else
#endif
evas_cache_image_ref(&pd->image->cache_entry);
pd->glim = evas_gl_common_image_new_from_rgbaimage(gc, pd->image, NULL, &err);
if ((err != EVAS_LOAD_ERROR_NONE) || !pd->glim)
{

View File

@ -2502,7 +2502,7 @@ eng_ector_buffer_new(void *data, Evas *evas, void *pixels,
Ector_Buffer *buf = NULL;
int iw = width + l + r;
int ih = height + t + b;
int pxs = (cspace = EFL_GFX_COLORSPACE_ARGB8888) ? 4 : 1;
int pxs = (cspace == EFL_GFX_COLORSPACE_ARGB8888) ? 4 : 1;
if (stride && (stride != iw * pxs))
WRN("stride support is not implemented for ector gl buffers at this point!");

View File

@ -3772,17 +3772,52 @@ eng_ector_buffer_wrap(void *data EINA_UNUSED, Evas *e, void *engine_image, Eina_
}
static Ector_Buffer *
eng_ector_buffer_new(void *data EINA_UNUSED, Evas *e, void *pixels,
eng_ector_buffer_new(void *data EINA_UNUSED, Evas *evas, void *pixels,
int width, int height, int stride,
Efl_Gfx_Colorspace cspace, Eina_Bool writeable,
int l, int r, int t, int b,
Ector_Buffer_Flag flags EINA_UNUSED)
{
Ector_Buffer *buf = NULL;
int pxs = (cspace == EFL_GFX_COLORSPACE_ARGB8888) ? 4 : 1;
int iw = width + l + r;
int ih = height + t + b;
buf = eo_add(ECTOR_SOFTWARE_BUFFER_CLASS, e,
ector_buffer_pixels_set(pixels, width, height, stride, cspace,
writeable, l, r, t, b));
if ((flags & (ECTOR_BUFFER_FLAG_RENDERABLE | ECTOR_BUFFER_FLAG_DRAWABLE)) == 0)
{
buf = eo_add(ECTOR_SOFTWARE_BUFFER_CLASS, evas,
ector_buffer_pixels_set(pixels, width, height, stride, cspace,
writeable, l, r, t, b));
}
else
{
// Create an RGBA Image as backing
Image_Entry *ie;
if (pixels)
{
// no copy
ie = evas_cache_image_data(evas_common_image_cache_get(), iw, ih,
pixels, EINA_TRUE, (Evas_Colorspace) cspace);
if (!ie) return NULL;
}
else
{
// alloc buffer
ie = evas_cache_image_copied_data(evas_common_image_cache_get(), iw, ih,
NULL, EINA_TRUE, (Evas_Colorspace) cspace);
if (!ie) return NULL;
pixels = ((RGBA_Image *) ie)->image.data;
memset(pixels, 0, iw * ih * pxs);
}
ie->borders.l = l;
ie->borders.r = r;
ie->borders.t = t;
ie->borders.b = b;
buf = eng_ector_buffer_wrap(data, evas, ie, EINA_TRUE);
evas_cache_image_drop(ie);
}
return buf;
}