• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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> &params)
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 &param : 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