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