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.