[PR] lavfi/scene_sad: add RISC-V V implementations (PR #23959)

mengbinghan via ffmpeg-devel <[email protected]> Thu, 30 Jul 2026 11:03:07 -0000
Newsgroups gmane.comp.video.ffmpeg.devel
Message-ID <178540938784.51.10885155555131184836@29965ddac10e>
PR #23959 opened by mengbinghan
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23959
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23959.patch

# Summary of changes

Add RISC-V Vector implementations of scene SAD for 8-bit and 16-bit pixel formats.

# Testing

- `fate-checkasm-scene_sad` passed on SpacemiT X100
- 100 repeated checkasm runs passed on SpacemiT X100

# Performance

SpacemiT X100:

scene_sad8_c:         91408.8 (1.00x)
scene_sad8_rvv_i32:   12650.4 (7.22x)

scene_sad16_c:        76539.0 (1.00x)
scene_sad16_rvv_i32:  17237.9 (4.44x)



>From 554fbeab27d783a344e708cd7be921e6e7292d0c Mon Sep 17 00:00:00 2001
From: mengbinghan <[email protected]>
Date: Mon, 27 Jul 2026 16:22:10 +0800
Subject: [PATCH 1/2] lavfi/scene_sad: add RISC-V V 8-bit implementation

SpacemiT X100:
scene_sad8_c:         91408.8 (1.00x)
scene_sad8_rvv_i32:   12650.4 (7.22x)

Signed-off-by: mengbinghan <[email protected]>
---
 libavfilter/riscv/Makefile         |  2 +
 libavfilter/riscv/scene_sad_init.c | 37 ++++++++++++++
 libavfilter/riscv/scene_sad_rvv.S  | 80 ++++++++++++++++++++++++++++++
 libavfilter/scene_sad.c            |  4 +-
 libavfilter/scene_sad.h            |  2 +
 5 files changed, 124 insertions(+), 1 deletion(-)
 create mode 100644 libavfilter/riscv/scene_sad_init.c
 create mode 100644 libavfilter/riscv/scene_sad_rvv.S

diff --git a/libavfilter/riscv/Makefile b/libavfilter/riscv/Makefile
index 32b07eec1a..3934b3da8b 100644
--- a/libavfilter/riscv/Makefile
+++ b/libavfilter/riscv/Makefile
@@ -2,5 +2,7 @@ OBJS-$(CONFIG_AFIR_FILTER)                   += riscv/af_afir_init.o
 RVV-OBJS-$(CONFIG_AFIR_FILTER)               += riscv/af_afir_rvv.o
 OBJS-$(CONFIG_BLACKDETECT_FILTER) += riscv/vf_blackdetect_init.o
 RVV-OBJS-$(CONFIG_BLACKDETECT_FILTER) += riscv/vf_blackdetect_rvv.o
+OBJS-$(CONFIG_SCENE_SAD)                     += riscv/scene_sad_init.o
+RVV-OBJS-$(CONFIG_SCENE_SAD)                 += riscv/scene_sad_rvv.o
 
 SHLIBOBJS += riscv/cpu_common.o
diff --git a/libavfilter/riscv/scene_sad_init.c b/libavfilter/riscv/scene_sad_init.c
new file mode 100644
index 0000000000..e7ed3ad707
--- /dev/null
+++ b/libavfilter/riscv/scene_sad_init.c
@@ -0,0 +1,37 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+
+#include "libavutil/cpu.h"
+#include "libavfilter/scene_sad.h"
+
+void ff_scene_sad8_rvv(SCENE_SAD_PARAMS);
+
+ff_scene_sad_fn ff_scene_sad_get_fn_riscv(int depth)
+{
+#if HAVE_RVV
+    int flags = av_get_cpu_flags();
+
+    if (flags & AV_CPU_FLAG_RVV_I32) {
+        if (depth <= 8)
+            return ff_scene_sad8_rvv;
+    }
+#endif
+    return NULL;
+}
diff --git a/libavfilter/riscv/scene_sad_rvv.S b/libavfilter/riscv/scene_sad_rvv.S
new file mode 100644
index 0000000000..95c398a5d5
--- /dev/null
+++ b/libavfilter/riscv/scene_sad_rvv.S
@@ -0,0 +1,80 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/riscv/asm.S"
+
+.macro scene_sad_accumulate value
+#if __riscv_xlen >= 64
+        add         t3, t3, \value
+#else
+        add         t0, t3, \value
+        sltu        \value, t0, t3
+        mv          t3, t0
+        add         t4, t4, \value
+#endif
+.endm
+
+.macro scene_sad_store
+#if __riscv_xlen >= 64
+        sd          t3, (a6)
+#else
+        sw          t3, 0(a6)
+        sw          t4, 4(a6)
+#endif
+.endm
+
+func ff_scene_sad8_rvv, zve32x
+        lpad        0
+        mv          t3, zero
+#if __riscv_xlen < 64
+        mv          t4, zero
+#endif
+        beqz        a4, 3f
+        beqz        a5, 3f
+        sub         t5, a1, a4
+        sub         t6, a3, a4
+1:
+        mv          t1, a4
+2:
+        vsetvli     t0, t1, e8, m4, ta, ma
+        vle8.v      v8, (a0)
+        sub         t1, t1, t0
+        vle8.v      v12, (a2)
+        add         a0, a0, t0
+        vwsubu.vv   v16, v8, v12
+        add         a2, a2, t0
+        vwsubu.vv   v24, v12, v8
+        vsetvli     zero, zero, e16, m8, ta, ma
+        vmax.vv     v16, v16, v24
+        vsetivli    zero, 1, e32, m1, ta, ma
+        vmv.s.x     v0, zero
+        vsetvli     zero, t0, e16, m8, ta, ma
+        vwredsum.vs v0, v16, v0
+        vsetivli    zero, 1, e32, m1, ta, ma
+        vmv.x.s     t2, v0
+        scene_sad_accumulate t2
+        bnez        t1, 2b
+
+        add         a0, a0, t5
+        add         a2, a2, t6
+        addi        a5, a5, -1
+        bnez        a5, 1b
+3:
+        scene_sad_store
+        ret
+endfunc
diff --git a/libavfilter/scene_sad.c b/libavfilter/scene_sad.c
index 56177ced76..a8978d8161 100644
--- a/libavfilter/scene_sad.c
+++ b/libavfilter/scene_sad.c
@@ -59,7 +59,9 @@ void ff_scene_sad_c(SCENE_SAD_PARAMS)
 ff_scene_sad_fn ff_scene_sad_get_fn(int depth)
 {
     ff_scene_sad_fn sad = NULL;
-#if ARCH_X86 && HAVE_X86ASM
+#if ARCH_RISCV
+    sad = ff_scene_sad_get_fn_riscv(depth);
+#elif ARCH_X86 && HAVE_X86ASM
     sad = ff_scene_sad_get_fn_x86(depth);
 #endif
     if (!sad) {
diff --git a/libavfilter/scene_sad.h b/libavfilter/scene_sad.h
index 173a051f2b..b76135dcff 100644
--- a/libavfilter/scene_sad.h
+++ b/libavfilter/scene_sad.h
@@ -37,6 +37,8 @@ void ff_scene_sad_c(SCENE_SAD_PARAMS);
 
 void ff_scene_sad16_c(SCENE_SAD_PARAMS);
 
+ff_scene_sad_fn ff_scene_sad_get_fn_riscv(int depth);
+
 ff_scene_sad_fn ff_scene_sad_get_fn_x86(int depth);
 
 ff_scene_sad_fn ff_scene_sad_get_fn(int depth);
-- 
2.52.0


>From 387ab597c461282bc98670abdefa36807905f657 Mon Sep 17 00:00:00 2001
From: mengbinghan <[email protected]>
Date: Mon, 27 Jul 2026 16:22:36 +0800
Subject: [PATCH 2/2] lavfi/scene_sad: add RISC-V V 16-bit implementation

SpacemiT X100:
scene_sad16_c:        76539.0 (1.00x)
scene_sad16_rvv_i32:  17237.9 (4.44x)

Signed-off-by: mengbinghan <[email protected]>
---
 libavfilter/riscv/scene_sad_init.c |  3 +++
 libavfilter/riscv/scene_sad_rvv.S  | 42 ++++++++++++++++++++++++++++++
 2 files changed, 45 insertions(+)

diff --git a/libavfilter/riscv/scene_sad_init.c b/libavfilter/riscv/scene_sad_init.c
index e7ed3ad707..b45d1e2941 100644
--- a/libavfilter/riscv/scene_sad_init.c
+++ b/libavfilter/riscv/scene_sad_init.c
@@ -22,6 +22,7 @@
 #include "libavfilter/scene_sad.h"
 
 void ff_scene_sad8_rvv(SCENE_SAD_PARAMS);
+void ff_scene_sad16_rvv(SCENE_SAD_PARAMS);
 
 ff_scene_sad_fn ff_scene_sad_get_fn_riscv(int depth)
 {
@@ -31,6 +32,8 @@ ff_scene_sad_fn ff_scene_sad_get_fn_riscv(int depth)
     if (flags & AV_CPU_FLAG_RVV_I32) {
         if (depth <= 8)
             return ff_scene_sad8_rvv;
+        if (depth <= 16)
+            return ff_scene_sad16_rvv;
     }
 #endif
     return NULL;
diff --git a/libavfilter/riscv/scene_sad_rvv.S b/libavfilter/riscv/scene_sad_rvv.S
index 95c398a5d5..349bcb744e 100644
--- a/libavfilter/riscv/scene_sad_rvv.S
+++ b/libavfilter/riscv/scene_sad_rvv.S
@@ -78,3 +78,45 @@ func ff_scene_sad8_rvv, zve32x
         scene_sad_store
         ret
 endfunc
+
+func ff_scene_sad16_rvv, zve32x
+        lpad          0
+        mv            t3, zero
+#if __riscv_xlen < 64
+        mv            t4, zero
+#endif
+        beqz          a4, 3f
+        beqz          a5, 3f
+        slli          t0, a4, 1
+        sub           t5, a1, t0
+        sub           t6, a3, t0
+1:
+        mv            t1, a4
+2:
+        vsetvli       t0, t1, e16, m4, ta, ma
+        vle16.v       v8, (a0)
+        sub           t1, t1, t0
+        vle16.v       v12, (a2)
+        slli          t2, t0, 1
+        add           a0, a0, t2
+        vmaxu.vv      v16, v8, v12
+        add           a2, a2, t2
+        vminu.vv      v20, v8, v12
+        vsub.vv       v16, v16, v20
+        vsetivli      zero, 1, e32, m1, ta, ma
+        vmv.s.x       v0, zero
+        vsetvli       zero, t0, e16, m4, ta, ma
+        vwredsumu.vs  v0, v16, v0
+        vsetivli      zero, 1, e32, m1, ta, ma
+        vmv.x.s       t2, v0
+        scene_sad_accumulate t2
+        bnez          t1, 2b
+
+        add           a0, a0, t5
+        add           a2, a2, t6
+        addi          a5, a5, -1
+        bnez          a5, 1b
+3:
+        scene_sad_store
+        ret
+endfunc
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]