xref: /aosp_15_r20/external/deqp/external/vulkancts/modules/vulkan/video/vktVideoBaseDecodeUtils.hpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 #ifndef _VKTVIDEOBASEDECODEUTILS_HPP
2 #define _VKTVIDEOBASEDECODEUTILS_HPP
3 /*------------------------------------------------------------------------
4  * Vulkan Conformance Tests
5  * ------------------------
6  *
7  * Copyright (c) 2021 The Khronos Group Inc.
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  */
22 /*!
23  * \file
24  * \brief Video Encoding Base Classe Functionality
25  */
26 /*--------------------------------------------------------------------*/
27 /*
28  * Copyright 2020 NVIDIA Corporation.
29  *
30  * Licensed under the Apache License, Version 2.0 (the "License");
31  * you may not use this file except in compliance with the License.
32  * You may obtain a copy of the License at
33  *
34  *    http://www.apache.org/licenses/LICENSE-2.0
35  *
36  * Unless required by applicable law or agreed to in writing, software
37  * distributed under the License is distributed on an "AS IS" BASIS,
38  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
39  * See the License for the specific language governing permissions and
40  * limitations under the License.
41  */
42 
43 #include <array>
44 #include <bitset>
45 #include <list>
46 #include <queue>
47 #include <vector>
48 
49 #include "deMemory.h"
50 
51 #include "vktVideoTestUtils.hpp"
52 #include "vkBufferWithMemory.hpp"
53 #include "vkImageWithMemory.hpp"
54 
55 #include "vktVideoFrameBuffer.hpp"
56 #include "vktDemuxer.hpp"
57 
58 namespace vkt
59 {
60 namespace video
61 {
62 
63 using namespace vk;
64 using namespace std;
65 
66 #define MAKEFRAMERATE(num, den) (((num) << 14) | (den))
67 #define NV_FRAME_RATE_NUM(rate) ((rate) >> 14)
68 #define NV_FRAME_RATE_DEN(rate) ((rate)&0x3fff)
69 
70 const uint64_t TIMEOUT_100ms = 100 * 1000 * 1000;
71 
72 // Keeps track of data associated with active internal reference frames
73 class DpbSlot
74 {
75 public:
isInUse()76     bool isInUse()
77     {
78         return (m_reserved || m_inUse);
79     }
80 
isAvailable()81     bool isAvailable()
82     {
83         return !isInUse();
84     }
85 
Invalidate()86     bool Invalidate()
87     {
88         bool wasInUse = isInUse();
89         if (m_picBuf)
90         {
91             m_picBuf->Release();
92             m_picBuf = NULL;
93         }
94 
95         m_reserved = m_inUse = false;
96 
97         return wasInUse;
98     }
99 
getPictureResource()100     vkPicBuffBase *getPictureResource()
101     {
102         return m_picBuf;
103     }
104 
setPictureResource(vkPicBuffBase * picBuf,int32_t age=0)105     vkPicBuffBase *setPictureResource(vkPicBuffBase *picBuf, int32_t age = 0)
106     {
107         vkPicBuffBase *oldPic = m_picBuf;
108 
109         if (picBuf)
110         {
111             picBuf->AddRef();
112         }
113         m_picBuf = picBuf;
114 
115         if (oldPic)
116         {
117             oldPic->Release();
118         }
119 
120         m_pictureId = age;
121         return oldPic;
122     }
123 
Reserve()124     void Reserve()
125     {
126         m_reserved = true;
127     }
128 
MarkInUse(int32_t age=0)129     void MarkInUse(int32_t age = 0)
130     {
131         m_pictureId = age;
132         m_inUse     = true;
133     }
134 
getAge()135     int32_t getAge()
136     {
137         return m_pictureId;
138     }
139 
140 private:
141     int32_t m_pictureId;     // PictureID at map time (age)
142     vkPicBuffBase *m_picBuf; // Associated resource
143 
144     uint32_t m_reserved : 1;
145     uint32_t m_inUse    : 1;
146 };
147 
148 class DpbSlots
149 {
150 public:
DpbSlots(uint8_t dpbMaxSize)151     explicit DpbSlots(uint8_t dpbMaxSize)
152         : m_dpbMaxSize(0)
153         , m_slotInUseMask(0)
154         , m_dpb(m_dpbMaxSize)
155         , m_dpbSlotsAvailable()
156     {
157         Init(dpbMaxSize, false);
158     }
159 
Init(uint8_t newDpbMaxSize,bool reconfigure)160     int32_t Init(uint8_t newDpbMaxSize, bool reconfigure)
161     {
162         DE_ASSERT(newDpbMaxSize <= VkParserPerFrameDecodeParameters::MAX_DPB_REF_AND_SETUP_SLOTS);
163 
164         if (!reconfigure)
165         {
166             Deinit();
167         }
168 
169         if (reconfigure && (newDpbMaxSize < m_dpbMaxSize))
170         {
171             return m_dpbMaxSize;
172         }
173 
174         uint8_t oldDpbMaxSize = reconfigure ? m_dpbMaxSize : 0;
175         m_dpbMaxSize          = newDpbMaxSize;
176 
177         m_dpb.resize(m_dpbMaxSize);
178 
179         for (uint32_t ndx = oldDpbMaxSize; ndx < m_dpbMaxSize; ndx++)
180         {
181             m_dpb[ndx].Invalidate();
182         }
183 
184         for (uint8_t dpbIndx = oldDpbMaxSize; dpbIndx < m_dpbMaxSize; dpbIndx++)
185         {
186             m_dpbSlotsAvailable.push(dpbIndx);
187         }
188 
189         return m_dpbMaxSize;
190     }
191 
Deinit()192     void Deinit()
193     {
194         for (uint32_t ndx = 0; ndx < m_dpbMaxSize; ndx++)
195         {
196             m_dpb[ndx].Invalidate();
197         }
198 
199         while (!m_dpbSlotsAvailable.empty())
200         {
201             m_dpbSlotsAvailable.pop();
202         }
203 
204         m_dpbMaxSize    = 0;
205         m_slotInUseMask = 0;
206     }
207 
~DpbSlots()208     ~DpbSlots()
209     {
210         Deinit();
211     }
212 
AllocateSlot()213     int8_t AllocateSlot()
214     {
215         if (m_dpbSlotsAvailable.empty())
216         {
217             DE_ASSERT(!"No more h.264/5 DPB slots are available");
218             return -1;
219         }
220         int8_t slot = (int8_t)m_dpbSlotsAvailable.front();
221         DE_ASSERT((slot >= 0) && ((uint8_t)slot < m_dpbMaxSize));
222         m_slotInUseMask |= (1 << slot);
223         m_dpbSlotsAvailable.pop();
224         m_dpb[slot].Reserve();
225         return slot;
226     }
227 
FreeSlot(int8_t slot)228     void FreeSlot(int8_t slot)
229     {
230         DE_ASSERT((uint8_t)slot < m_dpbMaxSize);
231         DE_ASSERT(m_dpb[slot].isInUse());
232         DE_ASSERT(m_slotInUseMask & (1 << slot));
233 
234         m_dpb[slot].Invalidate();
235         m_dpbSlotsAvailable.push(slot);
236         m_slotInUseMask &= ~(1 << slot);
237     }
238 
operator [](uint32_t slot)239     DpbSlot &operator[](uint32_t slot)
240     {
241         DE_ASSERT(slot < m_dpbMaxSize);
242         return m_dpb[slot];
243     }
244 
245     // Return the remapped index given an external decode render target index
GetSlotOfPictureResource(vkPicBuffBase * pPic)246     int8_t GetSlotOfPictureResource(vkPicBuffBase *pPic)
247     {
248         for (int8_t i = 0; i < (int8_t)m_dpbMaxSize; i++)
249         {
250             if ((m_slotInUseMask & (1 << i)) && m_dpb[i].isInUse() && (pPic == m_dpb[i].getPictureResource()))
251             {
252                 return i;
253             }
254         }
255         return -1; // not found
256     }
257 
MapPictureResource(vkPicBuffBase * pPic,uint8_t dpbSlot,int32_t age=0)258     void MapPictureResource(vkPicBuffBase *pPic, uint8_t dpbSlot, int32_t age = 0)
259     {
260         for (uint8_t slot = 0; slot < m_dpbMaxSize; slot++)
261         {
262             if (slot == dpbSlot)
263             {
264                 m_dpb[slot].setPictureResource(pPic, age);
265             }
266             else if (pPic)
267             {
268                 if (m_dpb[slot].getPictureResource() == pPic)
269                 {
270                     FreeSlot(slot);
271                 }
272             }
273         }
274     }
275 
getSlotInUseMask()276     uint32_t getSlotInUseMask()
277     {
278         return m_slotInUseMask;
279     }
280 
getMaxSize()281     uint32_t getMaxSize()
282     {
283         return m_dpbMaxSize;
284     }
285 
286 private:
287     uint8_t m_dpbMaxSize;
288     uint32_t m_slotInUseMask;
289     std::vector<DpbSlot> m_dpb;
290     std::queue<uint8_t> m_dpbSlotsAvailable;
291 };
292 
293 class VulkanVideoSession : public VkVideoRefCountBase
294 {
295     enum
296     {
297         MAX_BOUND_MEMORY = 9
298     };
299 
300 public:
301     static VkResult Create(DeviceContext &devCtx, uint32_t videoQueueFamily, VkVideoCoreProfile *pVideoProfile,
302                            VkFormat pictureFormat, const VkExtent2D &maxCodedExtent, VkFormat referencePicturesFormat,
303                            uint32_t maxDpbSlots, uint32_t maxActiveReferencePictures, bool useInlineVideoQueries,
304                            VkSharedBaseObj<VulkanVideoSession> &videoSession);
305 
IsCompatible(VkDevice device,uint32_t videoQueueFamily,VkVideoCoreProfile * pVideoProfile,VkFormat pictureFormat,const VkExtent2D & maxCodedExtent,VkFormat referencePicturesFormat,uint32_t maxDpbSlots,uint32_t maxActiveReferencePictures)306     bool IsCompatible(VkDevice device, uint32_t videoQueueFamily, VkVideoCoreProfile *pVideoProfile,
307                       VkFormat pictureFormat, const VkExtent2D &maxCodedExtent, VkFormat referencePicturesFormat,
308                       uint32_t maxDpbSlots, uint32_t maxActiveReferencePictures)
309     {
310         if (*pVideoProfile != m_profile)
311         {
312             return false;
313         }
314 
315         if (maxCodedExtent.width > m_createInfo.maxCodedExtent.width)
316         {
317             return false;
318         }
319 
320         if (maxCodedExtent.height > m_createInfo.maxCodedExtent.height)
321         {
322             return false;
323         }
324 
325         if (maxDpbSlots > m_createInfo.maxDpbSlots)
326         {
327             return false;
328         }
329 
330         if (maxActiveReferencePictures > m_createInfo.maxActiveReferencePictures)
331         {
332             return false;
333         }
334 
335         if (m_createInfo.referencePictureFormat != referencePicturesFormat)
336         {
337             return false;
338         }
339 
340         if (m_createInfo.pictureFormat != pictureFormat)
341         {
342             return false;
343         }
344 
345         if (m_devCtx.device != device)
346         {
347             return false;
348         }
349 
350         if (m_createInfo.queueFamilyIndex != videoQueueFamily)
351         {
352             return false;
353         }
354 
355         return true;
356     }
357 
AddRef()358     int32_t AddRef() override
359     {
360         return ++m_refCount;
361     }
362 
Release()363     int32_t Release() override
364     {
365         uint32_t ret = --m_refCount;
366         // Destroy the device if refcount reaches zero
367         if (ret == 0)
368         {
369             delete this;
370         }
371         return ret;
372     }
373 
GetVideoSession() const374     VkVideoSessionKHR GetVideoSession() const
375     {
376         return m_videoSession;
377     }
378 
379 private:
VulkanVideoSession(DeviceContext & devCtx,VkVideoCoreProfile * pVideoProfile)380     VulkanVideoSession(DeviceContext &devCtx, VkVideoCoreProfile *pVideoProfile)
381         : m_refCount(0)
382         , m_profile(*pVideoProfile)
383         , m_devCtx(devCtx)
384         , m_videoSession(VkVideoSessionKHR(0))
385     {
386         deMemset(&m_createInfo, 0, sizeof(VkVideoSessionCreateInfoKHR));
387         m_createInfo.sType = VK_STRUCTURE_TYPE_VIDEO_SESSION_CREATE_INFO_KHR;
388 
389         for (auto &binding : m_memoryBound)
390         {
391             binding = VK_NULL_HANDLE;
392         }
393     }
394 
~VulkanVideoSession()395     ~VulkanVideoSession() override
396     {
397         auto &vk = m_devCtx.getDeviceDriver();
398         if (!!m_videoSession)
399         {
400             vk.destroyVideoSessionKHR(m_devCtx.device, m_videoSession, NULL);
401             m_videoSession = VK_NULL_HANDLE;
402         }
403 
404         for (uint32_t memIdx = 0; memIdx < MAX_BOUND_MEMORY; memIdx++)
405         {
406             if (m_memoryBound[memIdx] != VK_NULL_HANDLE)
407             {
408                 vk.freeMemory(m_devCtx.device, m_memoryBound[memIdx], 0);
409                 m_memoryBound[memIdx] = VK_NULL_HANDLE;
410             }
411         }
412     }
413 
414 private:
415     std::atomic<int32_t> m_refCount;
416     VkVideoCoreProfile m_profile;
417     DeviceContext &m_devCtx;
418     VkVideoSessionCreateInfoKHR m_createInfo;
419     VkVideoSessionKHR m_videoSession;
420     VkDeviceMemory m_memoryBound[MAX_BOUND_MEMORY];
421 };
422 
423 class VkParserVideoPictureParameters : public VkVideoRefCountBase
424 {
425 public:
426     static const uint32_t MAX_VPS_IDS = 16;
427     static const uint32_t MAX_SPS_IDS = 32;
428     static const uint32_t MAX_PPS_IDS = 256;
429 
430     //! Increment the reference count by 1.
431     virtual int32_t AddRef();
432 
433     //! Decrement the reference count by 1. When the reference count
434     //! goes to 0 the object is automatically destroyed.
435     virtual int32_t Release();
436 
VideoPictureParametersFromBase(VkVideoRefCountBase * pBase)437     static VkParserVideoPictureParameters *VideoPictureParametersFromBase(VkVideoRefCountBase *pBase)
438     {
439         if (!pBase)
440         {
441             return NULL;
442         }
443         VkParserVideoPictureParameters *pPictureParameters = static_cast<VkParserVideoPictureParameters *>(pBase);
444         if (m_refClassId == pPictureParameters->m_classId)
445         {
446             return pPictureParameters;
447         }
448         DE_ASSERT(false && "Invalid VkParserVideoPictureParameters from base");
449         return nullptr;
450     }
451 
452     static VkResult AddPictureParameters(
453         DeviceContext &deviceContext, VkSharedBaseObj<VulkanVideoSession> &videoSession,
454         VkSharedBaseObj<StdVideoPictureParametersSet> &stdPictureParametersSet,
455         VkSharedBaseObj<VkParserVideoPictureParameters> &currentVideoPictureParameters);
456 
457     static bool CheckStdObjectBeforeUpdate(
458         VkSharedBaseObj<StdVideoPictureParametersSet> &pictureParametersSet,
459         VkSharedBaseObj<VkParserVideoPictureParameters> &currentVideoPictureParameters);
460 
461     static VkResult Create(DeviceContext &deviceContext,
462                            VkSharedBaseObj<VkParserVideoPictureParameters> &templatePictureParameters,
463                            VkSharedBaseObj<VkParserVideoPictureParameters> &videoPictureParameters);
464 
465     static int32_t PopulateH264UpdateFields(const StdVideoPictureParametersSet *pStdPictureParametersSet,
466                                             VkVideoDecodeH264SessionParametersAddInfoKHR &h264SessionParametersAddInfo);
467 
468     static int32_t PopulateH265UpdateFields(const StdVideoPictureParametersSet *pStdPictureParametersSet,
469                                             VkVideoDecodeH265SessionParametersAddInfoKHR &h265SessionParametersAddInfo);
470 
471     VkResult CreateParametersObject(VkSharedBaseObj<VulkanVideoSession> &videoSession,
472                                     const StdVideoPictureParametersSet *pStdVideoPictureParametersSet,
473                                     VkParserVideoPictureParameters *pTemplatePictureParameters);
474 
475     VkResult UpdateParametersObject(StdVideoPictureParametersSet *pStdVideoPictureParametersSet);
476 
477     VkResult HandleNewPictureParametersSet(VkSharedBaseObj<VulkanVideoSession> &videoSession,
478                                            StdVideoPictureParametersSet *pStdVideoPictureParametersSet);
479 
operator VkVideoSessionParametersKHR() const480     operator VkVideoSessionParametersKHR() const
481     {
482         DE_ASSERT(m_sessionParameters != VK_NULL_HANDLE);
483         return m_sessionParameters;
484     }
485 
GetVideoSessionParametersKHR() const486     VkVideoSessionParametersKHR GetVideoSessionParametersKHR() const
487     {
488         DE_ASSERT(m_sessionParameters != VK_NULL_HANDLE);
489         return m_sessionParameters;
490     }
491 
GetId() const492     int32_t GetId() const
493     {
494         return m_Id;
495     }
496 
HasVpsId(uint32_t vpsId) const497     bool HasVpsId(uint32_t vpsId) const
498     {
499         DE_ASSERT(vpsId < MAX_VPS_IDS);
500         return m_vpsIdsUsed[vpsId];
501     }
502 
HasSpsId(uint32_t spsId) const503     bool HasSpsId(uint32_t spsId) const
504     {
505         DE_ASSERT(spsId < MAX_SPS_IDS);
506         return m_spsIdsUsed[spsId];
507     }
508 
HasPpsId(uint32_t ppsId) const509     bool HasPpsId(uint32_t ppsId) const
510     {
511         DE_ASSERT(ppsId < MAX_PPS_IDS);
512         return m_ppsIdsUsed[ppsId];
513     }
514 
515     bool UpdatePictureParametersHierarchy(VkSharedBaseObj<StdVideoPictureParametersSet> &pictureParametersObject);
516 
517     VkResult AddPictureParametersToQueue(VkSharedBaseObj<StdVideoPictureParametersSet> &pictureParametersSet);
518     int32_t FlushPictureParametersQueue(VkSharedBaseObj<VulkanVideoSession> &videoSession);
519 
520 protected:
VkParserVideoPictureParameters(DeviceContext & deviceContext,VkSharedBaseObj<VkParserVideoPictureParameters> & templatePictureParameters)521     VkParserVideoPictureParameters(DeviceContext &deviceContext,
522                                    VkSharedBaseObj<VkParserVideoPictureParameters> &templatePictureParameters)
523         : m_classId(m_refClassId)
524         , m_Id(-1)
525         , m_refCount(0)
526         , m_deviceContext(deviceContext)
527         , m_videoSession()
528         , m_sessionParameters(VK_NULL_HANDLE)
529         , m_templatePictureParameters(templatePictureParameters)
530     {
531     }
532 
533     virtual ~VkParserVideoPictureParameters();
534 
535 private:
536     static const char *m_refClassId;
537     static int32_t m_currentId;
538     const char *m_classId;
539     int32_t m_Id;
540     std::atomic<int32_t> m_refCount;
541     DeviceContext &m_deviceContext;
542     VkSharedBaseObj<VulkanVideoSession> m_videoSession;
543     VkVideoSessionParametersKHR m_sessionParameters;
544     std::bitset<MAX_VPS_IDS> m_vpsIdsUsed;
545     std::bitset<MAX_SPS_IDS> m_spsIdsUsed;
546     std::bitset<MAX_PPS_IDS> m_ppsIdsUsed;
547     std::bitset<MAX_SPS_IDS> m_av1SpsIdsUsed;
548     int m_updateCount{0};
549     VkSharedBaseObj<VkParserVideoPictureParameters> m_templatePictureParameters; // needed only for the create
550 
551     std::queue<VkSharedBaseObj<StdVideoPictureParametersSet>> m_pictureParametersQueue;
552     VkSharedBaseObj<StdVideoPictureParametersSet> m_lastPictParamsQueue[StdVideoPictureParametersSet::NUM_OF_TYPES];
553 };
554 
555 struct nvVideoDecodeH264DpbSlotInfo
556 {
557     VkVideoDecodeH264DpbSlotInfoKHR dpbSlotInfo;
558     StdVideoDecodeH264ReferenceInfo stdReferenceInfo;
559 
nvVideoDecodeH264DpbSlotInfovkt::video::nvVideoDecodeH264DpbSlotInfo560     nvVideoDecodeH264DpbSlotInfo() : dpbSlotInfo(), stdReferenceInfo()
561     {
562     }
563 
Initvkt::video::nvVideoDecodeH264DpbSlotInfo564     const VkVideoDecodeH264DpbSlotInfoKHR *Init(int8_t slotIndex)
565     {
566         DE_ASSERT((slotIndex >= 0) &&
567                   (slotIndex < (int8_t)VkParserPerFrameDecodeParameters::MAX_DPB_REF_AND_SETUP_SLOTS));
568         DE_UNREF(slotIndex);
569         dpbSlotInfo.sType             = VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_DPB_SLOT_INFO_KHR;
570         dpbSlotInfo.pNext             = NULL;
571         dpbSlotInfo.pStdReferenceInfo = &stdReferenceInfo;
572         return &dpbSlotInfo;
573     }
574 
IsReferencevkt::video::nvVideoDecodeH264DpbSlotInfo575     bool IsReference() const
576     {
577         return (dpbSlotInfo.pStdReferenceInfo == &stdReferenceInfo);
578     }
579 
operator boolvkt::video::nvVideoDecodeH264DpbSlotInfo580     operator bool() const
581     {
582         return IsReference();
583     }
Invalidatevkt::video::nvVideoDecodeH264DpbSlotInfo584     void Invalidate()
585     {
586         memset(this, 0x00, sizeof(*this));
587     }
588 };
589 
590 struct nvVideoDecodeH265DpbSlotInfo
591 {
592     VkVideoDecodeH265DpbSlotInfoKHR dpbSlotInfo;
593     StdVideoDecodeH265ReferenceInfo stdReferenceInfo;
594 
nvVideoDecodeH265DpbSlotInfovkt::video::nvVideoDecodeH265DpbSlotInfo595     nvVideoDecodeH265DpbSlotInfo() : dpbSlotInfo(), stdReferenceInfo()
596     {
597     }
598 
Initvkt::video::nvVideoDecodeH265DpbSlotInfo599     const VkVideoDecodeH265DpbSlotInfoKHR *Init(int8_t slotIndex)
600     {
601         DE_ASSERT((slotIndex >= 0) && (slotIndex < (int8_t)VkParserPerFrameDecodeParameters::MAX_DPB_REF_SLOTS));
602         DE_UNREF(slotIndex);
603         dpbSlotInfo.sType             = VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_DPB_SLOT_INFO_KHR;
604         dpbSlotInfo.pNext             = NULL;
605         dpbSlotInfo.pStdReferenceInfo = &stdReferenceInfo;
606         return &dpbSlotInfo;
607     }
608 
IsReferencevkt::video::nvVideoDecodeH265DpbSlotInfo609     bool IsReference() const
610     {
611         return (dpbSlotInfo.pStdReferenceInfo == &stdReferenceInfo);
612     }
613 
operator boolvkt::video::nvVideoDecodeH265DpbSlotInfo614     operator bool() const
615     {
616         return IsReference();
617     }
618 
Invalidatevkt::video::nvVideoDecodeH265DpbSlotInfo619     void Invalidate()
620     {
621         memset(this, 0x00, sizeof(*this));
622     }
623 };
624 
625 struct DpbSlotInfoAV1
626 {
627     VkVideoDecodeAV1DpbSlotInfoKHR dpbSlotInfo{};
628     StdVideoDecodeAV1ReferenceInfo stdReferenceInfo;
Initvkt::video::DpbSlotInfoAV1629     const VkVideoDecodeAV1DpbSlotInfoKHR *Init(int8_t slotIndex)
630     {
631         assert((slotIndex >= 0) && (slotIndex < STD_VIDEO_AV1_NUM_REF_FRAMES));
632         DE_UNREF(slotIndex);
633         dpbSlotInfo.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_AV1_DPB_SLOT_INFO_KHR;
634         dpbSlotInfo.pNext = NULL;
635         return &dpbSlotInfo;
636     }
637 
Invalidatevkt::video::DpbSlotInfoAV1638     void Invalidate()
639     {
640         memset(this, 0x00, sizeof(*this));
641     }
642 };
643 
644 // A pool of bitstream buffers and a collection of command buffers for all frames in the decode sequence.
645 class NvVkDecodeFrameData
646 {
647 public:
NvVkDecodeFrameData(const DeviceInterface & vkd,VkDevice device,uint32_t decodeQueueIdx)648     NvVkDecodeFrameData(const DeviceInterface &vkd, VkDevice device, uint32_t decodeQueueIdx)
649         : m_deviceInterface(vkd)
650         , m_device(device)
651         , m_decodeQueueIdx(decodeQueueIdx)
652         , m_videoCommandPool(VK_NULL_HANDLE)
653     {
654     }
655 
deinit()656     void deinit()
657     {
658         if (m_videoCommandPool != VK_NULL_HANDLE)
659         {
660             m_deviceInterface.freeCommandBuffers(m_device, m_videoCommandPool, (uint32_t)m_commandBuffers.size(),
661                                                  &m_commandBuffers[0]);
662             m_deviceInterface.destroyCommandPool(m_device, m_videoCommandPool, NULL);
663             m_videoCommandPool = VK_NULL_HANDLE;
664         }
665     }
666 
~NvVkDecodeFrameData()667     ~NvVkDecodeFrameData()
668     {
669         deinit();
670     }
671 
resize(size_t maxDecodeFramesCount)672     size_t resize(size_t maxDecodeFramesCount)
673     {
674         size_t allocatedCommandBuffers = 0;
675         if (m_videoCommandPool == VK_NULL_HANDLE)
676         {
677             VkCommandPoolCreateInfo cmdPoolInfo = {};
678             cmdPoolInfo.sType                   = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
679             cmdPoolInfo.flags                   = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
680             cmdPoolInfo.queueFamilyIndex        = m_decodeQueueIdx;
681             VK_CHECK(m_deviceInterface.createCommandPool(m_device, &cmdPoolInfo, nullptr, &m_videoCommandPool));
682 
683             VkCommandBufferAllocateInfo cmdInfo = {};
684             cmdInfo.sType                       = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
685             cmdInfo.commandBufferCount          = (uint32_t)maxDecodeFramesCount;
686             cmdInfo.level                       = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
687             cmdInfo.commandPool                 = m_videoCommandPool;
688 
689             m_commandBuffers.resize(maxDecodeFramesCount);
690             VK_CHECK(m_deviceInterface.allocateCommandBuffers(m_device, &cmdInfo, &m_commandBuffers[0]));
691             allocatedCommandBuffers = maxDecodeFramesCount;
692         }
693         else
694         {
695             allocatedCommandBuffers = m_commandBuffers.size();
696             DE_ASSERT(maxDecodeFramesCount <= allocatedCommandBuffers);
697         }
698 
699         return allocatedCommandBuffers;
700     }
701 
GetCommandBuffer(uint32_t slot)702     VkCommandBuffer GetCommandBuffer(uint32_t slot)
703     {
704         DE_ASSERT(slot < m_commandBuffers.size());
705         return m_commandBuffers[slot];
706     }
707 
size()708     size_t size()
709     {
710         return m_commandBuffers.size();
711     }
712 
713 private:
714     const DeviceInterface &m_deviceInterface;
715     VkDevice m_device;
716     uint32_t m_decodeQueueIdx;
717     VkCommandPool m_videoCommandPool;
718     std::vector<VkCommandBuffer> m_commandBuffers;
719 };
720 
721 struct nvVideoH264PicParameters
722 {
723     enum
724     {
725         MAX_REF_PICTURES_LIST_ENTRIES = 16
726     };
727 
728     StdVideoDecodeH264PictureInfo stdPictureInfo;
729     VkVideoDecodeH264PictureInfoKHR pictureInfo;
730     VkVideoDecodeH264SessionParametersAddInfoKHR pictureParameters;
731     nvVideoDecodeH264DpbSlotInfo currentDpbSlotInfo;
732     nvVideoDecodeH264DpbSlotInfo dpbRefList[MAX_REF_PICTURES_LIST_ENTRIES];
733 };
734 
735 struct nvVideoH265PicParameters
736 {
737     enum
738     {
739         MAX_REF_PICTURES_LIST_ENTRIES = 16
740     };
741 
742     StdVideoDecodeH265PictureInfo stdPictureInfo;
743     VkVideoDecodeH265PictureInfoKHR pictureInfo;
744     VkVideoDecodeH265SessionParametersAddInfoKHR pictureParameters;
745     nvVideoDecodeH265DpbSlotInfo dpbRefList[MAX_REF_PICTURES_LIST_ENTRIES];
746 };
747 
748 struct NvVkDecodeFrameDataSlot
749 {
750     uint32_t slot;
751     VkCommandBuffer commandBuffer;
752 };
753 
754 class VideoBaseDecoder final : public VkParserVideoDecodeClient
755 {
756     enum
757     {
758         MAX_FRM_CNT     = 32,
759         MAX_BUFFER_SIZE = MAX_FRM_CNT * (2 * 1024 * 1024), // 2 MiB per frame is more than enough for CTS
760     };
761 
762 public:
763     // The CTS has two methods of decoding: immediate and cached. In immediate mode decoding, the frame-associated
764     // data may be stack allocated and forgotten frame-to-frame. Cached decoding buffers up all these associated
765     // data so that the frames can be simulated as recorded out of order, in a highly controlled fashion.
766     // This struct is essentially the definition of the frame associated data needed in general by Vulkan.
767     // There is still redundancy due to the past integration of the NVIDIA sample app, which operates purely in immediate
768     // mode decoding.
769     struct CachedDecodeParameters
770     {
771         VkParserPictureData pd;
772         VkParserDecodePictureInfo decodedPictureInfo;
773         VkParserPerFrameDecodeParameters pictureParams;
774         // NVIDIA API conflates picture parameters with picture parameter objects.
775         VkSharedBaseObj<VkParserVideoPictureParameters> currentPictureParameterObject;
776         VkVideoReferenceSlotInfoKHR referenceSlots[VkParserPerFrameDecodeParameters::MAX_DPB_REF_AND_SETUP_SLOTS];
777         VkVideoReferenceSlotInfoKHR setupReferenceSlot;
778 
779         VkVideoDecodeH264DpbSlotInfoKHR h264SlotInfo{};
780         StdVideoDecodeH264ReferenceInfo h264RefInfo{};
781         VkVideoDecodeH265DpbSlotInfoKHR h265SlotInfo{};
782         StdVideoDecodeH265ReferenceInfo h265RefInfo{};
783 
784         nvVideoH264PicParameters h264PicParams;
785         nvVideoH265PicParameters h265PicParams;
786         VkParserAv1PictureData av1PicParams;
787 
788         NvVkDecodeFrameDataSlot frameDataSlot;
789         VkVideoBeginCodingInfoKHR decodeBeginInfo{};
790         VkBufferMemoryBarrier2KHR bitstreamBufferMemoryBarrier;
791         std::vector<VkImageMemoryBarrier2KHR> imageBarriers;
792         VulkanVideoFrameBuffer::PictureResourceInfo currentDpbPictureResourceInfo;
793         VulkanVideoFrameBuffer::PictureResourceInfo currentOutputPictureResourceInfo;
794         VkVideoPictureResourceInfoKHR currentOutputPictureResource;
795         VkVideoPictureResourceInfoKHR *pOutputPictureResource{};
796         VulkanVideoFrameBuffer::PictureResourceInfo *pOutputPictureResourceInfo{};
797         VulkanVideoFrameBuffer::PictureResourceInfo
798             pictureResourcesInfo[VkParserPerFrameDecodeParameters::MAX_DPB_REF_AND_SETUP_SLOTS];
799 
800         std::vector<VkVideoReferenceSlotInfoKHR> fullReferenceSlots;
801         int32_t picNumInDecodeOrder;
802         VulkanVideoFrameBuffer::FrameSynchronizationInfo frameSynchronizationInfo;
803 
804         // When set, command buffer recording for this cached frame will reset the codec.
805         bool performCodecReset{false};
806 
~CachedDecodeParametersvkt::video::VideoBaseDecoder::CachedDecodeParameters807         ~CachedDecodeParameters()
808         {
809         }
810     };
811 
812     struct Parameters
813     {
814         DeviceContext *context{};
815         const VkVideoCoreProfile *profile{};
816         size_t framesToCheck{};
817         bool queryDecodeStatus{};
818         bool useInlineQueries{};
819         bool resourcesWithoutProfiles{};
820         bool outOfOrderDecoding{};
821         bool alwaysRecreateDPB{};
822         bool intraOnlyDecoding{};
823         size_t pictureParameterUpdateTriggerHack{0};
824         bool forceDisableFilmGrain{false};
825         VkSharedBaseObj<VulkanVideoFrameBuffer> framebuffer;
826     };
827     explicit VideoBaseDecoder(Parameters &&params);
~VideoBaseDecoder()828     ~VideoBaseDecoder() override
829     {
830         Deinitialize();
831     }
832 
833     int32_t ReleaseDisplayedFrame(DecodedFrame *pDisplayedFrame);
GetVideoFrameBuffer()834     VulkanVideoFrameBuffer *GetVideoFrameBuffer()
835     {
836         return m_videoFrameBuffer.Get();
837     }
getVideoCaps() const838     const VkVideoCapabilitiesKHR *getVideoCaps() const
839     {
840         return &m_videoCaps;
841     }
842 
843     // VkParserVideoDecodeClient callbacks
844     // Returns max number of reference frames (always at least 2 for MPEG-2)
845     int32_t BeginSequence(const VkParserSequenceInfo *pnvsi) override;
846     // Returns a new INvidiaVulkanPicture interface
847     bool AllocPictureBuffer(VkPicIf **ppNvidiaVulkanPicture, uint32_t width, uint32_t height) override;
848     // Called when a picture is ready to be decoded
849     bool DecodePicture(VkParserPictureData *pNvidiaVulkanParserPictureData) override;
850     // Called when the stream parameters have changed
851     bool UpdatePictureParameters(VkSharedBaseObj<StdVideoPictureParametersSet> &pictureParametersObject, /* in */
852                                  VkSharedBaseObj<VkVideoRefCountBase> &client /* out */) override;
853     // Called when a picture is ready to be displayed
854     bool DisplayPicture(VkPicIf *pNvidiaVulkanPicture, int64_t llPTS) override;
855     // Called for custom NAL parsing (not required)
856     void UnhandledNALU(const uint8_t *pbData, size_t cbData) override;
857 
858     virtual void StartVideoSequence(const VkParserDetectedVideoFormat *pVideoFormat);
859     virtual int32_t DecodePictureWithParameters(de::MovePtr<CachedDecodeParameters> &params);
860     VkDeviceSize GetBitstreamBuffer(VkDeviceSize size, VkDeviceSize minBitstreamBufferOffsetAlignment,
861                                     VkDeviceSize minBitstreamBufferSizeAlignment,
862                                     const uint8_t *pInitializeBufferMemory, VkDeviceSize initializeBufferMemorySize,
863                                     VkSharedBaseObj<VulkanBitstreamBuffer> &bitstreamBuffer) override;
864 
865     // Parser methods
866     bool DecodePicture(VkParserPictureData *pParserPictureData, vkPicBuffBase *pVkPicBuff, VkParserDecodePictureInfo *);
867     uint32_t FillDpbH264State(const VkParserPictureData *pd, const VkParserH264DpbEntry *dpbIn,
868                               uint32_t maxDpbInSlotsInUse, nvVideoDecodeH264DpbSlotInfo *pDpbRefList,
869                               uint32_t maxRefPictures, VkVideoReferenceSlotInfoKHR *pReferenceSlots,
870                               int8_t *pGopReferenceImagesIndexes, StdVideoDecodeH264PictureInfoFlags currPicFlags,
871                               int32_t *pCurrAllocatedSlotIndex);
872     uint32_t FillDpbH265State(const VkParserPictureData *pd, const VkParserHevcPictureData *pin,
873                               nvVideoDecodeH265DpbSlotInfo *pDpbSlotInfo,
874                               StdVideoDecodeH265PictureInfo *pStdPictureInfo, uint32_t maxRefPictures,
875                               VkVideoReferenceSlotInfoKHR *pReferenceSlots, int8_t *pGopReferenceImagesIndexes,
876                               int32_t *pCurrAllocatedSlotIndex);
877 
878     int8_t AllocateDpbSlotForCurrentH264(vkPicBuffBase *pPic, StdVideoDecodeH264PictureInfoFlags currPicFlags,
879                                          int8_t presetDpbSlot);
880     int8_t AllocateDpbSlotForCurrentH265(vkPicBuffBase *pPic, bool isReference, int8_t presetDpbSlot);
881 
882     int8_t GetPicIdx(vkPicBuffBase *pNvidiaVulkanPictureBase);
883     int8_t GetPicIdx(VkPicIf *pNvidiaVulkanPicture);
884     int8_t GetPicDpbSlot(int8_t picIndex);
885     int8_t SetPicDpbSlot(int8_t picIndex, int8_t dpbSlot);
886     uint32_t ResetPicDpbSlots(uint32_t picIndexSlotValidMask);
887     bool GetFieldPicFlag(int8_t picIndex);
888     bool SetFieldPicFlag(int8_t picIndex, bool fieldPicFlag);
889 
890     void Deinitialize();
GetCurrentFrameData(uint32_t slotId,NvVkDecodeFrameDataSlot & frameDataSlot)891     int32_t GetCurrentFrameData(uint32_t slotId, NvVkDecodeFrameDataSlot &frameDataSlot)
892     {
893         if (slotId < m_decodeFramesData.size())
894         {
895             frameDataSlot.commandBuffer = m_decodeFramesData.GetCommandBuffer(slotId);
896             frameDataSlot.slot          = slotId;
897             return slotId;
898         }
899         return -1;
900     }
901 
902     void ApplyPictureParameters(de::MovePtr<CachedDecodeParameters> &cachedParameters);
903     void WaitForFrameFences(de::MovePtr<CachedDecodeParameters> &cachedParameters);
904     void RecordCommandBuffer(de::MovePtr<CachedDecodeParameters> &cachedParameters);
905     void SubmitQueue(de::MovePtr<CachedDecodeParameters> &cachedParameters);
906     void QueryDecodeResults(de::MovePtr<CachedDecodeParameters> &cachedParameters);
907     void decodeFramesOutOfOrder();
908     void reinitializeFormatsForProfile(const VkVideoCoreProfile *profile);
909 
910     DeviceContext *m_deviceContext{};
911     VkVideoCoreProfile m_profile{};
912     uint32_t m_framesToCheck{};
913     // Parser fields
914     int32_t m_nCurrentPictureID{};
915     uint32_t m_dpbSlotsMask{};
916     uint32_t m_fieldPicFlagMask{};
917     DpbSlots m_dpb;
918     std::array<int8_t, MAX_FRM_CNT> m_pictureToDpbSlotMap;
919     VkFormat m_dpbImageFormat{VK_FORMAT_UNDEFINED};
920     VkFormat m_outImageFormat{VK_FORMAT_UNDEFINED};
921     uint32_t m_maxNumDpbSlots{1};
922     vector<AllocationPtr> m_videoDecodeSessionAllocs;
923     Move<VkCommandPool> m_videoCommandPool{};
924     VkVideoCapabilitiesKHR m_videoCaps{};
925     VkVideoDecodeCapabilitiesKHR m_decodeCaps{};
926     VkVideoCodecOperationFlagsKHR m_supportedVideoCodecs{};
dpbAndOutputCoincide() const927     inline bool dpbAndOutputCoincide() const
928     {
929         return m_decodeCaps.flags & VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_COINCIDE_BIT_KHR;
930     }
931 
932     VkSharedBaseObj<VulkanVideoSession> m_videoSession{};
933     VkSharedBaseObj<VulkanVideoFrameBuffer> m_videoFrameBuffer{};
934     NvVkDecodeFrameData m_decodeFramesData;
935 
936     // This is only used by the frame buffer, to set picture number in decode order.
937     // The framebuffer should manage this state ideally.
938     int32_t m_decodePicCount{};
939 
940     VkParserDetectedVideoFormat m_videoFormat{};
941 
942     VkSharedBaseObj<VkParserVideoPictureParameters> m_currentPictureParameters{};
943     int m_pictureParameterUpdateCount{0};
944     // Due to the design of the NVIDIA decoder client library, there is not a clean way to reset parameter objects
945     // in between GOPs. This becomes a problem when the session object needs to change, and then the parameter
946     // objects get stored in the wrong session. This field contains a nonnegative integer, such that when it
947     // becomes equal to m_pictureParameterUpdateCount, it will forcibly reset the current picture parameters.
948     // This could be more general by taking a modulo formula, or a list of trigger numbers. But it is currently
949     // only required for the h264_resolution_change_dpb test plan, so no need for complication.
950     int m_resetPictureParametersFrameTriggerHack{};
triggerPictureParameterSequenceCount()951     void triggerPictureParameterSequenceCount()
952     {
953         ++m_pictureParameterUpdateCount;
954         if (m_resetPictureParametersFrameTriggerHack > 0 &&
955             m_pictureParameterUpdateCount == m_resetPictureParametersFrameTriggerHack)
956         {
957             m_currentPictureParameters = nullptr;
958         }
959     }
960 
961     bool m_forceDisableFilmGrain{false};
962     bool m_queryResultWithStatus{false};
963     bool m_useInlineQueries{false};
964     bool m_resourcesWithoutProfiles{false};
965     bool m_outOfOrderDecoding{false};
966     bool m_alwaysRecreateDPB{false};
967     bool m_intraOnlyDecoding{false};
968     vector<VkParserPerFrameDecodeParameters *> m_pPerFrameDecodeParameters;
969     vector<VkParserDecodePictureInfo *> m_pVulkanParserDecodePictureInfo;
970     vector<NvVkDecodeFrameData *> m_pFrameDatas;
971     vector<VkBufferMemoryBarrier2KHR> m_bitstreamBufferMemoryBarriers;
972     vector<vector<VkImageMemoryBarrier2KHR>> m_imageBarriersVec;
973     vector<VulkanVideoFrameBuffer::FrameSynchronizationInfo> m_frameSynchronizationInfos;
974     vector<VkCommandBufferSubmitInfoKHR> m_commandBufferSubmitInfos;
975     vector<VkVideoBeginCodingInfoKHR> m_decodeBeginInfos;
976     vector<vector<VulkanVideoFrameBuffer::PictureResourceInfo>> m_pictureResourcesInfos;
977     vector<VkDependencyInfoKHR> m_dependencyInfos;
978     vector<VkVideoEndCodingInfoKHR> m_decodeEndInfos;
979     vector<VkSubmitInfo2KHR> m_submitInfos;
980     vector<VkFence> m_frameCompleteFences;
981     vector<VkFence> m_frameConsumerDoneFences;
982     vector<VkSemaphoreSubmitInfoKHR> m_frameCompleteSemaphoreSubmitInfos;
983     vector<VkSemaphoreSubmitInfoKHR> m_frameConsumerDoneSemaphoreSubmitInfos;
984 
985     std::vector<de::MovePtr<CachedDecodeParameters>> m_cachedDecodeParams;
986     VkSharedBaseObj<BitstreamBufferImpl> m_bitstreamBuffer{};
987     VkDeviceSize m_bitstreamBytesProcessed{0};
988     VkParserSequenceInfo m_nvsi{};
989     bool m_useImageArray{false};
990     bool m_useImageViewArray{false};
991     bool m_useSeparateOutputImages{false};
992     bool m_resetDecoder{false};
993 };
994 
995 using VkVideoParser = VkSharedBaseObj<VulkanVideoDecodeParser>;
996 
997 // FIXME: sample app interface issues (collapse the interface into CTS eventually)
998 void createParser(VkVideoCodecOperationFlagBitsKHR codecOperation, std::shared_ptr<VideoBaseDecoder> decoder,
999                   VkVideoParser &parser, ElementaryStreamFraming framing);
1000 
1001 class FrameProcessor
1002 {
1003 public:
FrameProcessor()1004     FrameProcessor()
1005     {
1006     }
1007     FrameProcessor(std::shared_ptr<Demuxer> &&demuxer, std::shared_ptr<VideoBaseDecoder> decoder);
1008 
1009     void parseNextChunk();
1010     int getNextFrame(DecodedFrame *pFrame);
1011     void bufferFrames(int framesToDecode);
getBufferedDisplayCount() const1012     int getBufferedDisplayCount() const
1013     {
1014         return m_decoder->GetVideoFrameBuffer()->GetDisplayedFrameCount();
1015     }
decodeFrameOutOfOrder(int framesToCheck)1016     void decodeFrameOutOfOrder(int framesToCheck)
1017     {
1018         bufferFrames(framesToCheck);
1019         m_decoder->decodeFramesOutOfOrder();
1020     }
1021     std::shared_ptr<VideoBaseDecoder> m_decoder{};
1022     VkVideoParser m_parser{};
1023     std::shared_ptr<Demuxer> m_demuxer{};
1024     bool m_eos{false};
1025 };
1026 
1027 } // namespace video
1028 } // namespace vkt
1029 
1030 #endif // _VKTVIDEOBASEDECODEUTILS_HPP
1031