anv: add initial video decode support for h264.
authorDave Airlie <airlied@redhat.com>
Sun, 14 Nov 2021 23:20:52 +0000 (09:20 +1000)
committerMarge Bot <emma+marge@anholt.net>
Wed, 8 Feb 2023 02:56:28 +0000 (02:56 +0000)
This just adds the files with the programming info, it doesn't
enable the extensions etc

Acked-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/20782>

src/intel/vulkan/anv_private.h
src/intel/vulkan/anv_video.c [new file with mode: 0644]
src/intel/vulkan/genX_video.c [new file with mode: 0644]
src/intel/vulkan/meson.build

index f45f8ad..00efb87 100644 (file)
@@ -90,6 +90,7 @@
 #include "vk_queue.h"
 #include "vk_log.h"
 #include "vk_ycbcr_conversion.h"
+#include "vk_video.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -2770,6 +2771,11 @@ struct anv_cmd_buffer {
     * Structure holding tracepoints recorded in the command 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;
@@ -4089,9 +4095,35 @@ struct anv_acceleration_structure {
    struct anv_address                           address;
 };
 
+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);
 
@@ -4238,6 +4270,12 @@ 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(&gfx9_##thing) genX_thing;          \
diff --git a/src/intel/vulkan/anv_video.c b/src/intel/vulkan/anv_video.c
new file mode 100644 (file)
index 0000000..c14d5ec
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ * 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);
+   ANV_FROM_HANDLE(anv_video_session, vid, pCreateInfo->videoSession);
+   ANV_FROM_HANDLE(anv_video_session_params, templ, pCreateInfo->videoSessionParametersTemplate);
+   struct anv_video_session_params *params =
+      vk_alloc2(&device->vk.alloc, pAllocator, sizeof(*params), 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
+   if (!params)
+      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
+
+   VkResult result = vk_video_session_parameters_init(&device->vk,
+                                                      &params->vk,
+                                                      &vid->vk,
+                                                      templ ? &templ->vk : NULL,
+                                                      pCreateInfo);
+   if (result != VK_SUCCESS) {
+      vk_free2(&device->vk.alloc, pAllocator, params);
+      return result;
+   }
+
+   *pVideoSessionParameters = anv_video_session_params_to_handle(params);
+   return VK_SUCCESS;
+}
+
+void
+anv_DestroyVideoSessionParametersKHR(VkDevice _device,
+                                      VkVideoSessionParametersKHR _params,
+                                      const VkAllocationCallbacks *pAllocator)
+{
+   ANV_FROM_HANDLE(anv_device, device, _device);
+   ANV_FROM_HANDLE(anv_video_session_params, params, _params);
+   if (!_params)
+      return;
+   vk_video_session_parameters_finish(&device->vk, &params->vk);
+   vk_free2(&device->vk.alloc, 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;
+}
diff --git a/src/intel/vulkan/genX_video.c b/src/intel/vulkan/genX_video.c
new file mode 100644 (file)
index 0000000..7163efa
--- /dev/null
@@ -0,0 +1,448 @@
+/*
+ * 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_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;
+   };
+
+#if GFX_VER >= 12
+   anv_batch_emit(&cmd_buffer->batch, GENX(MI_FORCE_WAKEUP), wake) {
+      wake.MFXPowerWellControl = 1;
+      wake.MaskBits = 768;
+   }
+
+   anv_batch_emit(&cmd_buffer->batch, GENX(MFX_WAIT), mfx) {
+      mfx.MFXSyncControlFlag = 1;
+   }
+#endif
+
+   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;
+   }
+
+#if GFX_VER >= 12
+   anv_batch_emit(&cmd_buffer->batch, GENX(MFX_WAIT), mfx) {
+      mfx.MFXSyncControlFlag = 1;
+   }
+#endif
+
+   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);
+      }
+      buf.PreDeblockingDestinationAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
+         .MOCS = anv_mocs(cmd_buffer->device, buf.PreDeblockingDestinationAddress.bo, 0),
+      };
+      buf.PostDeblockingDestinationAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
+         .MOCS = anv_mocs(cmd_buffer->device, buf.PostDeblockingDestinationAddress.bo, 0),
+      };
+
+      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 };
+      buf.IntraRowStoreScratchBufferAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
+         .MOCS = anv_mocs(cmd_buffer->device, buf.IntraRowStoreScratchBufferAddress.bo, 0),
+      };
+      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.DeblockingFilterRowStoreScratchAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
+         .MOCS = anv_mocs(cmd_buffer->device, buf.DeblockingFilterRowStoreScratchAddress.bo, 0),
+      };
+      buf.MBStatusBufferAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
+         .MOCS = anv_mocs(cmd_buffer->device, NULL, 0),
+      };
+      buf.MBILDBStreamOutBufferAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
+         .MOCS = anv_mocs(cmd_buffer->device, NULL, 0),
+      };
+      buf.SecondMBILDBStreamOutBufferAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
+         .MOCS = anv_mocs(cmd_buffer->device, NULL, 0),
+      };
+      buf.ScaledReferenceSurfaceAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
+         .MOCS = anv_mocs(cmd_buffer->device, NULL, 0),
+      };
+      buf.OriginalUncompressedPictureSourceAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
+         .MOCS = anv_mocs(cmd_buffer->device, NULL, 0),
+      };
+      buf.StreamOutDataDestinationAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
+         .MOCS = anv_mocs(cmd_buffer->device, NULL, 0),
+      };
+
+      struct anv_bo *ref_bo = NULL;
+      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 (i == 0) {
+            ref_bo = ref_iv->image->bindings[0].address.bo;
+         }
+      }
+      buf.ReferencePictureAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
+         .MOCS = anv_mocs(cmd_buffer->device, ref_bo, 0),
+      };
+   }
+
+   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);
+      index_obj.MFXIndirectBitstreamObjectAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
+         .MOCS = anv_mocs(cmd_buffer->device, src_buffer->address.bo, 0),
+      };
+      index_obj.MFXIndirectMVObjectAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
+         .MOCS = anv_mocs(cmd_buffer->device, NULL, 0),
+      };
+      index_obj.MFDIndirectITCOEFFObjectAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
+         .MOCS = anv_mocs(cmd_buffer->device, NULL, 0),
+      };
+      index_obj.MFDIndirectITDBLKObjectAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
+         .MOCS = anv_mocs(cmd_buffer->device, NULL, 0),
+      };
+      index_obj.MFCIndirectPAKBSEObjectAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
+         .MOCS = anv_mocs(cmd_buffer->device, NULL, 0),
+      };
+   }
+
+   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 };
+
+      bsp.BSDMPCRowStoreScratchBufferAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
+         .MOCS = anv_mocs(cmd_buffer->device, bsp.BSDMPCRowStoreScratchBufferAddress.bo, 0),
+      };
+      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 };
+
+      bsp.MPRRowStoreScratchBufferAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
+         .MOCS = anv_mocs(cmd_buffer->device, bsp.MPRRowStoreScratchBufferAddress.bo, 0),
+      };
+      bsp.BitplaneReadBufferAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
+         .MOCS = anv_mocs(cmd_buffer->device, NULL, 0),
+      };
+   }
+
+   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;
+      }
+   }
+
+   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;
+      }
+   }
+
+   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;
+         for (unsigned m = 0; m < 3; m++)
+            for (unsigned q = 0; q < 16; q++)
+               qm.ForwardQuantizerMatrix[m * 16 + q] = pps->pScalingLists->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 + q] = pps->pScalingLists->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[q] = pps->pScalingLists->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[q] = pps->pScalingLists->ScalingList8x8[3][q];
+         }
+      }
+   } else if (sps->flags.seq_scaling_matrix_present_flag) {
+      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 + q] = sps->pScalingLists->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 + q] = sps->pScalingLists->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[q] = sps->pScalingLists->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[q] = sps->pScalingLists->ScalingList8x8[3][q];
+         }
+      }
+   } 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 */
+      struct anv_bo *dmv_bo = NULL;
+      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);
+         if (i == 0) {
+            dmv_bo = ref_iv->image->bindings[0].address.bo;
+         }
+         avc_directmode.POCList[2 * idx] = ref_info->PicOrderCnt[0];
+         avc_directmode.POCList[2 * idx + 1] = ref_info->PicOrderCnt[1];
+      }
+      avc_directmode.DirectMVBufferAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
+         .MOCS = anv_mocs(cmd_buffer->device, dmv_bo, 0),
+      };
+
+      avc_directmode.DirectMVBufferWriteAddress = anv_image_address(img,
+                                                                    &img->vid_dmv_top_surface);
+      avc_directmode.DirectMVBufferWriteAttributes = (struct GENX(MEMORYADDRESSATTRIBUTES)) {
+         .MOCS = anv_mocs(cmd_buffer->device, img->bindings[0].address.bo, 0),
+      };
+      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;
+         avc_bsd.InlineData.IntraPredictionErrorControl = 1;
+         avc_bsd.InlineData.Intra8x84x4PredictionErrorConcealmentControl = 1;
+         avc_bsd.InlineData.ISliceConcealmentMode = 1;
+      };
+   }
+}
+
+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
index 87ac4a5..ea9c468 100644 (file)
@@ -101,6 +101,7 @@ anv_per_hw_ver_files = files(
   'genX_pipeline.c',
   'genX_query.c',
   'genX_state.c',
+  'genX_video.c',
 )
 if with_intel_vk_rt
   anv_per_hw_ver_files += files('genX_acceleration_structure.c',)
@@ -163,6 +164,7 @@ libanv_files = files(
   'anv_queue.c',
   'anv_util.c',
   'anv_utrace.c',
+  'anv_video.c',
   'anv_wsi.c',
 )