[PATCH v2 0/2] VVC: AVX2 planar intra prediction
Gudikandula Samith via ffmpeg-devel <[email protected]>
| Newsgroups | gmane.comp.video.ffmpeg.devel |
|---|---|
| Message-ID | <[email protected]> |
This series adds an AVX2 implementation of the VVC planar intra
prediction kernel, which currently has no SIMD implementation on any
architecture. Only 8-bit is implemented here; the 10 and 12-bit paths
still use the C reference and can be added in a follow-up.
Patch 1 adds a checkasm test so the second patch can be verified. The
test iterates 8, 10 and 12 bit, so it will also cover the higher depths
once SIMD for them is added.
Patch 2 adds the 8-bit kernel and wires up x86 dispatch.
Tested on AMD Ryzen 7 5825U:
- checkasm passes: the 8-bit AVX2 kernel matches the C reference
- fate-vvc passes, unchanged from before the series
- framemd5 output is identical with and without -cpuflags 0
Changes since v1:
- checkasm: use separate top0/top1 and left0/left1 buffers so call_ref
cannot modify call_new's input
- checkasm: use MIN_TU_SIZE/MAX_TB_SIZE instead of magic 4/64
- checkasm: use checkasm_check_pixel instead of memcmp/fail
- asm: compute per-row A and B iteratively (faster; suggested by Frank)
- asm: index left[h] via r8 and drop r13, saving a mov
- asm: whitespace/alignment cleanup
Thanks to Frank for the v1 review.
Gudikandula Samith (2):
tests/checkasm: add vvc_intra test for pred_planar
lavc/vvc: add AVX2 planar intra prediction
libavcodec/x86/vvc/Makefile | 1 +
libavcodec/x86/vvc/dsp_init.c | 13 ++
libavcodec/x86/vvc/intra.asm | 233 ++++++++++++++++++++++++++++++++++
tests/checkasm/Makefile | 2 +-
tests/checkasm/checkasm.c | 7 +-
tests/checkasm/checkasm.h | 1 +
tests/checkasm/vvc_intra.c | 89 +++++++++++++
7 files changed, 342 insertions(+), 4 deletions(-)
create mode 100644 libavcodec/x86/vvc/intra.asm
create mode 100644 tests/checkasm/vvc_intra.c
Range-diff against v1:
1: e222150dee ! 1: 4f0463cfac tests/checkasm: add vvc_intra test for pred_planar
@@ tests/checkasm/vvc_intra.c (new)
+
+static void check_pred_planar(VVCDSPContext *c, const int bit_depth)
+{
-+ LOCAL_ALIGNED_32(uint8_t, dst0, [BUF_SIZE]);
-+ LOCAL_ALIGNED_32(uint8_t, dst1, [BUF_SIZE]);
-+ LOCAL_ALIGNED_32(uint8_t, top, [(MAX_TB_SIZE + 1) * 2]);
-+ LOCAL_ALIGNED_32(uint8_t, left, [(MAX_TB_SIZE + 1) * 2]);
++ LOCAL_ALIGNED_32(uint8_t, dst0, [BUF_SIZE]);
++ LOCAL_ALIGNED_32(uint8_t, dst1, [BUF_SIZE]);
++ LOCAL_ALIGNED_32(uint8_t, top0, [(MAX_TB_SIZE + 1) * 2]);
++ LOCAL_ALIGNED_32(uint8_t, top1, [(MAX_TB_SIZE + 1) * 2]);
++ LOCAL_ALIGNED_32(uint8_t, left0, [(MAX_TB_SIZE + 1) * 2]);
++ LOCAL_ALIGNED_32(uint8_t, left1, [(MAX_TB_SIZE + 1) * 2]);
+
+ const ptrdiff_t stride = BUF_STRIDE / SIZEOF_PIXEL;
+
+ declare_func(void, uint8_t *src, const uint8_t *top, const uint8_t *left,
+ int w, int h, ptrdiff_t stride);
+
-+ randomize_buffers(top, top, (MAX_TB_SIZE + 1) * 2);
-+ randomize_buffers(left, left, (MAX_TB_SIZE + 1) * 2);
++ randomize_buffers(top0, top1, (MAX_TB_SIZE + 1) * 2);
++ randomize_buffers(left0, left1, (MAX_TB_SIZE + 1) * 2);
+
-+ for (int h = 4; h <= 64; h <<= 1) {
-+ for (int w = 4; w <= 64; w <<= 1) {
++ for (int h = MIN_TU_SIZE; h <= MAX_TB_SIZE; h <<= 1) {
++ for (int w = MIN_TU_SIZE; w <= MAX_TB_SIZE; w <<= 1) {
+ if (check_func(c->intra.pred_planar,
+ "vvc_pred_planar_%dx%d_%d", w, h, bit_depth)) {
+ memset(dst0, 0, BUF_SIZE);
+ memset(dst1, 0, BUF_SIZE);
-+ call_ref(dst0, top, left, w, h, stride);
-+ call_new(dst1, top, left, w, h, stride);
-+ if (memcmp(dst0, dst1, BUF_SIZE))
-+ fail();
-+ bench_new(dst1, top, left, w, h, stride);
++ call_ref(dst0, top0, left0, w, h, stride);
++ call_new(dst1, top1, left1, w, h, stride);
++ checkasm_check_pixel(dst0, BUF_STRIDE, dst1, BUF_STRIDE,
++ w, h, "dst");
++ bench_new(dst1, top1, left1, w, h, stride);
+ }
+ }
+ }
2: 43cd7006f7 ! 2: 606ae7a384 lavc/vvc: add AVX2 planar intra prediction
@@ Commit message
Implements pred_planar for x86-64 AVX2 at 8 bit.
Benchmarks on AMD Ryzen 7 5825U:
- vvc_pred_planar_4x4_8_c: 52.8
- vvc_pred_planar_4x4_8_avx2: 24.1 (2.16x)
- vvc_pred_planar_8x8_8_c: 208.3
- vvc_pred_planar_8x8_8_avx2: 48.3 (4.31x)
- vvc_pred_planar_16x16_8_c: 778.0
- vvc_pred_planar_16x16_8_avx2: 160.4 (4.80x)
- vvc_pred_planar_32x32_8_c: 2356.0
- vvc_pred_planar_32x32_8_avx2: 580.3 (4.02x)
- vvc_pred_planar_64x64_8_c: 7414.0
- vvc_pred_planar_64x64_8_avx2: 2185.9 (3.27x)
+ vvc_pred_planar_4x4_8_c: 86.1
+ vvc_pred_planar_4x4_8_avx2: 30.4 (2.81x)
+ vvc_pred_planar_8x8_8_c: 307.0
+ vvc_pred_planar_8x8_8_avx2: 56.3 (5.39x)
+ vvc_pred_planar_16x16_8_c: 1116.0
+ vvc_pred_planar_16x16_8_avx2: 199.3 (5.46x)
+ vvc_pred_planar_32x32_8_c: 3328.7
+ vvc_pred_planar_32x32_8_avx2: 736.6 (4.01x)
+ vvc_pred_planar_64x64_8_c: 11554.9
+ vvc_pred_planar_64x64_8_avx2: 2761.3 (4.02x)
Signed-off-by: Gudikandula Samith <[email protected]>
@@ libavcodec/x86/vvc/intra.asm (new)
+ 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, \
+ 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64
+
++pw_1: times 16 dw 1
++
+
+SECTION .text
+
@@ libavcodec/x86/vvc/intra.asm (new)
+
+INIT_YMM avx2
+
-+; Per-row scalars, broadcast into vector registers:
-+; m8 = A = (h-1-y)
-+; m9 = B = (y+1) * left[h]
++; Per-row scalar that still has to be loaded every row:
+; m10 = C = left[y]
++; A = (h-1-y) in m8 and B = (y+1)*left[h] in m9 are advanced iteratively
++; at the end of each row loop (m8 -= 1, m9 += left[h]).
+%macro ROW_CONSTANTS 0
-+ mov eax, r12d
-+ sub eax, r11d ;A=(h-1-y)
-+ movd xm8, eax
-+ vpbroadcastw m8, xm8
-+ lea eax, [r11d+1]
-+ imul eax, r10d ;B=(y+1)*left[h]
-+ movd xm9, eax
-+ vpbroadcastw m9, xm9
-+ movzx eax, byte [leftq+r11]
-+ movd xm10, eax
++ movzx eax, byte [leftq + r11]
++ movd xm10, eax
+ vpbroadcastw m10, xm10
+%endmacro
++
+; Block-constant setup shared by every width.
+; %1 = logw (immediate), %2 = top[w] byte offset (=width)
+%macro PLANAR_SETUP 2
-+ mov r13d, hd
-+ bsr r6d, hd
-+ lea r7d, [r6d +%1 +1]
-+ mov r8d, hd
-+ shl r8d, %1 ;size=w*h= h<<logw
-+ movzx r9d, byte [topq + %2]
-+ movzx r10d, byte [leftq +r13]
-+ movd xm3, r9d
-+ vpbroadcastw m3, xm3
-+ movd xm4, r8d
-+ vpbroadcastd m4, xm4
-+ movd xm5, r6d
-+ movd xm6, r7d
-+ mov r12d, hd
-+ dec r12d
-+ xor r11d, r11d
++ bsr r6d, hd
++ lea r7d, [r6d + %1 + 1]
++ mov r8d, hd ; r8 = h (mov zero-extends into r8)
++ movzx r10d, byte [leftq + r8] ; left[h] (index by h before shifting)
++ shl r8d, %1 ; size = w*h = h<<logw
++ movzx r9d, byte [topq + %2]
++ movd xm3, r9d
++ vpbroadcastw m3, xm3
++ movd xm4, r8d
++ vpbroadcastd m4, xm4
++ movd xm5, r6d
++ movd xm6, r7d
++ movd xm7, r10d
++ vpbroadcastw m7, xm7 ; step for m9 = left[h]
++ mova m9, m7 ; B(y=0) = 1*left[h]
++ mov r12d, hd
++ dec r12d
++ movd xm8, r12d
++ vpbroadcastw m8, xm8 ; A(y=0) = h-1
++ xor r11d, r11d
+%endmacro
+
+; Process 16 columns starting at column offset %3.
+; %1 = (w-1-x) table, %2 = (x+1) table, %3 = column offset, %4 = logw immediate
+%macro PLANAR16 4
-+ pmovzxbw m0, [topq+%3]
++ pmovzxbw m0, [topq + %3]
+ movu m1, [%1 + %3*2]
+ movu m2, [%2 + %3*2]
+ vpmullw m11, m0, m8
@@ libavcodec/x86/vvc/intra.asm (new)
+; void ff_vvc_pred_planar_8_avx2(uint8_t *src, const uint8_t *top,
+; const uint8_t *left, int w, int h,
+; ptrdiff_t stride);
-+cglobal vvc_pred_planar_8, 6, 14, 16, src, top, left, w, h, stride
++cglobal vvc_pred_planar_8, 6, 13, 16, src, top, left, w, h, stride
+ cmp wd, 16
+ je .w16
+ cmp wd, 8
@@ libavcodec/x86/vvc/intra.asm (new)
+.w4_row:
+ ROW_CONSTANTS
+ PLANAR_NARROW pw_wm1x_w4, pw_xp1_w4, 2, movd
++ vpsubw m8, m8, [pw_1] ; A -= 1
++ vpaddw m9, m9, m7 ; B += left[h]
+ add srcq, strideq
+ inc r11d
+ cmp r11d, hd
@@ libavcodec/x86/vvc/intra.asm (new)
+.w8_row:
+ ROW_CONSTANTS
+ PLANAR_NARROW pw_wm1x_w8, pw_xp1_w8, 3, movq
++ vpsubw m8, m8, [pw_1] ; A -= 1
++ vpaddw m9, m9, m7 ; B += left[h]
+ add srcq, strideq
+ inc r11d
+ cmp r11d, hd
@@ libavcodec/x86/vvc/intra.asm (new)
+.w16_row:
+ ROW_CONSTANTS
+ PLANAR16 pw_wm1x_w16, pw_xp1_w16, 0, 4
++ vpsubw m8, m8, [pw_1] ; A -= 1
++ vpaddw m9, m9, m7 ; B += left[h]
+ add srcq, strideq
+ inc r11d
+ cmp r11d, hd
@@ libavcodec/x86/vvc/intra.asm (new)
+ ROW_CONSTANTS
+ PLANAR16 pw_wm1x_w32, pw_xp1_w32, 0, 5
+ PLANAR16 pw_wm1x_w32, pw_xp1_w32, 16, 5
++ vpsubw m8, m8, [pw_1] ; A -= 1
++ vpaddw m9, m9, m7 ; B += left[h]
+ add srcq, strideq
+ inc r11d
+ cmp r11d, hd
@@ libavcodec/x86/vvc/intra.asm (new)
+ PLANAR16 pw_wm1x_w64, pw_xp1_w64, 16, 6
+ PLANAR16 pw_wm1x_w64, pw_xp1_w64, 32, 6
+ PLANAR16 pw_wm1x_w64, pw_xp1_w64, 48, 6
++ vpsubw m8, m8, [pw_1] ; A -= 1
++ vpaddw m9, m9, m7 ; B += left[h]
+ add srcq, strideq
+ inc r11d
+ cmp r11d, hd
--
2.53.0
_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]