hasvk: Add VK_KHR_video_encode_intra_refresh for gen7.

Each macroblock's intra/inter decision is already made on its own when the
PAK objects are emitted, so refreshing a region is a matter of coding the
macroblocks it covers the way an I slice codes them.  Regions divide the
picture evenly along rows, columns or raster order, which leaves the block,
block-row and block-column modes supported and gives empty regions for free
when the cycle is longer than the split axis.

Two things needed care.  PAK keeps the I slice numbering for MbType5Bits
inside a P slice, where H.264 itself offsets intra mb_types by 5; handing it
the offset value hangs the MFC.  And under constrained intra prediction a
neighbour only counts as available if it is in the refresh region too,
because prediction may not cross into an inter macroblock.

Nothing constrains motion away from not-yet-refreshed regions, which is
sound only because there is no motion estimation: every vector is zero, so a
macroblock reads its own co-located block and never leaves its region.
Motion estimation will have to honour VkVideoReferenceIntraRefreshInfoKHR's
dirty region count.

Per-picture-partition mode is not offered.  It wants the refreshed slice
coded as an I slice, header included, rather than as intra macroblocks
inside a P slice.

dEQP-VK.video.encode.h264.intra_refresh_* goes from 44 NotSupported to 12
Pass; all three modes pass in the variants that can run.  The other 32 stop
at a CTS precondition, maxDpbSlots >= GOP frame count, which the driver's
two slots do not meet.  Raising that needs real DPB slot tracking and is
what gates B frames and ffmpeg's encoder too.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
elwrclandClaude Opus 5 committed 2026-08-21 07:35:13 +03:00
1 parent 113661753e
commit 0716678e70
6 files changed
+126 -12

No files matched your search

+44
View File
@@ -3852,6 +3852,50 @@ struct anv_video_session_params {
struct vk_video_session_parameters vk;
};
/* One picture's slice of an intra refresh cycle: the macroblocks of region
* `index` out of `cycle_duration` are coded intra, the rest inter.
*/
struct anv_video_intra_refresh {
VkVideoEncodeIntraRefreshModeFlagBitsKHR mode;
uint32_t cycle_duration;
uint32_t index;
};
/* Whether the macroblock at (x, y) falls in the region being refreshed. The
* regions divide the picture evenly, so a cycle longer than the number of
* blocks along the split axis simply leaves some of them empty.
*/
static inline bool
anv_video_mb_is_intra_refreshed(const struct anv_video_intra_refresh *ir,
uint32_t x, uint32_t y,
uint32_t width_in_mbs, uint32_t height_in_mbs)
{
if (ir == NULL || ir->cycle_duration == 0)
return false;
uint32_t pos, total;
switch (ir->mode) {
case VK_VIDEO_ENCODE_INTRA_REFRESH_MODE_BLOCK_ROW_BASED_BIT_KHR:
pos = y;
total = height_in_mbs;
break;
case VK_VIDEO_ENCODE_INTRA_REFRESH_MODE_BLOCK_COLUMN_BASED_BIT_KHR:
pos = x;
total = width_in_mbs;
break;
case VK_VIDEO_ENCODE_INTRA_REFRESH_MODE_BLOCK_BASED_BIT_KHR:
pos = y * width_in_mbs + x;
total = width_in_mbs * height_in_mbs;
break;
default:
return false;
}
uint32_t first = (uint64_t)ir->index * total / ir->cycle_duration;
uint32_t last = (uint64_t)(ir->index + 1) * total / ir->cycle_duration;
return pos >= first && pos < last;
}
static inline uint32_t khr_perf_query_preamble_offset(const struct anv_query_pool *pool,
uint32_t pass)
{