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 f68ef4dfb7ca3257493c178261c3d6e0e22b42a5
Author: [email protected] <[email protected]>
AuthorDate: Mon Aug 10 21:01:27 2026 -0600

    fix(evas_ector_gl): resume LRU after atlas flush, strengthen tests
    
    Review found two issues in the prior gradient-atlas fix:
    
    1. After draining pending draws in the all-pinned case, _alloc_row kept
       every row's last_used stamped with current_frame and returned row 0
       without resetting pin state.  The very next distinct gradient in the
       same pass found every row pinned again and forced another flush - one
       heavy-gradient pass turned into a flush per gradient.  Age the pinned
       rows by one after a successful flush so ordinary LRU resumes; document
       why the no-callback fallback still returns row 0 unconditionally
       (nothing was drained, so no row can honestly be called safe, and there
       is no other way to make progress).
    
    2. grad_atlas_flush_cb_optional asserted only r >= 0, which also passed
       under the pre-fix code and did not distinguish old buggy behaviour from
       the new correct behaviour.  Rewrote it to assert the deterministic
       fallback (row 0 reused every time with no callback registered), and
       extended grad_atlas_no_eviction_of_rows_used_this_frame to assert
       flush_calls stays at 1 across several more distinct gradients in the
       same pass, guarding directly against the flush-storm regression.
    
    Verified each test can fail: reverting the post-flush aging reproduces
    _flush_calls == 6 instead of 1; reverting the no-callback fallback to
    return a different row reproduces r == 1 instead of 0.
---
 .../engines/gl_generic/evas_ector_gl_grad_atlas.c  | 27 +++++++++++++++++--
 src/tests/ector/suite/ector_test_grad_atlas.c      | 31 +++++++++++++++++++---
 2 files changed, 53 insertions(+), 5 deletions(-)

diff --git a/src/modules/evas/engines/gl_generic/evas_ector_gl_grad_atlas.c b/src/modules/evas/engines/gl_generic/evas_ector_gl_grad_atlas.c
index fbb11bc01a..0cf1f8382a 100644
--- a/src/modules/evas/engines/gl_generic/evas_ector_gl_grad_atlas.c
+++ b/src/modules/evas/engines/gl_generic/evas_ector_gl_grad_atlas.c
@@ -180,8 +180,31 @@ _alloc_row(Span_Grad_Atlas *a)
      }
    if (best >= 0) return best;
 
-   /* Every row is pinned by this pass.  Drain, then any row may be reused. */
-   if (a->flush_cb) a->flush_cb(a->flush_data);
+   /* Every row is pinned by this pass.  Drain the pending draws, then no
+    * unflushed draw references any row any more - age every pinned row by
+    * one so ordinary LRU resumes for the rest of this pass instead of
+    * flushing again on the very next miss (which would turn a heavy-gradient
+    * pass into one pipe flush per gradient). */
+   if (a->flush_cb)
+     {
+        a->flush_cb(a->flush_data);
+        for (int i = 0; i < SPAN_GRAD_ATLAS_H; i++)
+          if (a->rows[i].last_used == a->current_frame)
+            a->rows[i].last_used = a->current_frame - 1;
+
+        best     = 0;
+        best_age = a->rows[0].last_used;
+        for (int i = 1; i < SPAN_GRAD_ATLAS_H; i++)
+          if (a->rows[i].last_used < best_age)
+            { best = i; best_age = a->rows[i].last_used; }
+        return best;
+     }
+
+   /* No callback registered: nothing was drained, so no row is actually
+    * safe to reuse.  There is no way to make progress otherwise (the
+    * gradient path has no failure mode for "atlas full mid-pass"), so
+    * return row 0 anyway - this is the same degenerate-but-non-crashing
+    * fallback the atlas has always had for an unrecoverable situation. */
    return 0;
 }
 
diff --git a/src/tests/ector/suite/ector_test_grad_atlas.c b/src/tests/ector/suite/ector_test_grad_atlas.c
index 48eb2fd5c2..536904edfa 100644
--- a/src/tests/ector/suite/ector_test_grad_atlas.c
+++ b/src/tests/ector/suite/ector_test_grad_atlas.c
@@ -230,27 +230,52 @@ EFL_START_TEST(grad_atlas_no_eviction_of_rows_used_this_frame)
    ck_assert_int_ge(new_row, 0);
    ck_assert_int_eq(_flush_calls, 1);
 
+   /* After the drain, no unflushed draw references any row any more, so the
+    * next several distinct gradients in the SAME pass must resume ordinary
+    * LRU reuse rather than forcing a flush each time - one flush must not
+    * turn into a flush storm for every further gradient. */
+   for (int i = 0; i < 5; i++)
+     {
+        _fill_ramp(ramp, (uint32_t)(20000 + i));
+        int r = span_grad_atlas_lookup(a, (void *)(uintptr_t)(0xD000 + i),
+                                       (uint32_t)(20000 + i), ramp);
+        ck_assert_int_ge(r, 0);
+     }
+   ck_assert_int_eq(_flush_calls, 1);
+
    span_grad_atlas_free(a);
 }
 EFL_END_TEST
 
 EFL_START_TEST(grad_atlas_flush_cb_optional)
 {
-   /* With no callback registered the atlas must still make progress rather
-    * than fail the lookup. */
+   /* With no callback registered, nothing is ever drained, so the atlas
+    * cannot claim any row is safe to reuse once all are pinned.  It falls
+    * back to always returning row 0 for further misses in the same pass -
+    * this is deterministic and must not crash across many repeated
+    * overwrites of that row. */
    Span_Grad_Atlas *a = span_grad_atlas_new();
    ck_assert_ptr_nonnull(a);
    span_grad_atlas_test_enable(a);
 
    uint8_t ramp[SPAN_GRAD_ATLAS_ROW_BYTES];
    span_grad_atlas_frame_begin(a);
-   for (int i = 0; i < SPAN_GRAD_ATLAS_H + 1; i++)
+   for (int i = 0; i < SPAN_GRAD_ATLAS_H; i++)
      {
         _fill_ramp(ramp, (uint32_t)(i + 1));
         int r = span_grad_atlas_lookup(a, (void *)(uintptr_t)(0x3000 + i),
                                        (uint32_t)(i + 1), ramp);
         ck_assert_int_ge(r, 0);
      }
+
+   /* Every subsequent distinct gradient in this pass must land on row 0. */
+   for (int i = 0; i < 5; i++)
+     {
+        _fill_ramp(ramp, (uint32_t)(40000 + i));
+        int r = span_grad_atlas_lookup(a, (void *)(uintptr_t)(0x4000 + i),
+                                       (uint32_t)(40000 + i), ramp);
+        ck_assert_int_eq(r, 0);
+     }
    span_grad_atlas_free(a);
 }
 EFL_END_TEST

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

Reply via email to