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 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 227 size_t size() const 228 { 229 return m_numImages; 230 } 231 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 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 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 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 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 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 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 423 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 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 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 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 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 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 504 size_t GetSize() override { 505 std::lock_guard<std::mutex> lock(m_displayQueueMutex); 506 return m_perFrameDecodeImageSet.size(); 507 } 508 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 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 538 int32_t VkVideoFrameBuffer::AddRef() 539 { 540 return ++m_refCount; 541 } 542 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 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 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 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 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 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 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 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 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 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 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