This is an automated email from the git hooks/post-receive script.

git pushed a commit to reference refs/pull/114/head
in repository efl.

View the commit online.

commit 0c6f7e50ff821efd93d2595f5ebd9bef65dc103b
Author: Cedric BAIL <[email protected]>
AuthorDate: Fri Aug 14 11:10:33 2026 -0600

    fix(evas_vg): apply container group opacity on the GL span path
    
    A vector container whose colour has alpha below 255 asks for group
    opacity, and _evas_vg_render() serves that by rendering the group into
    a CPU blend buffer and compositing it into the ector surface's pixel
    buffer. The GL engine rasterises shapes through the span path, which
    renders into an FBO and never reads that pixel buffer back, so the
    group's alpha was computed and then discarded: the group came out fully
    opaque, while the software engine had it right. Same scene, two
    engines, visibly different results.
    
    Fold the alpha into the draw context's multiplier for the subtree
    instead. eng_ector_renderer_draw() now passes that multiplier down as
    each shape's mul_col rather than a hardcoded 0xffffffff; the span
    collector already composites mul_col into the span colour and the
    shader already carries it per quad, so nothing below had to change.
    
    This applies the alpha per shape rather than to the flattened group, so
    shapes overlapping inside a group blend against each other before being
    faded rather than after. It is exact wherever a group's shapes are
    disjoint, which is the usual case for fading one out, and much closer
    than ignoring the alpha outright. The exact form needs the group
    rendered to its own FBO and composited, which the mask path's machinery
    could be extended to do.
    
    The software engine keeps the blend buffer; only the GL path, which
    cannot use it, takes the new route.
    
    With an opaque white shape in a container at alpha 128 over black, the
    centre pixel is now 0x80 on GL against 0x7f on the software engine,
    where GL previously gave 0xff. The ten VG expedite tests render
    byte-identical frames - none of them uses container alpha - and test
    125 and 121 are unchanged in speed.
    
    Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
---
 src/lib/evas/canvas/efl_canvas_vg_object.c        | 52 +++++++++++++++++++++++
 src/modules/evas/engines/gl_generic/evas_engine.c | 10 ++++-
 2 files changed, 60 insertions(+), 2 deletions(-)

diff --git a/src/lib/evas/canvas/efl_canvas_vg_object.c b/src/lib/evas/canvas/efl_canvas_vg_object.c
index 6e4da011e5..5748bfd7bf 100644
--- a/src/lib/evas/canvas/efl_canvas_vg_object.c
+++ b/src/lib/evas/canvas/efl_canvas_vg_object.c
@@ -444,6 +444,58 @@ _evas_vg_render(Evas_Object_Protected_Data *obj, Efl_Canvas_Vg_Object_Data *pd,
         int alpha = 255;
         efl_gfx_color_get(node, NULL, NULL, NULL, &alpha);
 
+        /* Group opacity on the GL engine.
+         *
+         * The blend-buffer path below composites the group into the ector
+         * surface's CPU pixel buffer.  The GL engine rasterises vector shapes
+         * through a span path that renders into an FBO and never reads that
+         * buffer back, so there the group's alpha would be computed and then
+         * dropped, leaving the group fully opaque.  Fold it into the draw
+         * context's multiplier instead, which the engine passes down as each
+         * shape's mul_col.
+         *
+         * This applies the alpha per shape rather than to the flattened
+         * group, so shapes that overlap inside the group blend against each
+         * other before being faded rather than after.  Identical wherever a
+         * group's shapes are disjoint, which is the usual case for fading one
+         * out; the exact form needs the group rendered to its own FBO. */
+        if ((alpha < 255) && ENFN->gl_surface_read_pixels)
+          {
+             int pr = 255, pg = 255, pb = 255, pa = 255;
+             Eina_Bool had_mul;
+
+             had_mul = !!ENFN->context_multiplier_get(engine, context,
+                                                      &pr, &pg, &pb, &pa);
+             if (!had_mul) { pr = pg = pb = pa = 255; }
+
+#define _VG_MUL(x, y)  (((x) * (y) + 0xff) >> 8)
+             ENFN->context_multiplier_set(engine, context,
+                                          _VG_MUL(pr, alpha), _VG_MUL(pg, alpha),
+                                          _VG_MUL(pb, alpha), _VG_MUL(pa, alpha));
+#undef _VG_MUL
+
+             EINA_LIST_FOREACH(cd->children, l, child)
+               {
+                  if (efl_isa(child, EFL_CANVAS_VG_CONTAINER_CLASS))
+                    {
+                       Efl_Canvas_Vg_Container_Data *child_cd =
+                          efl_data_scope_get(child, EFL_CANVAS_VG_CONTAINER_CLASS);
+                       if (child_cd && child_cd->comp.src) continue;
+                    }
+                  if (cd->comp_target && efl_isa(child, EFL_CANVAS_VG_GRADIENT_CLASS))
+                    continue;
+                  _evas_vg_render(obj, pd, engine, output, context, child,
+                                  clips, w, h, ector, do_async);
+               }
+
+             if (had_mul)
+               ENFN->context_multiplier_set(engine, context, pr, pg, pb, pa);
+             else
+               ENFN->context_multiplier_unset(engine, context);
+
+             return;
+          }
+
         if (alpha < 255)
           {
              //Replace with a new size.
diff --git a/src/modules/evas/engines/gl_generic/evas_engine.c b/src/modules/evas/engines/gl_generic/evas_engine.c
index 99d9263029..dc770a3537 100644
--- a/src/modules/evas/engines/gl_generic/evas_engine.c
+++ b/src/modules/evas/engines/gl_generic/evas_engine.c
@@ -2606,18 +2606,24 @@ eng_ector_buffer_new(void *engine, Evas *evas, int w, int h,
 
 static void
 eng_ector_renderer_draw(void *engine EINA_UNUSED, void *surface,
-                        void *context EINA_UNUSED, Ector_Renderer *renderer,
+                        void *context, Ector_Renderer *renderer,
                         Eina_Array *clips EINA_UNUSED, Eina_Bool do_async EINA_UNUSED)
 {
    int w, h;
    Eina_Rectangle *r;
    Eina_Array *c = eina_array_new(4);
    Evas_GL_Image *glimg = surface;
+   RGBA_Draw_Context *dc = context;
+   /* Carry the draw context's multiplier through as the shape's mul_col.
+    * It is how group opacity reaches the span path: a vector container with
+    * alpha folds itself into this multiplier rather than compositing through
+    * a CPU blend buffer the GL path never reads back. */
+   unsigned int mul_col = (dc && dc->mul.use) ? dc->mul.col : 0xffffffff;
 
    eng_image_size_get(engine, glimg, &w, &h);
    eina_array_push(c, eina_rectangle_new(0, 0, w, h));
 
-   ector_renderer_draw(renderer, EFL_GFX_RENDER_OP_BLEND, c, 0xffffffff);
+   ector_renderer_draw(renderer, EFL_GFX_RENDER_OP_BLEND, c, mul_col);
 
    while ((r = eina_array_pop(c)))
      eina_rectangle_free(r);

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.

Reply via email to