xref: /aosp_15_r20/external/deqp/external/vulkancts/modules/vulkan/video/vktVideoDecodeTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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 
187     TEST_TYPE_AV1_DECODE_I,
188     TEST_TYPE_AV1_DECODE_I_P,
189     TEST_TYPE_AV1_DECODE_I_P_NOT_MATCHING_ORDER,
190     TEST_TYPE_AV1_DECODE_BASIC_8,
191     TEST_TYPE_AV1_DECODE_BASIC_8_NOT_MATCHING_ORDER,
192     TEST_TYPE_AV1_DECODE_ALLINTRA_8,
193     TEST_TYPE_AV1_DECODE_ALLINTRA_NOSETUP_8,
194     TEST_TYPE_AV1_DECODE_ALLINTRA_BC_8,
195     TEST_TYPE_AV1_DECODE_CDFUPDATE_8,
196     TEST_TYPE_AV1_DECODE_GLOBALMOTION_8,
197     TEST_TYPE_AV1_DECODE_FILMGRAIN_8,
198     TEST_TYPE_AV1_DECODE_SVCL1T2_8,
199     TEST_TYPE_AV1_DECODE_SUPERRES_8,
200     TEST_TYPE_AV1_DECODE_SIZEUP_8,
201 
202     TEST_TYPE_AV1_DECODE_BASIC_10,
203     TEST_TYPE_AV1_DECODE_ORDERHINT_10,
204     TEST_TYPE_AV1_DECODE_FORWARDKEYFRAME_10,
205     TEST_TYPE_AV1_DECODE_LOSSLESS_10,
206     TEST_TYPE_AV1_DECODE_LOOPFILTER_10,
207     TEST_TYPE_AV1_DECODE_CDEF_10,
208     TEST_TYPE_AV1_DECODE_ARGON_FILMGRAIN_10,
209     TEST_TYPE_AV1_DECODE_ARGON_TEST_787,
210 
211     TEST_TYPE_AV1_DECODE_ARGON_SEQCHANGE_AFFINE_8,
212 
213     TEST_TYPE_LAST
214 };
215 
getTestName(TestType type)216 const char *getTestName(TestType type)
217 {
218     const char *testName;
219     switch (type)
220     {
221     case TEST_TYPE_H264_DECODE_I:
222         testName = "h264_i";
223         break;
224     case TEST_TYPE_H264_DECODE_I_P:
225         testName = "h264_i_p";
226         break;
227     case TEST_TYPE_H264_DECODE_CLIP_A:
228         testName = "h264_420_8bit_high_176x144_30frames";
229         break;
230     case TEST_TYPE_H264_DECODE_I_P_NOT_MATCHING_ORDER:
231         testName = "h264_i_p_not_matching_order";
232         break;
233     case TEST_TYPE_H264_DECODE_I_P_B_13:
234         testName = "h264_i_p_b_13";
235         break;
236     case TEST_TYPE_H264_DECODE_I_P_B_13_NOT_MATCHING_ORDER:
237         testName = "h264_i_p_b_13_not_matching_order";
238         break;
239     case TEST_TYPE_H264_DECODE_QUERY_RESULT_WITH_STATUS:
240         testName = "h264_query_with_status";
241         break;
242     case TEST_TYPE_H264_DECODE_INLINE_QUERY_RESULT_WITH_STATUS:
243         testName = "h264_inline_query_with_status";
244         break;
245     case TEST_TYPE_H264_DECODE_RESOURCES_WITHOUT_PROFILES:
246         testName = "h264_resources_without_profiles";
247         break;
248     case TEST_TYPE_H264_DECODE_RESOLUTION_CHANGE:
249         testName = "h264_resolution_change";
250         break;
251     case TEST_TYPE_H264_DECODE_RESOLUTION_CHANGE_DPB:
252         testName = "h264_resolution_change_dpb";
253         break;
254     case TEST_TYPE_H264_DECODE_INTERLEAVED:
255         testName = "h264_interleaved";
256         break;
257     case TEST_TYPE_H264_H265_DECODE_INTERLEAVED:
258         testName = "h264_h265_interleaved";
259         break;
260     case TEST_TYPE_H265_DECODE_I:
261         testName = "h265_i";
262         break;
263     case TEST_TYPE_H265_DECODE_I_P:
264         testName = "h265_i_p";
265         break;
266     case TEST_TYPE_H265_DECODE_CLIP_D:
267         testName = "h265_420_8bit_main_176x144_30frames";
268         break;
269     case TEST_TYPE_H265_DECODE_I_P_NOT_MATCHING_ORDER:
270         testName = "h265_i_p_not_matching_order";
271         break;
272     case TEST_TYPE_H265_DECODE_I_P_B_13:
273         testName = "h265_i_p_b_13";
274         break;
275     case TEST_TYPE_H265_DECODE_I_P_B_13_NOT_MATCHING_ORDER:
276         testName = "h265_i_p_b_13_not_matching_order";
277         break;
278     case TEST_TYPE_H265_DECODE_QUERY_RESULT_WITH_STATUS:
279         testName = "h265_query_with_status";
280         break;
281     case TEST_TYPE_H265_DECODE_INLINE_QUERY_RESULT_WITH_STATUS:
282         testName = "h265_inline_query_with_status";
283         break;
284     case TEST_TYPE_H265_DECODE_RESOURCES_WITHOUT_PROFILES:
285         testName = "h265_resources_without_profiles";
286         break;
287     case TEST_TYPE_AV1_DECODE_I:
288         testName = "av1_i";
289         break;
290     case TEST_TYPE_AV1_DECODE_I_P:
291         testName = "av1_i_p";
292         break;
293     case TEST_TYPE_AV1_DECODE_I_P_NOT_MATCHING_ORDER:
294         testName = "av1_i_p_not_matching_order";
295         break;
296     case TEST_TYPE_AV1_DECODE_BASIC_8:
297         testName = "av1_basic_8";
298         break;
299     case TEST_TYPE_AV1_DECODE_BASIC_8_NOT_MATCHING_ORDER:
300         testName = "av1_basic_8_not_matching_order";
301         break;
302     case TEST_TYPE_AV1_DECODE_BASIC_10:
303         testName = "av1_basic_10";
304         break;
305     case TEST_TYPE_AV1_DECODE_ALLINTRA_8:
306         testName = "av1_allintra_8";
307         break;
308     case TEST_TYPE_AV1_DECODE_ALLINTRA_NOSETUP_8:
309         testName = "av1_allintra_nosetup_8";
310         break;
311     case TEST_TYPE_AV1_DECODE_ALLINTRA_BC_8:
312         testName = "av1_allintrabc_8";
313         break;
314     case TEST_TYPE_AV1_DECODE_CDFUPDATE_8:
315         testName = "av1_cdfupdate_8";
316         break;
317     case TEST_TYPE_AV1_DECODE_GLOBALMOTION_8:
318         testName = "av1_globalmotion_8";
319         break;
320     case TEST_TYPE_AV1_DECODE_FILMGRAIN_8:
321         testName = "av1_filmgrain_8";
322         break;
323     case TEST_TYPE_AV1_DECODE_SVCL1T2_8:
324         testName = "av1_svcl1t2_8";
325         break;
326     case TEST_TYPE_AV1_DECODE_SUPERRES_8:
327         testName = "av1_superres_8";
328         break;
329     case TEST_TYPE_AV1_DECODE_SIZEUP_8:
330         testName = "av1_sizeup_8";
331         break;
332     case TEST_TYPE_AV1_DECODE_ARGON_SEQCHANGE_AFFINE_8:
333         testName = "av1_argon_seqchange_affine_8";
334         break;
335     case TEST_TYPE_AV1_DECODE_ORDERHINT_10:
336         testName = "av1_orderhint_10";
337         break;
338     case TEST_TYPE_AV1_DECODE_FORWARDKEYFRAME_10:
339         testName = "av1_forwardkeyframe_10";
340         break;
341     case TEST_TYPE_AV1_DECODE_LOSSLESS_10:
342         testName = "av1_lossless_10";
343         break;
344     case TEST_TYPE_AV1_DECODE_LOOPFILTER_10:
345         testName = "av1_loopfilter_10";
346         break;
347     case TEST_TYPE_AV1_DECODE_CDEF_10:
348         testName = "av1_cdef_10";
349         break;
350     case TEST_TYPE_AV1_DECODE_ARGON_FILMGRAIN_10:
351         testName = "av1_argon_filmgrain_10_test1019";
352         break;
353     case TEST_TYPE_AV1_DECODE_ARGON_TEST_787:
354         testName = "av1_argon_test787";
355         break;
356     default:
357         TCU_THROW(InternalError, "Unknown TestType");
358     }
359     return testName;
360 }
361 
362 enum DecoderOption : uint32_t
363 {
364     // The default is to do nothing additional to ordinary playback.
365     Default = 0,
366     // All decode operations will have their status checked for success (Q2 2023: not all vendors support these)
367     UseStatusQueries = 1 << 0,
368     // Same as above, but tested with inline queries from the video_maintenance1 extension.
369     UseInlineStatusQueries = 1 << 1,
370     // Do not playback the clip in the "normal fashion", instead cached decode parameters for later process
371     // this is primarily used to support out-of-order submission test cases.
372     // It is a limited mode of operation, only able to cache 32 frames. This is ample to test out-of-order recording.
373     CachedDecoding = 1 << 2,
374     // When a parameter object changes the resolution of the test content, and the new video session would otherwise
375     // still be compatible with the last session (for example, larger decode surfaces preceeding smaller decode surfaces,
376     // a frame downsize), force the session to be recreated anyway.
377     RecreateDPBImages = 1 << 3,
378     // Test profile-less resources from the video_mainteance1 extension.
379     ResourcesWithoutProfiles = 1 << 4,
380     FilmGrainPresent         = 1 << 5,
381     IntraOnlyDecoding        = 1 << 6,
382     AnnexB                   = 1 << 7,
383 };
384 
385 static const int ALL_FRAMES = 0;
386 
387 struct BaseDecodeParam
388 {
389     ClipName clip;
390     int framesToCheck;
391     DecoderOption decoderOptions;
392 };
393 
394 struct DecodeTestParam
395 {
396     TestType type;
397     BaseDecodeParam stream;
398 
399 } g_DecodeTests[] = {
400     {TEST_TYPE_H264_DECODE_I, {CLIP_A, 1, DecoderOption::Default}},
401     {TEST_TYPE_H264_DECODE_I_P, {CLIP_A, 2, DecoderOption::Default}},
402     {TEST_TYPE_H264_DECODE_I_P_NOT_MATCHING_ORDER, {CLIP_A, 2, DecoderOption::CachedDecoding}},
403     {TEST_TYPE_H264_DECODE_CLIP_A, {CLIP_A, ALL_FRAMES, DecoderOption::Default}},
404     {TEST_TYPE_H264_DECODE_I_P_B_13, {CLIP_H264_4K_26_IBP_MAIN, ALL_FRAMES, DecoderOption::Default}},
405     {TEST_TYPE_H264_DECODE_I_P_B_13_NOT_MATCHING_ORDER,
406      {CLIP_H264_4K_26_IBP_MAIN, ALL_FRAMES, DecoderOption::CachedDecoding}},
407     {TEST_TYPE_H264_DECODE_QUERY_RESULT_WITH_STATUS, {CLIP_A, ALL_FRAMES, DecoderOption::UseStatusQueries}},
408     {TEST_TYPE_H264_DECODE_INLINE_QUERY_RESULT_WITH_STATUS,
409      {CLIP_A, ALL_FRAMES, (DecoderOption)(DecoderOption::UseStatusQueries | DecoderOption::UseInlineStatusQueries)}},
410     {TEST_TYPE_H264_DECODE_RESOURCES_WITHOUT_PROFILES, {CLIP_A, ALL_FRAMES, DecoderOption::ResourcesWithoutProfiles}},
411     {TEST_TYPE_H264_DECODE_RESOLUTION_CHANGE, {CLIP_C, ALL_FRAMES, DecoderOption::Default}},
412     {TEST_TYPE_H264_DECODE_RESOLUTION_CHANGE_DPB, {CLIP_C, ALL_FRAMES, DecoderOption::RecreateDPBImages}},
413 
414     {TEST_TYPE_H265_DECODE_I, {CLIP_D, 1, DecoderOption::Default}},
415     {TEST_TYPE_H265_DECODE_I_P, {CLIP_D, 2, DecoderOption::Default}},
416     {TEST_TYPE_H265_DECODE_I_P_NOT_MATCHING_ORDER, {CLIP_D, 2, DecoderOption::CachedDecoding}},
417     {TEST_TYPE_H265_DECODE_I_P_B_13, {CLIP_JELLY_HEVC, ALL_FRAMES, DecoderOption::Default}},
418     {TEST_TYPE_H265_DECODE_I_P_B_13_NOT_MATCHING_ORDER, {CLIP_JELLY_HEVC, ALL_FRAMES, DecoderOption::CachedDecoding}},
419     {TEST_TYPE_H265_DECODE_CLIP_D, {CLIP_D, ALL_FRAMES, DecoderOption::Default}},
420     {TEST_TYPE_H265_DECODE_QUERY_RESULT_WITH_STATUS, {CLIP_D, ALL_FRAMES, DecoderOption::UseStatusQueries}},
421     {TEST_TYPE_H265_DECODE_INLINE_QUERY_RESULT_WITH_STATUS,
422      {CLIP_D, ALL_FRAMES, (DecoderOption)(DecoderOption::UseStatusQueries | DecoderOption::UseInlineStatusQueries)}},
423     {TEST_TYPE_H265_DECODE_RESOURCES_WITHOUT_PROFILES, {CLIP_D, ALL_FRAMES, DecoderOption::ResourcesWithoutProfiles}},
424 
425     {TEST_TYPE_AV1_DECODE_I, {CLIP_BASIC_8, 1, DecoderOption::Default}},
426     {TEST_TYPE_AV1_DECODE_I_P, {CLIP_BASIC_8, 2, DecoderOption::Default}},
427     {TEST_TYPE_AV1_DECODE_I_P_NOT_MATCHING_ORDER, {CLIP_BASIC_8, 2, DecoderOption::CachedDecoding}},
428     {TEST_TYPE_AV1_DECODE_BASIC_8, {CLIP_BASIC_8, ALL_FRAMES, DecoderOption::Default}},
429     {TEST_TYPE_AV1_DECODE_BASIC_8_NOT_MATCHING_ORDER, {CLIP_BASIC_8, 24, DecoderOption::CachedDecoding}},
430     {TEST_TYPE_AV1_DECODE_ALLINTRA_8, {CLIP_ALLINTRA_8, ALL_FRAMES, DecoderOption::Default}},
431     {TEST_TYPE_AV1_DECODE_ALLINTRA_NOSETUP_8, {CLIP_ALLINTRA_8, ALL_FRAMES, DecoderOption::IntraOnlyDecoding}},
432     {TEST_TYPE_AV1_DECODE_ALLINTRA_BC_8, {CLIP_ALLINTRA_INTRABC_8, ALL_FRAMES, DecoderOption::Default}},
433     {TEST_TYPE_AV1_DECODE_CDFUPDATE_8, {CLIP_CDFUPDATE_8, ALL_FRAMES, DecoderOption::Default}},
434     {TEST_TYPE_AV1_DECODE_GLOBALMOTION_8, {CLIP_GLOBALMOTION_8, ALL_FRAMES, DecoderOption::Default}},
435     {TEST_TYPE_AV1_DECODE_FILMGRAIN_8, {CLIP_FILMGRAIN_8, ALL_FRAMES, DecoderOption::FilmGrainPresent}},
436     {TEST_TYPE_AV1_DECODE_SVCL1T2_8, {CLIP_SVCL1T2_8, ALL_FRAMES, DecoderOption::Default}},
437     {TEST_TYPE_AV1_DECODE_SUPERRES_8, {CLIP_SUPERRES_8, ALL_FRAMES, DecoderOption::Default}},
438     {TEST_TYPE_AV1_DECODE_SIZEUP_8, {CLIP_SIZEUP_8, ALL_FRAMES, DecoderOption::Default}},
439     {TEST_TYPE_AV1_DECODE_BASIC_10, {CLIP_BASIC_10, ALL_FRAMES, DecoderOption::Default}},
440     {TEST_TYPE_AV1_DECODE_ORDERHINT_10, {CLIP_ORDERHINT_10, ALL_FRAMES, DecoderOption::Default}},
441     {TEST_TYPE_AV1_DECODE_FORWARDKEYFRAME_10, {CLIP_FORWARDKEYFRAME_10, ALL_FRAMES, DecoderOption::Default}},
442     {TEST_TYPE_AV1_DECODE_LOSSLESS_10, {CLIP_LOSSLESS_10, ALL_FRAMES, DecoderOption::Default}},
443     {TEST_TYPE_AV1_DECODE_LOOPFILTER_10, {CLIP_LOOPFILTER_10, ALL_FRAMES, DecoderOption::Default}},
444     {TEST_TYPE_AV1_DECODE_CDEF_10, {CLIP_CDEF_10, ALL_FRAMES, DecoderOption::Default}},
445 
446     // TODO: Did not have sufficient implementations to find out why this is failing.
447     // {TEST_TYPE_AV1_DECODE_ARGON_SEQCHANGE_AFFINE_8, {CLIP_ARGON_SEQCHANGE_AFFINE_8, 4, DecoderOption::AnnexB}},
448 
449     // TODO: Frames after the first hit asserts in the parser. First frame decodes correctly.
450     // TODO: Filmgrain option not set here, because the first frame doesn't have it enabled.
451     {TEST_TYPE_AV1_DECODE_ARGON_FILMGRAIN_10, {CLIP_ARGON_FILMGRAIN_10, 1, (DecoderOption)(DecoderOption::AnnexB)}},
452 
453     // TODO: Did not have sufficient implementations to find out why this is failing.
454     //{TEST_TYPE_AV1_DECODE_ARGON_TEST_787, {CLIP_ARGON_TEST_787, 2, DecoderOption::AnnexB}},
455 };
456 
457 struct InterleavingDecodeTestParams
458 {
459     TestType type;
460     BaseDecodeParam streamA;
461     BaseDecodeParam streamB;
462 } g_InterleavingTests[] = {
463     {TEST_TYPE_H264_DECODE_INTERLEAVED,
464      {CLIP_A, ALL_FRAMES, DecoderOption::CachedDecoding},
465      {CLIP_A, ALL_FRAMES, DecoderOption::CachedDecoding}},
466     {TEST_TYPE_H264_H265_DECODE_INTERLEAVED,
467      {CLIP_A, ALL_FRAMES, DecoderOption::CachedDecoding},
468      {CLIP_D, ALL_FRAMES, DecoderOption::CachedDecoding}},
469 };
470 
471 class TestDefinition
472 {
473 public:
create(DecodeTestParam params,uint32_t baseSeed)474     static MovePtr<TestDefinition> create(DecodeTestParam params, uint32_t baseSeed)
475     {
476         return MovePtr<TestDefinition>(new TestDefinition(params, baseSeed));
477     }
478 
TestDefinition(DecodeTestParam params,uint32_t baseSeed)479     TestDefinition(DecodeTestParam params, uint32_t baseSeed)
480         : m_params(params)
481         , m_info(clipInfo(params.stream.clip))
482         , m_hash(baseSeed)
483     {
484         for (const auto &profile : m_info->sessionProfiles)
485         {
486             m_profiles.push_back(VkVideoCoreProfile(profile.codecOperation, profile.subsamplingFlags,
487                                                     profile.lumaBitDepth, profile.chromaBitDepth, profile.profileIDC,
488                                                     params.stream.decoderOptions & DecoderOption::FilmGrainPresent));
489         }
490 
491         if (m_params.stream.framesToCheck == ALL_FRAMES)
492         {
493             m_params.stream.framesToCheck = m_info->totalFrames;
494         }
495 
496         if (params.type == TEST_TYPE_H264_DECODE_RESOLUTION_CHANGE_DPB)
497         {
498             m_pictureParameterUpdateTriggerHack = 3;
499         }
500     }
501 
getTestType() const502     TestType getTestType() const
503     {
504         return m_params.type;
505     }
506 
getClipFilename() const507     const char *getClipFilename() const
508     {
509         return m_info->filename;
510     }
511 
getClipInfo() const512     const ClipInfo *getClipInfo() const
513     {
514         return m_info;
515     };
516 
getCodecOperation(int session) const517     VkVideoCodecOperationFlagBitsKHR getCodecOperation(int session) const
518     {
519         return m_profiles[session].GetCodecType();
520     }
521 
getProfile(int session) const522     const VkVideoCoreProfile *getProfile(int session) const
523     {
524         return &m_profiles[session];
525     }
526 
framesToCheck() const527     int framesToCheck() const
528     {
529         return m_params.stream.framesToCheck;
530     }
531 
hasOption(DecoderOption o) const532     bool hasOption(DecoderOption o) const
533     {
534         return (m_params.stream.decoderOptions & o) != 0;
535     }
536 
getParamaterUpdateHackRequirement() const537     int getParamaterUpdateHackRequirement() const
538     {
539         return m_pictureParameterUpdateTriggerHack;
540     }
541 
requiredDeviceFlags() const542     VideoDevice::VideoDeviceFlags requiredDeviceFlags() const
543     {
544         VideoDevice::VideoDeviceFlags flags = VideoDevice::VIDEO_DEVICE_FLAG_REQUIRE_SYNC2_OR_NOT_SUPPORTED;
545 
546         if (hasOption(DecoderOption::UseStatusQueries))
547             flags |= VideoDevice::VIDEO_DEVICE_FLAG_QUERY_WITH_STATUS_FOR_DECODE_SUPPORT;
548 
549         if (hasOption(DecoderOption::UseInlineStatusQueries) || hasOption(DecoderOption::ResourcesWithoutProfiles))
550             flags |= VideoDevice::VIDEO_DEVICE_FLAG_REQUIRE_MAINTENANCE_1;
551 
552         return flags;
553     }
554 
extensionProperties(int session) const555     const VkExtensionProperties *extensionProperties(int session) const
556     {
557         static const VkExtensionProperties h264StdExtensionVersion = {
558             VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_EXTENSION_NAME, VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_SPEC_VERSION};
559         static const VkExtensionProperties h265StdExtensionVersion = {
560             VK_STD_VULKAN_VIDEO_CODEC_H265_DECODE_EXTENSION_NAME, VK_STD_VULKAN_VIDEO_CODEC_H265_DECODE_SPEC_VERSION};
561         static const VkExtensionProperties av1StdExtensionVersion = {
562             VK_STD_VULKAN_VIDEO_CODEC_AV1_DECODE_EXTENSION_NAME, VK_STD_VULKAN_VIDEO_CODEC_AV1_DECODE_SPEC_VERSION};
563 
564         switch (m_profiles[session].GetCodecType())
565         {
566         case VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR:
567             return &h264StdExtensionVersion;
568         case VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR:
569             return &h265StdExtensionVersion;
570         case VK_VIDEO_CODEC_OPERATION_DECODE_AV1_BIT_KHR:
571             return &av1StdExtensionVersion;
572         default:
573             tcu::die("Unsupported video codec %s\n", util::codecToName(m_profiles[session].GetCodecType()));
574             break;
575         }
576 
577         TCU_THROW(InternalError, "Unsupported codec");
578     };
579 
updateHash(uint32_t baseHash)580     void updateHash(uint32_t baseHash)
581     {
582         m_hash = deUint32Hash(baseHash);
583     }
584 
585 private:
586     DecodeTestParam m_params;
587     const ClipInfo *m_info{};
588     uint32_t m_hash{};
589     std::vector<VkVideoCoreProfile> m_profiles;
590     // The 1-based count of parameter set updates after which to force
591     // a parameter object release.  This is required due to the design
592     // of the NVIDIA decode-client API. It sends parameter updates and
593     // expects constructed parameter objects back synchronously,
594     // before the next video session is created in a following
595     // BeginSequence call.
596     int m_pictureParameterUpdateTriggerHack{0}; // Zero is "off"
597 };
598 
599 // Vulkan video is not supported on android platform
600 // all external libraries, helper functions and test instances has been excluded
601 #ifdef DE_BUILD_VIDEO
602 
decoderFromTestDefinition(DeviceContext * devctx,const TestDefinition & test,bool forceDisableFilmGrain=false)603 static std::shared_ptr<VideoBaseDecoder> decoderFromTestDefinition(DeviceContext *devctx, const TestDefinition &test,
604                                                                    bool forceDisableFilmGrain = false)
605 {
606     VkSharedBaseObj<VulkanVideoFrameBuffer> vkVideoFrameBuffer;
607     VK_CHECK(VulkanVideoFrameBuffer::Create(devctx, test.hasOption(DecoderOption::UseStatusQueries),
608                                             test.hasOption(DecoderOption::ResourcesWithoutProfiles),
609                                             vkVideoFrameBuffer));
610 
611     VideoBaseDecoder::Parameters params;
612     params.profile                           = test.getProfile(0);
613     params.context                           = devctx;
614     params.framebuffer                       = vkVideoFrameBuffer;
615     params.framesToCheck                     = test.framesToCheck();
616     params.queryDecodeStatus                 = test.hasOption(DecoderOption::UseStatusQueries);
617     params.useInlineQueries                  = test.hasOption(DecoderOption::UseInlineStatusQueries);
618     params.resourcesWithoutProfiles          = test.hasOption(DecoderOption::ResourcesWithoutProfiles);
619     params.outOfOrderDecoding                = test.hasOption(DecoderOption::CachedDecoding);
620     params.alwaysRecreateDPB                 = test.hasOption(DecoderOption::RecreateDPBImages);
621     params.intraOnlyDecoding                 = test.hasOption(DecoderOption::IntraOnlyDecoding);
622     params.pictureParameterUpdateTriggerHack = test.getParamaterUpdateHackRequirement();
623     params.forceDisableFilmGrain             = forceDisableFilmGrain;
624 
625     return std::make_shared<VideoBaseDecoder>(std::move(params));
626 }
627 
628 struct DownloadedFrame
629 {
630     std::vector<uint8_t> luma;
631     std::vector<uint8_t> cb;
632     std::vector<uint8_t> cr;
633 
checksumvkt::video::__anonf0d182de0111::DownloadedFrame634     std::string checksum() const
635     {
636         MD5Digest digest;
637         MD5Context ctx{};
638         MD5Init(&ctx);
639         MD5Update(&ctx, luma.data(), luma.size());
640         MD5Update(&ctx, cb.data(), cb.size());
641         MD5Update(&ctx, cr.data(), cr.size());
642         MD5Final(&digest, &ctx);
643         return MD5DigestToBase16(digest);
644     }
645 };
646 
roru16(uint16_t x,uint16_t n)647 DE_INLINE uint16_t roru16(uint16_t x, uint16_t n)
648 {
649     return n == 0 ? x : (x >> n) | (x << (-n & 15));
650 }
651 
copyAllPlanesToBuffers(const DeviceDriver & vkd,const DecodedFrame & frame,const VkExtent2D & imageExtent,const PlanarFormatDescription & planarDescription,VkCommandBuffer cmdbuf,std::vector<std::unique_ptr<BufferWithMemory>> & planeBuffers)652 static void copyAllPlanesToBuffers(const DeviceDriver &vkd, const DecodedFrame &frame, const VkExtent2D &imageExtent,
653                                    const PlanarFormatDescription &planarDescription, VkCommandBuffer cmdbuf,
654                                    std::vector<std::unique_ptr<BufferWithMemory>> &planeBuffers)
655 {
656     for (uint32_t planeNdx = 0; planeNdx < planarDescription.numPlanes; planeNdx++)
657     {
658         uint32_t width = imageExtent.width;
659         if (planeNdx > 0)
660             width = (width + 1) & ~1;
661 
662         width /= planarDescription.planes[planeNdx].widthDivisor;
663         uint32_t height                    = imageExtent.height / planarDescription.planes[planeNdx].heightDivisor;
664         VkExtent3D planeExtent             = {width, height, 1u};
665         const VkImageAspectFlagBits aspect = getPlaneAspect(planeNdx);
666         {
667 
668             const VkImageMemoryBarrier preCopyBarrier = {
669                 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
670                 DE_NULL,
671                 0u,
672                 VK_ACCESS_TRANSFER_READ_BIT,
673                 VK_IMAGE_LAYOUT_GENERAL,
674                 VK_IMAGE_LAYOUT_GENERAL,
675                 VK_QUEUE_FAMILY_IGNORED,
676                 VK_QUEUE_FAMILY_IGNORED,
677                 frame.outputImageView->GetImageResource()->GetImage(),
678                 {(VkImageAspectFlags)aspect, 0u, 1u, frame.imageLayerIndex, 1u}};
679 
680             vkd.cmdPipelineBarrier(cmdbuf, (VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
681                                    (VkPipelineStageFlags)VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0u, 0u,
682                                    (const VkMemoryBarrier *)DE_NULL, 0u, (const VkBufferMemoryBarrier *)DE_NULL, 1u,
683                                    &preCopyBarrier);
684         }
685         {
686             const VkBufferImageCopy copy = {0u, // bufferOffset
687                                             0u, // bufferRowLength
688                                             0u, // bufferImageHeight
689                                             {(VkImageAspectFlags)aspect, 0u, frame.imageLayerIndex, 1u},
690                                             makeOffset3D(0u, 0u, 0u),
691                                             planeExtent};
692             vkd.cmdCopyImageToBuffer(cmdbuf, frame.outputImageView->GetImageResource()->GetImage(),
693                                      VK_IMAGE_LAYOUT_GENERAL, planeBuffers[planeNdx]->get(), 1u, &copy);
694         }
695         {
696             const VkBufferMemoryBarrier postCopyBarrier = {VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
697                                                            DE_NULL,
698                                                            VK_ACCESS_TRANSFER_WRITE_BIT,
699                                                            VK_ACCESS_HOST_READ_BIT,
700                                                            VK_QUEUE_FAMILY_IGNORED,
701                                                            VK_QUEUE_FAMILY_IGNORED,
702                                                            planeBuffers[planeNdx]->get(),
703                                                            0u,
704                                                            VK_WHOLE_SIZE};
705 
706             vkd.cmdPipelineBarrier(cmdbuf, (VkPipelineStageFlags)VK_PIPELINE_STAGE_TRANSFER_BIT,
707                                    (VkPipelineStageFlags)VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0u, 0u,
708                                    (const VkMemoryBarrier *)DE_NULL, 1u, &postCopyBarrier, 0u,
709                                    (const VkImageMemoryBarrier *)DE_NULL);
710         }
711     }
712 }
713 
getDecodedImage(DeviceContext & devctx,VkImageLayout originalLayout,const DecodedFrame & frame)714 DownloadedFrame getDecodedImage(DeviceContext &devctx, VkImageLayout originalLayout, const DecodedFrame &frame)
715 {
716     auto &vkd                     = devctx.getDeviceDriver();
717     auto device                   = devctx.device;
718     auto queueFamilyIndexDecode   = devctx.decodeQueueFamilyIdx();
719     auto queueFamilyIndexTransfer = devctx.transferQueueFamilyIdx();
720     const VkExtent2D imageExtent{(uint32_t)frame.displayWidth, (uint32_t)frame.displayHeight};
721     const VkImage image         = frame.outputImageView->GetImageResource()->GetImage();
722     const VkFormat format       = frame.outputImageView->GetImageResource()->GetImageCreateInfo().format;
723     const VkQueue queueDecode   = getDeviceQueue(vkd, device, queueFamilyIndexDecode, 0u);
724     const VkQueue queueTransfer = getDeviceQueue(vkd, device, queueFamilyIndexTransfer, 0u);
725 
726     PlanarFormatDescription planarDescription = getPlanarFormatDescription(format);
727     DE_ASSERT(planarDescription.numPlanes == 2 || planarDescription.numPlanes == 3);
728     const VkImageSubresourceRange imageSubresourceRange =
729         makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, frame.imageLayerIndex, 1);
730 
731     const Move<VkCommandPool> cmdDecodePool(makeCommandPool(vkd, device, queueFamilyIndexDecode));
732     const Move<VkCommandBuffer> cmdDecodeBuffer(
733         allocateCommandBuffer(vkd, device, *cmdDecodePool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
734     const Move<VkCommandPool> cmdTransferPool(makeCommandPool(vkd, device, queueFamilyIndexTransfer));
735     const Move<VkCommandBuffer> cmdTransferBuffer(
736         allocateCommandBuffer(vkd, device, *cmdTransferPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
737 
738     if (frame.frameCompleteFence != VK_NULL_HANDLE)
739         VK_CHECK(vkd.waitForFences(device, 1, &frame.frameCompleteFence, VK_FALSE, ~(uint64_t)0u));
740 
741     auto computePlaneSize = [](const VkExtent2D extent, const PlanarFormatDescription &desc, int plane)
742     {
743         uint32_t w = extent.width;
744         uint32_t h = extent.height;
745 
746         if (plane > 0)
747         {
748             w = (w + 1) /
749                 desc.planes[plane]
750                     .widthDivisor; // This is what libaom does, but probably not the h/w - there's ambiguity about what to do for non-even dimensions imo
751             h = (h + 1) / desc.planes[plane].heightDivisor;
752             return w * h * desc.planes[plane].elementSizeBytes;
753         }
754 
755         return w * h * desc.planes[plane].elementSizeBytes;
756     };
757 
758     // Create a buffer to hold each planes' samples.
759     std::vector<std::unique_ptr<BufferWithMemory>> planeBuffers;
760     planeBuffers.reserve(planarDescription.numPlanes);
761     for (int plane = 0; plane < planarDescription.numPlanes; plane++)
762     {
763         const VkBufferCreateInfo bufferInfo = {
764             VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
765             DE_NULL,
766             (VkBufferCreateFlags)0u,
767             computePlaneSize(imageExtent, planarDescription, plane),
768             VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
769             VK_SHARING_MODE_EXCLUSIVE,
770             0u,
771             (const uint32_t *)DE_NULL,
772         };
773         planeBuffers.emplace_back(new BufferWithMemory(vkd, device, devctx.allocator(), bufferInfo,
774                                                        MemoryRequirement::HostVisible | MemoryRequirement::Any));
775     }
776 
777     Move<VkFence> decodeFence                   = createFence(vkd, device);
778     Move<VkFence> transferFence                 = createFence(vkd, device);
779     Move<VkSemaphore> semaphore                 = createSemaphore(vkd, device);
780     const VkPipelineStageFlags waitDstStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
781 
782     // First release the image from the decode queue to the xfer queue, transitioning it to a friendly format for copying.
783     const VkImageMemoryBarrier2KHR barrierDecodeRelease = makeImageMemoryBarrier2(
784         VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR, VK_ACCESS_2_VIDEO_DECODE_WRITE_BIT_KHR, VK_PIPELINE_STAGE_2_NONE,
785         0, // ignored for release operations
786         originalLayout, VK_IMAGE_LAYOUT_GENERAL, image, imageSubresourceRange, queueFamilyIndexDecode,
787         queueFamilyIndexTransfer);
788 
789     // And acquire it on the transfer queue
790     const VkImageMemoryBarrier2KHR barrierTransferAcquire =
791         makeImageMemoryBarrier2(VK_PIPELINE_STAGE_2_NONE,
792                                 0, // ignored for acquire operations
793                                 VK_PIPELINE_STAGE_2_TRANSFER_BIT, VK_ACCESS_2_MEMORY_READ_BIT, originalLayout,
794                                 VK_IMAGE_LAYOUT_GENERAL, // must match decode release
795                                 image,                   // must match decode release
796                                 imageSubresourceRange,   // must match decode release
797                                 queueFamilyIndexDecode,  // must match decode release
798                                 queueFamilyIndexTransfer);
799 
800     beginCommandBuffer(vkd, *cmdDecodeBuffer, 0u);
801     cmdPipelineImageMemoryBarrier2(vkd, *cmdDecodeBuffer, &barrierDecodeRelease);
802     endCommandBuffer(vkd, *cmdDecodeBuffer);
803 
804     bool haveSemaphore = frame.frameCompleteSemaphore != VK_NULL_HANDLE;
805     const VkSubmitInfo decodeSubmitInfo{
806         VK_STRUCTURE_TYPE_SUBMIT_INFO,
807         nullptr,
808         haveSemaphore ? 1u : 0u,
809         haveSemaphore ? &frame.frameCompleteSemaphore : nullptr,
810         haveSemaphore ? &waitDstStageMask : nullptr,
811         1u,
812         &*cmdDecodeBuffer,
813         1u,
814         &*semaphore,
815     };
816     VK_CHECK(vkd.queueSubmit(queueDecode, 1u, &decodeSubmitInfo, *decodeFence));
817     VK_CHECK(vkd.waitForFences(device, 1, &*decodeFence, true, ~0ull));
818 
819     beginCommandBuffer(vkd, *cmdTransferBuffer, 0u);
820     cmdPipelineImageMemoryBarrier2(vkd, *cmdTransferBuffer, &barrierTransferAcquire);
821     copyAllPlanesToBuffers(vkd, frame, imageExtent, planarDescription, *cmdTransferBuffer, planeBuffers);
822     endCommandBuffer(vkd, *cmdTransferBuffer);
823 
824     const VkSubmitInfo transferSubmitInfo{
825         VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType                              sType;
826         DE_NULL,                       // const void*                                  pNext;
827         1u,                            // uint32_t                                             waitSemaphoreCount;
828         &*semaphore,                   // const VkSemaphore*                   pWaitSemaphores;
829         &waitDstStageMask,             // const VkPipelineStageFlags*  pWaitDstStageMask;
830         1u,                            // uint32_t                                             commandBufferCount;
831         &*cmdTransferBuffer,           // const VkCommandBuffer*               pCommandBuffers;
832         1u,                            // uint32_t                                             signalSemaphoreCount;
833         &*semaphore,                   // const VkSemaphore*                   pSignalSemaphores;
834     };
835     VK_CHECK(vkd.queueSubmit(queueTransfer, 1u, &transferSubmitInfo, *transferFence));
836     VK_CHECK(vkd.waitForFences(device, 1, &*transferFence, true, ~0ull));
837 
838     DownloadedFrame downloadedFrame;
839     { // download the data from the buffers into the host buffers
840         tcu::UVec4 channelDepths = ycbcr::getYCbCrBitDepth(format);
841         DE_ASSERT(channelDepths.x() == channelDepths.y() &&
842                   channelDepths.y() == channelDepths.z()); // Sanity for interface mismatch
843         int bitDepth = channelDepths.x();
844         DE_ASSERT(bitDepth == 8 || bitDepth == 10 || bitDepth == 12 || bitDepth == 16);
845         TCU_CHECK_AND_THROW(InternalError, bitDepth != 16, "16-bit samples have not been tested yet");
846 
847         bool highBitDepth = bitDepth > 8;
848 
849         // Luma first
850         {
851             invalidateMappedMemoryRange(vkd, device, planeBuffers[0]->getAllocation().getMemory(), 0u, VK_WHOLE_SIZE);
852             VkDeviceSize planeSize = computePlaneSize(imageExtent, planarDescription, 0);
853             downloadedFrame.luma.resize(planeSize);
854             if (highBitDepth && bitDepth != 16) // 16-bit can take the straight memcpy case below, no undefined bits.
855             {
856                 const uint16_t *const samples = (uint16_t *)planeBuffers[0]->getAllocation().getHostPtr();
857                 uint16_t *const outputSamples = (uint16_t *)downloadedFrame.luma.data();
858 
859                 //int shift = 16 - bitDepth;
860                 if (bitDepth == 10)
861                 {
862                     for (VkDeviceSize sampleIdx = 0; sampleIdx < (imageExtent.width * imageExtent.height); sampleIdx++)
863                     {
864                         uint16_t sample          = samples[sampleIdx];
865                         outputSamples[sampleIdx] = roru16(sample, 6);
866                     }
867                 }
868                 else if (bitDepth == 12)
869                 {
870                     for (VkDeviceSize sampleIdx = 0; sampleIdx < planeSize; sampleIdx++)
871                     {
872                         uint16_t sample                 = samples[sampleIdx];
873                         downloadedFrame.luma[sampleIdx] = roru16(sample, 4);
874                     }
875                 }
876             }
877             else
878             {
879                 DE_ASSERT(bitDepth == 8);
880                 deMemcpy(downloadedFrame.luma.data(), planeBuffers[0]->getAllocation().getHostPtr(), planeSize);
881             }
882         }
883         if (planarDescription.numPlanes == 2)
884         {
885             invalidateMappedMemoryRange(vkd, device, planeBuffers[1]->getAllocation().getMemory(), 0u, VK_WHOLE_SIZE);
886             // Interleaved formats, deinterleave for MD5 comparisons (matches most other tool's notion of "raw YUV format")
887             //   this is a very slow operation, and accounts for ~80% of the decode test runtime.
888             //   it might be better to use reference checksums in the original hardware format, rather than xforming each time
889             //   but that makes comparison to software references more difficult...
890             VkDeviceSize planeSize = computePlaneSize(imageExtent, planarDescription, 1);
891             VkDeviceSize numWords  = planeSize / sizeof(uint16_t);
892             uint16_t *wordSamples  = (uint16_t *)planeBuffers[1]->getAllocation().getHostPtr();
893             downloadedFrame.cb.resize(numWords);
894             downloadedFrame.cr.resize(numWords);
895             if (bitDepth == 8)
896             {
897                 for (int i = 0; i < numWords; i++)
898                 {
899                     downloadedFrame.cb[i] = wordSamples[i] & 0xFF;
900                     downloadedFrame.cr[i] = (wordSamples[i] >> 8) & 0xFF;
901                 }
902             }
903             else
904             {
905                 DE_ASSERT(bitDepth == 10 || bitDepth == 12 || bitDepth == 16);
906                 uint16_t *sampleWordsCb16 = (uint16_t *)downloadedFrame.cb.data();
907                 uint16_t *sampleWordsCr16 = (uint16_t *)downloadedFrame.cr.data();
908                 for (int i = 0; i < numWords / 2; i++)
909                 {
910                     sampleWordsCb16[i] = roru16(wordSamples[2 * i], 16 - bitDepth);
911                     sampleWordsCr16[i] = roru16(wordSamples[2 * i + 1], 16 - bitDepth);
912                 }
913             }
914         }
915         else if (planarDescription.numPlanes == 3)
916         {
917             invalidateMappedMemoryRange(vkd, device, planeBuffers[1]->getAllocation().getMemory(), 0u, VK_WHOLE_SIZE);
918 
919             // Happy case, not deinterleaving, just straight memcpying
920             uint32_t evenWidth = (imageExtent.width + 1) & ~1;
921 
922             // Not sure, but don't think chroma planes can be subsampled differently.
923             DE_ASSERT(planarDescription.planes[1].widthDivisor == planarDescription.planes[2].widthDivisor);
924             DE_ASSERT(planarDescription.planes[1].heightDivisor == planarDescription.planes[2].heightDivisor);
925             DE_ASSERT(planarDescription.planes[1].elementSizeBytes == planarDescription.planes[2].elementSizeBytes);
926 
927             uint32_t width  = evenWidth / planarDescription.planes[1].widthDivisor;
928             uint32_t height = imageExtent.height / planarDescription.planes[1].heightDivisor;
929 
930             VkDeviceSize cbPlaneSize = width * height * planarDescription.planes[1].elementSizeBytes;
931             downloadedFrame.cb.resize(cbPlaneSize);
932             deMemcpy(downloadedFrame.cb.data(), planeBuffers[1]->getAllocation().getHostPtr(),
933                      downloadedFrame.cb.size());
934 
935             invalidateMappedMemoryRange(vkd, device, planeBuffers[2]->getAllocation().getMemory(), 0u, VK_WHOLE_SIZE);
936             downloadedFrame.cr.resize(cbPlaneSize);
937             deMemcpy(downloadedFrame.cr.data(), planeBuffers[2]->getAllocation().getHostPtr(),
938                      downloadedFrame.cr.size());
939         }
940     }
941 
942     // We're nearly there, the pain is almost over, release the image
943     // from the xfer queue, give it back to the decode queue, and
944     // transition it back to the original layout.
945     const VkImageMemoryBarrier2KHR barrierTransferRelease = makeImageMemoryBarrier2(
946         VK_PIPELINE_STAGE_2_TRANSFER_BIT, VK_ACCESS_2_MEMORY_WRITE_BIT, VK_PIPELINE_STAGE_2_NONE,
947         0, // ignored for release
948         VK_IMAGE_LAYOUT_GENERAL, originalLayout, image, imageSubresourceRange, queueFamilyIndexTransfer,
949         queueFamilyIndexDecode);
950 
951     const VkImageMemoryBarrier2KHR barrierDecodeAcquire = makeImageMemoryBarrier2(
952         VK_PIPELINE_STAGE_2_NONE,
953         0, // ignored for acquire
954         VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR, VK_ACCESS_2_VIDEO_DECODE_WRITE_BIT_KHR, VK_IMAGE_LAYOUT_GENERAL,
955         originalLayout, image, imageSubresourceRange, queueFamilyIndexTransfer, queueFamilyIndexDecode);
956 
957     vkd.resetCommandBuffer(*cmdTransferBuffer, 0u);
958     vkd.resetCommandBuffer(*cmdDecodeBuffer, 0u);
959 
960     vkd.resetFences(device, 1, &*transferFence);
961     vkd.resetFences(device, 1, &*decodeFence);
962 
963     beginCommandBuffer(vkd, *cmdTransferBuffer, 0u);
964     cmdPipelineImageMemoryBarrier2(vkd, *cmdTransferBuffer, &barrierTransferRelease);
965     endCommandBuffer(vkd, *cmdTransferBuffer);
966 
967     const VkSubmitInfo transferSubmitInfo2{
968         VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType                              sType;
969         DE_NULL,                       // const void*                                  pNext;
970         1u,                            // uint32_t                                             waitSemaphoreCount;
971         &*semaphore,                   // const VkSemaphore*                   pWaitSemaphores;
972         &waitDstStageMask,             // const VkPipelineStageFlags*  pWaitDstStageMask;
973         1u,                            // uint32_t                                             commandBufferCount;
974         &*cmdTransferBuffer,           // const VkCommandBuffer*               pCommandBuffers;
975         1u,                            // uint32_t                                             signalSemaphoreCount;
976         &*semaphore,                   // const VkSemaphore*                   pSignalSemaphores;
977     };
978     VK_CHECK(vkd.queueSubmit(queueTransfer, 1u, &transferSubmitInfo2, *transferFence));
979     VK_CHECK(vkd.waitForFences(device, 1, &*transferFence, true, ~0ull));
980 
981     beginCommandBuffer(vkd, *cmdDecodeBuffer, 0u);
982     cmdPipelineImageMemoryBarrier2(vkd, *cmdDecodeBuffer, &barrierDecodeAcquire);
983     endCommandBuffer(vkd, *cmdDecodeBuffer);
984 
985     const VkSubmitInfo decodeSubmitInfo2{
986         VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType                              sType;
987         DE_NULL,                       // const void*                                  pNext;
988         1u,                            // uint32_t                                             waitSemaphoreCount;
989         &*semaphore,                   // const VkSemaphore*                   pWaitSemaphores;
990         &waitDstStageMask,             // const VkPipelineStageFlags*  pWaitDstStageMask;
991         1u,                            // uint32_t                                             commandBufferCount;
992         &*cmdDecodeBuffer,             // const VkCommandBuffer*               pCommandBuffers;
993         0u,                            // uint32_t                                             signalSemaphoreCount;
994         DE_NULL,                       // const VkSemaphore*                   pSignalSemaphores;
995     };
996     VK_CHECK(vkd.queueSubmit(queueDecode, 1u, &decodeSubmitInfo2, *decodeFence));
997     VK_CHECK(vkd.waitForFences(device, 1, &*decodeFence, true, ~0ull));
998 
999     return downloadedFrame;
1000 }
1001 
1002 class VideoDecodeTestInstance : public VideoBaseTestInstance
1003 {
1004 public:
1005     VideoDecodeTestInstance(Context &context, const TestDefinition *testDefinition);
1006     tcu::TestStatus iterate(void);
1007 
1008 protected:
1009     const TestDefinition *m_testDefinition;
1010     static_assert(sizeof(DeviceContext) < 128, "DeviceContext has grown bigger than expected!");
1011     DeviceContext m_deviceContext;
1012 };
1013 
1014 class InterleavingDecodeTestInstance : public VideoBaseTestInstance
1015 {
1016 public:
1017     InterleavingDecodeTestInstance(Context &context, const std::vector<MovePtr<TestDefinition>> &testDefinitions);
1018     tcu::TestStatus iterate(void);
1019 
1020 protected:
1021     const std::vector<MovePtr<TestDefinition>> &m_testDefinitions;
1022     DeviceContext m_deviceContext;
1023     static_assert(sizeof(DeviceContext) < 128, "DeviceContext has grown bigger than expected!");
1024 };
1025 
InterleavingDecodeTestInstance(Context & context,const std::vector<MovePtr<TestDefinition>> & testDefinitions)1026 InterleavingDecodeTestInstance::InterleavingDecodeTestInstance(
1027     Context &context, const std::vector<MovePtr<TestDefinition>> &testDefinitions)
1028     : VideoBaseTestInstance(context)
1029     , m_testDefinitions(std::move(testDefinitions))
1030     , m_deviceContext(&m_context, &m_videoDevice)
1031 {
1032     int requiredCodecs                                = VK_VIDEO_CODEC_OPERATION_NONE_KHR;
1033     VideoDevice::VideoDeviceFlags requiredDeviceFlags = VideoDevice::VideoDeviceFlagBits::VIDEO_DEVICE_FLAG_NONE;
1034     for (const auto &test : m_testDefinitions)
1035     {
1036         VkVideoCodecOperationFlagBitsKHR testBits = test->getCodecOperation(0);
1037         requiredCodecs |= testBits;
1038         requiredDeviceFlags |= test->requiredDeviceFlags();
1039     }
1040     VkDevice device = getDeviceSupportingQueue(VK_QUEUE_VIDEO_DECODE_BIT_KHR | VK_QUEUE_TRANSFER_BIT, requiredCodecs,
1041                                                requiredDeviceFlags);
1042 
1043     m_deviceContext.updateDevice(
1044         m_context.getPhysicalDevice(), device,
1045         getDeviceQueue(m_context.getDeviceInterface(), device, m_videoDevice.getQueueFamilyIndexDecode(), 0), nullptr,
1046         getDeviceQueue(m_context.getDeviceInterface(), device, m_videoDevice.getQueueFamilyIndexTransfer(), 0));
1047 }
1048 
VideoDecodeTestInstance(Context & context,const TestDefinition * testDefinition)1049 VideoDecodeTestInstance::VideoDecodeTestInstance(Context &context, const TestDefinition *testDefinition)
1050     : VideoBaseTestInstance(context)
1051     , m_testDefinition(testDefinition)
1052     , m_deviceContext(&m_context, &m_videoDevice)
1053 {
1054     VkDevice device =
1055         getDeviceSupportingQueue(VK_QUEUE_VIDEO_DECODE_BIT_KHR | VK_QUEUE_TRANSFER_BIT,
1056                                  m_testDefinition->getCodecOperation(0), m_testDefinition->requiredDeviceFlags());
1057 
1058     m_deviceContext.updateDevice(
1059         m_context.getPhysicalDevice(), device,
1060         getDeviceQueue(m_context.getDeviceInterface(), device, m_videoDevice.getQueueFamilyIndexDecode(), 0), nullptr,
1061         getDeviceQueue(m_context.getDeviceInterface(), device, m_videoDevice.getQueueFamilyIndexTransfer(), 0));
1062 }
1063 
createProcessor(const TestDefinition * td,DeviceContext * dctx,bool forceDisableFilmGrain=false)1064 static std::unique_ptr<FrameProcessor> createProcessor(const TestDefinition *td, DeviceContext *dctx,
1065                                                        bool forceDisableFilmGrain = false)
1066 {
1067     Demuxer::Params demuxParams = {};
1068     demuxParams.data            = std::make_unique<BufferedReader>(td->getClipFilename());
1069     demuxParams.codecOperation  = td->getCodecOperation(0);
1070     demuxParams.framing         = td->getClipInfo()->framing;
1071 
1072     auto demuxer = Demuxer::create(std::move(demuxParams));
1073 
1074     std::shared_ptr<VideoBaseDecoder> decoder = decoderFromTestDefinition(dctx, *td, forceDisableFilmGrain);
1075 
1076     return std::make_unique<FrameProcessor>(std::move(demuxer), decoder);
1077 }
1078 
iterate()1079 tcu::TestStatus VideoDecodeTestInstance::iterate()
1080 {
1081     bool filmGrainPresent                     = m_testDefinition->hasOption(DecoderOption::FilmGrainPresent);
1082     std::unique_ptr<FrameProcessor> processor = createProcessor(m_testDefinition, &m_deviceContext);
1083     std::unique_ptr<FrameProcessor> processorWithoutFilmGrain;
1084     if (filmGrainPresent)
1085     {
1086         processorWithoutFilmGrain = createProcessor(m_testDefinition, &m_deviceContext, true);
1087     }
1088 
1089     std::vector<int> incorrectFrames;
1090     std::vector<int> correctFrames;
1091 
1092     if (m_testDefinition->hasOption(DecoderOption::CachedDecoding))
1093     {
1094         processor->decodeFrameOutOfOrder(m_testDefinition->framesToCheck());
1095         if (processorWithoutFilmGrain)
1096             processorWithoutFilmGrain->decodeFrameOutOfOrder(m_testDefinition->framesToCheck());
1097     }
1098 
1099     bool hasSeparateOutputImages = !processor->m_decoder->dpbAndOutputCoincide() || filmGrainPresent;
1100 
1101     std::FILE *debug_OutputFileHandle;
1102 
1103     auto openTemporaryFile = [](const std::string &basename, std::FILE **handle)
1104     {
1105         DE_ASSERT(handle != nullptr);
1106         *handle = std::fopen(basename.c_str(), "wb");
1107         DE_ASSERT(*handle != nullptr);
1108     };
1109 
1110     if (debug_WriteOutFramesToSingleFile)
1111     {
1112         openTemporaryFile("output.yuv", &debug_OutputFileHandle);
1113     }
1114 
1115     bool throwFilmGrainQualityWarning = false;
1116     for (int frameNumber = 0; frameNumber < m_testDefinition->framesToCheck(); frameNumber++)
1117     {
1118         DecodedFrame frame;
1119         TCU_CHECK_AND_THROW(
1120             InternalError, processor->getNextFrame(&frame) > 0,
1121             "Expected more frames from the bitstream. Most likely an internal CTS bug, or maybe an invalid bitstream");
1122         DecodedFrame frameWithoutFilmgGrain;
1123         if (processorWithoutFilmGrain)
1124         {
1125             TCU_CHECK_AND_THROW(InternalError, processorWithoutFilmGrain->getNextFrame(&frameWithoutFilmgGrain) > 0,
1126                                 "Expected more frames from the bitstream. Most likely an internal CTS bug, or maybe an "
1127                                 "invalid bitstream");
1128         }
1129 
1130         if (debug_WriteOutFramesToSeparateFiles)
1131         {
1132             std::stringstream oss;
1133             oss << "output" << frame.displayOrder << "_" << frame.displayWidth << "_" << frame.displayHeight << ".yuv";
1134             openTemporaryFile(oss.str(), &debug_OutputFileHandle);
1135         }
1136 
1137         DownloadedFrame downloadedFrame = getDecodedImage(
1138             m_deviceContext,
1139             hasSeparateOutputImages ? VK_IMAGE_LAYOUT_VIDEO_DECODE_DST_KHR : VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR,
1140             frame);
1141 
1142         DownloadedFrame downloadedFrameWithoutFilmGrain;
1143         if (processorWithoutFilmGrain)
1144         {
1145             downloadedFrameWithoutFilmGrain =
1146                 getDecodedImage(m_deviceContext,
1147                                 !processor->m_decoder->dpbAndOutputCoincide() ? VK_IMAGE_LAYOUT_VIDEO_DECODE_DST_KHR :
1148                                                                                 VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR,
1149                                 frameWithoutFilmgGrain);
1150         }
1151 
1152         if (debug_WriteOutFramesToSingleFile || debug_WriteOutFramesToSeparateFiles)
1153         {
1154             DownloadedFrame &frameToWriteOut =
1155                 debug_WriteOutFilmGrain ? downloadedFrame : downloadedFrameWithoutFilmGrain;
1156             fwrite(frameToWriteOut.luma.data(), 1, frameToWriteOut.luma.size(), debug_OutputFileHandle);
1157             fwrite(frameToWriteOut.cb.data(), 1, frameToWriteOut.cb.size(), debug_OutputFileHandle);
1158             fwrite(frameToWriteOut.cr.data(), 1, frameToWriteOut.cr.size(), debug_OutputFileHandle);
1159             fflush(debug_OutputFileHandle);
1160         }
1161 
1162         if (debug_WriteOutFramesToSeparateFiles)
1163         {
1164             std::fclose(debug_OutputFileHandle);
1165         }
1166 
1167         std::string checksum       = checksumForClipFrame(m_testDefinition->getClipInfo(), frameNumber);
1168         std::string actualChecksum = downloadedFrame.checksum();
1169 
1170         double psnr = 0.0;
1171         if (processorWithoutFilmGrain)
1172         {
1173             static const double numPlanes = 3.0;
1174             util::PSNR(downloadedFrame.luma, downloadedFrameWithoutFilmGrain.luma);
1175             psnr += util::PSNR(downloadedFrame.cb, downloadedFrameWithoutFilmGrain.cb);
1176             psnr += util::PSNR(downloadedFrame.cr, downloadedFrameWithoutFilmGrain.cr);
1177             psnr /= numPlanes;
1178         }
1179 
1180         if (actualChecksum == checksum)
1181         {
1182             correctFrames.push_back(frameNumber);
1183         }
1184         else
1185         {
1186             if (processorWithoutFilmGrain)
1187             {
1188                 if (!de::inRange(psnr, kFilmgrainPSNRLowerBound, kFilmgrainPSNRUpperBound))
1189                 {
1190                     incorrectFrames.push_back(frameNumber);
1191                     throwFilmGrainQualityWarning = true;
1192                 }
1193                 else
1194                 {
1195                     correctFrames.push_back(frameNumber);
1196                 }
1197             }
1198             else
1199             {
1200                 incorrectFrames.push_back(frameNumber);
1201             }
1202         }
1203     }
1204 
1205     if (debug_WriteOutFramesToSingleFile)
1206     {
1207         fclose(debug_OutputFileHandle);
1208     }
1209 
1210     if (!correctFrames.empty() && correctFrames.size() == m_testDefinition->framesToCheck())
1211     {
1212         std::stringstream oss;
1213         oss << m_testDefinition->framesToCheck() << " correctly decoded frames";
1214         return tcu::TestStatus::pass(oss.str());
1215     }
1216     else
1217     {
1218         std::stringstream ss;
1219         ss << correctFrames.size() << " out of " << m_testDefinition->framesToCheck() << " frames rendered correctly (";
1220         if (correctFrames.size() < incorrectFrames.size())
1221         {
1222             ss << "correct frames: ";
1223             for (int i : correctFrames)
1224                 ss << i << " ";
1225         }
1226         else
1227         {
1228             ss << "incorrect frames: ";
1229             for (int i : incorrectFrames)
1230                 ss << i << " ";
1231         }
1232         ss << "\b)";
1233 
1234         if (throwFilmGrainQualityWarning)
1235         {
1236             TCU_THROW(QualityWarning, std::string("Potentially non-standard filmgrain synthesis process: ") + ss.str());
1237         }
1238 
1239         return tcu::TestStatus::fail(ss.str());
1240     }
1241 }
1242 
iterate(void)1243 tcu::TestStatus InterleavingDecodeTestInstance::iterate(void)
1244 {
1245     std::vector<std::unique_ptr<FrameProcessor>> processors;
1246     for (int i = 0; i < m_testDefinitions.size(); i++)
1247     {
1248         processors.push_back(createProcessor(&*m_testDefinitions[i], &m_deviceContext));
1249     }
1250 
1251     // First cache up all the decoded frames from the various decode sessions
1252     for (int i = 0; i < m_testDefinitions.size(); i++)
1253     {
1254         const auto &test = m_testDefinitions[i];
1255         auto &processor  = processors[i];
1256         processor->bufferFrames(test->framesToCheck());
1257         DE_ASSERT(processor->getBufferedDisplayCount() == test->framesToCheck());
1258     }
1259 
1260     auto interleaveCacheSize    = processors[0]->m_decoder->m_cachedDecodeParams.size();
1261     auto firstStreamDecodeQueue = processors[0]->m_decoder->m_deviceContext->decodeQueue;
1262 
1263     size_t totalFrames = 0;
1264     for (auto &processor : processors)
1265     {
1266         auto &decoder = processor->m_decoder;
1267         DE_ASSERT(decoder->m_cachedDecodeParams.size() == interleaveCacheSize);
1268         DE_ASSERT(decoder->m_deviceContext->decodeQueue == firstStreamDecodeQueue);
1269         totalFrames += decoder->m_cachedDecodeParams.size();
1270     }
1271 
1272     DE_UNREF(firstStreamDecodeQueue);
1273 
1274     // Interleave command buffer recording
1275     for (int i = 0; i < interleaveCacheSize; i++)
1276     {
1277         for (auto &processor : processors)
1278         {
1279             auto &decoder = processor->m_decoder;
1280             decoder->WaitForFrameFences(decoder->m_cachedDecodeParams[i]);
1281             decoder->ApplyPictureParameters(decoder->m_cachedDecodeParams[i]);
1282             decoder->RecordCommandBuffer(decoder->m_cachedDecodeParams[i]);
1283         }
1284     }
1285 
1286     // Interleave submissions
1287     for (int i = 0; i < interleaveCacheSize; i++)
1288     {
1289         for (int idx = 0; idx < processors.size(); idx++)
1290         {
1291             auto &decoder = processors[idx]->m_decoder;
1292             auto &test    = m_testDefinitions[idx];
1293             decoder->SubmitQueue(decoder->m_cachedDecodeParams[i]);
1294             if (test->hasOption(DecoderOption::UseStatusQueries))
1295             {
1296                 decoder->QueryDecodeResults(decoder->m_cachedDecodeParams[i]);
1297             }
1298         }
1299     }
1300 
1301     struct InterleavedDecodeResults
1302     {
1303         std::vector<int> correctFrames;
1304         std::vector<int> incorrectFrames;
1305     };
1306     std::vector<InterleavedDecodeResults> results(m_testDefinitions.size());
1307 
1308     for (int i = 0; i < m_testDefinitions.size(); i++)
1309     {
1310         auto &test      = m_testDefinitions[i];
1311         auto &processor = processors[i];
1312         bool hasSeparateOutputImages =
1313             processor->m_decoder->dpbAndOutputCoincide() && !test->hasOption(DecoderOption::FilmGrainPresent);
1314         for (int frameNumber = 0; frameNumber < m_testDefinitions[i]->framesToCheck(); frameNumber++)
1315         {
1316             DecodedFrame frame;
1317             TCU_CHECK_AND_THROW(InternalError, processor->getNextFrame(&frame) > 0,
1318                                 "Expected more frames from the bitstream. Most likely an internal CTS bug, or maybe an "
1319                                 "invalid bitstream");
1320 
1321             if (videoLoggingEnabled())
1322             {
1323                 std::cout << "Frame decoded: picIdx" << static_cast<uint32_t>(frame.pictureIndex) << " "
1324                           << frame.displayWidth << "x" << frame.displayHeight << " "
1325                           << "decode/display " << frame.decodeOrder << "/" << frame.displayOrder << " "
1326                           << "dstImageView " << frame.outputImageView->GetImageView() << std::endl;
1327             }
1328 
1329             DownloadedFrame downloadedFrame = getDecodedImage(
1330                 m_deviceContext,
1331                 hasSeparateOutputImages ? VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR : VK_IMAGE_LAYOUT_VIDEO_DECODE_DST_KHR,
1332                 frame);
1333 
1334             std::string expectedChecksum = checksumForClipFrame(test->getClipInfo(), frameNumber);
1335             std::string actualChecksum   = downloadedFrame.checksum();
1336             if (actualChecksum == expectedChecksum)
1337             {
1338                 results[i].correctFrames.push_back(frameNumber);
1339             }
1340             else
1341             {
1342                 results[i].incorrectFrames.push_back(frameNumber);
1343             }
1344         }
1345     }
1346 
1347     bool allTestsPassed  = true;
1348     int totalFramesCheck = 0;
1349     for (const auto &res : results)
1350     {
1351         if (!res.incorrectFrames.empty())
1352             allTestsPassed = false;
1353         totalFramesCheck += (res.correctFrames.size() + res.incorrectFrames.size());
1354     }
1355     DE_ASSERT(totalFramesCheck == totalFrames);
1356     DE_UNREF(totalFramesCheck);
1357 
1358     if (allTestsPassed)
1359         return tcu::TestStatus::pass(de::toString(totalFrames) + " correctly decoded frames");
1360     else
1361     {
1362         stringstream ss;
1363         ss << "Interleaving failure: ";
1364         for (int i = 0; i < results.size(); i++)
1365         {
1366             const auto &result = results[i];
1367             if (!result.incorrectFrames.empty())
1368             {
1369                 ss << " (stream #" << i << " incorrect frames: ";
1370                 for (int frame : result.incorrectFrames)
1371                     ss << frame << " ";
1372                 ss << "\b)";
1373             }
1374         }
1375         return tcu::TestStatus::fail(ss.str());
1376     }
1377 }
1378 
1379 #endif // #ifdef DE_BUILD_VIDEO
1380 
1381 class VideoDecodeTestCase : public vkt::TestCase
1382 {
1383 public:
VideoDecodeTestCase(tcu::TestContext & context,const char * name,MovePtr<TestDefinition> testDefinition)1384     VideoDecodeTestCase(tcu::TestContext &context, const char *name, MovePtr<TestDefinition> testDefinition)
1385         : vkt::TestCase(context, name)
1386         , m_testDefinition(testDefinition)
1387     {
1388     }
1389 
1390     TestInstance *createInstance(Context &context) const override;
1391     void checkSupport(Context &context) const override;
1392 
1393 private:
1394     MovePtr<TestDefinition> m_testDefinition;
1395 };
1396 
1397 class InterleavingDecodeTestCase : public vkt::TestCase
1398 {
1399 public:
InterleavingDecodeTestCase(tcu::TestContext & context,const char * name,std::vector<MovePtr<TestDefinition>> && testDefinitions)1400     InterleavingDecodeTestCase(tcu::TestContext &context, const char *name,
1401                                std::vector<MovePtr<TestDefinition>> &&testDefinitions)
1402         : vkt::TestCase(context, name)
1403         , m_testDefinitions(std::move(testDefinitions))
1404     {
1405     }
1406 
createInstance(Context & context) const1407     TestInstance *createInstance(Context &context) const override
1408     {
1409 #ifdef DE_BUILD_VIDEO
1410         return new InterleavingDecodeTestInstance(context, m_testDefinitions);
1411 #endif
1412         DE_UNREF(context);
1413         return nullptr;
1414     }
1415     void checkSupport(Context &context) const override;
1416 
1417 private:
1418     std::vector<MovePtr<TestDefinition>> m_testDefinitions;
1419 };
1420 
createInstance(Context & context) const1421 TestInstance *VideoDecodeTestCase::createInstance(Context &context) const
1422 {
1423 #ifdef DE_BUILD_VIDEO
1424     return new VideoDecodeTestInstance(context, m_testDefinition.get());
1425 #endif
1426 
1427 #ifndef DE_BUILD_VIDEO
1428     DE_UNREF(context);
1429     return nullptr;
1430 #endif
1431 }
1432 
checkSupport(Context & context) const1433 void VideoDecodeTestCase::checkSupport(Context &context) const
1434 {
1435     context.requireDeviceFunctionality("VK_KHR_video_queue");
1436     context.requireDeviceFunctionality("VK_KHR_synchronization2");
1437 
1438     switch (m_testDefinition->getTestType())
1439     {
1440     case TEST_TYPE_H264_DECODE_I:
1441     case TEST_TYPE_H264_DECODE_I_P:
1442     case TEST_TYPE_H264_DECODE_CLIP_A:
1443     case TEST_TYPE_H264_DECODE_I_P_NOT_MATCHING_ORDER:
1444     case TEST_TYPE_H264_DECODE_I_P_B_13:
1445     case TEST_TYPE_H264_DECODE_I_P_B_13_NOT_MATCHING_ORDER:
1446     case TEST_TYPE_H264_DECODE_QUERY_RESULT_WITH_STATUS:
1447     case TEST_TYPE_H264_DECODE_RESOLUTION_CHANGE:
1448     case TEST_TYPE_H264_DECODE_RESOLUTION_CHANGE_DPB:
1449     {
1450         context.requireDeviceFunctionality("VK_KHR_video_decode_h264");
1451         break;
1452     }
1453     case TEST_TYPE_H264_DECODE_INLINE_QUERY_RESULT_WITH_STATUS:
1454     case TEST_TYPE_H264_DECODE_RESOURCES_WITHOUT_PROFILES:
1455     {
1456         context.requireDeviceFunctionality("VK_KHR_video_decode_h264");
1457         context.requireDeviceFunctionality("VK_KHR_video_maintenance1");
1458         break;
1459     }
1460     case TEST_TYPE_H265_DECODE_I:
1461     case TEST_TYPE_H265_DECODE_I_P:
1462     case TEST_TYPE_H265_DECODE_CLIP_D:
1463     case TEST_TYPE_H265_DECODE_I_P_NOT_MATCHING_ORDER:
1464     case TEST_TYPE_H265_DECODE_I_P_B_13:
1465     case TEST_TYPE_H265_DECODE_I_P_B_13_NOT_MATCHING_ORDER:
1466     case TEST_TYPE_H265_DECODE_QUERY_RESULT_WITH_STATUS:
1467     {
1468         context.requireDeviceFunctionality("VK_KHR_video_decode_h265");
1469         break;
1470     }
1471     case TEST_TYPE_H265_DECODE_INLINE_QUERY_RESULT_WITH_STATUS:
1472     case TEST_TYPE_H265_DECODE_RESOURCES_WITHOUT_PROFILES:
1473     {
1474         context.requireDeviceFunctionality("VK_KHR_video_decode_h265");
1475         break;
1476     }
1477     case TEST_TYPE_AV1_DECODE_I:
1478     case TEST_TYPE_AV1_DECODE_I_P:
1479     case TEST_TYPE_AV1_DECODE_I_P_NOT_MATCHING_ORDER:
1480     case TEST_TYPE_AV1_DECODE_BASIC_8:
1481     case TEST_TYPE_AV1_DECODE_BASIC_8_NOT_MATCHING_ORDER:
1482     case TEST_TYPE_AV1_DECODE_BASIC_10:
1483     case TEST_TYPE_AV1_DECODE_ALLINTRA_8:
1484     case TEST_TYPE_AV1_DECODE_ALLINTRA_NOSETUP_8:
1485     case TEST_TYPE_AV1_DECODE_ALLINTRA_BC_8:
1486     case TEST_TYPE_AV1_DECODE_GLOBALMOTION_8:
1487     case TEST_TYPE_AV1_DECODE_CDFUPDATE_8:
1488     case TEST_TYPE_AV1_DECODE_FILMGRAIN_8:
1489     case TEST_TYPE_AV1_DECODE_SVCL1T2_8:
1490     case TEST_TYPE_AV1_DECODE_SUPERRES_8:
1491     case TEST_TYPE_AV1_DECODE_SIZEUP_8:
1492     case TEST_TYPE_AV1_DECODE_ARGON_SEQCHANGE_AFFINE_8:
1493     case TEST_TYPE_AV1_DECODE_ORDERHINT_10:
1494     case TEST_TYPE_AV1_DECODE_FORWARDKEYFRAME_10:
1495     case TEST_TYPE_AV1_DECODE_LOSSLESS_10:
1496     case TEST_TYPE_AV1_DECODE_LOOPFILTER_10:
1497     case TEST_TYPE_AV1_DECODE_CDEF_10:
1498     case TEST_TYPE_AV1_DECODE_ARGON_FILMGRAIN_10:
1499     case TEST_TYPE_AV1_DECODE_ARGON_TEST_787:
1500     {
1501         context.requireDeviceFunctionality("VK_KHR_video_decode_av1");
1502         break;
1503     }
1504     default:
1505         TCU_THROW(InternalError, "Unknown TestType");
1506     }
1507 
1508     const VkExtensionProperties *extensionProperties = m_testDefinition->extensionProperties(0);
1509     switch (m_testDefinition->getCodecOperation(0))
1510     {
1511     case VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR:
1512         if (strcmp(extensionProperties->extensionName, VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_EXTENSION_NAME) ||
1513             extensionProperties->specVersion != VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_SPEC_VERSION)
1514         {
1515             tcu::die("The requested decoder h.264 Codec STD version is NOT supported. The supported decoder h.264 "
1516                      "Codec STD version is version %d of %s\n",
1517                      VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_SPEC_VERSION,
1518                      VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_EXTENSION_NAME);
1519         }
1520         break;
1521     case VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR:
1522         if (strcmp(extensionProperties->extensionName, VK_STD_VULKAN_VIDEO_CODEC_H265_DECODE_EXTENSION_NAME) ||
1523             extensionProperties->specVersion != VK_STD_VULKAN_VIDEO_CODEC_H265_DECODE_SPEC_VERSION)
1524         {
1525             tcu::die("The requested decoder h.265 Codec STD version is NOT supported. The supported decoder h.265 "
1526                      "Codec STD version is version %d of %s\n",
1527                      VK_STD_VULKAN_VIDEO_CODEC_H265_DECODE_SPEC_VERSION,
1528                      VK_STD_VULKAN_VIDEO_CODEC_H265_DECODE_EXTENSION_NAME);
1529         }
1530         break;
1531     case VK_VIDEO_CODEC_OPERATION_DECODE_AV1_BIT_KHR:
1532         if (strcmp(extensionProperties->extensionName, VK_STD_VULKAN_VIDEO_CODEC_AV1_DECODE_EXTENSION_NAME) ||
1533             extensionProperties->specVersion != VK_STD_VULKAN_VIDEO_CODEC_AV1_DECODE_SPEC_VERSION)
1534         {
1535             tcu::die("The requested AV1 Codec STD version is NOT supported. The supported AV1 STD version is version "
1536                      "%d of %s\n",
1537                      VK_STD_VULKAN_VIDEO_CODEC_AV1_DECODE_SPEC_VERSION,
1538                      VK_STD_VULKAN_VIDEO_CODEC_AV1_DECODE_EXTENSION_NAME);
1539         }
1540         break;
1541     default:
1542         TCU_FAIL("Unsupported codec type");
1543     }
1544 }
1545 
checkSupport(Context & context) const1546 void InterleavingDecodeTestCase::checkSupport(Context &context) const
1547 {
1548     context.requireDeviceFunctionality("VK_KHR_video_queue");
1549     context.requireDeviceFunctionality("VK_KHR_synchronization2");
1550 
1551 #ifdef DE_DEBUG
1552     DE_ASSERT(!m_testDefinitions.empty());
1553     TestType firstType = m_testDefinitions[0]->getTestType();
1554     for (const auto &test : m_testDefinitions)
1555         DE_ASSERT(test->getTestType() == firstType);
1556 #endif
1557     switch (m_testDefinitions[0]->getTestType())
1558     {
1559     case TEST_TYPE_H264_DECODE_INTERLEAVED:
1560     {
1561         context.requireDeviceFunctionality("VK_KHR_video_decode_h264");
1562         break;
1563     }
1564     case TEST_TYPE_H264_H265_DECODE_INTERLEAVED:
1565     {
1566         context.requireDeviceFunctionality("VK_KHR_video_decode_h264");
1567         context.requireDeviceFunctionality("VK_KHR_video_decode_h265");
1568         break;
1569     }
1570     default:
1571         TCU_THROW(InternalError, "Unknown interleaving test type");
1572     }
1573 }
1574 
1575 } // namespace
1576 
createVideoDecodeTests(tcu::TestContext & testCtx)1577 tcu::TestCaseGroup *createVideoDecodeTests(tcu::TestContext &testCtx)
1578 {
1579     const uint32_t baseSeed = static_cast<uint32_t>(testCtx.getCommandLine().getBaseSeed());
1580     MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "decode"));
1581 
1582     for (const auto &decodeTest : g_DecodeTests)
1583     {
1584         auto defn = TestDefinition::create(decodeTest, baseSeed);
1585 
1586         const char *testName = getTestName(defn->getTestType());
1587         uint32_t rngSeed     = baseSeed ^ deStringHash(testName);
1588         defn->updateHash(rngSeed);
1589         group->addChild(new VideoDecodeTestCase(testCtx, testName, defn));
1590     }
1591 
1592     for (const auto &interleavingTest : g_InterleavingTests)
1593     {
1594         const char *testName = getTestName(interleavingTest.type);
1595         std::vector<MovePtr<TestDefinition>> defns;
1596         DecodeTestParam streamA{interleavingTest.type, interleavingTest.streamA};
1597         defns.push_back(TestDefinition::create(streamA, baseSeed));
1598         DecodeTestParam streamB{interleavingTest.type, interleavingTest.streamB};
1599         defns.push_back(TestDefinition::create(streamB, baseSeed));
1600         group->addChild(new InterleavingDecodeTestCase(testCtx, testName, std::move(defns)));
1601     }
1602 
1603     return group.release();
1604 }
1605 
1606 } // namespace video
1607 } // namespace vkt
1608