xref: /aosp_15_r20/external/deqp/external/vulkancts/modules/vulkan/video/vktVideoFrameBuffer.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2023 The Khronos Group Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20 * \file
21 * \brief Video framebuffer
22  *//*--------------------------------------------------------------------*/
23 /*
24  * Copyright 2020 NVIDIA Corporation.
25  *
26  * Licensed under the Apache License, Version 2.0 (the "License");
27  * you may not use this file except in compliance with the License.
28  * You may obtain a copy of the License at
29  *
30  *    http://www.apache.org/licenses/LICENSE-2.0
31  *
32  * Unless required by applicable law or agreed to in writing, software
33  * distributed under the License is distributed on an "AS IS" BASIS,
34  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
35  * See the License for the specific language governing permissions and
36  * limitations under the License.
37  */
38 
39 #include "vktVideoFrameBuffer.hpp"
40 
41 #include <queue>
42 
43 namespace vkt
44 {
45 namespace video
46 {
47 static VkSharedBaseObj<VkImageResourceView> emptyImageView;
48 
49 class NvPerFrameDecodeResources : public vkPicBuffBase
50 {
51 public:
NvPerFrameDecodeResources()52     NvPerFrameDecodeResources()
53         : m_picDispInfo()
54         , m_frameCompleteFence(VK_NULL_HANDLE)
55         , m_frameCompleteSemaphore(VK_NULL_HANDLE)
56         , m_frameConsumerDoneFence(VK_NULL_HANDLE)
57         , m_frameConsumerDoneSemaphore(VK_NULL_HANDLE)
58         , m_hasFrameCompleteSignalFence(false)
59         , m_hasFrameCompleteSignalSemaphore(false)
60         , m_hasConsummerSignalFence(false)
61         , m_hasConsummerSignalSemaphore(false)
62         , m_recreateImage(false)
63         , m_currentDpbImageLayerLayout(VK_IMAGE_LAYOUT_UNDEFINED)
64         , m_currentOutputImageLayout(VK_IMAGE_LAYOUT_UNDEFINED)
65         , m_vkDevCtx(nullptr)
66         , m_frameDpbImageView(VK_NULL_HANDLE)
67         , m_outImageView(VK_NULL_HANDLE)
68     {
69     }
70 
71     VkResult CreateImage(DeviceContext &vkDevCtx, const VkImageCreateInfo *pDpbImageCreateInfo,
72                          const VkImageCreateInfo *pOutImageCreateInfo, uint32_t imageIndex,
73                          VkSharedBaseObj<VkImageResource> &imageArrayParent,
74                          VkSharedBaseObj<VkImageResourceView> &imageViewArrayParent,
75                          bool useSeparateOutputImage = false, bool useLinearOutput = false);
76 
77     VkResult init(DeviceContext &vkDevCtx);
78 
79     void Deinit();
80 
81     NvPerFrameDecodeResources(const NvPerFrameDecodeResources &srcObj) = delete;
82     NvPerFrameDecodeResources(NvPerFrameDecodeResources &&srcObj)      = delete;
83 
~NvPerFrameDecodeResources()84     ~NvPerFrameDecodeResources() override
85     {
86         Deinit();
87     }
88 
GetFrameImageView()89     VkSharedBaseObj<VkImageResourceView> &GetFrameImageView()
90     {
91         if (ImageExist())
92         {
93             return m_frameDpbImageView;
94         }
95         else
96         {
97             return emptyImageView;
98         }
99     }
100 
GetDisplayImageView()101     VkSharedBaseObj<VkImageResourceView> &GetDisplayImageView()
102     {
103         if (ImageExist())
104         {
105             return m_outImageView;
106         }
107         else
108         {
109             return emptyImageView;
110         }
111     }
112 
ImageExist()113     bool ImageExist()
114     {
115 
116         return (!!m_frameDpbImageView && (m_frameDpbImageView->GetImageView() != VK_NULL_HANDLE));
117     }
118 
GetImageSetNewLayout(VkImageLayout newDpbImageLayout,VkVideoPictureResourceInfoKHR * pDpbPictureResource,VulkanVideoFrameBuffer::PictureResourceInfo * pDpbPictureResourceInfo,VkImageLayout newOutputImageLayout=VK_IMAGE_LAYOUT_MAX_ENUM,VkVideoPictureResourceInfoKHR * pOutputPictureResource=nullptr,VulkanVideoFrameBuffer::PictureResourceInfo * pOutputPictureResourceInfo=nullptr)119     bool GetImageSetNewLayout(VkImageLayout newDpbImageLayout, VkVideoPictureResourceInfoKHR *pDpbPictureResource,
120                               VulkanVideoFrameBuffer::PictureResourceInfo *pDpbPictureResourceInfo,
121                               VkImageLayout newOutputImageLayout                    = VK_IMAGE_LAYOUT_MAX_ENUM,
122                               VkVideoPictureResourceInfoKHR *pOutputPictureResource = nullptr,
123                               VulkanVideoFrameBuffer::PictureResourceInfo *pOutputPictureResourceInfo = nullptr)
124     {
125 
126         if (m_recreateImage || !ImageExist())
127         {
128             return false;
129         }
130 
131         if (pDpbPictureResourceInfo)
132         {
133             pDpbPictureResourceInfo->image       = m_frameDpbImageView->GetImageResource()->GetImage();
134             pDpbPictureResourceInfo->imageFormat = m_frameDpbImageView->GetImageResource()->GetImageCreateInfo().format;
135             pDpbPictureResourceInfo->currentImageLayout = m_currentDpbImageLayerLayout;
136         }
137 
138         if (VK_IMAGE_LAYOUT_MAX_ENUM != newDpbImageLayout)
139         {
140             m_currentDpbImageLayerLayout = newDpbImageLayout;
141         }
142 
143         if (pDpbPictureResource)
144         {
145             pDpbPictureResource->imageViewBinding = m_frameDpbImageView->GetImageView();
146         }
147 
148         if (pOutputPictureResourceInfo)
149         {
150             pOutputPictureResourceInfo->image       = m_outImageView->GetImageResource()->GetImage();
151             pOutputPictureResourceInfo->imageFormat = m_outImageView->GetImageResource()->GetImageCreateInfo().format;
152             pOutputPictureResourceInfo->currentImageLayout = m_currentOutputImageLayout;
153         }
154 
155         if (VK_IMAGE_LAYOUT_MAX_ENUM != newOutputImageLayout)
156         {
157             m_currentOutputImageLayout = newOutputImageLayout;
158         }
159 
160         if (pOutputPictureResource)
161         {
162             pOutputPictureResource->imageViewBinding = m_outImageView->GetImageView();
163         }
164 
165         return true;
166     }
167 
168     VkParserDecodePictureInfo m_picDispInfo;
169     VkFence m_frameCompleteFence;
170     VkSemaphore m_frameCompleteSemaphore;
171     VkFence m_frameConsumerDoneFence;
172     VkSemaphore m_frameConsumerDoneSemaphore;
173     uint32_t m_hasFrameCompleteSignalFence     : 1;
174     uint32_t m_hasFrameCompleteSignalSemaphore : 1;
175     uint32_t m_hasConsummerSignalFence         : 1;
176     uint32_t m_hasConsummerSignalSemaphore     : 1;
177     uint32_t m_recreateImage                   : 1;
178     // VPS
179     VkSharedBaseObj<VkVideoRefCountBase> stdVps;
180     // SPS
181     VkSharedBaseObj<VkVideoRefCountBase> stdSps;
182     // PPS
183     VkSharedBaseObj<VkVideoRefCountBase> stdPps;
184     // AV1 SPS
185     VkSharedBaseObj<VkVideoRefCountBase> stdAv1Sps;
186     // The bitstream Buffer
187     VkSharedBaseObj<VkVideoRefCountBase> bitstreamData;
188 
189 private:
190     VkImageLayout m_currentDpbImageLayerLayout;
191     VkImageLayout m_currentOutputImageLayout;
192     DeviceContext *m_vkDevCtx;
193     VkSharedBaseObj<VkImageResourceView> m_frameDpbImageView;
194     VkSharedBaseObj<VkImageResourceView> m_outImageView;
195 };
196 
197 class NvPerFrameDecodeImageSet
198 {
199 public:
200     static constexpr size_t maxImages = 32;
201 
NvPerFrameDecodeImageSet()202     NvPerFrameDecodeImageSet()
203         : m_queueFamilyIndex((uint32_t)-1)
204         , m_dpbImageCreateInfo()
205         , m_outImageCreateInfo()
206         , m_numImages(0)
207         , m_usesImageArray(false)
208         , m_usesImageViewArray(false)
209         , m_usesSeparateOutputImage(false)
210         , m_usesLinearOutput(false)
211         , m_perFrameDecodeResources(maxImages)
212         , m_imageArray()
213         , m_imageViewArray()
214     {
215     }
216 
217     int32_t init(DeviceContext &vkDevCtx, const VkVideoProfileInfoKHR *pDecodeProfile, uint32_t numImages,
218                  VkFormat dpbImageFormat, VkFormat outImageFormat, const VkExtent2D &maxImageExtent,
219                  VkImageUsageFlags dpbImageUsage, VkImageUsageFlags outImageUsage, uint32_t queueFamilyIndex,
220                  bool useImageArray = false, bool useImageViewArray = false, bool useSeparateOutputImages = false,
221                  bool useLinearOutput = false, bool resourcesWithoutProfiles = false);
222 
~NvPerFrameDecodeImageSet()223     ~NvPerFrameDecodeImageSet()
224     {
225         m_numImages = 0;
226     }
227 
operator [](unsigned int index)228     NvPerFrameDecodeResources &operator[](unsigned int index)
229     {
230         DE_ASSERT(index < m_perFrameDecodeResources.size());
231         return m_perFrameDecodeResources[index];
232     }
233 
size() const234     size_t size() const
235     {
236         return m_numImages;
237     }
238 
GetImageSetNewLayout(DeviceContext & vkDevCtx,uint32_t imageIndex,VkImageLayout newDpbImageLayout,VkVideoPictureResourceInfoKHR * pDpbPictureResource=nullptr,VulkanVideoFrameBuffer::PictureResourceInfo * pDpbPictureResourceInfo=nullptr,VkImageLayout newOutputImageLayout=VK_IMAGE_LAYOUT_MAX_ENUM,VkVideoPictureResourceInfoKHR * pOutputPictureResource=nullptr,VulkanVideoFrameBuffer::PictureResourceInfo * pOutputPictureResourceInfo=nullptr)239     VkResult GetImageSetNewLayout(DeviceContext &vkDevCtx, uint32_t imageIndex, VkImageLayout newDpbImageLayout,
240                                   VkVideoPictureResourceInfoKHR *pDpbPictureResource                   = nullptr,
241                                   VulkanVideoFrameBuffer::PictureResourceInfo *pDpbPictureResourceInfo = nullptr,
242                                   VkImageLayout newOutputImageLayout                    = VK_IMAGE_LAYOUT_MAX_ENUM,
243                                   VkVideoPictureResourceInfoKHR *pOutputPictureResource = nullptr,
244                                   VulkanVideoFrameBuffer::PictureResourceInfo *pOutputPictureResourceInfo = nullptr)
245     {
246 
247         VkResult result = VK_SUCCESS;
248         if (pDpbPictureResource)
249         {
250             if (m_imageViewArray)
251             {
252                 // We have an image view that has the same number of layers as the image.
253                 // In that scenario, while specifying the resource, the API must specifically choose the image layer.
254                 pDpbPictureResource->baseArrayLayer = imageIndex;
255             }
256             else
257             {
258                 // Let the image view sub-resource specify the image layer.
259                 pDpbPictureResource->baseArrayLayer = 0;
260             }
261         }
262 
263         if (pOutputPictureResource)
264         {
265             // Output pictures currently are only allocated as discrete
266             // Let the image view sub-resource specify the image layer.
267             pOutputPictureResource->baseArrayLayer = 0;
268         }
269 
270         bool validImage = m_perFrameDecodeResources[imageIndex].GetImageSetNewLayout(
271             newDpbImageLayout, pDpbPictureResource, pDpbPictureResourceInfo, newOutputImageLayout,
272             pOutputPictureResource, pOutputPictureResourceInfo);
273 
274         if (!validImage)
275         {
276             result = m_perFrameDecodeResources[imageIndex].CreateImage(
277                 vkDevCtx, &m_dpbImageCreateInfo, &m_outImageCreateInfo, imageIndex, m_imageArray, m_imageViewArray,
278                 m_usesSeparateOutputImage, m_usesLinearOutput);
279 
280             if (result == VK_SUCCESS)
281             {
282                 validImage = m_perFrameDecodeResources[imageIndex].GetImageSetNewLayout(
283                     newDpbImageLayout, pDpbPictureResource, pDpbPictureResourceInfo, newOutputImageLayout,
284                     pOutputPictureResource, pOutputPictureResourceInfo);
285 
286                 DE_ASSERT(validImage);
287             }
288         }
289 
290         return result;
291     }
292 
293 private:
294     uint32_t m_queueFamilyIndex;
295     VkVideoCoreProfile m_videoProfile;
296     VkImageCreateInfo m_dpbImageCreateInfo;
297     VkImageCreateInfo m_outImageCreateInfo;
298     uint32_t m_numImages;
299     // TODO: This code copied from the NVIDIA sample app has never been tested. Need to make sure the IHVs have a Radeon 5000 series GPU that uses this feature.
300     uint32_t m_usesImageArray          : 1;
301     uint32_t m_usesImageViewArray      : 1;
302     uint32_t m_usesSeparateOutputImage : 1;
303     uint32_t m_usesLinearOutput        : 1;
304     std::vector<NvPerFrameDecodeResources> m_perFrameDecodeResources;
305     VkSharedBaseObj<VkImageResource> m_imageArray;         // must be valid if m_usesImageArray is true
306     VkSharedBaseObj<VkImageResourceView> m_imageViewArray; // must be valid if m_usesImageViewArray is true
307 };
308 
309 class VkVideoFrameBuffer : public VulkanVideoFrameBuffer
310 {
311 public:
312     static constexpr size_t maxFramebufferImages = 32;
313 
VkVideoFrameBuffer(DeviceContext & vkDevCtx,bool supportsQueries,bool resourcesWithoutProfiles)314     VkVideoFrameBuffer(DeviceContext &vkDevCtx, bool supportsQueries, bool resourcesWithoutProfiles)
315         : m_vkDevCtx(vkDevCtx)
316         , m_refCount(0)
317         , m_perFrameDecodeImageSet()
318         , m_displayFrames()
319         , m_supportsQueries(supportsQueries)
320         , m_resourcesWithoutProfiles(resourcesWithoutProfiles)
321         , m_queryPool(VK_NULL_HANDLE)
322         , m_ownedByDisplayMask(0)
323         , m_frameNumInDecodeOrder(0)
324         , m_frameNumInDisplayOrder(0)
325         , m_numberParameterUpdates(0)
326     {
327     }
328 
329     int32_t AddRef() override;
330     int32_t Release() override;
331 
CreateVideoQueries(uint32_t numSlots,DeviceContext & vkDevCtx,const VkVideoProfileInfoKHR * pDecodeProfile)332     VkResult CreateVideoQueries(uint32_t numSlots, DeviceContext &vkDevCtx, const VkVideoProfileInfoKHR *pDecodeProfile)
333     {
334         DE_ASSERT(numSlots <= maxFramebufferImages);
335 
336         auto &vk = vkDevCtx.context->getDeviceInterface();
337 
338         if (m_queryPool == VK_NULL_HANDLE)
339         {
340             // It would be difficult to resize a query pool, so allocate the maximum possible slot.
341             numSlots = maxFramebufferImages;
342             VkQueryPoolCreateInfo queryPoolCreateInfo{};
343             queryPoolCreateInfo.sType      = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
344             queryPoolCreateInfo.pNext      = pDecodeProfile;
345             queryPoolCreateInfo.queryType  = VK_QUERY_TYPE_RESULT_STATUS_ONLY_KHR;
346             queryPoolCreateInfo.queryCount = numSlots; // m_numDecodeSurfaces frames worth
347 
348             return vk.createQueryPool(vkDevCtx.device, &queryPoolCreateInfo, nullptr, &m_queryPool);
349         }
350 
351         return VK_SUCCESS;
352     }
353 
DestroyVideoQueries()354     void DestroyVideoQueries()
355     {
356         if (m_queryPool != VK_NULL_HANDLE)
357         {
358             m_vkDevCtx.getDeviceDriver().destroyQueryPool(m_vkDevCtx.device, m_queryPool, nullptr);
359             m_queryPool = VK_NULL_HANDLE;
360         }
361     }
362 
FlushDisplayQueue()363     uint32_t FlushDisplayQueue()
364     {
365         uint32_t flushedImages = 0;
366         while (!m_displayFrames.empty())
367         {
368             uint8_t pictureIndex = m_displayFrames.front();
369             DE_ASSERT(pictureIndex < m_perFrameDecodeImageSet.size());
370             m_displayFrames.pop();
371             if (m_perFrameDecodeImageSet[(uint32_t)pictureIndex].IsAvailable())
372             {
373                 // The frame is not released yet - force release it.
374                 m_perFrameDecodeImageSet[(uint32_t)pictureIndex].Release();
375             }
376             flushedImages++;
377         }
378 
379         return flushedImages;
380     }
381 
382     int32_t InitImagePool(const VkVideoProfileInfoKHR *pDecodeProfile, uint32_t numImages, VkFormat dpbImageFormat,
383                           VkFormat outImageFormat, const VkExtent2D &maxImageExtent, VkImageUsageFlags dpbImageUsage,
384                           VkImageUsageFlags outImageUsage, uint32_t queueFamilyIndex, bool useImageArray,
385                           bool useImageViewArray, bool useSeparateOutputImage, bool useLinearOutput) override;
386 
Deinitialize()387     void Deinitialize()
388     {
389         FlushDisplayQueue();
390 
391         if (m_supportsQueries)
392             DestroyVideoQueries();
393 
394         m_ownedByDisplayMask     = 0;
395         m_frameNumInDecodeOrder  = 0;
396         m_frameNumInDisplayOrder = 0;
397 
398         if (m_queryPool != VK_NULL_HANDLE)
399         {
400             m_vkDevCtx.getDeviceDriver().destroyQueryPool(m_vkDevCtx.device, m_queryPool, nullptr);
401             m_queryPool = VK_NULL_HANDLE;
402         }
403     };
404 
QueueDecodedPictureForDisplay(int8_t picId,VulkanVideoDisplayPictureInfo * pDispInfo)405     int32_t QueueDecodedPictureForDisplay(int8_t picId, VulkanVideoDisplayPictureInfo *pDispInfo) override
406     {
407         DE_ASSERT((uint32_t)picId < m_perFrameDecodeImageSet.size());
408 
409         m_perFrameDecodeImageSet[picId].m_displayOrder = m_frameNumInDisplayOrder++;
410         m_perFrameDecodeImageSet[picId].m_timestamp    = pDispInfo->timestamp;
411         m_perFrameDecodeImageSet[picId].AddRef();
412 
413         m_displayFrames.push((uint8_t)picId);
414 
415         if (videoLoggingEnabled())
416         {
417             std::cout << std::dec << ";;; framebuffer: queue picture for display: " << (uint32_t)picId << " "
418                       << m_perFrameDecodeImageSet[picId].upscaledWidth << " x "
419                       << m_perFrameDecodeImageSet[picId].frameHeight
420                       << " displayOrder=" << m_perFrameDecodeImageSet[picId].m_displayOrder
421                       << " decodeOrder=" << m_perFrameDecodeImageSet[picId].m_decodeOrder
422                       << " timestamp=" << m_perFrameDecodeImageSet[picId].m_timestamp << std::endl;
423         }
424         return picId;
425     }
426 
427     int32_t QueuePictureForDecode(int8_t picId, VkParserDecodePictureInfo *pDecodePictureInfo,
428                                   ReferencedObjectsInfo *pReferencedObjectsInfo,
429                                   FrameSynchronizationInfo *pFrameSynchronizationInfo) override;
430 
GetDisplayedFrameCount() const431     size_t GetDisplayedFrameCount() const override
432     {
433         return m_displayFrames.size();
434     }
435 
436     // dequeue
437     int32_t DequeueDecodedPicture(DecodedFrame *pDecodedFrame) override;
438 
439     int32_t ReleaseDisplayedPicture(DecodedFrameRelease **pDecodedFramesRelease, uint32_t numFramesToRelease) override;
440 
441     int32_t GetDpbImageResourcesByIndex(
442         uint32_t numResources, const int8_t *referenceSlotIndexes, VkVideoPictureResourceInfoKHR *dpbPictureResources,
443         PictureResourceInfo *dpbPictureResourcesInfo,
444         VkImageLayout newDpbImageLayerLayout = VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR) override;
445 
446     int32_t GetCurrentImageResourceByIndex(int8_t referenceSlotIndex, VkVideoPictureResourceInfoKHR *dpbPictureResource,
447                                            PictureResourceInfo *dpbPictureResourceInfo,
448                                            VkImageLayout newDpbImageLayerLayout = VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR,
449                                            VkVideoPictureResourceInfoKHR *outputPictureResource = nullptr,
450                                            PictureResourceInfo *outputPictureResourceInfo       = nullptr,
451                                            VkImageLayout newOutputImageLayerLayout = VK_IMAGE_LAYOUT_MAX_ENUM) override;
452 
ReleaseImageResources(uint32_t numResources,const uint32_t * indexes)453     int32_t ReleaseImageResources(uint32_t numResources, const uint32_t *indexes) override
454     {
455         for (unsigned int resId = 0; resId < numResources; resId++)
456         {
457             if ((uint32_t)indexes[resId] < m_perFrameDecodeImageSet.size())
458             {
459                 m_perFrameDecodeImageSet[indexes[resId]].Deinit();
460             }
461         }
462         return (int32_t)m_perFrameDecodeImageSet.size();
463     }
464 
SetPicNumInDecodeOrder(int32_t picId,int32_t picNumInDecodeOrder)465     int32_t SetPicNumInDecodeOrder(int32_t picId, int32_t picNumInDecodeOrder) override
466     {
467         if ((uint32_t)picId < m_perFrameDecodeImageSet.size())
468         {
469             int32_t oldPicNumInDecodeOrder                = (int32_t)m_perFrameDecodeImageSet[picId].m_decodeOrder;
470             m_perFrameDecodeImageSet[picId].m_decodeOrder = picNumInDecodeOrder;
471             return oldPicNumInDecodeOrder;
472         }
473         DE_ASSERT(false);
474         return -1;
475     }
476 
SetPicNumInDisplayOrder(int32_t picId,int32_t picNumInDisplayOrder)477     int32_t SetPicNumInDisplayOrder(int32_t picId, int32_t picNumInDisplayOrder) override
478     {
479         if ((uint32_t)picId < m_perFrameDecodeImageSet.size())
480         {
481             int32_t oldPicNumInDisplayOrder                = m_perFrameDecodeImageSet[picId].m_displayOrder;
482             m_perFrameDecodeImageSet[picId].m_displayOrder = picNumInDisplayOrder;
483             return oldPicNumInDisplayOrder;
484         }
485         DE_ASSERT(false);
486         return -1;
487     }
488 
GetImageResourceByIndex(int8_t picId)489     virtual const VkSharedBaseObj<VkImageResourceView> &GetImageResourceByIndex(int8_t picId)
490     {
491         if ((uint32_t)picId < m_perFrameDecodeImageSet.size())
492         {
493             return m_perFrameDecodeImageSet[picId].GetFrameImageView();
494         }
495         DE_ASSERT(false);
496         return emptyImageView;
497     }
498 
ReservePictureBuffer()499     vkPicBuffBase *ReservePictureBuffer() override
500     {
501         int foundPicId = -1;
502         for (int picId = 0; picId < m_perFrameDecodeImageSet.size(); picId++)
503         {
504             if (m_perFrameDecodeImageSet[picId].IsAvailable())
505             {
506                 foundPicId = picId;
507                 break;
508             }
509         }
510 
511         if (foundPicId >= 0)
512         {
513             m_perFrameDecodeImageSet[foundPicId].Reset();
514             m_perFrameDecodeImageSet[foundPicId].AddRef();
515             m_perFrameDecodeImageSet[foundPicId].m_picIdx = foundPicId;
516             return &m_perFrameDecodeImageSet[foundPicId];
517         }
518 
519         DE_ASSERT(foundPicId >= 0);
520         return nullptr;
521     }
522 
GetSize()523     size_t GetSize() override
524     {
525         return m_perFrameDecodeImageSet.size();
526     }
527 
~VkVideoFrameBuffer()528     virtual ~VkVideoFrameBuffer()
529     {
530         Deinitialize();
531     }
532 
533 private:
534     DeviceContext &m_vkDevCtx;
535     std::atomic<int32_t> m_refCount;
536     NvPerFrameDecodeImageSet m_perFrameDecodeImageSet;
537     std::queue<uint8_t> m_displayFrames;
538     bool m_supportsQueries;
539     bool m_resourcesWithoutProfiles;
540     VkQueryPool m_queryPool;
541     uint32_t m_ownedByDisplayMask;
542     int32_t m_frameNumInDecodeOrder;
543     int32_t m_frameNumInDisplayOrder;
544     uint32_t m_numberParameterUpdates;
545 };
546 
Create(DeviceContext * vkDevCtx,bool supportsQueries,bool resourcesWithoutProfiles,VkSharedBaseObj<VulkanVideoFrameBuffer> & vkVideoFrameBuffer)547 VkResult VulkanVideoFrameBuffer::Create(DeviceContext *vkDevCtx, bool supportsQueries, bool resourcesWithoutProfiles,
548                                         VkSharedBaseObj<VulkanVideoFrameBuffer> &vkVideoFrameBuffer)
549 {
550     VkSharedBaseObj<VkVideoFrameBuffer> videoFrameBuffer(
551         new VkVideoFrameBuffer(*vkDevCtx, supportsQueries, resourcesWithoutProfiles));
552     if (videoFrameBuffer)
553     {
554         vkVideoFrameBuffer = videoFrameBuffer;
555         return VK_SUCCESS;
556     }
557     return VK_ERROR_OUT_OF_HOST_MEMORY;
558 }
559 
AddRef()560 int32_t VkVideoFrameBuffer::AddRef()
561 {
562     return ++m_refCount;
563 }
564 
Release()565 int32_t VkVideoFrameBuffer::Release()
566 {
567     uint32_t ret;
568     ret = --m_refCount;
569     // Destroy the device if refcount reaches zero
570     if (ret == 0)
571     {
572         delete this;
573     }
574     return ret;
575 }
576 
QueuePictureForDecode(int8_t picId,VkParserDecodePictureInfo * pDecodePictureInfo,VulkanVideoFrameBuffer::ReferencedObjectsInfo * pReferencedObjectsInfo,VulkanVideoFrameBuffer::FrameSynchronizationInfo * pFrameSynchronizationInfo)577 int32_t VkVideoFrameBuffer::QueuePictureForDecode(
578     int8_t picId, VkParserDecodePictureInfo *pDecodePictureInfo,
579     VulkanVideoFrameBuffer::ReferencedObjectsInfo *pReferencedObjectsInfo,
580     VulkanVideoFrameBuffer::FrameSynchronizationInfo *pFrameSynchronizationInfo)
581 {
582     DE_ASSERT((uint32_t)picId < m_perFrameDecodeImageSet.size());
583 
584     m_perFrameDecodeImageSet[picId].m_picDispInfo = *pDecodePictureInfo;
585     m_perFrameDecodeImageSet[picId].m_decodeOrder = m_frameNumInDecodeOrder++;
586     m_perFrameDecodeImageSet[picId].stdPps        = const_cast<VkVideoRefCountBase *>(pReferencedObjectsInfo->pStdPps);
587     m_perFrameDecodeImageSet[picId].stdSps        = const_cast<VkVideoRefCountBase *>(pReferencedObjectsInfo->pStdSps);
588     m_perFrameDecodeImageSet[picId].stdVps        = const_cast<VkVideoRefCountBase *>(pReferencedObjectsInfo->pStdVps);
589     m_perFrameDecodeImageSet[picId].stdAv1Sps = const_cast<VkVideoRefCountBase *>(pReferencedObjectsInfo->pStdAV1Sps);
590     m_perFrameDecodeImageSet[picId].bitstreamData =
591         const_cast<VkVideoRefCountBase *>(pReferencedObjectsInfo->pBitstreamData);
592 
593     if (videoLoggingEnabled())
594     {
595         static int counter = 0;
596         tcu::print(";;; %d queue decode: %d: decoderOrder=%d displayOrder=%d completeFence=%d consumerDoneFence=%d "
597                    "completeSem=%d consumerDoneSem=%d\n",
598                    counter++, picId, (int)m_perFrameDecodeImageSet[picId].m_decodeOrder,
599                    m_perFrameDecodeImageSet[picId].m_displayOrder,
600                    (uint32_t)m_perFrameDecodeImageSet[picId].m_frameCompleteFence.getInternal(),
601                    (uint32_t)m_perFrameDecodeImageSet[picId].m_frameConsumerDoneFence.getInternal(),
602                    (uint32_t)m_perFrameDecodeImageSet[picId].m_frameCompleteSemaphore.getInternal(),
603                    (uint32_t)m_perFrameDecodeImageSet[picId].m_frameConsumerDoneSemaphore.getInternal());
604     }
605 
606     if (pFrameSynchronizationInfo->hasFrameCompleteSignalFence)
607     {
608         pFrameSynchronizationInfo->frameCompleteFence = m_perFrameDecodeImageSet[picId].m_frameCompleteFence;
609         if (!!pFrameSynchronizationInfo->frameCompleteFence)
610         {
611             m_perFrameDecodeImageSet[picId].m_hasFrameCompleteSignalFence = true;
612         }
613     }
614 
615     if (m_perFrameDecodeImageSet[picId].m_hasConsummerSignalFence)
616     {
617         pFrameSynchronizationInfo->frameConsumerDoneFence = m_perFrameDecodeImageSet[picId].m_frameConsumerDoneFence;
618         m_perFrameDecodeImageSet[picId].m_hasConsummerSignalFence = false;
619     }
620 
621     if (pFrameSynchronizationInfo->hasFrameCompleteSignalSemaphore)
622     {
623         pFrameSynchronizationInfo->frameCompleteSemaphore = m_perFrameDecodeImageSet[picId].m_frameCompleteSemaphore;
624         if (!!pFrameSynchronizationInfo->frameCompleteSemaphore)
625         {
626             m_perFrameDecodeImageSet[picId].m_hasFrameCompleteSignalSemaphore = true;
627         }
628     }
629 
630     if (m_perFrameDecodeImageSet[picId].m_hasConsummerSignalSemaphore)
631     {
632         pFrameSynchronizationInfo->frameConsumerDoneSemaphore =
633             m_perFrameDecodeImageSet[picId].m_frameConsumerDoneSemaphore;
634         m_perFrameDecodeImageSet[picId].m_hasConsummerSignalSemaphore = false;
635     }
636 
637     pFrameSynchronizationInfo->queryPool    = m_queryPool;
638     pFrameSynchronizationInfo->startQueryId = picId;
639     pFrameSynchronizationInfo->numQueries   = 1;
640 
641     return picId;
642 }
643 
DequeueDecodedPicture(DecodedFrame * pDecodedFrame)644 int32_t VkVideoFrameBuffer::DequeueDecodedPicture(DecodedFrame *pDecodedFrame)
645 {
646     int numberofPendingFrames = 0;
647     int pictureIndex          = -1;
648     if (!m_displayFrames.empty())
649     {
650         numberofPendingFrames = (int)m_displayFrames.size();
651         pictureIndex          = m_displayFrames.front();
652         DE_ASSERT((pictureIndex >= 0) && ((uint32_t)pictureIndex < m_perFrameDecodeImageSet.size()));
653         // TODO: This incorrectly trips in some Argon tests,
654         // suspect it's a problem with the showable vs never
655         // shown frames not being tracked correctly.
656         DE_ASSERT(!(m_ownedByDisplayMask & (1 << pictureIndex)));
657         m_ownedByDisplayMask |= (1 << pictureIndex);
658         m_displayFrames.pop();
659     }
660 
661     if ((uint32_t)pictureIndex < m_perFrameDecodeImageSet.size())
662     {
663         pDecodedFrame->pictureIndex = pictureIndex;
664 
665         pDecodedFrame->imageLayerIndex = m_perFrameDecodeImageSet[pictureIndex].m_picDispInfo.imageLayerIndex;
666 
667         pDecodedFrame->decodedImageView = m_perFrameDecodeImageSet[pictureIndex].GetFrameImageView();
668         pDecodedFrame->outputImageView  = m_perFrameDecodeImageSet[pictureIndex].GetDisplayImageView();
669 
670         pDecodedFrame->displayWidth  = m_perFrameDecodeImageSet[pictureIndex].m_picDispInfo.displayWidth;
671         pDecodedFrame->displayHeight = m_perFrameDecodeImageSet[pictureIndex].m_picDispInfo.displayHeight;
672 
673         if (m_perFrameDecodeImageSet[pictureIndex].m_hasFrameCompleteSignalFence)
674         {
675             pDecodedFrame->frameCompleteFence = m_perFrameDecodeImageSet[pictureIndex].m_frameCompleteFence;
676             m_perFrameDecodeImageSet[pictureIndex].m_hasFrameCompleteSignalFence = false;
677         }
678         else
679         {
680             pDecodedFrame->frameCompleteFence = VK_NULL_HANDLE;
681         }
682 
683         if (m_perFrameDecodeImageSet[pictureIndex].m_hasFrameCompleteSignalSemaphore)
684         {
685             pDecodedFrame->frameCompleteSemaphore = m_perFrameDecodeImageSet[pictureIndex].m_frameCompleteSemaphore;
686             m_perFrameDecodeImageSet[pictureIndex].m_hasFrameCompleteSignalSemaphore = false;
687         }
688         else
689         {
690             pDecodedFrame->frameCompleteSemaphore = VK_NULL_HANDLE;
691         }
692 
693         pDecodedFrame->frameConsumerDoneFence     = m_perFrameDecodeImageSet[pictureIndex].m_frameConsumerDoneFence;
694         pDecodedFrame->frameConsumerDoneSemaphore = m_perFrameDecodeImageSet[pictureIndex].m_frameConsumerDoneSemaphore;
695 
696         pDecodedFrame->timestamp    = m_perFrameDecodeImageSet[pictureIndex].m_timestamp;
697         pDecodedFrame->decodeOrder  = (int32_t)m_perFrameDecodeImageSet[pictureIndex].m_decodeOrder;
698         pDecodedFrame->displayOrder = m_perFrameDecodeImageSet[pictureIndex].m_displayOrder;
699 
700         pDecodedFrame->queryPool    = m_queryPool;
701         pDecodedFrame->startQueryId = pictureIndex;
702         pDecodedFrame->numQueries   = 1;
703     }
704 
705     return numberofPendingFrames;
706 }
707 
ReleaseDisplayedPicture(DecodedFrameRelease ** pDecodedFramesRelease,uint32_t numFramesToRelease)708 int32_t VkVideoFrameBuffer::ReleaseDisplayedPicture(DecodedFrameRelease **pDecodedFramesRelease,
709                                                     uint32_t numFramesToRelease)
710 {
711     for (uint32_t i = 0; i < numFramesToRelease; i++)
712     {
713         const DecodedFrameRelease *pDecodedFrameRelease = pDecodedFramesRelease[i];
714         int picId                                       = pDecodedFrameRelease->pictureIndex;
715         DE_ASSERT((picId >= 0) && ((uint32_t)picId < m_perFrameDecodeImageSet.size()));
716 
717         DE_ASSERT(m_perFrameDecodeImageSet[picId].m_decodeOrder == pDecodedFrameRelease->decodeOrder);
718         DE_ASSERT(m_perFrameDecodeImageSet[picId].m_displayOrder == pDecodedFrameRelease->displayOrder);
719 
720         DE_ASSERT(m_ownedByDisplayMask & (1 << picId));
721         m_ownedByDisplayMask &= ~(1 << picId);
722         m_perFrameDecodeImageSet[picId].bitstreamData = nullptr;
723         m_perFrameDecodeImageSet[picId].stdPps        = nullptr;
724         m_perFrameDecodeImageSet[picId].stdSps        = nullptr;
725         m_perFrameDecodeImageSet[picId].stdVps        = nullptr;
726         m_perFrameDecodeImageSet[picId].stdAv1Sps     = nullptr;
727         m_perFrameDecodeImageSet[picId].Release();
728 
729         m_perFrameDecodeImageSet[picId].m_hasConsummerSignalFence = pDecodedFrameRelease->hasConsummerSignalFence;
730         m_perFrameDecodeImageSet[picId].m_hasConsummerSignalSemaphore =
731             pDecodedFrameRelease->hasConsummerSignalSemaphore;
732     }
733     return 0;
734 }
735 
GetDpbImageResourcesByIndex(uint32_t numResources,const int8_t * referenceSlotIndexes,VkVideoPictureResourceInfoKHR * dpbPictureResources,VulkanVideoFrameBuffer::PictureResourceInfo * dpbPictureResourcesInfo,VkImageLayout newDpbImageLayerLayout)736 int32_t VkVideoFrameBuffer::GetDpbImageResourcesByIndex(
737     uint32_t numResources, const int8_t *referenceSlotIndexes, VkVideoPictureResourceInfoKHR *dpbPictureResources,
738     VulkanVideoFrameBuffer::PictureResourceInfo *dpbPictureResourcesInfo, VkImageLayout newDpbImageLayerLayout)
739 {
740     DE_ASSERT(dpbPictureResources);
741     for (unsigned int resId = 0; resId < numResources; resId++)
742     {
743         if ((uint32_t)referenceSlotIndexes[resId] < m_perFrameDecodeImageSet.size())
744         {
745             VkResult result = m_perFrameDecodeImageSet.GetImageSetNewLayout(
746                 m_vkDevCtx, referenceSlotIndexes[resId], newDpbImageLayerLayout, &dpbPictureResources[resId],
747                 &dpbPictureResourcesInfo[resId]);
748 
749             DE_ASSERT(result == VK_SUCCESS);
750             if (result != VK_SUCCESS)
751             {
752                 return -1;
753             }
754 
755             DE_ASSERT(dpbPictureResources[resId].sType == VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_INFO_KHR);
756             dpbPictureResources[resId].codedOffset = {
757                 0, 0}; // FIXME: This parameter must to be adjusted based on the interlaced mode.
758 
759             dpbPictureResources[resId].codedExtent.width =
760                 m_perFrameDecodeImageSet[referenceSlotIndexes[resId]].upscaledWidth;
761             dpbPictureResources[resId].codedExtent.height =
762                 m_perFrameDecodeImageSet[referenceSlotIndexes[resId]].frameHeight;
763         }
764     }
765     return numResources;
766 }
767 
GetCurrentImageResourceByIndex(int8_t picIdx,VkVideoPictureResourceInfoKHR * dpbPictureResource,VulkanVideoFrameBuffer::PictureResourceInfo * dpbPictureResourceInfo,VkImageLayout newDpbImageLayerLayout,VkVideoPictureResourceInfoKHR * outputPictureResource,VulkanVideoFrameBuffer::PictureResourceInfo * outputPictureResourceInfo,VkImageLayout newOutputImageLayerLayout)768 int32_t VkVideoFrameBuffer::GetCurrentImageResourceByIndex(
769     int8_t picIdx, VkVideoPictureResourceInfoKHR *dpbPictureResource,
770     VulkanVideoFrameBuffer::PictureResourceInfo *dpbPictureResourceInfo, VkImageLayout newDpbImageLayerLayout,
771     VkVideoPictureResourceInfoKHR *outputPictureResource,
772     VulkanVideoFrameBuffer::PictureResourceInfo *outputPictureResourceInfo, VkImageLayout newOutputImageLayerLayout)
773 {
774     DE_ASSERT(dpbPictureResource);
775     if ((uint32_t)picIdx < m_perFrameDecodeImageSet.size())
776     {
777         VkResult result = m_perFrameDecodeImageSet.GetImageSetNewLayout(
778             m_vkDevCtx, picIdx, newDpbImageLayerLayout, dpbPictureResource, dpbPictureResourceInfo,
779             newOutputImageLayerLayout, outputPictureResource, outputPictureResourceInfo);
780         DE_ASSERT(result == VK_SUCCESS);
781         if (result != VK_SUCCESS)
782         {
783             return -1;
784         }
785 
786         DE_ASSERT(dpbPictureResource->sType == VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_INFO_KHR);
787     }
788     return picIdx;
789 }
790 
InitImagePool(const VkVideoProfileInfoKHR * pDecodeProfile,uint32_t numImages,VkFormat dpbImageFormat,VkFormat outImageFormat,const VkExtent2D & maxImageExtent,VkImageUsageFlags dpbImageUsage,VkImageUsageFlags outImageUsage,uint32_t queueFamilyIndex,bool useImageArray,bool useImageViewArray,bool useSeparateOutputImage,bool useLinearOutput)791 int32_t VkVideoFrameBuffer::InitImagePool(const VkVideoProfileInfoKHR *pDecodeProfile, uint32_t numImages,
792                                           VkFormat dpbImageFormat, VkFormat outImageFormat,
793                                           const VkExtent2D &maxImageExtent, VkImageUsageFlags dpbImageUsage,
794                                           VkImageUsageFlags outImageUsage, uint32_t queueFamilyIndex,
795                                           bool useImageArray, bool useImageViewArray, bool useSeparateOutputImage,
796                                           bool useLinearOutput)
797 {
798     DE_ASSERT(numImages && (numImages <= maxFramebufferImages) && pDecodeProfile);
799 
800     if (m_supportsQueries)
801         VK_CHECK(CreateVideoQueries(numImages, m_vkDevCtx, pDecodeProfile));
802 
803     int32_t imageSetCreateResult = m_perFrameDecodeImageSet.init(
804         m_vkDevCtx, pDecodeProfile, numImages, dpbImageFormat, outImageFormat, maxImageExtent, dpbImageUsage,
805         outImageUsage, queueFamilyIndex, useImageArray, useImageViewArray, useSeparateOutputImage, useLinearOutput,
806         m_resourcesWithoutProfiles);
807     m_numberParameterUpdates++;
808 
809     return imageSetCreateResult;
810 }
811 
CreateImage(DeviceContext & vkDevCtx,const VkImageCreateInfo * pDpbImageCreateInfo,const VkImageCreateInfo * pOutImageCreateInfo,uint32_t imageIndex,VkSharedBaseObj<VkImageResource> & imageArrayParent,VkSharedBaseObj<VkImageResourceView> & imageViewArrayParent,bool useSeparateOutputImage,bool useLinearOutput)812 VkResult NvPerFrameDecodeResources::CreateImage(DeviceContext &vkDevCtx, const VkImageCreateInfo *pDpbImageCreateInfo,
813                                                 const VkImageCreateInfo *pOutImageCreateInfo, uint32_t imageIndex,
814                                                 VkSharedBaseObj<VkImageResource> &imageArrayParent,
815                                                 VkSharedBaseObj<VkImageResourceView> &imageViewArrayParent,
816                                                 bool useSeparateOutputImage, bool useLinearOutput)
817 {
818     VkResult result = VK_SUCCESS;
819 
820     if (!ImageExist() || m_recreateImage)
821     {
822 
823         DE_ASSERT(m_vkDevCtx != nullptr);
824 
825         m_currentDpbImageLayerLayout = pDpbImageCreateInfo->initialLayout;
826         m_currentOutputImageLayout   = pOutImageCreateInfo->initialLayout;
827 
828         VkSharedBaseObj<VkImageResource> imageResource;
829         if (!imageArrayParent)
830         {
831             result = VkImageResource::Create(vkDevCtx, pDpbImageCreateInfo, imageResource);
832             if (result != VK_SUCCESS)
833             {
834                 return result;
835             }
836         }
837         else
838         {
839             // We are using a parent array image
840             imageResource = imageArrayParent;
841         }
842 
843         if (!imageViewArrayParent)
844         {
845 
846             uint32_t baseArrayLayer                  = imageArrayParent ? imageIndex : 0;
847             VkImageSubresourceRange subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, baseArrayLayer, 1};
848             result = VkImageResourceView::Create(vkDevCtx, imageResource, subresourceRange, m_frameDpbImageView);
849 
850             if (result != VK_SUCCESS)
851             {
852                 return result;
853             }
854 
855             if (!(useSeparateOutputImage || useLinearOutput))
856             {
857                 m_outImageView = m_frameDpbImageView;
858             }
859         }
860         else
861         {
862 
863             m_frameDpbImageView = imageViewArrayParent;
864 
865             if (!(useSeparateOutputImage || useLinearOutput))
866             {
867                 VkImageSubresourceRange subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, imageIndex, 1};
868                 result = VkImageResourceView::Create(vkDevCtx, imageResource, subresourceRange, m_outImageView);
869                 if (result != VK_SUCCESS)
870                 {
871                     return result;
872                 }
873             }
874         }
875 
876         if (useSeparateOutputImage || useLinearOutput)
877         {
878 
879             VkSharedBaseObj<VkImageResource> displayImageResource;
880             result = VkImageResource::Create(vkDevCtx, pOutImageCreateInfo, displayImageResource);
881             if (result != VK_SUCCESS)
882             {
883                 return result;
884             }
885 
886             VkImageSubresourceRange subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
887             result = VkImageResourceView::Create(vkDevCtx, displayImageResource, subresourceRange, m_outImageView);
888             if (result != VK_SUCCESS)
889             {
890                 return result;
891             }
892         }
893     }
894 
895     m_currentDpbImageLayerLayout = VK_IMAGE_LAYOUT_UNDEFINED;
896     m_currentOutputImageLayout   = VK_IMAGE_LAYOUT_UNDEFINED;
897     m_recreateImage              = false;
898 
899     return result;
900 }
901 
init(DeviceContext & vkDevCtx)902 VkResult NvPerFrameDecodeResources::init(DeviceContext &vkDevCtx)
903 {
904     m_vkDevCtx  = &vkDevCtx;
905     auto &vk    = vkDevCtx.getDeviceDriver();
906     auto device = vkDevCtx.device;
907 
908     // The fence waited on for the first frame should be signaled.
909     const VkFenceCreateInfo fenceFrameCompleteInfo = {VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, nullptr,
910                                                       VK_FENCE_CREATE_SIGNALED_BIT};
911     VkResult result = vk.createFence(device, &fenceFrameCompleteInfo, nullptr, &m_frameCompleteFence);
912 
913     VkFenceCreateInfo fenceInfo{};
914     fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
915     result          = vk.createFence(device, &fenceInfo, nullptr, &m_frameConsumerDoneFence);
916     DE_ASSERT(result == VK_SUCCESS);
917 
918     VkSemaphoreCreateInfo semInfo{};
919     semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
920     result        = vk.createSemaphore(device, &semInfo, nullptr, &m_frameCompleteSemaphore);
921     DE_ASSERT(result == VK_SUCCESS);
922     result = vk.createSemaphore(device, &semInfo, nullptr, &m_frameConsumerDoneSemaphore);
923     DE_ASSERT(result == VK_SUCCESS);
924 
925     Reset();
926 
927     return result;
928 }
929 
Deinit()930 void NvPerFrameDecodeResources::Deinit()
931 {
932     bitstreamData = nullptr;
933     stdPps        = nullptr;
934     stdSps        = nullptr;
935     stdVps        = nullptr;
936     stdAv1Sps     = nullptr;
937 
938     if (m_vkDevCtx == nullptr)
939     {
940         assert((m_frameCompleteFence == VK_NULL_HANDLE) && (m_frameConsumerDoneFence == VK_NULL_HANDLE) &&
941                (m_frameCompleteSemaphore == VK_NULL_HANDLE) && (m_frameConsumerDoneSemaphore == VK_NULL_HANDLE) &&
942                !m_frameDpbImageView && !m_outImageView);
943         return;
944     }
945 
946     DE_ASSERT(m_vkDevCtx);
947     auto &vk    = m_vkDevCtx->getDeviceDriver();
948     auto device = m_vkDevCtx->device;
949 
950     if (m_frameCompleteFence != VK_NULL_HANDLE)
951     {
952         vk.destroyFence(device, m_frameCompleteFence, nullptr);
953         m_frameCompleteFence = VK_NULL_HANDLE;
954     }
955 
956     if (m_frameConsumerDoneFence != VK_NULL_HANDLE)
957     {
958         vk.destroyFence(device, m_frameConsumerDoneFence, nullptr);
959         m_frameConsumerDoneFence = VK_NULL_HANDLE;
960     }
961 
962     if (m_frameCompleteSemaphore != VK_NULL_HANDLE)
963     {
964         vk.destroySemaphore(device, m_frameCompleteSemaphore, nullptr);
965         m_frameCompleteSemaphore = VK_NULL_HANDLE;
966     }
967 
968     if (m_frameConsumerDoneSemaphore != VK_NULL_HANDLE)
969     {
970         vk.destroySemaphore(device, m_frameConsumerDoneSemaphore, nullptr);
971         m_frameConsumerDoneSemaphore = VK_NULL_HANDLE;
972     }
973 
974     m_frameDpbImageView = nullptr;
975     m_outImageView      = nullptr;
976 
977     m_vkDevCtx = nullptr;
978 
979     Reset();
980 }
981 
init(DeviceContext & vkDevCtx,const VkVideoProfileInfoKHR * pDecodeProfile,uint32_t numImages,VkFormat dpbImageFormat,VkFormat outImageFormat,const VkExtent2D & maxImageExtent,VkImageUsageFlags dpbImageUsage,VkImageUsageFlags outImageUsage,uint32_t queueFamilyIndex,bool useImageArray,bool useImageViewArray,bool useSeparateOutputImage,bool useLinearOutput,bool resourcesWithoutProfiles)982 int32_t NvPerFrameDecodeImageSet::init(DeviceContext &vkDevCtx, const VkVideoProfileInfoKHR *pDecodeProfile,
983                                        uint32_t numImages, VkFormat dpbImageFormat, VkFormat outImageFormat,
984                                        const VkExtent2D &maxImageExtent, VkImageUsageFlags dpbImageUsage,
985                                        VkImageUsageFlags outImageUsage, uint32_t queueFamilyIndex, bool useImageArray,
986                                        bool useImageViewArray, bool useSeparateOutputImage, bool useLinearOutput,
987                                        bool resourcesWithoutProfiles)
988 {
989     if (numImages > m_perFrameDecodeResources.size())
990     {
991         DE_ASSERT(!"Number of requested images exceeds the max size of the image array");
992         return -1;
993     }
994 
995     const bool reconfigureImages =
996         (m_numImages && (m_dpbImageCreateInfo.sType == VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO)) &&
997         ((m_dpbImageCreateInfo.format != dpbImageFormat) ||
998          (m_dpbImageCreateInfo.extent.width < maxImageExtent.width) ||
999          (m_dpbImageCreateInfo.extent.height < maxImageExtent.height));
1000 
1001     for (uint32_t imageIndex = m_numImages; imageIndex < numImages; imageIndex++)
1002     {
1003         VkResult result = m_perFrameDecodeResources[imageIndex].init(vkDevCtx);
1004         DE_ASSERT(result == VK_SUCCESS);
1005         if (result != VK_SUCCESS)
1006         {
1007             return -1;
1008         }
1009     }
1010 
1011     if (useImageViewArray)
1012     {
1013         useImageArray = true;
1014     }
1015 
1016     m_videoProfile.InitFromProfile(pDecodeProfile);
1017 
1018     m_queueFamilyIndex = queueFamilyIndex;
1019 
1020     // Image create info for the DPBs
1021     m_dpbImageCreateInfo.sType       = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
1022     m_dpbImageCreateInfo.pNext       = resourcesWithoutProfiles ? nullptr : m_videoProfile.GetProfileListInfo();
1023     m_dpbImageCreateInfo.imageType   = VK_IMAGE_TYPE_2D;
1024     m_dpbImageCreateInfo.format      = dpbImageFormat;
1025     m_dpbImageCreateInfo.extent      = {maxImageExtent.width, maxImageExtent.height, 1};
1026     m_dpbImageCreateInfo.mipLevels   = 1;
1027     m_dpbImageCreateInfo.arrayLayers = useImageArray ? numImages : 1;
1028     m_dpbImageCreateInfo.samples     = VK_SAMPLE_COUNT_1_BIT;
1029     m_dpbImageCreateInfo.tiling      = VK_IMAGE_TILING_OPTIMAL;
1030     m_dpbImageCreateInfo.usage       = dpbImageUsage;
1031     m_dpbImageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
1032     m_dpbImageCreateInfo.queueFamilyIndexCount = 1;
1033     m_dpbImageCreateInfo.pQueueFamilyIndices   = &m_queueFamilyIndex;
1034     m_dpbImageCreateInfo.initialLayout         = VK_IMAGE_LAYOUT_UNDEFINED;
1035     m_dpbImageCreateInfo.flags = resourcesWithoutProfiles ? VK_IMAGE_CREATE_VIDEO_PROFILE_INDEPENDENT_BIT_KHR : 0;
1036 
1037     // Image create info for the output
1038     if (useSeparateOutputImage || useLinearOutput)
1039     {
1040         m_outImageCreateInfo             = m_dpbImageCreateInfo;
1041         m_outImageCreateInfo.format      = outImageFormat;
1042         m_outImageCreateInfo.arrayLayers = 1;
1043         m_outImageCreateInfo.tiling      = useLinearOutput ? VK_IMAGE_TILING_LINEAR : VK_IMAGE_TILING_OPTIMAL;
1044         m_outImageCreateInfo.usage       = outImageUsage;
1045 
1046         if ((outImageUsage & VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR) == 0)
1047         {
1048             // A simple output image not directly used by the decoder
1049             m_outImageCreateInfo.pNext = nullptr;
1050         }
1051     }
1052 
1053     if (useImageArray)
1054     {
1055         // Create an image that has the same number of layers as the DPB images required.
1056         VkResult result = VkImageResource::Create(vkDevCtx, &m_dpbImageCreateInfo, m_imageArray);
1057         if (result != VK_SUCCESS)
1058         {
1059             return -1;
1060         }
1061     }
1062     else
1063     {
1064         m_imageArray = nullptr;
1065     }
1066 
1067     if (useImageViewArray)
1068     {
1069         DE_ASSERT(m_imageArray);
1070         // Create an image view that has the same number of layers as the image.
1071         // In that scenario, while specifying the resource, the API must specifically choose the image layer.
1072         VkImageSubresourceRange subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, numImages};
1073         VkResult result = VkImageResourceView::Create(vkDevCtx, m_imageArray, subresourceRange, m_imageViewArray);
1074 
1075         if (result != VK_SUCCESS)
1076         {
1077             return -1;
1078         }
1079     }
1080 
1081     uint32_t firstIndex   = reconfigureImages ? 0 : m_numImages;
1082     uint32_t maxNumImages = std::max(m_numImages, numImages);
1083     for (uint32_t imageIndex = firstIndex; imageIndex < maxNumImages; imageIndex++)
1084     {
1085 
1086         if (m_perFrameDecodeResources[imageIndex].ImageExist() && reconfigureImages)
1087         {
1088 
1089             m_perFrameDecodeResources[imageIndex].m_recreateImage = true;
1090         }
1091         else if (!m_perFrameDecodeResources[imageIndex].ImageExist())
1092         {
1093 
1094             VkResult result = m_perFrameDecodeResources[imageIndex].CreateImage(
1095                 vkDevCtx, &m_dpbImageCreateInfo, &m_outImageCreateInfo, imageIndex, m_imageArray, m_imageViewArray,
1096                 useSeparateOutputImage, useLinearOutput);
1097 
1098             DE_ASSERT(result == VK_SUCCESS);
1099             if (result != VK_SUCCESS)
1100             {
1101                 return -1;
1102             }
1103         }
1104     }
1105 
1106     m_numImages               = numImages;
1107     m_usesImageArray          = useImageArray;
1108     m_usesImageViewArray      = useImageViewArray;
1109     m_usesSeparateOutputImage = useSeparateOutputImage;
1110     m_usesLinearOutput        = useLinearOutput;
1111 
1112     return (int32_t)numImages;
1113 }
1114 
1115 } // namespace video
1116 } // namespace vkt
1117