mirror of
https://github.com/elwrcl/intel-hard-graphics.git
synced 2026-10-31 10:58:03 +03:00
hasvk: Partition the picture across slices instead of reading first_mb_in_slice.
Splitting a picture into slices is the implementation's job. The encoder instead read first_mb_in_slice out of each entry's slice header and used the next entry's value as the end of the range, but clients leave that field at zero on every entry and expect the driver to derive it and write it into the emitted header. A multi-slice picture therefore came out as one slice covering nothing, and vkCmdEncodeVideoKHR failed. Divide the macroblock rows evenly across the NALU slice entries, which keeps every slice row-aligned as required while VK_VIDEO_ENCODE_H264_CAPABILITY_ROW_UNALIGNED_SLICE_BIT_KHR is not advertised, and reject more slices than there are rows. This also removes the workaround for ffmpeg passing first_mb_in_slice=1, which was not a client bug at all: the field was never an input. Per-picture-partition intra refresh needs nothing beyond this, since the refreshed partition is just a slice the client marks as an I slice and slices are already coded by their own slice_type, so offer that mode too. dEQP-VK.video.encode.h264 goes from 76 to 84 of 120. The remaining 36 are honest: quantization maps have no hardware path on gen7, where the only per-macroblock QP is the one the CPU writes into the PAK object and the only indirect data a PAK object fetches is motion vectors; B frames and rate control are not implemented. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
2 files changed
+17
-28
No files matched your search
@@ -237,11 +237,12 @@ anv_GetPhysicalDeviceVideoCapabilitiesKHR(VkPhysicalDevice physicalDevice,
|
||||
if (ir_caps) {
|
||||
/* Each macroblock's intra/inter decision is made on its own when the
|
||||
* PAK objects are emitted, so the picture can be split along any of
|
||||
* these axes. 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.
|
||||
* these axes. Per-picture-partition mode needs nothing extra: the
|
||||
* refreshed partition is a slice the client marks as an I slice, and
|
||||
* slices are already coded according to their own slice_type.
|
||||
*/
|
||||
ir_caps->intraRefreshModes =
|
||||
VK_VIDEO_ENCODE_INTRA_REFRESH_MODE_PER_PICTURE_PARTITION_BIT_KHR |
|
||||
VK_VIDEO_ENCODE_INTRA_REFRESH_MODE_BLOCK_BASED_BIT_KHR |
|
||||
VK_VIDEO_ENCODE_INTRA_REFRESH_MODE_BLOCK_ROW_BASED_BIT_KHR |
|
||||
VK_VIDEO_ENCODE_INTRA_REFRESH_MODE_BLOCK_COLUMN_BASED_BIT_KHR;
|
||||
|
||||
@@ -1178,11 +1178,17 @@ anv_h264_encode_video(struct anv_cmd_buffer *cmd_buffer,
|
||||
intra_refresh_ptr = &intra_refresh;
|
||||
}
|
||||
|
||||
/* Emit each slice. Slice s covers the macroblock range
|
||||
* [first_mb_in_slice[s], first_mb_in_slice[s+1]); the last slice runs to the
|
||||
* end of the frame. Each NALU slice entry carries its own QP and slice
|
||||
* header. The MFC appends slices in the destination buffer automatically. */
|
||||
/* Emit each slice. Partitioning the picture is the implementation's job:
|
||||
* first_mb_in_slice is something the driver derives and writes into the
|
||||
* emitted header, not something the client hands down -- clients leave it
|
||||
* at zero for every entry. Divide the macroblock rows evenly across the
|
||||
* NALU slice entries, which also keeps every slice row-aligned, as
|
||||
* VK_VIDEO_ENCODE_H264_CAPABILITY_ROW_UNALIGNED_SLICE_BIT_KHR is not
|
||||
* advertised. Each entry carries its own QP and slice header; the MFC
|
||||
* appends slices in the destination buffer automatically. */
|
||||
uint32_t slice_count = h264_pic_info->naluSliceEntryCount;
|
||||
if (slice_count > height_in_mbs)
|
||||
return VK_ERROR_INITIALIZATION_FAILED;
|
||||
for (uint32_t s = 0; s < slice_count; s++) {
|
||||
const VkVideoEncodeH264NaluSliceInfoKHR *entry =
|
||||
&h264_pic_info->pNaluSliceEntries[s];
|
||||
@@ -1192,27 +1198,9 @@ anv_h264_encode_video(struct anv_cmd_buffer *cmd_buffer,
|
||||
if (entry->constantQp < 0 || entry->constantQp > 51)
|
||||
return VK_ERROR_INITIALIZATION_FAILED;
|
||||
|
||||
uint32_t slice_start_mb = sh->first_mb_in_slice;
|
||||
uint32_t slice_end_mb = total_mbs;
|
||||
if (s + 1 < slice_count) {
|
||||
const StdVideoEncodeH264SliceHeader *next_sh =
|
||||
h264_pic_info->pNaluSliceEntries[s + 1].pStdSliceHeader;
|
||||
if (!next_sh)
|
||||
return VK_ERROR_INITIALIZATION_FAILED;
|
||||
slice_end_mb = next_sh->first_mb_in_slice;
|
||||
}
|
||||
|
||||
/* H.264 requires the first slice of a picture to start at macroblock 0
|
||||
* (7.4.3: first_mb_in_slice of the first slice is 0). ffmpeg's h264_vulkan
|
||||
* encoder violates this — it passes first_mb_in_slice=1 for the sole slice.
|
||||
* Trusting that value skips MB 0, so the MFC only receives total_mbs-1 PAK
|
||||
* objects for a frame it knows has total_mbs macroblocks; it then waits
|
||||
* forever for the missing MB and the VCS ring hangs ("stopped heartbeat",
|
||||
* no page fault, parked on MFC_AVC_PAK_OBJECT). Force the first slice to
|
||||
* start at MB 0 so the frame is fully covered and the emitted slice header
|
||||
* stays consistent with the coded data. */
|
||||
if (s == 0)
|
||||
slice_start_mb = 0;
|
||||
uint32_t slice_start_mb = s * height_in_mbs / slice_count * width_in_mbs;
|
||||
uint32_t slice_end_mb =
|
||||
(s + 1) * height_in_mbs / slice_count * width_in_mbs;
|
||||
|
||||
if (getenv("HASVK_ENC_LOG"))
|
||||
mesa_logi("ENC slice[%u] first_mb_in_slice=%u -> start=%u end=%u total_mbs=%u",
|
||||
|
||||
Reference in new issue
Block a user