This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch span-gl-clean
in repository efl.
View the commit online.
commit d11ee49ee554066645225e8344fda7247884871c
Author: [email protected] <[email protected]>
AuthorDate: Mon Aug 10 21:13:19 2026 -0600
perf(evas_ector_gl): pack span rows into one upload without unpack_subimage
The span buffer's row stride is wider than the uploaded rect, so without
GL_EXT_unpack_subimage the rows could not be given to GL directly and the
upload fell back to one glTexSubImage2D per scanline - where the row count
is the full VG surface height, per collector, per shape, per frame. A
600 pixel canvas with twenty fill-and-stroke shapes is 24000 calls a frame.
Copy the rows into a contiguous scratch buffer and upload once, mirroring
what the first-frame creation path already does. The fast path is
untouched; devices that advertise the extension never execute this.
Verified by temporarily forcing the branch: the vector tests come out
bit-identical to the normal path.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
---
.../engines/gl_generic/evas_ector_gl_span_shader.c | 58 +++++++++++++++++++---
1 file changed, 52 insertions(+), 6 deletions(-)
diff --git a/src/modules/evas/engines/gl_generic/evas_ector_gl_span_shader.c b/src/modules/evas/engines/gl_generic/evas_ector_gl_span_shader.c
index 743a145316..ce2d432b2e 100644
--- a/src/modules/evas/engines/gl_generic/evas_ector_gl_span_shader.c
+++ b/src/modules/evas/engines/gl_generic/evas_ector_gl_span_shader.c
@@ -27,6 +27,25 @@
#include "evas_ector_gl_span.h"
#include "evas_ector_gl_grad_atlas.h"
+/* Scratch buffer for the no-EXT_unpack_subimage upload path: span rows are
+ * copied here tightly packed so one glTexSubImage2D covers the whole
+ * sub-rect. Grown on demand, never shrunk; freed in span_shader_shutdown. */
+static uint8_t *_span_pack_buf = NULL;
+static size_t _span_pack_sz = 0;
+
+static uint8_t *
+_span_pack_buf_get(size_t need)
+{
+ if (need > _span_pack_sz)
+ {
+ uint8_t *p = realloc(_span_pack_buf, need);
+ if (!p) return NULL;
+ _span_pack_buf = p;
+ _span_pack_sz = need;
+ }
+ return _span_pack_buf;
+}
+
/* ------------------------------------------------------------------ */
/* GLSL shader source strings */
/* ------------------------------------------------------------------ */
@@ -980,6 +999,10 @@ span_shader_shutdown(void)
glDeleteTextures(1, &_white_mask_tex);
_white_mask_tex = 0;
}
+
+ free(_span_pack_buf);
+ _span_pack_buf = NULL;
+ _span_pack_sz = 0;
}
/* ------------------------------------------------------------------ */
@@ -1123,15 +1146,38 @@ span_collector_upload_textures(Span_Collector *sc, void *gc_ptr)
}
else
{
- int row;
- for (row = 0; row < sc->height; row++)
+ /* No GL_UNPACK_ROW_LENGTH: the span buffer's stride
+ * ((max_spans + 1) * 4) is wider than the uploaded rect, so
+ * the rows cannot be handed to GL as-is. Pack them into a
+ * contiguous scratch buffer and upload once, rather than
+ * issuing one call per scanline per shape per frame. */
+ size_t row_bytes = (size_t)tex_width * 4;
+ size_t need = row_bytes * (size_t)sc->height;
+ uint8_t *packed = _span_pack_buf_get(need);
+
+ if (packed)
{
- const uint8_t *src = "" + (size_t)row * sc->stride;
+ int row;
+ for (row = 0; row < sc->height; row++)
+ memcpy(packed + (size_t)row * row_bytes,
+ tex->buffer + (size_t)row * sc->stride,
+ row_bytes);
glTexSubImage2D(GL_TEXTURE_2D, 0,
- evas_t->x, evas_t->y + row,
- tex_width, 1,
+ evas_t->x, evas_t->y,
+ tex_width, sc->height,
evas_t->pt->format,
- GL_UNSIGNED_BYTE, src);
+ GL_UNSIGNED_BYTE, packed);
+ }
+ else
+ {
+ int row;
+ for (row = 0; row < sc->height; row++)
+ glTexSubImage2D(GL_TEXTURE_2D, 0,
+ evas_t->x, evas_t->y + row,
+ tex_width, 1,
+ evas_t->pt->format,
+ GL_UNSIGNED_BYTE,
+ tex->buffer + (size_t)row * sc->stride);
}
}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.