• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2023 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 Video decoding tests
23  */
24 /*--------------------------------------------------------------------*/
25 
26 #include <utility>
27 #include <memory>
28 
29 #include "deDefs.h"
30 #include "deFilePath.hpp"
31 #include "deStringUtil.hpp"
32 
33 #include "tcuTestLog.hpp"
34 #include "tcuCommandLine.hpp"
35 
36 #include "vkDefs.hpp"
37 #include "vktVideoDecodeTests.hpp"
38 #include "vktVideoTestUtils.hpp"
39 #include "vkBarrierUtil.hpp"
40 #include "vkObjUtil.hpp"
41 #include "vkCmdUtil.hpp"
42 #include "vkImageUtil.hpp"
43 
44 #include "vktVideoClipInfo.hpp"
45 
46 #ifdef DE_BUILD_VIDEO
47 #include "vktVideoBaseDecodeUtils.hpp"
48 #include <VulkanH264Decoder.h>
49 #include <VulkanH265Decoder.h>
50 #include <VulkanAV1Decoder.h>
51 #endif
52 
53 namespace vkt
54 {
55 namespace video
56 {
57 #ifdef DE_BUILD_VIDEO
58 // Set this to 1 to have the decoded YCbCr frames written to the
59 // filesystem in the YV12 format.
60 // Check the relevant sections to change the file name and so on...
61 static constexpr bool debug_WriteOutFramesToSingleFile = false;
62 // Default behaviour is to write all decoded frames to one
63 // file. Setting this to 1 will output each frame to its own file.
64 static constexpr bool debug_WriteOutFramesToSeparateFiles = false;
65 // If true, the dumped frames will contain the results of decoding
66 // with filmgrain as expected. When false, `apply_grain` is forced to
67 // zero, resulting in dumped frames having no post-processing
68 // applied. This is useful for debugging the filmgrain process. Only
69 // AV1 has been considered so far.
70 static constexpr bool debug_WriteOutFilmGrain = true;
71 
72 static_assert(!(debug_WriteOutFramesToSingleFile && debug_WriteOutFramesToSeparateFiles));
73 
74 static constexpr double kFilmgrainPSNRLowerBound = 28.0;
75 static constexpr double kFilmgrainPSNRUpperBound = 34.0;
76 
FrameProcessor(std::shared_ptr<Demuxer> && demuxer,std::shared_ptr<VideoBaseDecoder> decoder)77 FrameProcessor::FrameProcessor(std::shared_ptr<Demuxer> &&demuxer, std::shared_ptr<VideoBaseDecoder> decoder)
78     : m_decoder(decoder)
79     , m_demuxer(std::move(demuxer))
80 {
81     // TOOD: The parser interface is most unfortunate, it's as close
82     // as inside-out to our needs as you can get. Eventually integrate
83     // it more cleanly into the CTS.
84     createParser(m_demuxer->codecOperation(), m_decoder, m_parser, m_demuxer->framing());
85 }
86 
parseNextChunk()87 void FrameProcessor::parseNextChunk()
88 {
89     std::vector<uint8_t> demuxedPacket = m_demuxer->nextPacket();
90 
91     VkParserBitstreamPacket pkt;
92     pkt.pByteStream     = demuxedPacket.data();
93     pkt.nDataLength     = demuxedPacket.size();
94     pkt.llPTS           = 0;                         // Irrelevant for CTS
95     pkt.bEOS            = demuxedPacket.size() == 0; // true if this is an End-Of-Stream packet (flush everything)
96     pkt.bPTSValid       = false;                     // Irrelevant for CTS
97     pkt.bDiscontinuity  = false;                     // Irrelevant for CTS
98     pkt.bPartialParsing = false;                     // false: parse entire packet, true: parse until next
99     pkt.bEOP            = false;                     // Irrelevant for CTS
100     pkt.pbSideData      = nullptr;                   // Irrelevant for CTS
101     pkt.nSideDataLength = 0;                         // Irrelevant for CTS
102 
103     size_t parsedBytes       = 0;
104     const bool parserSuccess = m_parser->ParseByteStream(&pkt, &parsedBytes);
105     m_eos                    = demuxedPacket.size() == 0 || !parserSuccess;
106 }
107 
getNextFrame(DecodedFrame * pFrame)108 int FrameProcessor::getNextFrame(DecodedFrame *pFrame)
109 {
110     int32_t framesInQueue = m_decoder->GetVideoFrameBuffer()->DequeueDecodedPicture(pFrame);
111     while (!framesInQueue && !m_eos)
112     {
113         parseNextChunk();
114         framesInQueue = m_decoder->GetVideoFrameBuffer()->DequeueDecodedPicture(pFrame);
115     }
116 
117     if (!framesInQueue && !m_eos)
118     {
119         return -1;
120     }
121 
122     return framesInQueue;
123 }
124 
bufferFrames(int framesToDecode)125 void FrameProcessor::bufferFrames(int framesToDecode)
126 {
127     // This loop is for the out-of-order submissions cases. First the
128     // requisite frame information is gathered from the
129     // parser<->decoder loop.
130     // Then the command buffers are recorded in a random order w.r.t
131     // original coding order. Queue submissions are always in coding
132     // order.
133     // NOTE: For this sequence to work, the frame buffer must have
134     // enough decode surfaces for the GOP intended for decode,
135     // otherwise picture allocation will fail pretty quickly! See
136     // m_numDecodeSurfaces, m_maxDecodeFramesCount
137     // NOTE: When requesting two frames to be buffered, it's only
138     // guaranteed in the successful case you will get 2 *or more*
139     // frames for decode.  This is due to the inter-frame references,
140     // where the second frame, for example, may need further coded
141     // frames as dependencies.
142     DE_ASSERT(m_decoder->m_outOfOrderDecoding);
143     do
144     {
145         parseNextChunk();
146         size_t decodedFrames = m_decoder->GetVideoFrameBuffer()->GetDisplayedFrameCount();
147         if (decodedFrames >= framesToDecode)
148             break;
149     } while (!m_eos);
150     auto &cachedParams = m_decoder->m_cachedDecodeParams;
151     TCU_CHECK_MSG(cachedParams.size() >= framesToDecode, "Unknown decoder failure");
152 }
153 #endif
154 
155 namespace
156 {
157 using namespace vk;
158 using de::MovePtr;
159 
160 enum TestType
161 {
162     TEST_TYPE_H264_DECODE_I,   // Case 6
163     TEST_TYPE_H264_DECODE_I_P, // Case 7
164     TEST_TYPE_H264_DECODE_CLIP_A,
165     TEST_TYPE_H264_DECODE_I_P_B_13,                    // Case 7a
166     TEST_TYPE_H264_DECODE_I_P_NOT_MATCHING_ORDER,      // Case 8
167     TEST_TYPE_H264_DECODE_I_P_B_13_NOT_MATCHING_ORDER, // Case 8a
168     TEST_TYPE_H264_DECODE_QUERY_RESULT_WITH_STATUS,    // Case 9
169     TEST_TYPE_H264_DECODE_INLINE_QUERY_RESULT_WITH_STATUS,
170     TEST_TYPE_H264_DECODE_RESOURCES_WITHOUT_PROFILES,
171     TEST_TYPE_H264_DECODE_RESOLUTION_CHANGE,       // Case 17
172     TEST_TYPE_H264_DECODE_RESOLUTION_CHANGE_DPB,   // Case 18
173     TEST_TYPE_H264_DECODE_INTERLEAVED,             // Case 21
174     TEST_TYPE_H264_BOTH_DECODE_ENCODE_INTERLEAVED, // Case 23 TODO
175     TEST_TYPE_H264_H265_DECODE_INTERLEAVED,        // Case 24
176 
177     TEST_TYPE_H265_DECODE_I,   // Case 15
178     TEST_TYPE_H265_DECODE_I_P, // Case 16
179     TEST_TYPE_H265_DECODE_CLIP_D,
180     TEST_TYPE_H265_DECODE_I_P_NOT_MATCHING_ORDER,      // Case 16-2
181     TEST_TYPE_H265_DECODE_I_P_B_13,                    // Case 16-3
182     TEST_TYPE_H265_DECODE_I_P_B_13_NOT_MATCHING_ORDER, // Case 16-4
183     TEST_TYPE_H265_DECODE_QUERY_RESULT_WITH_STATUS,
184     TEST_TYPE_H265_DECODE_INLINE_QUERY_RESULT_WITH_STATUS,
185     TEST_TYPE_H265_DECODE_RESOURCES_WITHOUT_PROFILES,
186     TEST_TYPE_H265_DECODE_SLIST_A,
187     TEST_TYPE_H265_DECODE_SLIST_B,
188 
189     TEST_TYPE_AV1_DECODE_I,
190     TEST_TYPE_AV1_DECODE_I_P,
191     TEST_TYPE_AV1_DECODE_I_P_NOT_MATCHING_ORDER,
192     TEST_TYPE_AV1_DECODE_BASIC_8,
193     TEST_TYPE_AV1_DECODE_BASIC_8_NOT_MATCHING_ORDER,
194     TEST_TYPE_AV1_DECODE_ALLINTRA_8,
195     TEST_TYPE_AV1_DECODE_ALLINTRA_NOSETUP_8,
196     TEST_TYPE_AV1_DECODE_ALLINTRA_BC_8,
197     TEST_TYPE_AV1_DECODE_CDFUPDATE_8,
198     TEST_TYPE_AV1_DECODE_GLOBALMOTION_8,
199     TEST_TYPE_AV1_DECODE_FILMGRAIN_8,
200     TEST_TYPE_AV1_DECODE_SVCL1T2_8,
201     TEST_TYPE_AV1_DECODE_SUPERRES_8,
202     TEST_TYPE_AV1_DECODE_SIZEUP_8,
203 
204     TEST_TYPE_AV1_DECODE_BASIC_10,
205     TEST_TYPE_AV1_DECODE_ORDERHINT_10,
206     TEST_TYPE_AV1_DECODE_FORWARDKEYFRAME_10,
207     TEST_TYPE_AV1_DECODE_LOSSLESS_10,
208     TEST_TYPE_AV1_DECODE_LOOPFILTER_10,
209     TEST_TYPE_AV1_DECODE_CDEF_10,
210     TEST_TYPE_AV1_DECODE_ARGON_FILMGRAIN_10,
211     TEST_TYPE_AV1_DECODE_ARGON_TEST_787,
212 
213     TEST_TYPE_AV1_DECODE_ARGON_SEQCHANGE_AFFINE_8,
214 
215     TEST_TYPE_LAST
216 };
217 
218 enum TestCodec
219 {
220     TEST_CODEC_H264,
221     TEST_CODEC_H265,
222     TEST_CODEC_AV1,
223 
224     TEST_CODEC_LAST
225 };
226 
testTypeToStr(TestType type)227 static const char *testTypeToStr(TestType type)
228 {
229     const char *testName;
230     switch (type)
231     {
232     case TEST_TYPE_H264_DECODE_I:
233     case TEST_TYPE_H265_DECODE_I:
234     case TEST_TYPE_AV1_DECODE_I:
235         testName = "i";
236         break;
237     case TEST_TYPE_H264_DECODE_I_P:
238     case TEST_TYPE_H265_DECODE_I_P:
239     case TEST_TYPE_AV1_DECODE_I_P:
240         testName = "i_p";
241         break;
242     case TEST_TYPE_H264_DECODE_CLIP_A:
243         testName = "420_8bit_high_176x144_30frames";
244         break;
245     case TEST_TYPE_H264_DECODE_I_P_NOT_MATCHING_ORDER:
246     case TEST_TYPE_H265_DECODE_I_P_NOT_MATCHING_ORDER:
247     case TEST_TYPE_AV1_DECODE_I_P_NOT_MATCHING_ORDER:
248         testName = "i_p_not_matching_order";
249         break;
250     case TEST_TYPE_H264_DECODE_I_P_B_13:
251     case TEST_TYPE_H265_DECODE_I_P_B_13:
252         testName = "i_p_b_13";
253         break;
254     case TEST_TYPE_H264_DECODE_I_P_B_13_NOT_MATCHING_ORDER:
255     case TEST_TYPE_H265_DECODE_I_P_B_13_NOT_MATCHING_ORDER:
256         testName = "i_p_b_13_not_matching_order";
257         break;
258     case TEST_TYPE_H264_DECODE_QUERY_RESULT_WITH_STATUS:
259     case TEST_TYPE_H265_DECODE_QUERY_RESULT_WITH_STATUS:
260         testName = "query_with_status";
261         break;
262     case TEST_TYPE_H264_DECODE_INLINE_QUERY_RESULT_WITH_STATUS:
263     case TEST_TYPE_H265_DECODE_INLINE_QUERY_RESULT_WITH_STATUS:
264         testName = "inline_query_with_status";
265         break;
266     case TEST_TYPE_H264_DECODE_RESOURCES_WITHOUT_PROFILES:
267     case TEST_TYPE_H265_DECODE_RESOURCES_WITHOUT_PROFILES:
268         testName = "resources_without_profiles";
269         break;
270     case TEST_TYPE_H264_DECODE_RESOLUTION_CHANGE:
271         testName = "resolution_change";
272         break;
273     case TEST_TYPE_H264_DECODE_RESOLUTION_CHANGE_DPB:
274         testName = "resolution_change_dpb";
275         break;
276     case TEST_TYPE_H264_DECODE_INTERLEAVED:
277         testName = "interleaved";
278         break;
279     case TEST_TYPE_H264_H265_DECODE_INTERLEAVED:
280         testName = "h265_interleaved";
281         break;
282     case TEST_TYPE_H265_DECODE_CLIP_D:
283         testName = "420_8bit_main_176x144_30frames";
284         break;
285     case TEST_TYPE_H265_DECODE_SLIST_A:
286         testName = "slist_a";
287         break;
288     case TEST_TYPE_H265_DECODE_SLIST_B:
289         testName = "slist_b";
290         break;
291     case TEST_TYPE_AV1_DECODE_BASIC_8:
292         testName = "basic_8";
293         break;
294     case TEST_TYPE_AV1_DECODE_BASIC_8_NOT_MATCHING_ORDER:
295         testName = "basic_8_not_matching_order";
296         break;
297     case TEST_TYPE_AV1_DECODE_BASIC_10:
298         testName = "basic_10";
299         break;
300     case TEST_TYPE_AV1_DECODE_ALLINTRA_8:
301         testName = "allintra_8";
302         break;
303     case TEST_TYPE_AV1_DECODE_ALLINTRA_NOSETUP_8:
304         testName = "allintra_nosetup_8";
305         break;
306     case TEST_TYPE_AV1_DECODE_ALLINTRA_BC_8:
307         testName = "allintrabc_8";
308         break;
309     case TEST_TYPE_AV1_DECODE_CDFUPDATE_8:
310         testName = "cdfupdate_8";
311         break;
312     case TEST_TYPE_AV1_DECODE_GLOBALMOTION_8:
313         testName = "globalmotion_8";
314         break;
315     case TEST_TYPE_AV1_DECODE_FILMGRAIN_8:
316         testName = "filmgrain_8";
317         break;
318     case TEST_TYPE_AV1_DECODE_SVCL1T2_8:
319         testName = "svcl1t2_8";
320         break;
321     case TEST_TYPE_AV1_DECODE_SUPERRES_8:
322         testName = "superres_8";
323         break;
324     case TEST_TYPE_AV1_DECODE_SIZEUP_8:
325         testName = "sizeup_8";
326         break;
327     case TEST_TYPE_AV1_DECODE_ARGON_SEQCHANGE_AFFINE_8:
328         testName = "argon_seqchange_affine_8";
329         break;
330     case TEST_TYPE_AV1_DECODE_ORDERHINT_10:
331         testName = "orderhint_10";
332         break;
333     case TEST_TYPE_AV1_DECODE_FORWARDKEYFRAME_10:
334         testName = "forwardkeyframe_10";
335         break;
336     case TEST_TYPE_AV1_DECODE_LOSSLESS_10:
337         testName = "lossless_10";
338         break;
339     case TEST_TYPE_AV1_DECODE_LOOPFILTER_10:
340         testName = "loopfilter_10";
341         break;
342     case TEST_TYPE_AV1_DECODE_CDEF_10:
343         testName = "cdef_10";
344         break;
345     case TEST_TYPE_AV1_DECODE_ARGON_FILMGRAIN_10:
346         testName = "argon_filmgrain_10_test1019";
347         break;
348     case TEST_TYPE_AV1_DECODE_ARGON_TEST_787:
349         testName = "argon_test787";
350         break;
351     default:
352         TCU_THROW(InternalError, "Unknown TestType");
353     }
354     return testName;
355 }
356 
getTestCodec(const TestType testType)357 enum TestCodec getTestCodec(const TestType testType)
358 {
359     switch (testType)
360     {
361     case TEST_TYPE_H264_DECODE_I:
362     case TEST_TYPE_H264_DECODE_I_P:
363     case TEST_TYPE_H264_DECODE_CLIP_A:
364     case TEST_TYPE_H264_DECODE_I_P_NOT_MATCHING_ORDER:
365     case TEST_TYPE_H264_DECODE_I_P_B_13:
366     case TEST_TYPE_H264_DECODE_I_P_B_13_NOT_MATCHING_ORDER:
367     case TEST_TYPE_H264_DECODE_QUERY_RESULT_WITH_STATUS:
368     case TEST_TYPE_H264_DECODE_INLINE_QUERY_RESULT_WITH_STATUS:
369     case TEST_TYPE_H264_DECODE_RESOURCES_WITHOUT_PROFILES:
370     case TEST_TYPE_H264_DECODE_RESOLUTION_CHANGE:
371     case TEST_TYPE_H264_DECODE_RESOLUTION_CHANGE_DPB:
372     case TEST_TYPE_H264_DECODE_INTERLEAVED:
373     case TEST_TYPE_H264_H265_DECODE_INTERLEAVED:
374         return TEST_CODEC_H264;
375 
376     case TEST_TYPE_H265_DECODE_I:
377     case TEST_TYPE_H265_DECODE_I_P:
378     case TEST_TYPE_H265_DECODE_CLIP_D:
379     case TEST_TYPE_H265_DECODE_I_P_NOT_MATCHING_ORDER:
380     case TEST_TYPE_H265_DECODE_I_P_B_13:
381     case TEST_TYPE_H265_DECODE_I_P_B_13_NOT_MATCHING_ORDER:
382     case TEST_TYPE_H265_DECODE_QUERY_RESULT_WITH_STATUS:
383     case TEST_TYPE_H265_DECODE_INLINE_QUERY_RESULT_WITH_STATUS:
384     case TEST_TYPE_H265_DECODE_RESOURCES_WITHOUT_PROFILES:
385     case TEST_TYPE_H265_DECODE_SLIST_A:
386     case TEST_TYPE_H265_DECODE_SLIST_B:
387         return TEST_CODEC_H265;
388 
389     case TEST_TYPE_AV1_DECODE_I:
390     case TEST_TYPE_AV1_DECODE_I_P:
391     case TEST_TYPE_AV1_DECODE_I_P_NOT_MATCHING_ORDER:
392     case TEST_TYPE_AV1_DECODE_BASIC_8:
393     case TEST_TYPE_AV1_DECODE_BASIC_8_NOT_MATCHING_ORDER:
394     case TEST_TYPE_AV1_DECODE_BASIC_10:
395     case TEST_TYPE_AV1_DECODE_ALLINTRA_8:
396     case TEST_TYPE_AV1_DECODE_ALLINTRA_NOSETUP_8:
397     case TEST_TYPE_AV1_DECODE_ALLINTRA_BC_8:
398     case TEST_TYPE_AV1_DECODE_CDFUPDATE_8:
399     case TEST_TYPE_AV1_DECODE_GLOBALMOTION_8:
400     case TEST_TYPE_AV1_DECODE_FILMGRAIN_8:
401     case TEST_TYPE_AV1_DECODE_SVCL1T2_8:
402     case TEST_TYPE_AV1_DECODE_SUPERRES_8:
403     case TEST_TYPE_AV1_DECODE_SIZEUP_8:
404     case TEST_TYPE_AV1_DECODE_ARGON_SEQCHANGE_AFFINE_8:
405     case TEST_TYPE_AV1_DECODE_ORDERHINT_10:
406     case TEST_TYPE_AV1_DECODE_FORWARDKEYFRAME_10:
407     case TEST_TYPE_AV1_DECODE_LOSSLESS_10:
408     case TEST_TYPE_AV1_DECODE_LOOPFILTER_10:
409     case TEST_TYPE_AV1_DECODE_CDEF_10:
410     case TEST_TYPE_AV1_DECODE_ARGON_FILMGRAIN_10:
411     case TEST_TYPE_AV1_DECODE_ARGON_TEST_787:
412         return TEST_CODEC_AV1;
413 
414     default:
415         TCU_THROW(InternalError, "Unknown TestType");
416     }
417 }
418 
419 enum DecoderOption : uint32_t
420 {
421     // The default is to do nothing additional to ordinary playback.
422     Default = 0,
423     // All decode operations will have their status checked for success (Q2 2023: not all vendors support these)
424     UseStatusQueries = 1 << 0,
425     // Same as above, but tested with inline queries from the video_maintenance1 extension.
426     UseInlineStatusQueries = 1 << 1,
427     // Do not playback the clip in the "normal fashion", instead cached decode parameters for later process
428     // this is primarily used to support out-of-order submission test cases.
429     // It is a limited mode of operation, only able to cache 32 frames. This is ample to test out-of-order recording.
430     CachedDecoding = 1 << 2,
431     // When a parameter object changes the resolution of the test content, and the new video session would otherwise
432     // still be compatible with the last session (for example, larger decode surfaces preceeding smaller decode surfaces,
433     // a frame downsize), force the session to be recreated anyway.
434     RecreateDPBImages = 1 << 3,
435     // Test profile-less resources from the video_mainteance1 extension.
436     ResourcesWithoutProfiles = 1 << 4,
437     FilmGrainPresent         = 1 << 5,
438     IntraOnlyDecoding        = 1 << 6,
439     AnnexB                   = 1 << 7,
440 };
441 
442 static const int ALL_FRAMES = 0;
443 
444 struct BaseDecodeParam
445 {
446     ClipName clip;
447     int framesToCheck;
448     DecoderOption decoderOptions;
449 };
450 
451 struct DecodeTestParam
452 {
453     TestType type;
454     BaseDecodeParam stream;
455 
456 } g_DecodeTests[] = {
457     {TEST_TYPE_H264_DECODE_I, {CLIP_A, 1, DecoderOption::Default}},
458     {TEST_TYPE_H264_DECODE_I_P, {CLIP_A, 2, DecoderOption::Default}},
459     {TEST_TYPE_H264_DECODE_I_P_NOT_MATCHING_ORDER, {CLIP_A, 2, DecoderOption::CachedDecoding}},
460     {TEST_TYPE_H264_DECODE_CLIP_A, {CLIP_A, ALL_FRAMES, DecoderOption::Default}},
461     {TEST_TYPE_H264_DECODE_I_P_B_13, {CLIP_H264_4K_26_IBP_MAIN, ALL_FRAMES, DecoderOption::Default}},
462     {TEST_TYPE_H264_DECODE_I_P_B_13_NOT_MATCHING_ORDER,
463      {CLIP_H264_4K_26_IBP_MAIN, ALL_FRAMES, DecoderOption::CachedDecoding}},
464     {TEST_TYPE_H264_DECODE_QUERY_RESULT_WITH_STATUS, {CLIP_A, ALL_FRAMES, DecoderOption::UseStatusQueries}},
465     {TEST_TYPE_H264_DECODE_INLINE_QUERY_RESULT_WITH_STATUS,
466      {CLIP_A, ALL_FRAMES, (DecoderOption)(DecoderOption::UseStatusQueries | DecoderOption::UseInlineStatusQueries)}},
467     {TEST_TYPE_H264_DECODE_RESOURCES_WITHOUT_PROFILES, {CLIP_A, ALL_FRAMES, DecoderOption::ResourcesWithoutProfiles}},
468     {TEST_TYPE_H264_DECODE_RESOLUTION_CHANGE, {CLIP_C, ALL_FRAMES, DecoderOption::Default}},
469     {TEST_TYPE_H264_DECODE_RESOLUTION_CHANGE_DPB, {CLIP_C, ALL_FRAMES, DecoderOption::RecreateDPBImages}},
470 
471     {TEST_TYPE_H265_DECODE_I, {CLIP_D, 1, DecoderOption::Default}},
472     {TEST_TYPE_H265_DECODE_I_P, {CLIP_D, 2, DecoderOption::Default}},
473     {TEST_TYPE_H265_DECODE_I_P_NOT_MATCHING_ORDER, {CLIP_D, 2, DecoderOption::CachedDecoding}},
474     {TEST_TYPE_H265_DECODE_I_P_B_13, {CLIP_JELLY_HEVC, ALL_FRAMES, DecoderOption::Default}},
475     {TEST_TYPE_H265_DECODE_I_P_B_13_NOT_MATCHING_ORDER, {CLIP_JELLY_HEVC, ALL_FRAMES, DecoderOption::CachedDecoding}},
476     {TEST_TYPE_H265_DECODE_CLIP_D, {CLIP_D, ALL_FRAMES, DecoderOption::Default}},
477     {TEST_TYPE_H265_DECODE_QUERY_RESULT_WITH_STATUS, {CLIP_D, ALL_FRAMES, DecoderOption::UseStatusQueries}},
478     {TEST_TYPE_H265_DECODE_INLINE_QUERY_RESULT_WITH_STATUS,
479      {CLIP_D, ALL_FRAMES, (DecoderOption)(DecoderOption::UseStatusQueries | DecoderOption::UseInlineStatusQueries)}},
480     {TEST_TYPE_H265_DECODE_RESOURCES_WITHOUT_PROFILES, {CLIP_D, ALL_FRAMES, DecoderOption::ResourcesWithoutProfiles}},
481     {TEST_TYPE_H265_DECODE_SLIST_A, {CLIP_ITU_SLIST_A_HEVC, 28, DecoderOption::Default}},
482     {TEST_TYPE_H265_DECODE_SLIST_B, {CLIP_ITU_SLIST_B_HEVC, 28, DecoderOption::Default}},
483 
484     {TEST_TYPE_AV1_DECODE_I, {CLIP_BASIC_8, 1, DecoderOption::Default}},
485     {TEST_TYPE_AV1_DECODE_I_P, {CLIP_BASIC_8, 2, DecoderOption::Default}},
486     {TEST_TYPE_AV1_DECODE_I_P_NOT_MATCHING_ORDER, {CLIP_BASIC_8, 2, DecoderOption::CachedDecoding}},
487     {TEST_TYPE_AV1_DECODE_BASIC_8, {CLIP_BASIC_8, ALL_FRAMES, DecoderOption::Default}},
488     {TEST_TYPE_AV1_DECODE_BASIC_8_NOT_MATCHING_ORDER, {CLIP_BASIC_8, 24, DecoderOption::CachedDecoding}},
489     {TEST_TYPE_AV1_DECODE_ALLINTRA_8, {CLIP_ALLINTRA_8, ALL_FRAMES, DecoderOption::Default}},
490     {TEST_TYPE_AV1_DECODE_ALLINTRA_NOSETUP_8, {CLIP_ALLINTRA_8, ALL_FRAMES, DecoderOption::IntraOnlyDecoding}},
491     {TEST_TYPE_AV1_DECODE_ALLINTRA_BC_8, {CLIP_ALLINTRA_INTRABC_8, ALL_FRAMES, DecoderOption::Default}},
492     {TEST_TYPE_AV1_DECODE_CDFUPDATE_8, {CLIP_CDFUPDATE_8, ALL_FRAMES, DecoderOption::Default}},
493     {TEST_TYPE_AV1_DECODE_GLOBALMOTION_8, {CLIP_GLOBALMOTION_8, ALL_FRAMES, DecoderOption::Default}},
494     {TEST_TYPE_AV1_DECODE_FILMGRAIN_8, {CLIP_FILMGRAIN_8, ALL_FRAMES, DecoderOption::FilmGrainPresent}},
495     {TEST_TYPE_AV1_DECODE_SVCL1T2_8, {CLIP_SVCL1T2_8, ALL_FRAMES, DecoderOption::Default}},
496     {TEST_TYPE_AV1_DECODE_SUPERRES_8, {CLIP_SUPERRES_8, ALL_FRAMES, DecoderOption::Default}},
497     {TEST_TYPE_AV1_DECODE_SIZEUP_8, {CLIP_SIZEUP_8, ALL_FRAMES, DecoderOption::Default}},
498     {TEST_TYPE_AV1_DECODE_BASIC_10, {CLIP_BASIC_10, ALL_FRAMES, DecoderOption::Default}},
499     {TEST_TYPE_AV1_DECODE_ORDERHINT_10, {CLIP_ORDERHINT_10, ALL_FRAMES, DecoderOption::Default}},
500     {TEST_TYPE_AV1_DECODE_FORWARDKEYFRAME_10, {CLIP_FORWARDKEYFRAME_10, ALL_FRAMES, DecoderOption::Default}},
501     {TEST_TYPE_AV1_DECODE_LOSSLESS_10, {CLIP_LOSSLESS_10, ALL_FRAMES, DecoderOption::Default}},
502     {TEST_TYPE_AV1_DECODE_LOOPFILTER_10, {CLIP_LOOPFILTER_10, ALL_FRAMES, DecoderOption::Default}},
503     {TEST_TYPE_AV1_DECODE_CDEF_10, {CLIP_CDEF_10, ALL_FRAMES, DecoderOption::Default}},
504 
505     // TODO: Did not have sufficient implementations to find out why this is failing.
506     // {TEST_TYPE_AV1_DECODE_ARGON_SEQCHANGE_AFFINE_8, {CLIP_ARGON_SEQCHANGE_AFFINE_8, 4, DecoderOption::AnnexB}},
507 
508     // TODO: Frames after the first hit asserts in the parser. First frame decodes correctly.
509     // TODO: Filmgrain option not set here, because the first frame doesn't have it enabled.
510     {TEST_TYPE_AV1_DECODE_ARGON_FILMGRAIN_10, {CLIP_ARGON_FILMGRAIN_10, 1, (DecoderOption)(DecoderOption::AnnexB)}},
511 
512     // TODO: Did not have sufficient implementations to find out why this is failing.
513     //{TEST_TYPE_AV1_DECODE_ARGON_TEST_787, {CLIP_ARGON_TEST_787, 2, DecoderOption::AnnexB}},
514 };
515 
516 struct InterleavingDecodeTestParams
517 {
518     TestType type;
519     BaseDecodeParam streamA;
520     BaseDecodeParam streamB;
521 } g_InterleavingTests[] = {
522     {TEST_TYPE_H264_DECODE_INTERLEAVED,
523      {CLIP_A, ALL_FRAMES, DecoderOption::CachedDecoding},
524      {CLIP_A, ALL_FRAMES, DecoderOption::CachedDecoding}},
525     {TEST_TYPE_H264_H265_DECODE_INTERLEAVED,
526      {CLIP_A, ALL_FRAMES, DecoderOption::CachedDecoding},
527      {CLIP_D, ALL_FRAMES, DecoderOption::CachedDecoding}},
528 };
529 
530 class TestDefinition
531 {
532 public:
create(DecodeTestParam params,uint32_t baseSeed,bool layeredDpb)533     static MovePtr<TestDefinition> create(DecodeTestParam params, uint32_t baseSeed, bool layeredDpb)
534     {
535         return MovePtr<TestDefinition>(new TestDefinition(params, baseSeed, layeredDpb));
536     }
537 
TestDefinition(DecodeTestParam params,uint32_t baseSeed,bool layeredDpb)538     TestDefinition(DecodeTestParam params, uint32_t baseSeed, bool layeredDpb)
539         : m_params(params)
540         , m_info(clipInfo(params.stream.clip))
541         , m_hash(baseSeed)
542         , m_isLayeredDpb(layeredDpb)
543     {
544         for (const auto &profile : m_info->sessionProfiles)
545         {
546             m_profiles.push_back(VkVideoCoreProfile(profile.codecOperation, profile.subsamplingFlags,
547                                                     profile.lumaBitDepth, profile.chromaBitDepth, profile.profileIDC,
548                                                     params.stream.decoderOptions & DecoderOption::FilmGrainPresent));
549         }
550 
551         if (m_params.stream.framesToCheck == ALL_FRAMES)
552         {
553             m_params.stream.framesToCheck = m_info->totalFrames;
554         }
555 
556         if (params.type == TEST_TYPE_H264_DECODE_RESOLUTION_CHANGE_DPB)
557         {
558             m_pictureParameterUpdateTriggerHack = 3;
559         }
560     }
561 
getTestType() const562     TestType getTestType() const
563     {
564         return m_params.type;
565     }
566 
getClipFilename() const567     const char *getClipFilename() const
568     {
569         return m_info->filename;
570     }
571 
getClipFilePath() const572     std::string getClipFilePath() const
573     {
574         std::vector<std::string> resourcePathComponents = {"vulkan", "video", m_info->filename};
575         de::FilePath resourcePath                       = de::FilePath::join(resourcePathComponents);
576         return resourcePath.getPath();
577     }
578 
getClipInfo() const579     const ClipInfo *getClipInfo() const
580     {
581         return m_info;
582     };
583 
getCodecOperation(int session) const584     VkVideoCodecOperationFlagBitsKHR getCodecOperation(int session) const
585     {
586         return m_profiles[session].GetCodecType();
587     }
588 
getProfile(int session) const589     const VkVideoCoreProfile *getProfile(int session) const
590     {
591         return &m_profiles[session];
592     }
593 
getTestName() const594     const std::string getTestName() const
595     {
596         std::stringstream oss;
597         oss << testTypeToStr(getTestType());
598         if (isLayered())
599             oss << "_layered_dpb";
600         else
601             oss << "_separated_dpb";
602 
603         return oss.str();
604     }
605 
framesToCheck() const606     int framesToCheck() const
607     {
608         return m_params.stream.framesToCheck;
609     }
610 
hasOption(DecoderOption o) const611     bool hasOption(DecoderOption o) const
612     {
613         return (m_params.stream.decoderOptions & o) != 0;
614     }
615 
isLayered() const616     bool isLayered() const
617     {
618         return m_isLayeredDpb;
619     }
620 
getParamaterUpdateHackRequirement() const621     int getParamaterUpdateHackRequirement() const
622     {
623         return m_pictureParameterUpdateTriggerHack;
624     }
625 
requiredDeviceFlags() const626     VideoDevice::VideoDeviceFlags requiredDeviceFlags() const
627     {
628         VideoDevice::VideoDeviceFlags flags = VideoDevice::VIDEO_DEVICE_FLAG_REQUIRE_SYNC2_OR_NOT_SUPPORTED;
629 
630         if (hasOption(DecoderOption::UseStatusQueries))
631             flags |= VideoDevice::VIDEO_DEVICE_FLAG_QUERY_WITH_STATUS_FOR_DECODE_SUPPORT;
632 
633         if (hasOption(DecoderOption::UseInlineStatusQueries) || hasOption(DecoderOption::ResourcesWithoutProfiles))
634             flags |= VideoDevice::VIDEO_DEVICE_FLAG_REQUIRE_MAINTENANCE_1;
635 
636         return flags;
637     }
638 
extensionProperties(int session) const639     const VkExtensionProperties *extensionProperties(int session) const
640     {
641         static const VkExtensionProperties h264StdExtensionVersion = {
642             VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_EXTENSION_NAME, VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_SPEC_VERSION};
643         static const VkExtensionProperties h265StdExtensionVersion = {
644             VK_STD_VULKAN_VIDEO_CODEC_H265_DECODE_EXTENSION_NAME, VK_STD_VULKAN_VIDEO_CODEC_H265_DECODE_SPEC_VERSION};
645         static const VkExtensionProperties av1StdExtensionVersion = {
646             VK_STD_VULKAN_VIDEO_CODEC_AV1_DECODE_EXTENSION_NAME, VK_STD_VULKAN_VIDEO_CODEC_AV1_DECODE_SPEC_VERSION};
647 
648         switch (m_profiles[session].GetCodecType())
649         {
650         case VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR:
651             return &h264StdExtensionVersion;
652         case VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR:
653             return &h265StdExtensionVersion;
654         case VK_VIDEO_CODEC_OPERATION_DECODE_AV1_BIT_KHR:
655             return &av1StdExtensionVersion;
656         default:
657             tcu::die("Unsupported video codec %s\n", util::codecToName(m_profiles[session].GetCodecType()));
658             break;
659         }
660 
661         TCU_THROW(InternalError, "Unsupported codec");
662     };
663 
updateHash(uint32_t baseHash)664     void updateHash(uint32_t baseHash)
665     {
666         m_hash = deUint32Hash(baseHash);
667     }
668 
669 private:
670     DecodeTestParam m_params;
671     const ClipInfo *m_info{};
672     uint32_t m_hash{};
673     bool m_isLayeredDpb{};
674     std::vector<VkVideoCoreProfile> m_profiles;
675     // The 1-based count of parameter set updates after which to force
676     // a parameter object release.  This is required due to the design
677     // of the NVIDIA decode-client API. It sends parameter updates and
678     // expects constructed parameter objects back synchronously,
679     // before the next video session is created in a following
680     // BeginSequence call.
681     int m_pictureParameterUpdateTriggerHack{0}; // Zero is "off"
682 };
683 
684 // Vulkan video is not supported on android platform
685 // all external libraries, helper functions and test instances has been excluded
686 #ifdef DE_BUILD_VIDEO
687 
decoderFromTestDefinition(DeviceContext * devctx,const TestDefinition & test,bool forceDisableFilmGrain=false)688 static std::shared_ptr<VideoBaseDecoder> decoderFromTestDefinition(DeviceContext *devctx, const TestDefinition &test,
689                                                                    bool forceDisableFilmGrain = false)
690 {
691     VkSharedBaseObj<VulkanVideoFrameBuffer> vkVideoFrameBuffer;
692     VK_CHECK(VulkanVideoFrameBuffer::Create(devctx, test.hasOption(DecoderOption::UseStatusQueries),
693                                             test.hasOption(DecoderOption::ResourcesWithoutProfiles),
694                                             vkVideoFrameBuffer));
695 
696     VideoBaseDecoder::Parameters params;
697     params.profile                           = test.getProfile(0);
698     params.context                           = devctx;
699     params.framebuffer                       = vkVideoFrameBuffer;
700     params.framesToCheck                     = test.framesToCheck();
701     params.layeredDpb                        = test.isLayered();
702     params.queryDecodeStatus                 = test.hasOption(DecoderOption::UseStatusQueries);
703     params.useInlineQueries                  = test.hasOption(DecoderOption::UseInlineStatusQueries);
704     params.resourcesWithoutProfiles          = test.hasOption(DecoderOption::ResourcesWithoutProfiles);
705     params.outOfOrderDecoding                = test.hasOption(DecoderOption::CachedDecoding);
706     params.alwaysRecreateDPB                 = test.hasOption(DecoderOption::RecreateDPBImages);
707     params.intraOnlyDecoding                 = test.hasOption(DecoderOption::IntraOnlyDecoding);
708     params.pictureParameterUpdateTriggerHack = test.getParamaterUpdateHackRequirement();
709     params.forceDisableFilmGrain             = forceDisableFilmGrain;
710 
711     return std::make_shared<VideoBaseDecoder>(std::move(params));
712 }
713 
714 struct DownloadedFrame
715 {
716     std::vector<uint8_t> luma;
717     std::vector<uint8_t> cb;
718     std::vector<uint8_t> cr;
719 
checksumvkt::video::__anond247ad5e0111::DownloadedFrame720     std::string checksum() const
721     {
722         MD5Digest digest;
723         MD5Context ctx{};
724         MD5Init(&ctx);
725         MD5Update(&ctx, luma.data(), luma.size());
726         MD5Update(&ctx, cb.data(), cb.size());
727         MD5Update(&ctx, cr.data(), cr.size());
728         MD5Final(&digest, &ctx);
729         return MD5DigestToBase16(digest);
730     }
731 };
732 
roru16(uint16_t x,uint16_t n)733 inline uint16_t roru16(uint16_t x, uint16_t n)
734 {
735     return n == 0 ? x : (x >> n) | (x << (-n & 15));
736 }
737 
copyAllPlanesToBuffers(const DeviceDriver & vkd,const DecodedFrame & frame,const VkExtent2D & imageExtent,const PlanarFormatDescription & planarDescription,VkCommandBuffer cmdbuf,std::vector<std::unique_ptr<BufferWithMemory>> & planeBuffers)738 static void copyAllPlanesToBuffers(const DeviceDriver &vkd, const DecodedFrame &frame, const VkExtent2D &imageExtent,
739                                    const PlanarFormatDescription &planarDescription, VkCommandBuffer cmdbuf,
740                                    std::vector<std::unique_ptr<BufferWithMemory>> &planeBuffers)
741 {
742     for (uint32_t planeNdx = 0; planeNdx < planarDescription.numPlanes; planeNdx++)
743     {
744         uint32_t width = imageExtent.width;
745         if (planeNdx > 0)
746             width = (width + 1) & ~1;
747 
748         width /= planarDescription.planes[planeNdx].widthDivisor;
749         uint32_t height                    = imageExtent.height / planarDescription.planes[planeNdx].heightDivisor;
750         VkExtent3D planeExtent             = {width, height, 1u};
751         const VkImageAspectFlagBits aspect = getPlaneAspect(planeNdx);
752         {
753 
754             const VkImageMemoryBarrier preCopyBarrier = {
755                 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
756                 nullptr,
757                 0u,
758                 VK_ACCESS_TRANSFER_READ_BIT,
759                 VK_IMAGE_LAYOUT_GENERAL,
760                 VK_IMAGE_LAYOUT_GENERAL,
761                 VK_QUEUE_FAMILY_IGNORED,
762                 VK_QUEUE_FAMILY_IGNORED,
763                 frame.outputImageView->GetImageResource()->GetImage(),
764                 {(VkImageAspectFlags)aspect, 0u, 1u, frame.imageLayerIndex, 1u}};
765 
766             vkd.cmdPipelineBarrier(cmdbuf, (VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
767                                    (VkPipelineStageFlags)VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0u, 0u,
768                                    nullptr, 0u, nullptr, 1u, &preCopyBarrier);
769         }
770         {
771             const VkBufferImageCopy copy = {0u, // bufferOffset
772                                             0u, // bufferRowLength
773                                             0u, // bufferImageHeight
774                                             {(VkImageAspectFlags)aspect, 0u, frame.imageLayerIndex, 1u},
775                                             makeOffset3D(0u, 0u, 0u),
776                                             planeExtent};
777             vkd.cmdCopyImageToBuffer(cmdbuf, frame.outputImageView->GetImageResource()->GetImage(),
778                                      VK_IMAGE_LAYOUT_GENERAL, planeBuffers[planeNdx]->get(), 1u, &copy);
779         }
780         {
781             const VkBufferMemoryBarrier postCopyBarrier = {VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
782                                                            nullptr,
783                                                            VK_ACCESS_TRANSFER_WRITE_BIT,
784                                                            VK_ACCESS_HOST_READ_BIT,
785                                                            VK_QUEUE_FAMILY_IGNORED,
786                                                            VK_QUEUE_FAMILY_IGNORED,
787                                                            planeBuffers[planeNdx]->get(),
788                                                            0u,
789                                                            VK_WHOLE_SIZE};
790 
791             vkd.cmdPipelineBarrier(cmdbuf, (VkPipelineStageFlags)VK_PIPELINE_STAGE_TRANSFER_BIT,
792                                    (VkPipelineStageFlags)VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0u, 0u, nullptr,
793                                    1u, &postCopyBarrier, 0u, nullptr);
794         }
795     }
796 }
797 
getDecodedImage(DeviceContext & devctx,VkImageLayout originalLayout,const DecodedFrame & frame)798 DownloadedFrame getDecodedImage(DeviceContext &devctx, VkImageLayout originalLayout, const DecodedFrame &frame)
799 {
800     auto &vkd                     = devctx.getDeviceDriver();
801     auto device                   = devctx.device;
802     auto queueFamilyIndexDecode   = devctx.decodeQueueFamilyIdx();
803     auto queueFamilyIndexTransfer = devctx.transferQueueFamilyIdx();
804     const VkExtent2D imageExtent{(uint32_t)frame.displayWidth, (uint32_t)frame.displayHeight};
805     const VkImage image         = frame.outputImageView->GetImageResource()->GetImage();
806     const VkFormat format       = frame.outputImageView->GetImageResource()->GetImageCreateInfo().format;
807     const VkQueue queueDecode   = getDeviceQueue(vkd, device, queueFamilyIndexDecode, 0u);
808     const VkQueue queueTransfer = getDeviceQueue(vkd, device, queueFamilyIndexTransfer, 0u);
809 
810     PlanarFormatDescription planarDescription = getPlanarFormatDescription(format);
811     DE_ASSERT(planarDescription.numPlanes == 2 || planarDescription.numPlanes == 3);
812     const VkImageSubresourceRange imageSubresourceRange =
813         makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, frame.imageLayerIndex, 1);
814 
815     if (videoLoggingEnabled())
816     {
817         tcu::print(";;; getDecodedImage layer=%d arrayLayers=%d\n", frame.imageLayerIndex,
818                    frame.outputImageView->GetImageResource()->GetImageCreateInfo().arrayLayers);
819     }
820 
821     const Move<VkCommandPool> cmdDecodePool(makeCommandPool(vkd, device, queueFamilyIndexDecode));
822     const Move<VkCommandBuffer> cmdDecodeBuffer(
823         allocateCommandBuffer(vkd, device, *cmdDecodePool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
824     const Move<VkCommandPool> cmdTransferPool(makeCommandPool(vkd, device, queueFamilyIndexTransfer));
825     const Move<VkCommandBuffer> cmdTransferBuffer(
826         allocateCommandBuffer(vkd, device, *cmdTransferPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
827 
828     if (frame.frameCompleteFence != VK_NULL_HANDLE)
829         VK_CHECK(vkd.waitForFences(device, 1, &frame.frameCompleteFence, VK_FALSE, ~(uint64_t)0u));
830 
831     auto computePlaneSize = [](const VkExtent2D extent, const PlanarFormatDescription &desc, int plane)
832     {
833         uint32_t w = extent.width;
834         uint32_t h = extent.height;
835 
836         if (plane > 0)
837         {
838             w = (w + 1) /
839                 desc.planes[plane]
840                     .widthDivisor; // This is what libaom does, but probably not the h/w - there's ambiguity about what to do for non-even dimensions imo
841             h = (h + 1) / desc.planes[plane].heightDivisor;
842             return w * h * desc.planes[plane].elementSizeBytes;
843         }
844 
845         return w * h * desc.planes[plane].elementSizeBytes;
846     };
847 
848     // Create a buffer to hold each planes' samples.
849     std::vector<std::unique_ptr<BufferWithMemory>> planeBuffers;
850     planeBuffers.reserve(planarDescription.numPlanes);
851     for (int plane = 0; plane < planarDescription.numPlanes; plane++)
852     {
853         const VkBufferCreateInfo bufferInfo = {
854             VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
855             nullptr,
856             (VkBufferCreateFlags)0u,
857             computePlaneSize(imageExtent, planarDescription, plane),
858             VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
859             VK_SHARING_MODE_EXCLUSIVE,
860             0u,
861             nullptr,
862         };
863         planeBuffers.emplace_back(new BufferWithMemory(vkd, device, devctx.allocator(), bufferInfo,
864                                                        MemoryRequirement::HostVisible | MemoryRequirement::Any));
865     }
866 
867     Move<VkFence> decodeFence                   = createFence(vkd, device);
868     Move<VkFence> transferFence                 = createFence(vkd, device);
869     Move<VkSemaphore> semaphore                 = createSemaphore(vkd, device);
870     const VkPipelineStageFlags waitDstStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
871 
872     // First release the image from the decode queue to the xfer queue, transitioning it to a friendly format for copying.
873     const VkImageMemoryBarrier2KHR barrierDecodeRelease = makeImageMemoryBarrier2(
874         VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR, VK_ACCESS_2_VIDEO_DECODE_WRITE_BIT_KHR, VK_PIPELINE_STAGE_2_NONE,
875         0, // ignored for release operations
876         originalLayout, VK_IMAGE_LAYOUT_GENERAL, image, imageSubresourceRange, queueFamilyIndexDecode,
877         queueFamilyIndexTransfer);
878 
879     // And acquire it on the transfer queue
880     const VkImageMemoryBarrier2KHR barrierTransferAcquire =
881         makeImageMemoryBarrier2(VK_PIPELINE_STAGE_2_NONE,
882                                 0, // ignored for acquire operations
883                                 VK_PIPELINE_STAGE_2_TRANSFER_BIT, VK_ACCESS_2_MEMORY_READ_BIT, originalLayout,
884                                 VK_IMAGE_LAYOUT_GENERAL, // must match decode release
885                                 image,                   // must match decode release
886                                 imageSubresourceRange,   // must match decode release
887                                 queueFamilyIndexDecode,  // must match decode release
888                                 queueFamilyIndexTransfer);
889 
890     beginCommandBuffer(vkd, *cmdDecodeBuffer, 0u);
891     cmdPipelineImageMemoryBarrier2(vkd, *cmdDecodeBuffer, &barrierDecodeRelease);
892     endCommandBuffer(vkd, *cmdDecodeBuffer);
893 
894     bool haveSemaphore = frame.frameCompleteSemaphore != VK_NULL_HANDLE;
895     const VkSubmitInfo decodeSubmitInfo{
896         VK_STRUCTURE_TYPE_SUBMIT_INFO,
897         nullptr,
898         haveSemaphore ? 1u : 0u,
899         haveSemaphore ? &frame.frameCompleteSemaphore : nullptr,
900         haveSemaphore ? &waitDstStageMask : nullptr,
901         1u,
902         &*cmdDecodeBuffer,
903         1u,
904         &*semaphore,
905     };
906     VK_CHECK(vkd.queueSubmit(queueDecode, 1u, &decodeSubmitInfo, *decodeFence));
907     VK_CHECK(vkd.waitForFences(device, 1, &*decodeFence, true, ~0ull));
908 
909     beginCommandBuffer(vkd, *cmdTransferBuffer, 0u);
910     cmdPipelineImageMemoryBarrier2(vkd, *cmdTransferBuffer, &barrierTransferAcquire);
911     copyAllPlanesToBuffers(vkd, frame, imageExtent, planarDescription, *cmdTransferBuffer, planeBuffers);
912     endCommandBuffer(vkd, *cmdTransferBuffer);
913 
914     const VkSubmitInfo transferSubmitInfo{
915         VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType                              sType;
916         nullptr,                       // const void*                                  pNext;
917         1u,                            // uint32_t                                             waitSemaphoreCount;
918         &*semaphore,                   // const VkSemaphore*                   pWaitSemaphores;
919         &waitDstStageMask,             // const VkPipelineStageFlags*  pWaitDstStageMask;
920         1u,                            // uint32_t                                             commandBufferCount;
921         &*cmdTransferBuffer,           // const VkCommandBuffer*               pCommandBuffers;
922         1u,                            // uint32_t                                             signalSemaphoreCount;
923         &*semaphore,                   // const VkSemaphore*                   pSignalSemaphores;
924     };
925     VK_CHECK(vkd.queueSubmit(queueTransfer, 1u, &transferSubmitInfo, *transferFence));
926     VK_CHECK(vkd.waitForFences(device, 1, &*transferFence, true, ~0ull));
927 
928     DownloadedFrame downloadedFrame;
929     { // download the data from the buffers into the host buffers
930         tcu::UVec4 channelDepths = ycbcr::getYCbCrBitDepth(format);
931         DE_ASSERT(channelDepths.x() == channelDepths.y() &&
932                   channelDepths.y() == channelDepths.z()); // Sanity for interface mismatch
933         int bitDepth = channelDepths.x();
934         DE_ASSERT(bitDepth == 8 || bitDepth == 10 || bitDepth == 12 || bitDepth == 16);
935         TCU_CHECK_AND_THROW(InternalError, bitDepth != 16, "16-bit samples have not been tested yet");
936 
937         bool highBitDepth = bitDepth > 8;
938 
939         // Luma first
940         {
941             invalidateMappedMemoryRange(vkd, device, planeBuffers[0]->getAllocation().getMemory(), 0u, VK_WHOLE_SIZE);
942             VkDeviceSize planeSize = computePlaneSize(imageExtent, planarDescription, 0);
943             downloadedFrame.luma.resize(planeSize);
944             if (highBitDepth && bitDepth != 16) // 16-bit can take the straight memcpy case below, no undefined bits.
945             {
946                 const uint16_t *const samples = (uint16_t *)planeBuffers[0]->getAllocation().getHostPtr();
947                 uint16_t *const outputSamples = (uint16_t *)downloadedFrame.luma.data();
948 
949                 //int shift = 16 - bitDepth;
950                 if (bitDepth == 10)
951                 {
952                     for (VkDeviceSize sampleIdx = 0; sampleIdx < (imageExtent.width * imageExtent.height); sampleIdx++)
953                     {
954                         uint16_t sample          = samples[sampleIdx];
955                         outputSamples[sampleIdx] = roru16(sample, 6);
956                     }
957                 }
958                 else if (bitDepth == 12)
959                 {
960                     for (VkDeviceSize sampleIdx = 0; sampleIdx < planeSize; sampleIdx++)
961                     {
962                         uint16_t sample                 = samples[sampleIdx];
963                         downloadedFrame.luma[sampleIdx] = roru16(sample, 4);
964                     }
965                 }
966             }
967             else
968             {
969                 DE_ASSERT(bitDepth == 8);
970                 deMemcpy(downloadedFrame.luma.data(), planeBuffers[0]->getAllocation().getHostPtr(), planeSize);
971             }
972         }
973         if (planarDescription.numPlanes == 2)
974         {
975             invalidateMappedMemoryRange(vkd, device, planeBuffers[1]->getAllocation().getMemory(), 0u, VK_WHOLE_SIZE);
976             // Interleaved formats, deinterleave for MD5 comparisons (matches most other tool's notion of "raw YUV format")
977             //   this is a very slow operation, and accounts for ~80% of the decode test runtime.
978             //   it might be better to use reference checksums in the original hardware format, rather than xforming each time
979             //   but that makes comparison to software references more difficult...
980             VkDeviceSize planeSize = computePlaneSize(imageExtent, planarDescription, 1);
981             VkDeviceSize numWords  = planeSize / sizeof(uint16_t);
982             uint16_t *wordSamples  = (uint16_t *)planeBuffers[1]->getAllocation().getHostPtr();
983             downloadedFrame.cb.resize(numWords);
984             downloadedFrame.cr.resize(numWords);
985             if (bitDepth == 8)
986             {
987                 for (int i = 0; i < numWords; i++)
988                 {
989                     downloadedFrame.cb[i] = wordSamples[i] & 0xFF;
990                     downloadedFrame.cr[i] = (wordSamples[i] >> 8) & 0xFF;
991                 }
992             }
993             else
994             {
995                 DE_ASSERT(bitDepth == 10 || bitDepth == 12 || bitDepth == 16);
996                 uint16_t *sampleWordsCb16 = (uint16_t *)downloadedFrame.cb.data();
997                 uint16_t *sampleWordsCr16 = (uint16_t *)downloadedFrame.cr.data();
998                 for (int i = 0; i < numWords / 2; i++)
999                 {
1000                     sampleWordsCb16[i] = roru16(wordSamples[2 * i], 16 - bitDepth);
1001                     sampleWordsCr16[i] = roru16(wordSamples[2 * i + 1], 16 - bitDepth);
1002                 }
1003             }
1004         }
1005         else if (planarDescription.numPlanes == 3)
1006         {
1007             invalidateMappedMemoryRange(vkd, device, planeBuffers[1]->getAllocation().getMemory(), 0u, VK_WHOLE_SIZE);
1008 
1009             // Happy case, not deinterleaving, just straight memcpying
1010             uint32_t evenWidth = (imageExtent.width + 1) & ~1;
1011 
1012             // Not sure, but don't think chroma planes can be subsampled differently.
1013             DE_ASSERT(planarDescription.planes[1].widthDivisor == planarDescription.planes[2].widthDivisor);
1014             DE_ASSERT(planarDescription.planes[1].heightDivisor == planarDescription.planes[2].heightDivisor);
1015             DE_ASSERT(planarDescription.planes[1].elementSizeBytes == planarDescription.planes[2].elementSizeBytes);
1016 
1017             uint32_t width  = evenWidth / planarDescription.planes[1].widthDivisor;
1018             uint32_t height = imageExtent.height / planarDescription.planes[1].heightDivisor;
1019 
1020             VkDeviceSize cbPlaneSize = width * height * planarDescription.planes[1].elementSizeBytes;
1021             downloadedFrame.cb.resize(cbPlaneSize);
1022             deMemcpy(downloadedFrame.cb.data(), planeBuffers[1]->getAllocation().getHostPtr(),
1023                      downloadedFrame.cb.size());
1024 
1025             invalidateMappedMemoryRange(vkd, device, planeBuffers[2]->getAllocation().getMemory(), 0u, VK_WHOLE_SIZE);
1026             downloadedFrame.cr.resize(cbPlaneSize);
1027             deMemcpy(downloadedFrame.cr.data(), planeBuffers[2]->getAllocation().getHostPtr(),
1028                      downloadedFrame.cr.size());
1029         }
1030     }
1031 
1032     // We're nearly there, the pain is almost over, release the image
1033     // from the xfer queue, give it back to the decode queue, and
1034     // transition it back to the original layout.
1035     const VkImageMemoryBarrier2KHR barrierTransferRelease = makeImageMemoryBarrier2(
1036         VK_PIPELINE_STAGE_2_TRANSFER_BIT, VK_ACCESS_2_MEMORY_WRITE_BIT, VK_PIPELINE_STAGE_2_NONE,
1037         0, // ignored for release
1038         VK_IMAGE_LAYOUT_GENERAL, originalLayout, image, imageSubresourceRange, queueFamilyIndexTransfer,
1039         queueFamilyIndexDecode);
1040 
1041     const VkImageMemoryBarrier2KHR barrierDecodeAcquire = makeImageMemoryBarrier2(
1042         VK_PIPELINE_STAGE_2_NONE,
1043         0, // ignored for acquire
1044         VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR, VK_ACCESS_2_VIDEO_DECODE_WRITE_BIT_KHR, VK_IMAGE_LAYOUT_GENERAL,
1045         originalLayout, image, imageSubresourceRange, queueFamilyIndexTransfer, queueFamilyIndexDecode);
1046 
1047     vkd.resetCommandBuffer(*cmdTransferBuffer, 0u);
1048     vkd.resetCommandBuffer(*cmdDecodeBuffer, 0u);
1049 
1050     vkd.resetFences(device, 1, &*transferFence);
1051     vkd.resetFences(device, 1, &*decodeFence);
1052 
1053     beginCommandBuffer(vkd, *cmdTransferBuffer, 0u);
1054     cmdPipelineImageMemoryBarrier2(vkd, *cmdTransferBuffer, &barrierTransferRelease);
1055     endCommandBuffer(vkd, *cmdTransferBuffer);
1056 
1057     const VkSubmitInfo transferSubmitInfo2{
1058         VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType                              sType;
1059         nullptr,                       // const void*                                  pNext;
1060         1u,                            // uint32_t                                             waitSemaphoreCount;
1061         &*semaphore,                   // const VkSemaphore*                   pWaitSemaphores;
1062         &waitDstStageMask,             // const VkPipelineStageFlags*  pWaitDstStageMask;
1063         1u,                            // uint32_t                                             commandBufferCount;
1064         &*cmdTransferBuffer,           // const VkCommandBuffer*               pCommandBuffers;
1065         1u,                            // uint32_t                                             signalSemaphoreCount;
1066         &*semaphore,                   // const VkSemaphore*                   pSignalSemaphores;
1067     };
1068     VK_CHECK(vkd.queueSubmit(queueTransfer, 1u, &transferSubmitInfo2, *transferFence));
1069     VK_CHECK(vkd.waitForFences(device, 1, &*transferFence, true, ~0ull));
1070 
1071     beginCommandBuffer(vkd, *cmdDecodeBuffer, 0u);
1072     cmdPipelineImageMemoryBarrier2(vkd, *cmdDecodeBuffer, &barrierDecodeAcquire);
1073     endCommandBuffer(vkd, *cmdDecodeBuffer);
1074 
1075     const VkSubmitInfo decodeSubmitInfo2{
1076         VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType                              sType;
1077         nullptr,                       // const void*                                  pNext;
1078         1u,                            // uint32_t                                             waitSemaphoreCount;
1079         &*semaphore,                   // const VkSemaphore*                   pWaitSemaphores;
1080         &waitDstStageMask,             // const VkPipelineStageFlags*  pWaitDstStageMask;
1081         1u,                            // uint32_t                                             commandBufferCount;
1082         &*cmdDecodeBuffer,             // const VkCommandBuffer*               pCommandBuffers;
1083         0u,                            // uint32_t                                             signalSemaphoreCount;
1084         nullptr,                       // const VkSemaphore*                   pSignalSemaphores;
1085     };
1086     VK_CHECK(vkd.queueSubmit(queueDecode, 1u, &decodeSubmitInfo2, *decodeFence));
1087     VK_CHECK(vkd.waitForFences(device, 1, &*decodeFence, true, ~0ull));
1088 
1089     return downloadedFrame;
1090 }
1091 
1092 class VideoDecodeTestInstance : public VideoBaseTestInstance
1093 {
1094 public:
1095     VideoDecodeTestInstance(Context &context, const TestDefinition *testDefinition);
1096     tcu::TestStatus iterate(void);
1097 
1098 protected:
1099     const TestDefinition *m_testDefinition;
1100     static_assert(sizeof(DeviceContext) < 128, "DeviceContext has grown bigger than expected!");
1101     DeviceContext m_deviceContext;
1102 };
1103 
1104 class InterleavingDecodeTestInstance : public VideoBaseTestInstance
1105 {
1106 public:
1107     InterleavingDecodeTestInstance(Context &context, const std::vector<MovePtr<TestDefinition>> &testDefinitions);
1108     tcu::TestStatus iterate(void);
1109 
1110 protected:
1111     const std::vector<MovePtr<TestDefinition>> &m_testDefinitions;
1112     DeviceContext m_deviceContext;
1113     static_assert(sizeof(DeviceContext) < 128, "DeviceContext has grown bigger than expected!");
1114 };
1115 
InterleavingDecodeTestInstance(Context & context,const std::vector<MovePtr<TestDefinition>> & testDefinitions)1116 InterleavingDecodeTestInstance::InterleavingDecodeTestInstance(
1117     Context &context, const std::vector<MovePtr<TestDefinition>> &testDefinitions)
1118     : VideoBaseTestInstance(context)
1119     , m_testDefinitions(std::move(testDefinitions))
1120     , m_deviceContext(&m_context, &m_videoDevice)
1121 {
1122     int requiredCodecs                                = VK_VIDEO_CODEC_OPERATION_NONE_KHR;
1123     VideoDevice::VideoDeviceFlags requiredDeviceFlags = VideoDevice::VideoDeviceFlagBits::VIDEO_DEVICE_FLAG_NONE;
1124     for (const auto &test : m_testDefinitions)
1125     {
1126         VkVideoCodecOperationFlagBitsKHR testBits = test->getCodecOperation(0);
1127         requiredCodecs |= testBits;
1128         requiredDeviceFlags |= test->requiredDeviceFlags();
1129     }
1130     VkDevice device = getDeviceSupportingQueue(VK_QUEUE_VIDEO_DECODE_BIT_KHR | VK_QUEUE_TRANSFER_BIT, requiredCodecs,
1131                                                requiredDeviceFlags);
1132 
1133     m_deviceContext.updateDevice(
1134         m_context.getPhysicalDevice(), device,
1135         getDeviceQueue(m_context.getDeviceInterface(), device, m_videoDevice.getQueueFamilyIndexDecode(), 0), nullptr,
1136         getDeviceQueue(m_context.getDeviceInterface(), device, m_videoDevice.getQueueFamilyIndexTransfer(), 0));
1137 }
1138 
VideoDecodeTestInstance(Context & context,const TestDefinition * testDefinition)1139 VideoDecodeTestInstance::VideoDecodeTestInstance(Context &context, const TestDefinition *testDefinition)
1140     : VideoBaseTestInstance(context)
1141     , m_testDefinition(testDefinition)
1142     , m_deviceContext(&m_context, &m_videoDevice)
1143 {
1144     VkDevice device =
1145         getDeviceSupportingQueue(VK_QUEUE_VIDEO_DECODE_BIT_KHR | VK_QUEUE_TRANSFER_BIT,
1146                                  m_testDefinition->getCodecOperation(0), m_testDefinition->requiredDeviceFlags());
1147 
1148     m_deviceContext.updateDevice(
1149         m_context.getPhysicalDevice(), device,
1150         getDeviceQueue(m_context.getDeviceInterface(), device, m_videoDevice.getQueueFamilyIndexDecode(), 0), nullptr,
1151         getDeviceQueue(m_context.getDeviceInterface(), device, m_videoDevice.getQueueFamilyIndexTransfer(), 0));
1152 }
1153 
createProcessor(const TestDefinition * td,DeviceContext * dctx,bool forceDisableFilmGrain=false)1154 static std::unique_ptr<FrameProcessor> createProcessor(const TestDefinition *td, DeviceContext *dctx,
1155                                                        bool forceDisableFilmGrain = false)
1156 {
1157     Demuxer::Params demuxParams = {};
1158     demuxParams.data            = std::make_unique<BufferedReader>(td->getClipFilePath());
1159     demuxParams.codecOperation  = td->getCodecOperation(0);
1160     demuxParams.framing         = td->getClipInfo()->framing;
1161 
1162     auto demuxer = Demuxer::create(std::move(demuxParams));
1163 
1164     std::shared_ptr<VideoBaseDecoder> decoder = decoderFromTestDefinition(dctx, *td, forceDisableFilmGrain);
1165 
1166     return std::make_unique<FrameProcessor>(std::move(demuxer), decoder);
1167 }
1168 
iterate()1169 tcu::TestStatus VideoDecodeTestInstance::iterate()
1170 {
1171     bool filmGrainPresent                     = m_testDefinition->hasOption(DecoderOption::FilmGrainPresent);
1172     std::unique_ptr<FrameProcessor> processor = createProcessor(m_testDefinition, &m_deviceContext);
1173     std::unique_ptr<FrameProcessor> processorWithoutFilmGrain;
1174     if (filmGrainPresent)
1175     {
1176         processorWithoutFilmGrain = createProcessor(m_testDefinition, &m_deviceContext, true);
1177     }
1178 
1179     std::vector<int> incorrectFrames;
1180     std::vector<int> correctFrames;
1181 
1182     if (m_testDefinition->hasOption(DecoderOption::CachedDecoding))
1183     {
1184         processor->decodeFrameOutOfOrder(m_testDefinition->framesToCheck());
1185         if (processorWithoutFilmGrain)
1186             processorWithoutFilmGrain->decodeFrameOutOfOrder(m_testDefinition->framesToCheck());
1187     }
1188 
1189     bool hasSeparateOutputImages = !processor->m_decoder->dpbAndOutputCoincide() || filmGrainPresent;
1190 
1191     std::FILE *debug_OutputFileHandle;
1192 
1193     auto openTemporaryFile = [](const std::string &basename, std::FILE **handle)
1194     {
1195         DE_ASSERT(handle != nullptr);
1196         *handle = std::fopen(basename.c_str(), "wb");
1197         DE_ASSERT(*handle != nullptr);
1198     };
1199 
1200     if (debug_WriteOutFramesToSingleFile)
1201     {
1202         openTemporaryFile("output.yuv", &debug_OutputFileHandle);
1203     }
1204 
1205     bool throwFilmGrainQualityWarning = false;
1206     for (int frameNumber = 0; frameNumber < m_testDefinition->framesToCheck(); frameNumber++)
1207     {
1208         DecodedFrame frame;
1209         TCU_CHECK_AND_THROW(
1210             InternalError, processor->getNextFrame(&frame) > 0,
1211             "Expected more frames from the bitstream. Most likely an internal CTS bug, or maybe an invalid bitstream");
1212         DecodedFrame frameWithoutFilmgGrain;
1213         if (processorWithoutFilmGrain)
1214         {
1215             TCU_CHECK_AND_THROW(InternalError, processorWithoutFilmGrain->getNextFrame(&frameWithoutFilmgGrain) > 0,
1216                                 "Expected more frames from the bitstream. Most likely an internal CTS bug, or maybe an "
1217                                 "invalid bitstream");
1218         }
1219 
1220         if (debug_WriteOutFramesToSeparateFiles)
1221         {
1222             std::stringstream oss;
1223             oss << "output" << frame.displayOrder << "_" << frame.displayWidth << "_" << frame.displayHeight << ".yuv";
1224             openTemporaryFile(oss.str(), &debug_OutputFileHandle);
1225         }
1226 
1227         DownloadedFrame downloadedFrame = getDecodedImage(
1228             m_deviceContext,
1229             hasSeparateOutputImages ? VK_IMAGE_LAYOUT_VIDEO_DECODE_DST_KHR : VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR,
1230             frame);
1231 
1232         DownloadedFrame downloadedFrameWithoutFilmGrain;
1233         if (processorWithoutFilmGrain)
1234         {
1235             downloadedFrameWithoutFilmGrain =
1236                 getDecodedImage(m_deviceContext,
1237                                 !processor->m_decoder->dpbAndOutputCoincide() ? VK_IMAGE_LAYOUT_VIDEO_DECODE_DST_KHR :
1238                                                                                 VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR,
1239                                 frameWithoutFilmgGrain);
1240         }
1241 
1242         if (debug_WriteOutFramesToSingleFile || debug_WriteOutFramesToSeparateFiles)
1243         {
1244             DownloadedFrame &frameToWriteOut =
1245                 debug_WriteOutFilmGrain ? downloadedFrame : downloadedFrameWithoutFilmGrain;
1246             fwrite(frameToWriteOut.luma.data(), 1, frameToWriteOut.luma.size(), debug_OutputFileHandle);
1247             fwrite(frameToWriteOut.cb.data(), 1, frameToWriteOut.cb.size(), debug_OutputFileHandle);
1248             fwrite(frameToWriteOut.cr.data(), 1, frameToWriteOut.cr.size(), debug_OutputFileHandle);
1249             fflush(debug_OutputFileHandle);
1250         }
1251 
1252         if (debug_WriteOutFramesToSeparateFiles)
1253         {
1254             std::fclose(debug_OutputFileHandle);
1255         }
1256 
1257         std::string checksum       = checksumForClipFrame(m_testDefinition->getClipInfo(), frameNumber);
1258         std::string actualChecksum = downloadedFrame.checksum();
1259 
1260         double psnr = 0.0;
1261         if (processorWithoutFilmGrain)
1262         {
1263             static const double numPlanes = 3.0;
1264             util::PSNR(downloadedFrame.luma, downloadedFrameWithoutFilmGrain.luma);
1265             psnr += util::PSNR(downloadedFrame.cb, downloadedFrameWithoutFilmGrain.cb);
1266             psnr += util::PSNR(downloadedFrame.cr, downloadedFrameWithoutFilmGrain.cr);
1267             psnr /= numPlanes;
1268         }
1269 
1270         if (actualChecksum == checksum)
1271         {
1272             correctFrames.push_back(frameNumber);
1273         }
1274         else
1275         {
1276             if (processorWithoutFilmGrain)
1277             {
1278                 if (!de::inRange(psnr, kFilmgrainPSNRLowerBound, kFilmgrainPSNRUpperBound))
1279                 {
1280                     incorrectFrames.push_back(frameNumber);
1281                     throwFilmGrainQualityWarning = true;
1282                 }
1283                 else
1284                 {
1285                     correctFrames.push_back(frameNumber);
1286                 }
1287             }
1288             else
1289             {
1290                 incorrectFrames.push_back(frameNumber);
1291             }
1292         }
1293     }
1294 
1295     if (debug_WriteOutFramesToSingleFile)
1296     {
1297         fclose(debug_OutputFileHandle);
1298     }
1299 
1300     if (!correctFrames.empty() && correctFrames.size() == m_testDefinition->framesToCheck())
1301     {
1302         std::stringstream oss;
1303         oss << m_testDefinition->framesToCheck() << " correctly decoded frames";
1304         return tcu::TestStatus::pass(oss.str());
1305     }
1306     else
1307     {
1308         std::stringstream ss;
1309         ss << correctFrames.size() << " out of " << m_testDefinition->framesToCheck() << " frames rendered correctly (";
1310         if (correctFrames.size() < incorrectFrames.size())
1311         {
1312             ss << "correct frames: ";
1313             for (int i : correctFrames)
1314                 ss << i << " ";
1315         }
1316         else
1317         {
1318             ss << "incorrect frames: ";
1319             for (int i : incorrectFrames)
1320                 ss << i << " ";
1321         }
1322         ss << "\b)";
1323 
1324         if (throwFilmGrainQualityWarning)
1325         {
1326             TCU_THROW(QualityWarning, std::string("Potentially non-standard filmgrain synthesis process: ") + ss.str());
1327         }
1328 
1329         return tcu::TestStatus::fail(ss.str());
1330     }
1331 }
1332 
iterate(void)1333 tcu::TestStatus InterleavingDecodeTestInstance::iterate(void)
1334 {
1335     std::vector<std::unique_ptr<FrameProcessor>> processors;
1336     for (int i = 0; i < m_testDefinitions.size(); i++)
1337     {
1338         processors.push_back(createProcessor(&*m_testDefinitions[i], &m_deviceContext));
1339     }
1340 
1341     // First cache up all the decoded frames from the various decode sessions
1342     for (int i = 0; i < m_testDefinitions.size(); i++)
1343     {
1344         const auto &test = m_testDefinitions[i];
1345         auto &processor  = processors[i];
1346         processor->bufferFrames(test->framesToCheck());
1347         DE_ASSERT(processor->getBufferedDisplayCount() == test->framesToCheck());
1348     }
1349 
1350     auto interleaveCacheSize    = processors[0]->m_decoder->m_cachedDecodeParams.size();
1351     auto firstStreamDecodeQueue = processors[0]->m_decoder->m_deviceContext->decodeQueue;
1352 
1353     size_t totalFrames = 0;
1354     for (auto &processor : processors)
1355     {
1356         auto &decoder = processor->m_decoder;
1357         DE_ASSERT(decoder->m_cachedDecodeParams.size() == interleaveCacheSize);
1358         DE_ASSERT(decoder->m_deviceContext->decodeQueue == firstStreamDecodeQueue);
1359         totalFrames += decoder->m_cachedDecodeParams.size();
1360     }
1361 
1362     DE_UNREF(firstStreamDecodeQueue);
1363 
1364     // Interleave command buffer recording
1365     for (int i = 0; i < interleaveCacheSize; i++)
1366     {
1367         for (auto &processor : processors)
1368         {
1369             auto &decoder = processor->m_decoder;
1370             decoder->WaitForFrameFences(decoder->m_cachedDecodeParams[i]);
1371             decoder->ApplyPictureParameters(decoder->m_cachedDecodeParams[i]);
1372             decoder->RecordCommandBuffer(decoder->m_cachedDecodeParams[i]);
1373         }
1374     }
1375 
1376     // Interleave submissions
1377     for (int i = 0; i < interleaveCacheSize; i++)
1378     {
1379         for (int idx = 0; idx < processors.size(); idx++)
1380         {
1381             auto &decoder = processors[idx]->m_decoder;
1382             auto &test    = m_testDefinitions[idx];
1383             decoder->SubmitQueue(decoder->m_cachedDecodeParams[i]);
1384             if (test->hasOption(DecoderOption::UseStatusQueries))
1385             {
1386                 decoder->QueryDecodeResults(decoder->m_cachedDecodeParams[i]);
1387             }
1388         }
1389     }
1390 
1391     struct InterleavedDecodeResults
1392     {
1393         std::vector<int> correctFrames;
1394         std::vector<int> incorrectFrames;
1395     };
1396     std::vector<InterleavedDecodeResults> results(m_testDefinitions.size());
1397 
1398     for (int i = 0; i < m_testDefinitions.size(); i++)
1399     {
1400         auto &test      = m_testDefinitions[i];
1401         auto &processor = processors[i];
1402         bool hasSeparateOutputImages =
1403             processor->m_decoder->dpbAndOutputCoincide() && !test->hasOption(DecoderOption::FilmGrainPresent);
1404         for (int frameNumber = 0; frameNumber < m_testDefinitions[i]->framesToCheck(); frameNumber++)
1405         {
1406             DecodedFrame frame;
1407             TCU_CHECK_AND_THROW(InternalError, processor->getNextFrame(&frame) > 0,
1408                                 "Expected more frames from the bitstream. Most likely an internal CTS bug, or maybe an "
1409                                 "invalid bitstream");
1410 
1411             if (videoLoggingEnabled())
1412             {
1413                 std::cout << "Frame decoded: picIdx" << static_cast<uint32_t>(frame.pictureIndex) << " "
1414                           << frame.displayWidth << "x" << frame.displayHeight << " "
1415                           << "decode/display " << frame.decodeOrder << "/" << frame.displayOrder << " "
1416                           << "dstImageView " << frame.outputImageView->GetImageView() << std::endl;
1417             }
1418 
1419             DownloadedFrame downloadedFrame = getDecodedImage(
1420                 m_deviceContext,
1421                 hasSeparateOutputImages ? VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR : VK_IMAGE_LAYOUT_VIDEO_DECODE_DST_KHR,
1422                 frame);
1423 
1424             std::string expectedChecksum = checksumForClipFrame(test->getClipInfo(), frameNumber);
1425             std::string actualChecksum   = downloadedFrame.checksum();
1426             if (actualChecksum == expectedChecksum)
1427             {
1428                 results[i].correctFrames.push_back(frameNumber);
1429             }
1430             else
1431             {
1432                 results[i].incorrectFrames.push_back(frameNumber);
1433             }
1434         }
1435     }
1436 
1437     bool allTestsPassed  = true;
1438     int totalFramesCheck = 0;
1439     for (const auto &res : results)
1440     {
1441         if (!res.incorrectFrames.empty())
1442             allTestsPassed = false;
1443         totalFramesCheck += (res.correctFrames.size() + res.incorrectFrames.size());
1444     }
1445     DE_ASSERT(totalFramesCheck == totalFrames);
1446     DE_UNREF(totalFramesCheck);
1447 
1448     if (allTestsPassed)
1449         return tcu::TestStatus::pass(de::toString(totalFrames) + " correctly decoded frames");
1450     else
1451     {
1452         stringstream ss;
1453         ss << "Interleaving failure: ";
1454         for (int i = 0; i < results.size(); i++)
1455         {
1456             const auto &result = results[i];
1457             if (!result.incorrectFrames.empty())
1458             {
1459                 ss << " (stream #" << i << " incorrect frames: ";
1460                 for (int frame : result.incorrectFrames)
1461                     ss << frame << " ";
1462                 ss << "\b)";
1463             }
1464         }
1465         return tcu::TestStatus::fail(ss.str());
1466     }
1467 }
1468 
1469 #endif // #ifdef DE_BUILD_VIDEO
1470 
1471 class VideoDecodeTestCase : public vkt::TestCase
1472 {
1473 public:
VideoDecodeTestCase(tcu::TestContext & context,const char * name,MovePtr<TestDefinition> testDefinition)1474     VideoDecodeTestCase(tcu::TestContext &context, const char *name, MovePtr<TestDefinition> testDefinition)
1475         : vkt::TestCase(context, name)
1476         , m_testDefinition(testDefinition)
1477     {
1478     }
1479 
1480     TestInstance *createInstance(Context &context) const override;
1481     void checkSupport(Context &context) const override;
1482 
1483 private:
1484     MovePtr<TestDefinition> m_testDefinition;
1485 };
1486 
1487 class InterleavingDecodeTestCase : public vkt::TestCase
1488 {
1489 public:
InterleavingDecodeTestCase(tcu::TestContext & context,const char * name,std::vector<MovePtr<TestDefinition>> && testDefinitions)1490     InterleavingDecodeTestCase(tcu::TestContext &context, const char *name,
1491                                std::vector<MovePtr<TestDefinition>> &&testDefinitions)
1492         : vkt::TestCase(context, name)
1493         , m_testDefinitions(std::move(testDefinitions))
1494     {
1495     }
1496 
createInstance(Context & context) const1497     TestInstance *createInstance(Context &context) const override
1498     {
1499 #ifdef DE_BUILD_VIDEO
1500         return new InterleavingDecodeTestInstance(context, m_testDefinitions);
1501 #endif
1502         DE_UNREF(context);
1503         return nullptr;
1504     }
1505     void checkSupport(Context &context) const override;
1506 
1507 private:
1508     std::vector<MovePtr<TestDefinition>> m_testDefinitions;
1509 };
1510 
createInstance(Context & context) const1511 TestInstance *VideoDecodeTestCase::createInstance(Context &context) const
1512 {
1513 #ifdef DE_BUILD_VIDEO
1514     return new VideoDecodeTestInstance(context, m_testDefinition.get());
1515 #endif
1516 
1517 #ifndef DE_BUILD_VIDEO
1518     DE_UNREF(context);
1519     return nullptr;
1520 #endif
1521 }
1522 
checkSupport(Context & context) const1523 void VideoDecodeTestCase::checkSupport(Context &context) const
1524 {
1525     context.requireDeviceFunctionality("VK_KHR_video_queue");
1526     context.requireDeviceFunctionality("VK_KHR_video_decode_queue");
1527     context.requireDeviceFunctionality("VK_KHR_synchronization2");
1528 
1529     switch (m_testDefinition->getTestType())
1530     {
1531     case TEST_TYPE_H264_DECODE_I:
1532     case TEST_TYPE_H264_DECODE_I_P:
1533     case TEST_TYPE_H264_DECODE_CLIP_A:
1534     case TEST_TYPE_H264_DECODE_I_P_NOT_MATCHING_ORDER:
1535     case TEST_TYPE_H264_DECODE_I_P_B_13:
1536     case TEST_TYPE_H264_DECODE_I_P_B_13_NOT_MATCHING_ORDER:
1537     case TEST_TYPE_H264_DECODE_QUERY_RESULT_WITH_STATUS:
1538     case TEST_TYPE_H264_DECODE_RESOLUTION_CHANGE:
1539     case TEST_TYPE_H264_DECODE_RESOLUTION_CHANGE_DPB:
1540     {
1541         context.requireDeviceFunctionality("VK_KHR_video_decode_h264");
1542         break;
1543     }
1544     case TEST_TYPE_H264_DECODE_INLINE_QUERY_RESULT_WITH_STATUS:
1545     case TEST_TYPE_H264_DECODE_RESOURCES_WITHOUT_PROFILES:
1546     {
1547         context.requireDeviceFunctionality("VK_KHR_video_decode_h264");
1548         context.requireDeviceFunctionality("VK_KHR_video_maintenance1");
1549         break;
1550     }
1551     case TEST_TYPE_H265_DECODE_I:
1552     case TEST_TYPE_H265_DECODE_I_P:
1553     case TEST_TYPE_H265_DECODE_CLIP_D:
1554     case TEST_TYPE_H265_DECODE_I_P_NOT_MATCHING_ORDER:
1555     case TEST_TYPE_H265_DECODE_I_P_B_13:
1556     case TEST_TYPE_H265_DECODE_I_P_B_13_NOT_MATCHING_ORDER:
1557     case TEST_TYPE_H265_DECODE_QUERY_RESULT_WITH_STATUS:
1558     case TEST_TYPE_H265_DECODE_SLIST_A:
1559     case TEST_TYPE_H265_DECODE_SLIST_B:
1560     {
1561         context.requireDeviceFunctionality("VK_KHR_video_decode_h265");
1562         break;
1563     }
1564     case TEST_TYPE_H265_DECODE_INLINE_QUERY_RESULT_WITH_STATUS:
1565     case TEST_TYPE_H265_DECODE_RESOURCES_WITHOUT_PROFILES:
1566     {
1567         context.requireDeviceFunctionality("VK_KHR_video_decode_h265");
1568         context.requireDeviceFunctionality("VK_KHR_video_maintenance1");
1569         break;
1570     }
1571     case TEST_TYPE_AV1_DECODE_I:
1572     case TEST_TYPE_AV1_DECODE_I_P:
1573     case TEST_TYPE_AV1_DECODE_I_P_NOT_MATCHING_ORDER:
1574     case TEST_TYPE_AV1_DECODE_BASIC_8:
1575     case TEST_TYPE_AV1_DECODE_BASIC_8_NOT_MATCHING_ORDER:
1576     case TEST_TYPE_AV1_DECODE_BASIC_10:
1577     case TEST_TYPE_AV1_DECODE_ALLINTRA_8:
1578     case TEST_TYPE_AV1_DECODE_ALLINTRA_NOSETUP_8:
1579     case TEST_TYPE_AV1_DECODE_ALLINTRA_BC_8:
1580     case TEST_TYPE_AV1_DECODE_GLOBALMOTION_8:
1581     case TEST_TYPE_AV1_DECODE_CDFUPDATE_8:
1582     case TEST_TYPE_AV1_DECODE_FILMGRAIN_8:
1583     case TEST_TYPE_AV1_DECODE_SVCL1T2_8:
1584     case TEST_TYPE_AV1_DECODE_SUPERRES_8:
1585     case TEST_TYPE_AV1_DECODE_SIZEUP_8:
1586     case TEST_TYPE_AV1_DECODE_ARGON_SEQCHANGE_AFFINE_8:
1587     case TEST_TYPE_AV1_DECODE_ORDERHINT_10:
1588     case TEST_TYPE_AV1_DECODE_FORWARDKEYFRAME_10:
1589     case TEST_TYPE_AV1_DECODE_LOSSLESS_10:
1590     case TEST_TYPE_AV1_DECODE_LOOPFILTER_10:
1591     case TEST_TYPE_AV1_DECODE_CDEF_10:
1592     case TEST_TYPE_AV1_DECODE_ARGON_FILMGRAIN_10:
1593     case TEST_TYPE_AV1_DECODE_ARGON_TEST_787:
1594     {
1595         context.requireDeviceFunctionality("VK_KHR_video_decode_av1");
1596         break;
1597     }
1598     default:
1599         TCU_THROW(InternalError, "Unknown TestType");
1600     }
1601 
1602     const VkExtensionProperties *extensionProperties = m_testDefinition->extensionProperties(0);
1603     switch (m_testDefinition->getCodecOperation(0))
1604     {
1605     case VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR:
1606         if (strcmp(extensionProperties->extensionName, VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_EXTENSION_NAME) ||
1607             extensionProperties->specVersion != VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_SPEC_VERSION)
1608         {
1609             tcu::die("The requested decoder h.264 Codec STD version is NOT supported. The supported decoder h.264 "
1610                      "Codec STD version is version %d of %s\n",
1611                      VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_SPEC_VERSION,
1612                      VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_EXTENSION_NAME);
1613         }
1614         break;
1615     case VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR:
1616         if (strcmp(extensionProperties->extensionName, VK_STD_VULKAN_VIDEO_CODEC_H265_DECODE_EXTENSION_NAME) ||
1617             extensionProperties->specVersion != VK_STD_VULKAN_VIDEO_CODEC_H265_DECODE_SPEC_VERSION)
1618         {
1619             tcu::die("The requested decoder h.265 Codec STD version is NOT supported. The supported decoder h.265 "
1620                      "Codec STD version is version %d of %s\n",
1621                      VK_STD_VULKAN_VIDEO_CODEC_H265_DECODE_SPEC_VERSION,
1622                      VK_STD_VULKAN_VIDEO_CODEC_H265_DECODE_EXTENSION_NAME);
1623         }
1624         break;
1625     case VK_VIDEO_CODEC_OPERATION_DECODE_AV1_BIT_KHR:
1626         if (strcmp(extensionProperties->extensionName, VK_STD_VULKAN_VIDEO_CODEC_AV1_DECODE_EXTENSION_NAME) ||
1627             extensionProperties->specVersion != VK_STD_VULKAN_VIDEO_CODEC_AV1_DECODE_SPEC_VERSION)
1628         {
1629             tcu::die("The requested AV1 Codec STD version is NOT supported. The supported AV1 STD version is version "
1630                      "%d of %s\n",
1631                      VK_STD_VULKAN_VIDEO_CODEC_AV1_DECODE_SPEC_VERSION,
1632                      VK_STD_VULKAN_VIDEO_CODEC_AV1_DECODE_EXTENSION_NAME);
1633         }
1634         break;
1635     default:
1636         TCU_FAIL("Unsupported codec type");
1637     }
1638 }
1639 
checkSupport(Context & context) const1640 void InterleavingDecodeTestCase::checkSupport(Context &context) const
1641 {
1642     context.requireDeviceFunctionality("VK_KHR_video_queue");
1643     context.requireDeviceFunctionality("VK_KHR_video_decode_queue");
1644     context.requireDeviceFunctionality("VK_KHR_synchronization2");
1645 
1646 #ifdef DE_DEBUG
1647     DE_ASSERT(!m_testDefinitions.empty());
1648     TestType firstType = m_testDefinitions[0]->getTestType();
1649     for (const auto &test : m_testDefinitions)
1650         DE_ASSERT(test->getTestType() == firstType);
1651 #endif
1652     switch (m_testDefinitions[0]->getTestType())
1653     {
1654     case TEST_TYPE_H264_DECODE_INTERLEAVED:
1655     {
1656         context.requireDeviceFunctionality("VK_KHR_video_decode_h264");
1657         break;
1658     }
1659     case TEST_TYPE_H264_H265_DECODE_INTERLEAVED:
1660     {
1661         context.requireDeviceFunctionality("VK_KHR_video_decode_h264");
1662         context.requireDeviceFunctionality("VK_KHR_video_decode_h265");
1663         break;
1664     }
1665     default:
1666         TCU_THROW(InternalError, "Unknown interleaving test type");
1667     }
1668 }
1669 
1670 } // namespace
1671 
createVideoDecodeTests(tcu::TestContext & testCtx)1672 tcu::TestCaseGroup *createVideoDecodeTests(tcu::TestContext &testCtx)
1673 {
1674     const uint32_t baseSeed = static_cast<uint32_t>(testCtx.getCommandLine().getBaseSeed());
1675     MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "decode"));
1676     MovePtr<tcu::TestCaseGroup> h264Group(new tcu::TestCaseGroup(testCtx, "h264", "H.264 video codec"));
1677     MovePtr<tcu::TestCaseGroup> h265Group(new tcu::TestCaseGroup(testCtx, "h265", "H.265 video codec"));
1678     MovePtr<tcu::TestCaseGroup> av1Group(new tcu::TestCaseGroup(testCtx, "av1", "AV1 video codec"));
1679 
1680     for (bool layeredDpb : {true, false})
1681     {
1682         for (const auto &decodeTest : g_DecodeTests)
1683         {
1684             auto defn                  = TestDefinition::create(decodeTest, baseSeed, layeredDpb);
1685             const std::string testName = defn->getTestName();
1686             uint32_t rngSeed           = baseSeed ^ deStringHash(testName.c_str());
1687             defn->updateHash(rngSeed);
1688 
1689             auto testCodec = getTestCodec(decodeTest.type);
1690             if (testCodec == TEST_CODEC_H264)
1691                 h264Group->addChild(new VideoDecodeTestCase(testCtx, testName.c_str(), defn));
1692             else if (testCodec == TEST_CODEC_H265)
1693                 h265Group->addChild(new VideoDecodeTestCase(testCtx, testName.c_str(), defn));
1694             else
1695                 av1Group->addChild(new VideoDecodeTestCase(testCtx, testName.c_str(), defn));
1696         }
1697         for (const auto &interleavingTest : g_InterleavingTests)
1698         {
1699             std::vector<MovePtr<TestDefinition>> defns;
1700             DecodeTestParam streamA{interleavingTest.type, interleavingTest.streamA};
1701             DecodeTestParam streamB{interleavingTest.type, interleavingTest.streamB};
1702             auto defnA                 = TestDefinition::create(streamA, baseSeed, layeredDpb);
1703             auto defnB                 = TestDefinition::create(streamB, baseSeed, layeredDpb);
1704             const std::string testName = defnA->getTestName();
1705             defns.push_back(std::move(defnA));
1706             defns.push_back(std::move(defnB));
1707 
1708             auto testCodec = getTestCodec(interleavingTest.type);
1709             if (testCodec == TEST_CODEC_H264)
1710                 h264Group->addChild(new InterleavingDecodeTestCase(testCtx, testName.c_str(), std::move(defns)));
1711             else if (testCodec == TEST_CODEC_H265)
1712                 h265Group->addChild(new InterleavingDecodeTestCase(testCtx, testName.c_str(), std::move(defns)));
1713             else
1714                 av1Group->addChild(new InterleavingDecodeTestCase(testCtx, testName.c_str(), std::move(defns)));
1715         }
1716     } // layered true / false
1717 
1718     group->addChild(h264Group.release());
1719     group->addChild(h265Group.release());
1720     group->addChild(av1Group.release());
1721 
1722     return group.release();
1723 }
1724 
1725 } // namespace video
1726 } // namespace vkt
1727