• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2021 The Khronos Group Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Video decoding module
22  *//*--------------------------------------------------------------------*/
23 /*
24  * Copyright 2020 NVIDIA Corporation.
25  *
26  * Licensed under the Apache License, Version 2.0 (the "License");
27  * you may not use this file except in compliance with the License.
28  * You may obtain a copy of the License at
29  *
30  *    http://www.apache.org/licenses/LICENSE-2.0
31  *
32  * Unless required by applicable law or agreed to in writing, software
33  * distributed under the License is distributed on an "AS IS" BASIS,
34  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
35  * See the License for the specific language governing permissions and
36  * limitations under the License.
37  */
38 
39 #include "vktVideoBaseDecodeUtils.hpp"
40 
41 #include "vkDefs.hpp"
42 #include "vkStrUtil.hpp"
43 #include "vkBarrierUtil.hpp"
44 #include "vkObjUtil.hpp"
45 
46 #include <unordered_set>
47 #include <algorithm>
48 #include <numeric>
49 #include <random>
50 
51 // FIXME: The samples repo is missing this internal include from their H265 decoder
52 #include "nvVulkanh265ScalingList.h"
53 #include <VulkanH264Decoder.h>
54 #include <VulkanH265Decoder.h>
55 #include <VulkanAV1Decoder.h>
56 
57 namespace vkt
58 {
59 namespace video
60 {
61 using namespace vk;
62 using namespace std;
63 using de::MovePtr;
64 
65 static const uint32_t topFieldShift        = 0;
66 static const uint32_t topFieldMask         = (1 << topFieldShift);
67 static const uint32_t bottomFieldShift     = 1;
68 static const uint32_t bottomFieldMask      = (1 << bottomFieldShift);
69 static const uint32_t fieldIsReferenceMask = (topFieldMask | bottomFieldMask);
70 
71 // The number of frame surfaces and associated frame data to
72 // pool. This is an exuberant maximum for testing convenience. No real
73 // sequence should require this many concurrent surfaces.
74 static constexpr uint32_t MAX_NUM_DECODE_SURFACES = 32u;
75 
76 static constexpr uint32_t H26X_MAX_DPB_SLOTS = 16u;
77 // static constexpr uint32_t AV1_MAX_DPB_SLOTS = 8u;
78 
79 using VkVideoParser = VkSharedBaseObj<VulkanVideoDecodeParser>;
80 
createParser(VkVideoCodecOperationFlagBitsKHR codecOperation,std::shared_ptr<VideoBaseDecoder> decoder,VkVideoParser & parser,ElementaryStreamFraming framing)81 void createParser(VkVideoCodecOperationFlagBitsKHR codecOperation, std::shared_ptr<VideoBaseDecoder> decoder,
82                   VkVideoParser &parser, ElementaryStreamFraming framing)
83 {
84     const VkVideoCapabilitiesKHR *videoCaps     = decoder->getVideoCaps();
85     const VkParserInitDecodeParameters pdParams = {
86         NV_VULKAN_VIDEO_PARSER_API_VERSION,
87         dynamic_cast<VkParserVideoDecodeClient *>(decoder.get()),
88         static_cast<uint32_t>(2 * 1024 * 1024), // 2MiB is an arbitrary choice (and pointless for the CTS)
89         static_cast<uint32_t>(videoCaps->minBitstreamBufferOffsetAlignment),
90         static_cast<uint32_t>(videoCaps->minBitstreamBufferSizeAlignment),
91         0,
92         0,
93         nullptr,
94         true,
95     };
96 
97     switch (codecOperation)
98     {
99     case VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR:
100     {
101         VkSharedBaseObj<VulkanH264Decoder> nvVideoH264DecodeParser(new VulkanH264Decoder(codecOperation));
102         parser = nvVideoH264DecodeParser;
103         break;
104     }
105     case VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR:
106     {
107         VkSharedBaseObj<VulkanH265Decoder> nvVideoH265DecodeParser(new VulkanH265Decoder(codecOperation));
108         parser = nvVideoH265DecodeParser;
109         break;
110     }
111     case VK_VIDEO_CODEC_OPERATION_DECODE_AV1_BIT_KHR:
112     {
113         VkSharedBaseObj<VulkanAV1Decoder> nvVideoAV1DecodeParser(
114             new VulkanAV1Decoder(codecOperation, framing == ElementaryStreamFraming::AV1_ANNEXB));
115         parser = nvVideoAV1DecodeParser;
116         break;
117     }
118     default:
119         TCU_FAIL("Unsupported codec type");
120     }
121 
122     VK_CHECK(parser->Initialize(&pdParams));
123 }
124 
GetPic(VkPicIf * pPicBuf)125 inline vkPicBuffBase *GetPic(VkPicIf *pPicBuf)
126 {
127     return (vkPicBuffBase *)pPicBuf;
128 }
129 
130 typedef struct dpbH264Entry
131 {
132     int8_t dpbSlot;
133     // bit0(used_for_reference)=1: top field used for reference,
134     // bit1(used_for_reference)=1: bottom field used for reference
135     uint32_t used_for_reference : 2;
136     uint32_t is_long_term       : 1; // 0 = short-term, 1 = long-term
137     uint32_t is_non_existing    : 1; // 1 = marked as non-existing
138     uint32_t is_field_ref       : 1; // set if unpaired field or complementary field pair
139     union
140     {
141         int16_t FieldOrderCnt[2]; // h.264 : 2*32 [top/bottom].
142         int32_t PicOrderCnt;      // HEVC PicOrderCnt
143     };
144     union
145     {
146         int16_t FrameIdx; // : 16   short-term: FrameNum (16 bits), long-term:
147         // LongTermFrameIdx (4 bits)
148         int8_t originalDpbIndex; // Original Dpb source Index.
149     };
150     vkPicBuffBase *m_picBuff; // internal picture reference
151 
setReferenceAndTopBottomFieldvkt::video::dpbH264Entry152     void setReferenceAndTopBottomField(bool isReference, bool nonExisting, bool isLongTerm, bool isFieldRef,
153                                        bool topFieldIsReference, bool bottomFieldIsReference, int16_t frameIdx,
154                                        const int16_t fieldOrderCntList[2], vkPicBuffBase *picBuff)
155     {
156         is_non_existing = nonExisting;
157         is_long_term    = isLongTerm;
158         is_field_ref    = isFieldRef;
159         if (isReference && isFieldRef)
160         {
161             used_for_reference = (bottomFieldIsReference << bottomFieldShift) | (topFieldIsReference << topFieldShift);
162         }
163         else
164         {
165             used_for_reference = isReference ? 3 : 0;
166         }
167 
168         FrameIdx = frameIdx;
169 
170         FieldOrderCnt[0] = fieldOrderCntList[used_for_reference == 2]; // 0: for progressive and top reference; 1: for
171         // bottom reference only.
172         FieldOrderCnt[1] = fieldOrderCntList[used_for_reference != 1]; // 0: for top reference only;  1: for bottom
173         // reference and progressive.
174 
175         dpbSlot   = -1;
176         m_picBuff = picBuff;
177     }
178 
setReferencevkt::video::dpbH264Entry179     void setReference(bool isLongTerm, int32_t picOrderCnt, vkPicBuffBase *picBuff)
180     {
181         is_non_existing    = (picBuff == NULL);
182         is_long_term       = isLongTerm;
183         is_field_ref       = false;
184         used_for_reference = (picBuff != NULL) ? 3 : 0;
185 
186         PicOrderCnt = picOrderCnt;
187 
188         dpbSlot          = -1;
189         m_picBuff        = picBuff;
190         originalDpbIndex = -1;
191     }
192 
isRefvkt::video::dpbH264Entry193     bool isRef()
194     {
195         return (used_for_reference != 0);
196     }
197 
getPictureFlagvkt::video::dpbH264Entry198     StdVideoDecodeH264ReferenceInfoFlags getPictureFlag(bool currentPictureIsProgressive)
199     {
200         StdVideoDecodeH264ReferenceInfoFlags picFlags = StdVideoDecodeH264ReferenceInfoFlags();
201         if (videoLoggingEnabled())
202             std::cout << "\t\t Flags: ";
203 
204         if (used_for_reference)
205         {
206             if (videoLoggingEnabled())
207                 std::cout << "FRAME_IS_REFERENCE ";
208             // picFlags.is_reference = true;
209         }
210 
211         if (is_long_term)
212         {
213             if (videoLoggingEnabled())
214                 std::cout << "IS_LONG_TERM ";
215             picFlags.used_for_long_term_reference = true;
216         }
217         if (is_non_existing)
218         {
219             if (videoLoggingEnabled())
220                 std::cout << "IS_NON_EXISTING ";
221             picFlags.is_non_existing = true;
222         }
223 
224         if (is_field_ref)
225         {
226             if (videoLoggingEnabled())
227                 std::cout << "IS_FIELD ";
228             // picFlags.field_pic_flag = true;
229         }
230 
231         if (!currentPictureIsProgressive && (used_for_reference & topFieldMask))
232         {
233             if (videoLoggingEnabled())
234                 std::cout << "TOP_FIELD_IS_REF ";
235             picFlags.top_field_flag = true;
236         }
237         if (!currentPictureIsProgressive && (used_for_reference & bottomFieldMask))
238         {
239             if (videoLoggingEnabled())
240                 std::cout << "BOTTOM_FIELD_IS_REF ";
241             picFlags.bottom_field_flag = true;
242         }
243 
244         return picFlags;
245     }
246 
setH264PictureDatavkt::video::dpbH264Entry247     void setH264PictureData(nvVideoDecodeH264DpbSlotInfo *pDpbRefList, VkVideoReferenceSlotInfoKHR *pReferenceSlots,
248                             uint32_t dpbEntryIdx, uint32_t dpbSlotIndex, bool currentPictureIsProgressive)
249     {
250         DE_ASSERT(dpbEntryIdx <= H26X_MAX_DPB_SLOTS && dpbSlotIndex <= H26X_MAX_DPB_SLOTS);
251 
252         DE_ASSERT((dpbSlotIndex == (uint32_t)dpbSlot) || is_non_existing);
253         pReferenceSlots[dpbEntryIdx].sType     = VK_STRUCTURE_TYPE_VIDEO_REFERENCE_SLOT_INFO_KHR;
254         pReferenceSlots[dpbEntryIdx].slotIndex = dpbSlotIndex;
255         pReferenceSlots[dpbEntryIdx].pNext     = pDpbRefList[dpbEntryIdx].Init(dpbSlotIndex);
256 
257         StdVideoDecodeH264ReferenceInfo *pRefPicInfo = &pDpbRefList[dpbEntryIdx].stdReferenceInfo;
258         pRefPicInfo->FrameNum                        = FrameIdx;
259         if (videoLoggingEnabled())
260         {
261             std::cout << "\tdpbEntryIdx: " << dpbEntryIdx << "dpbSlotIndex: " << dpbSlotIndex
262                       << " FrameIdx: " << (int32_t)FrameIdx;
263         }
264         pRefPicInfo->flags          = getPictureFlag(currentPictureIsProgressive);
265         pRefPicInfo->PicOrderCnt[0] = FieldOrderCnt[0];
266         pRefPicInfo->PicOrderCnt[1] = FieldOrderCnt[1];
267         if (videoLoggingEnabled())
268             std::cout << " fieldOrderCnt[0]: " << pRefPicInfo->PicOrderCnt[0]
269                       << " fieldOrderCnt[1]: " << pRefPicInfo->PicOrderCnt[1] << std::endl;
270     }
271 
setH265PictureDatavkt::video::dpbH264Entry272     void setH265PictureData(nvVideoDecodeH265DpbSlotInfo *pDpbSlotInfo, VkVideoReferenceSlotInfoKHR *pReferenceSlots,
273                             uint32_t dpbEntryIdx, uint32_t dpbSlotIndex)
274     {
275         DE_ASSERT(dpbEntryIdx <= H26X_MAX_DPB_SLOTS && dpbSlotIndex <= H26X_MAX_DPB_SLOTS);
276 
277         DE_ASSERT(isRef());
278 
279         DE_ASSERT((dpbSlotIndex == (uint32_t)dpbSlot) || is_non_existing);
280         pReferenceSlots[dpbEntryIdx].sType     = VK_STRUCTURE_TYPE_VIDEO_REFERENCE_SLOT_INFO_KHR;
281         pReferenceSlots[dpbEntryIdx].slotIndex = dpbSlotIndex;
282         pReferenceSlots[dpbEntryIdx].pNext     = pDpbSlotInfo[dpbEntryIdx].Init(dpbSlotIndex);
283 
284         StdVideoDecodeH265ReferenceInfo *pRefPicInfo    = &pDpbSlotInfo[dpbEntryIdx].stdReferenceInfo;
285         pRefPicInfo->PicOrderCntVal                     = PicOrderCnt;
286         pRefPicInfo->flags.used_for_long_term_reference = is_long_term;
287 
288         if (videoLoggingEnabled())
289         {
290             std::cout << "\tdpbIndex: " << dpbSlotIndex << " picOrderCntValList: " << PicOrderCnt;
291 
292             std::cout << "\t\t Flags: ";
293             std::cout << "FRAME IS REFERENCE ";
294             if (pRefPicInfo->flags.used_for_long_term_reference)
295             {
296                 std::cout << "IS LONG TERM ";
297             }
298             std::cout << std::endl;
299         }
300     }
301 
302 } dpbH264Entry;
303 
GetPicIdx(vkPicBuffBase * pPicBuf)304 int8_t VideoBaseDecoder::GetPicIdx(vkPicBuffBase *pPicBuf)
305 {
306     if (pPicBuf)
307     {
308         int32_t picIndex = pPicBuf->m_picIdx;
309 
310         if ((picIndex >= 0) && ((uint32_t)picIndex < MAX_NUM_DECODE_SURFACES))
311         {
312             return (int8_t)picIndex;
313         }
314     }
315 
316     return -1;
317 }
318 
GetPicIdx(VkPicIf * pPicBuf)319 int8_t VideoBaseDecoder::GetPicIdx(VkPicIf *pPicBuf)
320 {
321     return GetPicIdx(GetPic(pPicBuf));
322 }
323 
GetPicDpbSlot(int8_t picIndex)324 int8_t VideoBaseDecoder::GetPicDpbSlot(int8_t picIndex)
325 {
326     return m_pictureToDpbSlotMap[picIndex];
327 }
328 
GetFieldPicFlag(int8_t picIndex)329 bool VideoBaseDecoder::GetFieldPicFlag(int8_t picIndex)
330 {
331     DE_ASSERT((picIndex >= 0) && ((uint32_t)picIndex < MAX_NUM_DECODE_SURFACES));
332 
333     return !!(m_fieldPicFlagMask & (1 << (uint32_t)picIndex));
334 }
335 
SetFieldPicFlag(int8_t picIndex,bool fieldPicFlag)336 bool VideoBaseDecoder::SetFieldPicFlag(int8_t picIndex, bool fieldPicFlag)
337 {
338     DE_ASSERT((picIndex >= 0) && ((uint32_t)picIndex < MAX_NUM_DECODE_SURFACES));
339 
340     bool oldFieldPicFlag = GetFieldPicFlag(picIndex);
341 
342     if (fieldPicFlag)
343     {
344         m_fieldPicFlagMask |= (1 << (uint32_t)picIndex);
345     }
346     else
347     {
348         m_fieldPicFlagMask &= ~(1 << (uint32_t)picIndex);
349     }
350 
351     return oldFieldPicFlag;
352 }
353 
SetPicDpbSlot(int8_t picIndex,int8_t dpbSlot)354 int8_t VideoBaseDecoder::SetPicDpbSlot(int8_t picIndex, int8_t dpbSlot)
355 {
356     int8_t oldDpbSlot = m_pictureToDpbSlotMap[picIndex];
357 
358     m_pictureToDpbSlotMap[picIndex] = dpbSlot;
359 
360     if (dpbSlot >= 0)
361     {
362         m_dpbSlotsMask |= (1 << picIndex);
363     }
364     else
365     {
366         m_dpbSlotsMask &= ~(1 << picIndex);
367 
368         if (oldDpbSlot >= 0)
369         {
370             m_dpb.FreeSlot(oldDpbSlot);
371         }
372     }
373 
374     return oldDpbSlot;
375 }
376 
ResetPicDpbSlots(uint32_t picIndexSlotValidMask)377 uint32_t VideoBaseDecoder::ResetPicDpbSlots(uint32_t picIndexSlotValidMask)
378 {
379     uint32_t resetSlotsMask = ~(picIndexSlotValidMask | ~m_dpbSlotsMask);
380 
381     for (uint32_t picIdx = 0; (picIdx < MAX_NUM_DECODE_SURFACES) && resetSlotsMask; picIdx++)
382     {
383         if (resetSlotsMask & (1 << picIdx))
384         {
385             resetSlotsMask &= ~(1 << picIdx);
386 
387             SetPicDpbSlot((int8_t)picIdx, -1);
388         }
389     }
390 
391     return m_dpbSlotsMask;
392 }
393 
VideoBaseDecoder(Parameters && params)394 VideoBaseDecoder::VideoBaseDecoder(Parameters &&params)
395     : m_deviceContext(params.context)
396     , m_profile(*params.profile)
397     , m_framesToCheck(params.framesToCheck)
398     , m_dpb(3)
399     , m_layeredDpb(params.layeredDpb)
400     , m_videoFrameBuffer(params.framebuffer)
401     , m_decodeFramesData(params.context->getDeviceDriver(), params.context->device,
402                          params.context->decodeQueueFamilyIdx())
403     , m_resetPictureParametersFrameTriggerHack(params.pictureParameterUpdateTriggerHack)
404     , m_forceDisableFilmGrain(params.forceDisableFilmGrain)
405     , m_queryResultWithStatus(params.queryDecodeStatus)
406     , m_useInlineQueries(params.useInlineQueries)
407     , m_resourcesWithoutProfiles(params.resourcesWithoutProfiles)
408     , m_outOfOrderDecoding(params.outOfOrderDecoding)
409     , m_alwaysRecreateDPB(params.alwaysRecreateDPB)
410     , m_intraOnlyDecoding(params.intraOnlyDecoding)
411 {
412     std::fill(m_pictureToDpbSlotMap.begin(), m_pictureToDpbSlotMap.end(), -1);
413     reinitializeFormatsForProfile(params.profile);
414 }
415 
reinitializeFormatsForProfile(const VkVideoCoreProfile * profile)416 void VideoBaseDecoder::reinitializeFormatsForProfile(const VkVideoCoreProfile *profile)
417 {
418     VkResult res;
419     res = util::getVideoDecodeCapabilities(*m_deviceContext, *profile, m_videoCaps, m_decodeCaps);
420     if (res != VK_SUCCESS)
421         TCU_THROW(NotSupportedError, "Implementation does not support this video profile");
422 
423     res = util::getSupportedVideoFormats(*m_deviceContext, m_profile, m_decodeCaps.flags, m_outImageFormat,
424                                          m_dpbImageFormat);
425     if (res != VK_SUCCESS)
426         TCU_THROW(NotSupportedError, "Implementation does not have any supported video formats for this profile");
427 
428     m_supportedVideoCodecs = util::getSupportedCodecs(
429         *m_deviceContext, m_deviceContext->decodeQueueFamilyIdx(), VK_QUEUE_VIDEO_DECODE_BIT_KHR,
430         VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR | VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR);
431     DE_ASSERT(m_supportedVideoCodecs != VK_VIDEO_CODEC_OPERATION_NONE_KHR);
432 
433     VK_CHECK(BitstreamBufferImpl::Create(m_deviceContext, m_deviceContext->decodeQueueFamilyIdx(), MAX_BUFFER_SIZE,
434                                          0,    // Not used
435                                          4096, // Be generous, this is a default
436                                          m_bitstreamBuffer, m_profile.GetProfileListInfo()));
437 }
438 
Deinitialize()439 void VideoBaseDecoder::Deinitialize()
440 {
441     const DeviceInterface &vkd = m_deviceContext->getDeviceDriver();
442     VkDevice device            = m_deviceContext->device;
443     VkQueue queueDecode        = m_deviceContext->decodeQueue;
444     VkQueue queueTransfer      = m_deviceContext->transferQueue;
445 
446     if (queueDecode)
447         vkd.queueWaitIdle(queueDecode);
448 
449     if (queueTransfer)
450         vkd.queueWaitIdle(queueTransfer);
451 
452     vkd.deviceWaitIdle(device);
453 
454     m_dpb.Deinit();
455     m_videoFrameBuffer = nullptr;
456     m_decodeFramesData.deinit();
457     m_videoSession = nullptr;
458 }
459 
StartVideoSequence(const VkParserDetectedVideoFormat * pVideoFormat)460 void VideoBaseDecoder::StartVideoSequence(const VkParserDetectedVideoFormat *pVideoFormat)
461 {
462     VkExtent2D codedExtent = {pVideoFormat->coded_width, pVideoFormat->coded_height};
463     DE_ASSERT(pVideoFormat->display_area.right >= 0 && pVideoFormat->display_area.left >= 0 &&
464               pVideoFormat->display_area.top >= 0 && pVideoFormat->display_area.bottom >= 0);
465     uint32_t displayWidth = static_cast<uint32_t>(pVideoFormat->display_area.right) -
466                             static_cast<uint32_t>(pVideoFormat->display_area.left);
467     uint32_t displayHeight = static_cast<uint32_t>(pVideoFormat->display_area.bottom) -
468                              static_cast<uint32_t>(pVideoFormat->display_area.top);
469     VkExtent2D imageExtent = {std::max(codedExtent.width, displayWidth), std::max(codedExtent.height, displayHeight)};
470     imageExtent.width      = deAlign32(imageExtent.width, m_videoCaps.pictureAccessGranularity.width);
471     imageExtent.height     = deAlign32(imageExtent.height, m_videoCaps.pictureAccessGranularity.height);
472 
473     VkVideoCodecOperationFlagBitsKHR detectedVideoCodec = pVideoFormat->codec;
474 
475     if (!de::inRange(codedExtent.width, m_videoCaps.minCodedExtent.width, m_videoCaps.maxCodedExtent.width) ||
476         !de::inRange(codedExtent.height, m_videoCaps.minCodedExtent.height, m_videoCaps.maxCodedExtent.height))
477     {
478         stringstream msg;
479         msg << "Session coded extent (" << codedExtent.width << ", " << codedExtent.height
480             << ") is not within the supported range of: (" << m_videoCaps.minCodedExtent.width << ", "
481             << m_videoCaps.minCodedExtent.height << ") -- (" << m_videoCaps.maxCodedExtent.width << ", "
482             << m_videoCaps.maxCodedExtent.height << ")";
483         TCU_THROW(NotSupportedError, msg.str());
484     }
485 
486     if (!de::inRange(imageExtent.width, m_videoCaps.minCodedExtent.width, m_videoCaps.maxCodedExtent.width) ||
487         !de::inRange(imageExtent.height, m_videoCaps.minCodedExtent.height, m_videoCaps.maxCodedExtent.height))
488     {
489         stringstream msg;
490         msg << "Session image extent (" << imageExtent.width << ", " << imageExtent.height
491             << ") is not within the supported range of: (" << m_videoCaps.minCodedExtent.width << ", "
492             << m_videoCaps.minCodedExtent.height << ") -- (" << m_videoCaps.maxCodedExtent.width << ", "
493             << m_videoCaps.maxCodedExtent.height << ")";
494         TCU_THROW(NotSupportedError, msg.str());
495     }
496 
497     VkVideoCoreProfile videoProfile(detectedVideoCodec, pVideoFormat->chromaSubsampling, pVideoFormat->lumaBitDepth,
498                                     pVideoFormat->chromaBitDepth, pVideoFormat->codecProfile,
499                                     pVideoFormat->filmGrainEnabled);
500     m_profile = videoProfile;
501     reinitializeFormatsForProfile(&videoProfile);
502 
503     DE_ASSERT(((detectedVideoCodec & m_supportedVideoCodecs) != 0));
504 
505     if (m_videoFormat.coded_width && m_videoFormat.coded_height)
506     {
507         // CreateDecoder() has been called before, and now there's possible config change
508         m_deviceContext->waitDecodeQueue();
509         m_deviceContext->deviceWaitIdle();
510     }
511 
512     uint32_t maxDpbSlotCount = pVideoFormat->maxNumDpbSlots;
513 
514     if (videoLoggingEnabled())
515     {
516         std::cout << std::dec << "Sequence/GOP Information" << std::endl
517                   << "\tCodec        : " << util::getVideoCodecString(pVideoFormat->codec) << std::endl
518                   << "\tFrame rate   : " << pVideoFormat->frame_rate.numerator << "/"
519                   << pVideoFormat->frame_rate.denominator << " = "
520                   << ((pVideoFormat->frame_rate.denominator != 0) ?
521                           (1.0 * pVideoFormat->frame_rate.numerator / pVideoFormat->frame_rate.denominator) :
522                           0.0)
523                   << " fps" << std::endl
524                   << "\tSequence     : " << (pVideoFormat->progressive_sequence ? "Progressive" : "Interlaced")
525                   << std::endl
526                   << "\tCoded size   : [" << codedExtent.width << ", " << codedExtent.height << "]" << std::endl
527                   << "\tImage size   : [" << imageExtent.width << ", " << imageExtent.height << "]" << std::endl
528                   << "\tDisplay area : [" << pVideoFormat->display_area.left << ", " << pVideoFormat->display_area.top
529                   << ", " << pVideoFormat->display_area.right << ", " << pVideoFormat->display_area.bottom << "]"
530                   << std::endl
531                   << "\tChroma       : " << util::getVideoChromaFormatString(pVideoFormat->chromaSubsampling)
532                   << std::endl
533                   << "\tBit depth    : " << pVideoFormat->bit_depth_luma_minus8 + 8 << std::endl
534                   << "\tCodec        : " << VkVideoCoreProfile::CodecToName(detectedVideoCodec) << std::endl
535                   << "\tCoded extent : " << codedExtent.width << " x " << codedExtent.height << std::endl
536                   << "\tMax DPB slots : " << maxDpbSlotCount << std::endl;
537     }
538 
539     if (!m_videoSession ||
540         !m_videoSession->IsCompatible(m_deviceContext->device, m_deviceContext->decodeQueueFamilyIdx(), &videoProfile,
541                                       m_outImageFormat, imageExtent, m_dpbImageFormat, maxDpbSlotCount,
542                                       maxDpbSlotCount) ||
543         m_alwaysRecreateDPB)
544     {
545 
546         VK_CHECK(VulkanVideoSession::Create(*m_deviceContext, m_deviceContext->decodeQueueFamilyIdx(), &videoProfile,
547                                             m_outImageFormat, imageExtent, m_dpbImageFormat, maxDpbSlotCount,
548                                             std::min<uint32_t>(maxDpbSlotCount, m_videoCaps.maxActiveReferencePictures),
549                                             m_useInlineQueries, m_videoSession));
550         // after creating a new video session, we need codec reset.
551         m_resetDecoder = true;
552     }
553 
554     if (m_currentPictureParameters)
555     {
556         m_currentPictureParameters->FlushPictureParametersQueue(m_videoSession);
557     }
558 
559     VkImageUsageFlags outImageUsage =
560         (VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
561     VkImageUsageFlags dpbImageUsage = VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR;
562 
563     if (dpbAndOutputCoincide() && (!pVideoFormat->filmGrainEnabled || m_forceDisableFilmGrain))
564     {
565         dpbImageUsage = VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR | VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR |
566                         VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
567     }
568     else
569     {
570         m_useSeparateOutputImages = true;
571     }
572 
573     if (!(m_videoCaps.flags & VK_VIDEO_CAPABILITY_SEPARATE_REFERENCE_IMAGES_BIT_KHR) && !m_layeredDpb)
574     {
575         TCU_THROW(NotSupportedError, "separate reference images are not supported");
576     }
577 
578     if (m_layeredDpb)
579     {
580         m_useImageArray     = true;
581         m_useImageViewArray = true;
582     }
583     else
584     {
585         m_useImageArray     = false;
586         m_useImageViewArray = false;
587     }
588 
589     bool useLinearOutput = false;
590     int32_t ret          = m_videoFrameBuffer->InitImagePool(
591         videoProfile.GetProfile(), MAX_NUM_DECODE_SURFACES, m_dpbImageFormat, m_outImageFormat, imageExtent,
592         dpbImageUsage, outImageUsage, m_deviceContext->decodeQueueFamilyIdx(), m_useImageArray, m_useImageViewArray,
593         m_useSeparateOutputImages, useLinearOutput);
594 
595     DE_ASSERT((uint32_t)ret == MAX_NUM_DECODE_SURFACES);
596     DE_UNREF(ret);
597     m_decodeFramesData.resize(MAX_NUM_DECODE_SURFACES);
598 
599     // Save the original config
600     m_videoFormat = *pVideoFormat;
601 }
602 
BeginSequence(const VkParserSequenceInfo * pnvsi)603 int32_t VideoBaseDecoder::BeginSequence(const VkParserSequenceInfo *pnvsi)
604 {
605     // TODO: The base class needs refactoring between the codecs
606     bool isAv1  = (pnvsi->eCodec == VK_VIDEO_CODEC_OPERATION_DECODE_AV1_BIT_KHR);
607     bool isH264 = (pnvsi->eCodec == VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR);
608     bool isH265 = (pnvsi->eCodec == VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR);
609     bool isH26x = isH264 || isH265;
610     TCU_CHECK_AND_THROW(InternalError, isAv1 || isH26x, "Unsupported codec");
611 
612     // TODO: This is not used by anything...
613     bool sequenceUpdate = m_nvsi.nMaxWidth != 0 && m_nvsi.nMaxHeight != 0;
614 
615     uint32_t maxDpbSlots = 0;
616     if (isAv1)
617         maxDpbSlots = STD_VIDEO_AV1_NUM_REF_FRAMES + 1; // +1 for the nearly aways present setup slot.
618     else if (isH264)
619         maxDpbSlots = VkParserPerFrameDecodeParameters::MAX_DPB_REF_AND_SETUP_SLOTS;
620     else if (isH265)
621         maxDpbSlots = VkParserPerFrameDecodeParameters::MAX_DPB_REF_SLOTS;
622 
623     uint32_t configDpbSlots = (pnvsi->nMinNumDpbSlots > 0) ? pnvsi->nMinNumDpbSlots : maxDpbSlots;
624     configDpbSlots          = std::min<uint32_t>(configDpbSlots, maxDpbSlots);
625 
626     if (m_intraOnlyDecoding)
627     {
628         maxDpbSlots    = 0;
629         configDpbSlots = 0;
630     }
631 
632     bool sequenceReconfigureFormat      = false;
633     bool sequenceReconfigureCodedExtent = false;
634     if (sequenceUpdate)
635     {
636         if ((pnvsi->eCodec != m_nvsi.eCodec) || (pnvsi->nChromaFormat != m_nvsi.nChromaFormat) ||
637             (pnvsi->uBitDepthLumaMinus8 != m_nvsi.uBitDepthLumaMinus8) ||
638             (pnvsi->uBitDepthChromaMinus8 != m_nvsi.uBitDepthChromaMinus8) || (pnvsi->bProgSeq != m_nvsi.bProgSeq))
639         {
640             sequenceReconfigureFormat = true;
641         }
642 
643         if ((pnvsi->nCodedWidth != m_nvsi.nCodedWidth) || (pnvsi->nCodedHeight != m_nvsi.nCodedHeight))
644         {
645             sequenceReconfigureCodedExtent = true;
646         }
647     }
648 
649     m_nvsi = *pnvsi;
650 
651     if (isAv1)
652     {
653         m_nvsi.nMaxWidth  = std::max(m_nvsi.nMaxWidth, m_nvsi.nDisplayWidth);
654         m_nvsi.nMaxHeight = std::max(m_nvsi.nMaxHeight, m_nvsi.nDisplayHeight);
655     }
656     else if (isH26x)
657     {
658         m_nvsi.nMaxWidth  = m_nvsi.nDisplayWidth;
659         m_nvsi.nMaxHeight = m_nvsi.nDisplayHeight;
660     }
661 
662     VkParserDetectedVideoFormat detectedFormat;
663     memset(&detectedFormat, 0, sizeof(detectedFormat));
664 
665     detectedFormat.sequenceUpdate                 = sequenceUpdate;
666     detectedFormat.sequenceReconfigureFormat      = sequenceReconfigureFormat;
667     detectedFormat.sequenceReconfigureCodedExtent = sequenceReconfigureCodedExtent;
668     detectedFormat.codec                          = m_nvsi.eCodec;
669     detectedFormat.frame_rate.numerator           = NV_FRAME_RATE_NUM(m_nvsi.frameRate);
670     detectedFormat.frame_rate.denominator         = NV_FRAME_RATE_DEN(m_nvsi.frameRate);
671     detectedFormat.progressive_sequence           = m_nvsi.bProgSeq;
672     // Note: it is strange to have the upscaled width here. Tidy all the indirection from the sample app here.
673     detectedFormat.coded_width =
674         (m_nvsi.eCodec == VK_VIDEO_CODEC_OPERATION_DECODE_AV1_BIT_KHR) ? m_nvsi.nDisplayWidth : m_nvsi.nCodedWidth;
675     detectedFormat.coded_height        = m_nvsi.nCodedHeight;
676     detectedFormat.display_area.right  = m_nvsi.nDisplayWidth;
677     detectedFormat.display_area.bottom = m_nvsi.nDisplayHeight;
678     detectedFormat.max_session_width   = m_nvsi.nMaxWidth;
679     detectedFormat.max_session_height  = m_nvsi.nMaxHeight;
680 
681     if ((StdChromaFormatIdc)pnvsi->nChromaFormat == chroma_format_idc_monochrome)
682     {
683         detectedFormat.chromaSubsampling = VK_VIDEO_CHROMA_SUBSAMPLING_MONOCHROME_BIT_KHR;
684     }
685     else if ((StdChromaFormatIdc)pnvsi->nChromaFormat == chroma_format_idc_420)
686     {
687         detectedFormat.chromaSubsampling = VK_VIDEO_CHROMA_SUBSAMPLING_420_BIT_KHR;
688     }
689     else if ((StdChromaFormatIdc)pnvsi->nChromaFormat == chroma_format_idc_422)
690     {
691         detectedFormat.chromaSubsampling = VK_VIDEO_CHROMA_SUBSAMPLING_422_BIT_KHR;
692     }
693     else if ((StdChromaFormatIdc)pnvsi->nChromaFormat == chroma_format_idc_444)
694     {
695         detectedFormat.chromaSubsampling = VK_VIDEO_CHROMA_SUBSAMPLING_444_BIT_KHR;
696     }
697     else
698     {
699         DE_ASSERT(!"Invalid chroma sub-sampling format");
700     }
701 
702     switch (pnvsi->uBitDepthLumaMinus8)
703     {
704     case 0:
705         detectedFormat.lumaBitDepth = VK_VIDEO_COMPONENT_BIT_DEPTH_8_BIT_KHR;
706         break;
707     case 2:
708         detectedFormat.lumaBitDepth = VK_VIDEO_COMPONENT_BIT_DEPTH_10_BIT_KHR;
709         break;
710     case 4:
711         detectedFormat.lumaBitDepth = VK_VIDEO_COMPONENT_BIT_DEPTH_12_BIT_KHR;
712         break;
713     default:
714         DE_ASSERT(false);
715     }
716 
717     switch (pnvsi->uBitDepthChromaMinus8)
718     {
719     case 0:
720         detectedFormat.chromaBitDepth = VK_VIDEO_COMPONENT_BIT_DEPTH_8_BIT_KHR;
721         break;
722     case 2:
723         detectedFormat.chromaBitDepth = VK_VIDEO_COMPONENT_BIT_DEPTH_10_BIT_KHR;
724         break;
725     case 4:
726         detectedFormat.chromaBitDepth = VK_VIDEO_COMPONENT_BIT_DEPTH_12_BIT_KHR;
727         break;
728     default:
729         DE_ASSERT(false);
730     }
731 
732     detectedFormat.bit_depth_luma_minus8                             = pnvsi->uBitDepthLumaMinus8;
733     detectedFormat.bit_depth_chroma_minus8                           = pnvsi->uBitDepthChromaMinus8;
734     detectedFormat.bitrate                                           = pnvsi->lBitrate;
735     detectedFormat.display_aspect_ratio.x                            = pnvsi->lDARWidth;
736     detectedFormat.display_aspect_ratio.y                            = pnvsi->lDARHeight;
737     detectedFormat.video_signal_description.video_format             = pnvsi->lVideoFormat;
738     detectedFormat.video_signal_description.video_full_range_flag    = pnvsi->uVideoFullRange;
739     detectedFormat.video_signal_description.color_primaries          = pnvsi->lColorPrimaries;
740     detectedFormat.video_signal_description.transfer_characteristics = pnvsi->lTransferCharacteristics;
741     detectedFormat.video_signal_description.matrix_coefficients      = pnvsi->lMatrixCoefficients;
742     detectedFormat.seqhdr_data_length                                = 0; // Not used.
743     detectedFormat.minNumDecodeSurfaces                              = pnvsi->nMinNumDecodeSurfaces;
744     detectedFormat.maxNumDpbSlots                                    = configDpbSlots;
745     detectedFormat.codecProfile                                      = pnvsi->codecProfile;
746     detectedFormat.filmGrainEnabled                                  = pnvsi->filmGrainEnabled;
747 
748     // NVIDIA sample app legacy
749     StartVideoSequence(&detectedFormat);
750 
751     // AV1 and VP9 support cross-sequence referencing.
752     if (pnvsi->eCodec == VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR ||
753         pnvsi->eCodec == VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR)
754     {
755         m_maxNumDpbSlots = m_dpb.Init(configDpbSlots, false /* reconfigure the DPB size if true */);
756         // Ensure the picture map is empited, so that DPB slot management doesn't get confused in-between sequences.
757         m_pictureToDpbSlotMap.fill(-1);
758     }
759     else if (pnvsi->eCodec == VK_VIDEO_CODEC_OPERATION_DECODE_AV1_BIT_KHR)
760     {
761         if (m_dpb.getMaxSize() < configDpbSlots)
762         {
763             m_maxNumDpbSlots = m_dpb.Init(configDpbSlots, false);
764         }
765     }
766     else
767     {
768         TCU_THROW(InternalError, "Codec DPB management not fully implemented");
769     }
770 
771     return MAX_NUM_DECODE_SURFACES;
772 }
773 
AllocPictureBuffer(VkPicIf ** ppNvidiaVulkanPicture,uint32_t codedWidth,uint32_t codedHeight)774 bool VideoBaseDecoder::AllocPictureBuffer(VkPicIf **ppNvidiaVulkanPicture, uint32_t codedWidth, uint32_t codedHeight)
775 {
776     bool result = false;
777 
778     *ppNvidiaVulkanPicture = m_videoFrameBuffer->ReservePictureBuffer();
779 
780     if (*ppNvidiaVulkanPicture)
781     {
782         result                                  = true;
783         (*ppNvidiaVulkanPicture)->upscaledWidth = codedWidth;
784         (*ppNvidiaVulkanPicture)->frameHeight   = codedHeight;
785     }
786 
787     if (!result)
788     {
789         *ppNvidiaVulkanPicture = nullptr;
790     }
791 
792     return result;
793 }
794 
DecodePicture(VkParserPictureData * pd)795 bool VideoBaseDecoder::DecodePicture(VkParserPictureData *pd)
796 {
797     bool result = false;
798 
799     if (!pd->pCurrPic)
800     {
801         return result;
802     }
803 
804     vkPicBuffBase *pVkPicBuff = GetPic(pd->pCurrPic);
805     const int32_t picIdx      = pVkPicBuff ? pVkPicBuff->m_picIdx : -1;
806     if (videoLoggingEnabled())
807         tcu::print("VulkanVideoParser::DecodePicture picIdx=%d progressive=%d\n", picIdx, pd->progressive_frame);
808 
809     DE_ASSERT(picIdx < MAX_FRM_CNT);
810 
811     VkParserDecodePictureInfo decodePictureInfo = VkParserDecodePictureInfo();
812     decodePictureInfo.pictureIndex              = picIdx;
813     decodePictureInfo.flags.progressiveFrame    = pd->progressive_frame;
814     decodePictureInfo.flags.fieldPic            = pd->field_pic_flag; // 0 = frame picture, 1 = field picture
815     decodePictureInfo.flags.repeatFirstField =
816         pd->repeat_first_field; // For 3:2 pulldown (number of additional fields, 2 = frame doubling, 4 = frame tripling)
817     decodePictureInfo.flags.refPic = pd->ref_pic_flag; // Frame is a reference frame
818 
819     // Mark the first field as unpaired Detect unpaired fields
820     if (pd->field_pic_flag)
821     {
822         decodePictureInfo.flags.bottomField =
823             pd->bottom_field_flag; // 0 = top field, 1 = bottom field (ignored if field_pic_flag=0)
824         decodePictureInfo.flags.secondField   = pd->second_field;    // Second field of a complementary field pair
825         decodePictureInfo.flags.topFieldFirst = pd->top_field_first; // Frame pictures only
826 
827         if (!pd->second_field)
828         {
829             decodePictureInfo.flags.unpairedField = true; // Incomplete (half) frame.
830         }
831         else
832         {
833             if (decodePictureInfo.flags.unpairedField)
834             {
835                 decodePictureInfo.flags.syncToFirstField = true;
836                 decodePictureInfo.flags.unpairedField    = false;
837             }
838         }
839     }
840 
841     decodePictureInfo.frameSyncinfo.unpairedField    = decodePictureInfo.flags.unpairedField;
842     decodePictureInfo.frameSyncinfo.syncToFirstField = decodePictureInfo.flags.syncToFirstField;
843 
844     return DecodePicture(pd, pVkPicBuff, &decodePictureInfo);
845 }
846 
DecodePicture(VkParserPictureData * pd,vkPicBuffBase *,VkParserDecodePictureInfo * pDecodePictureInfo)847 bool VideoBaseDecoder::DecodePicture(VkParserPictureData *pd, vkPicBuffBase * /*pVkPicBuff*/,
848                                      VkParserDecodePictureInfo *pDecodePictureInfo)
849 {
850     if (!pd->pCurrPic)
851     {
852         return false;
853     }
854 
855     const uint32_t PicIdx = GetPicIdx(pd->pCurrPic);
856     TCU_CHECK(PicIdx < MAX_FRM_CNT);
857 
858     m_cachedDecodeParams.emplace_back(new CachedDecodeParameters);
859     auto &cachedParameters = m_cachedDecodeParams.back();
860     bool bRet              = false;
861 
862     cachedParameters->performCodecReset = m_resetDecoder;
863     m_resetDecoder                      = false;
864 
865     // Copy the picture data over, taking care to memcpy the heap resources that might get freed on the parser side (we have no guarantees about those pointers)
866     cachedParameters->pd = *pd;
867 
868     // And again for the decoded picture information, these are all POD types for now.
869     cachedParameters->decodedPictureInfo = *pDecodePictureInfo;
870     pDecodePictureInfo                   = &cachedParameters->decodedPictureInfo;
871 
872     // Now build up the frame's decode parameters and store it in the cache
873     cachedParameters->pictureParams                       = VkParserPerFrameDecodeParameters();
874     VkParserPerFrameDecodeParameters *pCurrFrameDecParams = &cachedParameters->pictureParams;
875     pCurrFrameDecParams->currPicIdx                       = PicIdx;
876     pCurrFrameDecParams->numSlices                        = pd->numSlices;
877     pCurrFrameDecParams->firstSliceIndex                  = pd->firstSliceIndex;
878 
879     // We must copy to properly support out-of-order use cases, since the parser will overwrite this frames data with subsequent frames.
880     m_bitstreamBuffer->CopyDataFromBuffer(pd->bitstreamData, pd->bitstreamDataOffset, m_bitstreamBytesProcessed,
881                                           pd->bitstreamDataLen);
882     pCurrFrameDecParams->bitstreamDataLen    = pd->bitstreamDataLen;
883     pCurrFrameDecParams->bitstreamDataOffset = m_bitstreamBytesProcessed;
884     pCurrFrameDecParams->bitstreamData       = m_bitstreamBuffer;
885     m_bitstreamBytesProcessed += deAlignSize(pd->bitstreamDataLen, m_videoCaps.minBitstreamBufferOffsetAlignment);
886 
887     // Setup the frame references
888     auto &referenceSlots                = cachedParameters->referenceSlots;
889     auto &setupReferenceSlot            = cachedParameters->setupReferenceSlot;
890     setupReferenceSlot.sType            = VK_STRUCTURE_TYPE_VIDEO_REFERENCE_SLOT_INFO_KHR;
891     setupReferenceSlot.pPictureResource = nullptr;
892     setupReferenceSlot.slotIndex        = -1;
893 
894     pCurrFrameDecParams->decodeFrameInfo.sType                    = VK_STRUCTURE_TYPE_VIDEO_DECODE_INFO_KHR;
895     pCurrFrameDecParams->decodeFrameInfo.dstPictureResource.sType = VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_INFO_KHR;
896     pCurrFrameDecParams->dpbSetupPictureResource.sType            = VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_INFO_KHR;
897 
898     if (m_profile.GetCodecType() == VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR)
899     {
900         const VkParserH264PictureData *const pin               = &pd->CodecSpecific.h264;
901         cachedParameters->h264PicParams                        = nvVideoH264PicParameters();
902         VkVideoDecodeH264PictureInfoKHR *h264PictureInfo       = &cachedParameters->h264PicParams.pictureInfo;
903         nvVideoDecodeH264DpbSlotInfo *h264DpbReferenceList     = cachedParameters->h264PicParams.dpbRefList;
904         StdVideoDecodeH264PictureInfo *h264StandardPictureInfo = &cachedParameters->h264PicParams.stdPictureInfo;
905 
906         pCurrFrameDecParams->pStdPps = pin->pStdPps;
907         pCurrFrameDecParams->pStdSps = pin->pStdSps;
908         pCurrFrameDecParams->pStdVps = nullptr;
909 
910         h264PictureInfo->pStdPictureInfo           = &cachedParameters->h264PicParams.stdPictureInfo;
911         h264PictureInfo->sType                     = VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_PICTURE_INFO_KHR;
912         h264PictureInfo->pNext                     = nullptr;
913         pCurrFrameDecParams->decodeFrameInfo.pNext = h264PictureInfo;
914 
915         h264StandardPictureInfo->pic_parameter_set_id = pin->pic_parameter_set_id; // PPS ID
916         h264StandardPictureInfo->seq_parameter_set_id = pin->seq_parameter_set_id; // SPS ID;
917         h264StandardPictureInfo->frame_num            = (uint16_t)pin->frame_num;
918         h264PictureInfo->sliceCount                   = pd->numSlices;
919 
920         uint32_t maxSliceCount = 0;
921         DE_ASSERT(pd->firstSliceIndex == 0); // No slice and MV modes are supported yet
922         h264PictureInfo->pSliceOffsets = pd->bitstreamData->GetStreamMarkersPtr(pd->firstSliceIndex, maxSliceCount);
923         DE_ASSERT(maxSliceCount == pd->numSlices);
924 
925         StdVideoDecodeH264PictureInfoFlags currPicFlags = StdVideoDecodeH264PictureInfoFlags();
926         currPicFlags.is_intra                           = (pd->intra_pic_flag != 0);
927         // 0 = frame picture, 1 = field picture
928         if (pd->field_pic_flag)
929         {
930             // 0 = top field, 1 = bottom field (ignored if field_pic_flag = 0)
931             currPicFlags.field_pic_flag = true;
932             if (pd->bottom_field_flag)
933             {
934                 currPicFlags.bottom_field_flag = true;
935             }
936         }
937         // Second field of a complementary field pair
938         if (pd->second_field)
939         {
940             currPicFlags.complementary_field_pair = true;
941         }
942         // Frame is a reference frame
943         if (pd->ref_pic_flag)
944         {
945             currPicFlags.is_reference = true;
946         }
947         h264StandardPictureInfo->flags = currPicFlags;
948         if (!pd->field_pic_flag)
949         {
950             h264StandardPictureInfo->PicOrderCnt[0] = pin->CurrFieldOrderCnt[0];
951             h264StandardPictureInfo->PicOrderCnt[1] = pin->CurrFieldOrderCnt[1];
952         }
953         else
954         {
955             h264StandardPictureInfo->PicOrderCnt[pd->bottom_field_flag] = pin->CurrFieldOrderCnt[pd->bottom_field_flag];
956         }
957 
958         const uint32_t maxDpbInputSlots = sizeof(pin->dpb) / sizeof(pin->dpb[0]);
959         pCurrFrameDecParams->numGopReferenceSlots =
960             FillDpbH264State(pd, pin->dpb, maxDpbInputSlots, h264DpbReferenceList,
961                              VkParserPerFrameDecodeParameters::MAX_DPB_REF_SLOTS, // 16 reference pictures
962                              referenceSlots, pCurrFrameDecParams->pGopReferenceImagesIndexes,
963                              h264StandardPictureInfo->flags, &setupReferenceSlot.slotIndex);
964 
965         DE_ASSERT(!pd->ref_pic_flag || (setupReferenceSlot.slotIndex >= 0));
966 
967         // TODO: Dummy struct to silence validation. The root problem is that the dpb map doesn't take account of the setup slot,
968         // for some reason... So we can't use the existing logic to setup the picture flags and frame number from the dpbEntry
969         // class.
970         cachedParameters->h264SlotInfo.sType             = VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_DPB_SLOT_INFO_KHR;
971         cachedParameters->h264SlotInfo.pNext             = nullptr;
972         cachedParameters->h264SlotInfo.pStdReferenceInfo = &cachedParameters->h264RefInfo;
973 
974         if (setupReferenceSlot.slotIndex >= 0)
975         {
976             setupReferenceSlot.pPictureResource                      = &pCurrFrameDecParams->dpbSetupPictureResource;
977             setupReferenceSlot.pNext                                 = &cachedParameters->h264SlotInfo;
978             pCurrFrameDecParams->decodeFrameInfo.pSetupReferenceSlot = &setupReferenceSlot;
979         }
980         if (pCurrFrameDecParams->numGopReferenceSlots)
981         {
982             DE_ASSERT(pCurrFrameDecParams->numGopReferenceSlots <=
983                       (int32_t)VkParserPerFrameDecodeParameters::MAX_DPB_REF_SLOTS);
984             for (uint32_t dpbEntryIdx = 0; dpbEntryIdx < (uint32_t)pCurrFrameDecParams->numGopReferenceSlots;
985                  dpbEntryIdx++)
986             {
987                 pCurrFrameDecParams->pictureResources[dpbEntryIdx].sType =
988                     VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_INFO_KHR;
989                 referenceSlots[dpbEntryIdx].pPictureResource = &pCurrFrameDecParams->pictureResources[dpbEntryIdx];
990                 DE_ASSERT(h264DpbReferenceList[dpbEntryIdx].IsReference());
991             }
992 
993             pCurrFrameDecParams->decodeFrameInfo.pReferenceSlots    = referenceSlots;
994             pCurrFrameDecParams->decodeFrameInfo.referenceSlotCount = pCurrFrameDecParams->numGopReferenceSlots;
995         }
996         else
997         {
998             pCurrFrameDecParams->decodeFrameInfo.pReferenceSlots    = NULL;
999             pCurrFrameDecParams->decodeFrameInfo.referenceSlotCount = 0;
1000         }
1001 
1002         pDecodePictureInfo->displayWidth  = m_nvsi.nDisplayWidth;
1003         pDecodePictureInfo->displayHeight = m_nvsi.nDisplayHeight;
1004     }
1005     else if (m_profile.GetCodecType() == VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR)
1006     {
1007         const VkParserHevcPictureData *const pin       = &pd->CodecSpecific.hevc;
1008         cachedParameters->h265PicParams                = nvVideoH265PicParameters();
1009         VkVideoDecodeH265PictureInfoKHR *pPictureInfo  = &cachedParameters->h265PicParams.pictureInfo;
1010         StdVideoDecodeH265PictureInfo *pStdPictureInfo = &cachedParameters->h265PicParams.stdPictureInfo;
1011         nvVideoDecodeH265DpbSlotInfo *pDpbRefList      = cachedParameters->h265PicParams.dpbRefList;
1012 
1013         pCurrFrameDecParams->pStdPps = pin->pStdPps;
1014         pCurrFrameDecParams->pStdSps = pin->pStdSps;
1015         pCurrFrameDecParams->pStdVps = pin->pStdVps;
1016         if (videoLoggingEnabled())
1017         {
1018             std::cout << "\n\tCurrent h.265 Picture VPS update : " << pin->pStdVps->GetUpdateSequenceCount()
1019                       << std::endl;
1020             std::cout << "\n\tCurrent h.265 Picture SPS update : " << pin->pStdSps->GetUpdateSequenceCount()
1021                       << std::endl;
1022             std::cout << "\tCurrent h.265 Picture PPS update : " << pin->pStdPps->GetUpdateSequenceCount() << std::endl;
1023         }
1024 
1025         pPictureInfo->sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_PICTURE_INFO_KHR;
1026         pPictureInfo->pNext = nullptr;
1027 
1028         pPictureInfo->pStdPictureInfo              = &cachedParameters->h265PicParams.stdPictureInfo;
1029         pCurrFrameDecParams->decodeFrameInfo.pNext = &cachedParameters->h265PicParams.pictureInfo;
1030 
1031         if (pd->CodecSpecific.hevc.mv_hevc_enable)
1032         {
1033             pDecodePictureInfo->viewId = pd->CodecSpecific.hevc.nuh_layer_id;
1034         }
1035         else
1036         {
1037             pDecodePictureInfo->viewId = 0;
1038         }
1039 
1040         pPictureInfo->sliceSegmentCount = pd->numSlices;
1041         uint32_t maxSliceCount          = 0;
1042         DE_ASSERT(pd->firstSliceIndex == 0); // No slice and MV modes are supported yet
1043         pPictureInfo->pSliceSegmentOffsets = pd->bitstreamData->GetStreamMarkersPtr(pd->firstSliceIndex, maxSliceCount);
1044         DE_ASSERT(maxSliceCount == pd->numSlices);
1045 
1046         pStdPictureInfo->pps_pic_parameter_set_id   = pin->pic_parameter_set_id;       // PPS ID
1047         pStdPictureInfo->pps_seq_parameter_set_id   = pin->seq_parameter_set_id;       // SPS ID
1048         pStdPictureInfo->sps_video_parameter_set_id = pin->vps_video_parameter_set_id; // VPS ID
1049 
1050         pStdPictureInfo->flags.IrapPicFlag = pin->IrapPicFlag; // Intra Random Access Point for current picture.
1051         pStdPictureInfo->flags.IdrPicFlag  = pin->IdrPicFlag;  // Instantaneous Decoding Refresh for current picture.
1052         pStdPictureInfo->flags.IsReference = pd->ref_pic_flag;
1053         pStdPictureInfo->flags.short_term_ref_pic_set_sps_flag = pin->short_term_ref_pic_set_sps_flag;
1054 
1055         pStdPictureInfo->NumBitsForSTRefPicSetInSlice = pin->NumBitsForShortTermRPSInSlice;
1056 
1057         // NumDeltaPocsOfRefRpsIdx = s->sh.short_term_rps ?
1058         // s->sh.short_term_rps->rps_idx_num_delta_pocs : 0
1059         pStdPictureInfo->NumDeltaPocsOfRefRpsIdx = pin->NumDeltaPocsOfRefRpsIdx;
1060         pStdPictureInfo->PicOrderCntVal          = pin->CurrPicOrderCntVal;
1061 
1062         if (videoLoggingEnabled())
1063             std::cout << "\tnumPocStCurrBefore: " << (int32_t)pin->NumPocStCurrBefore
1064                       << " numPocStCurrAfter: " << (int32_t)pin->NumPocStCurrAfter
1065                       << " numPocLtCurr: " << (int32_t)pin->NumPocLtCurr << std::endl;
1066 
1067         pCurrFrameDecParams->numGopReferenceSlots = FillDpbH265State(
1068             pd, pin, pDpbRefList, pStdPictureInfo,
1069             VkParserPerFrameDecodeParameters::MAX_DPB_REF_SLOTS, // max 16 reference pictures
1070             referenceSlots, pCurrFrameDecParams->pGopReferenceImagesIndexes, &setupReferenceSlot.slotIndex);
1071 
1072         DE_ASSERT(!pd->ref_pic_flag || (setupReferenceSlot.slotIndex >= 0));
1073         // TODO: Dummy struct to silence validation. The root problem is that the dpb map doesn't take account of the setup slot,
1074         // for some reason... So we can't use the existing logic to setup the picture flags and frame number from the dpbEntry
1075         // class.
1076         cachedParameters->h265SlotInfo.sType             = VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_DPB_SLOT_INFO_KHR;
1077         cachedParameters->h265SlotInfo.pNext             = nullptr;
1078         cachedParameters->h265SlotInfo.pStdReferenceInfo = &cachedParameters->h265RefInfo;
1079 
1080         if (setupReferenceSlot.slotIndex >= 0)
1081         {
1082             setupReferenceSlot.pPictureResource                      = &pCurrFrameDecParams->dpbSetupPictureResource;
1083             setupReferenceSlot.pNext                                 = &cachedParameters->h265SlotInfo;
1084             pCurrFrameDecParams->decodeFrameInfo.pSetupReferenceSlot = &setupReferenceSlot;
1085         }
1086         if (pCurrFrameDecParams->numGopReferenceSlots)
1087         {
1088             DE_ASSERT(pCurrFrameDecParams->numGopReferenceSlots <=
1089                       (int32_t)VkParserPerFrameDecodeParameters::MAX_DPB_REF_SLOTS);
1090             for (uint32_t dpbEntryIdx = 0; dpbEntryIdx < (uint32_t)pCurrFrameDecParams->numGopReferenceSlots;
1091                  dpbEntryIdx++)
1092             {
1093                 pCurrFrameDecParams->pictureResources[dpbEntryIdx].sType =
1094                     VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_INFO_KHR;
1095                 referenceSlots[dpbEntryIdx].pPictureResource = &pCurrFrameDecParams->pictureResources[dpbEntryIdx];
1096                 DE_ASSERT(pDpbRefList[dpbEntryIdx].IsReference());
1097             }
1098 
1099             pCurrFrameDecParams->decodeFrameInfo.pReferenceSlots    = referenceSlots;
1100             pCurrFrameDecParams->decodeFrameInfo.referenceSlotCount = pCurrFrameDecParams->numGopReferenceSlots;
1101         }
1102         else
1103         {
1104             pCurrFrameDecParams->decodeFrameInfo.pReferenceSlots    = nullptr;
1105             pCurrFrameDecParams->decodeFrameInfo.referenceSlotCount = 0;
1106         }
1107 
1108         if (videoLoggingEnabled())
1109         {
1110             for (int32_t i = 0; i < H26X_MAX_DPB_SLOTS; i++)
1111             {
1112                 std::cout << "\tdpbIndex: " << i;
1113                 if (pDpbRefList[i])
1114                 {
1115                     std::cout << " REFERENCE FRAME";
1116 
1117                     std::cout << " picOrderCntValList: "
1118                               << (int32_t)pDpbRefList[i].dpbSlotInfo.pStdReferenceInfo->PicOrderCntVal;
1119 
1120                     std::cout << "\t\t Flags: ";
1121                     if (pDpbRefList[i].dpbSlotInfo.pStdReferenceInfo->flags.used_for_long_term_reference)
1122                     {
1123                         std::cout << "IS LONG TERM ";
1124                     }
1125                 }
1126                 else
1127                 {
1128                     std::cout << " NOT A REFERENCE ";
1129                 }
1130                 std::cout << std::endl;
1131             }
1132         }
1133 
1134         pDecodePictureInfo->displayWidth  = m_nvsi.nDisplayWidth;
1135         pDecodePictureInfo->displayHeight = m_nvsi.nDisplayHeight;
1136     }
1137     else if (m_profile.GetCodecType() == VK_VIDEO_CODEC_OPERATION_DECODE_AV1_BIT_KHR)
1138     {
1139         // Keep a reference for out-of-order decoding
1140         memcpy(&cachedParameters->av1PicParams, &pd->CodecSpecific.av1, sizeof(VkParserAv1PictureData));
1141         VkParserAv1PictureData *const p      = &cachedParameters->av1PicParams;
1142         VkVideoDecodeAV1PictureInfoKHR *pKhr = &p->khr_info;
1143         StdVideoDecodeAV1PictureInfo *pStd   = &p->std_info;
1144 
1145         // Chain up KHR structures
1146         pKhr->sType             = VK_STRUCTURE_TYPE_VIDEO_DECODE_AV1_PICTURE_INFO_KHR;
1147         pKhr->pNext             = nullptr;
1148         pKhr->pStdPictureInfo   = pStd;
1149         pKhr->frameHeaderOffset = 0;
1150         pKhr->pTileOffsets      = &p->tileOffsets[0];
1151         pKhr->pTileSizes        = &p->tileSizes[0];
1152         DE_ASSERT(pKhr->tileCount > 0);
1153 
1154         p->tileInfo.pWidthInSbsMinus1  = &p->width_in_sbs_minus_1[0];
1155         p->tileInfo.pHeightInSbsMinus1 = &p->height_in_sbs_minus_1[0];
1156         p->tileInfo.pMiColStarts       = &p->MiColStarts[0];
1157         p->tileInfo.pMiRowStarts       = &p->MiRowStarts[0];
1158         pStd->pTileInfo                = &p->tileInfo;
1159 
1160         pStd->pQuantization = &p->quantization;
1161         pStd->pSegmentation = &p->segmentation;
1162         pStd->pLoopFilter   = &p->loopFilter;
1163         pStd->pCDEF         = &p->CDEF;
1164 
1165         if (pStd->flags.UsesLr)
1166         {
1167             // Historical note: some drivers were performing the
1168             // logMinus5 mapping internally, and others might not have
1169             // been but are happy with the values. The CTS was
1170             // mirroring that during initial development of the AV1
1171             // decode spec. This differs from the AV1 derived values
1172             // for LoopRestorationSize coming from the bitstream.
1173             std::unordered_set<int> allowableRestorationSizeValues = {32, 64, 128, 256};
1174             DE_UNREF(allowableRestorationSizeValues);
1175             auto &lrs = p->loopRestoration.LoopRestorationSize;
1176             for (int i = 0; i < STD_VIDEO_AV1_MAX_NUM_PLANES; i++)
1177             {
1178                 DE_ASSERT(allowableRestorationSizeValues.find(lrs[i]) != allowableRestorationSizeValues.end());
1179                 lrs[i] = deLog2Floor32(lrs[i]) - 5;
1180             }
1181             pStd->pLoopRestoration = &p->loopRestoration;
1182         }
1183         else
1184         {
1185             pStd->pLoopRestoration = nullptr;
1186         }
1187 
1188         pStd->pGlobalMotion = &p->globalMotion;
1189         pStd->pFilmGrain    = &p->filmGrain;
1190 
1191         // TODO: Hack around a ref-counting issue in the frame
1192         // buffer. A better approach would be to modify the frame
1193         // buffer not to drop displayed frames in cached decoding
1194         // mode.
1195         pCurrFrameDecParams->isAV1 = true;
1196 
1197         if (videoLoggingEnabled())
1198         {
1199             const char *frameTypeStr = getdVideoAV1FrameTypeName(p->std_info.frame_type);
1200             printf(";;;; ======= AV1 begin frame %d (%dx%d) (frame type: %s) (show frame? %s) =======\n",
1201                    m_nCurrentPictureID, p->upscaled_width, p->frame_height, frameTypeStr, p->showFrame ? "yes" : "no");
1202 
1203             printf("ref_frame_idx: ");
1204             for (int i = 0; i < 7; i++)
1205                 printf("%02d ", i);
1206             printf("\nref_frame_idx: ");
1207             for (int i = 0; i < 7; i++)
1208                 printf("%02d ", p->ref_frame_idx[i]);
1209             printf("\n");
1210             printf("m_pictureToDpbSlotMap: ");
1211             for (int i = 0; i < MAX_FRM_CNT; i++)
1212             {
1213                 printf("%02d ", i);
1214             }
1215             printf("\nm_pictureToDpbSlotMap: ");
1216             for (int i = 0; i < MAX_FRM_CNT; i++)
1217             {
1218                 printf("%02d ", m_pictureToDpbSlotMap[i]);
1219             }
1220             printf("\n");
1221 
1222             printf("ref_frame_picture: ");
1223             for (int32_t inIdx = 0; inIdx < STD_VIDEO_AV1_NUM_REF_FRAMES; inIdx++)
1224             {
1225                 printf("%02d ", inIdx);
1226             }
1227             printf("\nref_frame_picture: ");
1228             for (int32_t inIdx = 0; inIdx < STD_VIDEO_AV1_NUM_REF_FRAMES; inIdx++)
1229             {
1230                 int8_t picIdx = p->pic_idx[inIdx];
1231                 printf("%02d ", picIdx);
1232             }
1233             printf("\n");
1234         }
1235 
1236         pCurrFrameDecParams->pStdPps    = nullptr;
1237         pCurrFrameDecParams->pStdSps    = nullptr;
1238         pCurrFrameDecParams->pStdVps    = nullptr;
1239         pCurrFrameDecParams->pStdAv1Sps = p->pStdSps;
1240 
1241         pCurrFrameDecParams->decodeFrameInfo.pNext = pKhr;
1242         p->setupSlot.pStdReferenceInfo             = &p->setupSlotInfo;
1243         setupReferenceSlot.pNext                   = &p->setupSlot;
1244 
1245         if (!m_intraOnlyDecoding)
1246         {
1247             DE_ASSERT(m_maxNumDpbSlots <= STD_VIDEO_AV1_NUM_REF_FRAMES + 1); // + 1 for scratch slot
1248             uint32_t refDpbUsedAndValidMask = 0;
1249             uint32_t referenceIndex         = 0;
1250             std::unordered_set<int8_t> activeReferences;
1251             bool isKeyFrame       = p->std_info.frame_type == STD_VIDEO_AV1_FRAME_TYPE_KEY;
1252             bool isIntraOnlyFrame = p->std_info.frame_type == STD_VIDEO_AV1_FRAME_TYPE_INTRA_ONLY;
1253             for (size_t refName = 0; refName < STD_VIDEO_AV1_REFS_PER_FRAME; refName++)
1254             {
1255                 int8_t picIdx = isKeyFrame ? -1 : p->pic_idx[p->ref_frame_idx[refName]];
1256                 if (picIdx < 0)
1257                 {
1258                     pKhr->referenceNameSlotIndices[refName] = -1;
1259                     continue;
1260                 }
1261                 int8_t dpbSlot = GetPicDpbSlot(picIdx);
1262                 assert(dpbSlot >= 0);
1263                 pKhr->referenceNameSlotIndices[refName] = dpbSlot;
1264                 activeReferences.insert(dpbSlot);
1265                 //hdr.delta_frame_id_minus_1[dpbSlot] = pin->delta_frame_id_minus_1[pin->ref_frame_idx[i]];
1266             }
1267 
1268             if (videoLoggingEnabled())
1269             {
1270                 printf("%d referenceNameSlotIndex: ", m_nCurrentPictureID);
1271                 for (int i = 0; i < STD_VIDEO_AV1_REFS_PER_FRAME; i++)
1272                 {
1273                     printf("%02d ", i);
1274                 }
1275                 printf("\n%d referenceNameSlotIndex: ", m_nCurrentPictureID);
1276                 for (int i = 0; i < STD_VIDEO_AV1_REFS_PER_FRAME; i++)
1277                 {
1278                     printf("%02d ", pKhr->referenceNameSlotIndices[i]);
1279                 }
1280                 printf("\n");
1281             }
1282 
1283             for (int32_t inIdx = 0; inIdx < STD_VIDEO_AV1_NUM_REF_FRAMES; inIdx++)
1284             {
1285                 int8_t picIdx  = isKeyFrame ? -1 : p->pic_idx[inIdx];
1286                 int8_t dpbSlot = -1;
1287                 if ((picIdx >= 0) && !(refDpbUsedAndValidMask & (1 << picIdx)))
1288                 { // Causes an assert in the driver that the DPB is invalid, with a slotindex of -1.
1289                     dpbSlot = GetPicDpbSlot(picIdx);
1290 
1291                     DE_ASSERT(dpbSlot >= 0);
1292                     if (dpbSlot < 0)
1293                         continue;
1294 
1295                     refDpbUsedAndValidMask |= (1 << picIdx);
1296                     m_dpb[dpbSlot].MarkInUse(m_nCurrentPictureID);
1297 
1298                     if (activeReferences.count(dpbSlot) == 0)
1299                     {
1300                         continue;
1301                     }
1302 
1303                     // Setup the reference info for the current dpb slot.
1304                     p->dpbSlots[inIdx].sType             = VK_STRUCTURE_TYPE_VIDEO_DECODE_AV1_DPB_SLOT_INFO_KHR;
1305                     p->dpbSlots[inIdx].pStdReferenceInfo = &p->dpbSlotInfos[inIdx];
1306 
1307                     referenceSlots[referenceIndex].sType     = VK_STRUCTURE_TYPE_VIDEO_REFERENCE_SLOT_INFO_KHR;
1308                     referenceSlots[referenceIndex].pNext     = &p->dpbSlots[inIdx];
1309                     referenceSlots[referenceIndex].slotIndex = dpbSlot;
1310 
1311                     pCurrFrameDecParams->pGopReferenceImagesIndexes[referenceIndex] = picIdx;
1312                     referenceIndex++;
1313                 }
1314             }
1315 
1316             if (videoLoggingEnabled())
1317             {
1318                 printf(";;; pReferenceSlots (%d): ", referenceIndex);
1319                 for (size_t i = 0; i < referenceIndex; i++)
1320                 {
1321                     printf("%02d ", referenceSlots[i].slotIndex);
1322                 }
1323                 printf("\n");
1324             }
1325 
1326             ResetPicDpbSlots(refDpbUsedAndValidMask);
1327 
1328             // Take into account the reference picture now.
1329             int8_t currPicIdx = GetPicIdx(pd->pCurrPic);
1330             int8_t dpbSlot    = -1;
1331             DE_ASSERT(currPicIdx >= 0);
1332             if (currPicIdx >= 0)
1333             {
1334                 refDpbUsedAndValidMask |= (1 << currPicIdx); // How does this do anything?
1335             }
1336 
1337             if (true /*pd->ref_pic_flag*/)
1338             {
1339                 dpbSlot = GetPicDpbSlot(currPicIdx); // use the associated slot, if not allocate a new slot.
1340                 if (dpbSlot < 0)
1341                 {
1342                     dpbSlot = m_dpb.AllocateSlot();
1343                     DE_ASSERT(dpbSlot >= 0);
1344                     SetPicDpbSlot(currPicIdx, dpbSlot); // Assign the dpbSlot to the current picture index.
1345                     m_dpb[dpbSlot].setPictureResource(GetPic(pd->pCurrPic),
1346                                                       m_nCurrentPictureID); // m_nCurrentPictureID is our main index.
1347                 }
1348                 DE_ASSERT(dpbSlot >= 0);
1349             }
1350 
1351             setupReferenceSlot.slotIndex = dpbSlot;
1352             DE_ASSERT(!pd->ref_pic_flag || (setupReferenceSlot.slotIndex >= 0));
1353 
1354             if (videoLoggingEnabled())
1355             {
1356                 printf("SlotsInUse: ");
1357                 uint32_t slotsInUse = m_dpb.getSlotInUseMask();
1358                 for (int i = 0; i < 9; i++)
1359                 {
1360                     printf("%02d ", i);
1361                 }
1362                 uint8_t greenSquare[]  = {0xf0, 0x9f, 0x9f, 0xa9, 0x00};
1363                 uint8_t redSquare[]    = {0xf0, 0x9f, 0x9f, 0xa5, 0x00};
1364                 uint8_t yellowSquare[] = {0xf0, 0x9f, 0x9f, 0xa8, 0x00};
1365                 printf("\nSlotsInUse: ");
1366                 for (int i = 0; i < 9; i++)
1367                 {
1368                     printf("%-2s ", (slotsInUse & (1 << i)) ?
1369                                         (i == dpbSlot ? (char *)yellowSquare : (char *)greenSquare) :
1370                                         (char *)redSquare);
1371                 }
1372                 printf("\n");
1373             }
1374             setupReferenceSlot.pPictureResource                      = &pCurrFrameDecParams->dpbSetupPictureResource;
1375             pCurrFrameDecParams->decodeFrameInfo.pSetupReferenceSlot = &setupReferenceSlot;
1376             pCurrFrameDecParams->numGopReferenceSlots                = referenceIndex;
1377 
1378             if (isIntraOnlyFrame)
1379             {
1380                 // Do not actually reference anything, but ensure the DPB slots for future frames are undisturbed.
1381                 pCurrFrameDecParams->numGopReferenceSlots = 0;
1382                 for (size_t i = 0; i < STD_VIDEO_AV1_REFS_PER_FRAME; i++)
1383                 {
1384                     pKhr->referenceNameSlotIndices[i] = -1;
1385                 }
1386             }
1387         }
1388         else
1389         {
1390             // Intra only decoding
1391             pCurrFrameDecParams->numGopReferenceSlots = 0;
1392             for (size_t i = 0; i < STD_VIDEO_AV1_REFS_PER_FRAME; i++)
1393             {
1394                 pKhr->referenceNameSlotIndices[i] = -1;
1395             }
1396         }
1397 
1398         if (pCurrFrameDecParams->numGopReferenceSlots)
1399         {
1400             assert(pCurrFrameDecParams->numGopReferenceSlots < 9);
1401             for (uint32_t dpbEntryIdx = 0; dpbEntryIdx < (uint32_t)pCurrFrameDecParams->numGopReferenceSlots;
1402                  dpbEntryIdx++)
1403             {
1404                 pCurrFrameDecParams->pictureResources[dpbEntryIdx].sType =
1405                     VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_INFO_KHR;
1406                 referenceSlots[dpbEntryIdx].pPictureResource = &pCurrFrameDecParams->pictureResources[dpbEntryIdx];
1407             }
1408 
1409             pCurrFrameDecParams->decodeFrameInfo.pReferenceSlots    = referenceSlots;
1410             pCurrFrameDecParams->decodeFrameInfo.referenceSlotCount = pCurrFrameDecParams->numGopReferenceSlots;
1411         }
1412         else
1413         {
1414             pCurrFrameDecParams->decodeFrameInfo.pReferenceSlots    = NULL;
1415             pCurrFrameDecParams->decodeFrameInfo.referenceSlotCount = 0;
1416         }
1417 
1418         if (videoLoggingEnabled())
1419         {
1420             printf(";;; tiling: %d tiles %d cols %d rows\n", p->khr_info.tileCount, p->tileInfo.TileCols,
1421                    p->tileInfo.TileRows);
1422             for (uint32_t i = 0; i < p->khr_info.tileCount; i++)
1423             {
1424                 printf(";;; \ttile %d: offset %d size %d (sbs: %dx%d) (mi: %dx%d): ", i, p->tileOffsets[i],
1425                        p->tileSizes[i], p->tileInfo.pWidthInSbsMinus1[i] + 1, p->tileInfo.pHeightInSbsMinus1[i] + 1,
1426                        p->tileInfo.pMiColStarts[i], p->tileInfo.pMiRowStarts[i]);
1427 
1428                 VkDeviceSize maxSize = 0;
1429                 uint32_t adjustedTileOffset =
1430                     p->tileOffsets[i] + static_cast<uint32_t>(pCurrFrameDecParams->bitstreamDataOffset);
1431                 const uint8_t *bitstreamBytes =
1432                     pCurrFrameDecParams->bitstreamData->GetReadOnlyDataPtr(adjustedTileOffset, maxSize);
1433 
1434                 for (uint32_t j = 0; j < std::min(p->tileSizes[i], 16u); j++)
1435                 {
1436                     printf("%02x ", bitstreamBytes[j]);
1437                 }
1438                 printf("\n");
1439             }
1440         }
1441 
1442         if (m_forceDisableFilmGrain)
1443         {
1444             pStd->flags.apply_grain = 0;
1445         }
1446 
1447         cachedParameters->pictureParams.filmGrainEnabled = pStd->flags.apply_grain;
1448 
1449         pDecodePictureInfo->displayWidth  = p->upscaled_width;
1450         pDecodePictureInfo->displayHeight = p->frame_height;
1451     }
1452 
1453     bRet = DecodePictureWithParameters(cachedParameters) >= 0;
1454 
1455     DE_ASSERT(bRet);
1456 
1457     m_nCurrentPictureID++;
1458 
1459     return bRet;
1460 }
1461 
DecodePictureWithParameters(MovePtr<CachedDecodeParameters> & cachedParameters)1462 int32_t VideoBaseDecoder::DecodePictureWithParameters(MovePtr<CachedDecodeParameters> &cachedParameters)
1463 {
1464     TCU_CHECK_MSG(m_videoSession, "Video session has not been initialized!");
1465 
1466     auto *pPicParams = &cachedParameters->pictureParams;
1467 
1468     DE_ASSERT((uint32_t)pPicParams->currPicIdx < MAX_NUM_DECODE_SURFACES);
1469 
1470     cachedParameters->picNumInDecodeOrder = m_decodePicCount++;
1471     m_videoFrameBuffer->SetPicNumInDecodeOrder(pPicParams->currPicIdx, cachedParameters->picNumInDecodeOrder);
1472 
1473     DE_ASSERT(pPicParams->bitstreamData->GetMaxSize() >= pPicParams->bitstreamDataLen);
1474     pPicParams->decodeFrameInfo.srcBuffer       = pPicParams->bitstreamData->GetBuffer();
1475     pPicParams->decodeFrameInfo.srcBufferOffset = pPicParams->bitstreamDataOffset;
1476     pPicParams->decodeFrameInfo.srcBufferRange =
1477         deAlign64(pPicParams->bitstreamDataLen, m_videoCaps.minBitstreamBufferSizeAlignment);
1478     DE_ASSERT(pPicParams->firstSliceIndex == 0);
1479 
1480     int32_t retPicIdx = GetCurrentFrameData((uint32_t)pPicParams->currPicIdx, cachedParameters->frameDataSlot);
1481     DE_ASSERT(retPicIdx == pPicParams->currPicIdx);
1482 
1483     if (retPicIdx != pPicParams->currPicIdx)
1484     {
1485         fprintf(stderr, "\nERROR: DecodePictureWithParameters() retPicIdx(%d) != currPicIdx(%d)\n", retPicIdx,
1486                 pPicParams->currPicIdx);
1487     }
1488 
1489     auto &decodeBeginInfo = cachedParameters->decodeBeginInfo;
1490     decodeBeginInfo.sType = VK_STRUCTURE_TYPE_VIDEO_BEGIN_CODING_INFO_KHR;
1491     // CmdResetQueryPool are NOT Supported yet.
1492     decodeBeginInfo.pNext        = pPicParams->beginCodingInfoPictureParametersExt;
1493     decodeBeginInfo.videoSession = m_videoSession->GetVideoSession();
1494 
1495     cachedParameters->currentPictureParameterObject = m_currentPictureParameters;
1496 
1497     DE_ASSERT(!!pPicParams->decodeFrameInfo.srcBuffer);
1498     cachedParameters->bitstreamBufferMemoryBarrier = {VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2_KHR,
1499                                                       nullptr,
1500                                                       VK_PIPELINE_STAGE_2_NONE_KHR,
1501                                                       0, // VK_ACCESS_2_HOST_WRITE_BIT_KHR,
1502                                                       VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR,
1503                                                       VK_ACCESS_2_VIDEO_DECODE_READ_BIT_KHR,
1504                                                       (uint32_t)m_deviceContext->decodeQueueFamilyIdx(),
1505                                                       (uint32_t)m_deviceContext->decodeQueueFamilyIdx(),
1506                                                       pPicParams->decodeFrameInfo.srcBuffer,
1507                                                       pPicParams->decodeFrameInfo.srcBufferOffset,
1508                                                       pPicParams->decodeFrameInfo.srcBufferRange};
1509 
1510     bool isLayeredDpb          = m_useImageArray || m_useImageViewArray;
1511     uint32_t currPicArrayLayer = isLayeredDpb ? pPicParams->currPicIdx : 0;
1512     const VkImageSubresourceRange currPicSubresourceRange =
1513         makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, currPicArrayLayer, 1);
1514     // The destination image is never layered.
1515     const VkImageSubresourceRange dstSubresourceRange =
1516         makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1);
1517 
1518     cachedParameters->currentDpbPictureResourceInfo    = VulkanVideoFrameBuffer::PictureResourceInfo();
1519     cachedParameters->currentOutputPictureResourceInfo = VulkanVideoFrameBuffer::PictureResourceInfo();
1520     deMemset(&cachedParameters->currentOutputPictureResource, 0, sizeof(VkVideoPictureResourceInfoKHR));
1521     cachedParameters->currentOutputPictureResource.sType = VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_INFO_KHR;
1522 
1523     auto *pOutputPictureResource     = cachedParameters->pOutputPictureResource;
1524     auto *pOutputPictureResourceInfo = cachedParameters->pOutputPictureResourceInfo;
1525     if (!dpbAndOutputCoincide())
1526     {
1527         // Output Distinct will use the decodeFrameInfo.dstPictureResource directly.
1528         pOutputPictureResource = &pPicParams->decodeFrameInfo.dstPictureResource;
1529     }
1530     else
1531     {
1532         if (!pPicParams->filmGrainEnabled)
1533         {
1534             pOutputPictureResource = &cachedParameters->currentOutputPictureResource;
1535         }
1536         else
1537         {
1538             pOutputPictureResource = &pPicParams->decodeFrameInfo.dstPictureResource;
1539         }
1540     }
1541 
1542     pOutputPictureResourceInfo = &cachedParameters->currentOutputPictureResourceInfo;
1543 
1544     if (pPicParams->currPicIdx != m_videoFrameBuffer->GetCurrentImageResourceByIndex(
1545                                       pPicParams->currPicIdx, &pPicParams->dpbSetupPictureResource,
1546                                       &cachedParameters->currentDpbPictureResourceInfo,
1547                                       VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR, pOutputPictureResource,
1548                                       pOutputPictureResourceInfo, VK_IMAGE_LAYOUT_VIDEO_DECODE_DST_KHR))
1549     {
1550         DE_ASSERT(!"GetImageResourcesByIndex has failed");
1551     }
1552 
1553     pPicParams->dpbSetupPictureResource.codedOffset = {
1554         0, 0}; // FIXME: This parameter must to be adjusted based on the interlaced mode.
1555     pPicParams->dpbSetupPictureResource.codedExtent = {(uint32_t)cachedParameters->decodedPictureInfo.displayWidth,
1556                                                        (uint32_t)cachedParameters->decodedPictureInfo.displayHeight};
1557 
1558     if (pOutputPictureResource)
1559     {
1560         DE_ASSERT(pOutputPictureResource->sType == VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_INFO_KHR);
1561         pOutputPictureResource->codedOffset = {
1562             0, 0}; // FIXME: This parameter must to be adjusted based on the interlaced mode.
1563         pOutputPictureResource->codedExtent = {(uint32_t)cachedParameters->decodedPictureInfo.displayWidth,
1564                                                (uint32_t)cachedParameters->decodedPictureInfo.displayHeight};
1565     }
1566 
1567     if (dpbAndOutputCoincide() && !pPicParams->filmGrainEnabled)
1568     {
1569         // For the Output Coincide, the DPB and destination output resources are the same.
1570         pPicParams->decodeFrameInfo.dstPictureResource = pPicParams->dpbSetupPictureResource;
1571 
1572         // Also, when we are copying the output we need to know which layer is used for the current frame.
1573         // This is if a multi-layered image is used for the DPB and the output (since they coincide).
1574         cachedParameters->decodedPictureInfo.imageLayerIndex = pPicParams->dpbSetupPictureResource.baseArrayLayer;
1575     }
1576     else if (pOutputPictureResourceInfo)
1577     {
1578         // For Output Distinct transition the image to DECODE_DST
1579         if (pOutputPictureResourceInfo->currentImageLayout == VK_IMAGE_LAYOUT_UNDEFINED)
1580         {
1581             VkImageMemoryBarrier2KHR dstBarrier = makeImageMemoryBarrier2(
1582                 VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR, VK_ACCESS_2_VIDEO_DECODE_READ_BIT_KHR,
1583                 VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR, VK_ACCESS_2_VIDEO_DECODE_WRITE_BIT_KHR,
1584                 pOutputPictureResourceInfo->currentImageLayout, VK_IMAGE_LAYOUT_VIDEO_DECODE_DST_KHR,
1585                 pOutputPictureResourceInfo->image, dstSubresourceRange);
1586             cachedParameters->imageBarriers.push_back(dstBarrier);
1587         }
1588     }
1589 
1590     if (cachedParameters->currentDpbPictureResourceInfo.currentImageLayout == VK_IMAGE_LAYOUT_UNDEFINED)
1591     {
1592         VkImageMemoryBarrier2KHR dpbBarrier = makeImageMemoryBarrier2(
1593             VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR, VK_ACCESS_2_VIDEO_DECODE_READ_BIT_KHR,
1594             VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR, VK_ACCESS_2_VIDEO_DECODE_WRITE_BIT_KHR,
1595             pOutputPictureResourceInfo->currentImageLayout, VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR,
1596             cachedParameters->currentDpbPictureResourceInfo.image, currPicSubresourceRange);
1597         cachedParameters->imageBarriers.push_back(dpbBarrier);
1598     }
1599 
1600     deMemset(cachedParameters->pictureResourcesInfo, 0,
1601              DE_LENGTH_OF_ARRAY(cachedParameters->pictureResourcesInfo) *
1602                  sizeof(cachedParameters->pictureResourcesInfo[0]));
1603     const int8_t *pGopReferenceImagesIndexes = pPicParams->pGopReferenceImagesIndexes;
1604     if (pPicParams->numGopReferenceSlots)
1605     {
1606         if (pPicParams->numGopReferenceSlots !=
1607             m_videoFrameBuffer->GetDpbImageResourcesByIndex(
1608                 pPicParams->numGopReferenceSlots, pGopReferenceImagesIndexes, pPicParams->pictureResources,
1609                 cachedParameters->pictureResourcesInfo, VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR))
1610         {
1611             DE_ASSERT(!"GetImageResourcesByIndex has failed");
1612         }
1613         for (int32_t resId = 0; resId < pPicParams->numGopReferenceSlots; resId++)
1614         {
1615             const VkImageSubresourceRange dpbSubresourceRange = makeImageSubresourceRange(
1616                 VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, isLayeredDpb ? pGopReferenceImagesIndexes[resId] : 0, 1);
1617 
1618             VkImageMemoryBarrier2KHR dpbBarrier = makeImageMemoryBarrier2(
1619                 VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR, VK_ACCESS_2_VIDEO_DECODE_WRITE_BIT_KHR,
1620                 VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR, VK_ACCESS_2_VIDEO_DECODE_READ_BIT_KHR,
1621                 cachedParameters->pictureResourcesInfo[resId].currentImageLayout, VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR,
1622                 cachedParameters->pictureResourcesInfo[resId].image, dpbSubresourceRange);
1623             cachedParameters->imageBarriers.push_back(dpbBarrier);
1624         }
1625 
1626         if (videoLoggingEnabled())
1627         {
1628             for (int32_t resId = 0; resId < pPicParams->numGopReferenceSlots; resId++)
1629             {
1630                 tcu::print(";;; DPB %d: %d x %d\n", resId, pPicParams->pictureResources[resId].codedExtent.width,
1631                            pPicParams->pictureResources[resId].codedExtent.height);
1632             }
1633         }
1634     }
1635 
1636     decodeBeginInfo.referenceSlotCount = pPicParams->decodeFrameInfo.referenceSlotCount;
1637     decodeBeginInfo.pReferenceSlots    = pPicParams->decodeFrameInfo.pReferenceSlots;
1638 
1639     // Ensure the resource for the resources associated with the
1640     // reference slot (if it exists) are in the bound picture
1641     // resources set.  See VUID-vkCmdDecodeVideoKHR-pDecodeInfo-07149.
1642     if (pPicParams->decodeFrameInfo.pSetupReferenceSlot != nullptr)
1643     {
1644         cachedParameters->fullReferenceSlots.clear();
1645         for (uint32_t i = 0; i < decodeBeginInfo.referenceSlotCount; i++)
1646             cachedParameters->fullReferenceSlots.push_back(decodeBeginInfo.pReferenceSlots[i]);
1647         VkVideoReferenceSlotInfoKHR setupActivationSlot = {};
1648         setupActivationSlot.sType                       = VK_STRUCTURE_TYPE_VIDEO_REFERENCE_SLOT_INFO_KHR;
1649         setupActivationSlot.slotIndex                   = -1;
1650         setupActivationSlot.pPictureResource            = &pPicParams->dpbSetupPictureResource;
1651         cachedParameters->fullReferenceSlots.push_back(setupActivationSlot);
1652         decodeBeginInfo.referenceSlotCount++;
1653         decodeBeginInfo.pReferenceSlots = cachedParameters->fullReferenceSlots.data();
1654     }
1655 
1656     if (cachedParameters->decodedPictureInfo.flags.unpairedField)
1657     {
1658         // DE_ASSERT(pFrameSyncinfo->frameCompleteSemaphore == VK_NULL_HANDLE);
1659         cachedParameters->decodedPictureInfo.flags.syncFirstReady = true;
1660     }
1661     // FIXME: the below sequence for interlaced synchronization.
1662     cachedParameters->decodedPictureInfo.flags.syncToFirstField = false;
1663 
1664     cachedParameters->frameSynchronizationInfo = VulkanVideoFrameBuffer::FrameSynchronizationInfo();
1665     cachedParameters->frameSynchronizationInfo.hasFrameCompleteSignalFence = true;
1666     cachedParameters->frameSynchronizationInfo.hasFrameCompleteSignalSemaphore =
1667         cachedParameters->av1PicParams.showFrame;
1668 
1669     VulkanVideoFrameBuffer::ReferencedObjectsInfo referencedObjectsInfo(pPicParams->bitstreamData, pPicParams->pStdPps,
1670                                                                         pPicParams->pStdSps, pPicParams->pStdVps,
1671                                                                         pPicParams->pStdAv1Sps);
1672     int currPicIdx =
1673         m_videoFrameBuffer->QueuePictureForDecode(pPicParams->currPicIdx, &cachedParameters->decodedPictureInfo,
1674                                                   &referencedObjectsInfo, &cachedParameters->frameSynchronizationInfo);
1675     DE_ASSERT(currPicIdx == currPicIdx);
1676     DE_UNREF(currPicIdx);
1677 
1678     if (m_outOfOrderDecoding)
1679     {
1680         if (cachedParameters->pictureParams.isAV1)
1681             // We do not want the displayed frames to be evicted until we are ready to submit them
1682             // So keep a reference in the cached object
1683             cachedParameters->pd.pCurrPic->AddRef();
1684         return pPicParams->currPicIdx;
1685     }
1686 
1687     WaitForFrameFences(cachedParameters);
1688     ApplyPictureParameters(cachedParameters);
1689     RecordCommandBuffer(cachedParameters);
1690     SubmitQueue(cachedParameters);
1691     if (m_queryResultWithStatus)
1692     {
1693         QueryDecodeResults(cachedParameters);
1694     }
1695 
1696     return pPicParams->currPicIdx;
1697 }
1698 
ApplyPictureParameters(de::MovePtr<CachedDecodeParameters> & cachedParameters)1699 void VideoBaseDecoder::ApplyPictureParameters(de::MovePtr<CachedDecodeParameters> &cachedParameters)
1700 {
1701     auto *pPicParams = &cachedParameters->pictureParams;
1702     VkSharedBaseObj<VkVideoRefCountBase> currentVkPictureParameters;
1703     VkParserVideoPictureParameters *pOwnerPictureParameters = nullptr;
1704 
1705     if ((m_profile.GetCodecType() == VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR) ||
1706         (m_profile.GetCodecType() == VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR))
1707     {
1708         bool valid = pPicParams->pStdPps->GetClientObject(currentVkPictureParameters);
1709         TCU_CHECK(currentVkPictureParameters && valid);
1710         pOwnerPictureParameters =
1711             VkParserVideoPictureParameters::VideoPictureParametersFromBase(currentVkPictureParameters);
1712         TCU_CHECK(pOwnerPictureParameters);
1713         int32_t ret = pOwnerPictureParameters->FlushPictureParametersQueue(m_videoSession);
1714         TCU_CHECK(ret >= 0);
1715         DE_UNREF(ret);
1716         bool isSps    = false;
1717         int32_t spsId = pPicParams->pStdPps->GetSpsId(isSps);
1718         TCU_CHECK(!isSps);
1719         TCU_CHECK(spsId >= 0);
1720         TCU_CHECK(pOwnerPictureParameters->HasSpsId(spsId));
1721         bool isPps    = false;
1722         int32_t ppsId = pPicParams->pStdPps->GetPpsId(isPps);
1723         TCU_CHECK(isPps);
1724         TCU_CHECK(ppsId >= 0);
1725         TCU_CHECK(pOwnerPictureParameters->HasPpsId(ppsId));
1726         DE_UNREF(valid);
1727     }
1728     else if (m_profile.GetCodecType() == VK_VIDEO_CODEC_OPERATION_DECODE_AV1_BIT_KHR)
1729     {
1730         bool valid = pPicParams->pStdAv1Sps->GetClientObject(currentVkPictureParameters);
1731         TCU_CHECK(currentVkPictureParameters && valid);
1732         pOwnerPictureParameters =
1733             VkParserVideoPictureParameters::VideoPictureParametersFromBase(currentVkPictureParameters);
1734         TCU_CHECK(pOwnerPictureParameters);
1735         int32_t ret = pOwnerPictureParameters->FlushPictureParametersQueue(m_videoSession);
1736         TCU_CHECK(ret >= 0);
1737         DE_UNREF(ret);
1738     }
1739     cachedParameters->decodeBeginInfo.videoSessionParameters = *pOwnerPictureParameters;
1740 }
1741 
WaitForFrameFences(de::MovePtr<CachedDecodeParameters> & cachedParameters)1742 void VideoBaseDecoder::WaitForFrameFences(de::MovePtr<CachedDecodeParameters> &cachedParameters)
1743 {
1744     // Check here that the frame for this entry (for this command buffer) has already completed decoding.
1745     // Otherwise we may step over a hot command buffer by starting a new recording.
1746     // This fence wait should be NOP in 99.9% of the cases, because the decode queue is deep enough to
1747     // ensure the frame has already been completed.
1748     VK_CHECK(m_deviceContext->getDeviceDriver().waitForFences(
1749         m_deviceContext->device, 1, &cachedParameters->frameSynchronizationInfo.frameCompleteFence, true,
1750         TIMEOUT_100ms));
1751     VkResult result = m_deviceContext->getDeviceDriver().getFenceStatus(
1752         m_deviceContext->device, cachedParameters->frameSynchronizationInfo.frameCompleteFence);
1753     TCU_CHECK_MSG(result == VK_SUCCESS || result == VK_NOT_READY, "Bad fence status");
1754 }
1755 
RecordCommandBuffer(de::MovePtr<CachedDecodeParameters> & cachedParameters)1756 void VideoBaseDecoder::RecordCommandBuffer(de::MovePtr<CachedDecodeParameters> &cachedParameters)
1757 {
1758     auto &vk = m_deviceContext->getDeviceDriver();
1759 
1760     VkCommandBuffer commandBuffer = cachedParameters->frameDataSlot.commandBuffer;
1761 
1762     VkCommandBufferBeginInfo beginInfo{};
1763     beginInfo.sType            = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
1764     beginInfo.flags            = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
1765     beginInfo.pInheritanceInfo = nullptr;
1766 
1767     VkVideoInlineQueryInfoKHR inlineQueryInfo{};
1768     inlineQueryInfo.sType = VK_STRUCTURE_TYPE_VIDEO_INLINE_QUERY_INFO_KHR;
1769 
1770     vk.beginCommandBuffer(commandBuffer, &beginInfo);
1771 
1772     if (m_queryResultWithStatus || m_useInlineQueries)
1773     {
1774         vk.cmdResetQueryPool(commandBuffer, cachedParameters->frameSynchronizationInfo.queryPool,
1775                              cachedParameters->frameSynchronizationInfo.startQueryId,
1776                              cachedParameters->frameSynchronizationInfo.numQueries);
1777     }
1778 
1779     vk.cmdBeginVideoCodingKHR(commandBuffer, &cachedParameters->decodeBeginInfo);
1780 
1781     if (cachedParameters->performCodecReset)
1782     {
1783         VkVideoCodingControlInfoKHR codingControlInfo = {VK_STRUCTURE_TYPE_VIDEO_CODING_CONTROL_INFO_KHR, nullptr,
1784                                                          VK_VIDEO_CODING_CONTROL_RESET_BIT_KHR};
1785         vk.cmdControlVideoCodingKHR(commandBuffer, &codingControlInfo);
1786     }
1787 
1788     const VkDependencyInfoKHR dependencyInfo = {
1789         VK_STRUCTURE_TYPE_DEPENDENCY_INFO_KHR,
1790         nullptr,
1791         VK_DEPENDENCY_BY_REGION_BIT,
1792         0,
1793         nullptr,
1794         1,
1795         &cachedParameters->bitstreamBufferMemoryBarrier,
1796         static_cast<uint32_t>(cachedParameters->imageBarriers.size()),
1797         cachedParameters->imageBarriers.data(),
1798     };
1799     vk.cmdPipelineBarrier2(commandBuffer, &dependencyInfo);
1800 
1801     if (m_useInlineQueries)
1802     {
1803         const void *currentPNext                              = cachedParameters->pictureParams.decodeFrameInfo.pNext;
1804         inlineQueryInfo.pNext                                 = currentPNext;
1805         inlineQueryInfo.queryPool                             = cachedParameters->frameSynchronizationInfo.queryPool;
1806         inlineQueryInfo.firstQuery                            = cachedParameters->frameSynchronizationInfo.startQueryId;
1807         inlineQueryInfo.queryCount                            = cachedParameters->frameSynchronizationInfo.numQueries;
1808         cachedParameters->pictureParams.decodeFrameInfo.pNext = &inlineQueryInfo;
1809     }
1810 
1811     if (m_queryResultWithStatus && !m_useInlineQueries)
1812     {
1813         vk.cmdBeginQuery(commandBuffer, cachedParameters->frameSynchronizationInfo.queryPool,
1814                          cachedParameters->frameSynchronizationInfo.startQueryId, VkQueryControlFlags());
1815     }
1816 
1817     vk.cmdDecodeVideoKHR(commandBuffer, &cachedParameters->pictureParams.decodeFrameInfo);
1818 
1819     if (m_queryResultWithStatus && !m_useInlineQueries)
1820     {
1821         vk.cmdEndQuery(commandBuffer, cachedParameters->frameSynchronizationInfo.queryPool,
1822                        cachedParameters->frameSynchronizationInfo.startQueryId);
1823     }
1824 
1825     VkVideoEndCodingInfoKHR decodeEndInfo{};
1826     decodeEndInfo.sType = VK_STRUCTURE_TYPE_VIDEO_END_CODING_INFO_KHR;
1827     vk.cmdEndVideoCodingKHR(commandBuffer, &decodeEndInfo);
1828 
1829     m_deviceContext->getDeviceDriver().endCommandBuffer(commandBuffer);
1830 }
1831 
SubmitQueue(de::MovePtr<CachedDecodeParameters> & cachedParameters)1832 void VideoBaseDecoder::SubmitQueue(de::MovePtr<CachedDecodeParameters> &cachedParameters)
1833 {
1834     auto &vk                      = m_deviceContext->getDeviceDriver();
1835     auto device                   = m_deviceContext->device;
1836     VkCommandBuffer commandBuffer = cachedParameters->frameDataSlot.commandBuffer;
1837     VkSubmitInfo submitInfo{};
1838     submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
1839     submitInfo.waitSemaphoreCount =
1840         (cachedParameters->frameSynchronizationInfo.frameConsumerDoneSemaphore == VK_NULL_HANDLE) ? 0 : 1;
1841     submitInfo.pWaitSemaphores = &cachedParameters->frameSynchronizationInfo.frameConsumerDoneSemaphore;
1842     VkPipelineStageFlags videoDecodeSubmitWaitStages = VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR;
1843     submitInfo.pWaitDstStageMask                     = &videoDecodeSubmitWaitStages;
1844     submitInfo.commandBufferCount                    = 1;
1845     submitInfo.pCommandBuffers                       = &commandBuffer;
1846     bool haveSignalSemaphore        = cachedParameters->frameSynchronizationInfo.hasFrameCompleteSignalSemaphore;
1847     submitInfo.signalSemaphoreCount = haveSignalSemaphore ? 1 : 0;
1848     submitInfo.pSignalSemaphores =
1849         haveSignalSemaphore ? &cachedParameters->frameSynchronizationInfo.frameCompleteSemaphore : nullptr;
1850 
1851     VK_CHECK(vk.resetFences(device, 1, &cachedParameters->frameSynchronizationInfo.frameCompleteFence));
1852     VK_CHECK(vk.queueSubmit(m_deviceContext->decodeQueue, 1, &submitInfo,
1853                             cachedParameters->frameSynchronizationInfo.frameCompleteFence));
1854 
1855     if (videoLoggingEnabled())
1856     {
1857         std::cout << ";;; submit frame:"
1858                   << " PicIdx=" << cachedParameters->pictureParams.currPicIdx
1859                   << " decodeOrder=" << cachedParameters->picNumInDecodeOrder
1860                   << " frameCompleteFence=" << cachedParameters->frameSynchronizationInfo.frameCompleteFence
1861                   << " frameCompleteSem=" << cachedParameters->frameSynchronizationInfo.frameCompleteSemaphore
1862                   << " dstImageView="
1863                   << cachedParameters->pictureParams.decodeFrameInfo.dstPictureResource.imageViewBinding << std::endl;
1864     }
1865 }
1866 
QueryDecodeResults(de::MovePtr<CachedDecodeParameters> & cachedParameters)1867 void VideoBaseDecoder::QueryDecodeResults(de::MovePtr<CachedDecodeParameters> &cachedParameters)
1868 {
1869     auto &vk    = m_deviceContext->getDeviceDriver();
1870     auto device = m_deviceContext->device;
1871 
1872     WaitForFrameFences(cachedParameters);
1873 
1874     VkQueryResultStatusKHR decodeStatus;
1875     VkResult result = vk.getQueryPoolResults(device, cachedParameters->frameSynchronizationInfo.queryPool,
1876                                              cachedParameters->frameSynchronizationInfo.startQueryId, 1,
1877                                              sizeof(decodeStatus), &decodeStatus, sizeof(decodeStatus),
1878                                              VK_QUERY_RESULT_WITH_STATUS_BIT_KHR | VK_QUERY_RESULT_WAIT_BIT);
1879     if (videoLoggingEnabled())
1880     {
1881         std::cout << ";;; QueryDecodeResults:"
1882                   << " PicIdx=" << cachedParameters->pictureParams.currPicIdx << " status=" << decodeStatus
1883                   << std::endl;
1884     }
1885 
1886     TCU_CHECK_AND_THROW(TestError, result == VK_SUCCESS || result == VK_ERROR_DEVICE_LOST,
1887                         "Driver has returned an invalid query result");
1888     TCU_CHECK_AND_THROW(TestError, decodeStatus != VK_QUERY_RESULT_STATUS_ERROR_KHR,
1889                         "Decode query returned an unexpected error");
1890 }
1891 
decodeFramesOutOfOrder()1892 void VideoBaseDecoder::decodeFramesOutOfOrder()
1893 {
1894     if (videoLoggingEnabled())
1895     {
1896         tcu::print(";;; Begin out of order decoding\n");
1897     }
1898 
1899     std::vector<int> ordering(m_cachedDecodeParams.size());
1900     std::iota(ordering.begin(), ordering.end(), 0);
1901     if (ordering.size() == 2)
1902         std::swap(ordering[0], ordering[1]);
1903     else
1904     {
1905         auto rng = std::mt19937(42);
1906         std::shuffle(ordering.begin(), ordering.end(), rng);
1907     }
1908     DE_ASSERT(m_cachedDecodeParams.size() > 1);
1909 
1910     if (videoLoggingEnabled())
1911     {
1912         tcu::print(";;; record order: ");
1913         for (int recordOrderIdx : ordering)
1914             tcu::print("%d ", recordOrderIdx);
1915         tcu::print("\n");
1916     }
1917 
1918     // Record out of order
1919     for (int recordOrderIdx : ordering)
1920     {
1921         auto &cachedParams = m_cachedDecodeParams[recordOrderIdx];
1922         WaitForFrameFences(cachedParams);
1923         ApplyPictureParameters(cachedParams);
1924         RecordCommandBuffer(cachedParams);
1925     }
1926 
1927     // Submit in order
1928     for (int i = 0; i < m_cachedDecodeParams.size(); i++)
1929     {
1930         auto &cachedParams = m_cachedDecodeParams[i];
1931         SubmitQueue(cachedParams);
1932         if (m_queryResultWithStatus || m_useInlineQueries)
1933         {
1934             QueryDecodeResults(cachedParams);
1935         }
1936     }
1937 }
1938 
UpdatePictureParameters(VkSharedBaseObj<StdVideoPictureParametersSet> & pictureParametersObject,VkSharedBaseObj<VkVideoRefCountBase> & client)1939 bool VideoBaseDecoder::UpdatePictureParameters(
1940     VkSharedBaseObj<StdVideoPictureParametersSet> &pictureParametersObject, /* in */
1941     VkSharedBaseObj<VkVideoRefCountBase> &client)
1942 {
1943     triggerPictureParameterSequenceCount();
1944 
1945     VkResult result = VkParserVideoPictureParameters::AddPictureParameters(
1946         *m_deviceContext, m_videoSession, pictureParametersObject, m_currentPictureParameters);
1947     client = m_currentPictureParameters;
1948     return (result == VK_SUCCESS);
1949 }
1950 
DisplayPicture(VkPicIf * pNvidiaVulkanPicture,int64_t)1951 bool VideoBaseDecoder::DisplayPicture(VkPicIf *pNvidiaVulkanPicture, int64_t /*llPTS*/)
1952 {
1953     vkPicBuffBase *pVkPicBuff = GetPic(pNvidiaVulkanPicture);
1954 
1955     DE_ASSERT(pVkPicBuff != nullptr);
1956     int32_t picIdx = pVkPicBuff ? pVkPicBuff->m_picIdx : -1;
1957     DE_ASSERT(picIdx != -1);
1958     DE_ASSERT(m_videoFrameBuffer != nullptr);
1959 
1960     if (videoLoggingEnabled())
1961     {
1962         std::cout << ";;; DisplayPicture: " << picIdx << std::endl;
1963     }
1964 
1965     VulkanVideoDisplayPictureInfo dispInfo = VulkanVideoDisplayPictureInfo();
1966 
1967     dispInfo.timestamp = 0; // NOTE: we ignore PTS in the CTS
1968 
1969     const int32_t retVal = m_videoFrameBuffer->QueueDecodedPictureForDisplay((int8_t)picIdx, &dispInfo);
1970     DE_ASSERT(picIdx == retVal);
1971     DE_UNREF(retVal);
1972 
1973     return true;
1974 }
1975 
ReleaseDisplayedFrame(DecodedFrame * pDisplayedFrame)1976 int32_t VideoBaseDecoder::ReleaseDisplayedFrame(DecodedFrame *pDisplayedFrame)
1977 {
1978     if (pDisplayedFrame->pictureIndex == -1)
1979         return -1;
1980 
1981     DecodedFrameRelease decodedFramesRelease         = {pDisplayedFrame->pictureIndex, 0, 0, 0, 0, 0};
1982     DecodedFrameRelease *decodedFramesReleasePtr     = &decodedFramesRelease;
1983     pDisplayedFrame->pictureIndex                    = -1;
1984     decodedFramesRelease.decodeOrder                 = pDisplayedFrame->decodeOrder;
1985     decodedFramesRelease.displayOrder                = pDisplayedFrame->displayOrder;
1986     decodedFramesRelease.hasConsummerSignalFence     = pDisplayedFrame->hasConsummerSignalFence;
1987     decodedFramesRelease.hasConsummerSignalSemaphore = pDisplayedFrame->hasConsummerSignalSemaphore;
1988     decodedFramesRelease.timestamp                   = 0;
1989 
1990     return m_videoFrameBuffer->ReleaseDisplayedPicture(&decodedFramesReleasePtr, 1);
1991 }
1992 
GetBitstreamBuffer(VkDeviceSize newSize,VkDeviceSize minBitstreamBufferOffsetAlignment,VkDeviceSize minBitstreamBufferSizeAlignment,const uint8_t * pInitializeBufferMemory,VkDeviceSize initializeBufferMemorySize,VkSharedBaseObj<VulkanBitstreamBuffer> & bitstreamBuffer)1993 VkDeviceSize VideoBaseDecoder::GetBitstreamBuffer(VkDeviceSize newSize, VkDeviceSize minBitstreamBufferOffsetAlignment,
1994                                                   VkDeviceSize minBitstreamBufferSizeAlignment,
1995                                                   const uint8_t *pInitializeBufferMemory,
1996                                                   VkDeviceSize initializeBufferMemorySize,
1997                                                   VkSharedBaseObj<VulkanBitstreamBuffer> &bitstreamBuffer)
1998 {
1999     DE_ASSERT(initializeBufferMemorySize <= newSize);
2000 
2001     VkSharedBaseObj<BitstreamBufferImpl> newBitstreamBuffer;
2002     VK_CHECK(BitstreamBufferImpl::Create(m_deviceContext, m_deviceContext->decodeQueueFamilyIdx(), newSize,
2003                                          minBitstreamBufferOffsetAlignment, minBitstreamBufferSizeAlignment,
2004                                          newBitstreamBuffer, m_profile.GetProfileListInfo()));
2005     DE_ASSERT(newBitstreamBuffer);
2006     newSize = newBitstreamBuffer->GetMaxSize();
2007     DE_ASSERT(initializeBufferMemorySize <= newSize);
2008 
2009     size_t bytesToCopy = std::min(initializeBufferMemorySize, newSize);
2010     size_t bytesCopied =
2011         newBitstreamBuffer->CopyDataFromBuffer((const uint8_t *)pInitializeBufferMemory, 0, 0, bytesToCopy);
2012     DE_ASSERT(bytesToCopy == bytesCopied);
2013     DE_UNREF(bytesCopied);
2014 
2015     newBitstreamBuffer->MemsetData(0x0, bytesToCopy, newSize - bytesToCopy);
2016 
2017     bitstreamBuffer = newBitstreamBuffer;
2018     if (videoLoggingEnabled())
2019     {
2020         std::cout << "Allocated bitstream buffer with size " << newSize << " B, " << newSize / 1024 << " KB, "
2021                   << newSize / 1024 / 1024 << " MB" << std::endl;
2022     }
2023 
2024     return newBitstreamBuffer->GetMaxSize();
2025 }
2026 
UnhandledNALU(const uint8_t * pbData,size_t cbData)2027 void VideoBaseDecoder::UnhandledNALU(const uint8_t *pbData, size_t cbData)
2028 {
2029     const vector<uint8_t> data(pbData, pbData + cbData);
2030     ostringstream css;
2031 
2032     css << "UnhandledNALU=";
2033 
2034     for (const auto &i : data)
2035         css << std::hex << std::setw(2) << std::setfill('0') << (uint32_t)i << ' ';
2036 
2037     TCU_THROW(InternalError, css.str());
2038 }
2039 
FillDpbH264State(const VkParserPictureData * pd,const VkParserH264DpbEntry * dpbIn,uint32_t maxDpbInSlotsInUse,nvVideoDecodeH264DpbSlotInfo * pDpbRefList,uint32_t,VkVideoReferenceSlotInfoKHR * pReferenceSlots,int8_t * pGopReferenceImagesIndexes,StdVideoDecodeH264PictureInfoFlags currPicFlags,int32_t * pCurrAllocatedSlotIndex)2040 uint32_t VideoBaseDecoder::FillDpbH264State(const VkParserPictureData *pd, const VkParserH264DpbEntry *dpbIn,
2041                                             uint32_t maxDpbInSlotsInUse, nvVideoDecodeH264DpbSlotInfo *pDpbRefList,
2042                                             uint32_t /*maxRefPictures*/, VkVideoReferenceSlotInfoKHR *pReferenceSlots,
2043                                             int8_t *pGopReferenceImagesIndexes,
2044                                             StdVideoDecodeH264PictureInfoFlags currPicFlags,
2045                                             int32_t *pCurrAllocatedSlotIndex)
2046 {
2047     // #### Update m_dpb based on dpb parameters ####
2048     // Create unordered DPB and generate a bitmask of all render targets present
2049     // in DPB
2050     uint32_t num_ref_frames = pd->CodecSpecific.h264.pStdSps->GetStdH264Sps()->max_num_ref_frames;
2051     DE_ASSERT(num_ref_frames <= H26X_MAX_DPB_SLOTS);
2052     DE_ASSERT(num_ref_frames <= m_maxNumDpbSlots);
2053     // TODO(legacy): Why does AVC require a setup slot to be accounted for here, but not HEVC?
2054     dpbH264Entry refOnlyDpbIn[H26X_MAX_DPB_SLOTS + 1]; // max number of Dpb
2055     // surfaces
2056     memset(&refOnlyDpbIn, 0, m_maxNumDpbSlots * sizeof(refOnlyDpbIn[0]));
2057     uint32_t refDpbUsedAndValidMask = 0;
2058     uint32_t numUsedRef             = 0;
2059     for (int32_t inIdx = 0; (uint32_t)inIdx < maxDpbInSlotsInUse; inIdx++)
2060     {
2061         // used_for_reference: 0 = unused, 1 = top_field, 2 = bottom_field, 3 =
2062         // both_fields
2063         const uint32_t used_for_reference = dpbIn[inIdx].used_for_reference & fieldIsReferenceMask;
2064         if (used_for_reference)
2065         {
2066             int8_t picIdx = (!dpbIn[inIdx].not_existing && dpbIn[inIdx].pPicBuf) ? GetPicIdx(dpbIn[inIdx].pPicBuf) : -1;
2067             const bool isFieldRef              = (picIdx >= 0) ?
2068                                                      GetFieldPicFlag(picIdx) :
2069                                                      (used_for_reference && (used_for_reference != fieldIsReferenceMask));
2070             const int16_t fieldOrderCntList[2] = {(int16_t)dpbIn[inIdx].FieldOrderCnt[0],
2071                                                   (int16_t)dpbIn[inIdx].FieldOrderCnt[1]};
2072             refOnlyDpbIn[numUsedRef].setReferenceAndTopBottomField(
2073                 !!used_for_reference, (picIdx < 0), /* not_existing is frame inferred by the decoding
2074                                              process for gaps in frame_num */
2075                 !!dpbIn[inIdx].is_long_term, isFieldRef, !!(used_for_reference & topFieldMask),
2076                 !!(used_for_reference & bottomFieldMask), dpbIn[inIdx].FrameIdx, fieldOrderCntList,
2077                 GetPic(dpbIn[inIdx].pPicBuf));
2078             if (picIdx >= 0)
2079             {
2080                 refDpbUsedAndValidMask |= (1 << picIdx);
2081             }
2082             numUsedRef++;
2083         }
2084         // Invalidate all slots.
2085         pReferenceSlots[inIdx].slotIndex  = -1;
2086         pGopReferenceImagesIndexes[inIdx] = -1;
2087     }
2088 
2089     DE_ASSERT(numUsedRef <= H26X_MAX_DPB_SLOTS);
2090     DE_ASSERT(numUsedRef <= m_maxNumDpbSlots);
2091     DE_ASSERT(numUsedRef <= num_ref_frames);
2092 
2093     if (videoLoggingEnabled())
2094     {
2095         std::cout << " =>>> ********************* picIdx: " << (int32_t)GetPicIdx(pd->pCurrPic)
2096                   << " *************************" << std::endl;
2097         std::cout << "\tRef frames data in for picIdx: " << (int32_t)GetPicIdx(pd->pCurrPic) << std::endl
2098                   << "\tSlot Index:\t\t";
2099         if (numUsedRef == 0)
2100             std::cout << "(none)" << std::endl;
2101         else
2102         {
2103             for (uint32_t slot = 0; slot < numUsedRef; slot++)
2104             {
2105                 if (!refOnlyDpbIn[slot].is_non_existing)
2106                 {
2107                     std::cout << slot << ",\t";
2108                 }
2109                 else
2110                 {
2111                     std::cout << 'X' << ",\t";
2112                 }
2113             }
2114             std::cout << std::endl;
2115         }
2116         std::cout << "\tPict Index:\t\t";
2117         if (numUsedRef == 0)
2118             std::cout << "(none)" << std::endl;
2119         else
2120         {
2121             for (uint32_t slot = 0; slot < numUsedRef; slot++)
2122             {
2123                 if (!refOnlyDpbIn[slot].is_non_existing)
2124                 {
2125                     std::cout << refOnlyDpbIn[slot].m_picBuff->m_picIdx << ",\t";
2126                 }
2127                 else
2128                 {
2129                     std::cout << 'X' << ",\t";
2130                 }
2131             }
2132         }
2133         std::cout << "\n\tTotal Ref frames for picIdx: " << (int32_t)GetPicIdx(pd->pCurrPic) << " : " << numUsedRef
2134                   << " out of " << num_ref_frames << " MAX(" << m_maxNumDpbSlots << ")" << std::endl
2135                   << std::endl;
2136 
2137         std::cout << std::flush;
2138     }
2139 
2140     // Map all frames not present in DPB as non-reference, and generate a mask of
2141     // all used DPB entries
2142     /* uint32_t destUsedDpbMask = */ ResetPicDpbSlots(refDpbUsedAndValidMask);
2143 
2144     // Now, map DPB render target indices to internal frame buffer index,
2145     // assign each reference a unique DPB entry, and create the ordered DPB
2146     // This is an undocumented MV restriction: the position in the DPB is stored
2147     // along with the co-located data, so once a reference frame is assigned a DPB
2148     // entry, it can no longer change.
2149 
2150     // Find or allocate slots for existing dpb items.
2151     // Take into account the reference picture now.
2152     int8_t currPicIdx = GetPicIdx(pd->pCurrPic);
2153     DE_ASSERT(currPicIdx >= 0);
2154     int8_t bestNonExistingPicIdx = currPicIdx;
2155     if (refDpbUsedAndValidMask)
2156     {
2157         int32_t minFrameNumDiff = 0x10000;
2158         for (int32_t dpbIdx = 0; (uint32_t)dpbIdx < numUsedRef; dpbIdx++)
2159         {
2160             if (!refOnlyDpbIn[dpbIdx].is_non_existing)
2161             {
2162                 vkPicBuffBase *picBuff = refOnlyDpbIn[dpbIdx].m_picBuff;
2163                 int8_t picIdx          = GetPicIdx(picBuff); // should always be valid at this point
2164                 DE_ASSERT(picIdx >= 0);
2165                 // We have up to 17 internal frame buffers, but only MAX_DPB_SIZE dpb
2166                 // entries, so we need to re-map the index from the [0..MAX_DPB_SIZE]
2167                 // range to [0..15]
2168                 int8_t dpbSlot = GetPicDpbSlot(picIdx);
2169                 if (dpbSlot < 0)
2170                 {
2171                     dpbSlot = m_dpb.AllocateSlot();
2172                     DE_ASSERT((dpbSlot >= 0) && ((uint32_t)dpbSlot < m_maxNumDpbSlots));
2173                     SetPicDpbSlot(picIdx, dpbSlot);
2174                     m_dpb[dpbSlot].setPictureResource(picBuff, m_nCurrentPictureID);
2175                 }
2176                 m_dpb[dpbSlot].MarkInUse(m_nCurrentPictureID);
2177                 DE_ASSERT(dpbSlot >= 0);
2178 
2179                 if (dpbSlot >= 0)
2180                 {
2181                     refOnlyDpbIn[dpbIdx].dpbSlot = dpbSlot;
2182                 }
2183                 else
2184                 {
2185                     // This should never happen
2186                     printf("DPB mapping logic broken!\n");
2187                     DE_ASSERT(0);
2188                 }
2189 
2190                 int32_t frameNumDiff = ((int32_t)pd->CodecSpecific.h264.frame_num - refOnlyDpbIn[dpbIdx].FrameIdx);
2191                 if (frameNumDiff <= 0)
2192                 {
2193                     frameNumDiff = 0xffff;
2194                 }
2195                 if (frameNumDiff < minFrameNumDiff)
2196                 {
2197                     bestNonExistingPicIdx = picIdx;
2198                     minFrameNumDiff       = frameNumDiff;
2199                 }
2200                 else if (bestNonExistingPicIdx == currPicIdx)
2201                 {
2202                     bestNonExistingPicIdx = picIdx;
2203                 }
2204             }
2205         }
2206     }
2207     // In Vulkan, we always allocate a Dbp slot for the current picture,
2208     // regardless if it is going to become a reference or not. Non-reference slots
2209     // get freed right after usage. if (pd->ref_pic_flag) {
2210     int8_t currPicDpbSlot = AllocateDpbSlotForCurrentH264(GetPic(pd->pCurrPic), currPicFlags, pd->current_dpb_id);
2211     DE_ASSERT(currPicDpbSlot >= 0);
2212     *pCurrAllocatedSlotIndex = currPicDpbSlot;
2213 
2214     if (refDpbUsedAndValidMask)
2215     {
2216         // Find or allocate slots for non existing dpb items and populate the slots.
2217         uint32_t dpbInUseMask          = m_dpb.getSlotInUseMask();
2218         int8_t firstNonExistingDpbSlot = 0;
2219         for (uint32_t dpbIdx = 0; dpbIdx < numUsedRef; dpbIdx++)
2220         {
2221             int8_t dpbSlot = -1;
2222             int8_t picIdx  = -1;
2223             if (refOnlyDpbIn[dpbIdx].is_non_existing)
2224             {
2225                 DE_ASSERT(refOnlyDpbIn[dpbIdx].m_picBuff == NULL);
2226                 while (((uint32_t)firstNonExistingDpbSlot < m_maxNumDpbSlots) && (dpbSlot == -1))
2227                 {
2228                     if (!(dpbInUseMask & (1 << firstNonExistingDpbSlot)))
2229                     {
2230                         dpbSlot = firstNonExistingDpbSlot;
2231                     }
2232                     firstNonExistingDpbSlot++;
2233                 }
2234                 DE_ASSERT((dpbSlot >= 0) && ((uint32_t)dpbSlot < m_maxNumDpbSlots));
2235                 picIdx = bestNonExistingPicIdx;
2236                 // Find the closest valid refpic already in the DPB
2237                 uint32_t minDiffPOC = 0x7fff;
2238                 for (uint32_t j = 0; j < numUsedRef; j++)
2239                 {
2240                     if (!refOnlyDpbIn[j].is_non_existing &&
2241                         (refOnlyDpbIn[j].used_for_reference & refOnlyDpbIn[dpbIdx].used_for_reference) ==
2242                             refOnlyDpbIn[dpbIdx].used_for_reference)
2243                     {
2244                         uint32_t diffPOC =
2245                             abs((int32_t)(refOnlyDpbIn[j].FieldOrderCnt[0] - refOnlyDpbIn[dpbIdx].FieldOrderCnt[0]));
2246                         if (diffPOC <= minDiffPOC)
2247                         {
2248                             minDiffPOC = diffPOC;
2249                             picIdx     = GetPicIdx(refOnlyDpbIn[j].m_picBuff);
2250                         }
2251                     }
2252                 }
2253             }
2254             else
2255             {
2256                 DE_ASSERT(refOnlyDpbIn[dpbIdx].m_picBuff != NULL);
2257                 dpbSlot = refOnlyDpbIn[dpbIdx].dpbSlot;
2258                 picIdx  = GetPicIdx(refOnlyDpbIn[dpbIdx].m_picBuff);
2259             }
2260             DE_ASSERT((dpbSlot >= 0) && ((uint32_t)dpbSlot < m_maxNumDpbSlots));
2261             refOnlyDpbIn[dpbIdx].setH264PictureData(pDpbRefList, pReferenceSlots, dpbIdx, dpbSlot,
2262                                                     pd->progressive_frame);
2263             pGopReferenceImagesIndexes[dpbIdx] = picIdx;
2264         }
2265     }
2266 
2267     if (videoLoggingEnabled())
2268     {
2269         uint32_t slotInUseMask   = m_dpb.getSlotInUseMask();
2270         uint32_t slotsInUseCount = 0;
2271         std::cout << "\tAllocated DPB slot " << (int32_t)currPicDpbSlot << " for "
2272                   << (pd->ref_pic_flag ? "REFERENCE" : "NON-REFERENCE") << " picIdx: " << (int32_t)currPicIdx
2273                   << std::endl;
2274         std::cout << "\tDPB frames map for picIdx: " << (int32_t)currPicIdx << std::endl << "\tSlot Index:\t\t";
2275         for (uint32_t slot = 0; slot < m_dpb.getMaxSize(); slot++)
2276         {
2277             if (slotInUseMask & (1 << slot))
2278             {
2279                 std::cout << slot << ",\t";
2280                 slotsInUseCount++;
2281             }
2282             else
2283             {
2284                 std::cout << 'X' << ",\t";
2285             }
2286         }
2287         std::cout << std::endl << "\tPict Index:\t\t";
2288         for (uint32_t slot = 0; slot < m_dpb.getMaxSize(); slot++)
2289         {
2290             if (slotInUseMask & (1 << slot))
2291             {
2292                 if (m_dpb[slot].getPictureResource())
2293                 {
2294                     std::cout << m_dpb[slot].getPictureResource()->m_picIdx << ",\t";
2295                 }
2296                 else
2297                 {
2298                     std::cout << "non existent"
2299                               << ",\t";
2300                 }
2301             }
2302             else
2303             {
2304                 std::cout << 'X' << ",\t";
2305             }
2306         }
2307         std::cout << "\n\tTotal slots in use for picIdx: " << (int32_t)currPicIdx << " : " << slotsInUseCount
2308                   << " out of " << m_dpb.getMaxSize() << std::endl;
2309         std::cout << " <<<= ********************* picIdx: " << (int32_t)GetPicIdx(pd->pCurrPic)
2310                   << " *************************" << std::endl
2311                   << std::endl;
2312         std::cout << std::flush;
2313     }
2314     return refDpbUsedAndValidMask ? numUsedRef : 0;
2315 }
2316 
FillDpbH265State(const VkParserPictureData * pd,const VkParserHevcPictureData * pin,nvVideoDecodeH265DpbSlotInfo * pDpbSlotInfo,StdVideoDecodeH265PictureInfo * pStdPictureInfo,uint32_t,VkVideoReferenceSlotInfoKHR * pReferenceSlots,int8_t * pGopReferenceImagesIndexes,int32_t * pCurrAllocatedSlotIndex)2317 uint32_t VideoBaseDecoder::FillDpbH265State(const VkParserPictureData *pd, const VkParserHevcPictureData *pin,
2318                                             nvVideoDecodeH265DpbSlotInfo *pDpbSlotInfo,
2319                                             StdVideoDecodeH265PictureInfo *pStdPictureInfo, uint32_t /*maxRefPictures*/,
2320                                             VkVideoReferenceSlotInfoKHR *pReferenceSlots,
2321                                             int8_t *pGopReferenceImagesIndexes, int32_t *pCurrAllocatedSlotIndex)
2322 {
2323     // #### Update m_dpb based on dpb parameters ####
2324     // Create unordered DPB and generate a bitmask of all render targets present
2325     // in DPB
2326     dpbH264Entry refOnlyDpbIn[H26X_MAX_DPB_SLOTS];
2327     DE_ASSERT(m_maxNumDpbSlots <= H26X_MAX_DPB_SLOTS);
2328     memset(&refOnlyDpbIn, 0, m_maxNumDpbSlots * sizeof(refOnlyDpbIn[0]));
2329     uint32_t refDpbUsedAndValidMask = 0;
2330     uint32_t numUsedRef             = 0;
2331     if (videoLoggingEnabled())
2332         std::cout << "Ref frames data: " << std::endl;
2333     for (int32_t inIdx = 0; inIdx < H26X_MAX_DPB_SLOTS; inIdx++)
2334     {
2335         // used_for_reference: 0 = unused, 1 = top_field, 2 = bottom_field, 3 =
2336         // both_fields
2337         int8_t picIdx = GetPicIdx(pin->RefPics[inIdx]);
2338         if (picIdx >= 0)
2339         {
2340             DE_ASSERT(numUsedRef < H26X_MAX_DPB_SLOTS);
2341             refOnlyDpbIn[numUsedRef].setReference((pin->IsLongTerm[inIdx] == 1), pin->PicOrderCntVal[inIdx],
2342                                                   GetPic(pin->RefPics[inIdx]));
2343             if (picIdx >= 0)
2344             {
2345                 refDpbUsedAndValidMask |= (1 << picIdx);
2346             }
2347             refOnlyDpbIn[numUsedRef].originalDpbIndex = inIdx;
2348             numUsedRef++;
2349         }
2350         // Invalidate all slots.
2351         pReferenceSlots[inIdx].slotIndex  = -1;
2352         pGopReferenceImagesIndexes[inIdx] = -1;
2353     }
2354 
2355     if (videoLoggingEnabled())
2356         std::cout << "Total Ref frames: " << numUsedRef << std::endl;
2357 
2358     DE_ASSERT(numUsedRef <= m_maxNumDpbSlots);
2359     DE_ASSERT(numUsedRef <= H26X_MAX_DPB_SLOTS);
2360 
2361     // Take into account the reference picture now.
2362     int8_t currPicIdx = GetPicIdx(pd->pCurrPic);
2363     DE_ASSERT(currPicIdx >= 0);
2364     if (currPicIdx >= 0)
2365     {
2366         refDpbUsedAndValidMask |= (1 << currPicIdx);
2367     }
2368 
2369     // Map all frames not present in DPB as non-reference, and generate a mask of
2370     // all used DPB entries
2371     /* uint32_t destUsedDpbMask = */ ResetPicDpbSlots(refDpbUsedAndValidMask);
2372 
2373     // Now, map DPB render target indices to internal frame buffer index,
2374     // assign each reference a unique DPB entry, and create the ordered DPB
2375     // This is an undocumented MV restriction: the position in the DPB is stored
2376     // along with the co-located data, so once a reference frame is assigned a DPB
2377     // entry, it can no longer change.
2378 
2379     int8_t frmListToDpb[H26X_MAX_DPB_SLOTS];
2380     // TODO change to -1 for invalid indexes.
2381     memset(&frmListToDpb, 0, sizeof(frmListToDpb));
2382     // Find or allocate slots for existing dpb items.
2383     for (int32_t dpbIdx = 0; (uint32_t)dpbIdx < numUsedRef; dpbIdx++)
2384     {
2385         if (!refOnlyDpbIn[dpbIdx].is_non_existing)
2386         {
2387             vkPicBuffBase *picBuff = refOnlyDpbIn[dpbIdx].m_picBuff;
2388             int32_t picIdx         = GetPicIdx(picBuff); // should always be valid at this point
2389             DE_ASSERT(picIdx >= 0);
2390             // We have up to 17 internal frame buffers, but only H26X_MAX_DPB_SLOTS
2391             // dpb entries, so we need to re-map the index from the
2392             // [0..H26X_MAX_DPB_SLOTS] range to [0..15]
2393             int8_t dpbSlot = GetPicDpbSlot(picIdx);
2394             if (dpbSlot < 0)
2395             {
2396                 dpbSlot = m_dpb.AllocateSlot();
2397                 DE_ASSERT(dpbSlot >= 0);
2398                 SetPicDpbSlot(picIdx, dpbSlot);
2399                 m_dpb[dpbSlot].setPictureResource(picBuff, m_nCurrentPictureID);
2400             }
2401             m_dpb[dpbSlot].MarkInUse(m_nCurrentPictureID);
2402             DE_ASSERT(dpbSlot >= 0);
2403 
2404             if (dpbSlot >= 0)
2405             {
2406                 refOnlyDpbIn[dpbIdx].dpbSlot = dpbSlot;
2407                 uint32_t originalDpbIndex    = refOnlyDpbIn[dpbIdx].originalDpbIndex;
2408                 DE_ASSERT(originalDpbIndex < H26X_MAX_DPB_SLOTS);
2409                 frmListToDpb[originalDpbIndex] = dpbSlot;
2410             }
2411             else
2412             {
2413                 // This should never happen
2414                 printf("DPB mapping logic broken!\n");
2415                 DE_ASSERT(0);
2416             }
2417         }
2418     }
2419 
2420     // Find or allocate slots for non existing dpb items and populate the slots.
2421     uint32_t dpbInUseMask          = m_dpb.getSlotInUseMask();
2422     int8_t firstNonExistingDpbSlot = 0;
2423     for (uint32_t dpbIdx = 0; dpbIdx < numUsedRef; dpbIdx++)
2424     {
2425         int8_t dpbSlot = -1;
2426         if (refOnlyDpbIn[dpbIdx].is_non_existing)
2427         {
2428             // There shouldn't be  not_existing in h.265
2429             DE_ASSERT(0);
2430             DE_ASSERT(refOnlyDpbIn[dpbIdx].m_picBuff == NULL);
2431             while (((uint32_t)firstNonExistingDpbSlot < m_maxNumDpbSlots) && (dpbSlot == -1))
2432             {
2433                 if (!(dpbInUseMask & (1 << firstNonExistingDpbSlot)))
2434                 {
2435                     dpbSlot = firstNonExistingDpbSlot;
2436                 }
2437                 firstNonExistingDpbSlot++;
2438             }
2439             DE_ASSERT((dpbSlot >= 0) && ((uint32_t)dpbSlot < m_maxNumDpbSlots));
2440         }
2441         else
2442         {
2443             DE_ASSERT(refOnlyDpbIn[dpbIdx].m_picBuff != NULL);
2444             dpbSlot = refOnlyDpbIn[dpbIdx].dpbSlot;
2445         }
2446         DE_ASSERT((dpbSlot >= 0) && (dpbSlot < H26X_MAX_DPB_SLOTS));
2447         refOnlyDpbIn[dpbIdx].setH265PictureData(pDpbSlotInfo, pReferenceSlots, dpbIdx, dpbSlot);
2448         pGopReferenceImagesIndexes[dpbIdx] = GetPicIdx(refOnlyDpbIn[dpbIdx].m_picBuff);
2449     }
2450 
2451     if (videoLoggingEnabled())
2452     {
2453         std::cout << "frmListToDpb:" << std::endl;
2454         for (int8_t dpbResIdx = 0; dpbResIdx < H26X_MAX_DPB_SLOTS; dpbResIdx++)
2455         {
2456             std::cout << "\tfrmListToDpb[" << (int32_t)dpbResIdx << "] is " << (int32_t)frmListToDpb[dpbResIdx]
2457                       << std::endl;
2458         }
2459     }
2460 
2461     int32_t numPocStCurrBefore = 0;
2462     const size_t maxNumPocStCurrBefore =
2463         sizeof(pStdPictureInfo->RefPicSetStCurrBefore) / sizeof(pStdPictureInfo->RefPicSetStCurrBefore[0]);
2464     DE_ASSERT((size_t)pin->NumPocStCurrBefore <= maxNumPocStCurrBefore);
2465     if ((size_t)pin->NumPocStCurrBefore > maxNumPocStCurrBefore)
2466     {
2467         tcu::print(
2468             "\nERROR: FillDpbH265State() pin->NumPocStCurrBefore(%d) must be smaller than maxNumPocStCurrBefore(%zd)\n",
2469             pin->NumPocStCurrBefore, maxNumPocStCurrBefore);
2470     }
2471     for (int32_t i = 0; i < pin->NumPocStCurrBefore; i++)
2472     {
2473         uint8_t idx = (uint8_t)pin->RefPicSetStCurrBefore[i];
2474         if (idx < H26X_MAX_DPB_SLOTS)
2475         {
2476             if (videoLoggingEnabled())
2477                 std::cout << "\trefPicSetStCurrBefore[" << i << "] is " << (int32_t)idx << " -> "
2478                           << (int32_t)frmListToDpb[idx] << std::endl;
2479             pStdPictureInfo->RefPicSetStCurrBefore[numPocStCurrBefore++] = frmListToDpb[idx] & 0xf;
2480         }
2481     }
2482     while (numPocStCurrBefore < 8)
2483     {
2484         pStdPictureInfo->RefPicSetStCurrBefore[numPocStCurrBefore++] = 0xff;
2485     }
2486 
2487     int32_t numPocStCurrAfter = 0;
2488     const size_t maxNumPocStCurrAfter =
2489         sizeof(pStdPictureInfo->RefPicSetStCurrAfter) / sizeof(pStdPictureInfo->RefPicSetStCurrAfter[0]);
2490     DE_ASSERT((size_t)pin->NumPocStCurrAfter <= maxNumPocStCurrAfter);
2491     if ((size_t)pin->NumPocStCurrAfter > maxNumPocStCurrAfter)
2492     {
2493         fprintf(
2494             stderr,
2495             "\nERROR: FillDpbH265State() pin->NumPocStCurrAfter(%d) must be smaller than maxNumPocStCurrAfter(%zd)\n",
2496             pin->NumPocStCurrAfter, maxNumPocStCurrAfter);
2497     }
2498     for (int32_t i = 0; i < pin->NumPocStCurrAfter; i++)
2499     {
2500         uint8_t idx = (uint8_t)pin->RefPicSetStCurrAfter[i];
2501         if (idx < H26X_MAX_DPB_SLOTS)
2502         {
2503             if (videoLoggingEnabled())
2504                 std::cout << "\trefPicSetStCurrAfter[" << i << "] is " << (int32_t)idx << " -> "
2505                           << (int32_t)frmListToDpb[idx] << std::endl;
2506             pStdPictureInfo->RefPicSetStCurrAfter[numPocStCurrAfter++] = frmListToDpb[idx] & 0xf;
2507         }
2508     }
2509     while (numPocStCurrAfter < 8)
2510     {
2511         pStdPictureInfo->RefPicSetStCurrAfter[numPocStCurrAfter++] = 0xff;
2512     }
2513 
2514     int32_t numPocLtCurr = 0;
2515     const size_t maxNumPocLtCurr =
2516         sizeof(pStdPictureInfo->RefPicSetLtCurr) / sizeof(pStdPictureInfo->RefPicSetLtCurr[0]);
2517     DE_ASSERT((size_t)pin->NumPocLtCurr <= maxNumPocLtCurr);
2518     if ((size_t)pin->NumPocLtCurr > maxNumPocLtCurr)
2519     {
2520         fprintf(stderr, "\nERROR: FillDpbH265State() pin->NumPocLtCurr(%d) must be smaller than maxNumPocLtCurr(%zd)\n",
2521                 pin->NumPocLtCurr, maxNumPocLtCurr);
2522     }
2523     for (int32_t i = 0; i < pin->NumPocLtCurr; i++)
2524     {
2525         uint8_t idx = (uint8_t)pin->RefPicSetLtCurr[i];
2526         if (idx < H26X_MAX_DPB_SLOTS)
2527         {
2528             if (videoLoggingEnabled())
2529                 std::cout << "\trefPicSetLtCurr[" << i << "] is " << (int32_t)idx << " -> "
2530                           << (int32_t)frmListToDpb[idx] << std::endl;
2531             pStdPictureInfo->RefPicSetLtCurr[numPocLtCurr++] = frmListToDpb[idx] & 0xf;
2532         }
2533     }
2534     while (numPocLtCurr < 8)
2535     {
2536         pStdPictureInfo->RefPicSetLtCurr[numPocLtCurr++] = 0xff;
2537     }
2538 
2539     for (int32_t i = 0; i < 8; i++)
2540     {
2541         if (videoLoggingEnabled())
2542             std::cout << "\tlist indx " << i << ": "
2543                       << " refPicSetStCurrBefore: " << (int32_t)pStdPictureInfo->RefPicSetStCurrBefore[i]
2544                       << " refPicSetStCurrAfter: " << (int32_t)pStdPictureInfo->RefPicSetStCurrAfter[i]
2545                       << " refPicSetLtCurr: " << (int32_t)pStdPictureInfo->RefPicSetLtCurr[i] << std::endl;
2546     }
2547 
2548     int8_t dpbSlot = AllocateDpbSlotForCurrentH265(GetPic(pd->pCurrPic), true /* isReference */, pd->current_dpb_id);
2549     *pCurrAllocatedSlotIndex = dpbSlot;
2550     DE_ASSERT(!(dpbSlot < 0));
2551     if (dpbSlot >= 0)
2552     {
2553         // TODO: The NVIDIA DPB management is quite broken, and always wants to allocate DPBs even for non-reference frames.
2554         //DE_ASSERT(pd->ref_pic_flag);
2555     }
2556 
2557     return numUsedRef;
2558 }
2559 
AllocateDpbSlotForCurrentH264(vkPicBuffBase * pPic,StdVideoDecodeH264PictureInfoFlags currPicFlags,int8_t)2560 int8_t VideoBaseDecoder::AllocateDpbSlotForCurrentH264(vkPicBuffBase *pPic,
2561                                                        StdVideoDecodeH264PictureInfoFlags currPicFlags,
2562                                                        int8_t /*presetDpbSlot*/)
2563 {
2564     // Now, map the current render target
2565     int8_t dpbSlot    = -1;
2566     int8_t currPicIdx = GetPicIdx(pPic);
2567     DE_ASSERT(currPicIdx >= 0);
2568     SetFieldPicFlag(currPicIdx, currPicFlags.field_pic_flag);
2569     // In Vulkan we always allocate reference slot for the current picture.
2570     if (true /* currPicFlags.is_reference */)
2571     {
2572         dpbSlot = GetPicDpbSlot(currPicIdx);
2573         if (dpbSlot < 0)
2574         {
2575             dpbSlot = m_dpb.AllocateSlot();
2576             DE_ASSERT(dpbSlot >= 0);
2577             SetPicDpbSlot(currPicIdx, dpbSlot);
2578             m_dpb[dpbSlot].setPictureResource(pPic, m_nCurrentPictureID);
2579         }
2580         DE_ASSERT(dpbSlot >= 0);
2581     }
2582     return dpbSlot;
2583 }
2584 
AllocateDpbSlotForCurrentH265(vkPicBuffBase * pPic,bool isReference,int8_t)2585 int8_t VideoBaseDecoder::AllocateDpbSlotForCurrentH265(vkPicBuffBase *pPic, bool isReference, int8_t /*presetDpbSlot*/)
2586 {
2587     // Now, map the current render target
2588     int8_t dpbSlot    = -1;
2589     int8_t currPicIdx = GetPicIdx(pPic);
2590     DE_ASSERT(currPicIdx >= 0);
2591     DE_ASSERT(isReference);
2592     if (isReference)
2593     {
2594         dpbSlot = GetPicDpbSlot(currPicIdx);
2595         if (dpbSlot < 0)
2596         {
2597             dpbSlot = m_dpb.AllocateSlot();
2598             DE_ASSERT(dpbSlot >= 0);
2599             SetPicDpbSlot(currPicIdx, dpbSlot);
2600             m_dpb[dpbSlot].setPictureResource(pPic, m_nCurrentPictureID);
2601         }
2602         DE_ASSERT(dpbSlot >= 0);
2603     }
2604     return dpbSlot;
2605 }
2606 
getRecommendedFormat(const vector<VkFormat> & formats,VkFormat recommendedFormat)2607 VkFormat getRecommendedFormat(const vector<VkFormat> &formats, VkFormat recommendedFormat)
2608 {
2609     if (formats.empty())
2610         return VK_FORMAT_UNDEFINED;
2611     else if (recommendedFormat != VK_FORMAT_UNDEFINED &&
2612              std::find(formats.begin(), formats.end(), recommendedFormat) != formats.end())
2613         return recommendedFormat;
2614     else
2615         return formats[0];
2616 }
2617 
Create(DeviceContext & vkDevCtx,uint32_t videoQueueFamily,VkVideoCoreProfile * pVideoProfile,VkFormat pictureFormat,const VkExtent2D & maxCodedExtent,VkFormat referencePicturesFormat,uint32_t maxDpbSlots,uint32_t maxActiveReferencePictures,bool useInlineVideoQueries,VkSharedBaseObj<VulkanVideoSession> & videoSession)2618 VkResult VulkanVideoSession::Create(DeviceContext &vkDevCtx, uint32_t videoQueueFamily,
2619                                     VkVideoCoreProfile *pVideoProfile, VkFormat pictureFormat,
2620                                     const VkExtent2D &maxCodedExtent, VkFormat referencePicturesFormat,
2621                                     uint32_t maxDpbSlots, uint32_t maxActiveReferencePictures,
2622                                     bool useInlineVideoQueries, VkSharedBaseObj<VulkanVideoSession> &videoSession)
2623 {
2624     auto &vk    = vkDevCtx.getDeviceDriver();
2625     auto device = vkDevCtx.device;
2626 
2627     VulkanVideoSession *pNewVideoSession = new VulkanVideoSession(vkDevCtx, pVideoProfile);
2628 
2629     static const VkExtensionProperties h264DecodeStdExtensionVersion = {
2630         VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_EXTENSION_NAME, VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_SPEC_VERSION};
2631     static const VkExtensionProperties h265DecodeStdExtensionVersion = {
2632         VK_STD_VULKAN_VIDEO_CODEC_H265_DECODE_EXTENSION_NAME, VK_STD_VULKAN_VIDEO_CODEC_H265_DECODE_SPEC_VERSION};
2633     static const VkExtensionProperties av1DecodeStdExtensionVersion = {
2634         VK_STD_VULKAN_VIDEO_CODEC_AV1_DECODE_EXTENSION_NAME, VK_STD_VULKAN_VIDEO_CODEC_AV1_DECODE_SPEC_VERSION};
2635     static const VkExtensionProperties h264EncodeStdExtensionVersion = {
2636         VK_STD_VULKAN_VIDEO_CODEC_H264_ENCODE_EXTENSION_NAME, VK_STD_VULKAN_VIDEO_CODEC_H264_ENCODE_SPEC_VERSION};
2637     static const VkExtensionProperties h265EncodeStdExtensionVersion = {
2638         VK_STD_VULKAN_VIDEO_CODEC_H265_ENCODE_EXTENSION_NAME, VK_STD_VULKAN_VIDEO_CODEC_H265_ENCODE_SPEC_VERSION};
2639 
2640     VkVideoSessionCreateInfoKHR &createInfo = pNewVideoSession->m_createInfo;
2641     createInfo.flags                      = useInlineVideoQueries ? VK_VIDEO_SESSION_CREATE_INLINE_QUERIES_BIT_KHR : 0;
2642     createInfo.pVideoProfile              = pVideoProfile->GetProfile();
2643     createInfo.queueFamilyIndex           = videoQueueFamily;
2644     createInfo.pictureFormat              = pictureFormat;
2645     createInfo.maxCodedExtent             = maxCodedExtent;
2646     createInfo.maxDpbSlots                = maxDpbSlots;
2647     createInfo.maxActiveReferencePictures = maxActiveReferencePictures;
2648     createInfo.referencePictureFormat     = referencePicturesFormat;
2649 
2650     switch ((int32_t)pVideoProfile->GetCodecType())
2651     {
2652     case VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR:
2653         createInfo.pStdHeaderVersion = &h264DecodeStdExtensionVersion;
2654         break;
2655     case VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR:
2656         createInfo.pStdHeaderVersion = &h265DecodeStdExtensionVersion;
2657         break;
2658     case VK_VIDEO_CODEC_OPERATION_DECODE_AV1_BIT_KHR:
2659         createInfo.pStdHeaderVersion = &av1DecodeStdExtensionVersion;
2660         break;
2661     case VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_KHR:
2662         createInfo.pStdHeaderVersion = &h264EncodeStdExtensionVersion;
2663         break;
2664     case VK_VIDEO_CODEC_OPERATION_ENCODE_H265_BIT_KHR:
2665         createInfo.pStdHeaderVersion = &h265EncodeStdExtensionVersion;
2666         break;
2667     default:
2668         DE_ASSERT(0);
2669     }
2670     VkResult result = vk.createVideoSessionKHR(device, &createInfo, NULL, &pNewVideoSession->m_videoSession);
2671     if (result != VK_SUCCESS)
2672     {
2673         return result;
2674     }
2675 
2676     uint32_t videoSessionMemoryRequirementsCount = 0;
2677     VkVideoSessionMemoryRequirementsKHR decodeSessionMemoryRequirements[MAX_BOUND_MEMORY];
2678     // Get the count first
2679     result = vk.getVideoSessionMemoryRequirementsKHR(device, pNewVideoSession->m_videoSession,
2680                                                      &videoSessionMemoryRequirementsCount, NULL);
2681     DE_ASSERT(result == VK_SUCCESS);
2682     DE_ASSERT(videoSessionMemoryRequirementsCount <= MAX_BOUND_MEMORY);
2683 
2684     memset(decodeSessionMemoryRequirements, 0x00, sizeof(decodeSessionMemoryRequirements));
2685     for (uint32_t i = 0; i < videoSessionMemoryRequirementsCount; i++)
2686     {
2687         decodeSessionMemoryRequirements[i].sType = VK_STRUCTURE_TYPE_VIDEO_SESSION_MEMORY_REQUIREMENTS_KHR;
2688     }
2689 
2690     result =
2691         vk.getVideoSessionMemoryRequirementsKHR(device, pNewVideoSession->m_videoSession,
2692                                                 &videoSessionMemoryRequirementsCount, decodeSessionMemoryRequirements);
2693     if (result != VK_SUCCESS)
2694     {
2695         return result;
2696     }
2697 
2698     uint32_t decodeSessionBindMemoryCount = videoSessionMemoryRequirementsCount;
2699     VkBindVideoSessionMemoryInfoKHR decodeSessionBindMemory[MAX_BOUND_MEMORY];
2700 
2701     for (uint32_t memIdx = 0; memIdx < decodeSessionBindMemoryCount; memIdx++)
2702     {
2703 
2704         uint32_t memoryTypeIndex = 0;
2705         uint32_t memoryTypeBits  = decodeSessionMemoryRequirements[memIdx].memoryRequirements.memoryTypeBits;
2706         if (memoryTypeBits == 0)
2707         {
2708             return VK_ERROR_INITIALIZATION_FAILED;
2709         }
2710 
2711         // Find an available memory type that satisfies the requested properties.
2712         for (; !(memoryTypeBits & 1); memoryTypeIndex++)
2713         {
2714             memoryTypeBits >>= 1;
2715         }
2716 
2717         VkMemoryAllocateInfo memInfo = {
2718             VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,                          // sType
2719             NULL,                                                            // pNext
2720             decodeSessionMemoryRequirements[memIdx].memoryRequirements.size, // allocationSize
2721             memoryTypeIndex,                                                 // memoryTypeIndex
2722         };
2723 
2724         result = vk.allocateMemory(device, &memInfo, 0, &pNewVideoSession->m_memoryBound[memIdx]);
2725         if (result != VK_SUCCESS)
2726         {
2727             return result;
2728         }
2729 
2730         DE_ASSERT(result == VK_SUCCESS);
2731         decodeSessionBindMemory[memIdx].pNext  = NULL;
2732         decodeSessionBindMemory[memIdx].sType  = VK_STRUCTURE_TYPE_BIND_VIDEO_SESSION_MEMORY_INFO_KHR;
2733         decodeSessionBindMemory[memIdx].memory = pNewVideoSession->m_memoryBound[memIdx];
2734 
2735         decodeSessionBindMemory[memIdx].memoryBindIndex = decodeSessionMemoryRequirements[memIdx].memoryBindIndex;
2736         decodeSessionBindMemory[memIdx].memoryOffset    = 0;
2737         decodeSessionBindMemory[memIdx].memorySize = decodeSessionMemoryRequirements[memIdx].memoryRequirements.size;
2738     }
2739 
2740     result = vk.bindVideoSessionMemoryKHR(device, pNewVideoSession->m_videoSession, decodeSessionBindMemoryCount,
2741                                           decodeSessionBindMemory);
2742     DE_ASSERT(result == VK_SUCCESS);
2743 
2744     videoSession = pNewVideoSession;
2745 
2746     // Make sure we do not use dangling (on the stack) pointers
2747     createInfo.pNext = nullptr;
2748 
2749     return result;
2750 }
2751 
Create(DeviceContext & vkDevCtx,const VkImageCreateInfo * pImageCreateInfo,VkSharedBaseObj<VkImageResource> & imageResource)2752 VkResult VkImageResource::Create(DeviceContext &vkDevCtx, const VkImageCreateInfo *pImageCreateInfo,
2753                                  VkSharedBaseObj<VkImageResource> &imageResource)
2754 {
2755     imageResource = new VkImageResource(vkDevCtx, pImageCreateInfo);
2756 
2757     return VK_SUCCESS;
2758 }
2759 
Create(DeviceContext & vkDevCtx,VkSharedBaseObj<VkImageResource> & imageResource,const VkImageCreateInfo * pImageCreateInfo,VkImageSubresourceRange & imageSubresourceRange,VkSharedBaseObj<VkImageResourceView> & imageResourceView)2760 VkResult VkImageResourceView::Create(DeviceContext &vkDevCtx, VkSharedBaseObj<VkImageResource> &imageResource,
2761                                      const VkImageCreateInfo *pImageCreateInfo,
2762                                      VkImageSubresourceRange &imageSubresourceRange,
2763                                      VkSharedBaseObj<VkImageResourceView> &imageResourceView)
2764 {
2765     auto &vk        = vkDevCtx.getDeviceDriver();
2766     VkDevice device = vkDevCtx.device;
2767     VkImageView imageView;
2768     VkImageViewCreateInfo viewInfo = VkImageViewCreateInfo();
2769     viewInfo.sType                 = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
2770     viewInfo.pNext                 = nullptr;
2771     viewInfo.image                 = imageResource->GetImage();
2772     viewInfo.viewType   = pImageCreateInfo->arrayLayers > 1 ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D;
2773     viewInfo.format     = imageResource->GetImageCreateInfo().format;
2774     viewInfo.components = {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
2775                            VK_COMPONENT_SWIZZLE_IDENTITY};
2776     viewInfo.subresourceRange = imageSubresourceRange;
2777     viewInfo.flags            = 0;
2778     VkResult result           = vk.createImageView(device, &viewInfo, nullptr, &imageView);
2779     if (result != VK_SUCCESS)
2780     {
2781         return result;
2782     }
2783 
2784     imageResourceView = new VkImageResourceView(vkDevCtx, imageResource, imageView, imageSubresourceRange);
2785 
2786     return result;
2787 }
2788 
~VkImageResourceView()2789 VkImageResourceView::~VkImageResourceView()
2790 {
2791     auto &vk    = m_vkDevCtx.getDeviceDriver();
2792     auto device = m_vkDevCtx.device;
2793 
2794     if (m_imageView != VK_NULL_HANDLE)
2795     {
2796         vk.destroyImageView(device, m_imageView, nullptr);
2797         m_imageView = VK_NULL_HANDLE;
2798     }
2799 
2800     m_imageResource = nullptr;
2801 }
2802 
2803 const char *VkParserVideoPictureParameters::m_refClassId = "VkParserVideoPictureParameters";
2804 int32_t VkParserVideoPictureParameters::m_currentId      = 0;
2805 
PopulateH264UpdateFields(const StdVideoPictureParametersSet * pStdPictureParametersSet,VkVideoDecodeH264SessionParametersAddInfoKHR & h264SessionParametersAddInfo)2806 int32_t VkParserVideoPictureParameters::PopulateH264UpdateFields(
2807     const StdVideoPictureParametersSet *pStdPictureParametersSet,
2808     VkVideoDecodeH264SessionParametersAddInfoKHR &h264SessionParametersAddInfo)
2809 {
2810     int32_t currentId = -1;
2811     if (pStdPictureParametersSet == nullptr)
2812     {
2813         return currentId;
2814     }
2815 
2816     DE_ASSERT((pStdPictureParametersSet->GetStdType() == StdVideoPictureParametersSet::TYPE_H264_SPS) ||
2817               (pStdPictureParametersSet->GetStdType() == StdVideoPictureParametersSet::TYPE_H264_PPS));
2818 
2819     DE_ASSERT(h264SessionParametersAddInfo.sType ==
2820               VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_ADD_INFO_KHR);
2821 
2822     if (pStdPictureParametersSet->GetStdType() == StdVideoPictureParametersSet::TYPE_H264_SPS)
2823     {
2824         h264SessionParametersAddInfo.stdSPSCount = 1;
2825         h264SessionParametersAddInfo.pStdSPSs    = pStdPictureParametersSet->GetStdH264Sps();
2826         bool isSps                               = false;
2827         currentId                                = pStdPictureParametersSet->GetSpsId(isSps);
2828         DE_ASSERT(isSps);
2829     }
2830     else if (pStdPictureParametersSet->GetStdType() == StdVideoPictureParametersSet::TYPE_H264_PPS)
2831     {
2832         h264SessionParametersAddInfo.stdPPSCount = 1;
2833         h264SessionParametersAddInfo.pStdPPSs    = pStdPictureParametersSet->GetStdH264Pps();
2834         bool isPps                               = false;
2835         currentId                                = pStdPictureParametersSet->GetPpsId(isPps);
2836         DE_ASSERT(isPps);
2837     }
2838     else
2839     {
2840         DE_ASSERT(!"Incorrect h.264 type");
2841     }
2842 
2843     return currentId;
2844 }
2845 
PopulateH265UpdateFields(const StdVideoPictureParametersSet * pStdPictureParametersSet,VkVideoDecodeH265SessionParametersAddInfoKHR & h265SessionParametersAddInfo)2846 int32_t VkParserVideoPictureParameters::PopulateH265UpdateFields(
2847     const StdVideoPictureParametersSet *pStdPictureParametersSet,
2848     VkVideoDecodeH265SessionParametersAddInfoKHR &h265SessionParametersAddInfo)
2849 {
2850     int32_t currentId = -1;
2851     if (pStdPictureParametersSet == nullptr)
2852     {
2853         return currentId;
2854     }
2855 
2856     DE_ASSERT((pStdPictureParametersSet->GetStdType() == StdVideoPictureParametersSet::TYPE_H265_VPS) ||
2857               (pStdPictureParametersSet->GetStdType() == StdVideoPictureParametersSet::TYPE_H265_SPS) ||
2858               (pStdPictureParametersSet->GetStdType() == StdVideoPictureParametersSet::TYPE_H265_PPS));
2859 
2860     DE_ASSERT(h265SessionParametersAddInfo.sType ==
2861               VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_ADD_INFO_KHR);
2862 
2863     if (pStdPictureParametersSet->GetStdType() == StdVideoPictureParametersSet::TYPE_H265_VPS)
2864     {
2865         h265SessionParametersAddInfo.stdVPSCount = 1;
2866         h265SessionParametersAddInfo.pStdVPSs    = pStdPictureParametersSet->GetStdH265Vps();
2867         bool isVps                               = false;
2868         currentId                                = pStdPictureParametersSet->GetVpsId(isVps);
2869         DE_ASSERT(isVps);
2870     }
2871     else if (pStdPictureParametersSet->GetStdType() == StdVideoPictureParametersSet::TYPE_H265_SPS)
2872     {
2873         h265SessionParametersAddInfo.stdSPSCount = 1;
2874         h265SessionParametersAddInfo.pStdSPSs    = pStdPictureParametersSet->GetStdH265Sps();
2875         bool isSps                               = false;
2876         currentId                                = pStdPictureParametersSet->GetSpsId(isSps);
2877         DE_ASSERT(isSps);
2878     }
2879     else if (pStdPictureParametersSet->GetStdType() == StdVideoPictureParametersSet::TYPE_H265_PPS)
2880     {
2881         h265SessionParametersAddInfo.stdPPSCount = 1;
2882         h265SessionParametersAddInfo.pStdPPSs    = pStdPictureParametersSet->GetStdH265Pps();
2883         bool isPps                               = false;
2884         currentId                                = pStdPictureParametersSet->GetPpsId(isPps);
2885         DE_ASSERT(isPps);
2886     }
2887     else
2888     {
2889         DE_ASSERT(!"Incorrect h.265 type");
2890     }
2891 
2892     return currentId;
2893 }
2894 
Create(DeviceContext & deviceContext,VkSharedBaseObj<VkParserVideoPictureParameters> & templatePictureParameters,VkSharedBaseObj<VkParserVideoPictureParameters> & videoPictureParameters)2895 VkResult VkParserVideoPictureParameters::Create(
2896     DeviceContext &deviceContext, VkSharedBaseObj<VkParserVideoPictureParameters> &templatePictureParameters,
2897     VkSharedBaseObj<VkParserVideoPictureParameters> &videoPictureParameters)
2898 {
2899     VkSharedBaseObj<VkParserVideoPictureParameters> newVideoPictureParameters(
2900         new VkParserVideoPictureParameters(deviceContext, templatePictureParameters));
2901     if (!newVideoPictureParameters)
2902     {
2903         return VK_ERROR_OUT_OF_HOST_MEMORY;
2904     }
2905 
2906     videoPictureParameters = newVideoPictureParameters;
2907     return VK_SUCCESS;
2908 }
2909 
CreateParametersObject(VkSharedBaseObj<VulkanVideoSession> & videoSession,const StdVideoPictureParametersSet * pStdVideoPictureParametersSet,VkParserVideoPictureParameters * pTemplatePictureParameters)2910 VkResult VkParserVideoPictureParameters::CreateParametersObject(
2911     VkSharedBaseObj<VulkanVideoSession> &videoSession,
2912     const StdVideoPictureParametersSet *pStdVideoPictureParametersSet,
2913     VkParserVideoPictureParameters *pTemplatePictureParameters)
2914 {
2915     int32_t currentId = -1;
2916 
2917     VkVideoSessionParametersCreateInfoKHR createInfo{};
2918     createInfo.sType = VK_STRUCTURE_TYPE_VIDEO_SESSION_PARAMETERS_CREATE_INFO_KHR;
2919 
2920     VkVideoDecodeH264SessionParametersCreateInfoKHR h264SessionParametersCreateInfo{};
2921     h264SessionParametersCreateInfo.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_CREATE_INFO_KHR;
2922     VkVideoDecodeH264SessionParametersAddInfoKHR h264SessionParametersAddInfo{};
2923     h264SessionParametersAddInfo.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_ADD_INFO_KHR;
2924 
2925     VkVideoDecodeH265SessionParametersCreateInfoKHR h265SessionParametersCreateInfo{};
2926     h265SessionParametersCreateInfo.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_CREATE_INFO_KHR;
2927     VkVideoDecodeH265SessionParametersAddInfoKHR h265SessionParametersAddInfo{};
2928     h265SessionParametersAddInfo.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_ADD_INFO_KHR;
2929 
2930     VkVideoDecodeAV1SessionParametersCreateInfoKHR av1SessionParametersCreateInfo{};
2931     av1SessionParametersCreateInfo.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_AV1_SESSION_PARAMETERS_CREATE_INFO_KHR;
2932 
2933     createInfo.videoSessionParametersTemplate =
2934         pTemplatePictureParameters ? VkVideoSessionParametersKHR(*pTemplatePictureParameters) : VK_NULL_HANDLE;
2935 
2936     StdVideoPictureParametersSet::StdType updateType = pStdVideoPictureParametersSet->GetStdType();
2937     switch (updateType)
2938     {
2939     case StdVideoPictureParametersSet::TYPE_H264_SPS:
2940     case StdVideoPictureParametersSet::TYPE_H264_PPS:
2941     {
2942         createInfo.pNext                                   = &h264SessionParametersCreateInfo;
2943         h264SessionParametersCreateInfo.maxStdSPSCount     = MAX_SPS_IDS;
2944         h264SessionParametersCreateInfo.maxStdPPSCount     = MAX_PPS_IDS;
2945         h264SessionParametersCreateInfo.pParametersAddInfo = &h264SessionParametersAddInfo;
2946 
2947         currentId = PopulateH264UpdateFields(pStdVideoPictureParametersSet, h264SessionParametersAddInfo);
2948     }
2949     break;
2950     case StdVideoPictureParametersSet::TYPE_H265_VPS:
2951     case StdVideoPictureParametersSet::TYPE_H265_SPS:
2952     case StdVideoPictureParametersSet::TYPE_H265_PPS:
2953     {
2954         createInfo.pNext                                   = &h265SessionParametersCreateInfo;
2955         h265SessionParametersCreateInfo.maxStdVPSCount     = MAX_VPS_IDS;
2956         h265SessionParametersCreateInfo.maxStdSPSCount     = MAX_SPS_IDS;
2957         h265SessionParametersCreateInfo.maxStdPPSCount     = MAX_PPS_IDS;
2958         h265SessionParametersCreateInfo.pParametersAddInfo = &h265SessionParametersAddInfo;
2959 
2960         currentId = PopulateH265UpdateFields(pStdVideoPictureParametersSet, h265SessionParametersAddInfo);
2961     }
2962     break;
2963     case StdVideoPictureParametersSet::TYPE_AV1_SPS:
2964     {
2965         createInfo.pNext = &av1SessionParametersCreateInfo;
2966         if (pStdVideoPictureParametersSet == nullptr)
2967         {
2968             currentId = -1;
2969         }
2970         else
2971         {
2972             assert(pStdVideoPictureParametersSet->GetStdType() == StdVideoPictureParametersSet::TYPE_AV1_SPS);
2973             assert(av1SessionParametersCreateInfo.sType ==
2974                    VK_STRUCTURE_TYPE_VIDEO_DECODE_AV1_SESSION_PARAMETERS_CREATE_INFO_KHR);
2975             av1SessionParametersCreateInfo.pStdSequenceHeader =
2976                 const_cast<StdVideoAV1SequenceHeader *>(pStdVideoPictureParametersSet->GetStdAV1Sps());
2977             bool isAv1Sps = false;
2978             currentId     = pStdVideoPictureParametersSet->GetAv1SpsId(isAv1Sps);
2979             DE_ASSERT(isAv1Sps);
2980         }
2981         createInfo.videoSessionParametersTemplate =
2982             VK_NULL_HANDLE; // TODO: The parameter set code is legacy from the sample app, it could be radically simplified.
2983     }
2984     break;
2985     default:
2986         DE_ASSERT(!"Invalid parameter set type");
2987         return VK_ERROR_INITIALIZATION_FAILED;
2988     }
2989 
2990     createInfo.videoSession = videoSession->GetVideoSession();
2991     VkResult result         = m_deviceContext.getDeviceDriver().createVideoSessionParametersKHR(
2992         m_deviceContext.device, &createInfo, nullptr, &m_sessionParameters);
2993 
2994     TCU_CHECK_AND_THROW(InternalError, result == VK_SUCCESS, "Could not create video session");
2995     m_videoSession = videoSession;
2996 
2997     if (pTemplatePictureParameters)
2998     {
2999         m_vpsIdsUsed    = pTemplatePictureParameters->m_vpsIdsUsed;
3000         m_spsIdsUsed    = pTemplatePictureParameters->m_spsIdsUsed;
3001         m_ppsIdsUsed    = pTemplatePictureParameters->m_ppsIdsUsed;
3002         m_av1SpsIdsUsed = pTemplatePictureParameters->m_av1SpsIdsUsed; // TODO Review
3003     }
3004 
3005     assert(currentId >= 0);
3006     switch (pStdVideoPictureParametersSet->GetParameterType())
3007     {
3008     case StdVideoPictureParametersSet::PPS_TYPE:
3009         m_ppsIdsUsed.set(currentId, true);
3010         break;
3011 
3012     case StdVideoPictureParametersSet::SPS_TYPE:
3013         m_spsIdsUsed.set(currentId, true);
3014         break;
3015 
3016     case StdVideoPictureParametersSet::VPS_TYPE:
3017         m_vpsIdsUsed.set(currentId, true);
3018         break;
3019     case StdVideoPictureParametersSet::AV1_SPS_TYPE:
3020         m_av1SpsIdsUsed.set(currentId, true);
3021         break;
3022     default:
3023         DE_ASSERT(!"Invalid StdVideoPictureParametersSet Parameter Type!");
3024     }
3025     m_Id = ++m_currentId;
3026 
3027     return result;
3028 }
3029 
UpdateParametersObject(StdVideoPictureParametersSet * pStdVideoPictureParametersSet)3030 VkResult VkParserVideoPictureParameters::UpdateParametersObject(
3031     StdVideoPictureParametersSet *pStdVideoPictureParametersSet)
3032 {
3033     if (pStdVideoPictureParametersSet == nullptr)
3034     {
3035         return VK_SUCCESS;
3036     }
3037 
3038     int32_t currentId = -1;
3039     VkVideoSessionParametersUpdateInfoKHR updateInfo{};
3040     updateInfo.sType = VK_STRUCTURE_TYPE_VIDEO_SESSION_PARAMETERS_UPDATE_INFO_KHR;
3041     VkVideoDecodeH264SessionParametersAddInfoKHR h264SessionParametersAddInfo{};
3042     h264SessionParametersAddInfo.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_ADD_INFO_KHR;
3043     VkVideoDecodeH265SessionParametersAddInfoKHR h265SessionParametersAddInfo{};
3044     h265SessionParametersAddInfo.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_ADD_INFO_KHR;
3045 
3046     StdVideoPictureParametersSet::StdType updateType = pStdVideoPictureParametersSet->GetStdType();
3047     switch (updateType)
3048     {
3049     case StdVideoPictureParametersSet::TYPE_H264_SPS:
3050     case StdVideoPictureParametersSet::TYPE_H264_PPS:
3051     {
3052         updateInfo.pNext = &h264SessionParametersAddInfo;
3053         currentId        = PopulateH264UpdateFields(pStdVideoPictureParametersSet, h264SessionParametersAddInfo);
3054     }
3055     break;
3056     case StdVideoPictureParametersSet::TYPE_H265_VPS:
3057     case StdVideoPictureParametersSet::TYPE_H265_SPS:
3058     case StdVideoPictureParametersSet::TYPE_H265_PPS:
3059     {
3060         updateInfo.pNext = &h265SessionParametersAddInfo;
3061         currentId        = PopulateH265UpdateFields(pStdVideoPictureParametersSet, h265SessionParametersAddInfo);
3062     }
3063     break;
3064     case StdVideoPictureParametersSet::TYPE_AV1_SPS:
3065     {
3066         // Control should not get here. New parameter objects in AV1 imply the creation of a new session..
3067         // TODO: Properly fix the call chains in the case of AV1, for now just ignore the updates...
3068         return VK_SUCCESS;
3069         DE_ASSERT(false && "There should be no calls to UpdateParametersObject for AV1");
3070         break;
3071     }
3072     default:
3073         DE_ASSERT(!"Invalid Parser format");
3074         return VK_ERROR_INITIALIZATION_FAILED;
3075     }
3076 
3077     updateInfo.updateSequenceCount = ++m_updateCount;
3078     VK_CHECK(m_deviceContext.getDeviceDriver().updateVideoSessionParametersKHR(m_deviceContext.device,
3079                                                                                m_sessionParameters, &updateInfo));
3080 
3081     DE_ASSERT(currentId >= 0);
3082     switch (pStdVideoPictureParametersSet->GetParameterType())
3083     {
3084     case StdVideoPictureParametersSet::PPS_TYPE:
3085         m_ppsIdsUsed.set(currentId, true);
3086         break;
3087 
3088     case StdVideoPictureParametersSet::SPS_TYPE:
3089         m_spsIdsUsed.set(currentId, true);
3090         break;
3091 
3092     case StdVideoPictureParametersSet::VPS_TYPE:
3093         m_vpsIdsUsed.set(currentId, true);
3094         break;
3095     case StdVideoPictureParametersSet::AV1_SPS_TYPE:
3096         TCU_FAIL("Parameter set updates are not supported in AV1!");
3097         break;
3098     default:
3099         DE_ASSERT(!"Invalid StdVideoPictureParametersSet Parameter Type!");
3100     }
3101 
3102     return VK_SUCCESS;
3103 }
3104 
~VkParserVideoPictureParameters()3105 VkParserVideoPictureParameters::~VkParserVideoPictureParameters()
3106 {
3107     if (!!m_sessionParameters)
3108     {
3109         m_deviceContext.getDeviceDriver().destroyVideoSessionParametersKHR(m_deviceContext.device, m_sessionParameters,
3110                                                                            nullptr);
3111         m_sessionParameters = VK_NULL_HANDLE;
3112     }
3113     m_videoSession = nullptr;
3114 }
3115 
UpdatePictureParametersHierarchy(VkSharedBaseObj<StdVideoPictureParametersSet> & pictureParametersObject)3116 bool VkParserVideoPictureParameters::UpdatePictureParametersHierarchy(
3117     VkSharedBaseObj<StdVideoPictureParametersSet> &pictureParametersObject)
3118 {
3119     int32_t nodeId                                         = -1;
3120     bool isNodeId                                          = false;
3121     StdVideoPictureParametersSet::ParameterType nodeParent = StdVideoPictureParametersSet::INVALID_TYPE;
3122     StdVideoPictureParametersSet::ParameterType nodeChild  = StdVideoPictureParametersSet::INVALID_TYPE;
3123     switch (pictureParametersObject->GetParameterType())
3124     {
3125     case StdVideoPictureParametersSet::PPS_TYPE:
3126         nodeParent = StdVideoPictureParametersSet::SPS_TYPE;
3127         nodeId     = pictureParametersObject->GetPpsId(isNodeId);
3128         if (!((uint32_t)nodeId < VkParserVideoPictureParameters::MAX_PPS_IDS))
3129         {
3130             DE_ASSERT(!"PPS ID is out of bounds");
3131             return false;
3132         }
3133         DE_ASSERT(isNodeId);
3134         if (m_lastPictParamsQueue[nodeParent])
3135         {
3136             bool isParentId           = false;
3137             const int32_t spsParentId = pictureParametersObject->GetSpsId(isParentId);
3138             DE_ASSERT(!isParentId);
3139             if (spsParentId == m_lastPictParamsQueue[nodeParent]->GetSpsId(isParentId))
3140             {
3141                 DE_ASSERT(isParentId);
3142                 pictureParametersObject->m_parent = m_lastPictParamsQueue[nodeParent];
3143             }
3144         }
3145         break;
3146     case StdVideoPictureParametersSet::SPS_TYPE:
3147         nodeParent = StdVideoPictureParametersSet::VPS_TYPE;
3148         nodeChild  = StdVideoPictureParametersSet::PPS_TYPE;
3149         nodeId     = pictureParametersObject->GetSpsId(isNodeId);
3150         if (!((uint32_t)nodeId < VkParserVideoPictureParameters::MAX_SPS_IDS))
3151         {
3152             DE_ASSERT(!"SPS ID is out of bounds");
3153             return false;
3154         }
3155         DE_ASSERT(isNodeId);
3156         if (m_lastPictParamsQueue[nodeChild])
3157         {
3158             const int32_t spsChildId = m_lastPictParamsQueue[nodeChild]->GetSpsId(isNodeId);
3159             DE_ASSERT(!isNodeId);
3160             if (spsChildId == nodeId)
3161             {
3162                 m_lastPictParamsQueue[nodeChild]->m_parent = pictureParametersObject;
3163             }
3164         }
3165         if (m_lastPictParamsQueue[nodeParent])
3166         {
3167             const int32_t vpsParentId = pictureParametersObject->GetVpsId(isNodeId);
3168             DE_ASSERT(!isNodeId);
3169             if (vpsParentId == m_lastPictParamsQueue[nodeParent]->GetVpsId(isNodeId))
3170             {
3171                 pictureParametersObject->m_parent = m_lastPictParamsQueue[nodeParent];
3172                 DE_ASSERT(isNodeId);
3173             }
3174         }
3175         break;
3176     case StdVideoPictureParametersSet::VPS_TYPE:
3177         nodeChild = StdVideoPictureParametersSet::SPS_TYPE;
3178         nodeId    = pictureParametersObject->GetVpsId(isNodeId);
3179         if (!((uint32_t)nodeId < VkParserVideoPictureParameters::MAX_VPS_IDS))
3180         {
3181             DE_ASSERT(!"VPS ID is out of bounds");
3182             return false;
3183         }
3184         DE_ASSERT(isNodeId);
3185         if (m_lastPictParamsQueue[nodeChild])
3186         {
3187             const int32_t vpsParentId = m_lastPictParamsQueue[nodeChild]->GetVpsId(isNodeId);
3188             DE_ASSERT(!isNodeId);
3189             if (vpsParentId == nodeId)
3190             {
3191                 m_lastPictParamsQueue[nodeChild]->m_parent = pictureParametersObject;
3192             }
3193         }
3194         break;
3195     default:
3196         DE_ASSERT("!Invalid STD type");
3197         return false;
3198     }
3199     m_lastPictParamsQueue[pictureParametersObject->GetParameterType()] = pictureParametersObject;
3200 
3201     return true;
3202 }
3203 
AddPictureParametersToQueue(VkSharedBaseObj<StdVideoPictureParametersSet> & pictureParametersSet)3204 VkResult VkParserVideoPictureParameters::AddPictureParametersToQueue(
3205     VkSharedBaseObj<StdVideoPictureParametersSet> &pictureParametersSet)
3206 {
3207     m_pictureParametersQueue.push(pictureParametersSet);
3208     return VK_SUCCESS;
3209 }
3210 
HandleNewPictureParametersSet(VkSharedBaseObj<VulkanVideoSession> & videoSession,StdVideoPictureParametersSet * pStdVideoPictureParametersSet)3211 VkResult VkParserVideoPictureParameters::HandleNewPictureParametersSet(
3212     VkSharedBaseObj<VulkanVideoSession> &videoSession, StdVideoPictureParametersSet *pStdVideoPictureParametersSet)
3213 {
3214     VkResult result;
3215     if (m_sessionParameters == VK_NULL_HANDLE)
3216     {
3217         DE_ASSERT(videoSession != VK_NULL_HANDLE);
3218         DE_ASSERT(m_videoSession == VK_NULL_HANDLE);
3219         if (m_templatePictureParameters)
3220         {
3221             m_templatePictureParameters->FlushPictureParametersQueue(videoSession);
3222         }
3223         result = CreateParametersObject(videoSession, pStdVideoPictureParametersSet, m_templatePictureParameters);
3224         DE_ASSERT(result == VK_SUCCESS);
3225         m_templatePictureParameters = nullptr; // the template object is not needed anymore
3226         m_videoSession              = videoSession;
3227     }
3228     else
3229     {
3230         DE_ASSERT(m_videoSession != VK_NULL_HANDLE);
3231         DE_ASSERT(m_sessionParameters != VK_NULL_HANDLE);
3232         result = UpdateParametersObject(pStdVideoPictureParametersSet);
3233         DE_ASSERT(result == VK_SUCCESS);
3234     }
3235 
3236     return result;
3237 }
3238 
FlushPictureParametersQueue(VkSharedBaseObj<VulkanVideoSession> & videoSession)3239 int32_t VkParserVideoPictureParameters::FlushPictureParametersQueue(VkSharedBaseObj<VulkanVideoSession> &videoSession)
3240 {
3241     if (!videoSession)
3242     {
3243         return -1;
3244     }
3245     uint32_t numQueueItems = 0;
3246     while (!m_pictureParametersQueue.empty())
3247     {
3248         VkSharedBaseObj<StdVideoPictureParametersSet> &stdVideoPictureParametersSet = m_pictureParametersQueue.front();
3249 
3250         VkResult result = HandleNewPictureParametersSet(videoSession, stdVideoPictureParametersSet);
3251         if (result != VK_SUCCESS)
3252         {
3253             return -1;
3254         }
3255 
3256         m_pictureParametersQueue.pop();
3257         numQueueItems++;
3258     }
3259 
3260     return numQueueItems;
3261 }
3262 
CheckStdObjectBeforeUpdate(VkSharedBaseObj<StdVideoPictureParametersSet> & stdPictureParametersSet,VkSharedBaseObj<VkParserVideoPictureParameters> & currentVideoPictureParameters)3263 bool VkParserVideoPictureParameters::CheckStdObjectBeforeUpdate(
3264     VkSharedBaseObj<StdVideoPictureParametersSet> &stdPictureParametersSet,
3265     VkSharedBaseObj<VkParserVideoPictureParameters> &currentVideoPictureParameters)
3266 {
3267     if (!stdPictureParametersSet)
3268     {
3269         return false;
3270     }
3271 
3272     bool stdObjectUpdate = (stdPictureParametersSet->GetUpdateSequenceCount() > 0);
3273 
3274     if (!currentVideoPictureParameters || stdObjectUpdate)
3275     {
3276 
3277         // Create new Vulkan Picture Parameters object
3278         return true;
3279     }
3280     else
3281     { // existing VkParserVideoPictureParameters object
3282         DE_ASSERT(currentVideoPictureParameters);
3283         // Update with the existing Vulkan Picture Parameters object
3284     }
3285 
3286     VkSharedBaseObj<VkVideoRefCountBase> clientObject;
3287     stdPictureParametersSet->GetClientObject(clientObject);
3288     DE_ASSERT(!clientObject);
3289 
3290     return false;
3291 }
3292 
AddPictureParameters(DeviceContext & deviceContext,VkSharedBaseObj<VulkanVideoSession> &,VkSharedBaseObj<StdVideoPictureParametersSet> & stdPictureParametersSet,VkSharedBaseObj<VkParserVideoPictureParameters> & currentVideoPictureParameters)3293 VkResult VkParserVideoPictureParameters::AddPictureParameters(
3294     DeviceContext &deviceContext, VkSharedBaseObj<VulkanVideoSession> & /*videoSession*/,
3295     VkSharedBaseObj<StdVideoPictureParametersSet> &stdPictureParametersSet, /* from the parser */
3296     VkSharedBaseObj<VkParserVideoPictureParameters>
3297         &currentVideoPictureParameters /* reference to member field of decoder */)
3298 {
3299     DE_ASSERT(stdPictureParametersSet);
3300 
3301     VkResult result;
3302     if (CheckStdObjectBeforeUpdate(stdPictureParametersSet, currentVideoPictureParameters))
3303     {
3304         result = VkParserVideoPictureParameters::Create(deviceContext, currentVideoPictureParameters,
3305                                                         currentVideoPictureParameters);
3306     }
3307 
3308     result = currentVideoPictureParameters->AddPictureParametersToQueue(stdPictureParametersSet);
3309 
3310     return result;
3311 }
3312 
AddRef()3313 int32_t VkParserVideoPictureParameters::AddRef()
3314 {
3315     return ++m_refCount;
3316 }
3317 
Release()3318 int32_t VkParserVideoPictureParameters::Release()
3319 {
3320     uint32_t ret;
3321     ret = --m_refCount;
3322     // Destroy the device if refcount reaches zero
3323     if (ret == 0)
3324     {
3325         delete this;
3326     }
3327     return ret;
3328 }
3329 
createBasicDecoder(DeviceContext * deviceContext,const VkVideoCoreProfile * profile,size_t framesToCheck,bool resolutionChange)3330 shared_ptr<VideoBaseDecoder> createBasicDecoder(DeviceContext *deviceContext, const VkVideoCoreProfile *profile,
3331                                                 size_t framesToCheck, bool resolutionChange)
3332 {
3333     VkSharedBaseObj<VulkanVideoFrameBuffer> vkVideoFrameBuffer;
3334 
3335     VK_CHECK(VulkanVideoFrameBuffer::Create(deviceContext,
3336                                             false, // UseResultStatusQueries
3337                                             false, // ResourcesWithoutProfiles
3338                                             vkVideoFrameBuffer));
3339 
3340     VideoBaseDecoder::Parameters params;
3341 
3342     params.profile            = profile;
3343     params.context            = deviceContext;
3344     params.framebuffer        = vkVideoFrameBuffer;
3345     params.framesToCheck      = framesToCheck;
3346     params.queryDecodeStatus  = false;
3347     params.outOfOrderDecoding = false;
3348     params.alwaysRecreateDPB  = resolutionChange;
3349     params.layeredDpb         = true;
3350 
3351     return std::make_shared<VideoBaseDecoder>(std::move(params));
3352 }
3353 
getDecodedImageFromContext(DeviceContext & deviceContext,VkImageLayout layout,const DecodedFrame * frame)3354 de::MovePtr<vkt::ycbcr::MultiPlaneImageData> getDecodedImageFromContext(DeviceContext &deviceContext,
3355                                                                         VkImageLayout layout, const DecodedFrame *frame)
3356 {
3357     auto &videoDeviceDriver       = deviceContext.getDeviceDriver();
3358     auto device                   = deviceContext.device;
3359     auto queueFamilyIndexDecode   = deviceContext.decodeQueueFamilyIdx();
3360     auto queueFamilyIndexTransfer = deviceContext.transferQueueFamilyIdx();
3361     const VkExtent2D imageExtent{(uint32_t)frame->displayWidth, (uint32_t)frame->displayHeight};
3362     const VkImage image      = frame->outputImageView->GetImageResource()->GetImage();
3363     const VkFormat format    = frame->outputImageView->GetImageResource()->GetImageCreateInfo().format;
3364     uint32_t imageLayerIndex = frame->imageLayerIndex;
3365 
3366     MovePtr<vkt::ycbcr::MultiPlaneImageData> multiPlaneImageData(
3367         new vkt::ycbcr::MultiPlaneImageData(format, tcu::UVec2(imageExtent.width, imageExtent.height)));
3368     const VkQueue queueDecode   = getDeviceQueue(videoDeviceDriver, device, queueFamilyIndexDecode, 0u);
3369     const VkQueue queueTransfer = getDeviceQueue(videoDeviceDriver, device, queueFamilyIndexTransfer, 0u);
3370     const VkImageSubresourceRange imageSubresourceRange =
3371         makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, imageLayerIndex, 1);
3372 
3373     const VkImageMemoryBarrier2KHR imageBarrierDecode =
3374         makeImageMemoryBarrier2(VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR, VK_ACCESS_2_VIDEO_DECODE_WRITE_BIT_KHR,
3375                                 VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR, VK_ACCESS_NONE_KHR, layout,
3376                                 VK_IMAGE_LAYOUT_GENERAL, image, imageSubresourceRange);
3377 
3378     const VkImageMemoryBarrier2KHR imageBarrierOwnershipDecode = makeImageMemoryBarrier2(
3379         VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR, VK_ACCESS_NONE_KHR, VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR,
3380         VK_ACCESS_NONE_KHR, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL, image, imageSubresourceRange,
3381         queueFamilyIndexDecode, queueFamilyIndexTransfer);
3382 
3383     const VkImageMemoryBarrier2KHR imageBarrierOwnershipTransfer = makeImageMemoryBarrier2(
3384         VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR, VK_ACCESS_NONE_KHR, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
3385         VK_ACCESS_NONE_KHR, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL, image, imageSubresourceRange,
3386         queueFamilyIndexDecode, queueFamilyIndexTransfer);
3387 
3388     const VkImageMemoryBarrier2KHR imageBarrierTransfer = makeImageMemoryBarrier2(
3389         VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_ACCESS_MEMORY_WRITE_BIT, VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR,
3390         VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, image,
3391         imageSubresourceRange);
3392 
3393     const Move<VkCommandPool> cmdDecodePool(makeCommandPool(videoDeviceDriver, device, queueFamilyIndexDecode));
3394     const Move<VkCommandBuffer> cmdDecodeBuffer(
3395         allocateCommandBuffer(videoDeviceDriver, device, *cmdDecodePool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
3396     const Move<VkCommandPool> cmdTransferPool(makeCommandPool(videoDeviceDriver, device, queueFamilyIndexTransfer));
3397     const Move<VkCommandBuffer> cmdTransferBuffer(
3398         allocateCommandBuffer(videoDeviceDriver, device, *cmdTransferPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
3399 
3400     Move<VkSemaphore> semaphore                 = createSemaphore(videoDeviceDriver, device);
3401     Move<VkFence> decodeFence                   = createFence(videoDeviceDriver, device);
3402     Move<VkFence> transferFence                 = createFence(videoDeviceDriver, device);
3403     VkFence fences[]                            = {*decodeFence, *transferFence};
3404     const VkPipelineStageFlags waitDstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
3405 
3406     VkSubmitInfo decodeSubmitInfo = {
3407         VK_STRUCTURE_TYPE_SUBMIT_INFO, //  VkStructureType sType;
3408         nullptr,                       //  const void* pNext;
3409         0u,                            //  uint32_t waitSemaphoreCount;
3410         nullptr,                       //  const VkSemaphore* pWaitSemaphores;
3411         nullptr,                       //  const VkPipelineStageFlags* pWaitDstStageMask;
3412         1u,                            //  uint32_t commandBufferCount;
3413         &*cmdDecodeBuffer,             //  const VkCommandBuffer* pCommandBuffers;
3414         1u,                            //  uint32_t signalSemaphoreCount;
3415         &*semaphore,                   //  const VkSemaphore* pSignalSemaphores;
3416     };
3417     if (frame->frameCompleteSemaphore != VK_NULL_HANDLE)
3418     {
3419         decodeSubmitInfo.waitSemaphoreCount = 1;
3420         decodeSubmitInfo.pWaitSemaphores    = &frame->frameCompleteSemaphore;
3421         decodeSubmitInfo.pWaitDstStageMask  = &waitDstStageMask;
3422     }
3423     const VkSubmitInfo transferSubmitInfo = {
3424         VK_STRUCTURE_TYPE_SUBMIT_INFO, //  VkStructureType sType;
3425         nullptr,                       //  const void* pNext;
3426         1u,                            //  uint32_t waitSemaphoreCount;
3427         &*semaphore,                   //  const VkSemaphore* pWaitSemaphores;
3428         &waitDstStageMask,             //  const VkPipelineStageFlags* pWaitDstStageMask;
3429         1u,                            //  uint32_t commandBufferCount;
3430         &*cmdTransferBuffer,           //  const VkCommandBuffer* pCommandBuffers;
3431         0u,                            //  uint32_t signalSemaphoreCount;
3432         nullptr,                       //  const VkSemaphore* pSignalSemaphores;
3433     };
3434 
3435     beginCommandBuffer(videoDeviceDriver, *cmdDecodeBuffer, 0u);
3436     cmdPipelineImageMemoryBarrier2(videoDeviceDriver, *cmdDecodeBuffer, &imageBarrierDecode);
3437     cmdPipelineImageMemoryBarrier2(videoDeviceDriver, *cmdDecodeBuffer, &imageBarrierOwnershipDecode);
3438     endCommandBuffer(videoDeviceDriver, *cmdDecodeBuffer);
3439 
3440     beginCommandBuffer(videoDeviceDriver, *cmdTransferBuffer, 0u);
3441     cmdPipelineImageMemoryBarrier2(videoDeviceDriver, *cmdTransferBuffer, &imageBarrierOwnershipTransfer);
3442     cmdPipelineImageMemoryBarrier2(videoDeviceDriver, *cmdTransferBuffer, &imageBarrierTransfer);
3443     endCommandBuffer(videoDeviceDriver, *cmdTransferBuffer);
3444 
3445     VK_CHECK(videoDeviceDriver.queueSubmit(queueDecode, 1u, &decodeSubmitInfo, *decodeFence));
3446     VK_CHECK(videoDeviceDriver.queueSubmit(queueTransfer, 1u, &transferSubmitInfo, *transferFence));
3447 
3448     VK_CHECK(videoDeviceDriver.waitForFences(device, DE_LENGTH_OF_ARRAY(fences), fences, true, ~0ull));
3449 
3450     vkt::ycbcr::downloadImage(videoDeviceDriver, device, queueFamilyIndexTransfer, deviceContext.allocator(), image,
3451                               multiPlaneImageData.get(), 0, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, imageLayerIndex);
3452 
3453     const VkImageMemoryBarrier2KHR imageBarrierTransfer2 =
3454         makeImageMemoryBarrier2(VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR, VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR,
3455                                 VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR, VK_ACCESS_NONE_KHR,
3456                                 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, layout, image, imageSubresourceRange);
3457 
3458     videoDeviceDriver.resetCommandBuffer(*cmdTransferBuffer, 0u);
3459     videoDeviceDriver.resetFences(device, 1, &*transferFence);
3460     beginCommandBuffer(videoDeviceDriver, *cmdTransferBuffer, 0u);
3461     cmdPipelineImageMemoryBarrier2(videoDeviceDriver, *cmdTransferBuffer, &imageBarrierTransfer2);
3462     endCommandBuffer(videoDeviceDriver, *cmdTransferBuffer);
3463 
3464     const VkSubmitInfo transferSubmitInfo2 = {
3465         VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType;
3466         nullptr,                       //  const void* pNext;
3467         0u,                            //  uint32_t waitSemaphoreCount;
3468         nullptr,                       //  const VkSemaphore* pWaitSemaphores;
3469         nullptr,                       //  const VkPipelineStageFlags* pWaitDstStageMask;
3470         1u,                            //  uint32_t commandBufferCount;
3471         &*cmdTransferBuffer,           //  const VkCommandBuffer* pCommandBuffers;
3472         0u,                            //  uint32_t signalSemaphoreCount;
3473         nullptr,                       // const VkSemaphore* pSignalSemaphores;
3474     };
3475 
3476     VK_CHECK(videoDeviceDriver.queueSubmit(queueTransfer, 1u, &transferSubmitInfo2, *transferFence));
3477     VK_CHECK(videoDeviceDriver.waitForFences(device, 1, &*transferFence, true, ~0ull));
3478 
3479     return multiPlaneImageData;
3480 }
3481 
3482 } // namespace video
3483 } // namespace vkt
3484