hasvk: add initial video decode support for h264.

This just adds the files with the programming info, it doesn't
enable the extensions etc

[dancingmirrors: A few forward port fixes.]
This commit is contained in:
Dave Airlie authored and elwrcl committed 2026-07-21 15:23:49 +03:00
1 parent 4d12fc3ec6
commit 1db147a9ce
4 files changed
+678

No files matched your search

+34
View File
@@ -88,6 +88,7 @@
#include "vk_queue.h"
#include "vk_log.h"
#include "vk_ycbcr_conversion.h"
#include "vk_video.h"
/* Pre-declarations needed for WSI entrypoints */
struct wl_surface;
@@ -2635,6 +2636,11 @@ struct anv_cmd_buffer {
*
*/
struct u_trace trace;
struct {
struct anv_video_session *vid;
struct anv_video_session_params *params;
} video;
};
extern const struct vk_command_buffer_ops anv_cmd_buffer_ops;
@@ -3700,9 +3706,35 @@ static inline uint32_t khr_perf_query_preamble_offset(const struct anv_query_poo
return pool->pass_size * pass + 8;
}
struct anv_vid_mem {
struct anv_device_memory *mem;
VkDeviceSize offset;
VkDeviceSize size;
};
#define ANV_VIDEO_MEM_REQS_H264 4
#define ANV_MB_WIDTH 16
#define ANV_MB_HEIGHT 16
enum {
ANV_VID_MEM_H264_INTRA_ROW_STORE,
ANV_VID_MEM_H264_DEBLOCK_FILTER_ROW_STORE,
ANV_VID_MEM_H264_BSD_MPC_ROW_SCRATCH,
ANV_VID_MEM_H264_MPR_ROW_SCRATCH,
ANV_VID_MEM_H264_MAX,
};
struct anv_video_session {
struct vk_video_session vk;
/* the decoder needs some private memory allocations */
struct anv_vid_mem vid_mem[ANV_VID_MEM_H264_MAX];
};
struct anv_video_session_params {
struct vk_video_session_parameters vk;
};
void
anv_dump_pipe_bits(enum anv_pipe_bits bits);
@@ -3832,6 +3864,8 @@ VK_DEFINE_NONDISP_HANDLE_CASTS(anv_sampler, base, VkSampler,
VK_DEFINE_NONDISP_HANDLE_CASTS(anv_performance_configuration_intel, base,
VkPerformanceConfigurationINTEL,
VK_OBJECT_TYPE_PERFORMANCE_CONFIGURATION_INTEL)
VK_DEFINE_NONDISP_HANDLE_CASTS(anv_video_session, vk.base, VkVideoSessionKHR, VK_OBJECT_TYPE_VIDEO_SESSION_KHR)
VK_DEFINE_NONDISP_HANDLE_CASTS(anv_video_session_params, vk.base, VkVideoSessionParametersKHR, VK_OBJECT_TYPE_VIDEO_SESSION_PARAMETERS_KHR)
#define anv_genX(devinfo, thing) ({ \
__typeof(&gfx7_##thing) genX_thing; \
+260
View File
@@ -0,0 +1,260 @@
/*
* 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 "vk_video/vulkan_video_codecs_common.h"
VkResult
anv_CreateVideoSessionKHR(VkDevice _device,
const VkVideoSessionCreateInfoKHR *pCreateInfo,
const VkAllocationCallbacks *pAllocator,
VkVideoSessionKHR *pVideoSession)
{
ANV_FROM_HANDLE(anv_device, device, _device);
struct anv_video_session *vid =
vk_alloc2(&device->vk.alloc, pAllocator, sizeof(*vid), 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
if (!vid)
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
memset(vid, 0, sizeof(struct anv_video_session));
VkResult result = vk_video_session_init(&device->vk,
&vid->vk,
pCreateInfo);
if (result != VK_SUCCESS) {
vk_free2(&device->vk.alloc, pAllocator, vid);
return result;
}
*pVideoSession = anv_video_session_to_handle(vid);
return VK_SUCCESS;
}
void
anv_DestroyVideoSessionKHR(VkDevice _device,
VkVideoSessionKHR _session,
const VkAllocationCallbacks *pAllocator)
{
ANV_FROM_HANDLE(anv_device, device, _device);
ANV_FROM_HANDLE(anv_video_session, vid, _session);
if (!_session)
return;
vk_object_base_finish(&vid->vk.base);
vk_free2(&device->vk.alloc, pAllocator, vid);
}
VkResult
anv_CreateVideoSessionParametersKHR(VkDevice _device,
const
VkVideoSessionParametersCreateInfoKHR
*pCreateInfo,
const VkAllocationCallbacks *pAllocator,
VkVideoSessionParametersKHR
*pVideoSessionParameters)
{
ANV_FROM_HANDLE(anv_device, device, _device);
struct vk_video_session_parameters *params =
vk_video_session_parameters_create(&device->vk, pCreateInfo, pAllocator,
sizeof(struct
anv_video_session_params));
if (!params)
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
*pVideoSessionParameters = vk_video_session_parameters_to_handle(params);
return VK_SUCCESS;
}
void
anv_DestroyVideoSessionParametersKHR(VkDevice _device,
VkVideoSessionParametersKHR _params,
const VkAllocationCallbacks *pAllocator)
{
ANV_FROM_HANDLE(anv_device, device, _device);
VK_FROM_HANDLE(vk_video_session_parameters, params, _params);
vk_video_session_parameters_destroy(&device->vk, pAllocator, params);
}
VkResult
anv_GetPhysicalDeviceVideoCapabilitiesKHR(VkPhysicalDevice physicalDevice,
const VkVideoProfileInfoKHR *pVideoProfile,
VkVideoCapabilitiesKHR *pCapabilities)
{
pCapabilities->minBitstreamBufferOffsetAlignment = 32;
pCapabilities->minBitstreamBufferSizeAlignment = 32;
pCapabilities->pictureAccessGranularity.width = ANV_MB_WIDTH;
pCapabilities->pictureAccessGranularity.height = ANV_MB_HEIGHT;
pCapabilities->minCodedExtent.width = ANV_MB_WIDTH;
pCapabilities->minCodedExtent.height = ANV_MB_HEIGHT;
pCapabilities->maxCodedExtent.width = 4096;
pCapabilities->maxCodedExtent.height = 4096;
pCapabilities->flags = VK_VIDEO_CAPABILITY_SEPARATE_REFERENCE_IMAGES_BIT_KHR;
struct VkVideoDecodeCapabilitiesKHR *dec_caps = (struct VkVideoDecodeCapabilitiesKHR *)
vk_find_struct(pCapabilities->pNext, VIDEO_DECODE_CAPABILITIES_KHR);
if (dec_caps)
dec_caps->flags = VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_COINCIDE_BIT_KHR;
switch (pVideoProfile->videoCodecOperation) {
case VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR: {
struct VkVideoDecodeH264CapabilitiesKHR *ext = (struct VkVideoDecodeH264CapabilitiesKHR *)
vk_find_struct(pCapabilities->pNext, VIDEO_DECODE_H264_CAPABILITIES_KHR);
pCapabilities->maxDpbSlots = 17;
pCapabilities->maxActiveReferencePictures = 16;
ext->fieldOffsetGranularity.x = 0;
ext->fieldOffsetGranularity.y = 0;
ext->maxLevelIdc = 51;
strcpy(pCapabilities->stdHeaderVersion.extensionName, VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_EXTENSION_NAME);
pCapabilities->stdHeaderVersion.specVersion = VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_SPEC_VERSION;
break;
}
default:
break;
}
return VK_SUCCESS;
}
VkResult
anv_GetPhysicalDeviceVideoFormatPropertiesKHR(VkPhysicalDevice physicalDevice,
const VkPhysicalDeviceVideoFormatInfoKHR *pVideoFormatInfo,
uint32_t *pVideoFormatPropertyCount,
VkVideoFormatPropertiesKHR *pVideoFormatProperties)
{
*pVideoFormatPropertyCount = 1;
if (!pVideoFormatProperties)
return VK_SUCCESS;
pVideoFormatProperties[0].format = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM;
pVideoFormatProperties[0].imageType = VK_IMAGE_TYPE_2D;
pVideoFormatProperties[0].imageTiling = VK_IMAGE_TILING_OPTIMAL;
pVideoFormatProperties[0].imageUsageFlags = pVideoFormatInfo->imageUsage;
return VK_SUCCESS;
}
static void
get_h264_video_session_mem_reqs(struct anv_video_session *vid,
VkVideoSessionMemoryRequirementsKHR *mem_reqs,
uint32_t memory_types)
{
uint32_t width_in_mb = align(vid->vk.max_coded.width, ANV_MB_WIDTH) / ANV_MB_WIDTH;
/* intra row store is width in macroblocks * 64 */
mem_reqs[0].memoryBindIndex = ANV_VID_MEM_H264_INTRA_ROW_STORE;
mem_reqs[0].memoryRequirements.size = width_in_mb * 64;
mem_reqs[0].memoryRequirements.alignment = 4096;
mem_reqs[0].memoryRequirements.memoryTypeBits = memory_types;
/* deblocking filter row store is width in macroblocks * 64 * 4*/
mem_reqs[1].memoryBindIndex = ANV_VID_MEM_H264_DEBLOCK_FILTER_ROW_STORE;
mem_reqs[1].memoryRequirements.size = width_in_mb * 64 * 4;
mem_reqs[1].memoryRequirements.alignment = 4096;
mem_reqs[1].memoryRequirements.memoryTypeBits = memory_types;
/* bsd mpc row scratch is width in macroblocks * 64 * 2 */
mem_reqs[2].memoryBindIndex = ANV_VID_MEM_H264_BSD_MPC_ROW_SCRATCH;
mem_reqs[2].memoryRequirements.size = width_in_mb * 64 * 2;
mem_reqs[2].memoryRequirements.alignment = 4096;
mem_reqs[2].memoryRequirements.memoryTypeBits = memory_types;
/* mpr row scratch is width in macroblocks * 64 * 2 */
mem_reqs[3].memoryBindIndex = ANV_VID_MEM_H264_MPR_ROW_SCRATCH;
mem_reqs[3].memoryRequirements.size = width_in_mb * 64 * 2;
mem_reqs[3].memoryRequirements.alignment = 4096;
mem_reqs[3].memoryRequirements.memoryTypeBits = memory_types;
}
VkResult
anv_GetVideoSessionMemoryRequirementsKHR(VkDevice _device,
VkVideoSessionKHR videoSession,
uint32_t *pVideoSessionMemoryRequirementsCount,
VkVideoSessionMemoryRequirementsKHR *mem_reqs)
{
ANV_FROM_HANDLE(anv_device, device, _device);
ANV_FROM_HANDLE(anv_video_session, vid, videoSession);
switch (vid->vk.op) {
case VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR:
*pVideoSessionMemoryRequirementsCount = ANV_VIDEO_MEM_REQS_H264;
break;
default:
UNREACHABLE("unknown codec");
}
if (!mem_reqs)
return VK_SUCCESS;
uint32_t memory_types = (1ull << device->physical->memory.type_count) - 1;
switch (vid->vk.op) {
case VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR:
get_h264_video_session_mem_reqs(vid, mem_reqs, memory_types);
break;
default:
UNREACHABLE("unknown codec");
}
return VK_SUCCESS;
}
VkResult
anv_UpdateVideoSessionParametersKHR(VkDevice _device,
VkVideoSessionParametersKHR _params,
const VkVideoSessionParametersUpdateInfoKHR *pUpdateInfo)
{
ANV_FROM_HANDLE(anv_video_session_params, params, _params);
return vk_video_session_parameters_update(&params->vk, pUpdateInfo);
}
static void
copy_bind(struct anv_vid_mem *dst,
const VkBindVideoSessionMemoryInfoKHR *src)
{
dst->mem = anv_device_memory_from_handle(src->memory);
dst->offset = src->memoryOffset;
dst->size = src->memorySize;
}
VkResult
anv_BindVideoSessionMemoryKHR(VkDevice _device,
VkVideoSessionKHR videoSession,
uint32_t bind_mem_count,
const VkBindVideoSessionMemoryInfoKHR *bind_mem)
{
ANV_FROM_HANDLE(anv_video_session, vid, videoSession);
assert(bind_mem_count == 4);
switch (vid->vk.op) {
case VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR:
for (unsigned i = 0; i < bind_mem_count; i++) {
copy_bind(&vid->vid_mem[bind_mem[i].memoryBindIndex], &bind_mem[i]);
break;
}
break;
default:
UNREACHABLE("unknown codec");
}
return VK_SUCCESS;
}
+382
View File
@@ -0,0 +1,382 @@
/*
* 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 "genxml/gen_macros.h"
#include "genxml/genX_video_pack.h"
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);
cmd_buffer->video.vid = NULL;
cmd_buffer->video.params = NULL;
}
static void
anv_h264_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;
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 = vk_video_find_h264_dec_std_sps(&params->vk, h264_pic_info->pStdPictureInfo->seq_parameter_set_id);
const StdVideoH264PictureParameterSet *pps = vk_video_find_h264_dec_std_pps(&params->vk, h264_pic_info->pStdPictureInfo->pic_parameter_set_id);
anv_batch_emit(&cmd_buffer->batch, GENX(MI_FLUSH_DW), flush) {
flush.DWordLength = 2;
flush.VideoPipelineCacheInvalidate = 1;
};
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_PIPE_MODE_SELECT), sel) {
sel.StandardSelect = SS_AVC;
sel.CodecSelect = Decode;
sel.DecoderShortFormatMode = ShortFormatDriverInterface;
sel.DecoderModeSelect = VLDMode; // Hardcoded
sel.PreDeblockingOutputEnable = 0;
sel.PostDeblockingOutputEnable = 1;
}
const struct anv_image_view *iv = anv_image_view_from_handle(frame_info->dstPictureResource.imageViewBinding);
const struct anv_image *img = iv->image;
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_SURFACE_STATE), ss) {
ss.Width = img->vk.extent.width - 1;
ss.Height = img->vk.extent.height - 1;
ss.SurfaceFormat = PLANAR_420_8; // assert on this?
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 = align(img->vk.extent.height, 32);
ss.YOffsetforVCr = align(img->vk.extent.height, 32);
}
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_PIPE_BUF_ADDR_STATE), buf) {
bool use_pre_deblock = false;
if (use_pre_deblock) {
buf.PreDeblockingDestinationAddress = anv_image_address(img,
&img->planes[0].primary_surface.memory_range);
} else {
buf.PostDeblockingDestinationAddress = anv_image_address(img,
&img->planes[0].primary_surface.memory_range);
}
#if GFX_VERx10 >= 75
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 };
#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 >= 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 };
#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 };
#endif
#endif
#if GFX_VERx10 == 75
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
#if GFX_VERx10 == 80
struct anv_bo *ref_bo = NULL;
#endif
for (unsigned 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);
int idx = frame_info->pReferenceSlots[i].slotIndex;
buf.ReferencePictureAddress[idx] = anv_image_address(ref_iv->image,
&ref_iv->image->planes[0].primary_surface.memory_range);
#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);
#if 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 == 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_BSD_MPC_ROW_SCRATCH].offset };
#if 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
}
anv_batch_emit(&cmd_buffer->batch, GENX(MFD_AVC_DPB_STATE), avc_dpb) {
for (unsigned i = 0; i < frame_info->referenceSlotCount; i++) {
const struct VkVideoDecodeH264DpbSlotInfoKHR *dpb_slot =
vk_find_struct_const(frame_info->pReferenceSlots[i].pNext, VIDEO_DECODE_H264_DPB_SLOT_INFO_KHR);
const StdVideoDecodeH264ReferenceInfo *ref_info = dpb_slot->pStdReferenceInfo;
int idx = frame_info->pReferenceSlots[i].slotIndex;
avc_dpb.NonExistingFrame[idx] = ref_info->flags.is_non_existing;
avc_dpb.LongTermFrame[idx] = ref_info->flags.used_for_long_term_reference;
if (!ref_info->flags.top_field_flag && !ref_info->flags.bottom_field_flag)
avc_dpb.UsedforReference[idx] = 3;
else
avc_dpb.UsedforReference[idx] = ref_info->flags.top_field_flag | (ref_info->flags.bottom_field_flag << 1);
avc_dpb.LTSTFrameNumberList[idx] = ref_info->FrameNum;
}
}
#if GFX_VERx10 >= 75
anv_batch_emit(&cmd_buffer->batch, GENX(MFD_AVC_PICID_STATE), picid) {
picid.PictureIDRemappingDisable = false;
for (unsigned i = 0; i < frame_info->referenceSlotCount; i++) {
int idx = frame_info->pReferenceSlots[i].slotIndex;
picid.PictureID[i] = idx;
}
}
#endif
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_AVC_IMG_STATE), avc_img) {
avc_img.FrameWidth = sps->pic_width_in_mbs_minus1;
avc_img.FrameHeight = sps->pic_height_in_map_units_minus1;
avc_img.FrameSize = (sps->pic_width_in_mbs_minus1 + 1) * (sps->pic_height_in_map_units_minus1 + 1);
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 = pps->chroma_qp_index_offset & 0x1f;
avc_img.SecondChromaQPOffset = pps->second_chroma_qp_index_offset & 0x1f;
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 = frame_info->referenceSlotCount;
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 = pps->pic_init_qp_minus26;
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 = sps->log2_max_frame_num_minus4;
avc_img.Log2MaxPicOrderCountLSB = sps->log2_max_pic_order_cnt_lsb_minus4;
avc_img.CurrentPictureFrameNumber = h264_pic_info->pStdPictureInfo->frame_num;
}
if (pps->flags.pic_scaling_matrix_present_flag) {
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_QM_STATE), qm) {
qm.DWordLength = 16;
qm.AVC = AVC_4x4_Intra_MATRIX;
}
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_QM_STATE), qm) {
qm.DWordLength = 16;
qm.AVC = AVC_4x4_Inter_MATRIX;
}
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;
}
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_QM_STATE), qm) {
qm.DWordLength = 16;
qm.AVC = AVC_8x8_Inter_MATRIX;
}
}
} else {
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_QM_STATE), qm) {
qm.DWordLength = 16;
qm.AVC = AVC_4x4_Intra_MATRIX;
for (unsigned q = 0; q < 3 * 16; q++)
qm.ForwardQuantizerMatrix[q] = 0x10;
}
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_QM_STATE), qm) {
qm.DWordLength = 16;
qm.AVC = AVC_4x4_Inter_MATRIX;
for (unsigned q = 0; q < 3 * 16; q++)
qm.ForwardQuantizerMatrix[q] = 0x10;
}
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[q] = 0x10;
}
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[q] = 0x10;
}
}
}
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_AVC_DIRECTMODE_STATE), avc_directmode) {
/* bind reference frame DMV */
for (unsigned i = 0; i < frame_info->referenceSlotCount; i++) {
int idx = frame_info->pReferenceSlots[i].slotIndex;
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;
avc_directmode.DirectMVBufferAddress[idx] = anv_image_address(ref_iv->image,
&ref_iv->image->vid_dmv_top_surface);
avc_directmode.POCList[2 * idx] = ref_info->PicOrderCnt[0];
avc_directmode.POCList[2 * idx + 1] = ref_info->PicOrderCnt[1];
}
#if GFX_VERx10 == 70
avc_directmode.DirectMVBufferWriteAddress[0] = anv_image_address(img,
&img->vid_dmv_top_surface);
#else
avc_directmode.DirectMVBufferWriteAddress = anv_image_address(img,
&img->vid_dmv_top_surface);
#endif
avc_directmode.POCList[32] = h264_pic_info->pStdPictureInfo->PicOrderCnt[0];
avc_directmode.POCList[33] = h264_pic_info->pStdPictureInfo->PicOrderCnt[1];
}
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) {
uint32_t next_offset = h264_pic_info->pSliceOffsets[s + 1];
uint32_t next_end = h264_pic_info->pSliceOffsets[s + 2];
if (s == h264_pic_info->sliceCount - 2)
next_end = frame_info->srcBufferRange;
anv_batch_emit(&cmd_buffer->batch, GENX(MFD_AVC_SLICEADDR), sliceaddr) {
sliceaddr.IndirectBSDDataLength = next_end - next_offset - HEADER_OFFSET;
/* start decoding after the 3-byte header. */
sliceaddr.IndirectBSDDataStartAddress = buffer_offset + next_offset + HEADER_OFFSET;
};
this_end = next_offset;
} else
this_end = frame_info->srcBufferRange;
anv_batch_emit(&cmd_buffer->batch, GENX(MFD_AVC_BSD_OBJECT), avc_bsd) {
avc_bsd.IndirectBSDDataLength = this_end - current_offset - HEADER_OFFSET;
/* start decoding after the 3-byte header. */
avc_bsd.IndirectBSDDataStartAddress = buffer_offset + current_offset + HEADER_OFFSET;
avc_bsd.InlineData.LastSlice = last_slice;
avc_bsd.InlineData.FixPrevMBSkipped = 1;
#if GFX_VERx10 >= 75
avc_bsd.InlineData.IntraPredictionErrorControl = 1;
avc_bsd.InlineData.Intra8x84x4PredictionErrorConcealmentControl = 1;
avc_bsd.InlineData.ISliceConcealmentMode = 1;
#endif
};
}
}
void
genX(CmdDecodeVideoKHR)(VkCommandBuffer commandBuffer,
const VkVideoDecodeInfoKHR *frame_info)
{
ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, commandBuffer);
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:
assert(0);
}
}
#ifdef VK_ENABLE_BETA_EXTENSIONS
void
genX(CmdEncodeVideoKHR)(VkCommandBuffer commandBuffer,
const VkVideoEncodeInfoKHR *pEncodeInfo)
{
}
#endif
+2
View File
@@ -62,6 +62,7 @@ anv_per_hw_ver_files = files(
'genX_pipeline.c',
'genX_query.c',
'genX_state.c',
'genX_video.c',
)
foreach g : [['70', ['gfx7_cmd_buffer.c']],
['75', ['gfx7_cmd_buffer.c']],
@@ -114,6 +115,7 @@ libanv_files = files(
'anv_queue.c',
'anv_util.c',
'anv_utrace.c',
'anv_video.c',
'anv_wsi.c',
)