Files
intel-hard-graphics/src/intel/vulkan_hasvk/genX_cmd_video.c
T

1006 lines
46 KiB
C

/*
* Copyright © 2021 Red Hat
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "anv_private.h"
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include "util/vl_zscan_data.h"
#include "genxml/gen_macros.h"
#include "genxml/genX_video_pack.h"
#include "anv_video_h264_slice.h"
static uint32_t
anv_h264_find_slice_nal(const uint8_t *buf, uint32_t off, uint32_t limit)
{
for (int pass = 0; pass < 2; pass++) {
if (off + 2 >= limit)
break;
uint32_t sc;
if (buf[off] == 0 && buf[off + 1] == 0 && buf[off + 2] == 1)
sc = 3;
else if (off + 3 < limit &&
buf[off] == 0 && buf[off + 1] == 0 &&
buf[off + 2] == 0 && buf[off + 3] == 1)
sc = 4;
else
break;
if (off + sc >= limit)
break;
/* Skip AUD and continue to scan. */
if ((buf[off + sc] & 0x1f) == 9) {
off += sc + 1;
while (off + 2 < limit) {
if (buf[off] == 0 && buf[off + 1] == 0 &&
(buf[off + 2] == 1 ||
(off + 3 < limit &&
buf[off + 2] == 0 && buf[off + 3] == 1)))
break;
off++;
}
continue;
}
return off + sc;
}
return off + 3;
}
/* With chroma_format_idc == 0 (monochrome) the luma is correct but the chroma
* is never written so fill it with 0x80 to avoid sampled garbage.
*/
static void
anv_video_init_neutral_chroma(struct anv_device *device,
const struct anv_image *img)
{
struct anv_image *mut_img = (struct anv_image *)img;
if (img->n_planes < 2 || mut_img->vid_neutral_chroma_init)
return;
const struct anv_image_memory_range *range =
&img->planes[1].primary_surface.memory_range;
struct anv_address addr = anv_image_address(img, range);
if (addr.bo == NULL)
return;
void *map = addr.bo->map;
bool mapped_here = false;
if (!map) {
if (anv_device_map_bo(device, addr.bo, 0, addr.bo->size,
0, &map) != VK_SUCCESS)
return;
mapped_here = true;
}
memset((uint8_t *)map + addr.offset, 0x80, range->size);
if (mapped_here)
anv_device_unmap_bo(device, addr.bo, map, addr.bo->size);
mut_img->vid_neutral_chroma_init = true;
}
void
genX(CmdBeginVideoCodingKHR) (VkCommandBuffer commandBuffer,
const VkVideoBeginCodingInfoKHR * pBeginInfo)
{
ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, commandBuffer);
ANV_FROM_HANDLE(anv_video_session, vid, pBeginInfo->videoSession);
ANV_FROM_HANDLE(anv_video_session_params, params,
pBeginInfo->videoSessionParameters);
cmd_buffer->video.vid = vid;
cmd_buffer->video.params = params;
}
void
genX(CmdControlVideoCodingKHR) (VkCommandBuffer commandBuffer,
const VkVideoCodingControlInfoKHR *
pCodingControlInfo)
{
}
void genX(CmdEndVideoCodingKHR) (VkCommandBuffer commandBuffer,
const VkVideoEndCodingInfoKHR *
pEndCodingInfo)
{
ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, commandBuffer);
#if GFX_VER == 8
anv_batch_emit(&cmd_buffer->batch, GENX(MI_FLUSH_DW), flush) {
flush.PostSyncOperation = 0;
}
#elif GFX_VER <= 75
anv_batch_emit(&cmd_buffer->batch, GENX(PIPE_CONTROL), pc) {
pc.CommandStreamerStallEnable = 1;
pc.StallAtPixelScoreboard = 1;
}
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_WAIT), wait) {
wait.MFXSyncControlFlag = 1;
}
#endif
cmd_buffer->video.vid = NULL;
cmd_buffer->video.params = NULL;
}
static inline void
anv_h264_sane_field_pocs(const int32_t poc[2], int32_t *top, int32_t *bottom)
{
int32_t t = poc[0], b = poc[1];
if (t == INT32_MAX) t = b;
if (b == INT32_MAX) b = t;
*top = t; *bottom = b;
}
static inline struct anv_address
anv_h264_dpb_addr(const struct anv_image_view *iv, uint32_t layer, bool clamp0)
{
if (clamp0)
return anv_image_address(iv->image,
&iv->image->planes[0].primary_surface.memory_range);
return anv_image_dpb_address(iv, layer);
}
static inline struct anv_address
anv_h264_dmv_top(const struct anv_image_view *iv, uint32_t layer, bool clamp0)
{
if (clamp0)
return anv_image_address(iv->image, &iv->image->vid_dmv_top_surface);
return anv_image_dmv_top_address(iv, layer);
}
static inline struct anv_address
anv_h264_dmv_bottom(const struct anv_image_view *iv, uint32_t layer, bool clamp0)
{
if (clamp0)
return anv_image_address(iv->image, &iv->image->vid_dmv_bottom_surface);
return anv_image_dmv_bottom_address(iv, layer);
}
static void
anv_h264_decode_video(struct anv_cmd_buffer *cmd_buffer,
const VkVideoDecodeInfoKHR *frame_info)
{
/*
* Build a remapping table from Vulkan DPB slot index to hardware slot index
* (0-15). Some streams assign DPB slot indices >= 16 but the hardware only
* supports 16 frame-store entries, so we transparently redirect high slot
* indices onto unused low ones.
*/
int8_t slot_to_hw[64];
memset(slot_to_hw, -1, sizeof(slot_to_hw));
{
bool used[16] = {};
for (uint32_t i = 0; i < frame_info->referenceSlotCount; i++) {
int s = frame_info->pReferenceSlots[i].slotIndex;
if (s >= 0 && s < 16) {
used[s] = true;
slot_to_hw[s] = (int8_t)s;
}
}
int next_free = 0;
for (uint32_t i = 0; i < frame_info->referenceSlotCount; i++) {
int s = frame_info->pReferenceSlots[i].slotIndex;
if (s >= 16 && s < 64) {
while (next_free < 16 && used[next_free])
next_free++;
if (next_free < 16) {
slot_to_hw[s] = (int8_t)next_free;
used[next_free++] = true;
} else {
mesa_logw_once("Too many simultaneous H.264 DPB references - dropping.");
}
}
}
}
ANV_FROM_HANDLE(anv_buffer, src_buffer, frame_info->srcBuffer);
struct anv_video_session *vid = cmd_buffer->video.vid;
struct anv_video_session_params *params = cmd_buffer->video.params;
const struct VkVideoDecodeH264PictureInfoKHR *h264_pic_info =
vk_find_struct_const(frame_info->pNext, VIDEO_DECODE_H264_PICTURE_INFO_KHR);
const StdVideoH264SequenceParameterSet *sps;
const StdVideoH264PictureParameterSet *pps;
vk_video_get_h264_parameters(&vid->vk, params ? &params->vk : NULL, frame_info, h264_pic_info, &sps, &pps);
anv_batch_emit(&cmd_buffer->batch, GENX(MI_FLUSH_DW), flush) {
flush.VideoPipelineCacheInvalidate = 1;
};
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_PIPE_MODE_SELECT), sel) {
sel.StandardSelect = SS_AVC;
sel.CodecSelect = Decode;
sel.DecoderShortFormatMode = LongFormatDriverInterface;
sel.PreDeblockingOutputEnable = false;
sel.PostDeblockingOutputEnable = true;
sel.DecoderModeSelect = VLDMode;
}
const struct anv_image_view *iv = anv_image_view_from_handle(frame_info->dstPictureResource.imageViewBinding);
const struct anv_image *img = iv->image;
#if GFX_VER < 8
const bool gen7_layered_clamp =
img->vk.array_layers > 1 && !img->vid_layered_interleaved;
if (gen7_layered_clamp)
mesa_logw_once("Layered DPB is broken on GFX 7 when the array pitch is not tile aligned.");
#else
const bool gen7_layered_clamp = false;
#endif
if (ANV_DEBUG(VIDEO_DEBUG)) {
const StdVideoDecodeH264PictureInfo *p = h264_pic_info->pStdPictureInfo;
mesa_logi("f_num=%d poc=%d/%d field=%u bot=%u idr=%u ref=%u "
"slices=%u refs=%u dst_layer=%u img=%p layers=%u",
p->frame_num, p->PicOrderCnt[0], p->PicOrderCnt[1],
p->flags.field_pic_flag, p->flags.bottom_field_flag,
p->flags.IdrPicFlag, p->flags.is_reference,
h264_pic_info->sliceCount, frame_info->referenceSlotCount,
frame_info->dstPictureResource.baseArrayLayer,
(void *)img, img->vk.array_layers);
for (uint32_t i = 0; i < frame_info->referenceSlotCount; i++) {
const struct anv_image_view *r =
anv_image_view_from_handle(frame_info->pReferenceSlots[i].pPictureResource->imageViewBinding);
mesa_logi("ref[%u] slot=%d layer=%u img=%p same_as_dst=%d",
i, frame_info->pReferenceSlots[i].slotIndex,
frame_info->pReferenceSlots[i].pPictureResource->baseArrayLayer,
(void *)r->image, r->image == img);
}
}
/* Conceal as gray in the "non-existing" case. */
anv_video_init_neutral_chroma(cmd_buffer->device, img);
for (uint32_t i = 0; i < frame_info->referenceSlotCount; i++) {
const struct anv_image_view *ref_iv =
anv_image_view_from_handle(frame_info->pReferenceSlots[i].pPictureResource->imageViewBinding);
anv_video_init_neutral_chroma(cmd_buffer->device, ref_iv->image);
}
uint32_t frame_width_mbs = sps->pic_width_in_mbs_minus1 + 1;
uint32_t frame_height_mbs = sps->pic_height_in_map_units_minus1 + 1;
if (!sps->flags.frame_mbs_only_flag)
frame_height_mbs *= 2;
if (frame_width_mbs > 256 || frame_height_mbs > 255)
mesa_logw_once("Frame %ux%u MBs exceeds hardware limits - clamping.",
frame_width_mbs, frame_height_mbs);
frame_width_mbs = MIN2(frame_width_mbs, 256u);
frame_height_mbs = MIN2(frame_height_mbs, 255u);
uint32_t y_cb_offset =
(img->planes[1].primary_surface.memory_range.offset -
img->planes[0].primary_surface.memory_range.offset) /
img->planes[0].primary_surface.isl.row_pitch_B;
if (ANV_DEBUG(VIDEO_DEBUG)) {
mesa_logi("dst extent=%ux%u tiling=%u pitch=%u "
"plane0_off=%"PRIu64" plane1_off=%"PRIu64" phys_h=%u y_cb_offset=%u\n",
img->vk.extent.width, img->vk.extent.height,
img->planes[0].primary_surface.isl.tiling,
img->planes[0].primary_surface.isl.row_pitch_B,
img->planes[0].primary_surface.memory_range.offset,
img->planes[1].primary_surface.memory_range.offset,
img->planes[0].primary_surface.isl.phys_level0_sa.h,
y_cb_offset);
}
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_SURFACE_STATE), ss) {
ss.Width = img->vk.extent.width - 1;
ss.Height = frame_height_mbs * 16 - 1;
ss.SurfaceFormat = PLANAR_420_8;
ss.InterleaveChroma = 1;
ss.SurfacePitch = img->planes[0].primary_surface.isl.row_pitch_B - 1;
ss.TiledSurface = img->planes[0].primary_surface.isl.tiling != ISL_TILING_LINEAR;
ss.TileWalk = TW_YMAJOR;
ss.YOffsetforUCb = MIN2(y_cb_offset, 32767u);
ss.YOffsetforVCr = 0;
}
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_PIPE_BUF_ADDR_STATE), buf) {
memset(buf.ReferencePictureAddress, 0, sizeof(buf.ReferencePictureAddress));
#if GFX_VERx10 == 70
memset(buf.ReferencePictureArbitrationPriorityControl, 0, sizeof(buf.ReferencePictureArbitrationPriorityControl));
memset(buf.ReferencePictureGraphicsDataType, 0, sizeof(buf.ReferencePictureGraphicsDataType));
memset(buf.ReferencePictureCacheabilityControl, 0, sizeof(buf.ReferencePictureCacheabilityControl));
#elif GFX_VERx10 == 75
memset(buf.ReferencePictureMOCS, 0, sizeof(buf.ReferencePictureMOCS));
#endif
memset(&buf, 0, sizeof(buf));
buf.DWordLength = GENX(MFX_PIPE_BUF_ADDR_STATE_length) - 2;
buf.SubOpcodeB = 2;
buf.Pipeline = 2;
buf.CommandType = 3;
struct anv_address dst_addr =
anv_h264_dpb_addr(iv, frame_info->dstPictureResource.baseArrayLayer, gen7_layered_clamp);
#if GFX_VERx10 == 70
buf.PostDeblockingDestinationAddress = dst_addr;
buf.PostDeblockingDestinationCacheabilityControl = 2;
#else
buf.PostDeblockingDestinationAddress = dst_addr;
buf.PreDeblockingDestinationMOCS = anv_mocs(cmd_buffer->device, buf.PreDeblockingDestinationAddress.bo, 0);
buf.PostDeblockingDestinationMOCS = anv_mocs(cmd_buffer->device, buf.PostDeblockingDestinationAddress.bo, 0);
buf.OriginalUncompressedPictureSourceMOCS = anv_mocs(cmd_buffer->device, NULL, 0);
buf.StreamOutDataDestinationMOCS = anv_mocs(cmd_buffer->device, NULL, 0);
#endif
#if GFX_VER == 8
buf.IntraRowStoreScratchBufferAddressHigh = (struct anv_address) { vid->vid_mem[ANV_VID_MEM_H264_INTRA_ROW_STORE].mem->bo,
vid->vid_mem[ANV_VID_MEM_H264_INTRA_ROW_STORE].offset };
buf.IntraRowStoreScratchBufferMOCS = anv_mocs(cmd_buffer->device, buf.IntraRowStoreScratchBufferAddressHigh.bo, 0);
buf.DeblockingFilterRowStoreScratchAddressHigh = (struct anv_address) { vid->vid_mem[ANV_VID_MEM_H264_DEBLOCK_FILTER_ROW_STORE].mem->bo,
vid->vid_mem[ANV_VID_MEM_H264_DEBLOCK_FILTER_ROW_STORE].offset };
buf.DeblockingFilterRowStoreScratchMOCS = anv_mocs(cmd_buffer->device, buf.DeblockingFilterRowStoreScratchAddressHigh.bo, 0);
buf.MBStatusBufferMOCS = anv_mocs(cmd_buffer->device, NULL, 0);
buf.MBILDBStreamOutBufferMOCS = anv_mocs(cmd_buffer->device, NULL, 0);
#else
buf.IntraRowStoreScratchBufferAddress = (struct anv_address) { vid->vid_mem[ANV_VID_MEM_H264_INTRA_ROW_STORE].mem->bo,
vid->vid_mem[ANV_VID_MEM_H264_INTRA_ROW_STORE].offset };
#if GFX_VERx10 == 70
buf.IntraRowStoreScratchBufferCacheabilityControl = 2;
#elif GFX_VERx10 >= 75
buf.IntraRowStoreScratchBufferMOCS = anv_mocs(cmd_buffer->device, vid->vid_mem[ANV_VID_MEM_H264_INTRA_ROW_STORE].mem->bo, 0);
#endif
#if GFX_VERx10 == 70
buf.DeblockingFilterRowStoreScratchBufferAddress =
(struct anv_address) { vid->vid_mem[ANV_VID_MEM_H264_DEBLOCK_FILTER_ROW_STORE].mem->bo, vid->vid_mem[ANV_VID_MEM_H264_DEBLOCK_FILTER_ROW_STORE].offset };
buf.DeblockingFilterRowStoreScratchBufferCacheabilityControl = 2;
#else
buf.DeblockingFilterRowStoreScratchAddress =
(struct anv_address) { vid->vid_mem[ANV_VID_MEM_H264_DEBLOCK_FILTER_ROW_STORE].mem->bo, vid->vid_mem[ANV_VID_MEM_H264_DEBLOCK_FILTER_ROW_STORE].offset };
buf.DeblockingFilterRowStoreScratchMOCS = anv_mocs(cmd_buffer->device, vid->vid_mem[ANV_VID_MEM_H264_DEBLOCK_FILTER_ROW_STORE].mem->bo, 0);
buf.MBStatusBufferMOCS = anv_mocs(cmd_buffer->device, NULL, 0);
buf.MBILDBStreamOutBufferMOCS = anv_mocs(cmd_buffer->device, NULL, 0);
#endif
#endif
#if GFX_VERx10 == 80
struct anv_bo *ref_bo = NULL;
#endif
for (unsigned i = 0; i < frame_info->referenceSlotCount; i++) {
int s = frame_info->pReferenceSlots[i].slotIndex;
int hw = (s >= 0 && s < 64) ? (int)slot_to_hw[s] : -1;
if (hw < 0)
continue;
const struct anv_image_view *ref_iv = anv_image_view_from_handle(frame_info->pReferenceSlots[i].pPictureResource->imageViewBinding);
struct anv_address ref_addr =
anv_h264_dpb_addr(ref_iv,
frame_info->pReferenceSlots[i].pPictureResource->baseArrayLayer,
gen7_layered_clamp);
buf.ReferencePictureAddress[hw] = ref_addr;
#if GFX_VERx10 == 70
buf.ReferencePictureCacheabilityControl[hw] = 2;
#elif GFX_VERx10 == 75
buf.ReferencePictureMOCS[hw] = anv_mocs(cmd_buffer->device, ref_addr.bo, 0);
#endif
#if GFX_VERx10 == 80
if (i == 0)
ref_bo = ref_iv->image->bindings[0].address.bo;
#endif
}
#if GFX_VERx10 == 80
buf.ReferencePictureMOCS = anv_mocs(cmd_buffer->device, ref_bo, 0);
#endif
}
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_IND_OBJ_BASE_ADDR_STATE), index_obj) {
index_obj.MFXIndirectBitstreamObjectAddress = anv_address_add(src_buffer->address,
frame_info->srcBufferOffset & ~4095);
#if GFX_VERx10 == 70
index_obj.MFXIndirectBitstreamObjectCacheabilityControl = 2;
#elif GFX_VERx10 == 75
index_obj.MFXIndirectBitstreamObjectMOCS = anv_mocs(cmd_buffer->device, src_buffer->address.bo,
0);
index_obj.MFXIndirectMVObjectMOCS = anv_mocs(cmd_buffer->device, NULL, 0);
index_obj.MFDIndirectITCOEFFObjectMOCS = anv_mocs(cmd_buffer->device, NULL, 0);
index_obj.MFDIndirectITDBLKObjectMOCS = anv_mocs(cmd_buffer->device, NULL, 0);
index_obj.MFCIndirectPAKBSEObjectMOCS = anv_mocs(cmd_buffer->device, NULL, 0);
#endif
#if GFX_VER == 7
index_obj.MFXIndirectBitstreamObjectAccessUpperBound = (struct anv_address) { NULL, 0x80000000 };
#endif
}
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_BSP_BUF_BASE_ADDR_STATE), bsp) {
bsp.BSDMPCRowStoreScratchBufferAddress = (struct anv_address) { vid->vid_mem[ANV_VID_MEM_H264_BSD_MPC_ROW_SCRATCH].mem->bo,
vid->vid_mem[ANV_VID_MEM_H264_BSD_MPC_ROW_SCRATCH].offset };
#if GFX_VERx10 == 70
bsp.BSDMPCRowStoreScratchBufferCacheabilityControl = 2;
#elif GFX_VERx10 == 75
bsp.BSDMPCRowStoreScratchBufferMOCS = anv_mocs(cmd_buffer->device, vid->vid_mem[ANV_VID_MEM_H264_BSD_MPC_ROW_SCRATCH].mem->bo, 0);
#endif
bsp.MPRRowStoreScratchBufferAddress = (struct anv_address) { vid->vid_mem[ANV_VID_MEM_H264_MPR_ROW_SCRATCH].mem->bo,
vid->vid_mem[ANV_VID_MEM_H264_MPR_ROW_SCRATCH].offset };
#if GFX_VERx10 == 70
bsp.MPRRowStoreScratchBufferCacheabilityControl = 2;
#elif GFX_VERx10 == 75
bsp.MPRRowStoreScratchBufferMOCS = anv_mocs(cmd_buffer->device, vid->vid_mem[ANV_VID_MEM_H264_MPR_ROW_SCRATCH].mem->bo, 0);
bsp.BitplaneReadBufferMOCS = anv_mocs(cmd_buffer->device, NULL, 0);
#endif
}
#if GFX_VERx10 >= 75
anv_batch_emit(&cmd_buffer->batch, GENX(MFD_AVC_PICID_STATE), picid) {
picid.PictureIDRemappingDisable = true;
}
#endif
if (pps->chroma_qp_index_offset < -12 || pps->chroma_qp_index_offset > 12 ||
pps->second_chroma_qp_index_offset < -12 ||
pps->second_chroma_qp_index_offset > 12 ||
pps->pic_init_qp_minus26 < -26 || pps->pic_init_qp_minus26 > 25 ||
sps->log2_max_frame_num_minus4 > 12 ||
sps->log2_max_pic_order_cnt_lsb_minus4 > 12) {
mesa_logw_once("Out of range H.264 SPS/PPS parameter "
"(sps_id=%u pps_id=%u chroma_qp=%d/%d init_qp_m26=%d "
"log2_frame=%u log2_poc=%u) - clamping.",
pps->seq_parameter_set_id, pps->pic_parameter_set_id,
pps->chroma_qp_index_offset,
pps->second_chroma_qp_index_offset,
pps->pic_init_qp_minus26, sps->log2_max_frame_num_minus4,
sps->log2_max_pic_order_cnt_lsb_minus4);
}
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_AVC_IMG_STATE), avc_img) {
avc_img.FrameWidth = MIN2(frame_width_mbs - 1, 255u);
avc_img.FrameHeight = MIN2(frame_height_mbs - 1, 254u);
avc_img.FrameSize = frame_width_mbs * frame_height_mbs;
if (!h264_pic_info->pStdPictureInfo->flags.field_pic_flag)
avc_img.ImageStructure = FramePicture;
else if (h264_pic_info->pStdPictureInfo->flags.bottom_field_flag)
avc_img.ImageStructure = BottomFieldPicture;
else
avc_img.ImageStructure = TopFieldPicture;
avc_img.WeightedBiPredictionIDC = pps->weighted_bipred_idc;
avc_img.WeightedPredictionEnable = pps->flags.weighted_pred_flag;
avc_img.FirstChromaQPOffset = CLAMP(pps->chroma_qp_index_offset, -12, 12);
avc_img.SecondChromaQPOffset = CLAMP(pps->second_chroma_qp_index_offset, -12, 12);
avc_img.FieldPicture = h264_pic_info->pStdPictureInfo->flags.field_pic_flag;
avc_img.MBAFFMode = (sps->flags.mb_adaptive_frame_field_flag &&
!h264_pic_info->pStdPictureInfo->flags.field_pic_flag);
avc_img.FrameMBOnly = sps->flags.frame_mbs_only_flag;
avc_img._8x8IDCTTransformMode = pps->flags.transform_8x8_mode_flag;
avc_img.Direct8x8Inference = sps->flags.direct_8x8_inference_flag;
avc_img.ConstrainedIntraPrediction = pps->flags.constrained_intra_pred_flag;
avc_img.NonReferencePicture = !h264_pic_info->pStdPictureInfo->flags.is_reference;
avc_img.EntropyCodingSyncEnable = pps->flags.entropy_coding_mode_flag;
avc_img.ChromaFormatIDC = sps->chroma_format_idc;
avc_img.TrellisQuantizationChromaDisable = true;
avc_img.NumberofReferenceFrames = MIN2(frame_info->referenceSlotCount, 16u);
avc_img.NumberofActiveReferencePicturesfromL0 = pps->num_ref_idx_l0_default_active_minus1 + 1;
avc_img.NumberofActiveReferencePicturesfromL1 = pps->num_ref_idx_l1_default_active_minus1 + 1;
avc_img.InitialQPValue = CLAMP(pps->pic_init_qp_minus26, -26, 25);
avc_img.PicOrderPresent = pps->flags.bottom_field_pic_order_in_frame_present_flag;
avc_img.DeltaPicOrderAlwaysZero = sps->flags.delta_pic_order_always_zero_flag;
avc_img.PicOrderCountType = sps->pic_order_cnt_type;
avc_img.DeblockingFilterControlPresent = pps->flags.deblocking_filter_control_present_flag;
avc_img.RedundantPicCountPresent = pps->flags.redundant_pic_cnt_present_flag;
avc_img.Log2MaxFrameNumber = MIN2((uint32_t)sps->log2_max_frame_num_minus4, 12u);
avc_img.Log2MaxPicOrderCountLSB = MIN2((uint32_t)sps->log2_max_pic_order_cnt_lsb_minus4, 12u);
avc_img.CurrentPictureFrameNumber = h264_pic_info->pStdPictureInfo->frame_num;
}
if (ANV_DEBUG(VIDEO_DEBUG) &&
h264_pic_info->pStdPictureInfo->flags.field_pic_flag) {
const StdVideoDecodeH264PictureInfo *p = h264_pic_info->pStdPictureInfo;
mesa_logi("field_pic=%u bottom=%u mb_adaptive=%u frame_mbs_only=%u "
"mbaff_frame_flag=%u width_mbs=%u height_mbs=%u chroma_idc=%u entropy=%u "
"8x8=%u chroma_qp=%d/%d init_qp_m26=%d wp=%u wbi=%u frame_num=%u poc=%d/%d "
"constr_intra=%u num_ref=%u nact_l0=%u nact_l1=%u",
p->flags.field_pic_flag, p->flags.bottom_field_flag,
sps->flags.mb_adaptive_frame_field_flag, sps->flags.frame_mbs_only_flag,
(unsigned)(sps->flags.mb_adaptive_frame_field_flag && !p->flags.field_pic_flag),
frame_width_mbs, frame_height_mbs, sps->chroma_format_idc,
pps->flags.entropy_coding_mode_flag, pps->flags.transform_8x8_mode_flag,
pps->chroma_qp_index_offset, pps->second_chroma_qp_index_offset,
pps->pic_init_qp_minus26, pps->flags.weighted_pred_flag,
pps->weighted_bipred_idc, p->frame_num,
p->PicOrderCnt[0], p->PicOrderCnt[1],
pps->flags.constrained_intra_pred_flag,
frame_info->referenceSlotCount,
pps->num_ref_idx_l0_default_active_minus1 + 1,
pps->num_ref_idx_l1_default_active_minus1 + 1);
}
StdVideoH264ScalingLists scaling_lists;
vk_video_derive_h264_scaling_list(sps, pps, &scaling_lists);
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_QM_STATE), qm) {
qm.DWordLength = 16;
qm.AVC = AVC_4x4_Intra_MATRIX;
for (unsigned m = 0; m < 3; m++)
for (unsigned q = 0; q < 16; q++)
qm.ForwardQuantizerMatrix[m * 16 + vl_zscan_normal_16[q]] =
scaling_lists.ScalingList4x4[m][q];
}
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_QM_STATE), qm) {
qm.DWordLength = 16;
qm.AVC = AVC_4x4_Inter_MATRIX;
for (unsigned m = 0; m < 3; m++)
for (unsigned q = 0; q < 16; q++)
qm.ForwardQuantizerMatrix[m * 16 + vl_zscan_normal_16[q]] =
scaling_lists.ScalingList4x4[m + 3][q];
}
if (pps->flags.transform_8x8_mode_flag) {
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_QM_STATE), qm) {
qm.DWordLength = 16;
qm.AVC = AVC_8x8_Intra_MATRIX;
for (unsigned q = 0; q < 64; q++)
qm.ForwardQuantizerMatrix[vl_zscan_normal[q]] =
scaling_lists.ScalingList8x8[0][q];
}
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_QM_STATE), qm) {
qm.DWordLength = 16;
qm.AVC = AVC_8x8_Inter_MATRIX;
for (unsigned q = 0; q < 64; q++)
qm.ForwardQuantizerMatrix[vl_zscan_normal[q]] =
scaling_lists.ScalingList8x8[1][q];
}
}
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
struct anv_bo *dmv_bo = NULL;
#pragma GCC diagnostic pop
const uint8_t *bs_map = src_buffer->address.bo->map;
bool bs_mapped_here = false;
if (!bs_map) {
void *tmp = NULL;
if (anv_device_map_bo(cmd_buffer->device,
src_buffer->address.bo,
0, src_buffer->address.bo->size,
0, &tmp) == VK_SUCCESS) {
bs_map = (const uint8_t *)tmp;
bs_mapped_here = true;
}
}
uint32_t mb_width = sps->pic_width_in_mbs_minus1 + 1;
uint32_t pic_height_in_map_units = sps->pic_height_in_map_units_minus1 + 1;
uint32_t mb_height = sps->flags.frame_mbs_only_flag ?
pic_height_in_map_units : pic_height_in_map_units * 2;
/* Slice vertical positions are expressed in macroblock rows.
* Under MBAFF first_mb_in_slice addresses a macroblock pair, so the true MB
* row is (first_mb_in_slice / mb_width) * 2 while the column is unchanged.
*/
bool field_pic = h264_pic_info->pStdPictureInfo->flags.field_pic_flag;
bool mbaff = sps->flags.mb_adaptive_frame_field_flag && !field_pic;
uint32_t pic_height_mbs = field_pic ? (mb_height / 2) : mb_height;
struct anv_h264_slice_params *sp =
calloc(h264_pic_info->sliceCount, sizeof(*sp));
if (sp) {
for (unsigned s = 0; s < h264_pic_info->sliceCount; s++) {
uint32_t slice_off = h264_pic_info->pSliceOffsets[s];
uint32_t buf_end = (s + 1 < h264_pic_info->sliceCount) ?
h264_pic_info->pSliceOffsets[s + 1] :
frame_info->srcBufferRange;
uint32_t bo_base = frame_info->srcBufferOffset & ~4095u;
uint32_t page_off = frame_info->srcBufferOffset & 4095u;
uint32_t bo_nalu = bs_map ?
anv_h264_find_slice_nal(bs_map + bo_base,
page_off + slice_off,
page_off + buf_end) :
page_off + slice_off + 3;
uint32_t nalu_size = (page_off + buf_end > bo_nalu) ?
(page_off + buf_end - bo_nalu) : 0;
bool ok = false;
if (bs_map && nalu_size > 0 &&
bo_base + bo_nalu + nalu_size <= src_buffer->address.bo->size) {
ok = anv_h264_parse_slice_header(
bs_map + bo_base, bo_nalu, nalu_size,
sps, pps, h264_pic_info,
frame_info->referenceSlotCount,
frame_info->pReferenceSlots,
&sp[s]);
}
if (!ok) {
memset(&sp[s], 0, sizeof(sp[s]));
sp[s].slice_type = ANV_H264_SLICE_I;
sp[s].first_mb_in_slice = 0;
sp[s].num_ref_idx_l0_active_minus1 =
pps->num_ref_idx_l0_default_active_minus1;
sp[s].num_ref_idx_l1_active_minus1 =
pps->num_ref_idx_l1_default_active_minus1;
memset(sp[s].ref_list0, ANV_H264_INVALID_SLOT,
sizeof(sp[s].ref_list0));
memset(sp[s].ref_list1, ANV_H264_INVALID_SLOT,
sizeof(sp[s].ref_list1));
}
sp[s].parse_ok = ok;
}
}
uint32_t buffer_offset = frame_info->srcBufferOffset & 4095;
#define HEADER_OFFSET 3
for (unsigned s = 0; s < h264_pic_info->sliceCount; s++) {
bool last_slice = s == (h264_pic_info->sliceCount - 1);
uint32_t current_offset = h264_pic_info->pSliceOffsets[s];
uint32_t this_end;
if (!last_slice) {
this_end = h264_pic_info->pSliceOffsets[s + 1];
} else {
this_end = frame_info->srcBufferRange;
}
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_AVC_DIRECTMODE_STATE), avc_directmode) {
for (unsigned i = 0; i < frame_info->referenceSlotCount; i++) {
int s = frame_info->pReferenceSlots[i].slotIndex;
int hw = (s >= 0 && s < 64) ? (int)slot_to_hw[s] : -1;
if (hw < 0)
continue;
const struct VkVideoDecodeH264DpbSlotInfoKHR *dpb_slot =
vk_find_struct_const(frame_info->pReferenceSlots[i].pNext, VIDEO_DECODE_H264_DPB_SLOT_INFO_KHR);
const struct anv_image_view *ref_iv = anv_image_view_from_handle(frame_info->pReferenceSlots[i].pPictureResource->imageViewBinding);
const StdVideoDecodeH264ReferenceInfo *ref_info = dpb_slot->pStdReferenceInfo;
uint32_t ref_layer =
frame_info->pReferenceSlots[i].pPictureResource->baseArrayLayer;
if (i == 0)
dmv_bo = anv_h264_dmv_top(ref_iv, ref_layer, gen7_layered_clamp).bo;
#if GFX_VERx10 == 70
{
bool ref_is_field = ref_info &&
(ref_info->flags.top_field_flag ^ ref_info->flags.bottom_field_flag);
bool ref_dmv_bottom = ref_is_field &&
!sps->flags.direct_8x8_inference_flag;
avc_directmode.DirectMVBufferAddress[hw * 2] =
anv_h264_dmv_top(ref_iv, ref_layer, gen7_layered_clamp);
avc_directmode.DirectMVBufferAddress[hw * 2 + 1] = ref_dmv_bottom ?
anv_h264_dmv_bottom(ref_iv, ref_layer, gen7_layered_clamp) :
anv_h264_dmv_top(ref_iv, ref_layer, gen7_layered_clamp);
}
avc_directmode.DirectMVBufferCacheabilityControl[hw * 2] = 2;
avc_directmode.DirectMVBufferCacheabilityControl[hw * 2 + 1] = 2;
#elif GFX_VERx10 == 75
{
struct anv_address dmv_addr = anv_h264_dmv_top(ref_iv, ref_layer, gen7_layered_clamp);
if (hw == 0) {
avc_directmode.DirectMVBuffer0Address = dmv_addr;
avc_directmode.DirectMVBufferMOCS = anv_mocs(cmd_buffer->device, dmv_addr.bo, 0);
} else {
avc_directmode.DirectMVBufferAddress1[hw - 1] = dmv_addr;
avc_directmode.DirectMVBufferMOCS1[hw - 1] = anv_mocs(cmd_buffer->device, dmv_addr.bo, 0);
}
}
#elif GFX_VERx10 == 80
avc_directmode.DirectMVBufferAddress[hw] = anv_h264_dmv_top(ref_iv, ref_layer, gen7_layered_clamp);
#endif
{
int32_t ref_top, ref_bot;
anv_h264_sane_field_pocs(ref_info->PicOrderCnt, &ref_top, &ref_bot);
avc_directmode.POCList[2 * hw] = ref_top;
avc_directmode.POCList[2 * hw + 1] = ref_bot;
}
}
uint32_t dst_layer = frame_info->dstPictureResource.baseArrayLayer;
#if GFX_VERx10 == 70
{
bool cur_dmv_bottom = field_pic && !sps->flags.direct_8x8_inference_flag;
avc_directmode.DirectMVBufferWriteAddress[0] =
anv_h264_dmv_top(iv, dst_layer, gen7_layered_clamp);
avc_directmode.DirectMVBufferWriteAddress[1] = cur_dmv_bottom ?
anv_h264_dmv_bottom(iv, dst_layer, gen7_layered_clamp) :
anv_h264_dmv_top(iv, dst_layer, gen7_layered_clamp);
}
avc_directmode.DirectMVBufferWriteCacheabilityControl[0] = 2;
avc_directmode.DirectMVBufferWriteCacheabilityControl[1] = 2;
#elif GFX_VERx10 == 75
avc_directmode.DirectMVBufferWriteAddress = anv_h264_dmv_top(iv, dst_layer, gen7_layered_clamp);
avc_directmode.DirectMVBufferWriteMOCS = anv_mocs(cmd_buffer->device, avc_directmode.DirectMVBufferWriteAddress.bo, 0);
if (!avc_directmode.DirectMVBufferMOCS)
avc_directmode.DirectMVBufferMOCS = anv_mocs(cmd_buffer->device, avc_directmode.DirectMVBufferWriteAddress.bo, 0);
#elif GFX_VERx10 == 80
avc_directmode.DirectMVBufferAttributes.TargetCache = 2; /* LLC/eLLC */
avc_directmode.DirectMVBufferWriteAddress = anv_h264_dmv_top(iv, dst_layer, gen7_layered_clamp);
avc_directmode.DirectMVBufferWriteAttributes.TargetCache = 2;
#endif
{
int32_t cur_top, cur_bot;
anv_h264_sane_field_pocs(h264_pic_info->pStdPictureInfo->PicOrderCnt,
&cur_top, &cur_bot);
avc_directmode.POCList[32] = cur_top;
avc_directmode.POCList[33] = cur_bot;
}
}
const struct anv_h264_slice_params *cur = sp ? &sp[s] : NULL;
for (unsigned list = 0; list <= 1; list++) {
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_AVC_REF_IDX_STATE), ref_idx) {
ref_idx.ReferencePictureListSelect = list;
const uint8_t *rl = (list == 0) ?
(cur ? cur->ref_list0 : NULL) :
(cur ? cur->ref_list1 : NULL);
const uint8_t *rlb = (list == 0) ?
(cur ? cur->ref_list0_bottom : NULL) :
(cur ? cur->ref_list1_bottom : NULL);
for (unsigned e = 0; e < 32; e++) {
uint8_t slot = (rl && e < ANV_H264_MAX_REF_FRAMES) ?
rl[e] : ANV_H264_INVALID_SLOT;
if (slot == ANV_H264_INVALID_SLOT) {
ref_idx.ReferenceListEntry[e] = 0xFF;
} else {
int8_t hw = (slot < 64) ? slot_to_hw[slot] : -1;
if (hw < 0) {
ref_idx.ReferenceListEntry[e] = 0xFF;
} else {
bool is_long = false, ref_top = false, ref_bottom_f = false;
for (uint32_t i = 0; i < frame_info->referenceSlotCount; i++) {
if (frame_info->pReferenceSlots[i].slotIndex == slot) {
const struct VkVideoDecodeH264DpbSlotInfoKHR *d =
vk_find_struct_const(frame_info->pReferenceSlots[i].pNext,
VIDEO_DECODE_H264_DPB_SLOT_INFO_KHR);
if (d && d->pStdReferenceInfo) {
is_long = d->pStdReferenceInfo->flags.used_for_long_term_reference ||
d->pStdReferenceInfo->flags.is_non_existing;
ref_top = d->pStdReferenceInfo->flags.top_field_flag;
ref_bottom_f = d->pStdReferenceInfo->flags.bottom_field_flag;
}
break;
}
}
if (field_pic && rlb && e < ANV_H264_MAX_REF_FRAMES) {
ref_bottom_f = rlb[e];
ref_top = !rlb[e];
}
bool ref_is_field = ref_top ^ ref_bottom_f;
bool ref_bottom = (!ref_top) & ref_bottom_f;
ref_idx.ReferenceListEntry[e] =
(is_long ? 0x40u : 0x00u) |
(ref_is_field ? 0x00u : 0x20u) |
((uint8_t)hw << 1) |
(ref_bottom ? 0x01u : 0x00u);
}
}
}
}
}
/* Emit MFX_AVC_WEIGHTOFFSET_STATE for both list 0 and list 1. */
bool is_b = cur && cur->slice_type == ANV_H264_SLICE_B;
bool need_w_l0 = cur &&
((pps->flags.weighted_pred_flag &&
(cur->slice_type == ANV_H264_SLICE_P ||
cur->slice_type == ANV_H264_SLICE_SP)) ||
(pps->weighted_bipred_idc == 1 && is_b));
bool need_w_l1 = pps->weighted_bipred_idc == 1 && is_b;
if (need_w_l0 || need_w_l1) {
for (unsigned list = 0; list <= 1; list++) {
if (list == 0 && !need_w_l0) continue;
if (list == 1 && !need_w_l1) continue;
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_AVC_WEIGHTOFFSET_STATE), wo) {
wo.WeightandOffsetSelect = list;
int active = (list == 0) ?
cur->num_ref_idx_l0_active_minus1 + 1 :
cur->num_ref_idx_l1_active_minus1 + 1;
if (active > ANV_H264_MAX_REF_FRAMES)
active = ANV_H264_MAX_REF_FRAMES;
for (int i = 0; i < 32; i++) {
int16_t lw = (i < active) ? ((list == 0) ? cur->luma_weight_l0[i] : cur->luma_weight_l1[i]) : 0;
int16_t lo = (i < active) ? ((list == 0) ? cur->luma_offset_l0[i] : cur->luma_offset_l1[i]) : 0;
int16_t cw0 = (i < active) ? ((list == 0) ? cur->chroma_weight_l0[i][0] : cur->chroma_weight_l1[i][0]) : 0;
int16_t co0 = (i < active) ? ((list == 0) ? cur->chroma_offset_l0[i][0] : cur->chroma_offset_l1[i][0]) : 0;
int16_t cw1 = (i < active) ? ((list == 0) ? cur->chroma_weight_l0[i][1] : cur->chroma_weight_l1[i][1]) : 0;
int16_t co1 = (i < active) ? ((list == 0) ? cur->chroma_offset_l0[i][1] : cur->chroma_offset_l1[i][1]) : 0;
wo.WeightOffset[i * 3 + 0] = ((uint32_t)(uint16_t)lo << 16) | (uint16_t)lw;
wo.WeightOffset[i * 3 + 1] = ((uint32_t)(uint16_t)co0 << 16) | (uint16_t)cw0;
wo.WeightOffset[i * 3 + 2] = ((uint32_t)(uint16_t)co1 << 16) | (uint16_t)cw1;
}
}
}
}
/* The "phantom slice" for error concealment. */
if (s == 0 && cur && cur->first_mb_in_slice != 0) {
uint32_t first_hor = cur->first_mb_in_slice % mb_width;
uint32_t first_ver = cur->first_mb_in_slice / mb_width;
if (mbaff)
first_ver <<= 1;
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_AVC_SLICE_STATE), phantom) {
phantom.SliceType = ISlice;
phantom.SliceStartMBNumber = 0;
phantom.SliceHorizontalPosition = 0;
phantom.SliceVerticalPosition = 0;
phantom.NextSliceHorizontalPosition = first_hor;
phantom.NextSliceVerticalPosition = first_ver;
phantom.SliceQuantizationParameter = (uint32_t)(pps->pic_init_qp_minus26 + 26);
phantom.LastSliceGroup = false;
}
anv_batch_emit(&cmd_buffer->batch, GENX(MFD_AVC_BSD_OBJECT), phantom_bsd) {
phantom_bsd.IndirectBSDDataLength = 0;
phantom_bsd.IndirectBSDDataStartAddress = 0;
phantom_bsd.InlineData.LastSlice = false;
phantom_bsd.InlineData.FixPrevMBSkipped = 1;
#if GFX_VERx10 >= 75
phantom_bsd.InlineData.IntraPredictionErrorControl = 1;
phantom_bsd.InlineData.Intra8x84x4PredictionErrorConcealmentControl = 1;
phantom_bsd.InlineData.ISliceConcealmentMode = 1;
#endif
}
}
{
int st = cur ? cur->slice_type : ANV_H264_SLICE_I;
uint32_t cur_fmb = cur ? (uint32_t)cur->first_mb_in_slice : 0;
uint32_t cur_hor = cur_fmb % mb_width;
uint32_t cur_ver = cur_fmb / mb_width;
if (mbaff)
cur_ver <<= 1;
uint32_t next_hor, next_ver;
if (last_slice || !sp) {
/* This value is already in MB rows, so it can't be doubled for MBAFF. */
next_hor = 0;
next_ver = pic_height_mbs;
} else {
uint32_t next_fmb = (uint32_t)sp[s + 1].first_mb_in_slice;
next_hor = next_fmb % mb_width;
next_ver = next_fmb / mb_width;
if (mbaff)
next_ver <<= 1;
if (next_ver >= pic_height_mbs) { next_hor = 0; next_ver = pic_height_mbs; }
}
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_AVC_SLICE_STATE), ss) {
ss.SliceType =
(st == ANV_H264_SLICE_P || st == ANV_H264_SLICE_SP) ? PSlice :
(st == ANV_H264_SLICE_B) ? BSlice :
ISlice;
bool implicit_bipred = (st == ANV_H264_SLICE_B &&
pps->weighted_bipred_idc == 2);
ss.Log2WeightDenominatorLuma = implicit_bipred ? 5 :
(cur ? CLAMP(cur->luma_log2_weight_denom, 0, 7) : 0);
ss.Log2WeightDenominatorChroma = implicit_bipred ? 5 :
(cur ? CLAMP(cur->chroma_log2_weight_denom, 0, 7) : 0);
ss.NumberofReferencePicturesinInterpredictionList0 =
(cur && st != ANV_H264_SLICE_I && st != ANV_H264_SLICE_SI) ?
MIN2((uint32_t)(cur->num_ref_idx_l0_active_minus1 + 1),
(uint32_t)ANV_H264_MAX_REF_FRAMES) : 0;
ss.NumberofReferencePicturesinInterpredictionList1 =
(cur && st == ANV_H264_SLICE_B) ?
MIN2((uint32_t)(cur->num_ref_idx_l1_active_minus1 + 1),
(uint32_t)ANV_H264_MAX_REF_FRAMES) : 0;
ss.SliceAlphaC0OffsetDiv2 = CLAMP(cur ? cur->slice_alpha_c0_offset_div2 : 0, -6, 6);
ss.SliceBetaOffsetDiv2 = CLAMP(cur ? cur->slice_beta_offset_div2 : 0, -6, 6);
ss.SliceQuantizationParameter =
(uint32_t)CLAMP((int)(pps->pic_init_qp_minus26 + 26 +
(cur ? cur->slice_qp_delta : 0)), 0, 51);
ss.CABACInitIDC = cur ? MIN2((uint32_t)cur->cabac_init_idc, 2u) : 0;
ss.DisableDeblockingFilterIndicator =
cur ? MIN2((uint32_t)cur->disable_deblocking_filter_idc, 2u) : 0;
ss.DirectPredictionType =
(cur && cur->direct_spatial_mv_pred_flag) ? Spatial : Temporal;
ss.WeightedPredictionIndicator =
(st == ANV_H264_SLICE_B) ? (uint32_t)pps->weighted_bipred_idc :
need_w_l0 ? 1u : 0u;
ss.SliceStartMBNumber = MIN2(cur_fmb, 32767u);
ss.SliceHorizontalPosition = MIN2(cur_hor, 255u);
ss.SliceVerticalPosition = MIN2(cur_ver, 255u);
ss.NextSliceHorizontalPosition = MIN2(next_hor, 255u);
ss.NextSliceVerticalPosition = MIN2(next_ver, 255u);
ss.LastSliceGroup = last_slice;
ss.SliceID = s & (uint32_t)((1u << 4) - 1);
}
if (ANV_DEBUG(VIDEO_DEBUG) && field_pic && cur) {
char l0[128] = {0}, l1[128] = {0};
for (int e = 0; e < 8; e++) {
char t[16];
snprintf(t, sizeof(t), "%d ", (int8_t)cur->ref_list0[e]);
strncat(l0, t, sizeof(l0) - strlen(l0) - 1);
snprintf(t, sizeof(t), "%d ", (int8_t)cur->ref_list1[e]);
strncat(l1, t, sizeof(l1) - strlen(l1) - 1);
}
mesa_logi("slice[%u]: type=%d first_mb=%u qp=%d cabac_init=%d "
"disable_dblk=%d spatial_direct=%d nref_l0=%d nref_l1=%d "
"hor=%u ver=%u next_hor=%u next_ver=%u last=%d | L0: %s| L1: %s",
s, st, cur_fmb,
(int)(pps->pic_init_qp_minus26 + 26 + cur->slice_qp_delta),
cur->cabac_init_idc, cur->disable_deblocking_filter_idc,
cur->direct_spatial_mv_pred_flag,
cur->num_ref_idx_l0_active_minus1 + 1,
cur->num_ref_idx_l1_active_minus1 + 1,
cur_hor, cur_ver, next_hor, next_ver, last_slice, l0, l1);
}
}
uint32_t bsd_nal = bs_map ?
anv_h264_find_slice_nal(
bs_map + (frame_info->srcBufferOffset & ~4095u),
buffer_offset + current_offset,
buffer_offset + this_end) :
buffer_offset + current_offset + HEADER_OFFSET;
anv_batch_emit(&cmd_buffer->batch, GENX(MFD_AVC_BSD_OBJECT), avc_bsd) {
/* Bound the bitstream object to this slice's data. */
avc_bsd.IndirectBSDDataLength = buffer_offset + this_end - bsd_nal;
avc_bsd.IndirectBSDDataStartAddress = bsd_nal;
avc_bsd.InlineData.LastSlice = last_slice;
avc_bsd.InlineData.FixPrevMBSkipped = 1;
avc_bsd.InlineData.MBHeaderErrorHandling = 1;
avc_bsd.InlineData.EntropyErrorHandling = 1;
avc_bsd.InlineData.MPRErrorHandling = 1;
avc_bsd.InlineData.BSDPrematureCompleteErrorHandling = 1;
avc_bsd.InlineData.IntraPredMode4x48x8LumaErrorControl = 1;
/* Initially I thought Ivy Bridge was incapable of doing short mode
* and loved to draw rainbows all day, but the more likely scenario
* was a fundamental breakdown here.
*/
if (cur) {
avc_bsd.InlineData.FirstMBByteOffsetofSliceDataorSliceHeader =
cur->first_mb_byte_offset;
avc_bsd.InlineData.FirstMBBitOffset = cur->first_mb_bit_offset;
}
#if GFX_VERx10 >= 75
avc_bsd.InlineData.IntraPredictionErrorControl = 1;
avc_bsd.InlineData.Intra8x84x4PredictionErrorConcealmentControl = 1;
avc_bsd.InlineData.ISliceConcealmentMode = 1;
#endif
}
}
free(sp);
if (bs_mapped_here)
anv_device_unmap_bo(cmd_buffer->device,
src_buffer->address.bo,
(void *)bs_map,
src_buffer->address.bo->size);
}
void
genX(CmdDecodeVideoKHR) (VkCommandBuffer commandBuffer,
const VkVideoDecodeInfoKHR * frame_info)
{
ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, commandBuffer);
if (!cmd_buffer->video.vid)
abort();
switch (cmd_buffer->video.vid->vk.op) {
case VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR:
anv_h264_decode_video(cmd_buffer, frame_info);
break;
default:
UNREACHABLE("Unsupported video codec operation!");
}
}