From c7b1a40b5ec2d63ce32be3d78e60ea1f3206140a Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Thu, 20 Jun 2019 16:07:05 +0900 Subject: [PATCH] ector: Fix precomp layer rendering issue when it has alpha value Summary: When the precomp layer(parent layer) has alpha transparency and has more than 1 child layer and they overlap each other if vg object just propagate the alpha to child layer it will be applied twice in overlapped area. Even if the child layer does not have alpha transparency, parent alpha is applied to each child. Test Plan: N/A Reviewers: Hermet, smohanty Reviewed By: Hermet Subscribers: cedric, #reviewers, kimcinoo, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D9072 --- src/lib/ector/ector_surface.eo | 10 ++++ .../ector/software/ector_software_private.h | 1 + .../ector/software/ector_software_surface.c | 26 ++++++++ .../ector/software/ector_software_surface.eo | 1 + src/lib/evas/canvas/efl_canvas_vg_container.c | 3 + src/lib/evas/canvas/efl_canvas_vg_object.c | 59 ++++++++++++++++--- src/lib/evas/canvas/evas_vg_private.h | 4 ++ 7 files changed, 97 insertions(+), 7 deletions(-) diff --git a/src/lib/ector/ector_surface.eo b/src/lib/ector/ector_surface.eo index 0dcfff28ac..67a4813368 100644 --- a/src/lib/ector/ector_surface.eo +++ b/src/lib/ector/ector_surface.eo @@ -21,5 +21,15 @@ mixin @beta Ector.Surface extends Ector.Buffer @in type: const(Efl.Class); [[Efl class]] /* FIXME: Should probably be a more restricted type */ } } + draw_image @pure_virtual { + [[ Draw image's buffer to surface buffer. ]] + params { + @in image: Ector.Buffer; [[Image buffer]] + @in x: int; [[Buffer position x]] + @in y: int; [[Buffer position y]] + @in alpha: int; [[Buffer alpha value]] + } + return: bool; [[True if drawing was successful]] + } } } diff --git a/src/lib/ector/software/ector_software_private.h b/src/lib/ector/software/ector_software_private.h index 34ea0038b7..62d1c3f8fd 100644 --- a/src/lib/ector/software/ector_software_private.h +++ b/src/lib/ector/software/ector_software_private.h @@ -5,6 +5,7 @@ #include "sw_ft_raster.h" #include "sw_ft_stroker.h" #include "../ector_private.h" +#include "draw.h" typedef struct _Ector_Software_Surface_Data Ector_Software_Surface_Data; typedef struct _Ector_Software_Thread Ector_Software_Thread; diff --git a/src/lib/ector/software/ector_software_surface.c b/src/lib/ector/software/ector_software_surface.c index 10cf9962fd..08a2786f16 100644 --- a/src/lib/ector/software/ector_software_surface.c +++ b/src/lib/ector/software/ector_software_surface.c @@ -245,5 +245,31 @@ _ector_software_surface_ector_surface_reference_point_set(Eo *obj EINA_UNUSED, pd->y = y; } +static Eina_Bool +_ector_software_surface_ector_surface_draw_image(Eo *obj EINA_UNUSED, + Ector_Software_Surface_Data *pd, + Ector_Buffer *buffer, int x, int y, int alpha) +{ + if (!buffer || !pd->rasterizer || !pd->rasterizer->fill_data.raster_buffer->pixels.u32) + return EINA_FALSE; + + Ector_Software_Buffer_Base_Data *bd = efl_data_scope_get(buffer, ECTOR_SOFTWARE_BUFFER_BASE_MIXIN); + const int pix_stride = pd->rasterizer->fill_data.raster_buffer->stride / 4; + + uint32_t *src = bd->pixels.u32; + for (unsigned int local_y = 0; local_y < bd->generic->h; local_y++) + { + uint32_t *dst = pd->rasterizer->fill_data.raster_buffer->pixels.u32 + (x + ((local_y + y) * pix_stride)); + for (unsigned int local_x = 0; local_x < bd->generic->w; local_x++) + { + *src = draw_mul_256(alpha, *src); + int inv_alpha = 255 - ((*src) >> 24); + *dst = *src + draw_mul_256(inv_alpha, *dst); + dst++; + src++; + } + } + return EINA_TRUE; +} #include "ector_software_surface.eo.c" #include "ector_renderer_software.eo.c" diff --git a/src/lib/ector/software/ector_software_surface.eo b/src/lib/ector/software/ector_software_surface.eo index 77d6db28a3..62126401b8 100644 --- a/src/lib/ector/software/ector_software_surface.eo +++ b/src/lib/ector/software/ector_software_surface.eo @@ -6,6 +6,7 @@ class @beta Ector.Software.Surface extends Ector.Software.Buffer implements Ecto implements { Ector.Surface.renderer_factory_new; Ector.Surface.reference_point { set; } + Ector.Surface.draw_image; Efl.Object.destructor; Efl.Object.constructor; } diff --git a/src/lib/evas/canvas/efl_canvas_vg_container.c b/src/lib/evas/canvas/efl_canvas_vg_container.c index 9598168956..2c55071a4d 100644 --- a/src/lib/evas/canvas/efl_canvas_vg_container.c +++ b/src/lib/evas/canvas/efl_canvas_vg_container.c @@ -236,6 +236,9 @@ static void _efl_canvas_vg_container_efl_object_destructor(Eo *obj, Efl_Canvas_Vg_Container_Data *pd) { + if (pd->blend_pixels) free(pd->blend_pixels); + if (pd->blend_buffer) efl_unref(pd->blend_buffer); + //Destroy mask surface if (pd->mask.buffer) efl_unref(pd->mask.buffer); if (pd->mask.pixels) free(pd->mask.pixels); diff --git a/src/lib/evas/canvas/efl_canvas_vg_object.c b/src/lib/evas/canvas/efl_canvas_vg_object.c index c4e7c2b861..026640a80a 100644 --- a/src/lib/evas/canvas/efl_canvas_vg_object.c +++ b/src/lib/evas/canvas/efl_canvas_vg_object.c @@ -386,22 +386,66 @@ _efl_canvas_vg_object_efl_object_finalize(Eo *obj, Efl_Canvas_Vg_Object_Data *pd static void _evas_vg_render(Evas_Object_Protected_Data *obj, Efl_Canvas_Vg_Object_Data *pd, void *engine, void *output, void *context, Efl_VG *node, - Eina_Array *clips, Eina_Bool do_async) + Eina_Array *clips, int w, int h, Ector_Surface *ector, Eina_Bool do_async) { if (!efl_gfx_entity_visible_get(node)) return; if (efl_isa(node, EFL_CANVAS_VG_CONTAINER_CLASS)) { - Efl_Canvas_Vg_Container_Data *cd = - efl_data_scope_get(node, EFL_CANVAS_VG_CONTAINER_CLASS); + Efl_VG *child; + Eina_List *l; + Efl_Canvas_Vg_Container_Data *cd = efl_data_scope_get(node, EFL_CANVAS_VG_CONTAINER_CLASS); if (cd->mask.target) return; //Don't draw mask itself. - Efl_VG *child; - Eina_List *l; + int alpha = 255; + efl_gfx_color_get(node, NULL, NULL, NULL, &alpha); - EINA_LIST_FOREACH(cd->children, l, child) - _evas_vg_render(obj, pd, engine, output, context, child, clips, do_async); + if (alpha < 255) + { + // Reuse buffer + if (!cd->blend_pixels) + cd->blend_pixels = calloc(w * h, sizeof(uint32_t*)); + else + memset(cd->blend_pixels, 0, sizeof(uint32_t) * (w * h)); + + if (!cd->blend_buffer) + { + cd->blend_buffer = ENFN->ector_buffer_new(ENC, obj->layer->evas->evas, + w, h, + EFL_GFX_COLORSPACE_ARGB8888, + ECTOR_BUFFER_FLAG_DRAWABLE | + ECTOR_BUFFER_FLAG_CPU_READABLE | + ECTOR_BUFFER_FLAG_CPU_WRITABLE); + ector_buffer_pixels_set(cd->blend_buffer, cd->blend_pixels, + w, h, 0, + EFL_GFX_COLORSPACE_ARGB8888, EINA_TRUE); + } + + // Buffer change + ector_buffer_pixels_set(ector, cd->blend_pixels, + w, h, 0, + EFL_GFX_COLORSPACE_ARGB8888, EINA_TRUE); + ector_surface_reference_point_set(ector, 0,0); + + // Draw child node to changed buffer + EINA_LIST_FOREACH(cd->children, l, child) + _evas_vg_render(obj, pd, engine, output, context, child, clips, w, h, ector, do_async); + + // Re-set original surface + ENFN->ector_begin(engine, output, context, ector, 0, 0, EINA_FALSE, do_async); + + // Draw buffer to original surface.(Ector_Surface) + ector_surface_draw_image(ector, cd->blend_buffer, 0, 0, alpha); + + } + else + { + if (cd->blend_pixels) free(cd->blend_pixels); + if (cd->blend_buffer) efl_unref(cd->blend_buffer); + EINA_LIST_FOREACH(cd->children, l, child) + _evas_vg_render(obj, pd, engine, output, context, child, clips, w, h, ector, do_async); + } } else { @@ -451,6 +495,7 @@ _render_to_buffer(Evas_Object_Protected_Data *obj, Efl_Canvas_Vg_Object_Data *pd engine, buffer, context, root, NULL, + w, h, ector, do_async); ENFN->image_dirty_region(engine, buffer, 0, 0, w, h); diff --git a/src/lib/evas/canvas/evas_vg_private.h b/src/lib/evas/canvas/evas_vg_private.h index f4c47de4bb..73ff63e7d8 100644 --- a/src/lib/evas/canvas/evas_vg_private.h +++ b/src/lib/evas/canvas/evas_vg_private.h @@ -94,6 +94,10 @@ struct _Efl_Canvas_Vg_Container_Data //Masking feature. Efl_Canvas_Vg_Node *mask_src; //Mask Source Vg_Mask mask; //Mask source data + + //Layer transparency feature. This buffer is only valid when the layer has transparency. + Ector_Buffer *blend_buffer; + void *blend_pixels; }; struct _Efl_Canvas_Vg_Gradient_Data