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