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

git pushed a commit to branch fix-release-build
in repository efl.

View the commit online.

commit ccd6b1d3932478df077f68912bba7074af997463
Author: [email protected] <[email protected]>
AuthorDate: Mon Aug 3 20:13:34 2026 -0600

    evas: add AVX2 copy op kernels (pixel and color spans)
    
    The copy op table had no vector kernels on any x86 tier, falling back to scalar C
    for all spans. This adds AVX2 `pixel` and `color` span kernels plus their `_rel`
    (relative alpha) variants, enabling fast memcpy-like transfers with per-pixel
    alpha blending.
    
    Measured effect on expedite: test 80 (Rect Solid Few) moves from −4% to +48%
    versus SSE3, verified at 6% spread on an -O3 build. Test 58 (Image Data ARGB) is
    unchanged within noise because that path is already close to a plain memcpy.
    
    The `pixel_mask`, `pixel_color`, and `mask_color` copy groups were deliberately
    left on the C fallback. They would require `mul4_sym_avx2`, whose 1-LSB rounding
    gap is only acceptable in the blend table where SSE3 established that precedent,
    and there is no such precedent for copy. No non-temporal/streaming stores were
    used—plain stores already delivered the win, so the added complexity was not
    justified.
    
    Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
---
 .../evas/common/evas_op_copy/op_copy_color_avx2.c  | 94 ++++++++++++++++++++++
 .../evas/common/evas_op_copy/op_copy_master_avx2.c | 61 ++++++++++++++
 .../evas/common/evas_op_copy/op_copy_pixel_avx2.c  | 81 +++++++++++++++++++
 src/lib/evas/common/evas_op_copy_main_.c           | 37 ++++++++-
 src/lib/evas/common/meson.build                    |  3 +-
 src/tests/evas/meson.build                         |  2 +
 6 files changed, 275 insertions(+), 3 deletions(-)

