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