hasvk: Track DPB slots instead of assuming a single reference.

The encoder ignored VkVideoReferenceSlotInfoKHR entirely: it took
pReferenceSlots[0] as the one reference, wrote its address into frame store 0
and hardcoded the L0 list to that store.  Two DPB slots were all it could
honestly advertise, which is fewer than a GOP of any length needs.

Record each slot the operation names under its own index, since a slot maps
onto the frame store of the same index and MFX_PIPE_BUF_ADDR_STATE holds 16
of those, and build the L0 entries from StdVideoEncodeH264ReferenceListsInfo,
whose RefPicList0 already carries slot indices.  Clients that pass reference
slots without a list keep the old behaviour.

maxDpbSlots therefore goes to 16.  maxActiveReferencePictures stays at 1:
every macroblock is still coded against reference index 0, so a picture may
be kept in the DPB but only the one it names first is predicted from.

dEQP-VK.video.encode.h264.intra_refresh_* goes from 12 Pass and 32 stopped at
the maxDpbSlots >= GOP frame count precondition to 36 Pass, the remaining 8
being per-picture-partition mode, which is not offered.  The family as a whole
is 76 of 120 with no failures.  ffmpeg's h264_vulkan encoder no longer trips
its slot_index assertion and produces a full GOP.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
elwrclandClaude Opus 5 committed 2026-08-21 07:55:40 +03:00
1 parent 0716678e70
commit 9cb5c4385b
5 files changed
+84 -29

No files matched your search

+21 -12
View File
@@ -49,7 +49,8 @@ genX(hasvk_mfc_emit_static_state)(struct anv_cmd_buffer *cmd_buffer,
uint32_t dst_page_offset,
uint64_t dst_buffer_range,
uint32_t width_in_mbs, uint32_t height_in_mbs,
bool is_p, struct anv_address ref_address)
bool is_p,
const struct anv_video_reference_state *refs)
{
struct anv_video_session *vid = cmd_buffer->video.vid;
@@ -149,10 +150,13 @@ genX(hasvk_mfc_emit_static_state)(struct anv_cmd_buffer *cmd_buffer,
* them with the valid, mapped recon address. */
for (unsigned i = 0; i < ARRAY_SIZE(buf.ReferencePictureAddress); i++)
buf.ReferencePictureAddress[i] = recon_address;
/* Frame store 0 is the P-frame's reference (previous reconstructed
* frame); REF_IDX_STATE L0[0] maps ref index 0 to this frame store. */
if (is_p)
buf.ReferencePictureAddress[0] = ref_address;
/* Frame store i holds DPB slot i, so a slot the picture can reference
* goes straight into its own entry; the rest keep the recon address the
* PRM asks for. */
for (unsigned i = 0; i < ANV_VIDEO_MAX_DPB_SLOTS; i++) {
if (refs->slot_valid[i])
buf.ReferencePictureAddress[i] = refs->slot_address[i];
}
}
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_BSP_BUF_BASE_ADDR_STATE), bsp) {
@@ -290,17 +294,22 @@ genX(hasvk_mfc_emit_static_state)(struct anv_cmd_buffer *cmd_buffer,
dmv.POCList[i] = i / 2;
}
/* Reference index lists. Entries are set to the "non-existing" marker 0x80
* (intel_mfc_avc_ref_idx_state). For a P frame, L0[0] points at frame store
* 0: entry = (is_long_term<<6)|((top^bottom^1)<<5)|(frame_store_id<<1)|... ;
* for a short-term progressive frame at store 0 this is 0x20
* (intel_get_ref_idx_state_1). L1 is unused (P has no backward references). */
/* Reference index lists. Unused entries carry the "non-existing" marker
* 0x80 (intel_mfc_avc_ref_idx_state). A used one is
* (is_long_term<<6)|((top^bottom^1)<<5)|(frame_store_id<<1), which for a
* short-term progressive frame comes out as 0x20|(frame_store_id<<1)
* (intel_get_ref_idx_state_1). L1 stays empty: B frames are out of scope,
* so there are no backward references. */
for (unsigned list = 0; list < 2; list++) {
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)
ref_idx.ReferenceListEntry[0] = 0x20;
if (is_p && list == 0) {
unsigned n = MIN2(refs->l0_count,
ARRAY_SIZE(ref_idx.ReferenceListEntry));
for (unsigned i = 0; i < n; i++)
ref_idx.ReferenceListEntry[i] = 0x20 | (refs->l0_slot[i] << 1);
}
}
}
#endif /* GFX_VERx10 == 70 */