Commit 693195b518 for ffmpeg

commit 693195b518e6ec5c4314f6852c7859b9d356e8d5
Author: Mark Thompson <sw@jkqxz.net>
Date:   Sun Oct 25 14:21:24 2026 +0000

    lavc/apv: Precompute transquant constants once per tile component

    Adds a new dsp function to compute a constants buffer in the form most
    suitable to the specific implementation.  This gets called once per
    tile component to prepare the constants buffer, and then the transquant
    functions get a pointer to that buffer to use.

    CPU: Intel(R) Xeon(R) Gold 6252 CPU @ 2.10GHz
    Before:
      decode_transquant_10_c:       333.2
      decode_transquant_10_avx2:     65.5 ( 5.09x)
    After:
      decode_transquant_10_c:       330.9
      decode_transquant_10_avx2:     57.3 ( 5.78x)

    No significant difference on ARM Cortex-A53/A73.

diff --git a/libavcodec/aarch64/apv_dsp_constants.h b/libavcodec/aarch64/apv_dsp_constants.h
new file mode 100644
index 0000000000..3772be438f
--- /dev/null
+++ b/libavcodec/aarch64/apv_dsp_constants.h
@@ -0,0 +1,31 @@
+/*
+ * 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
+ */
+
+#ifndef AVCODEC_AARCH64_APV_DSP_CONSTANTS_H
+#define AVCODEC_AARCH64_APV_DSP_CONSTANTS_H
+
+/* Offsets in the constants buffer used by transquant_neon. */
+#define APV_CONST_QMATRIX        0
+#define APV_CONST_QP_SHIFT       128
+#define APV_CONST_DEQUANT_ROUND  132
+#define APV_CONST_NEG_BD_SHIFT   136
+#define APV_CONST_OUTPUT_ROUND   140
+#define APV_CONST_OUTPUT_MAX     144
+#define APV_CONST_OUTPUT_SHIFT   148
+
+#endif /* AVCODEC_AARCH64_APV_DSP_CONSTANTS_H */
diff --git a/libavcodec/aarch64/apv_dsp_init_aarch64.c b/libavcodec/aarch64/apv_dsp_init_aarch64.c
index 22d4598f91..ced0290196 100644
--- a/libavcodec/aarch64/apv_dsp_init_aarch64.c
+++ b/libavcodec/aarch64/apv_dsp_init_aarch64.c
@@ -16,23 +16,66 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */

+#include <assert.h>
+#include <stddef.h>
+#include <string.h>
+
 #include "config.h"
 #include "libavutil/attributes.h"
 #include "libavutil/cpu.h"
 #include "libavutil/aarch64/cpu.h"
 #include "libavcodec/apv_dsp.h"