diff --git a/src/lib/evas/common/evas_op_copy/op_copy_color_avx2.c b/src/lib/evas/common/evas_op_copy/op_copy_color_avx2.c
new file mode 100644
index 0000000000..b87a152b8c
--- /dev/null
+++ b/src/lib/evas/common/evas_op_copy/op_copy_color_avx2.c
@@ -0,0 +1,94 @@
+/* copy color --> dst */
+
+/* Ported from the plain-C reference (op_copy_color_.c). Unlike the pixel
+ * group, the C fallback here is a manual byte-store loop (*d = c; d++), not
+ * memcpy/memset, so there is a genuine vector opportunity: broadcast the
+ * constant color once and store it 8 pixels at a time. Bit-exact by
+ * construction (plain stores of the same 32-bit value, no rounding
+ * involved). The _rel variant (*d = MUL_SYM(*d>>24, c)) reuses mul_sym_avx2,
+ * already established bit-exact against the plain-C MUL_SYM macro (see
+ * op_blend_pixel_mask_avx2.c) - same pattern as op_copy_pixel_avx2.c's rel
+ * kernel, with the broadcast color standing in for the loaded source
+ * pixel. */
+
+#ifdef BUILD_AVX2
+
+static void
+_op_copy_c_dp_avx2(DATA32 *s EINA_UNUSED, DATA8 *m EINA_UNUSED, DATA32 c, DATA32 *d, int l) {
+   __m256i cv = _mm256_set1_epi32((int)c);
+   int i = 0;
+
+   for (; i + 8 <= l; i += 8)
+     _mm256_storeu_si256((__m256i *)(d + i), cv);
+   for (; i < l; i++)
+     d[i] = c;
+}
+
+#define _op_copy_cn_dp_avx2 _op_copy_c_dp_avx2
+#define _op_copy_can_dp_avx2 _op_copy_c_dp_avx2
+#define _op_copy_caa_dp_avx2 _op_copy_c_dp_avx2
+
+#define _op_copy_c_dpan_avx2 _op_copy_c_dp_avx2
+#define _op_copy_cn_dpan_avx2 _op_copy_c_dp_avx2
+#define _op_copy_can_dpan_avx2 _op_copy_c_dp_avx2
+#define _op_copy_caa_dpan_avx2 _op_copy_c_dp_avx2
+
+static void
+init_copy_color_span_funcs_avx2(void)
+{
+   op_copy_span_funcs[SP_N][SM_N][SC_N][DP][CPU_AVX2] = _op_copy_cn_dp_avx2;
+   op_copy_span_funcs[SP_N][SM_N][SC][DP][CPU_AVX2] = _op_copy_c_dp_avx2;
+   op_copy_span_funcs[SP_N][SM_N][SC_AN][DP][CPU_AVX2] = _op_copy_can_dp_avx2;
+   op_copy_span_funcs[SP_N][SM_N][SC_AA][DP][CPU_AVX2] = _op_copy_caa_dp_avx2;
+
+   op_copy_span_funcs[SP_N][SM_N][SC_N][DP_AN][CPU_AVX2] = _op_copy_cn_dpan_avx2;
+   op_copy_span_funcs[SP_N][SM_N][SC][DP_AN][CPU_AVX2] = _op_copy_c_dpan_avx2;
+   op_copy_span_funcs[SP_N][SM_N][SC_AN][DP_AN][CPU_AVX2] = _op_copy_can_dpan_avx2;
+   op_copy_span_funcs[SP_N][SM_N][SC_AA][DP_AN][CPU_AVX2] = _op_copy_caa_dpan_avx2;
+}
+
+/*-----*/
+
+/* copy_rel color --> dst */
+
+static void
+_op_copy_rel_c_dp_avx2(DATA32 *s EINA_UNUSED, DATA8 *m EINA_UNUSED, DATA32 c, DATA32 *d, int l) {
+   __m256i cv = _mm256_set1_epi32((int)c);
+   int i = 0;
+
+   for (; i + 8 <= l; i += 8)
+     {
+        __m256i d0 = _mm256_loadu_si256((__m256i *)(d + i));
+        __m256i a0 = _mm256_srli_epi32(d0, 24);
+        __m256i r0 = mul_sym_avx2(a0, cv);
+
+        _mm256_storeu_si256((__m256i *)(d + i), r0);
+     }
+   for (; i < l; i++)
+     d[i] = MUL_SYM(d[i] >> 24, c);
+}
+
+#define _op_copy_rel_cn_dp_avx2 _op_copy_rel_c_dp_avx2
+#define _op_copy_rel_can_dp_avx2 _op_copy_rel_c_dp_avx2
+#define _op_copy_rel_caa_dp_avx2 _op_copy_rel_c_dp_avx2
+
+#define _op_copy_rel_c_dpan_avx2 _op_copy_c_dp_avx2
+#define _op_copy_rel_cn_dpan_avx2 _op_copy_cn_dp_avx2
+#define _op_copy_rel_can_dpan_avx2 _op_copy_can_dp_avx2
+#define _op_copy_rel_caa_dpan_avx2 _op_copy_caa_dp_avx2
+
+static void
+init_copy_rel_color_span_funcs_avx2(void)
+{
+   op_copy_rel_span_funcs[SP_N][SM_N][SC_N][DP][CPU_AVX2] = _op_copy_rel_cn_dp_avx2;
+   op_copy_rel_span_funcs[SP_N][SM_N][SC][DP][CPU_AVX2] = _op_copy_rel_c_dp_avx2;
+   op_copy_rel_span_funcs[SP_N][SM_N][SC_AN][DP][CPU_AVX2] = _op_copy_rel_can_dp_avx2;
+   op_copy_rel_span_funcs[SP_N][SM_N][SC_AA][DP][CPU_AVX2] = _op_copy_rel_caa_dp_avx2;
+
+   op_copy_rel_span_funcs[SP_N][SM_N][SC_N][DP_AN][CPU_AVX2] = _op_copy_rel_cn_dpan_avx2;
+   op_copy_rel_span_funcs[SP_N][SM_N][SC][DP_AN][CPU_AVX2] = _op_copy_rel_c_dpan_avx2;
+   op_copy_rel_span_funcs[SP_N][SM_N][SC_AN][DP_AN][CPU_AVX2] = _op_copy_rel_can_dpan_avx2;
+   op_copy_rel_span_funcs[SP_N][SM_N][SC_AA][DP_AN][CPU_AVX2] = _op_copy_rel_caa_dpan_avx2;
+}
+
+#endif
diff --git a/src/lib/evas/common/evas_op_copy/op_copy_master_avx2.c b/src/lib/evas/common/evas_op_copy/op_copy_master_avx2.c
new file mode 100644
index 0000000000..67d71cd910
--- /dev/null
+++ b/src/lib/evas/common/evas_op_copy/op_copy_master_avx2.c
@@ -0,0 +1,61 @@
+/* AVX2 copy kernels.
+ *
+ * This translation unit is compiled with -mavx2, exactly like
+ * op_blend_master_avx2.c next door in evas_op_blend/ - see that file's
+ * header for why AVX2 code must live in its own TU and be gated at runtime
+ * by CPU_FEATURE_AVX2.
+ *
+ * Unlike blend, the copy op table has NO SSE3 kernels at all (see the
+ * per-file header comments in op_copy_pixel_avx2.c / op_copy_color_avx2.c):
+ * there is nothing to match bit-for-bit except the plain-C reference, which
+ * is also the correctness bar copy already has for every other tier (copy
+ * is exact, not a rounding op). So this master file does not need the
+ * SSE3 statics or NEED_SSE3 dance that op_blend_master_avx2.c carries for
+ * its 4-wide SSE3-body stage - the kernels in this group are written
+ * directly against AVX2 intrinsics with no SSE3 fallback tier.
+ */
+
+#define NEED_AVX2 1
+
+#include "Eina.h"
+#include "Evas.h"
+#include "evas_common_types.h"
+
+EXPORTAPI void evas_common_cpu_end_opt(void);
+
+#include "config.h"
+#include "evas_blend_ops.h"
+
+extern RGBA_Gfx_Func     op_copy_span_funcs[SP_LAST][SM_LAST][SC_LAST][DP_LAST][CPU_LAST];
+extern RGBA_Gfx_Func     op_copy_rel_span_funcs[SP_LAST][SM_LAST][SC_LAST][DP_LAST][CPU_LAST];
+
+# include "op_copy_pixel_avx2.c"
+# include "op_copy_color_avx2.c"
+
+void
+evas_common_op_copy_init_avx2(void)
+{
+#ifdef BUILD_AVX2
+   /* GA_MASK_AVX2 / RB_MASK_AVX2 are declared static in evas_blend_ops.h,
+    * so - same CRITICAL note as op_blend_master_avx2.c - this TU gets its
+    * own zero-initialised copies, separate from op_blend_master_avx2.c's.
+    * mul_sym_avx2, used by the _rel kernels in this group, needs them set
+    * here or every _rel call in this TU multiplies against zero masks.
+    * Values copied verbatim from op_blend_master_avx2.c; keep in sync if
+    * that file's ever change. */
+   GA_MASK_AVX2 = _mm256_set1_epi32(0x00FF00FF);
+   RB_MASK_AVX2 = _mm256_set1_epi32(0xFF00FF00);
+
+   init_copy_pixel_span_funcs_avx2();
+   init_copy_color_span_funcs_avx2();
+#endif
+}
+
+void
+evas_common_op_copy_rel_init_avx2(void)
+{
+#ifdef BUILD_AVX2
+   init_copy_rel_pixel_span_funcs_avx2();
+   init_copy_rel_color_span_funcs_avx2();
+#endif
+}
diff --git a/src/lib/evas/common/evas_op_copy/op_copy_pixel_avx2.c b/src/lib/evas/common/evas_op_copy/op_copy_pixel_avx2.c
new file mode 100644
index 0000000000..69f3f232d7
--- /dev/null
+++ b/src/lib/evas/common/evas_op_copy/op_copy_pixel_avx2.c
@@ -0,0 +1,81 @@
+/* copy pixel --> dst */
+
+/* Ported from the plain-C reference (op_copy_pixel_.c). Copy is bit-exact by
+ * definition (no rounding), so there is no divergence excuse here - this
+ * must match the C reference exactly, and does: the base kernel is a
+ * straight memcpy (identical body to the C fallback, which also calls
+ * memcpy - libc's memcpy already dispatches to an AVX2/AVX-512 ifunc on
+ * capable hardware, so there is nothing for a hand-rolled AVX2 loop to add
+ * here; this slot exists to keep the op-table's CPU_AVX2 tier fully
+ * populated for this group, not because it changes codegen). The _rel
+ * variant (*d = MUL_SYM(*d>>24, *s)) is a real vector opportunity and uses
+ * mul_sym_avx2, already established bit-exact against the plain-C MUL_SYM
+ * macro (see op_blend_pixel_mask_avx2.c). */
+
+#ifdef BUILD_AVX2
+
+static void
+_op_copy_p_dp_avx2(DATA32 *s, DATA8 *m EINA_UNUSED, DATA32 c EINA_UNUSED, DATA32 *d, int l) {
+   memcpy(d, s, l * sizeof(DATA32));
+}
+
+#define _op_copy_pan_dp_avx2 _op_copy_p_dp_avx2
+#define _op_copy_pas_dp_avx2 _op_copy_p_dp_avx2
+
+#define _op_copy_p_dpan_avx2 _op_copy_p_dp_avx2
+#define _op_copy_pan_dpan_avx2 _op_copy_pan_dp_avx2
+#define _op_copy_pas_dpan_avx2 _op_copy_pas_dp_avx2
+
+static void
+init_copy_pixel_span_funcs_avx2(void)
+{
+   op_copy_span_funcs[SP][SM_N][SC_N][DP][CPU_AVX2] = _op_copy_p_dp_avx2;
+   op_copy_span_funcs[SP_AN][SM_N][SC_N][DP][CPU_AVX2] = _op_copy_pan_dp_avx2;
+   op_copy_span_funcs[SP_AS][SM_N][SC_N][DP][CPU_AVX2] = _op_copy_pas_dp_avx2;
+
+   op_copy_span_funcs[SP][SM_N][SC_N][DP_AN][CPU_AVX2] = _op_copy_p_dpan_avx2;
+   op_copy_span_funcs[SP_AN][SM_N][SC_N][DP_AN][CPU_AVX2] = _op_copy_pan_dpan_avx2;
+   op_copy_span_funcs[SP_AS][SM_N][SC_N][DP_AN][CPU_AVX2] = _op_copy_pas_dpan_avx2;
+}
+
+/*-----*/
+
+/* copy_rel pixel --> dst */
+
+static void
+_op_copy_rel_p_dp_avx2(DATA32 *s, DATA8 *m EINA_UNUSED, DATA32 c EINA_UNUSED, DATA32 *d, int l) {
+   int i = 0;
+
+   for (; i + 8 <= l; i += 8)
+     {
+        __m256i s0 = _mm256_loadu_si256((__m256i *)(s + i));
+        __m256i d0 = _mm256_loadu_si256((__m256i *)(d + i));
+        __m256i a0 = _mm256_srli_epi32(d0, 24);
+        __m256i r0 = mul_sym_avx2(a0, s0);
+
+        _mm256_storeu_si256((__m256i *)(d + i), r0);
+     }
+   for (; i < l; i++)
+     d[i] = MUL_SYM(d[i] >> 24, s[i]);
+}
+
+#define _op_copy_rel_pas_dp_avx2 _op_copy_rel_p_dp_avx2
+#define _op_copy_rel_pan_dp_avx2 _op_copy_rel_p_dp_avx2
+
+#define _op_copy_rel_p_dpan_avx2 _op_copy_p_dpan_avx2
+#define _op_copy_rel_pan_dpan_avx2 _op_copy_pan_dpan_avx2
+#define _op_copy_rel_pas_dpan_avx2 _op_copy_pas_dpan_avx2
+
+static void
+init_copy_rel_pixel_span_funcs_avx2(void)
+{
+   op_copy_rel_span_funcs[SP][SM_N][SC_N][DP][CPU_AVX2] = _op_copy_rel_p_dp_avx2;
+   op_copy_rel_span_funcs[SP_AN][SM_N][SC_N][DP][CPU_AVX2] = _op_copy_rel_pan_dp_avx2;
+   op_copy_rel_span_funcs[SP_AS][SM_N][SC_N][DP][CPU_AVX2] = _op_copy_rel_pas_dp_avx2;
+
+   op_copy_rel_span_funcs[SP][SM_N][SC_N][DP_AN][CPU_AVX2] = _op_copy_rel_p_dpan_avx2;
+   op_copy_rel_span_funcs[SP_AN][SM_N][SC_N][DP_AN][CPU_AVX2] = _op_copy_rel_pan_dpan_avx2;
+   op_copy_rel_span_funcs[SP_AS][SM_N][SC_N][DP_AN][CPU_AVX2] = _op_copy_rel_pas_dpan_avx2;
+}
+
+#endif
diff --git a/src/lib/evas/common/evas_op_copy_main_.c b/src/lib/evas/common/evas_op_copy_main_.c
index f1679824ba..8005a19b87 100644
--- a/src/lib/evas/common/evas_op_copy_main_.c
+++ b/src/lib/evas/common/evas_op_copy_main_.c
@@ -1,9 +1,14 @@
 #include "evas_common_private.h"
 #include "evas_blend_private.h"
 
