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 &¶ms)
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> ¤tVideoPictureParameters)
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 ¤tVideoPictureParameters /* 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