+#include "apv_dsp_constants.h"
+
+typedef struct APVConstantsNEON {
+    int16_t qmatrix[64];
+    int32_t qp_shift;
+    int32_t dequant_round;
+    int32_t neg_bd_shift;
+    int32_t output_round;
+    int32_t output_max;
+    int32_t output_shift;
+} APVConstantsNEON;
+
+static_assert(sizeof(APVConstantsNEON) <= APV_DSP_CONSTANTS_SIZE,
+              "APV NEON constants buffer too small");
+static_assert(offsetof(APVConstantsNEON, qmatrix)       == APV_CONST_QMATRIX       &&
+              offsetof(APVConstantsNEON, qp_shift)      == APV_CONST_QP_SHIFT      &&
+              offsetof(APVConstantsNEON, dequant_round) == APV_CONST_DEQUANT_ROUND &&
+              offsetof(APVConstantsNEON, neg_bd_shift)  == APV_CONST_NEG_BD_SHIFT  &&
+              offsetof(APVConstantsNEON, output_round)  == APV_CONST_OUTPUT_ROUND  &&
+              offsetof(APVConstantsNEON, output_max)    == APV_CONST_OUTPUT_MAX    &&
+              offsetof(APVConstantsNEON, output_shift)  == APV_CONST_OUTPUT_SHIFT,
+              "APV NEON constants layout does not match assembly");
+
+static void apv_prepare_constants_neon(void *constants,
+                                       const int16_t *qmatrix,
+                                       int bit_depth,
+                                       int qp_shift)
+{
+    APVConstantsNEON *c = constants;
+    int bd_shift = bit_depth - 2;
+
+    memcpy(c->qmatrix, qmatrix, sizeof(c->qmatrix));
+    c->qp_shift      = qp_shift;
+    c->dequant_round = 1 << (bd_shift - 1);
+    c->neg_bd_shift  = -bd_shift;
+    c->output_round  = (1 << (19 - bit_depth)) + (1 << 19);
+    c->output_max    = (1 << bit_depth) - 1;
+    c->output_shift  = bit_depth - 20;
+}

 void ff_apv_decode_transquant_neon(void *output,
                                    ptrdiff_t pitch,
                                    const int16_t *input,
-                                   const int16_t *qmatrix,
-                                   int bit_depth,
-                                   int qp_shift);
+                                   const void *constants);

 av_cold void ff_apv_dsp_init_aarch64(APVDSPContext *dsp)
 {
     int cpu_flags = av_get_cpu_flags();

-    if (have_neon(cpu_flags))
+    if (have_neon(cpu_flags)) {
+        dsp->prepare_constants = apv_prepare_constants_neon;
         dsp->decode_transquant = ff_apv_decode_transquant_neon;
+    }
 }
diff --git a/libavcodec/aarch64/apv_dsp_neon.S b/libavcodec/aarch64/apv_dsp_neon.S
index 3110a4f6fb..13037ce61a 100644
--- a/libavcodec/aarch64/apv_dsp_neon.S
+++ b/libavcodec/aarch64/apv_dsp_neon.S
@@ -18,6 +18,7 @@

 #include "libavutil/aarch64/asm.S"
 #include "neon.S"
+#include "apv_dsp_constants.h"

 /* Dequant one row in 16x8
  * Input levels at x2 + off, qmatrix at x3 + off (function args)
@@ -278,21 +279,15 @@
 .endm

 /*
- * void ff_apv_decode_transquant_neon(void *output,           = x0
- *                                    ptrdiff_t pitch,        = x1
- *                                    const int16_t *input,   = x2
- *                                    const int16_t *qmatrix, = x3
- *                                    int bit_depth,          = w4
- *                                    int qp_shift)           = w5
+ * void ff_apv_decode_transquant_neon(void *output,            = x0
+ *                                    ptrdiff_t pitch,         = x1
+ *                                    const int16_t *input,    = x2
+ *                                    const void *constants)   = x3
  */
 function ff_apv_decode_transquant_neon, export=1
-        sub             w7, w4, #2       /* w7 = bd_shift */
-        movz            w14, #1
-
         /* Dequant */
