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