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