This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg.
commit 2997641b638e3bed0b5a008ea5ee2d171d7f082b Author: Lynne <[email protected]> AuthorDate: Sat Nov 7 15:13:30 2026 +0800 Commit: Lynne <[email protected]> CommitDate: Sat Nov 7 22:20:30 2026 +0800 avcodec/vulkan_apv: use the APV integer inverse transform The iDCT shader used the generic floating-point DCT, which cannot reproduce the integer transform APV specifies, nor its rounding and clipping. Its output differed from the software decoder and OpenAPV, by one in the 4:0:0 FATE sample and by up to 26 at 12 bits. Implement the specified dequantization, transform and rounding in 32-bit integers. The transform is split into its even and odd halves like the HEVC one, which takes 20 multiplies per 8-point pass rather than 64. Scaled coefficients beyond the 16-bit range are clamped before the shift, so the dequantization needs no 64-bit arithmetic either. On an RX 6900 XT, the transform takes 15us for a 1080p 4:2:2 frame, against 12us for the floating-point one. Fixes: #25431 --- libavcodec/vulkan/apv_idct.comp.glsl | 69 +++++++++++++++++++++++++++--------- libavcodec/vulkan_apv.c | 14 +------- 2 files changed, 53 insertions(+), 30 deletions(-) diff --git a/libavcodec/vulkan/apv_idct.comp.glsl b/libavcodec/vulkan/apv_idct.comp.glsl index c66df279af..99e32c5c62 100644 --- a/libavcodec/vulkan/apv_idct.comp.glsl +++ b/libavcodec/vulkan/apv_idct.comp.glsl @@ -23,7 +23,6 @@ #extension GL_GOOGLE_include_directive : require #include "common.glsl" -#include "dct.glsl" #define APV_MAX_NUM_COMP 4 #define APV_MAX_TILE_COLS 20 @@ -54,6 +53,45 @@ layout (push_constant, scalar) uniform pushConstants { const int apv_level_scale[6] = { 40, 45, 51, 57, 64, 71 }; +/* Rows are padded to avoid bank conflicts */ +shared int blocks[APV_BLOCKS_PER_WG][8*(8 + 1)]; + +/* Inverse of the APV integer transform, split into its even and odd halves + * like the HEVC one, then rounded and shifted down. */ +void apv_idct8(uint block, uint offset, uint stride, int shift) +{ + int s0 = blocks[block][0*stride + offset]; + int s1 = blocks[block][1*stride + offset]; + int s2 = blocks[block][2*stride + offset]; + int s3 = blocks[block][3*stride + offset]; + int s4 = blocks[block][4*stride + offset]; + int s5 = blocks[block][5*stride + offset]; + int s6 = blocks[block][6*stride + offset]; + int s7 = blocks[block][7*stride + offset]; + + /* Even half, with the rounding offset */ + int ee0 = 64*(s0 + s4) + (1 << (shift - 1)); + int ee1 = 64*(s0 - s4) + (1 << (shift - 1)); + int eo0 = 84*s2 + 35*s6; + int eo1 = 35*s2 - 84*s6; + int e0 = ee0 + eo0, e1 = ee1 + eo1, e2 = ee1 - eo1, e3 = ee0 - eo0; + + /* Odd half */ + int o0 = 89*s1 + 75*s3 + 50*s5 + 18*s7; + int o1 = 75*s1 - 18*s3 - 89*s5 - 50*s7; + int o2 = 50*s1 - 89*s3 + 18*s5 + 75*s7; + int o3 = 18*s1 - 50*s3 + 75*s5 - 89*s7; + + blocks[block][0*stride + offset] = (e0 + o0) >> shift; + blocks[block][1*stride + offset] = (e1 + o1) >> shift; + blocks[block][2*stride + offset] = (e2 + o2) >> shift; + blocks[block][3*stride + offset] = (e3 + o3) >> shift; + blocks[block][4*stride + offset] = (e3 - o3) >> shift; + blocks[block][5*stride + offset] = (e2 - o2) >> shift; + blocks[block][6*stride + offset] = (e1 - o1) >> shift; + blocks[block][7*stride + offset] = (e0 - o0) >> shift; +} + void main(void) { const uvec3 wgid = gl_WorkGroupID; @@ -89,8 +127,10 @@ void main(void) const int half_range = 1 << (bit_depth - 1); const int max_val = (1 << bit_depth) - 1; - const float fact = float(half_range); - const float norm = 1.0f / (1024.0f * fact); /* DCT normalization const */ + const int dequant_shift = bit_depth - 2; + /* Scaled coefficients beyond this saturate either way, clamping to it + * first keeps the dequantization within 32 bits */ + const int dequant_max = 1 << (16 + dequant_shift - qp_shift); /* This component's plane inside the flat coefficient buffer */ const int cw0 = int(tile_col[tile_count.x]); @@ -106,35 +146,30 @@ void main(void) /* blocks fully outside the coded area have nothing stored for them */ const bool oob = pos.x >= cstride || pos.y >= cheight; - /* Loop-invariant column scale */ - const float col_scale = norm * idct_scale[col]; - [[unroll]] for (uint y = 0u; y < 8u; y++) { /* load */ int coeff = oob ? 0 : int(coeffs_in[cbase + uint((pos.y + int(y)) * cstride + pos.x + int(col))]); - /* dequant + norm */ - int qs = level_scale * int(q_matrix[comp][col][y]) * (1 << qp_shift); - float v = float(coeff * qs) * col_scale; - /* scale */ - blocks[block][y * 9u + col] = v * idct_scale[y]; + /* dequant */ + int qs = level_scale * int(q_matrix[comp][col][y]); + int v = clamp(coeff * qs, -dequant_max, dequant_max) << qp_shift; + v = (v + (1 << (dequant_shift - 1))) >> dequant_shift; + blocks[block][y * 9u + col] = clamp(v, -32768, 32767); } barrier(); - idct8(block, col, 9); + apv_idct8(block, col, 9, 7); barrier(); - blocks[block][col * 9u] += 1.0f; - - idct8(block, col * 9u, 1); + apv_idct8(block, col * 9u, 1, 20 - bit_depth); barrier(); [[unroll]] for (int y = 0; y < 8; y++) { - float v = round(blocks[block][y * 9u + col] * fact); + int v = blocks[block][y * 9u + col] + half_range; imageStore(dst[comp], pos + ivec2(col, y), - uvec4(uint(clamp(int(v), 0, max_val)))); + uvec4(uint(clamp(v, 0, max_val)))); } } diff --git a/libavcodec/vulkan_apv.c b/libavcodec/vulkan_apv.c index e9c469e6ad..19fa3eb776 100644 --- a/libavcodec/vulkan_apv.c +++ b/libavcodec/vulkan_apv.c @@ -406,19 +406,7 @@ static int init_idct_shader(AVCodecContext *avctx, FFVulkanContext *s, AVHWFramesContext *dec_frames_ctx; dec_frames_ctx = (AVHWFramesContext *)avctx->hw_frames_ctx->data; - SPEC_LIST_CREATE(sl, 1 + 8, (1 + 8)*sizeof(uint32_t)) - SPEC_LIST_ADD(sl, 16, 32, 8); /* nb_blocks per workgroup */ - - const double idct_8_scales[8] = { - cos(4.0*M_PI/16.0) / 2.0, cos(1.0*M_PI/16.0) / 2.0, - cos(2.0*M_PI/16.0) / 2.0, cos(3.0*M_PI/16.0) / 2.0, - cos(4.0*M_PI/16.0) / 2.0, cos(5.0*M_PI/16.0) / 2.0, - cos(6.0*M_PI/16.0) / 2.0, cos(7.0*M_PI/16.0) / 2.0, - }; - for (int i = 0; i < 8; i++) - SPEC_LIST_ADD(sl, 18 + i, 32, av_float2int(idct_8_scales[i])); - - ff_vk_shader_load(shd, VK_SHADER_STAGE_COMPUTE_BIT, sl, + ff_vk_shader_load(shd, VK_SHADER_STAGE_COMPUTE_BIT, NULL, (uint32_t []) { 32, 2, 1 }, 0); ff_vk_shader_add_push_const(shd, 0, sizeof(DecodePushData), VK_SHADER_STAGE_COMPUTE_BIT); -- To stop receiving notification emails like this one, please contact [email protected]. _______________________________________________ ffmpeg-cvslog mailing list -- [email protected] To unsubscribe send an email to [email protected]
