mirror of
https://github.com/elwrcl/intel-hard-graphics.git
synced 2026-11-01 03:18:02 +03:00
hasvk: Encode B pictures on gen7.
The encoder refused B pictures outright. Three things were missing. The slice header writer marked every picture as a reference, nal_ref_idc hardcoded to 1. A B picture nothing will reference has to say so, otherwise a decoder keeps it in the DPB and its frame_num accounting drifts until the DPB overflows; the client's is_reference flag decides now, an IDR aside. The same writer emitted no B slice syntax at all, so direct_spatial_mv_pred_flag and the L1 reference list modification flag were absent and the bitstream went out of sync from that bit onwards. Spatial direct mode is chosen, which derives motion from neighbours rather than the co-located picture, so no direct MV buffer has to be read back. Finally the L1 reference list was never built. It comes from RefPicList1 the same way L0 comes from RefPicList0, and feeds MFX_AVC_REF_IDX_STATE list 1 and the L1 count in MFX_AVC_IMG_STATE. Prediction itself is unchanged: a B macroblock is coded as B_L0_16x16, so it predicts from L0 alone and costs about what a P macroblock costs. What a B picture buys here is that it need not enter the DPB, not a cheaper prediction. Bi-prediction would need the macroblock type raised to B_Bi_16x16 and motion vectors for both lists. dEQP-VK.video.encode.h264.i_p_b_13_* goes from NotSupported to 4/4 Pass. NOT FULLY VERIFIED: the run over the whole encode family aborted partway on an unrelated device loss, with two QualityWarnings in intra_refresh that were not there before, so this needs re-running on a healthy GPU before being trusted. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
5 files changed
+51
-22
No files matched your search
@@ -192,9 +192,9 @@ genX(hasvk_mfc_emit_static_state)(struct anv_cmd_buffer *cmd_buffer,
|
||||
avc_img.TrellisQuantizationChromaDisable = false;
|
||||
avc_img.IntraMBConformanceMaxSize = 0xEE8;
|
||||
avc_img.InterMBConformanceMaxSize = 0xBB8;
|
||||
avc_img.NumberofReferenceFrames = is_p ? 1 : 0;
|
||||
avc_img.NumberofActiveReferencePicturesfromL0 = is_p ? 1 : 0;
|
||||
avc_img.NumberofActiveReferencePicturesfromL1 = 0;
|
||||
avc_img.NumberofReferenceFrames = refs->l0_count + refs->l1_count;
|
||||
avc_img.NumberofActiveReferencePicturesfromL0 = refs->l0_count;
|
||||
avc_img.NumberofActiveReferencePicturesfromL1 = refs->l1_count;
|
||||
avc_img.InitialQPValue = 0; /* per-slice QP comes from SLICE_STATE */
|
||||
avc_img.PicOrderPresent = pps->flags.bottom_field_pic_order_in_frame_present_flag;
|
||||
avc_img.DeltaPicOrderAlwaysZero = sps->flags.delta_pic_order_always_zero_flag;
|
||||
@@ -304,11 +304,12 @@ genX(hasvk_mfc_emit_static_state)(struct anv_cmd_buffer *cmd_buffer,
|
||||
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_AVC_REF_IDX_STATE), ref_idx) {
|
||||
ref_idx.ReferencePictureListSelect = list;
|
||||
memset(ref_idx.ReferenceListEntry, 0x80, sizeof(ref_idx.ReferenceListEntry));
|
||||
if (is_p && list == 0) {
|
||||
unsigned n = MIN2(refs->l0_count,
|
||||
ARRAY_SIZE(ref_idx.ReferenceListEntry));
|
||||
const uint8_t *slots = list == 0 ? refs->l0_slot : refs->l1_slot;
|
||||
unsigned count = list == 0 ? refs->l0_count : refs->l1_count;
|
||||
if (is_p) {
|
||||
unsigned n = MIN2(count, ARRAY_SIZE(ref_idx.ReferenceListEntry));
|
||||
for (unsigned i = 0; i < n; i++)
|
||||
ref_idx.ReferenceListEntry[i] = 0x20 | (refs->l0_slot[i] << 1);
|
||||
ref_idx.ReferenceListEntry[i] = 0x20 | (slots[i] << 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -328,16 +329,19 @@ genX(hasvk_mfc_emit_slice)(struct anv_cmd_buffer *cmd_buffer,
|
||||
uint32_t dst_page_offset,
|
||||
const struct anv_video_intra_refresh *intra_refresh)
|
||||
{
|
||||
/* A P slice references the previous reconstructed frame; an I slice does
|
||||
* not. B slices are out of scope. */
|
||||
bool is_p = (slice_hdr->slice_type == STD_VIDEO_H264_SLICE_TYPE_P);
|
||||
/* An I slice predicts from nothing; P and B slices both predict from L0,
|
||||
* and a B slice additionally has L1 available. */
|
||||
bool is_b = (slice_hdr->slice_type == STD_VIDEO_H264_SLICE_TYPE_B);
|
||||
bool is_p = is_b || (slice_hdr->slice_type == STD_VIDEO_H264_SLICE_TYPE_P);
|
||||
|
||||
/* MFX_AVC_SLICE_STATE is not used by decode; fields are matched against the
|
||||
* VA-API reference encoder (gen6_mfc_avc_slice_state). The slice covers the
|
||||
* macroblock range [slice_start_mb, slice_end_mb) in raster order. */
|
||||
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_AVC_SLICE_STATE), slice) {
|
||||
slice.SliceType = is_p ? PSlice : ISlice; /* P=0,B=1,I=2 */
|
||||
slice.SliceType = is_b ? BSlice :
|
||||
is_p ? PSlice : ISlice; /* P=0,B=1,I=2 */
|
||||
slice.NumberofReferencePicturesinInterpredictionList0 = is_p ? 1 : 0;
|
||||
slice.NumberofReferencePicturesinInterpredictionList1 = is_b ? 1 : 0;
|
||||
slice.SliceQuantizationParameter = qp;
|
||||
slice.CABACInitIDC = is_p ? slice_hdr->cabac_init_idc : 0;
|
||||
slice.DisableDeblockingFilterIndicator = 1;
|
||||
|
||||
Reference in new issue
Block a user