radeonsi/vcn: Rework decode ref handling

The issue with using video buffer associated data is that the data will
not be cleared when the buffer is removed from DPB. This will cause
issues if application tries to reuse such buffer (buffer that was
valid buffer in DPB in the past, but is currently not active in DPB)
as a dummy buffer for missing reference.
With Tier2 this works correctly because we allocate the DPB buffers
internally, but with UDT we use the video buffers directly for
references and so we need to make sure to only use the valid buffer
for a given index.

Instead of storing the buffer index as video buffer associated data,
use the render_pic_list array that we already have for keeping track
of active buffers in DPB.

Acked-by: Leo Liu <leo.liu@amd.com>
Reviewed-by: Ruijing Dong <ruijing.dong@amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/33641>
This commit is contained in:
David Rosca 2025-02-06 18:15:19 +01:00 committed by Marge Bot
parent fd3f297eb5
commit 0e68a2655f

View file

@ -46,30 +46,6 @@ static void radeon_dec_destroy_associated_data(void *data)
/* NOOP, since we only use an intptr */
}
static void get_current_pic_index(struct radeon_decoder *dec,
struct pipe_video_buffer *target,
unsigned char *curr_pic_idx)
{
for (int i = 0; i < ARRAY_SIZE(dec->render_pic_list); ++i) {
if (dec->render_pic_list[i] && dec->render_pic_list[i] == target) {
if (target->codec != NULL)
*curr_pic_idx = (uintptr_t)vl_video_buffer_get_associated_data(target, &dec->base);
else {
*curr_pic_idx = i;
vl_video_buffer_set_associated_data(target, &dec->base, (void *)(uintptr_t)i,
&radeon_dec_destroy_associated_data);
}
break;
} else if (!dec->render_pic_list[i]) {
dec->render_pic_list[i] = target;
*curr_pic_idx = i;
vl_video_buffer_set_associated_data(target, &dec->base, (void *)(uintptr_t)i,
&radeon_dec_destroy_associated_data);
break;
}
}
}
static rvcn_dec_message_avc_t get_h264_msg(struct radeon_decoder *dec,
struct pipe_video_buffer *target,
struct pipe_h264_picture_desc *pic)
@ -155,63 +131,47 @@ static rvcn_dec_message_avc_t get_h264_msg(struct radeon_decoder *dec,
goto end;
}
for (i = 0; i < ARRAY_SIZE(dec->render_pic_list); i++) {
for (j = 0; (j < ARRAY_SIZE(pic->ref) && (pic->ref[j] != NULL)); j++) {
if (dec->render_pic_list[i] == pic->ref[j])
break;
if (j == ARRAY_SIZE(pic->ref) - 1)
dec->render_pic_list[i] = NULL;
else if (pic->ref[j + 1] == NULL)
result.decoded_pic_idx = 0xff;
memset(result.ref_frame_list, 0xff, sizeof(result.ref_frame_list));
for (i = 0; i < ARRAY_SIZE(pic->ref) + 1; i++) {
if (dec->render_pic_list[i]) {
bool found = false;
for (j = 0; j < ARRAY_SIZE(pic->ref); j++) {
if (dec->render_pic_list[i] == pic->ref[j]) {
result.ref_frame_list[j] = i;
if (pic->is_long_term[j])
result.ref_frame_list[j] |= 0x80;
if (pic->top_is_reference[j])
result.used_for_reference_flags |= (1 << (2 * j));
if (pic->bottom_is_reference[j])
result.used_for_reference_flags |= (1 << (2 * j + 1));
result.curr_pic_ref_frame_num++;
dec->ref_codec.bufs[num_refs].buf = pic->ref[j];
dec->ref_codec.bufs[num_refs++].index = i;
found = true;
}
}
if (!found)
dec->render_pic_list[i] = NULL;
}
}
for (i = 0; i < ARRAY_SIZE(dec->render_pic_list); ++i) {
if (dec->render_pic_list[i] && dec->render_pic_list[i] == target) {
if (target->codec != NULL){
result.decoded_pic_idx =
(uintptr_t)vl_video_buffer_get_associated_data(target, &dec->base);
} else {
result.decoded_pic_idx = i;
vl_video_buffer_set_associated_data(target, &dec->base, (void *)(uintptr_t)i,
&radeon_dec_destroy_associated_data);
}
break;
if (dec->render_pic_list[i] == target) {
result.decoded_pic_idx = i;
} else if (result.decoded_pic_idx == 0xff && !dec->render_pic_list[i]) {
dec->render_pic_list[i] = target;
result.decoded_pic_idx = i;
}
}
if (i == ARRAY_SIZE(dec->render_pic_list)) {
for (i = 0; i < ARRAY_SIZE(dec->render_pic_list); ++i) {
if (!dec->render_pic_list[i]) {
dec->render_pic_list[i] = target;
result.decoded_pic_idx = i;
vl_video_buffer_set_associated_data(target, &dec->base, (void *)(uintptr_t)i,
&radeon_dec_destroy_associated_data);
break;
}
}
}
for (i = 0; i < ARRAY_SIZE(result.ref_frame_list); i++) {
result.ref_frame_list[i] = pic->ref[i] ?
(uintptr_t)vl_video_buffer_get_associated_data(pic->ref[i], &dec->base) : 0xff;
if (result.ref_frame_list[i] != 0xff) {
if (pic->top_is_reference[i])
result.used_for_reference_flags |= (1 << (2 * i));
if (pic->bottom_is_reference[i])
result.used_for_reference_flags |= (1 << (2 * i + 1));
if (pic->is_long_term[i])
result.ref_frame_list[i] |= 0x80;
result.curr_pic_ref_frame_num++;
dec->ref_codec.bufs[num_refs].buf = pic->ref[i];
dec->ref_codec.bufs[num_refs++].index = result.ref_frame_list[i];
for (i = 0; i < ARRAY_SIZE(pic->ref) && pic->ref[i]; i++) {
if (pic->ref[i] && result.ref_frame_list[i] == 0xff) {
result.non_existing_frame_flags |= 1 << i;
} else {
for (j = 0; j < ARRAY_SIZE(dec->h264_valid_ref_num); j++) {
if ((dec->h264_valid_ref_num[j] != (unsigned)-1)
&& (dec->h264_valid_ref_num[j] == result.frame_num_list[i]))
break;
}
for (k = 0; k < ARRAY_SIZE(dec->h264_valid_poc_num); k++) {
if ((dec->h264_valid_poc_num[k] != (unsigned)-1)
&& ((dec->h264_valid_poc_num[k] == result.field_order_cnt_list[i][0])
@ -278,7 +238,7 @@ static rvcn_dec_message_hevc_t get_h265_msg(struct radeon_decoder *dec,
struct pipe_h265_picture_desc *pic)
{
rvcn_dec_message_hevc_t result;
unsigned i, j, num_refs = 0;
unsigned i, j, num_refs = 0, valid_ref = UINT32_MAX;
memset(&result, 0, sizeof(result));
result.sps_info_flags = 0;
@ -370,42 +330,39 @@ static rvcn_dec_message_hevc_t get_h265_msg(struct radeon_decoder *dec,
result.num_delta_pocs_ref_rps_idx = pic->NumDeltaPocsOfRefRpsIdx;
result.curr_poc = pic->CurrPicOrderCntVal;
for (i = 0; i < ARRAY_SIZE(dec->render_pic_list); i++) {
for (j = 0;
(j < ARRAY_SIZE(pic->ref) && (pic->ref[j] != NULL));
j++) {
if (dec->render_pic_list[i] == pic->ref[j])
break;
if (j == ARRAY_SIZE(pic->ref) - 1)
dec->render_pic_list[i] = NULL;
else if (pic->ref[j + 1] == NULL)
result.curr_idx = 0x7F;
memset(result.ref_pic_list, 0x7F, sizeof(result.ref_pic_list));
for (i = 0; i < ARRAY_SIZE(pic->ref) + 1; i++) {
if (dec->render_pic_list[i]) {
bool found = false;
for (j = 0; j < ARRAY_SIZE(pic->ref); j++) {
if (dec->render_pic_list[i] == pic->ref[j]) {
result.poc_list[j] = pic->PicOrderCntVal[j];
result.ref_pic_list[j] = i;
dec->ref_codec.bufs[num_refs].buf = pic->ref[j];
dec->ref_codec.bufs[num_refs++].index = i;
valid_ref = j;
found = true;
}
}
if (!found)
dec->render_pic_list[i] = NULL;
}
}
for (i = 0; i < ARRAY_SIZE(dec->render_pic_list); i++) {
if (dec->render_pic_list[i] == NULL) {
if (result.curr_idx == 0x7F && !dec->render_pic_list[i]) {
dec->render_pic_list[i] = target;
result.curr_idx = i;
break;
}
}
vl_video_buffer_set_associated_data(target, &dec->base, (void *)(uintptr_t)result.curr_idx,
&radeon_dec_destroy_associated_data);
for (i = 0; i < 16; ++i) {
struct pipe_video_buffer *ref = pic->ref[i];
uintptr_t ref_pic = 0;
result.poc_list[i] = pic->PicOrderCntVal[i];
if (ref) {
ref_pic = (uintptr_t)vl_video_buffer_get_associated_data(ref, &dec->base);
dec->ref_codec.bufs[num_refs].buf = pic->ref[i];
dec->ref_codec.bufs[num_refs++].index = ref_pic;
} else
ref_pic = 0x7F;
result.ref_pic_list[i] = ref_pic;
if (valid_ref != UINT32_MAX) {
for (i = 0; i < ARRAY_SIZE(pic->ref); i++) {
if (pic->ref[i] && result.ref_pic_list[i] == 0x7F) {
result.poc_list[i] = pic->PicOrderCntVal[valid_ref];
result.ref_pic_list[i] = result.ref_pic_list[valid_ref];
num_refs++;
}
}
}
for (i = 0; i < 8; ++i) {
@ -496,7 +453,7 @@ static rvcn_dec_message_vp9_t get_vp9_msg(struct radeon_decoder *dec,
struct pipe_vp9_picture_desc *pic)
{
rvcn_dec_message_vp9_t result;
unsigned i, j, num_refs = 0;
unsigned i, j, num_refs = 0, valid_ref = UINT32_MAX;
memset(&result, 0, sizeof(result));
@ -613,31 +570,35 @@ static rvcn_dec_message_vp9_t get_vp9_msg(struct radeon_decoder *dec,
result.uncompressed_header_size = pic->picture_parameter.frame_header_length_in_bytes;
result.compressed_header_size = pic->picture_parameter.first_partition_size;
assert(dec->base.max_references + 1 <= ARRAY_SIZE(dec->render_pic_list));
result.curr_pic_idx = 0x7F;
memset(result.ref_frame_map, 0x7F, sizeof(result.ref_frame_map));
//clear the dec->render list if it is not used as a reference
for (i = 0; i < ARRAY_SIZE(dec->render_pic_list); i++) {
for (i = 0; i < NUM_VP9_REFS + 1; i++) {
if (dec->render_pic_list[i]) {
for (j=0;j<8;j++) {
if (dec->render_pic_list[i] == pic->ref[j])
break;
bool found = false;
for (j = 0; j < NUM_VP9_REFS; j++) {
if (dec->render_pic_list[i] == pic->ref[j]) {
result.ref_frame_map[j] = i;
dec->ref_codec.bufs[num_refs].buf = pic->ref[j];
dec->ref_codec.bufs[num_refs++].index = i;
valid_ref = j;
found = true;
}
}
if (j == 8)
if (!found)
dec->render_pic_list[i] = NULL;
}
if (result.curr_pic_idx == 0x7F && !dec->render_pic_list[i]) {
dec->render_pic_list[i] = target;
result.curr_pic_idx = i;
}
}
get_current_pic_index(dec, target, &result.curr_pic_idx);
for (i = 0; i < 8; i++) {
uintptr_t ref_frame;
if (pic->ref[i]) {
ref_frame = (uintptr_t)vl_video_buffer_get_associated_data(pic->ref[i], &dec->base);
dec->ref_codec.bufs[num_refs].buf = pic->ref[i];
dec->ref_codec.bufs[num_refs++].index = ref_frame;
} else
ref_frame = 0x7f;
result.ref_frame_map[i] = ref_frame;
for (i = 0; i < NUM_VP9_REFS; i++) {
if (pic->ref[i] && result.ref_frame_map[i] == 0x7F) {
result.ref_frame_map[i] = valid_ref == UINT32_MAX ? 0 : result.ref_frame_map[valid_ref];
num_refs++;
}
}
result.frame_refs[0] = result.ref_frame_map[pic->picture_parameter.pic_fields.last_ref_frame];
@ -742,7 +703,7 @@ static rvcn_dec_message_av1_t get_av1_msg(struct radeon_decoder *dec,
struct pipe_av1_picture_desc *pic)
{
rvcn_dec_message_av1_t result;
unsigned i, j, num_refs = 0;
unsigned i, j, num_refs = 0, valid_ref = UINT32_MAX;
uint16_t tile_count = pic->picture_parameter.tile_cols * pic->picture_parameter.tile_rows;
memset(&result, 0, sizeof(result));
@ -882,9 +843,6 @@ static rvcn_dec_message_av1_t get_av1_msg(struct radeon_decoder *dec,
result.is_annexb = 0;
result.frame_type = pic->picture_parameter.pic_info_fields.frame_type;
result.primary_ref_frame = pic->picture_parameter.primary_ref_frame;
get_current_pic_index(dec, target, &result.curr_pic_idx);
result.sb_size = pic->picture_parameter.seq_info_fields.use_128x128_superblock;
result.interp_filter = pic->picture_parameter.interp_filter;
for (i = 0; i < 2; ++i)
@ -939,16 +897,37 @@ static rvcn_dec_message_av1_t get_av1_msg(struct radeon_decoder *dec,
result.height = MIN2(target->height, result.height);
result.superres_upscaled_width = MIN2(target->width, result.superres_upscaled_width);
for (i = 0; i < NUM_AV1_REFS; ++i) {
uintptr_t ref_frame;
if (pic->ref[i]) {
ref_frame = (uintptr_t)vl_video_buffer_get_associated_data(pic->ref[i], &dec->base);
dec->ref_codec.bufs[num_refs].buf = pic->ref[i];
dec->ref_codec.bufs[num_refs++].index = ref_frame;
} else
ref_frame = 0x7f;
result.ref_frame_map[i] = ref_frame;
result.curr_pic_idx = 0x7F;
memset(result.ref_frame_map, 0x7F, sizeof(result.ref_frame_map));
for (i = 0; i < NUM_AV1_REFS + 1; i++) {
if (dec->render_pic_list[i]) {
bool found = false;
for (j = 0; j < NUM_AV1_REFS; j++) {
if (dec->render_pic_list[i] == pic->ref[j]) {
result.ref_frame_map[j] = i;
dec->ref_codec.bufs[num_refs].buf = pic->ref[j];
dec->ref_codec.bufs[num_refs++].index = i;
valid_ref = j;
found = true;
}
}
if (!found)
dec->render_pic_list[i] = NULL;
}
if (result.curr_pic_idx == 0x7F && !dec->render_pic_list[i]) {
dec->render_pic_list[i] = target;
result.curr_pic_idx = i;
}
}
for (i = 0; i < NUM_AV1_REFS; i++) {
if (pic->ref[i] && result.ref_frame_map[i] == 0x7F) {
result.ref_frame_map[i] = valid_ref == UINT32_MAX ? 0 : result.ref_frame_map[valid_ref];
num_refs++;
}
}
for (i = 0; i < NUM_AV1_REFS_PER_FRAME; ++i)
result.frame_refs[i] = result.ref_frame_map[pic->picture_parameter.ref_frame_idx[i]];
@ -1239,6 +1218,7 @@ static uint32_t get_ref_pic_idx(struct radeon_decoder *dec, struct pipe_video_bu
}
static rvcn_dec_message_mpeg2_vld_t get_mpeg2_msg(struct radeon_decoder *dec,
struct pipe_video_buffer *target,
struct pipe_mpeg12_picture_desc *pic)
{
const int *zscan = pic->alternate_scan ? vl_zscan_alternate : vl_zscan_normal;
@ -1251,6 +1231,9 @@ static rvcn_dec_message_mpeg2_vld_t get_mpeg2_msg(struct radeon_decoder *dec,
result.forward_ref_pic_idx = get_ref_pic_idx(dec, pic->ref[0]);
result.backward_ref_pic_idx = get_ref_pic_idx(dec, pic->ref[1]);
vl_video_buffer_set_associated_data(target, &dec->base, (void *)(uintptr_t)dec->frame_number,
&radeon_dec_destroy_associated_data);
if (pic->intra_matrix) {
result.load_intra_quantiser_matrix = 1;
for (i = 0; i < 64; ++i) {
@ -1285,6 +1268,7 @@ static rvcn_dec_message_mpeg2_vld_t get_mpeg2_msg(struct radeon_decoder *dec,
}
static rvcn_dec_message_mpeg4_asp_vld_t get_mpeg4_msg(struct radeon_decoder *dec,
struct pipe_video_buffer *target,
struct pipe_mpeg4_picture_desc *pic)
{
rvcn_dec_message_mpeg4_asp_vld_t result;
@ -1296,6 +1280,9 @@ static rvcn_dec_message_mpeg4_asp_vld_t get_mpeg4_msg(struct radeon_decoder *dec
result.forward_ref_pic_idx = get_ref_pic_idx(dec, pic->ref[0]);
result.backward_ref_pic_idx = get_ref_pic_idx(dec, pic->ref[1]);
vl_video_buffer_set_associated_data(target, &dec->base, (void *)(uintptr_t)dec->frame_number,
&radeon_dec_destroy_associated_data);
result.variant_type = 0;
result.profile_and_level_indication = 0xF0;
@ -1866,7 +1853,7 @@ static struct pb_buffer_lean *rvcn_dec_message_decode(struct radeon_decoder *dec
}
case PIPE_VIDEO_FORMAT_MPEG12: {
rvcn_dec_message_mpeg2_vld_t mpeg2 =
get_mpeg2_msg(dec, (struct pipe_mpeg12_picture_desc *)picture);
get_mpeg2_msg(dec, target, (struct pipe_mpeg12_picture_desc *)picture);
memcpy(codec, (void *)&mpeg2, sizeof(rvcn_dec_message_mpeg2_vld_t));
index_codec->message_id = RDECODE_MESSAGE_MPEG2_VLD;
@ -1875,7 +1862,7 @@ static struct pb_buffer_lean *rvcn_dec_message_decode(struct radeon_decoder *dec
}
case PIPE_VIDEO_FORMAT_MPEG4: {
rvcn_dec_message_mpeg4_asp_vld_t mpeg4 =
get_mpeg4_msg(dec, (struct pipe_mpeg4_picture_desc *)picture);
get_mpeg4_msg(dec, target, (struct pipe_mpeg4_picture_desc *)picture);
memcpy(codec, (void *)&mpeg4, sizeof(rvcn_dec_message_mpeg4_asp_vld_t));
index_codec->message_id = RDECODE_MESSAGE_MPEG4_ASP_VLD;
@ -2419,7 +2406,6 @@ static void radeon_dec_begin_frame(struct pipe_video_codec *decoder,
struct pipe_picture_desc *picture)
{
struct radeon_decoder *dec = (struct radeon_decoder *)decoder;
uintptr_t frame;
assert(decoder);
@ -2450,12 +2436,6 @@ static void radeon_dec_begin_frame(struct pipe_video_codec *decoder,
break;
}
frame = ++dec->frame_number;
if (dec->stream_type != RDECODE_CODEC_VP9 && dec->stream_type != RDECODE_CODEC_AV1
&& dec->stream_type != RDECODE_CODEC_H264_PERF)
vl_video_buffer_set_associated_data(target, decoder, (void *)frame,
&radeon_dec_destroy_associated_data);
dec->bs_size = 0;
dec->bs_ptr = dec->ws->buffer_map(dec->ws, dec->bs_buffers[dec->cur_buffer].res->buf, &dec->cs,
PIPE_MAP_WRITE | RADEON_MAP_TEMPORARY);
@ -2641,6 +2621,8 @@ static int radeon_dec_end_frame(struct pipe_video_codec *decoder, struct pipe_vi
if (dec->error)
return 1;
dec->frame_number++;
if (!dec->send_cmd(dec, target, picture))
return 1;
@ -2872,9 +2854,6 @@ struct pipe_video_codec *radeon_create_decoder(struct pipe_context *context,
dec->cb_idx = 0;
}
for (i = 0; i < ARRAY_SIZE(dec->render_pic_list); i++)
dec->render_pic_list[i] = NULL;
if ((sctx->vcn_ip_ver >= VCN_3_0_0) && (stream_type == RDECODE_CODEC_H264_PERF)) {
for (i = 0; i < ARRAY_SIZE(dec->h264_valid_ref_num); i++)
dec->h264_valid_ref_num[i] = (unsigned) -1;