1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2024 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 /*!
21 * \file
22 * \brief AV1 Video Encoding Session tests
23 */
24 /*--------------------------------------------------------------------*/
25 #include "vktTestCase.hpp"
26 #include "vktVideoClipInfo.hpp"
27 #include "vktVideoEncodeTests.hpp"
28 #include "vktVideoTestUtils.hpp"
29
30 #include <cstddef>
31 #include <cstdint>
32 #include <fstream>
33 #include <string>
34 #include <algorithm>
35 #include <filesystem>
36 #include <chrono>
37
38 #ifdef DE_BUILD_VIDEO
39 #include <vulkan_video_encoder.h>
40 #endif
41
42 #include "ycbcr/vktYCbCrUtil.hpp"
43
44 #ifndef STREAM_DUMP_DEBUG
45 #define STREAM_DUMP_DEBUG 0
46 #endif
47
48 namespace vkt
49 {
50 namespace video
51 {
52 namespace
53 {
54 using namespace vk;
55 using namespace std;
56
57 using de::MovePtr;
58 using vkt::ycbcr::getYCbCrBitDepth;
59 using vkt::ycbcr::getYCbCrFormatChannelCount;
60 using vkt::ycbcr::isXChromaSubsampled;
61 using vkt::ycbcr::isYChromaSubsampled;
62
63 #define PSNR_THRESHOLD_LOWER_LIMIT 50.0
64
65 bool checkClipFileExists(const std::string &clipName);
66 void removeClip(const std::string &clipName);
67
68 enum BitDepth
69 {
70 BIT_DEPTH_8 = 8,
71 BIT_DEPTH_10 = 10,
72 BIT_DEPTH_12 = 12
73 };
74
75 enum ChromaSubsampling
76 {
77 CHROMA_SS_400 = 400,
78 CHROMA_SS_420 = 420,
79 CHROMA_SS_422 = 422,
80 CHROMA_SS_444 = 444
81 };
82
83 enum GOPStruct
84 {
85 GOP_I,
86 GOP_I_P,
87 GOP_I_P_B,
88 GOP_IDR_P_B
89 };
90
91 enum Ordering
92 {
93 ORDERED,
94 UNORDERED
95 };
96
97 enum ResolutionChange
98 {
99 RESOLUTION_NO_CHANGE,
100 RESOLUTION_TO_LARGER,
101 RESOLUTION_TO_SMALLER
102 };
103
104 enum QIndex
105 {
106 QINDEX_NONE = 1,
107 QINDEX_64 = 64,
108 QINDEX_128 = 128,
109 QINDEX_192 = 192,
110 QINDEX_255 = 255,
111 };
112
113 enum Tiling
114 {
115 TILING_1_TILE,
116 TILING_1x2,
117 TILING_4x4
118 };
119
120 enum Superblock
121 {
122 SUPERBLOCK_64x64 = 64,
123 SUPERBLOCK_128x128 = 128,
124 };
125
126 enum RateControl
127 {
128 RC_DEFAULT = 0,
129 RC_DISABLED = 1,
130 RC_CBR = 2,
131 RC_VBR = 4
132 };
133
134 enum LoopFilter
135 {
136 LF_OFF,
137 LF_ON,
138 };
139
140 enum LoopRestore
141 {
142 LR_OFF,
143 LR_ON,
144 };
145
146 enum CDEF
147 {
148 CDEF_OFF,
149 CDEF_ON,
150 };
151
152 enum DpbMode
153 {
154 DPB_MODE_DEFAULT,
155 DPB_MODE_SEPARATE,
156 DPB_MODE_LAYERED,
157 };
158
159 struct FrameSizeDef
160 {
161 const char *baseClipName;
162 uint32_t width;
163 uint32_t height;
164 };
165
166 struct BitDepthDef
167 {
168 enum BitDepth depth;
169 const char *subName;
170 };
171
172 struct ChromaSubsamplingDef
173 {
174 enum ChromaSubsampling subsampling;
175 const char *subName;
176 };
177
178 struct GOPDef
179 {
180 uint32_t frameCount;
181 enum GOPStruct gop;
182 bool open;
183 uint32_t gopFrameCount;
184 uint32_t consecutiveBFrames;
185 const char *subName;
186 };
187
188 struct OrderingDef
189 {
190 enum Ordering order;
191 const char *subName;
192 };
193
194 struct ResolutionChangeDef
195 {
196 enum ResolutionChange resolutionChange;
197 const char *subName;
198 };
199
200 struct QuantizationDef
201 {
202 uint32_t qIndex;
203 const char *subName;
204 };
205
206 struct TilingDef
207 {
208 enum Tiling tiling;
209 const char *subName;
210 };
211
212 struct SuperblockDef
213 {
214 enum Superblock superblock;
215 const char *subName;
216 };
217
218 struct RateControlDef
219 {
220 enum RateControl rc;
221 const char *subName;
222 };
223
224 struct LoopFilterDef
225 {
226 enum LoopFilter lf;
227 const char *subName;
228 };
229
230 struct LoopRestoreDef
231 {
232 enum LoopRestore lr;
233 const char *subName;
234 };
235
236 struct CDEFDef
237 {
238 enum CDEF cdef;
239 const char *subName;
240 };
241
242 struct DpbModeDef
243 {
244 enum DpbMode mode;
245 const char *subName;
246 };
247
248 struct TestDefinition
249 {
250 const FrameSizeDef &frameSize;
251 const BitDepthDef &bitDepth;
252 const ChromaSubsamplingDef &subsampling;
253 const GOPDef &gop;
254 const OrderingDef &ordering;
255 const ResolutionChangeDef &resolutionChange;
256 const QuantizationDef &quantization;
257 const TilingDef &tiling;
258 const SuperblockDef &superblock;
259 const RateControlDef &rateControl;
260 const LoopFilterDef &loopFilter;
261 const LoopRestoreDef &loopRestore;
262 const CDEFDef &cdef;
263 const DpbModeDef &dpbMode;
264 };
265
266 struct TestRequirements
267 {
268 std::vector<std::string> extensions;
269 bool requireBFrames;
270 bool useVariableBitrate;
271 bool useConstantBitrate;
272 uint32_t bitDepth;
273 uint32_t subSampling;
274 VkVideoCodecOperationFlagBitsKHR codecOperation;
275 uint32_t width;
276 uint32_t height;
277 VkVideoEncodeAV1SuperblockSizeFlagsKHR superblockSizes;
278 uint32_t maxTileColumns;
279 uint32_t maxTileRows;
280 bool useDpbArray;
281 bool isXSubsampled;
282 bool isYSubsampled;
283 tcu::UVec4 colorDepth;
284 };
285 class VideoTestInstance : public VideoBaseTestInstance
286 {
287 public:
VideoTestInstance(Context & context,const std::string & inputClipFilename,const std::string & outputClipFilename,const VkExtent2D expectedOutputExtent,const TestDefinition & definition,bool generatedContent)288 VideoTestInstance(Context &context, const std::string &inputClipFilename, const std::string &outputClipFilename,
289 const VkExtent2D expectedOutputExtent, const TestDefinition &definition, bool generatedContent)
290 : VideoBaseTestInstance(context)
291 , m_inputClipFilename(inputClipFilename)
292 , m_outputClipFilename(outputClipFilename)
293 , m_expectedOutputExtent(expectedOutputExtent)
294 , m_definition(definition)
295 , m_generatedContent(generatedContent)
296 {
297 }
298 virtual tcu::TestStatus iterate(void);
299 #ifdef DE_BUILD_VIDEO
setEncoder(VkSharedBaseObj<VulkanVideoEncoder> & encoder)300 void setEncoder(VkSharedBaseObj<VulkanVideoEncoder> &encoder)
301 {
302 m_encoder = encoder;
303 }
304 #endif
305
306 private:
307 #ifdef DE_BUILD_VIDEO
308 VkSharedBaseObj<VulkanVideoEncoder> m_encoder;
309 #endif
310 std::string m_inputClipFilename;
311 std::string m_outputClipFilename;
312
313 // Output resolution may be different from input resolution if
314 // overriding happened (e.g, due to codedPictureAlignment not being {8,8}).
315 VkExtent2D m_expectedOutputExtent;
316
317 TestDefinition m_definition;
318 bool m_generatedContent;
319 };
320
321 class VideoTestCase : public TestCase
322 {
323 public:
324 VideoTestCase(tcu::TestContext &testCtx, const char *testName, const TestRequirements &requirements,
325 const TestDefinition &definition);
326 virtual ~VideoTestCase(void);
327 TestInstance *createInstance(Context &ctx) const override;
328 void checkSupport(Context &ctx) const override;
329 void addRequirement(const std::string &requirement);
330 void validateCapabilities(Context &context) const;
331
332 protected:
333 TestRequirements m_requirements;
334 TestDefinition m_definition;
335 static VkExtent2D codedPictureAlignment;
336 };
337
338 VkExtent2D VideoTestCase::codedPictureAlignment = VkExtent2D({0, 0});
339
340 static void buildTestName(const TestDefinition &testDef, std::string &testName);
341
buildClipName(tcu::TestContext & testCtx,const TestDefinition & testDef,std::string & clipName,bool output)342 static void buildClipName(tcu::TestContext &testCtx, const TestDefinition &testDef, std::string &clipName, bool output)
343 {
344 auto &cmdLine = testCtx.getCommandLine();
345 auto archiveDir = cmdLine.getArchiveDir();
346 clipName = archiveDir + std::string("/vulkan/video/");
347
348 clipName += testDef.frameSize.baseClipName;
349 clipName += std::to_string(testDef.frameSize.width) + "x" + std::to_string(testDef.frameSize.height);
350
351 clipName += "_" + std::string(testDef.subsampling.subName);
352 clipName += "_" + std::string(testDef.bitDepth.subName);
353 clipName += "_" + std::string(testDef.gop.subName);
354 clipName += "_" + std::to_string(testDef.gop.frameCount);
355
356 std::string testName("");
357 buildTestName(testDef, testName);
358 clipName += "_" + testName;
359
360 if (output)
361 clipName += ".ivf";
362 else
363 clipName += ".yuv";
364 }
365
buildEncoderParams(const TestDefinition & testDef,std::vector<std::string> & params)366 static void buildEncoderParams(const TestDefinition &testDef, std::vector<std::string> ¶ms)
367 {
368 params.push_back("--codec");
369 params.push_back("av1");
370
371 params.push_back("--numFrames");
372 params.push_back(de::toString(testDef.gop.frameCount));
373
374 params.push_back("--inputWidth");
375 params.push_back(de::toString(testDef.frameSize.width));
376 params.push_back("--inputHeight");
377 params.push_back(de::toString(testDef.frameSize.height));
378
379 params.push_back("--idrPeriod");
380 switch (testDef.gop.gop)
381 {
382 case GOP_IDR_P_B:
383 params.push_back("30");
384 break;
385 default:
386 params.push_back("0");
387 break;
388 }
389
390 switch (testDef.tiling.tiling)
391 {
392 case TILING_1x2:
393 {
394 uint32_t tileWidthInSbs, tileHeightInSbs;
395 if (testDef.superblock.superblock)
396 {
397 tileWidthInSbs = static_cast<uint32_t>(
398 std::ceil((double)testDef.frameSize.width / (double)testDef.superblock.superblock));
399 tileHeightInSbs = static_cast<uint32_t>(
400 std::ceil((double)testDef.frameSize.height / (double)testDef.superblock.superblock));
401 }
402 else
403 {
404 TCU_THROW(NotSupportedError, "superblock should not be null");
405 }
406 params.push_back("--tiles");
407 params.push_back("--params");
408 params.push_back("0");
409 params.push_back("1");
410 params.push_back(std::to_string(tileWidthInSbs - 1));
411 params.push_back("2");
412 params.push_back(std::to_string((tileHeightInSbs / 2) - 1));
413 params.push_back(std::to_string((tileHeightInSbs - tileHeightInSbs / 2) - 1));
414 params.push_back("0");
415 break;
416 }
417 case TILING_4x4:
418 params.push_back("--tiles");
419 params.push_back("--params");
420 params.push_back("1");
421 params.push_back("4");
422 params.push_back("4");
423 params.push_back("0");
424 break;
425 default:
426 break;
427 }
428
429 params.push_back("--inputChromaSubsampling");
430 params.push_back(std::to_string(testDef.subsampling.subsampling).c_str());
431
432 params.push_back("--inputBpp");
433 params.push_back(std::to_string(testDef.bitDepth.depth));
434
435 params.push_back("--consecutiveBFrameCount");
436 params.push_back(de::toString(testDef.gop.consecutiveBFrames));
437
438 params.push_back("--gopFrameCount");
439 params.push_back(de::toString(testDef.gop.frameCount));
440
441 params.push_back("--qpI");
442 params.push_back(de::toString(testDef.quantization.qIndex));
443
444 params.push_back("--qpP");
445 params.push_back(de::toString(testDef.quantization.qIndex));
446
447 params.push_back("--qpB");
448 params.push_back(de::toString(testDef.quantization.qIndex));
449
450 params.push_back("--rateControlMode");
451 params.push_back(de::toString(testDef.rateControl.rc));
452
453 if (testDef.loopFilter.lf == LF_ON)
454 params.push_back("--lf");
455
456 if (testDef.loopRestore.lr == LR_ON)
457 params.push_back("--lr");
458
459 if (testDef.loopRestore.lr == LR_ON)
460 params.push_back("--cdef");
461
462 switch (testDef.dpbMode.mode)
463 {
464 case DPB_MODE_SEPARATE:
465 params.push_back("--dpbMode");
466 params.push_back("separate");
467 break;
468 case DPB_MODE_LAYERED:
469 params.push_back("--dpbMode");
470 params.push_back("layered");
471 break;
472 default:
473 break;
474 }
475
476 if (testDef.ordering.order == UNORDERED)
477 params.push_back("--testOutOfOrderRecording");
478 }
479
getChromaSubSampling(enum ChromaSubsampling subSampling)480 VkVideoChromaSubsamplingFlagsKHR getChromaSubSampling(enum ChromaSubsampling subSampling)
481 {
482 switch (subSampling)
483 {
484 case CHROMA_SS_400:
485 return VK_VIDEO_CHROMA_SUBSAMPLING_MONOCHROME_BIT_KHR;
486 case CHROMA_SS_420:
487 return VK_VIDEO_CHROMA_SUBSAMPLING_420_BIT_KHR;
488 case CHROMA_SS_422:
489 return VK_VIDEO_CHROMA_SUBSAMPLING_422_BIT_KHR;
490 case CHROMA_SS_444:
491 return VK_VIDEO_CHROMA_SUBSAMPLING_444_BIT_KHR;
492 };
493 return VK_VIDEO_CHROMA_SUBSAMPLING_INVALID_KHR;
494 }
495
getBitDepth(enum BitDepth bitDepth)496 VkVideoComponentBitDepthFlagBitsKHR getBitDepth(enum BitDepth bitDepth)
497 {
498 switch (bitDepth)
499 {
500 case BIT_DEPTH_8:
501 return VK_VIDEO_COMPONENT_BIT_DEPTH_8_BIT_KHR;
502 case BIT_DEPTH_10:
503 return VK_VIDEO_COMPONENT_BIT_DEPTH_10_BIT_KHR;
504 case BIT_DEPTH_12:
505 return VK_VIDEO_COMPONENT_BIT_DEPTH_12_BIT_KHR;
506 };
507 return VK_VIDEO_COMPONENT_BIT_DEPTH_INVALID_KHR;
508 }
509
iterate(void)510 tcu::TestStatus VideoTestInstance::iterate(void)
511 {
512 tcu::TestStatus status = tcu::TestStatus::fail("Unable to encode any frames");
513 #ifdef DE_BUILD_VIDEO
514 int64_t frameNumEncoded = 0;
515
516 // Encode all frames
517 int64_t totalFrames = m_encoder->GetNumberOfFrames();
518 for (int64_t i = 0; i < totalFrames; ++i)
519 {
520 VkResult result = m_encoder->EncodeNextFrame(frameNumEncoded);
521 if (result != VK_SUCCESS)
522 {
523 status = tcu::TestStatus::fail("Failed to encode frame " + de::toString(i));
524 break;
525 }
526 result = m_encoder->GetBitstream();
527 if (result != VK_SUCCESS)
528 {
529 status = tcu::TestStatus::fail("Failed to get bitstream for frame " + de::toString(i));
530 break;
531 }
532 }
533
534 if (frameNumEncoded + 1 == totalFrames)
535 {
536 status = validateEncodedContent(
537 VK_VIDEO_CODEC_OPERATION_ENCODE_AV1_BIT_KHR, STD_VIDEO_AV1_PROFILE_MAIN, m_outputClipFilename.c_str(),
538 m_inputClipFilename.c_str(), m_definition.gop.frameCount, m_definition.frameSize.width,
539 m_definition.frameSize.height, m_expectedOutputExtent,
540 getChromaSubSampling(m_definition.subsampling.subsampling), getBitDepth(m_definition.bitDepth.depth),
541 getBitDepth(m_definition.bitDepth.depth), PSNR_THRESHOLD_LOWER_LIMIT);
542 }
543 m_encoder = nullptr;
544 #else
545 DE_UNREF(m_definition);
546 DE_UNREF(m_expectedOutputExtent);
547 status = tcu::TestStatus::fail("Vulkan video is not supported on this platform");
548 #endif
549 #if STREAM_DUMP_DEBUG == 0
550 if (m_generatedContent)
551 {
552 removeClip(m_inputClipFilename);
553 }
554 removeClip(m_outputClipFilename);
555 #endif
556
557 return status;
558 }
559
VideoTestCase(tcu::TestContext & testCtx,const char * testName,const TestRequirements & requirements,const TestDefinition & definition)560 VideoTestCase::VideoTestCase(tcu::TestContext &testCtx, const char *testName, const TestRequirements &requirements,
561 const TestDefinition &definition)
562 : TestCase(testCtx, testName)
563 , m_requirements(requirements)
564 , m_definition(definition)
565
566 {
567 }
568
~VideoTestCase(void)569 VideoTestCase::~VideoTestCase(void)
570 {
571 }
572
createInstance(Context & ctx) const573 TestInstance *VideoTestCase::createInstance(Context &ctx) const
574 {
575 #ifdef DE_BUILD_VIDEO
576 VkSharedBaseObj<VulkanVideoEncoder> encoder;
577 #endif
578 VideoTestInstance *testInstance;
579 std::vector<const char *> args;
580 bool generatedContent = false;
581 std::vector<std::string> encoderParams;
582 std::stringstream ss;
583 std::string deviceID;
584
585 buildEncoderParams(m_definition, encoderParams);
586
587 std::string inputClipName("");
588 buildClipName(getTestContext(), m_definition, inputClipName, false);
589
590 std::string outputClipName("");
591 buildClipName(getTestContext(), m_definition, outputClipName, true);
592
593 args.push_back("vk-gl-cts"); //args needs the appname as a first argument
594 args.push_back("-i");
595 args.push_back(inputClipName.c_str());
596 args.push_back("-o");
597 args.push_back(outputClipName.c_str());
598
599 args.push_back("--deviceID");
600 ss << std::hex << getPhysicalDeviceProperties(ctx.getInstanceInterface(), ctx.getPhysicalDevice()).deviceID;
601 deviceID = ss.str();
602 args.push_back(deviceID.c_str());
603
604 for (const auto ¶m : encoderParams)
605 {
606 args.push_back(param.c_str());
607 }
608 #if STREAM_DUMP_DEBUG
609 std::cerr << "TEST ARGS: ";
610 for (auto &arg : args)
611 std::cerr << arg << " ";
612 std::cerr << endl;
613 #endif
614 if (!checkClipFileExists(inputClipName))
615 {
616 #ifdef DE_BUILD_VIDEO
617 vkt::video::util::generateYCbCrFile(inputClipName, m_definition.gop.frameCount, m_definition.frameSize.width,
618 m_definition.frameSize.height, m_definition.subsampling.subsampling,
619 m_definition.bitDepth.depth);
620 #endif
621 generatedContent = true;
622 }
623
624 VkExtent2D expectedOutputExtent = {m_definition.frameSize.width, m_definition.frameSize.height};
625 if (codedPictureAlignment.width != 8 || codedPictureAlignment.height != 8)
626 {
627 const auto w = de::roundUp(m_requirements.width, 8U);
628 const auto h = de::roundUp(m_requirements.height, 8U);
629
630 expectedOutputExtent.width = de::roundUp(w, codedPictureAlignment.width);
631 expectedOutputExtent.height = de::roundUp(h, codedPictureAlignment.height);
632 }
633 #ifdef DE_BUILD_VIDEO
634 VkResult result = CreateVulkanVideoEncoder(m_requirements.codecOperation, static_cast<int>(args.size()),
635 const_cast<char **>(args.data()), encoder);
636 if (result != VK_SUCCESS)
637 {
638 throw tcu::TestError("Failed to create VulkanVideoEncoder");
639 }
640 #endif
641 testInstance =
642 new VideoTestInstance(ctx, inputClipName, outputClipName, expectedOutputExtent, m_definition, generatedContent);
643 #ifdef DE_BUILD_VIDEO
644 testInstance->setEncoder(encoder);
645 #endif
646 return testInstance;
647 }
648
checkSupport(Context & ctx) const649 void VideoTestCase::checkSupport(Context &ctx) const
650 {
651 for (const auto &extension : m_requirements.extensions)
652 {
653 if (!ctx.isDeviceFunctionalitySupported(extension.c_str()))
654 {
655 throw tcu::NotSupportedError("Required extension " + extension + " not supported");
656 }
657 }
658
659 try
660 {
661 validateCapabilities(ctx);
662 }
663 catch (const tcu::NotSupportedError &e)
664 {
665 throw tcu::NotSupportedError(std::string("Capability check failed: ") + e.what());
666 }
667 }
668
validateCapabilities(Context & context) const669 void VideoTestCase::validateCapabilities(Context &context) const
670 {
671 const VkVideoCodecOperationFlagBitsKHR videoCodecEncodeOperation = m_requirements.codecOperation;
672 const VkImageUsageFlags usageFlag = VK_VIDEO_ENCODE_USAGE_DEFAULT_KHR;
673 const VkImageUsageFlags imageFlag = VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR;
674
675 const VkVideoEncodeAV1ProfileInfoKHR encodeProfileInfo = {
676 VK_STRUCTURE_TYPE_VIDEO_ENCODE_AV1_PROFILE_INFO_KHR, // sType
677 nullptr, // pNext
678 STD_VIDEO_AV1_PROFILE_MAIN // stdProfile
679 };
680
681 de::MovePtr<VkVideoEncodeAV1ProfileInfoKHR> encodeProfile =
682 de::MovePtr<VkVideoEncodeAV1ProfileInfoKHR>(new VkVideoEncodeAV1ProfileInfoKHR(encodeProfileInfo));
683
684 const MovePtr<VkVideoEncodeUsageInfoKHR> encodeUsageInfo = getEncodeUsageInfo(
685 encodeProfile.get(), usageFlag, VK_VIDEO_ENCODE_CONTENT_DEFAULT_KHR, VK_VIDEO_ENCODE_TUNING_MODE_DEFAULT_KHR);
686
687 const MovePtr<VkVideoProfileInfoKHR> videoEncodeProfile =
688 getVideoProfile(videoCodecEncodeOperation, encodeUsageInfo.get(), m_requirements.subSampling,
689 m_requirements.bitDepth, m_requirements.bitDepth);
690
691 const MovePtr<VkVideoProfileListInfoKHR> videoEncodeProfileList = getVideoProfileList(videoEncodeProfile.get(), 1);
692
693 const InstanceInterface &vki = context.getInstanceInterface();
694 const VkPhysicalDevice physicalDevice = context.getPhysicalDevice();
695
696 const MovePtr<VkVideoEncodeAV1CapabilitiesKHR> av1Capabilities = getVideoCapabilitiesExtensionAV1E();
697
698 const MovePtr<VkVideoEncodeCapabilitiesKHR> encodeCapabilities = getVideoEncodeCapabilities(av1Capabilities.get());
699
700 const MovePtr<VkVideoCapabilitiesKHR> videoCapabilities =
701 getVideoCapabilities(vki, physicalDevice, videoEncodeProfile.get(), encodeCapabilities.get());
702
703 if (m_requirements.requireBFrames)
704 {
705 if (av1Capabilities->maxBidirectionalCompoundReferenceCount == 0)
706 throw tcu::NotSupportedError("B frames encoding not supported for AV1");
707 }
708
709 if (m_requirements.useVariableBitrate &&
710 !(encodeCapabilities->rateControlModes & VK_VIDEO_ENCODE_RATE_CONTROL_MODE_VBR_BIT_KHR))
711 {
712 throw tcu::NotSupportedError("Variable bitrate not supported");
713 }
714
715 if (m_requirements.useConstantBitrate &&
716 !(encodeCapabilities->rateControlModes & VK_VIDEO_ENCODE_RATE_CONTROL_MODE_CBR_BIT_KHR))
717 {
718 throw tcu::NotSupportedError("Constant bitrate not supported");
719 }
720
721 if (!(av1Capabilities->superblockSizes & m_requirements.superblockSizes))
722 {
723 throw tcu::NotSupportedError("Required superblock size not supported");
724 }
725
726 if (m_requirements.width > videoCapabilities->maxCodedExtent.width ||
727 m_requirements.height > videoCapabilities->maxCodedExtent.height)
728 {
729 throw tcu::NotSupportedError("Required dimensions exceed maxCodedExtent");
730 }
731
732 if (m_requirements.width < videoCapabilities->minCodedExtent.width ||
733 m_requirements.height < videoCapabilities->minCodedExtent.height)
734 {
735 throw tcu::NotSupportedError("Required dimensions are smaller than minCodedExtent");
736 }
737
738 if (!m_requirements.useDpbArray &&
739 (videoCapabilities->flags & VK_VIDEO_CAPABILITY_SEPARATE_REFERENCE_IMAGES_BIT_KHR) == 0)
740 {
741 throw tcu::NotSupportedError("Separate DPB images not supported");
742 }
743
744 if (m_requirements.maxTileColumns > 0 || m_requirements.maxTileRows > 0)
745 {
746 uint32_t minTileWidth =
747 (m_requirements.width + m_requirements.maxTileColumns - 1) / m_requirements.maxTileColumns;
748 uint32_t minTileHeight = (m_requirements.height + m_requirements.maxTileRows - 1) / m_requirements.maxTileRows;
749
750 if (minTileWidth < av1Capabilities->minTileSize.width || minTileHeight < av1Capabilities->minTileSize.height)
751 {
752 throw tcu::NotSupportedError("Required tile dimensions are smaller than minTileSize");
753 }
754
755 if (m_requirements.width > av1Capabilities->maxTiles.width * av1Capabilities->maxTileSize.width ||
756 m_requirements.height > av1Capabilities->maxTiles.height * av1Capabilities->maxTileSize.height)
757 {
758 throw tcu::NotSupportedError("Required dimensions exceed maximum possible tiled area");
759 }
760 }
761
762 MovePtr<vector<VkFormat>> supportedFormats =
763 getSupportedFormats(vki, physicalDevice, imageFlag, videoEncodeProfileList.get());
764
765 if (!supportedFormats || supportedFormats->empty())
766 TCU_THROW(NotSupportedError, "No supported picture formats");
767
768 bool formatFound = false;
769 for (const auto &supportedFormat : *supportedFormats)
770 {
771 if (isXChromaSubsampled(supportedFormat) != m_requirements.isXSubsampled ||
772 isYChromaSubsampled(supportedFormat) != m_requirements.isYSubsampled)
773 {
774 continue;
775 }
776
777 tcu::UVec4 formatColorDepth = getYCbCrBitDepth(supportedFormat);
778 if (formatColorDepth != m_requirements.colorDepth)
779 {
780 continue;
781 }
782
783 // TODO nessery ?
784 // uint32_t channelCount = getYCbCrFormatChannelCount(supportedFormat);
785 // if (channelCount < 3) // Assuming we need at least 3 channels (Y, Cb, Cr)
786 // {
787 // continue;
788 // }
789
790 formatFound = true;
791 break;
792 }
793
794 if (!formatFound)
795 TCU_THROW(NotSupportedError,
796 "No supported format found matching the required chroma subsampling and color depth");
797
798 codedPictureAlignment = av1Capabilities->codedPictureAlignment;
799 }
800
createVideoTestCase(tcu::TestContext & testCtx,const char * testname,const TestRequirements & requirements,const TestDefinition & definition)801 VideoTestCase *createVideoTestCase(tcu::TestContext &testCtx, const char *testname,
802 const TestRequirements &requirements, const TestDefinition &definition)
803 {
804 VideoTestCase *testCase = new VideoTestCase(testCtx, testname, requirements, definition);
805 return testCase;
806 }
807
validateTestDefinition(const TestDefinition & testDef)808 bool validateTestDefinition(const TestDefinition &testDef)
809 {
810 // Here we check for invalid or unsupported combinations of test
811 // parameters.
812
813 // Not supported by vendors
814 if (testDef.subsampling.subsampling != CHROMA_SS_420)
815 return false;
816
817 // Not supported by vendors
818 if (testDef.bitDepth.depth == BIT_DEPTH_12)
819 return false;
820
821 // Superblocks: only 64x64 supported for now
822 if (testDef.superblock.superblock != SUPERBLOCK_64x64)
823 return false;
824
825 // Resolution change: only 64x64 supported for now
826 if (testDef.resolutionChange.resolutionChange != RESOLUTION_NO_CHANGE)
827 return false;
828
829 // ordering out of order only supported with I_P_B and 3 B-Frames
830 if (testDef.ordering.order == UNORDERED && testDef.gop.gop != GOP_IDR_P_B && testDef.gop.consecutiveBFrames != 3)
831 return false;
832
833 // The Qindex test should be performed only when rate control is disabled
834 if (testDef.quantization.qIndex != QINDEX_NONE && testDef.rateControl.rc != RC_DISABLED)
835 return false;
836
837 // The nested combination of tests should be performed only with 720x780
838 if (testDef.frameSize.width != 720 && testDef.frameSize.height != 480 &&
839 (testDef.ordering.order != ORDERED || testDef.resolutionChange.resolutionChange != RESOLUTION_NO_CHANGE ||
840 testDef.quantization.qIndex != QINDEX_NONE || testDef.superblock.superblock != SUPERBLOCK_64x64 ||
841 testDef.rateControl.rc != RC_DEFAULT || testDef.loopFilter.lf != LF_OFF || testDef.loopRestore.lr != LR_OFF ||
842 testDef.cdef.cdef != CDEF_OFF || testDef.dpbMode.mode != DPB_MODE_SEPARATE))
843 return false;
844
845 // Test only GOP_I_P_B in the case of resolution different from 720x780
846 if (testDef.frameSize.width != 720 && testDef.frameSize.height != 480 && (testDef.gop.gop != GOP_I_P_B))
847 return false;
848
849 // Remove TILING_1x2 from 7680x4320 resolution as it is not supported by the AV1 specification
850 // See MAX_TILE_WIDTH in https://aomediacodec.github.io/av1-spec/av1-spec.pdf
851 if (testDef.frameSize.width == 7680 && testDef.frameSize.height == 4320 && (testDef.tiling.tiling == TILING_1x2))
852 return false;
853
854 return true;
855 }
856
checkClipFileExists(const std::string & clipName)857 bool checkClipFileExists(const std::string &clipName)
858 {
859 ifstream f(clipName.c_str());
860 return f.good();
861 }
862
removeClip(const std::string & clipName)863 void removeClip(const std::string &clipName)
864 {
865 try
866 {
867 std::filesystem::remove(clipName);
868 }
869 catch (const std::filesystem::filesystem_error &e)
870 {
871 std::cerr << "Error deleting file: " << e.what() << std::endl;
872 }
873 }
874
addSubName(std::ostringstream & s,const char * subName)875 inline void addSubName(std::ostringstream &s, const char *subName)
876 {
877 if (strlen(subName) != 0)
878 {
879 if (s.str() != "")
880 s << "_";
881 s << subName;
882 }
883 }
884
buildTestName(const TestDefinition & testDef,std::string & testName)885 void buildTestName(const TestDefinition &testDef, std::string &testName)
886 {
887 std::ostringstream s;
888
889 addSubName(s, testDef.ordering.subName);
890 addSubName(s, testDef.resolutionChange.subName);
891 addSubName(s, testDef.quantization.subName);
892 addSubName(s, testDef.tiling.subName);
893 addSubName(s, testDef.superblock.subName);
894 addSubName(s, testDef.rateControl.subName);
895 addSubName(s, testDef.loopFilter.subName);
896 addSubName(s, testDef.loopRestore.subName);
897 addSubName(s, testDef.cdef.subName);
898 addSubName(s, testDef.dpbMode.subName);
899
900 testName = s.str();
901 if (testName == "")
902 testName = "default";
903 }
904
buildTestRequirements(const TestDefinition & testDef,TestRequirements & requirements)905 void buildTestRequirements(const TestDefinition &testDef, TestRequirements &requirements)
906 {
907 requirements.extensions.push_back("VK_KHR_video_queue");
908 requirements.extensions.push_back("VK_KHR_video_encode_queue");
909 requirements.extensions.push_back("VK_KHR_video_encode_av1");
910
911 requirements.codecOperation = VK_VIDEO_CODEC_OPERATION_ENCODE_AV1_BIT_KHR;
912
913 requirements.width = testDef.frameSize.width;
914 requirements.height = testDef.frameSize.height;
915
916 requirements.bitDepth = getBitDepth(testDef.bitDepth.depth);
917 requirements.subSampling = getChromaSubSampling(testDef.subsampling.subsampling);
918
919 requirements.requireBFrames = (testDef.gop.gop == GOP_I_P_B || testDef.gop.gop == GOP_IDR_P_B);
920
921 requirements.useVariableBitrate = (testDef.quantization.qIndex != 0);
922 requirements.useConstantBitrate = false;
923
924 requirements.superblockSizes = (testDef.superblock.superblock == SUPERBLOCK_64x64) ?
925 VK_VIDEO_ENCODE_AV1_SUPERBLOCK_SIZE_64_BIT_KHR :
926 VK_VIDEO_ENCODE_AV1_SUPERBLOCK_SIZE_128_BIT_KHR;
927
928 requirements.useDpbArray = (testDef.dpbMode.mode == DPB_MODE_LAYERED);
929
930 switch (testDef.tiling.tiling)
931 {
932 case TILING_1_TILE:
933 requirements.maxTileColumns = 1;
934 requirements.maxTileRows = 1;
935 break;
936 case TILING_1x2:
937 requirements.maxTileColumns = 1;
938 requirements.maxTileRows = 2;
939 break;
940 case TILING_4x4:
941 requirements.maxTileColumns = 4;
942 requirements.maxTileRows = 4;
943 break;
944 }
945
946 switch (testDef.subsampling.subsampling)
947 {
948 case CHROMA_SS_400:
949 requirements.isXSubsampled = false;
950 requirements.isYSubsampled = false;
951 break;
952 case CHROMA_SS_420:
953 requirements.isXSubsampled = true;
954 requirements.isYSubsampled = true;
955 break;
956 case CHROMA_SS_422:
957 requirements.isXSubsampled = true;
958 requirements.isYSubsampled = false;
959 break;
960 case CHROMA_SS_444:
961 requirements.isXSubsampled = false;
962 requirements.isYSubsampled = false;
963 break;
964 }
965
966 switch (testDef.bitDepth.depth)
967 {
968 case BIT_DEPTH_8:
969 requirements.colorDepth = tcu::UVec4(8, 8, 8, 0);
970 break;
971 case BIT_DEPTH_10:
972 requirements.colorDepth = tcu::UVec4(10, 10, 10, 0);
973 break;
974 case BIT_DEPTH_12:
975 requirements.colorDepth = tcu::UVec4(12, 12, 12, 0);
976 break;
977 }
978 }
979
980 } // namespace
981
createVideoEncodeTestAV1(tcu::TestContext & testCtx,const TestDefinition & testDef)982 VideoTestCase *createVideoEncodeTestAV1(tcu::TestContext &testCtx, const TestDefinition &testDef)
983 {
984 // Discard invalid or unsupported combinations
985 if (!validateTestDefinition(testDef))
986 return nullptr;
987
988 std::string testName("");
989 buildTestName(testDef, testName);
990
991 TestRequirements requirements;
992 buildTestRequirements(testDef, requirements);
993
994 auto testCase = createVideoTestCase(testCtx, testName.c_str(), requirements, testDef);
995
996 return testCase;
997 }
998
999 // Test definitions
1000
1001 static const std::vector<FrameSizeDef> frameSizeTests = {
1002 {"", 128, 128}, {"", 176, 144}, {"", 352, 288}, {"", 720, 480},
1003 {"", 1920, 1080}, {"", 3840, 2160}, {"", 7680, 4320},
1004 };
1005
1006 static const std::vector<BitDepthDef> bitDepthTests = {
1007 {BIT_DEPTH_8, "8le"},
1008 {BIT_DEPTH_10, "10le"},
1009 {BIT_DEPTH_12, "12le"},
1010 };
1011
1012 static const std::vector<ChromaSubsamplingDef> subsamplingTests = {
1013 {CHROMA_SS_400, "400"},
1014 {CHROMA_SS_420, "420"},
1015 {CHROMA_SS_422, "422"},
1016 {CHROMA_SS_444, "444"},
1017 };
1018
1019 static const std::vector<GOPDef> gopTests = {
1020 {15, GOP_I, false, 1, 0, "i"},
1021 {15, GOP_I_P, false, 2, 0, "i_p"},
1022 {15, GOP_I_P, true, 2, 0, "i_p_open"},
1023 {15, GOP_I_P_B, false, 13, 3, "i_p_b3_13"},
1024 {15, GOP_IDR_P_B, false, 13, 3, "idr_p_b3_13"},
1025 };
1026
1027 static const std::vector<OrderingDef> orderingTests = {
1028 {ORDERED, ""},
1029 {UNORDERED, "unordered"},
1030 };
1031
1032 static const std::vector<ResolutionChangeDef> resolutionChangeTests = {
1033 {RESOLUTION_NO_CHANGE, ""},
1034 {RESOLUTION_TO_LARGER, "res_to_larger"},
1035 {RESOLUTION_TO_SMALLER, "res_to_smaller"},
1036 };
1037
1038 static const std::vector<QuantizationDef> quantizationTests = {
1039 {QINDEX_NONE, ""}, {QINDEX_64, "qindex64"}, {QINDEX_128, "qindex128"},
1040 {QINDEX_192, "qindex192"}, {QINDEX_255, "qindex255"},
1041 };
1042
1043 static const std::vector<TilingDef> tilingTests = {
1044 {TILING_1_TILE, ""},
1045 {TILING_1x2, "tiling_1x2"},
1046 {TILING_4x4, "tiling_4x4"},
1047 };
1048
1049 static const std::vector<SuperblockDef> superblockTests = {
1050 {SUPERBLOCK_64x64, ""},
1051 {SUPERBLOCK_128x128, "superblocks_128x128"},
1052 };
1053
1054 static const std::vector<RateControlDef> rateControlTests = {
1055 {RC_DEFAULT, ""},
1056 {RC_DISABLED, "rc_disabled"},
1057 {RC_CBR, "rc_cbr"},
1058 {RC_VBR, "rc_vbr"},
1059 };
1060
1061 static const std::vector<LoopFilterDef> lfTests = {
1062 {LF_OFF, ""},
1063 {LF_ON, "lf"},
1064 };
1065
1066 static const std::vector<LoopRestoreDef> lrTests = {
1067 {LR_OFF, ""},
1068 {LR_ON, "lr"},
1069 };
1070
1071 static const std::vector<CDEFDef> cdefTests = {
1072 {CDEF_OFF, ""},
1073 {CDEF_ON, "cdef"},
1074 };
1075
1076 static const std::vector<DpbModeDef> dpbModeTests = {
1077 {DPB_MODE_SEPARATE, ""},
1078 {DPB_MODE_LAYERED, "layered_dpb"},
1079 };
1080
createVideoEncodeTestsAV1(tcu::TestContext & testCtx)1081 tcu::TestCaseGroup *createVideoEncodeTestsAV1(tcu::TestContext &testCtx)
1082 {
1083 MovePtr<tcu::TestCaseGroup> av1group(new tcu::TestCaseGroup(testCtx, "av1", "AV1 video codec"));
1084 std::ostringstream s;
1085 std::string groupName;
1086
1087 // Combine all tests types into a TestDefinition struct
1088 for (const auto &frameSizeTest : frameSizeTests)
1089 for (const auto &bitDepthTest : bitDepthTests)
1090 for (const auto &subsamplingTest : subsamplingTests)
1091 {
1092 s.str("");
1093 s << frameSizeTest.width << "x" << frameSizeTest.height;
1094 s << "_" << bitDepthTest.subName;
1095 s << "_" << subsamplingTest.subName;
1096 groupName = s.str();
1097 MovePtr<tcu::TestCaseGroup> resGroup(new tcu::TestCaseGroup(testCtx, groupName.c_str()));
1098
1099 for (const auto &gopTest : gopTests)
1100 {
1101 s.str("");
1102 s << gopTest.subName << "_" << gopTest.frameCount;
1103 groupName = s.str();
1104 MovePtr<tcu::TestCaseGroup> gopGroup(new tcu::TestCaseGroup(testCtx, groupName.c_str()));
1105 for (const auto &tilingTest : tilingTests)
1106 {
1107 for (const auto &orderingTest : orderingTests)
1108 for (const auto &resolutionChangeTest : resolutionChangeTests)
1109 for (const auto &quantizationTest : quantizationTests)
1110 for (const auto &superblockTest : superblockTests)
1111 for (const auto &rateControlTest : rateControlTests)
1112 for (const auto &lfTest : lfTests)
1113 for (const auto &lrTest : lrTests)
1114 for (const auto &cdefTest : cdefTests)
1115 for (const auto &dpbModeTest : dpbModeTests)
1116 {
1117 TestDefinition testDef = {
1118 frameSizeTest, bitDepthTest, subsamplingTest,
1119 gopTest, orderingTest, resolutionChangeTest,
1120 quantizationTest, tilingTest, superblockTest,
1121 rateControlTest, lfTest, lrTest,
1122 cdefTest, dpbModeTest};
1123 auto testCase = createVideoEncodeTestAV1(testCtx, testDef);
1124 if (testCase != nullptr)
1125 gopGroup->addChild(testCase);
1126 }
1127 }
1128 resGroup->addChild(gopGroup.release());
1129 }
1130 av1group->addChild(resGroup.release());
1131 }
1132 return av1group.release();
1133 }
1134 } // namespace video
1135 } // namespace vkt
1136