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, ©);
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