-static RGBA_Gfx_Func     op_copy_span_funcs[SP_LAST][SM_LAST][SC_LAST][DP_LAST][CPU_LAST];
+RGBA_Gfx_Func     op_copy_span_funcs[SP_LAST][SM_LAST][SC_LAST][DP_LAST][CPU_LAST];
 static RGBA_Gfx_Pt_Func  op_copy_pt_funcs[SP_LAST][SM_LAST][SC_LAST][DP_LAST][CPU_LAST];
 
+#ifdef BUILD_AVX2
+void evas_common_op_copy_init_avx2(void);
+void evas_common_op_copy_rel_init_avx2(void);
+#endif
+
 static void op_copy_init(void);
 static void op_copy_shutdown(void);
 
@@ -36,7 +41,7 @@ evas_common_gfx_compositor_copy_get(void)
 }
 
 
-static RGBA_Gfx_Func     op_copy_rel_span_funcs[SP_LAST][SM_LAST][SC_LAST][DP_LAST][CPU_LAST];
+RGBA_Gfx_Func     op_copy_rel_span_funcs[SP_LAST][SM_LAST][SC_LAST][DP_LAST][CPU_LAST];
 static RGBA_Gfx_Pt_Func  op_copy_rel_pt_funcs[SP_LAST][SM_LAST][SC_LAST][DP_LAST][CPU_LAST];
 
 static void op_copy_rel_init(void);