-        sub             w15, w7, #1
-        lsl             w10, w14, w15
-        neg             w15, w7
+        ldp             w5, w10, [x3, #APV_CONST_QP_SHIFT]
+        ldr             w15, [x3, #APV_CONST_NEG_BD_SHIFT]
         dup             v24.4s, w5       /* v24 = qp_shift */
         dup             v25.4s, w10      /* v25 = 1 << (bd_shift - 1) */
         dup             v26.4s, w15      /* v26 = -bd_shift */
@@ -306,11 +301,7 @@ function ff_apv_decode_transquant_neon, export=1
         dequant         v7, #112

         /* Row scaling constants */
-        movz            w16, #8, lsl #16 /* w16 = 1 << 19 */
-        lsr             w10, w16, w4
-        orr             w10, w10, w16    /* w10 = (1 << (19 - bit_depth)) + (1 << 19) */
-        lsl             w15, w14, w4
-        sub             w13, w15, #1     /* w13 = (1 << bit_depth) - 1 */
+        ldp             w10, w13, [x3, #APV_CONST_OUTPUT_ROUND]

         /* Column butterfly and normalise */
         butterfly_mul
@@ -323,7 +314,7 @@ function ff_apv_decode_transquant_neon, export=1
         butterfly_mul
         dup             v5.4s, w10       /* v5 = output offset */
         dup             v6.4s, w13       /* v6 = output max clip (min clip is zero) */
-        sub             w17, w4, #20     /* w17 = bit_depth - 20 (row_combine shift) */
+        ldr             w17, [x3, #APV_CONST_OUTPUT_SHIFT]
         row_combine

         /* Transpose back */
diff --git a/libavcodec/apv_decode.c b/libavcodec/apv_decode.c
index a6ca9ba8fb..7fd93ad0c2 100644
--- a/libavcodec/apv_decode.c
+++ b/libavcodec/apv_decode.c
@@ -188,9 +188,7 @@ static int apv_decode_block(AVCodecContext *avctx,
                             ptrdiff_t pitch,
                             GetBitContext *gbc,
                             APVEntropyState *entropy_state,
-                            int bit_depth,
-                            int qp_shift,
-                            const uint16_t *qmatrix)
+                            const void *constants)
 {
     APVDecodeContext *apv = avctx->priv_data;
     int err;
@@ -202,9 +200,7 @@ static int apv_decode_block(AVCodecContext *avctx,
     if (err < 0)
         return err;

-    apv->dsp.decode_transquant(output, pitch,
-                               coeff, qmatrix,
-                               bit_depth, qp_shift);
+    apv->dsp.decode_transquant(output, pitch, coeff, constants);

     return 0;
 }
@@ -242,9 +238,7 @@ static int apv_decode_tile_component(AVCodecContext *avctx, void *data,
     int blk_mb_width  = 2 >> sub_w_shift;
     int blk_mb_height = 2 >> sub_h_shift;

-    int bit_depth;
-    int qp_shift;
-    LOCAL_ALIGNED_32(uint16_t, qmatrix_scaled, [64]);
+    LOCAL_ALIGNED_32(uint8_t, constants, [APV_DSP_CONSTANTS_SIZE]);

     GetBitContext gbc;

@@ -265,20 +259,24 @@ static int apv_decode_tile_component(AVCodecContext *avctx, void *data,

     // Combine the bitstream quantisation matrix with the qp scaling
     // in advance.  (Including qp_shift as well would overflow 16 bits.)
-    // Fix the row ordering at the same time.
+    // Fix the row ordering at the same time.  Everything else which
+    // is constant for the tile component is derived from this by the
+    // DSP code.
     {
         static const uint8_t apv_level_scale[6] = { 40, 45, 51, 57, 64, 71 };
         int qp = tile->tile_header.tile_qp[comp_index];
         int level_scale = apv_level_scale[qp % 6];
-
-        bit_depth = input->frame_header.frame_info.bit_depth_minus8 + 8;
-        qp_shift  = qp / 6;
+        int bit_depth = input->frame_header.frame_info.bit_depth_minus8 + 8;
+        int16_t qmatrix_scaled[64];

         for (int y = 0; y < 8; y++) {
             for (int x = 0; x < 8; x++)
                 qmatrix_scaled[y * 8 + x] = level_scale *
                     input->frame_header.quantization_matrix.q_matrix[comp_index][x][y];
         }
+
+        apv->dsp.prepare_constants(constants, qmatrix_scaled,
+                                   bit_depth, qp / 6);
     }

     for (int mb_y = 0; mb_y < tile_mb_height; mb_y++) {
@@ -299,9 +297,7 @@ static int apv_decode_tile_component(AVCodecContext *avctx, void *data,
                     err = apv_decode_block(avctx,
                                            block_start, frame_pitch,
                                            &gbc, &entropy_state,
-                                           bit_depth,
-                                           qp_shift,
-                                           qmatrix_scaled);
+                                           constants);
                     if (err < 0) {
                         // Error in block decode means entropy desync,
                         // so this is not recoverable.
diff --git a/libavcodec/apv_dsp.c b/libavcodec/apv_dsp.c
index 7351e34b6a..eabab865c0 100644
--- a/libavcodec/apv_dsp.c
+++ b/libavcodec/apv_dsp.c
@@ -16,7 +16,9 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */

+#include <assert.h>
 #include <stdint.h>
+#include <string.h>

 #include "config.h"
 #include "libavutil/attributes.h"
@@ -38,15 +40,35 @@ static const int8_t apv_trans_matrix[8][8] = {
     {  18, -50,  75, -89,  89, -75,  50, -18 },
 };

+typedef struct APVConstantsC {
+    int16_t qmatrix[8][8];
+    int     bit_depth;
+    int     qp_shift;
+} APVConstantsC;
+
+static_assert(sizeof(APVConstantsC) <= APV_DSP_CONSTANTS_SIZE,
+              "APV DSP constants buffer too small");
+
+void ff_apv_prepare_constants_c(void *constants,
+                                const int16_t *qmatrix,
+                                int bit_depth,
+                                int qp_shift)
+{
+    APVConstantsC *c = constants;
+
+    memcpy(c->qmatrix, qmatrix, sizeof(c->qmatrix));
+    c->bit_depth = bit_depth;
+    c->qp_shift  = qp_shift;
+}
+
 static void apv_decode_transquant_c(void *output,
                                     ptrdiff_t pitch,
                                     const int16_t *input_flat,
-                                    const int16_t *qmatrix_flat,
-                                    int bit_depth,
-                                    int qp_shift)
+                                    const void *constants)
 {
-    const int16_t (*input)[8]   = (const int16_t(*)[8])input_flat;
-    const int16_t (*qmatrix)[8] = (const int16_t(*)[8])qmatrix_flat;
+    const APVConstantsC *c = constants;
+    const int16_t (*input)[8] = (const int16_t(*)[8])input_flat;
+    int bit_depth = c->bit_depth;

     int16_t scaled_coeff[8][8];
     int32_t recon_sample[8][8];
@@ -59,8 +81,10 @@ static void apv_decode_transquant_c(void *output,

         for (int y = 0; y < 8; y++) {
             for (int x = 0; x < 8; x++) {
-                int coeff = ((int)(input[y][x] * qmatrix[y][x] * (1U << qp_shift) +
-                             (1 << (bd_shift - 1)))) >> bd_shift;
+                int coeff = ((int)(input[y][x] *
+                                   c->qmatrix[y][x] *
+                                   (1U << c->qp_shift) +
+                                   (1 << (bd_shift - 1)))) >> bd_shift;

                 scaled_coeff[y][x] =
                     av_clip(coeff, APV_MIN_TRANS_COEFF,
@@ -119,6 +143,7 @@ static void apv_decode_transquant_c(void *output,

 av_cold void ff_apv_dsp_init(APVDSPContext *dsp)
 {
+    dsp->prepare_constants = ff_apv_prepare_constants_c;
     dsp->decode_transquant = apv_decode_transquant_c;

 #if ARCH_X86_64 && HAVE_X86ASM
diff --git a/libavcodec/apv_dsp.h b/libavcodec/apv_dsp.h
index c0836f3e2c..15ee195d0b 100644
--- a/libavcodec/apv_dsp.h
+++ b/libavcodec/apv_dsp.h
@@ -23,17 +23,42 @@
 #include <stdint.h>


+/**
+ * Size of the buffer holding constants for decode_transquant(), which
+ * must be large enough for the layout used by any implementation.
+ * The buffer must be 32-byte aligned.
+ */
+#define APV_DSP_CONSTANTS_SIZE 512
+
 typedef struct APVDSPContext {
-    void (*decode_transquant)(void *output,
-                              ptrdiff_t pitch,
-                              const int16_t *input,
+    /**
+     * Fill the constants buffer used by decode_transquant() for all
+     * blocks with the same quantisation parameters.  The layout of the
+     * buffer is private to the implementation.
+     */
+    void (*prepare_constants)(void *constants,
                               const int16_t *qmatrix,
                               int bit_depth,
                               int qp_shift);
+
+    /**
+     * Run transquant for a single block.  The constants argument must
+     * have been prepared by a call to prepare_constants() matching the
+     * implementation being used.
+     */
+    void (*decode_transquant)(void *output,
+                              ptrdiff_t pitch,
+                              const int16_t *input,
+                              const void *constants);
 } APVDSPContext;

 void ff_apv_dsp_init(APVDSPContext *dsp);

+void ff_apv_prepare_constants_c(void *constants,
+                                const int16_t *qmatrix,
+                                int bit_depth,
+                                int qp_shift);
+
 void ff_apv_dsp_init_x86_64(APVDSPContext *dsp);

 void ff_apv_dsp_init_aarch64(APVDSPContext *dsp);
diff --git a/libavcodec/x86/apv_dsp.asm b/libavcodec/x86/apv_dsp.asm
index 78098b38de..7eb5ba17d8 100644
--- a/libavcodec/x86/apv_dsp.asm
+++ b/libavcodec/x86/apv_dsp.asm
@@ -37,18 +37,23 @@ tmatrix_odd_2b: times 8 dw -89,  75
 tmatrix_odd_3a: times 8 dw  18,  75
 tmatrix_odd_3b: times 8 dw -50, -89

-cextern pd_1
 cextern pd_64
-vec_1_19: times 8 dd 1 << 19
+
+; Offsets in the constants buffer.
+; This must match APVConstantsAVX2 in apv_dsp_init.c.
+%define CONST_QMATRIX        0
+%define CONST_DEQUANT_ROUND  256
+%define CONST_OUTPUT_ROUND   288
+%define CONST_QP_SHIFT       320
+%define CONST_BD_SHIFT       324
+%define CONST_OUTPUT_SHIFT   328

 SECTION .text

 ; void ff_apv_decode_transquant_avx2(void *output,
 ;                                    ptrdiff_t pitch,
 ;                                    const int16_t *input,
-;                                    const int16_t *qmatrix,
-;                                    int bit_depth,
-;                                    int qp_shift);
+;                                    const void *constants);

 INIT_YMM avx2

@@ -95,37 +100,23 @@ INIT_YMM avx2
     vpsubd    m15, m0,  m4
 %endmacro

-cglobal apv_decode_transquant, 5, 7, 16, 32, output, pitch, input, qmatrix, bit_depth, qp_shift, tmp
-
-    ; Building rounding constant to for the final normalisation and
-    ; store it on the stack for use later.
-
-    mova      m0,  [pd_1]
-    mov       tmpd, 19
-    sub       tmpd, bit_depthd
-    movd      xm1, tmpd
-    vpslld    m0,  m0,  xm1
-    vpaddd    m0,  m0,  [vec_1_19]
-    mova      [rsp], m0
+cglobal apv_decode_transquant, 4, 5, 16, output, pitch, input, constants, tmp

-    ; Load input and dequantise
+    ; Load input and dequantise.  The qmatrix values are zero-extended
+    ; in the constants, so vpmaddwd with the sign-extended input gives
+    ; the product directly.

-    mova      m10, [pd_1]
-    lea       tmpd, [bit_depthd - 2]
-    movd      xm8, qp_shiftm
-    movd      xm9, tmpd
-    vpslld    m10, m10, xm9
-    vpsrld    m10, m10, 1
+    mova      m10, [constantsq + CONST_DEQUANT_ROUND]
+    movd      xm8, [constantsq + CONST_QP_SHIFT]
+    movd      xm9, [constantsq + CONST_BD_SHIFT]

     ; m8  = scalar qp_shift
     ; m9  = scalar bd_shift
     ; m10 = vector 1 << (bd_shift - 1)
-    ; m11 = qmatrix load

 %macro LOAD_AND_DEQUANT 2 ; (register, constant offset)
-    vpmovsxwd m%1, [inputq   + %2]
-    vpmovsxwd m11, [qmatrixq + %2]
-    vpmaddwd  m%1, m%1, m11
+    vpmovsxwd m%1, [inputq + %2]
+    vpmaddwd  m%1, m%1, [constantsq + CONST_QMATRIX + 2 * %2]
     vpslld    m%1, m%1, xm8
     vpaddd    m%1, m%1, m10
     vpsrad    m%1, m%1, xm9
@@ -193,16 +184,14 @@ cglobal apv_decode_transquant, 5, 7, 16, 32, output, pitch, input, qmatrix, bit_

     ; Transform rows.

-    TRANSFORM_PASS [rsp]
+    TRANSFORM_PASS [constantsq + CONST_OUTPUT_ROUND]

     ; Renormalise, clip and store output.  The rounding constant was
     ; already added by the transform pass, and here we split the shift
     ; on either side of the pack (20 - bit_depth -> 4 and 16 - bit_depth)
     ; so that the saturation precisely captures the clip we want.

-    mov       tmpd, 16
-    sub       tmpd, bit_depthd
-    movd      xm0, tmpd
+    movd      xm0, [constantsq + CONST_OUTPUT_SHIFT]

     vpsrad    m8,  m8,  4
     vpsrad    m9,  m9,  4
diff --git a/libavcodec/x86/apv_dsp_init.c b/libavcodec/x86/apv_dsp_init.c
index f87292a528..3d0f08f774 100644
--- a/libavcodec/x86/apv_dsp_init.c
+++ b/libavcodec/x86/apv_dsp_init.c
@@ -16,6 +16,9 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */

+#include <assert.h>
+#include <stddef.h>
+
 #include "config.h"
 #include "libavutil/attributes.h"
 #include "libavutil/cpu.h"
@@ -24,18 +27,54 @@

 #if ARCH_X86_64

+typedef struct APVConstantsAVX2 {
+    int32_t qmatrix[64];
+    int32_t dequant_round[8];
+    int32_t output_round[8];
+    int32_t qp_shift;
+    int32_t bd_shift;
+    int32_t output_shift;
+} APVConstantsAVX2;
+
+static_assert(sizeof(APVConstantsAVX2) <= APV_DSP_CONSTANTS_SIZE,
+              "APV AVX2 constants buffer too small");
+static_assert(offsetof(APVConstantsAVX2, dequant_round) == 256 &&
+              offsetof(APVConstantsAVX2, output_round)  == 288 &&
+              offsetof(APVConstantsAVX2, qp_shift)      == 320 &&
+              offsetof(APVConstantsAVX2, bd_shift)      == 324 &&
+              offsetof(APVConstantsAVX2, output_shift)  == 328,
+              "APV AVX2 constants layout does not match assembly");
+
+static void apv_prepare_constants_avx2(void *constants,
+                                       const int16_t *qmatrix,
+                                       int bit_depth,
+                                       int qp_shift)
+{
+    APVConstantsAVX2 *c = constants;
+    int bd_shift = bit_depth - 2;
+
+    for (int i = 0; i < 64; i++)
+        c->qmatrix[i] = (uint16_t)qmatrix[i];
+    for (int i = 0; i < 8; i++) {
+        c->dequant_round[i] = 1 << (bd_shift - 1);
+        c->output_round[i]  = (1 << (19 - bit_depth)) + (1 << 19);
+    }
+    c->qp_shift     = qp_shift;
+    c->bd_shift     = bd_shift;
+    c->output_shift = 16 - bit_depth;
+}
+
 void ff_apv_decode_transquant_avx2(void *output,
                                    ptrdiff_t pitch,
                                    const int16_t *input,
-                                   const int16_t *qmatrix,
-                                   int bit_depth,
-                                   int qp_shift);
+                                   const void *constants);

 av_cold void ff_apv_dsp_init_x86_64(APVDSPContext *dsp)
 {
     int cpu_flags = av_get_cpu_flags();

     if (EXTERNAL_AVX2_FAST(cpu_flags)) {
+        dsp->prepare_constants = apv_prepare_constants_avx2;
         dsp->decode_transquant = ff_apv_decode_transquant_avx2;
     }
 }
diff --git a/tests/checkasm/apv_dsp.c b/tests/checkasm/apv_dsp.c
index efd79fa9d4..265ffaec99 100644
--- a/tests/checkasm/apv_dsp.c
+++ b/tests/checkasm/apv_dsp.c
@@ -105,20 +105,20 @@ static void generate_block(int16_t *input, const int16_t *qmatrix,
     }
 }

-static void check_decode_transquant(int bit_depth)
+static void check_decode_transquant(const APVDSPContext *dsp, int bit_depth)
 {
     LOCAL_ALIGNED_32( int16_t, input,      [64]);
     LOCAL_ALIGNED_32( int16_t, qmatrix,    [64]);
     LOCAL_ALIGNED_32(uint16_t, new_output, [64]);
     LOCAL_ALIGNED_32(uint16_t, ref_output, [64]);
+    LOCAL_ALIGNED_32( uint8_t, new_constants, [APV_DSP_CONSTANTS_SIZE]);
+    LOCAL_ALIGNED_32( uint8_t, ref_constants, [APV_DSP_CONSTANTS_SIZE]);

     declare_func(void,
                  void *output,
                  ptrdiff_t pitch,
                  const int16_t *input,
-                 const int16_t *qmatrix,
-                 int bit_depth,
-                 int qp_shift);
+                 const void *constants);

     for (int n = 0; n < 256; n++) {
         // Fully random QP for each block.
@@ -141,8 +141,11 @@ static void check_decode_transquant(int bit_depth)

         generate_block(input, qmatrix, bit_depth, qp_shift, 0);

-        call_ref(ref_output, 16, input, qmatrix, bit_depth, qp_shift);
-        call_new(new_output, 16, input, qmatrix, bit_depth, qp_shift);
+        ff_apv_prepare_constants_c(ref_constants, qmatrix, bit_depth, qp_shift);
+        dsp->prepare_constants    (new_constants, qmatrix, bit_depth, qp_shift);
+
+        call_ref(ref_output, 16, input, ref_constants);
+        call_new(new_output, 16, input, new_constants);

         if (memcmp(new_output, ref_output, 64 * sizeof(*ref_output))) {
             fail();
@@ -158,12 +161,15 @@ static void check_decode_transquant(int bit_depth)
             qmatrix[i] = apv_level_scale[0] * 16;
         generate_block(input, qmatrix, bit_depth, qp_shift, 1);

-        call_ref(ref_output, 16, input, qmatrix, bit_depth, qp_shift);
-        call_new(new_output, 16, input, qmatrix, bit_depth, qp_shift);
+        ff_apv_prepare_constants_c(ref_constants, qmatrix, bit_depth, qp_shift);
+        dsp->prepare_constants    (new_constants, qmatrix, bit_depth, qp_shift);
+
+        call_ref(ref_output, 16, input, ref_constants);
+        call_new(new_output, 16, input, new_constants);
         if (memcmp(new_output, ref_output, 64 * sizeof(*ref_output)))
             fail();

-        bench_new(new_output, 16, input, qmatrix, bit_depth, qp_shift);
+        bench_new(new_output, 16, input, new_constants);
     }
 }

@@ -176,7 +182,7 @@ void checkasm_check_apv_dsp(void)
     for (int bit_depth = 10; bit_depth <= 16; bit_depth += 2) {
         if (check_func(dsp.decode_transquant,
                        "decode_transquant_%d", bit_depth))
-            check_decode_transquant(bit_depth);
+            check_decode_transquant(&dsp, bit_depth);
     }

     report("decode_transquant");