anv: Initial support for VP9 decoding

Helped from: Stéphane Cerveau <scerveau@igalia.com>
- Fix crash when segmentation is unavailable
- Set 8x8 to minCodedExtent
- Fix typo for GOLDEN and ALTREF scale factor

Signed-off-by: Hyunjun Ko <zzoon@igalia.com>
Acked-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/35485>
This commit is contained in:
Hyunjun Ko 2025-06-09 08:04:43 +02:00 committed by Marge Bot
parent 0689e3d873
commit 314de7af06
3 changed files with 1023 additions and 0 deletions

View file

@ -6413,6 +6413,8 @@ struct anv_vid_mem {
#define ANV_VIDEO_H265_MAX_NUM_REF_FRAME 16
#define ANV_VIDEO_H265_HCP_NUM_REF_FRAME 8
#define ANV_MAX_H265_CTB_SIZE 64
#define ANV_MAX_VP9_CTB_SIZE 64
#define ANV_VP9_SCALE_FACTOR_SHIFT 14
enum anv_vid_mem_h264_types {
ANV_VID_MEM_H264_INTRA_ROW_STORE,
@ -6437,6 +6439,25 @@ enum anv_vid_mem_h265_types {
ANV_VID_MEM_H265_ENC_MAX,
};
enum anv_vid_mem_vp9_types {
ANV_VID_MEM_VP9_DEBLOCK_FILTER_ROW_STORE_LINE,
ANV_VID_MEM_VP9_DEBLOCK_FILTER_ROW_STORE_TILE_LINE,
ANV_VID_MEM_VP9_DEBLOCK_FILTER_ROW_STORE_TILE_COLUMN,
ANV_VID_MEM_VP9_METADATA_LINE,
ANV_VID_MEM_VP9_METADATA_TILE_LINE,
ANV_VID_MEM_VP9_METADATA_TILE_COLUMN,
ANV_VID_MEM_VP9_PROBABILITY_0,
ANV_VID_MEM_VP9_PROBABILITY_1,
ANV_VID_MEM_VP9_PROBABILITY_2,
ANV_VID_MEM_VP9_PROBABILITY_3,
ANV_VID_MEM_VP9_SEGMENT_ID,
ANV_VID_MEM_VP9_HVD_LINE_ROW_STORE,
ANV_VID_MEM_VP9_HVD_TILE_ROW_STORE,
ANV_VID_MEM_VP9_MV_1,
ANV_VID_MEM_VP9_MV_2,
ANV_VID_MEM_VP9_DEC_MAX,
};
enum anv_vid_mem_av1_types {
ANV_VID_MEM_AV1_BITSTREAM_LINE_ROWSTORE,
ANV_VID_MEM_AV1_BITSTREAM_TILE_LINE_ROWSTORE,
@ -6482,14 +6503,49 @@ struct anv_av1_video_refs_info {
uint8_t default_cdf_index;
};
struct anv_vp9_last_frame_info {
uint32_t width;
uint32_t height;
StdVideoVP9FrameType frame_type;
bool key_frame;
bool show_frame;
bool mv_in_turn;
};
struct anv_video_session {
struct vk_video_session vk;
bool cdf_initialized;
VkVideoEncodeRateControlModeFlagBitsKHR rc_mode;
/* the decoder needs some private memory allocations */
struct anv_vid_mem vid_mem[ANV_VID_MEM_AV1_MAX];
struct anv_av1_video_refs_info prev_refs[STD_VIDEO_AV1_NUM_REF_FRAMES];
/* For VP9 decoding from here */
struct anv_vp9_last_frame_info vp9_last_frame;
/* Indicate if there's pending partial reset for prob 0 */
bool pending_frame_partial_reset;
/* Indicate if inter probs saved for prob 0 */
bool saved_inter_probs;
/*
* The prob_tbl_set can have the following:
*
* 0: Reset all
* 1: Reset partially from INTER_MODE_PROBS_OFFSET to SEG_PROBS_OFFSET
* 2: Copy seg prob
* 3: Copy seg prob default
* 4: Save inter probs
* 5: Restore inter probs
*/
BITSET_DECLARE(prob_tbl_set, 6);
/* Mask for resetting all each frame context */
BITSET_DECLARE(frame_ctx_reset_mask, 4);
/* Mask for copying seg probs each frame context */
BITSET_DECLARE(copy_seg_probs, 4);
};
struct anv_video_session_params {
@ -6499,6 +6555,19 @@ struct anv_video_session_params {
void anv_init_av1_cdf_tables(struct anv_cmd_buffer *cmd,
struct anv_video_session *vid);
void anv_update_vp9_tables(struct anv_cmd_buffer *cmd,
struct anv_video_session *video,
uint32_t prob_id,
bool key_frame,
const StdVideoVP9Segmentation *seg);
void anv_calculate_qmul(const struct VkVideoDecodeVP9PictureInfoKHR *vp9_pic,
uint32_t seg_id,
int16_t *ptr);
void anv_vp9_reset_segment_id(struct anv_cmd_buffer *cmd,
struct anv_video_session *vid);
uint32_t anv_video_get_image_mv_size(struct anv_device *device,
struct anv_image *image,
const struct VkVideoProfileListInfoKHR *profile_list);

View file

@ -24,6 +24,7 @@
#include "anv_private.h"
#include "av1_tables.h"
#include "vp9_tables.h"
#include "vk_video/vulkan_video_codecs_common.h"
VkResult
@ -230,6 +231,27 @@ anv_GetPhysicalDeviceVideoCapabilitiesKHR(VkPhysicalDevice physicalDevice,
pCapabilities->stdHeaderVersion.specVersion = VK_STD_VULKAN_VIDEO_CODEC_H265_DECODE_SPEC_VERSION;
break;
}
case VK_VIDEO_CODEC_OPERATION_DECODE_VP9_BIT_KHR: {
struct VkVideoDecodeVP9CapabilitiesKHR *ext = (struct VkVideoDecodeVP9CapabilitiesKHR *)
vk_find_struct(pCapabilities->pNext, VIDEO_DECODE_VP9_CAPABILITIES_KHR);
if (pVideoProfile->lumaBitDepth != VK_VIDEO_COMPONENT_BIT_DEPTH_8_BIT_KHR &&
pVideoProfile->lumaBitDepth != VK_VIDEO_COMPONENT_BIT_DEPTH_10_BIT_KHR)
return VK_ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR;
pCapabilities->maxDpbSlots = STD_VIDEO_VP9_NUM_REF_FRAMES + 4;
pCapabilities->maxActiveReferencePictures = STD_VIDEO_VP9_REFS_PER_FRAME;
pCapabilities->pictureAccessGranularity.width = 8;
pCapabilities->pictureAccessGranularity.height = 8;
pCapabilities->minCodedExtent.width = 8;
pCapabilities->minCodedExtent.height = 8;
ext->maxLevel = 4;
strcpy(pCapabilities->stdHeaderVersion.extensionName, VK_STD_VULKAN_VIDEO_CODEC_VP9_DECODE_EXTENSION_NAME);
pCapabilities->stdHeaderVersion.specVersion = VK_STD_VULKAN_VIDEO_CODEC_VP9_DECODE_SPEC_VERSION;
break;
}
default:
break;
}
@ -494,6 +516,57 @@ get_h265_video_mem_size(struct anv_video_session *vid, uint32_t mem_idx)
return size << 6;
}
static uint64_t
get_vp9_video_mem_size(struct anv_video_session *vid, uint32_t mem_idx)
{
uint32_t width_in_ctb =
DIV_ROUND_UP(vid->vk.max_coded.width, ANV_MAX_VP9_CTB_SIZE);
uint32_t height_in_ctb =
DIV_ROUND_UP(vid->vk.max_coded.height, ANV_MAX_VP9_CTB_SIZE);
uint64_t size;
switch (mem_idx) {
case ANV_VID_MEM_VP9_DEBLOCK_FILTER_ROW_STORE_LINE:
case ANV_VID_MEM_VP9_DEBLOCK_FILTER_ROW_STORE_TILE_LINE:
/* if profile <= 1: multiply 18, if profile > 1: multiply 36
* But we don't know the profile here, so use 36.
*/
size = width_in_ctb * 36;
break;
case ANV_VID_MEM_VP9_DEBLOCK_FILTER_ROW_STORE_TILE_COLUMN:
size = height_in_ctb * 34;
break;
case ANV_VID_MEM_VP9_METADATA_LINE:
case ANV_VID_MEM_VP9_METADATA_TILE_LINE:
size = width_in_ctb * 5;
break;
case ANV_VID_MEM_VP9_METADATA_TILE_COLUMN:
size = height_in_ctb * 5;
break;
case ANV_VID_MEM_VP9_PROBABILITY_0:
case ANV_VID_MEM_VP9_PROBABILITY_1:
case ANV_VID_MEM_VP9_PROBABILITY_2:
case ANV_VID_MEM_VP9_PROBABILITY_3:
size = 32;
break;
case ANV_VID_MEM_VP9_SEGMENT_ID:
size = width_in_ctb * height_in_ctb;
break;
case ANV_VID_MEM_VP9_HVD_LINE_ROW_STORE:
case ANV_VID_MEM_VP9_HVD_TILE_ROW_STORE:
size = width_in_ctb;
break;
case ANV_VID_MEM_VP9_MV_1:
case ANV_VID_MEM_VP9_MV_2:
size = (width_in_ctb * height_in_ctb * 9);
break;
default:
unreachable("unknown memory");
}
return size << 6;
}
static void
get_h264_video_session_mem_reqs(struct anv_video_session *vid,
VkVideoSessionMemoryRequirementsKHR *mem_reqs,
@ -546,6 +619,31 @@ get_h265_video_session_mem_reqs(struct anv_video_session *vid,
}
}
static void
get_vp9_video_session_mem_reqs(struct anv_video_session *vid,
VkVideoSessionMemoryRequirementsKHR *mem_reqs,
uint32_t *pVideoSessionMemoryRequirementsCount,
uint32_t memory_types)
{
VK_OUTARRAY_MAKE_TYPED(VkVideoSessionMemoryRequirementsKHR,
out,
mem_reqs,
pVideoSessionMemoryRequirementsCount);
for (unsigned i = 0; i < ANV_VID_MEM_VP9_DEC_MAX; i++) {
uint32_t bind_index =
ANV_VID_MEM_VP9_DEBLOCK_FILTER_ROW_STORE_LINE + i;
uint64_t size = get_vp9_video_mem_size(vid, i);
vk_outarray_append_typed(VkVideoSessionMemoryRequirementsKHR, &out, p) {
p->memoryBindIndex = bind_index;
p->memoryRequirements.size = size;
p->memoryRequirements.alignment = 4096;
p->memoryRequirements.memoryTypeBits = memory_types;
}
}
}
static const uint8_t av1_buffer_size[ANV_VID_MEM_AV1_MAX][4] = {
{ 2 , 4 , 2 , 4 }, /* bsdLineBuf, */
{ 2 , 4 , 2 , 4 }, /* bsdTileLineBuf, */
@ -784,6 +882,12 @@ anv_GetVideoSessionMemoryRequirementsKHR(VkDevice _device,
pVideoSessionMemoryRequirementsCount,
memory_types);
break;
case VK_VIDEO_CODEC_OPERATION_DECODE_VP9_BIT_KHR:
get_vp9_video_session_mem_reqs(vid,
mem_reqs,
pVideoSessionMemoryRequirementsCount,
memory_types);
break;
default:
unreachable("unknown codec");
}
@ -821,6 +925,7 @@ anv_BindVideoSessionMemoryKHR(VkDevice _device,
case VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR:
case VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR:
case VK_VIDEO_CODEC_OPERATION_DECODE_AV1_BIT_KHR:
case VK_VIDEO_CODEC_OPERATION_DECODE_VP9_BIT_KHR:
for (unsigned i = 0; i < bind_mem_count; i++) {
copy_bind(&vid->vid_mem[bind_mem[i].memoryBindIndex], &bind_mem[i]);
}
@ -1003,6 +1108,187 @@ anv_init_av1_cdf_tables(struct anv_cmd_buffer *cmd,
}
}
#define VP9_CTX_DEFAULT(field) { \
assert(sizeof(ctx.field) == sizeof(default_##field)); \
memcpy(ctx.field, default_##field, sizeof(default_##field)); \
}
static void
vp9_prob_buf_update(struct anv_video_session *vid,
void *ptr,
bool key_frame,
const StdVideoVP9Segmentation *seg)
{
vp9_frame_context ctx = { 0, };
/* Reset all */
if (BITSET_TEST(vid->prob_tbl_set, 0)) {
ctx.tx_probs = default_tx_probs;
VP9_CTX_DEFAULT(coef_probs_4x4);
VP9_CTX_DEFAULT(coef_probs_8x8);
VP9_CTX_DEFAULT(coef_probs_16x16);
VP9_CTX_DEFAULT(coef_probs_32x32);
VP9_CTX_DEFAULT(skip_probs);
if (key_frame) {
memcpy(ctx.partition_probs, vp9_kf_partition_probs,
sizeof(vp9_kf_partition_probs));
memcpy(ctx.uv_mode_probs, vp9_kf_uv_mode_probs,
sizeof(vp9_kf_uv_mode_probs));
} else {
VP9_CTX_DEFAULT(inter_mode_probs);
VP9_CTX_DEFAULT(switchable_interp_prob);
VP9_CTX_DEFAULT(intra_inter_prob);
VP9_CTX_DEFAULT(comp_inter_prob);
VP9_CTX_DEFAULT(single_ref_prob);
VP9_CTX_DEFAULT(comp_ref_prob);
VP9_CTX_DEFAULT(y_mode_prob);
VP9_CTX_DEFAULT(partition_probs);
ctx.nmvc = default_nmv_context;
VP9_CTX_DEFAULT(uv_mode_probs);
}
memcpy(ptr, &ctx, sizeof(vp9_frame_context));
}
/* Reset partially */
if (BITSET_TEST(vid->prob_tbl_set, 1)) {
if (key_frame) {
memcpy(ctx.partition_probs, vp9_kf_partition_probs,
sizeof(vp9_kf_partition_probs));
memcpy(ctx.uv_mode_probs, vp9_kf_uv_mode_probs,
sizeof(vp9_kf_uv_mode_probs));
} else {
VP9_CTX_DEFAULT(inter_mode_probs);
VP9_CTX_DEFAULT(switchable_interp_prob);
VP9_CTX_DEFAULT(intra_inter_prob);
VP9_CTX_DEFAULT(comp_inter_prob);
VP9_CTX_DEFAULT(single_ref_prob);
VP9_CTX_DEFAULT(comp_ref_prob);
VP9_CTX_DEFAULT(y_mode_prob);
VP9_CTX_DEFAULT(partition_probs);
ctx.nmvc = default_nmv_context;
VP9_CTX_DEFAULT(uv_mode_probs);
}
memcpy(ptr + INTER_MODE_PROBS_OFFSET, &ctx.inter_mode_probs, INTER_MODE_PROBS_SIZE);
}
/* Copy seg probs */
if (BITSET_TEST(vid->prob_tbl_set, 2)) {
memcpy(ctx.seg_tree_probs, seg->segmentation_tree_probs,
sizeof(ctx.seg_tree_probs));
memcpy(ctx.seg_pred_probs, seg->segmentation_pred_prob,
sizeof(ctx.seg_pred_probs));
memcpy(ptr + SEG_PROBS_OFFSET, &ctx.seg_tree_probs,
SEG_TREE_PROBS + PREDICTION_PROBS);
} else if (BITSET_TEST(vid->prob_tbl_set, 3)) {
VP9_CTX_DEFAULT(seg_tree_probs);
VP9_CTX_DEFAULT(seg_pred_probs);
memcpy(ptr + SEG_PROBS_OFFSET, &ctx,
SEG_TREE_PROBS + PREDICTION_PROBS);
}
/* TODO for 4, 5 */
}
void
anv_update_vp9_tables(struct anv_cmd_buffer *cmd,
struct anv_video_session *vid,
uint32_t prob_id,
bool key_frame,
const StdVideoVP9Segmentation *seg)
{
void *prob_map;
VkResult result =
anv_device_map_bo(cmd->device,
vid->vid_mem[prob_id].mem->bo,
vid->vid_mem[prob_id].offset,
vid->vid_mem[prob_id].size,
NULL /* placed_addr */,
&prob_map);
if (result != VK_SUCCESS) {
anv_batch_set_error(&cmd->batch, result);
return;
}
vp9_prob_buf_update(vid, prob_map, key_frame, seg);
/* Clear probability setting table */
for (int i = 0; i < 6; i++)
BITSET_CLEAR(vid->prob_tbl_set, i);
anv_device_unmap_bo(cmd->device,
vid->vid_mem[prob_id].mem->bo,
prob_map,
vid->vid_mem[prob_id].size, false);
}
void
anv_calculate_qmul(const struct VkVideoDecodeVP9PictureInfoKHR *vp9_pic,
uint32_t seg_id,
int16_t *ptr)
{
const StdVideoDecodeVP9PictureInfo *std_pic = vp9_pic->pStdPictureInfo;
const StdVideoVP9Segmentation *segmentation = std_pic->pSegmentation;
uint32_t bpp_index = std_pic->pColorConfig->BitDepth > 8 ? 1 : 0;
uint32_t qyac;
if (std_pic->flags.segmentation_enabled && segmentation->FeatureEnabled[seg_id]) {
if (segmentation->flags.segmentation_abs_or_delta_update) {
/* FIXME. which lvl needs to be picked */
qyac = segmentation->FeatureData[seg_id][0] & 0xff;
} else {
qyac = (std_pic->base_q_idx + segmentation->FeatureData[seg_id][0]) & 0xff;
}
} else {
qyac = std_pic->base_q_idx & 0xff;
}
uint32_t qydc = (qyac + std_pic->delta_q_y_dc) & 0xff;
uint32_t quvdc = (qyac + std_pic->delta_q_uv_dc) & 0xff;
uint32_t quvac = (qyac + std_pic->delta_q_uv_ac) & 0xff;
int16_t qmul[2][2] = { 0, };
qmul[0][0] = vp9_dc_qlookup[bpp_index][qydc];
qmul[0][1] = vp9_ac_qlookup[bpp_index][qyac];
qmul[1][0] = vp9_dc_qlookup[bpp_index][quvdc];
qmul[1][1] = vp9_ac_qlookup[bpp_index][quvac];
memcpy(ptr, qmul, sizeof(qmul));
}
void
anv_vp9_reset_segment_id(struct anv_cmd_buffer *cmd, struct anv_video_session *vid)
{
void *map;
VkResult result =
anv_device_map_bo(cmd->device,
vid->vid_mem[ANV_VID_MEM_VP9_SEGMENT_ID].mem->bo,
vid->vid_mem[ANV_VID_MEM_VP9_SEGMENT_ID].offset,
vid->vid_mem[ANV_VID_MEM_VP9_SEGMENT_ID].size,
NULL,
&map);
if (result != VK_SUCCESS) {
anv_batch_set_error(&cmd->batch, result);
return;
}
memset(map, 0, vid->vid_mem[ANV_VID_MEM_VP9_SEGMENT_ID].size);
anv_device_unmap_bo(cmd->device,
vid->vid_mem[ANV_VID_MEM_VP9_SEGMENT_ID].mem->bo,
map,
vid->vid_mem[ANV_VID_MEM_VP9_SEGMENT_ID].size, NULL);
}
uint32_t
anv_video_get_image_mv_size(struct anv_device *device,
struct anv_image *image,
@ -1019,6 +1305,11 @@ anv_video_get_image_mv_size(struct anv_device *device,
unsigned w_mb = DIV_ROUND_UP(image->vk.extent.width, 32);
unsigned h_mb = DIV_ROUND_UP(image->vk.extent.height, 32);
size = ALIGN(w_mb * h_mb, 2) << 6;
} else if (profile_list->pProfiles[i].videoCodecOperation == VK_VIDEO_CODEC_OPERATION_DECODE_VP9_BIT_KHR) {
unsigned w_ctb = DIV_ROUND_UP(image->vk.extent.width, ANV_MAX_VP9_CTB_SIZE);
unsigned h_ctb = DIV_ROUND_UP(image->vk.extent.height, ANV_MAX_VP9_CTB_SIZE);
size = (w_ctb * h_ctb * 9) << 6;
} else if (profile_list->pProfiles[i].videoCodecOperation == VK_VIDEO_CODEC_OPERATION_DECODE_AV1_BIT_KHR) {
uint32_t width_in_sb, height_in_sb;
get_av1_sb_size(&width_in_sb, &height_in_sb);

View file

@ -2568,6 +2568,666 @@ anv_av1_decode_video(struct anv_cmd_buffer *cmd_buffer,
}
#endif
static uint8_t
anv_vp9_get_ref_idx(const struct VkVideoDecodeInfoKHR *frame_info, int slot_id)
{
for (unsigned i = 0; i < frame_info->referenceSlotCount; i++) {
if (slot_id == frame_info->pReferenceSlots[i].slotIndex)
return i;
}
return -1;
}
static void
anv_vp9_decide_prob_tbl_set(struct anv_video_session *vid,
const StdVideoDecodeVP9PictureInfo *std_pic)
{
const bool key_frame = std_pic->frame_type == STD_VIDEO_VP9_FRAME_TYPE_KEY;
const bool key_frame_or_intra_only =
std_pic->flags.intra_only || std_pic->frame_type == STD_VIDEO_VP9_FRAME_TYPE_KEY;
const StdVideoVP9Segmentation *segmentation = std_pic->pSegmentation;
/* Probability table setting */
bool reset_all = key_frame || std_pic->flags.error_resilient_mode ||
(std_pic->reset_frame_context == 3 && std_pic->flags.intra_only);
bool reset_specified = std_pic->reset_frame_context == 2 && std_pic->flags.intra_only;
bool copy_seg_prob = false;
bool copy_seg_prob_default = false;
bool do_save_interprobs = false;
bool do_restore_interprobs = false;
if (std_pic->flags.segmentation_enabled) {
if (segmentation->flags.segmentation_update_map) {
for (int i = 0; i < 4; i++)
BITSET_CLEAR(vid->copy_seg_probs, i);
copy_seg_prob = true;
} else if (!BITSET_TEST(vid->copy_seg_probs, std_pic->frame_context_idx)) {
copy_seg_prob_default = true;
}
/* Mask for indicating seg probs are copied */
BITSET_SET(vid->copy_seg_probs, std_pic->frame_context_idx);
}
/*
* The prob_tbl_set can have the following:
*
* 0: Reset all
* 1: Reset partially from INTER_MODE_PROBS_OFFSET to SEG_PROBS_OFFSET
* 2: Copy seg prob
* 3: Copy seg prob default
* 4: Save inter probs
* 5: Restore inter probs
*/
if (reset_all) {
BITSET_SET(vid->prob_tbl_set, 0);
BITSET_SET(vid->frame_ctx_reset_mask, std_pic->frame_context_idx);
for (int i = 1; i < 4; i++)
BITSET_CLEAR(vid->frame_ctx_reset_mask, i);
vid->pending_frame_partial_reset = key_frame_or_intra_only;
vid->saved_inter_probs = false;
} else if (reset_specified) {
if (std_pic->frame_context_idx == 0) {
BITSET_SET(vid->prob_tbl_set, 0);
vid->pending_frame_partial_reset = true;
} else {
BITSET_CLEAR(vid->frame_ctx_reset_mask, std_pic->frame_context_idx);
if (!vid->pending_frame_partial_reset) {
if (!vid->saved_inter_probs) {
vid->saved_inter_probs = true;
do_save_interprobs = true;
}
BITSET_SET(vid->prob_tbl_set, 1);
}
}
} else if (std_pic->flags.intra_only) {
if (!vid->pending_frame_partial_reset) {
if (!vid->saved_inter_probs) {
vid->saved_inter_probs = true;
do_save_interprobs = true;
}
BITSET_SET(vid->prob_tbl_set, 1);
}
} else {
if (std_pic->frame_context_idx == 0) {
if (vid->pending_frame_partial_reset) {
BITSET_SET(vid->prob_tbl_set, 1);
vid->pending_frame_partial_reset = false;
} else if (vid->saved_inter_probs) {
vid->saved_inter_probs = false;
do_restore_interprobs = true;
}
} else {
if (!key_frame_or_intra_only &&
!BITSET_TEST(vid->frame_ctx_reset_mask, std_pic->frame_context_idx)) {
BITSET_SET(vid->frame_ctx_reset_mask, std_pic->frame_context_idx);
BITSET_SET(vid->prob_tbl_set, 0);
}
}
}
if (copy_seg_prob) {
BITSET_SET(vid->prob_tbl_set, 2);
} else if (copy_seg_prob_default) {
BITSET_SET(vid->prob_tbl_set, 3);
}
if (do_save_interprobs) {
BITSET_SET(vid->prob_tbl_set, 4);
} else if (do_restore_interprobs) {
BITSET_SET(vid->prob_tbl_set, 5);
}
return;
}
static void
anv_vp9_decode_video(struct anv_cmd_buffer *cmd_buffer,
const VkVideoDecodeInfoKHR *frame_info)
{
ANV_FROM_HANDLE(anv_buffer, src_buffer, frame_info->srcBuffer);
struct anv_video_session *vid = cmd_buffer->video.vid;
const struct VkVideoDecodeVP9PictureInfoKHR *vp9_pic_info =
vk_find_struct_const(frame_info->pNext, VIDEO_DECODE_VP9_PICTURE_INFO_KHR);
const StdVideoDecodeVP9PictureInfo *std_pic = vp9_pic_info->pStdPictureInfo;
const StdVideoVP9Segmentation *segmentation = std_pic->pSegmentation;
const StdVideoVP9LoopFilter *loop_filter = std_pic->pLoopFilter;
const bool key_frame = std_pic->frame_type == STD_VIDEO_VP9_FRAME_TYPE_KEY;
const bool key_frame_or_intra_only =
std_pic->flags.intra_only || std_pic->frame_type == STD_VIDEO_VP9_FRAME_TYPE_KEY;
/* 12 bit doesn't support for the moment */
bool is_10bit = std_pic->pColorConfig->BitDepth > 8;
uint32_t prob_id = ANV_VID_MEM_VP9_PROBABILITY_0 + std_pic->frame_context_idx;
bool is_scaling = false;
#if GFX_VER >= 12
anv_batch_emit(&cmd_buffer->batch, GENX(MI_FORCE_WAKEUP), wake) {
wake.HEVCPowerWellControl = 1;
wake.MaskBits = 768;
}
anv_batch_emit(&cmd_buffer->batch, GENX(VD_CONTROL_STATE), cs) {
cs.PipelineInitialization = true;
}
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_WAIT), mfx) {
mfx.MFXSyncControlFlag = 1;
}
#endif
anv_batch_emit(&cmd_buffer->batch, GENX(HCP_PIPE_MODE_SELECT), sel) {
sel.CodecSelect = Decode;
sel.CodecStandardSelect = VP9;
}
#if GFX_VER >= 12
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_WAIT), mfx) {
mfx.MFXSyncControlFlag = 1;
}
#endif
const struct anv_image_view *dst_iv =
anv_image_view_from_handle(frame_info->dstPictureResource.imageViewBinding);
const struct anv_image_view *iv = frame_info->pSetupReferenceSlot ?
anv_image_view_from_handle(frame_info->pSetupReferenceSlot->pPictureResource->imageViewBinding) :
dst_iv;
const struct anv_image *img = iv->image;
uint32_t frame_width = frame_info->dstPictureResource.codedExtent.width;
uint32_t frame_height = frame_info->dstPictureResource.codedExtent.height;
if (vid->vp9_last_frame.width != 0 &&
(frame_width != vid->vp9_last_frame.width ||
frame_height != vid->vp9_last_frame.height)) {
is_scaling = true;
}
anv_vp9_decide_prob_tbl_set(vid, std_pic);
anv_update_vp9_tables(cmd_buffer, vid, prob_id, key_frame_or_intra_only, segmentation);
if (key_frame_or_intra_only || is_scaling || std_pic->flags.error_resilient_mode)
anv_vp9_reset_segment_id(cmd_buffer, vid);
anv_batch_emit(&cmd_buffer->batch, GENX(HCP_SURFACE_STATE), ss) {
ss.SurfacePitch = img->planes[0].primary_surface.isl.row_pitch_B - 1;
ss.SurfaceID = HCP_CurrentDecodedPicture;
ss.SurfaceFormat = is_10bit ? P010 : PLANAR_420_8;
ss.YOffsetforUCb = img->planes[1].primary_surface.memory_range.offset /
img->planes[0].primary_surface.isl.row_pitch_B;
#if GFX_VER >= 11
ss.DefaultAlphaValue = 0xffff;
#endif
}
uint32_t last_frame_width = 0, last_frame_height = 0;
uint32_t golden_frame_width = 0, golden_frame_height = 0;
uint32_t altref_frame_width = 0, altref_frame_height = 0;
if (!key_frame_or_intra_only) {
for (uint8_t i = 0; i < 3; i++) {
uint8_t idx = anv_vp9_get_ref_idx(frame_info, vp9_pic_info->referenceNameSlotIndices[i]);
const struct anv_image_view *ref_iv =
anv_image_view_from_handle(frame_info->pReferenceSlots[idx].pPictureResource->imageViewBinding);
const struct anv_image *ref_img = ref_iv->image;
assert(frame_info->pReferenceSlots[idx].slotIndex == vp9_pic_info->referenceNameSlotIndices[i]);
if (i == 0) {
last_frame_width = frame_info->pReferenceSlots[idx].pPictureResource->codedExtent.width;
last_frame_height = frame_info->pReferenceSlots[idx].pPictureResource->codedExtent.height;
} else if (i == 1) {
golden_frame_width = frame_info->pReferenceSlots[idx].pPictureResource->codedExtent.width;
golden_frame_height = frame_info->pReferenceSlots[idx].pPictureResource->codedExtent.height;
} else if (i == 2) {
altref_frame_width = frame_info->pReferenceSlots[idx].pPictureResource->codedExtent.width;
altref_frame_height = frame_info->pReferenceSlots[idx].pPictureResource->codedExtent.height;
}
anv_batch_emit(&cmd_buffer->batch, GENX(HCP_SURFACE_STATE), ss) {
ss.SurfacePitch = ref_img->planes[0].primary_surface.isl.row_pitch_B - 1;
ss.SurfaceID = i + 2;
ss.SurfaceFormat = is_10bit ? P010 : PLANAR_420_8;
ss.YOffsetforUCb = ref_img->planes[1].primary_surface.memory_range.offset /
ref_img->planes[0].primary_surface.isl.row_pitch_B;
#if GFX_VER >= 11
ss.DefaultAlphaValue = 0xffff;
#endif
}
}
}
anv_batch_emit(&cmd_buffer->batch, GENX(HCP_PIPE_BUF_ADDR_STATE), buf) {
buf.DecodedPictureAddress =
anv_image_address(img, &img->planes[0].primary_surface.memory_range);
buf.DecodedPictureMemoryAddressAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
.MOCS = anv_mocs(cmd_buffer->device, buf.DecodedPictureAddress.bo, 0),
};
buf.DeblockingFilterLineBufferAddress = (struct anv_address) {
vid->vid_mem[ANV_VID_MEM_VP9_DEBLOCK_FILTER_ROW_STORE_LINE].mem->bo,
vid->vid_mem[ANV_VID_MEM_VP9_DEBLOCK_FILTER_ROW_STORE_LINE].offset
};
buf.DeblockingFilterLineBufferMemoryAddressAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
.MOCS = anv_mocs(cmd_buffer->device, buf.DeblockingFilterLineBufferAddress.bo, 0),
};
buf.DeblockingFilterTileLineBufferAddress = (struct anv_address) {
vid->vid_mem[ANV_VID_MEM_VP9_DEBLOCK_FILTER_ROW_STORE_TILE_LINE].mem->bo,
vid->vid_mem[ANV_VID_MEM_VP9_DEBLOCK_FILTER_ROW_STORE_TILE_LINE].offset
};
buf.DeblockingFilterTileLineBufferMemoryAddressAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
.MOCS = anv_mocs(cmd_buffer->device, buf.DeblockingFilterTileLineBufferAddress.bo, 0),
};
buf.DeblockingFilterTileColumnBufferAddress = (struct anv_address) {
vid->vid_mem[ANV_VID_MEM_VP9_DEBLOCK_FILTER_ROW_STORE_TILE_COLUMN].mem->bo,
vid->vid_mem[ANV_VID_MEM_VP9_DEBLOCK_FILTER_ROW_STORE_TILE_COLUMN].offset
};
buf.DeblockingFilterTileColumnBufferMemoryAddressAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
.MOCS = anv_mocs(cmd_buffer->device, buf.DeblockingFilterTileColumnBufferAddress.bo, 0),
};
buf.MetadataLineBufferAddress = (struct anv_address) {
vid->vid_mem[ANV_VID_MEM_VP9_METADATA_LINE].mem->bo,
vid->vid_mem[ANV_VID_MEM_VP9_METADATA_LINE].offset
};
buf.MetadataLineBufferMemoryAddressAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
.MOCS = anv_mocs(cmd_buffer->device, buf.MetadataLineBufferAddress.bo, 0),
};
buf.MetadataTileLineBufferAddress = (struct anv_address) {
vid->vid_mem[ANV_VID_MEM_VP9_METADATA_TILE_LINE].mem->bo,
vid->vid_mem[ANV_VID_MEM_VP9_METADATA_TILE_LINE].offset
};
buf.MetadataTileLineBufferMemoryAddressAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
.MOCS = anv_mocs(cmd_buffer->device, buf.MetadataTileLineBufferAddress.bo, 0),
};
buf.MetadataTileColumnBufferAddress = (struct anv_address) {
vid->vid_mem[ANV_VID_MEM_VP9_METADATA_TILE_COLUMN].mem->bo,
vid->vid_mem[ANV_VID_MEM_VP9_METADATA_TILE_COLUMN].offset
};
buf.MetadataTileColumnBufferMemoryAddressAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
.MOCS = anv_mocs(cmd_buffer->device, buf.MetadataTileColumnBufferAddress.bo, 0),
};
buf.SAOLineBufferMemoryAddressAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
.MOCS = anv_mocs(cmd_buffer->device, NULL, 0),
};
buf.SAOTileLineBufferMemoryAddressAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
.MOCS = anv_mocs(cmd_buffer->device, NULL, 0),
};
buf.SAOTileColumnBufferMemoryAddressAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
.MOCS = anv_mocs(cmd_buffer->device, NULL, 0),
};
/* For VP9 decoding, only 2 mv buffers are used alternately */
uint8_t cur_mv_idx = 0, col_mv_idx = 0;
if (!key_frame_or_intra_only) {
if (vid->vp9_last_frame.mv_in_turn) {
cur_mv_idx = ANV_VID_MEM_VP9_MV_1;
col_mv_idx = ANV_VID_MEM_VP9_MV_2;
} else {
cur_mv_idx = ANV_VID_MEM_VP9_MV_2;
col_mv_idx = ANV_VID_MEM_VP9_MV_1;
}
}
if (!key_frame_or_intra_only) {
buf.CurrentMVTemporalBufferAddress = (struct anv_address) {
vid->vid_mem[cur_mv_idx].mem->bo,
vid->vid_mem[cur_mv_idx].offset
};
}
buf.CurrentMVTemporalBufferMemoryAddressAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
.MOCS = anv_mocs(cmd_buffer->device, vid->vid_mem[cur_mv_idx].mem->bo, 0),
};
if (!key_frame_or_intra_only) {
for (uint8_t i = 0; i < 3; i++) {
uint8_t idx = anv_vp9_get_ref_idx(frame_info, vp9_pic_info->referenceNameSlotIndices[i]);
const struct anv_image_view *ref_iv =
anv_image_view_from_handle(frame_info->pReferenceSlots[idx].pPictureResource->imageViewBinding);
assert(frame_info->pReferenceSlots[idx].slotIndex == vp9_pic_info->referenceNameSlotIndices[i]);
buf.ReferencePictureAddress[i] =
anv_image_address(ref_iv->image, &ref_iv->image->planes[0].primary_surface.memory_range);
}
}
buf.ReferencePictureMemoryAddressAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
.MOCS = anv_mocs(cmd_buffer->device, NULL, 0),
};
buf.OriginalUncompressedPictureSourceMemoryAddressAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
.MOCS = anv_mocs(cmd_buffer->device, NULL, 0),
};
buf.StreamOutDataDestinationMemoryAddressAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
.MOCS = anv_mocs(cmd_buffer->device, NULL, 0),
};
buf.DecodedPictureStatusBufferMemoryAddressAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
.MOCS = anv_mocs(cmd_buffer->device, NULL, 0),
};
buf.LCUILDBStreamOutBufferMemoryAddressAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
.MOCS = anv_mocs(cmd_buffer->device, NULL, 0),
};
if (!key_frame_or_intra_only) {
buf.CollocatedMVTemporalBufferAddress[0] = (struct anv_address) {
vid->vid_mem[col_mv_idx].mem->bo,
vid->vid_mem[col_mv_idx].offset
};
}
buf.CollocatedMVTemporalBufferMemoryAddressAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
.MOCS = anv_mocs(cmd_buffer->device, buf.CollocatedMVTemporalBufferAddress[0].bo, 0),
};
buf.VP9ProbabilityBufferAddress = (struct anv_address) {
vid->vid_mem[prob_id].mem->bo,
vid->vid_mem[prob_id].offset
};
buf.VP9ProbabilityBufferMemoryAddressAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
.MOCS = anv_mocs(cmd_buffer->device, buf.VP9ProbabilityBufferAddress.bo, 0),
};
buf.VP9SegmentIDBufferAddress = (struct anv_address) {
vid->vid_mem[ANV_VID_MEM_VP9_SEGMENT_ID].mem->bo,
vid->vid_mem[ANV_VID_MEM_VP9_SEGMENT_ID].offset
};
buf.VP9SegmentIDBufferMemoryAddressAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
.MOCS = anv_mocs(cmd_buffer->device, NULL, 0),
};
buf.VP9HVDLineRowStoreBufferAddress = (struct anv_address) {
vid->vid_mem[ANV_VID_MEM_VP9_HVD_LINE_ROW_STORE].mem->bo,
vid->vid_mem[ANV_VID_MEM_VP9_HVD_LINE_ROW_STORE].offset
};
buf.VP9HVDLineRowStoreBufferMemoryAddressAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
.MOCS = anv_mocs(cmd_buffer->device, buf.VP9HVDLineRowStoreBufferAddress.bo, 0),
};
buf.VP9HVDTileRowStoreBufferAddress = (struct anv_address) {
vid->vid_mem[ANV_VID_MEM_VP9_HVD_TILE_ROW_STORE].mem->bo,
vid->vid_mem[ANV_VID_MEM_VP9_HVD_TILE_ROW_STORE].offset
};
buf.VP9HVDTileRowStoreBufferMemoryAddressAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
.MOCS = anv_mocs(cmd_buffer->device, buf.VP9HVDTileRowStoreBufferAddress.bo, 0),
};
#if GFX_VER >= 11
buf.SAOStreamOutDataDestinationBufferMemoryAddressAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
.MOCS = anv_mocs(cmd_buffer->device, NULL, 0),
};
buf.FrameStatisticsStreamOutDataDestinationBufferMemoryAddressAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
.MOCS = anv_mocs(cmd_buffer->device, NULL, 0),
};
buf.SSESourcePixelRowStoreBufferMemoryAddressAttributesReadWrite = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
.MOCS = anv_mocs(cmd_buffer->device, NULL, 0),
};
buf.HCPScalabilitySliceStateBufferMemoryAddressAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
.MOCS = anv_mocs(cmd_buffer->device, NULL, 0),
};
buf.HCPScalabilityCABACDecodedSyntaxElementsBufferMemoryAddressAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
.MOCS = anv_mocs(cmd_buffer->device, NULL, 0),
};
buf.MVUpperRightColumnStoreBufferMemoryAddressAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
.MOCS = anv_mocs(cmd_buffer->device, NULL, 0),
};
buf.IntraPredictionUpperRightColumnStoreBufferMemoryAddressAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
.MOCS = anv_mocs(cmd_buffer->device, NULL, 0),
};
buf.IntraPredictionLeftReconColumnStoreBufferMemoryAddressAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
.MOCS = anv_mocs(cmd_buffer->device, NULL, 0),
};
#endif
}
anv_batch_emit(&cmd_buffer->batch, GENX(HCP_IND_OBJ_BASE_ADDR_STATE), indirect) {
indirect.HCPIndirectBitstreamObjectBaseAddress =
anv_address_add(src_buffer->address, frame_info->srcBufferOffset & ~4095);
indirect.HCPIndirectBitstreamObjectMemoryAddressAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
.MOCS = anv_mocs(cmd_buffer->device, src_buffer->address.bo, 0),
};
indirect.HCPIndirectCUObjectMemoryAddressAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
.MOCS = anv_mocs(cmd_buffer->device, NULL, 0),
};
indirect.HCPPAKBSEObjectMemoryAddressAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
.MOCS = anv_mocs(cmd_buffer->device, NULL, 0),
};
#if GFX_VER >= 11
indirect.HCPVP9PAKCompressedHeaderSyntaxStreamInMemoryAddressAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
.MOCS = anv_mocs(cmd_buffer->device, NULL, 0),
};
indirect.HCPVP9PAKProbabilityCounterStreamOutMemoryAddressAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
.MOCS = anv_mocs(cmd_buffer->device, NULL, 0),
};
indirect.HCPVP9PAKProbabilityDeltasStreamInMemoryAddressAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
.MOCS = anv_mocs(cmd_buffer->device, NULL, 0),
};
indirect.HCPVP9PAKTileRecordStreamOutMemoryAddressAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
.MOCS = anv_mocs(cmd_buffer->device, NULL, 0),
};
indirect.HCPVP9PAKCULevelStatisticStreamOutMemoryAddressAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
.MOCS = anv_mocs(cmd_buffer->device, NULL, 0),
};
#endif
}
uint32_t num_segments;
if (!std_pic->flags.segmentation_enabled)
num_segments = 1;
else
num_segments = 8;
uint8_t loop_filter_level = loop_filter->loop_filter_level;
for (uint32_t i = 0; i < num_segments; i++) {
anv_batch_emit(&cmd_buffer->batch, GENX(HCP_VP9_SEGMENT_STATE), seg) {
seg.SegmentID = i;
int16_t qmul[2][2] = { 0, };
anv_calculate_qmul(vp9_pic_info, i, (int16_t *)qmul);
seg.LumaDCQuantScale = qmul[0][0];
seg.LumaACQuantScale = qmul[0][1];
seg.ChromaDCQuantScale = qmul[1][0];
seg.ChromaACQuantScale = qmul[1][1];
if (loop_filter->flags.loop_filter_delta_enabled) {
int shift = loop_filter->loop_filter_level >= 32;
if (loop_filter_level > 0) {
seg.FilterLevelRef0Mode0 = CLAMP(loop_filter_level +
loop_filter->loop_filter_ref_deltas[0] * (1 << shift), 0, 63);
seg.FilterLevelRef0Mode1 = seg.FilterLevelRef0Mode0;
seg.FilterLevelRef1Mode0 = CLAMP(loop_filter_level +
loop_filter->loop_filter_ref_deltas[1] * (1 <<shift) +
loop_filter->loop_filter_mode_deltas[0] * (1 << shift), 0, 0x3f);
seg.FilterLevelRef1Mode1 = CLAMP(loop_filter_level +
loop_filter->loop_filter_ref_deltas[1] * (1 <<shift)
+ loop_filter->loop_filter_mode_deltas[1] * (1 << shift), 0, 0x3f);
seg.FilterLevelRef2Mode0 = CLAMP(loop_filter_level +
loop_filter->loop_filter_ref_deltas[2] * (1 <<shift) +
loop_filter->loop_filter_mode_deltas[0] * (1 << shift), 0, 0x3f);
seg.FilterLevelRef2Mode1 = CLAMP(loop_filter_level +
loop_filter->loop_filter_ref_deltas[2] * (1 <<shift) +
loop_filter->loop_filter_mode_deltas[1] * (1 << shift), 0, 0x3f);
seg.FilterLevelRef3Mode0 = CLAMP(loop_filter_level +
loop_filter->loop_filter_ref_deltas[3] * (1 <<shift) +
loop_filter->loop_filter_mode_deltas[0] * (1 << shift), 0, 0x3f);
seg.FilterLevelRef3Mode1 = CLAMP(loop_filter_level +
loop_filter->loop_filter_ref_deltas[3] * (1 <<shift) +
loop_filter->loop_filter_mode_deltas[1] * (1 << shift), 0, 0x3f);
}
} else {
seg.FilterLevelRef0Mode0 = loop_filter_level;
seg.FilterLevelRef0Mode1 = loop_filter_level;
seg.FilterLevelRef1Mode0 = loop_filter_level;
seg.FilterLevelRef1Mode1 = loop_filter_level;
seg.FilterLevelRef2Mode0 = loop_filter_level;
seg.FilterLevelRef2Mode1 = loop_filter_level;
seg.FilterLevelRef3Mode0 = loop_filter_level;
seg.FilterLevelRef3Mode1 = loop_filter_level;
}
}
}
anv_batch_emit(&cmd_buffer->batch, GENX(HCP_VP9_PIC_STATE), pic) {
if (std_pic->flags.segmentation_enabled)
assert(segmentation != NULL);
pic.FrameWidth = ALIGN(frame_width, 8) - 1;
pic.FrameHeight = ALIGN(frame_height, 8) - 1;
/* STD_VIDEO_VP9_FRAME_TYPE_KEY == VP9_Key_frmae
* STD_VIDEO_VP9_FRAME_TYPE_NON_KEY == VP9_InterFrame
*/
pic.FrameType = std_pic->frame_type;
pic.AdaptProbabilities = !std_pic->flags.error_resilient_mode && !std_pic->flags.frame_parallel_decoding_mode;
pic.IntraOnly = std_pic->flags.intra_only;
pic.RefreshFrameContextEnable = std_pic->flags.refresh_frame_context;
pic.ErrorResilientModeEnable = std_pic->flags.error_resilient_mode;
pic.FrameParallelDecodingModeEnable = std_pic->flags.frame_parallel_decoding_mode;
pic.FilterLevel = std_pic->pLoopFilter->loop_filter_level;
pic.SharpnessLevel = std_pic->pLoopFilter->loop_filter_sharpness;
pic.SegmentationEnable = std_pic->flags.segmentation_enabled;
pic.SegmentationUpdateMap = segmentation && segmentation->flags.segmentation_update_map;
pic.LosslessMode = (std_pic->base_q_idx == 0) && (std_pic->delta_q_y_dc == 0) &&
(std_pic->delta_q_uv_dc == 0) && (std_pic->delta_q_uv_ac == 0);
pic.SegmentIDStreamOutEnable = pic.SegmentationUpdateMap;
pic.SegmentIDStreamInEnable = key_frame_or_intra_only ||
(std_pic->flags.segmentation_enabled &&
(!segmentation->flags.segmentation_update_map || segmentation->flags.segmentation_temporal_update)) ||
std_pic->flags.error_resilient_mode ||
is_scaling;
pic.Log2TileColumn = std_pic->tile_cols_log2;
pic.Log2TileRow = std_pic->tile_rows_log2;
if (std_pic->pColorConfig->subsampling_x == 1 || std_pic->pColorConfig->subsampling_y == 1) {
pic.ChromaSamplingFormat = Format_420;
} else if (std_pic->pColorConfig->subsampling_x == 1 || std_pic->pColorConfig->subsampling_y == 0) {
pic.ChromaSamplingFormat = Format_422;
} else if (std_pic->pColorConfig->subsampling_x == 0 || std_pic->pColorConfig->subsampling_y == 0) {
pic.ChromaSamplingFormat = Format_444;
}
pic.BitDepth = is_10bit ? _10bit : _8bit;
pic.ProfileLevel = std_pic->profile;
pic.UncompressedHeaderLength = vp9_pic_info->compressedHeaderOffset - vp9_pic_info->uncompressedHeaderOffset;
pic.FirstPartitionSize = vp9_pic_info->tilesOffset - vp9_pic_info->compressedHeaderOffset;
pic.MotionCompScalingEnable = true;
if (!key_frame) {
pic.AllowHiPrecisionMV = std_pic->flags.allow_high_precision_mv;
pic.MotionCompensationFilterType = std_pic->interpolation_filter;
pic.SegmentationTemporalUpdate = key_frame_or_intra_only || !segmentation ? 0 : segmentation->flags.segmentation_temporal_update;
bool use_pre_frame_mvs = !((std_pic->flags.error_resilient_mode) ||
(frame_width != vid->vp9_last_frame.width) ||
(frame_height != vid->vp9_last_frame.height) ||
vid->vp9_last_frame.key_frame ||
!vid->vp9_last_frame.show_frame);
if (is_scaling)
use_pre_frame_mvs = false;
pic.ReferenceFrameSignBias = std_pic->ref_frame_sign_bias_mask >> 1;
pic.LastFrameType = vid->vp9_last_frame.frame_type;
pic.UsePrevinFindMVReferences = use_pre_frame_mvs;
pic.HorizontalScaleFactorforLAST = (last_frame_width << ANV_VP9_SCALE_FACTOR_SHIFT) / frame_width;
pic.VerticalScaleFactorforLAST = (last_frame_height << ANV_VP9_SCALE_FACTOR_SHIFT) / frame_height;
pic.HorizontalScaleFactorforGOLDEN = (golden_frame_width << ANV_VP9_SCALE_FACTOR_SHIFT) / frame_width;
pic.VerticalScaleFactorforGOLDEN = (golden_frame_height << ANV_VP9_SCALE_FACTOR_SHIFT) / frame_height;;
pic.HorizontalScaleFactorforALTREF = (altref_frame_width << ANV_VP9_SCALE_FACTOR_SHIFT) / frame_width;
pic.VerticalScaleFactorforALTREF = (altref_frame_height << ANV_VP9_SCALE_FACTOR_SHIFT) / frame_height;;
pic.LastFrameWidth = last_frame_width == 0 ? 0 : last_frame_width - 1;
pic.LastFrameHeight = last_frame_height == 0 ? 0 : last_frame_height - 1;
pic.GoldenFrameWidth = golden_frame_width == 0 ? 0 : golden_frame_width - 1;
pic.GoldenFrameHeight = golden_frame_height == 0 ? 0 : golden_frame_height - 1;
pic.AltrefFrameWidth = altref_frame_width == 0 ? 0 : altref_frame_width - 1;
pic.AltrefFrameHeight = altref_frame_height == 0 ? 0 : altref_frame_height - 1;
}
}
vid->vp9_last_frame.frame_type = std_pic->frame_type;
vid->vp9_last_frame.width = frame_width;
vid->vp9_last_frame.height = frame_height;
vid->vp9_last_frame.key_frame = key_frame_or_intra_only;
vid->vp9_last_frame.show_frame = std_pic->flags.show_frame;
vid->vp9_last_frame.mv_in_turn = !vid->vp9_last_frame.mv_in_turn;
anv_batch_emit(&cmd_buffer->batch, GENX(HCP_BSD_OBJECT), bsd) {
bsd.IndirectBSDDataLength = frame_info->srcBufferRange - vp9_pic_info->compressedHeaderOffset;
bsd.IndirectBSDDataStartAddress = (frame_info->srcBufferOffset & 4095) + vp9_pic_info->compressedHeaderOffset;
}
#if GFX_VER >= 12
anv_batch_emit(&cmd_buffer->batch, GENX(VD_CONTROL_STATE), cs) {
cs.MemoryImplicitFlush = true;
}
#endif
anv_batch_emit(&cmd_buffer->batch, GENX(VD_PIPELINE_FLUSH), flush) {
flush.HEVCPipelineDone = true;
flush.HEVCPipelineCommandFlush = true;
flush.VDCommandMessageParserDone = true;
}
}
static void
handle_inline_query_end(struct anv_cmd_buffer *cmd_buffer,
const VkVideoInlineQueryInfoKHR *inline_query)
@ -2612,6 +3272,9 @@ genX(CmdDecodeVideoKHR)(VkCommandBuffer commandBuffer,
anv_av1_decode_video(cmd_buffer, frame_info);
break;
#endif
case VK_VIDEO_CODEC_OPERATION_DECODE_VP9_BIT_KHR:
anv_vp9_decode_video(cmd_buffer, frame_info);
break;
default:
assert(0);
}