@@ -100,6 +105,12 @@ op_copy_init(void)
 {
    memset(op_copy_span_funcs, 0, sizeof(op_copy_span_funcs));
    memset(op_copy_pt_funcs, 0, sizeof(op_copy_pt_funcs));
+#ifdef BUILD_AVX2
+   if (evas_common_cpu_has_feature(CPU_FEATURE_AVX2))
+     {
+        evas_common_op_copy_init_avx2();
+     }
+#endif
 #ifdef BUILD_MMX
    if (evas_common_cpu_has_feature(CPU_FEATURE_MMX))
      {
@@ -155,6 +166,14 @@ copy_gfx_span_func_cpu(int s, int m, int c, int d)
 {
    RGBA_Gfx_Func  func = NULL;
    int cpu = CPU_N;
+#ifdef BUILD_AVX2
+   if (evas_common_cpu_has_feature(CPU_FEATURE_AVX2))
+    {
+      cpu = CPU_AVX2;
+      func = op_copy_span_funcs[s][m][c][d][cpu];
+      if (func) return func;
+    }
+#endif
 #ifdef BUILD_MMX
    if (evas_common_cpu_has_feature(CPU_FEATURE_MMX))
     {
@@ -364,6 +383,12 @@ op_copy_rel_init(void)
 {
    memset(op_copy_rel_span_funcs, 0, sizeof(op_copy_rel_span_funcs));
    memset(op_copy_rel_pt_funcs, 0, sizeof(op_copy_rel_pt_funcs));
+#ifdef BUILD_AVX2
+   if (evas_common_cpu_has_feature(CPU_FEATURE_AVX2))
+     {
+        evas_common_op_copy_rel_init_avx2();
+     }
+#endif
 #ifdef BUILD_MMX
    init_copy_rel_pixel_span_funcs_mmx();
    init_copy_rel_pixel_color_span_funcs_mmx();
@@ -413,6 +438,14 @@ copy_rel_gfx_span_func_cpu(int s, int m, int c, int d)
 {
    RGBA_Gfx_Func func = NULL;
    int cpu = CPU_N;
+#ifdef BUILD_AVX2
+   if (evas_common_cpu_has_feature(CPU_FEATURE_AVX2))
+    {
+      cpu = CPU_AVX2;
+      func = op_copy_rel_span_funcs[s][m][c][d][cpu];
+      if (func) return func;
+    }
+#endif
 #ifdef BUILD_MMX
    if (evas_common_cpu_has_feature(CPU_FEATURE_MMX))
     {
diff --git a/src/lib/evas/common/meson.build b/src/lib/evas/common/meson.build
index 32807cea49..90bd28f809 100644
--- a/src/lib/evas/common/meson.build
+++ b/src/lib/evas/common/meson.build
@@ -90,7 +90,8 @@ endif
 
 if cpu_avx2 == true
   evas_src_opt_avx2 += files([
-    'evas_op_blend/op_blend_master_avx2.c'
+    'evas_op_blend/op_blend_master_avx2.c',
+    'evas_op_copy/op_copy_master_avx2.c'
   ])
 endif
 
diff --git a/src/tests/evas/meson.build b/src/tests/evas/meson.build
index b6c418024b..63670c7986 100644
--- a/src/tests/evas/meson.build
+++ b/src/tests/evas/meson.build
@@ -83,6 +83,7 @@ if cpu_avx2
     ['evas_test_simd_ops.c',
      '../../lib/evas/common/evas_op_blend/op_blend_master_avx2.c',
      '../../lib/evas/common/evas_op_blend/op_blend_master_sse3.c',
+     '../../lib/evas/common/evas_op_copy/op_copy_master_avx2.c',
      'evas_test_simd_avx2_alpha_stub.c'],
     dependencies: [evas_bin, evas, evas_ext_none_static_deps, eet],
     c_args : ['-DEVAS_BUILD', '-DSIMD_TIER=CPU_AVX2', '-DSIMD_NAME="avx2"'] + avx2_c_args
@@ -110,6 +111,7 @@ if cpu_avx2
     ['evas_test_simd_ops.c',
      '../../lib/evas/common/evas_op_blend/op_blend_master_avx2.c',
      '../../lib/evas/common/evas_op_blend/op_blend_master_sse3.c',
+     '../../lib/evas/common/evas_op_copy/op_copy_master_avx2.c',
      'evas_test_simd_avx2_alpha_stub.c'],
     dependencies: [evas_bin, evas, evas_ext_none_static_deps, eet],
     c_args : ['-DEVAS_BUILD', '-DSIMD_TIER=CPU_AVX2', '-DSIMD_NAME="avx2"',

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

Reply via email to