diff --git a/src/intel/vulkan_hasvk/anv_video.c b/src/intel/vulkan_hasvk/anv_video.c index 42b7464..9fe93cd 100644 --- a/src/intel/vulkan_hasvk/anv_video.c +++ b/src/intel/vulkan_hasvk/anv_video.c @@ -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; diff --git a/src/intel/vulkan_hasvk/genX_cmd_video.c b/src/intel/vulkan_hasvk/genX_cmd_video.c index 278ff00..a6e0db3 100644 --- a/src/intel/vulkan_hasvk/genX_cmd_video.c +++ b/src/intel/vulkan_hasvk/genX_cmd_video.c @@ -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",