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