1e5c31af7Sopenharmony_ci/*------------------------------------------------------------------------
2e5c31af7Sopenharmony_ci * Vulkan Conformance Tests
3e5c31af7Sopenharmony_ci * ------------------------
4e5c31af7Sopenharmony_ci *
5e5c31af7Sopenharmony_ci * Copyright (c) 2023 The Khronos Group Inc.
6e5c31af7Sopenharmony_ci *
7e5c31af7Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
8e5c31af7Sopenharmony_ci * you may not use this file except in compliance with the License.
9e5c31af7Sopenharmony_ci * You may obtain a copy of the License at
10e5c31af7Sopenharmony_ci *
11e5c31af7Sopenharmony_ci *	  http://www.apache.org/licenses/LICENSE-2.0
12e5c31af7Sopenharmony_ci *
13e5c31af7Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
14e5c31af7Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
15e5c31af7Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16e5c31af7Sopenharmony_ci * See the License for the specific language governing permissions and
17e5c31af7Sopenharmony_ci * limitations under the License.
18e5c31af7Sopenharmony_ci *
19e5c31af7Sopenharmony_ci */
20e5c31af7Sopenharmony_ci/*!
21e5c31af7Sopenharmony_ci * \file
22e5c31af7Sopenharmony_ci * \brief Video decoding tests
23e5c31af7Sopenharmony_ci */
24e5c31af7Sopenharmony_ci/*--------------------------------------------------------------------*/
25e5c31af7Sopenharmony_ci
26e5c31af7Sopenharmony_ci#include "vktVideoDecodeTests.hpp"
27e5c31af7Sopenharmony_ci#include "vktVideoTestUtils.hpp"
28e5c31af7Sopenharmony_ci#include "vkBarrierUtil.hpp"
29e5c31af7Sopenharmony_ci#include "vkObjUtil.hpp"
30e5c31af7Sopenharmony_ci
31e5c31af7Sopenharmony_ci#include "tcuFunctionLibrary.hpp"
32e5c31af7Sopenharmony_ci#include "tcuPlatform.hpp"
33e5c31af7Sopenharmony_ci#include "tcuTestLog.hpp"
34e5c31af7Sopenharmony_ci
35e5c31af7Sopenharmony_ci#include "vkCmdUtil.hpp"
36e5c31af7Sopenharmony_ci#include "vkDefs.hpp"
37e5c31af7Sopenharmony_ci#include "vkImageWithMemory.hpp"
38e5c31af7Sopenharmony_ci#include "tcuCommandLine.hpp"
39e5c31af7Sopenharmony_ci
40e5c31af7Sopenharmony_ci#include "vktVideoClipInfo.hpp"
41e5c31af7Sopenharmony_ci
42e5c31af7Sopenharmony_ci#include <deDefs.h>
43e5c31af7Sopenharmony_ci
44e5c31af7Sopenharmony_ci#ifdef DE_BUILD_VIDEO
45e5c31af7Sopenharmony_ci#include "extESExtractor.hpp"
46e5c31af7Sopenharmony_ci#include "vktVideoBaseDecodeUtils.hpp"
47e5c31af7Sopenharmony_ci
48e5c31af7Sopenharmony_ci#include "extNvidiaVideoParserIf.hpp"
49e5c31af7Sopenharmony_ci// FIXME: The samples repo is missing this internal include from their H265 decoder
50e5c31af7Sopenharmony_ci#include "nvVulkanh265ScalingList.h"
51e5c31af7Sopenharmony_ci#include <VulkanH264Decoder.h>
52e5c31af7Sopenharmony_ci#include <VulkanH265Decoder.h>
53e5c31af7Sopenharmony_ci
54e5c31af7Sopenharmony_ci#include <utility>
55e5c31af7Sopenharmony_ci#endif
56e5c31af7Sopenharmony_ci
57e5c31af7Sopenharmony_cinamespace vkt
58e5c31af7Sopenharmony_ci{
59e5c31af7Sopenharmony_cinamespace video
60e5c31af7Sopenharmony_ci{
61e5c31af7Sopenharmony_ci
62e5c31af7Sopenharmony_ci// Set this to 1 to have the decoded YCbCr frames written to the
63e5c31af7Sopenharmony_ci// filesystem in the YV12 format.
64e5c31af7Sopenharmony_ci// Check the relevant sections to change the file name and so on...
65e5c31af7Sopenharmony_ci#define FRAME_DUMP_DEBUG 0
66e5c31af7Sopenharmony_ci
67e5c31af7Sopenharmony_cinamespace
68e5c31af7Sopenharmony_ci{
69e5c31af7Sopenharmony_ciusing namespace vk;
70e5c31af7Sopenharmony_ciusing namespace std;
71e5c31af7Sopenharmony_ci
72e5c31af7Sopenharmony_ciusing de::MovePtr;
73e5c31af7Sopenharmony_ci
74e5c31af7Sopenharmony_cienum TestType
75e5c31af7Sopenharmony_ci{
76e5c31af7Sopenharmony_ci	TEST_TYPE_H264_DECODE_I, // Case 6
77e5c31af7Sopenharmony_ci	TEST_TYPE_H264_DECODE_I_P, // Case 7
78e5c31af7Sopenharmony_ci	TEST_TYPE_H264_DECODE_CLIP_A,
79e5c31af7Sopenharmony_ci	TEST_TYPE_H264_DECODE_I_P_B_13, // Case 7a
80e5c31af7Sopenharmony_ci	TEST_TYPE_H264_DECODE_I_P_NOT_MATCHING_ORDER, // Case 8
81e5c31af7Sopenharmony_ci	TEST_TYPE_H264_DECODE_I_P_B_13_NOT_MATCHING_ORDER, // Case 8a
82e5c31af7Sopenharmony_ci	TEST_TYPE_H264_DECODE_QUERY_RESULT_WITH_STATUS, // Case 9
83e5c31af7Sopenharmony_ci	TEST_TYPE_H264_DECODE_RESOLUTION_CHANGE, // Case 17
84e5c31af7Sopenharmony_ci	TEST_TYPE_H264_DECODE_RESOLUTION_CHANGE_DPB, // Case 18
85e5c31af7Sopenharmony_ci	TEST_TYPE_H264_DECODE_INTERLEAVED, // Case 21
86e5c31af7Sopenharmony_ci	TEST_TYPE_H264_BOTH_DECODE_ENCODE_INTERLEAVED, // Case 23 TODO
87e5c31af7Sopenharmony_ci	TEST_TYPE_H264_H265_DECODE_INTERLEAVED, // Case 24
88e5c31af7Sopenharmony_ci
89e5c31af7Sopenharmony_ci	TEST_TYPE_H265_DECODE_I, // Case 15
90e5c31af7Sopenharmony_ci	TEST_TYPE_H265_DECODE_I_P, // Case 16
91e5c31af7Sopenharmony_ci	TEST_TYPE_H265_DECODE_CLIP_D,
92e5c31af7Sopenharmony_ci	TEST_TYPE_H265_DECODE_I_P_NOT_MATCHING_ORDER, // Case 16-2
93e5c31af7Sopenharmony_ci	TEST_TYPE_H265_DECODE_I_P_B_13, // Case 16-3
94e5c31af7Sopenharmony_ci	TEST_TYPE_H265_DECODE_I_P_B_13_NOT_MATCHING_ORDER, // Case 16-4
95e5c31af7Sopenharmony_ci
96e5c31af7Sopenharmony_ci	TEST_TYPE_LAST
97e5c31af7Sopenharmony_ci};
98e5c31af7Sopenharmony_ci
99e5c31af7Sopenharmony_ciconst char* getTestName(TestType type)
100e5c31af7Sopenharmony_ci{
101e5c31af7Sopenharmony_ci	const char* testName;
102e5c31af7Sopenharmony_ci	switch (type)
103e5c31af7Sopenharmony_ci	{
104e5c31af7Sopenharmony_ci		case TEST_TYPE_H264_DECODE_I:
105e5c31af7Sopenharmony_ci			testName = "h264_i";
106e5c31af7Sopenharmony_ci			break;
107e5c31af7Sopenharmony_ci		case TEST_TYPE_H264_DECODE_I_P:
108e5c31af7Sopenharmony_ci			testName = "h264_i_p";
109e5c31af7Sopenharmony_ci			break;
110e5c31af7Sopenharmony_ci		case TEST_TYPE_H264_DECODE_CLIP_A:
111e5c31af7Sopenharmony_ci			testName = "h264_420_8bit_high_176x144_30frames";
112e5c31af7Sopenharmony_ci			break;
113e5c31af7Sopenharmony_ci		case TEST_TYPE_H264_DECODE_I_P_NOT_MATCHING_ORDER:
114e5c31af7Sopenharmony_ci			testName = "h264_i_p_not_matching_order";
115e5c31af7Sopenharmony_ci			break;
116e5c31af7Sopenharmony_ci		case TEST_TYPE_H264_DECODE_I_P_B_13:
117e5c31af7Sopenharmony_ci			testName = "h264_i_p_b_13";
118e5c31af7Sopenharmony_ci			break;
119e5c31af7Sopenharmony_ci		case TEST_TYPE_H264_DECODE_I_P_B_13_NOT_MATCHING_ORDER:
120e5c31af7Sopenharmony_ci			testName = "h264_i_p_b_13_not_matching_order";
121e5c31af7Sopenharmony_ci			break;
122e5c31af7Sopenharmony_ci		case TEST_TYPE_H264_DECODE_QUERY_RESULT_WITH_STATUS:
123e5c31af7Sopenharmony_ci			testName = "h264_query_with_status";
124e5c31af7Sopenharmony_ci			break;
125e5c31af7Sopenharmony_ci		case TEST_TYPE_H264_DECODE_RESOLUTION_CHANGE:
126e5c31af7Sopenharmony_ci			testName = "h264_resolution_change";
127e5c31af7Sopenharmony_ci			break;
128e5c31af7Sopenharmony_ci		case TEST_TYPE_H264_DECODE_RESOLUTION_CHANGE_DPB:
129e5c31af7Sopenharmony_ci			testName = "h264_resolution_change_dpb";
130e5c31af7Sopenharmony_ci			break;
131e5c31af7Sopenharmony_ci		case TEST_TYPE_H264_DECODE_INTERLEAVED:
132e5c31af7Sopenharmony_ci			testName = "h264_interleaved";
133e5c31af7Sopenharmony_ci			break;
134e5c31af7Sopenharmony_ci		case TEST_TYPE_H264_H265_DECODE_INTERLEAVED:
135e5c31af7Sopenharmony_ci			testName = "h264_h265_interleaved";
136e5c31af7Sopenharmony_ci			break;
137e5c31af7Sopenharmony_ci		case TEST_TYPE_H265_DECODE_I:
138e5c31af7Sopenharmony_ci			testName = "h265_i";
139e5c31af7Sopenharmony_ci			break;
140e5c31af7Sopenharmony_ci		case TEST_TYPE_H265_DECODE_I_P:
141e5c31af7Sopenharmony_ci			testName = "h265_i_p";
142e5c31af7Sopenharmony_ci			break;
143e5c31af7Sopenharmony_ci		case TEST_TYPE_H265_DECODE_CLIP_D:
144e5c31af7Sopenharmony_ci			testName = "h265_420_8bit_main_176x144_30frames";
145e5c31af7Sopenharmony_ci			break;
146e5c31af7Sopenharmony_ci		case TEST_TYPE_H265_DECODE_I_P_NOT_MATCHING_ORDER:
147e5c31af7Sopenharmony_ci			testName = "h265_i_p_not_matching_order";
148e5c31af7Sopenharmony_ci			break;
149e5c31af7Sopenharmony_ci		case TEST_TYPE_H265_DECODE_I_P_B_13:
150e5c31af7Sopenharmony_ci			testName = "h265_i_p_b_13";
151e5c31af7Sopenharmony_ci			break;
152e5c31af7Sopenharmony_ci		case TEST_TYPE_H265_DECODE_I_P_B_13_NOT_MATCHING_ORDER:
153e5c31af7Sopenharmony_ci			testName = "h265_i_p_b_13_not_matching_order";
154e5c31af7Sopenharmony_ci			break;
155e5c31af7Sopenharmony_ci		default:
156e5c31af7Sopenharmony_ci			TCU_THROW(InternalError, "Unknown TestType");
157e5c31af7Sopenharmony_ci	}
158e5c31af7Sopenharmony_ci	return testName;
159e5c31af7Sopenharmony_ci}
160e5c31af7Sopenharmony_ci
161e5c31af7Sopenharmony_ci
162e5c31af7Sopenharmony_cienum DecoderOption : deUint32
163e5c31af7Sopenharmony_ci{
164e5c31af7Sopenharmony_ci	// The default is to do nothing additional to ordinary playback.
165e5c31af7Sopenharmony_ci	Default			  = 0,
166e5c31af7Sopenharmony_ci	// All decode operations will have their status checked for success (Q2 2023: not all vendors support these)
167e5c31af7Sopenharmony_ci	UseStatusQueries  = 1 << 0,
168e5c31af7Sopenharmony_ci	// Do not playback the clip in the "normal fashion", instead cached decode parameters for later process
169e5c31af7Sopenharmony_ci	// this is primarily used to support out-of-order submission test cases, and per-GOP handling.
170e5c31af7Sopenharmony_ci	CachedDecoding	  = 1 << 1,
171e5c31af7Sopenharmony_ci	// When a parameter object changes the resolution of the test content, and the new video session would otherwise
172e5c31af7Sopenharmony_ci	// still be compatible with the last session (for example, larger decode surfaces preceeding smaller decode surfaces,
173e5c31af7Sopenharmony_ci	// a frame downsize), force the session to be recreated anyway.
174e5c31af7Sopenharmony_ci	RecreateDPBImages = 1 << 2,
175e5c31af7Sopenharmony_ci};
176e5c31af7Sopenharmony_cistatic const int ALL_FRAMES = 0;
177e5c31af7Sopenharmony_ci
178e5c31af7Sopenharmony_cistruct BaseDecodeParam
179e5c31af7Sopenharmony_ci{
180e5c31af7Sopenharmony_ci	ClipName	  clip;
181e5c31af7Sopenharmony_ci	int			  framesToCheck;
182e5c31af7Sopenharmony_ci	DecoderOption decoderOptions;
183e5c31af7Sopenharmony_ci};
184e5c31af7Sopenharmony_ci
185e5c31af7Sopenharmony_cistruct DecodeTestParam
186e5c31af7Sopenharmony_ci{
187e5c31af7Sopenharmony_ci	TestType		type;
188e5c31af7Sopenharmony_ci	BaseDecodeParam stream;
189e5c31af7Sopenharmony_ci
190e5c31af7Sopenharmony_ci} g_DecodeTests[] = {
191e5c31af7Sopenharmony_ci	{TEST_TYPE_H264_DECODE_I, {CLIP_A, 1, DecoderOption::Default}},
192e5c31af7Sopenharmony_ci	{TEST_TYPE_H264_DECODE_I_P, {CLIP_A, 2, DecoderOption::Default}},
193e5c31af7Sopenharmony_ci	{TEST_TYPE_H264_DECODE_I_P_NOT_MATCHING_ORDER, {CLIP_A, 2, DecoderOption::CachedDecoding}},
194e5c31af7Sopenharmony_ci	{TEST_TYPE_H264_DECODE_CLIP_A, {CLIP_A, ALL_FRAMES, DecoderOption::Default}},
195e5c31af7Sopenharmony_ci	{TEST_TYPE_H264_DECODE_I_P_B_13, {CLIP_H264_4K_26_IBP_MAIN, ALL_FRAMES, DecoderOption::Default}},
196e5c31af7Sopenharmony_ci	{TEST_TYPE_H264_DECODE_I_P_B_13_NOT_MATCHING_ORDER, {CLIP_H264_4K_26_IBP_MAIN, ALL_FRAMES, DecoderOption::CachedDecoding}},
197e5c31af7Sopenharmony_ci	{TEST_TYPE_H264_DECODE_QUERY_RESULT_WITH_STATUS, {CLIP_A, ALL_FRAMES, DecoderOption::UseStatusQueries}},
198e5c31af7Sopenharmony_ci	{TEST_TYPE_H264_DECODE_RESOLUTION_CHANGE, {CLIP_C, ALL_FRAMES, DecoderOption::Default}},
199e5c31af7Sopenharmony_ci	{TEST_TYPE_H264_DECODE_RESOLUTION_CHANGE_DPB, {CLIP_C, ALL_FRAMES, DecoderOption::RecreateDPBImages}},
200e5c31af7Sopenharmony_ci
201e5c31af7Sopenharmony_ci	{TEST_TYPE_H265_DECODE_I, {CLIP_D, 1, DecoderOption::Default}},
202e5c31af7Sopenharmony_ci	{TEST_TYPE_H265_DECODE_I_P, {CLIP_D, 2, DecoderOption::Default}},
203e5c31af7Sopenharmony_ci	{TEST_TYPE_H265_DECODE_I_P_NOT_MATCHING_ORDER, {CLIP_D, 2, DecoderOption::CachedDecoding}},
204e5c31af7Sopenharmony_ci	{TEST_TYPE_H265_DECODE_I_P_B_13, {CLIP_JELLY_HEVC, ALL_FRAMES, DecoderOption::Default}},
205e5c31af7Sopenharmony_ci	{TEST_TYPE_H265_DECODE_I_P_B_13_NOT_MATCHING_ORDER, {CLIP_JELLY_HEVC, ALL_FRAMES, DecoderOption::CachedDecoding}},
206e5c31af7Sopenharmony_ci	{TEST_TYPE_H265_DECODE_CLIP_D, {CLIP_D, ALL_FRAMES, DecoderOption::Default}},
207e5c31af7Sopenharmony_ci};
208e5c31af7Sopenharmony_ci
209e5c31af7Sopenharmony_cistruct InterleavingDecodeTestParams
210e5c31af7Sopenharmony_ci{
211e5c31af7Sopenharmony_ci	TestType	type;
212e5c31af7Sopenharmony_ci	BaseDecodeParam streamA;
213e5c31af7Sopenharmony_ci	BaseDecodeParam streamB;
214e5c31af7Sopenharmony_ci} g_InterleavingTests[] = {
215e5c31af7Sopenharmony_ci	{TEST_TYPE_H264_DECODE_INTERLEAVED, {CLIP_A, ALL_FRAMES, DecoderOption::CachedDecoding}, {CLIP_A, ALL_FRAMES, DecoderOption::CachedDecoding}},
216e5c31af7Sopenharmony_ci	{TEST_TYPE_H264_H265_DECODE_INTERLEAVED, {CLIP_A, ALL_FRAMES, DecoderOption::CachedDecoding}, {CLIP_D, ALL_FRAMES, DecoderOption::CachedDecoding}},
217e5c31af7Sopenharmony_ci};
218e5c31af7Sopenharmony_ci
219e5c31af7Sopenharmony_ciclass TestDefinition
220e5c31af7Sopenharmony_ci{
221e5c31af7Sopenharmony_cipublic:
222e5c31af7Sopenharmony_ci	static MovePtr<TestDefinition> create(DecodeTestParam params, deUint32 baseSeed)
223e5c31af7Sopenharmony_ci	{
224e5c31af7Sopenharmony_ci		return MovePtr<TestDefinition>(new TestDefinition(params, baseSeed));
225e5c31af7Sopenharmony_ci	}
226e5c31af7Sopenharmony_ci
227e5c31af7Sopenharmony_ci	TestDefinition(DecodeTestParam params, deUint32 baseSeed)
228e5c31af7Sopenharmony_ci		: m_params(params)
229e5c31af7Sopenharmony_ci		, m_info(clipInfo(params.stream.clip))
230e5c31af7Sopenharmony_ci		, m_hash(baseSeed)
231e5c31af7Sopenharmony_ci	{
232e5c31af7Sopenharmony_ci		m_profile = VkVideoCoreProfile(m_info->profile.codecOperation, m_info->profile.subsamplingFlags, m_info->profile.lumaBitDepth, m_info->profile.chromaBitDepth, m_info->profile.profileIDC);
233e5c31af7Sopenharmony_ci		if (m_params.stream.framesToCheck == ALL_FRAMES)
234e5c31af7Sopenharmony_ci		{
235e5c31af7Sopenharmony_ci			m_params.stream.framesToCheck = m_info->totalFrames;
236e5c31af7Sopenharmony_ci		}
237e5c31af7Sopenharmony_ci		if (params.type == TEST_TYPE_H264_DECODE_RESOLUTION_CHANGE_DPB)
238e5c31af7Sopenharmony_ci		{
239e5c31af7Sopenharmony_ci			m_pictureParameterUpdateTriggerHack = 3;
240e5c31af7Sopenharmony_ci		}
241e5c31af7Sopenharmony_ci	}
242e5c31af7Sopenharmony_ci
243e5c31af7Sopenharmony_ci	TestType getTestType() const
244e5c31af7Sopenharmony_ci	{
245e5c31af7Sopenharmony_ci		return m_params.type;
246e5c31af7Sopenharmony_ci	}
247e5c31af7Sopenharmony_ci
248e5c31af7Sopenharmony_ci	const char* getClipFilename() const
249e5c31af7Sopenharmony_ci	{
250e5c31af7Sopenharmony_ci		return m_info->filename;
251e5c31af7Sopenharmony_ci	}
252e5c31af7Sopenharmony_ci
253e5c31af7Sopenharmony_ci	const ClipInfo* getClipInfo() const
254e5c31af7Sopenharmony_ci	{
255e5c31af7Sopenharmony_ci		return m_info;
256e5c31af7Sopenharmony_ci	};
257e5c31af7Sopenharmony_ci
258e5c31af7Sopenharmony_ci	VkVideoCodecOperationFlagBitsKHR getCodecOperation() const
259e5c31af7Sopenharmony_ci	{
260e5c31af7Sopenharmony_ci		return m_profile.GetCodecType();
261e5c31af7Sopenharmony_ci	}
262e5c31af7Sopenharmony_ci	const VkVideoCoreProfile* getProfile() const
263e5c31af7Sopenharmony_ci	{
264e5c31af7Sopenharmony_ci		return &m_profile;
265e5c31af7Sopenharmony_ci	}
266e5c31af7Sopenharmony_ci
267e5c31af7Sopenharmony_ci	int framesToCheck() const
268e5c31af7Sopenharmony_ci	{
269e5c31af7Sopenharmony_ci		return m_params.stream.framesToCheck;
270e5c31af7Sopenharmony_ci	}
271e5c31af7Sopenharmony_ci
272e5c31af7Sopenharmony_ci	bool hasOption(DecoderOption o) const
273e5c31af7Sopenharmony_ci	{
274e5c31af7Sopenharmony_ci		return (m_params.stream.decoderOptions & o) != 0;
275e5c31af7Sopenharmony_ci	}
276e5c31af7Sopenharmony_ci
277e5c31af7Sopenharmony_ci	int getParamaterUpdateHackRequirement() const
278e5c31af7Sopenharmony_ci	{
279e5c31af7Sopenharmony_ci		return m_pictureParameterUpdateTriggerHack;
280e5c31af7Sopenharmony_ci	}
281e5c31af7Sopenharmony_ci
282e5c31af7Sopenharmony_ci	VideoDevice::VideoDeviceFlags requiredDeviceFlags() const
283e5c31af7Sopenharmony_ci	{
284e5c31af7Sopenharmony_ci		return VideoDevice::VIDEO_DEVICE_FLAG_REQUIRE_SYNC2_OR_NOT_SUPPORTED |
285e5c31af7Sopenharmony_ci			   (hasOption(DecoderOption::UseStatusQueries) ? VideoDevice::VIDEO_DEVICE_FLAG_QUERY_WITH_STATUS_FOR_DECODE_SUPPORT : VideoDevice::VIDEO_DEVICE_FLAG_NONE);
286e5c31af7Sopenharmony_ci	}
287e5c31af7Sopenharmony_ci
288e5c31af7Sopenharmony_ci	const VkExtensionProperties* extensionProperties() const
289e5c31af7Sopenharmony_ci	{
290e5c31af7Sopenharmony_ci		static const VkExtensionProperties h264StdExtensionVersion = {
291e5c31af7Sopenharmony_ci			VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_EXTENSION_NAME, VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_SPEC_VERSION};
292e5c31af7Sopenharmony_ci		static const VkExtensionProperties h265StdExtensionVersion = {
293e5c31af7Sopenharmony_ci			VK_STD_VULKAN_VIDEO_CODEC_H265_DECODE_EXTENSION_NAME, VK_STD_VULKAN_VIDEO_CODEC_H265_DECODE_SPEC_VERSION};
294e5c31af7Sopenharmony_ci
295e5c31af7Sopenharmony_ci		switch (m_profile.GetCodecType())
296e5c31af7Sopenharmony_ci		{
297e5c31af7Sopenharmony_ci			case VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR:
298e5c31af7Sopenharmony_ci				return &h264StdExtensionVersion;
299e5c31af7Sopenharmony_ci			case VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR:
300e5c31af7Sopenharmony_ci				return &h265StdExtensionVersion;
301e5c31af7Sopenharmony_ci			default:
302e5c31af7Sopenharmony_ci				tcu::die("Unsupported video codec %s\n", util::codecToName(m_profile.GetCodecType()));
303e5c31af7Sopenharmony_ci				break;
304e5c31af7Sopenharmony_ci		}
305e5c31af7Sopenharmony_ci
306e5c31af7Sopenharmony_ci		TCU_THROW(InternalError, "Unsupported codec");
307e5c31af7Sopenharmony_ci	};
308e5c31af7Sopenharmony_ci
309e5c31af7Sopenharmony_ci	void updateHash(deUint32 baseHash)
310e5c31af7Sopenharmony_ci	{
311e5c31af7Sopenharmony_ci		m_hash = deUint32Hash(baseHash);
312e5c31af7Sopenharmony_ci	}
313e5c31af7Sopenharmony_ci
314e5c31af7Sopenharmony_ciprivate:
315e5c31af7Sopenharmony_ci	DecodeTestParam	   m_params;
316e5c31af7Sopenharmony_ci	const ClipInfo*	   m_info{};
317e5c31af7Sopenharmony_ci	deUint32		   m_hash{};
318e5c31af7Sopenharmony_ci	VkVideoCoreProfile m_profile;
319e5c31af7Sopenharmony_ci	// The 1-based count of parameter set updates after which to force a parameter object release.
320e5c31af7Sopenharmony_ci	// This is required due to the design of the NVIDIA decode-client API. It sends parameter updates and expects constructed parameter
321e5c31af7Sopenharmony_ci	// objects back synchronously, before the next video session is created in a following BeginSequence call.
322e5c31af7Sopenharmony_ci	int				   m_pictureParameterUpdateTriggerHack{0}; // Zero is "off"
323e5c31af7Sopenharmony_ci};
324e5c31af7Sopenharmony_ci
325e5c31af7Sopenharmony_ci
326e5c31af7Sopenharmony_ci// Vulkan video is not supported on android platform
327e5c31af7Sopenharmony_ci// all external libraries, helper functions and test instances has been excluded
328e5c31af7Sopenharmony_ci#ifdef DE_BUILD_VIDEO
329e5c31af7Sopenharmony_ciusing VkVideoParser = VkSharedBaseObj<VulkanVideoDecodeParser>;
330e5c31af7Sopenharmony_ci
331e5c31af7Sopenharmony_civoid createParser(const TestDefinition* params, VideoBaseDecoder* decoder, VkSharedBaseObj<VulkanVideoDecodeParser>& parser)
332e5c31af7Sopenharmony_ci{
333e5c31af7Sopenharmony_ci	VkVideoCapabilitiesKHR		 videoCaps{};
334e5c31af7Sopenharmony_ci	VkVideoDecodeCapabilitiesKHR videoDecodeCaps{};
335e5c31af7Sopenharmony_ci	util::getVideoDecodeCapabilities(*decoder->m_deviceContext, decoder->m_profile, videoCaps, videoDecodeCaps);
336e5c31af7Sopenharmony_ci
337e5c31af7Sopenharmony_ci	const VkParserInitDecodeParameters pdParams = {
338e5c31af7Sopenharmony_ci		NV_VULKAN_VIDEO_PARSER_API_VERSION,
339e5c31af7Sopenharmony_ci		dynamic_cast<VkParserVideoDecodeClient*>(decoder),
340e5c31af7Sopenharmony_ci		static_cast<deUint32>(2 * 1024 * 1024), // 2MiB is the default bitstream buffer size
341e5c31af7Sopenharmony_ci		static_cast<deUint32>(videoCaps.minBitstreamBufferOffsetAlignment),
342e5c31af7Sopenharmony_ci		static_cast<deUint32>(videoCaps.minBitstreamBufferSizeAlignment),
343e5c31af7Sopenharmony_ci		0,
344e5c31af7Sopenharmony_ci		0,
345e5c31af7Sopenharmony_ci		nullptr,
346e5c31af7Sopenharmony_ci		true,
347e5c31af7Sopenharmony_ci	};
348e5c31af7Sopenharmony_ci
349e5c31af7Sopenharmony_ci	if (videoLoggingEnabled())
350e5c31af7Sopenharmony_ci	{
351e5c31af7Sopenharmony_ci		tcu::print("Creating a parser with offset alignment=%d and size alignment=%d\n",
352e5c31af7Sopenharmony_ci				   static_cast<deUint32>(videoCaps.minBitstreamBufferOffsetAlignment),
353e5c31af7Sopenharmony_ci				   static_cast<deUint32>(videoCaps.minBitstreamBufferSizeAlignment));
354e5c31af7Sopenharmony_ci	}
355e5c31af7Sopenharmony_ci
356e5c31af7Sopenharmony_ci	const VkExtensionProperties* pStdExtensionVersion = params->extensionProperties();
357e5c31af7Sopenharmony_ci	DE_ASSERT(pStdExtensionVersion);
358e5c31af7Sopenharmony_ci
359e5c31af7Sopenharmony_ci	switch (params->getCodecOperation())
360e5c31af7Sopenharmony_ci	{
361e5c31af7Sopenharmony_ci		case VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR:
362e5c31af7Sopenharmony_ci		{
363e5c31af7Sopenharmony_ci			if (strcmp(pStdExtensionVersion->extensionName, VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_EXTENSION_NAME) || pStdExtensionVersion->specVersion != VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_SPEC_VERSION)
364e5c31af7Sopenharmony_ci			{
365e5c31af7Sopenharmony_ci				tcu::die("The requested decoder h.264 Codec STD version is NOT supported. The supported decoder h.264 Codec STD version is version %d of %s\n",
366e5c31af7Sopenharmony_ci						 VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_SPEC_VERSION,
367e5c31af7Sopenharmony_ci						 VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_EXTENSION_NAME);
368e5c31af7Sopenharmony_ci			}
369e5c31af7Sopenharmony_ci			VkSharedBaseObj<VulkanH264Decoder> nvVideoH264DecodeParser(new VulkanH264Decoder(params->getCodecOperation()));
370e5c31af7Sopenharmony_ci			parser = nvVideoH264DecodeParser;
371e5c31af7Sopenharmony_ci			break;
372e5c31af7Sopenharmony_ci		}
373e5c31af7Sopenharmony_ci		case VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR:
374e5c31af7Sopenharmony_ci		{
375e5c31af7Sopenharmony_ci			if (strcmp(pStdExtensionVersion->extensionName, VK_STD_VULKAN_VIDEO_CODEC_H265_DECODE_EXTENSION_NAME) || pStdExtensionVersion->specVersion != VK_STD_VULKAN_VIDEO_CODEC_H265_DECODE_SPEC_VERSION)
376e5c31af7Sopenharmony_ci			{
377e5c31af7Sopenharmony_ci				tcu::die("The requested decoder h.265 Codec STD version is NOT supported. The supported decoder h.265 Codec STD version is version %d of %s\n",
378e5c31af7Sopenharmony_ci						 VK_STD_VULKAN_VIDEO_CODEC_H265_DECODE_SPEC_VERSION,
379e5c31af7Sopenharmony_ci						 VK_STD_VULKAN_VIDEO_CODEC_H265_DECODE_EXTENSION_NAME);
380e5c31af7Sopenharmony_ci			}
381e5c31af7Sopenharmony_ci			VkSharedBaseObj<VulkanH265Decoder> nvVideoH265DecodeParser(new VulkanH265Decoder(params->getCodecOperation()));
382e5c31af7Sopenharmony_ci			parser = nvVideoH265DecodeParser;
383e5c31af7Sopenharmony_ci			break;
384e5c31af7Sopenharmony_ci		}
385e5c31af7Sopenharmony_ci		default:
386e5c31af7Sopenharmony_ci			TCU_FAIL("Unsupported codec type!");
387e5c31af7Sopenharmony_ci	}
388e5c31af7Sopenharmony_ci
389e5c31af7Sopenharmony_ci	VK_CHECK(parser->Initialize(&pdParams));
390e5c31af7Sopenharmony_ci}
391e5c31af7Sopenharmony_ci
392e5c31af7Sopenharmony_cistatic MovePtr<VideoBaseDecoder> decoderFromTestDefinition(DeviceContext* devctx, const TestDefinition& test)
393e5c31af7Sopenharmony_ci{
394e5c31af7Sopenharmony_ci	VkSharedBaseObj<VulkanVideoFrameBuffer> vkVideoFrameBuffer;
395e5c31af7Sopenharmony_ci	VK_CHECK(VulkanVideoFrameBuffer::Create(devctx,
396e5c31af7Sopenharmony_ci											test.hasOption(DecoderOption::UseStatusQueries),
397e5c31af7Sopenharmony_ci											vkVideoFrameBuffer));
398e5c31af7Sopenharmony_ci
399e5c31af7Sopenharmony_ci	VideoBaseDecoder::Parameters params;
400e5c31af7Sopenharmony_ci	params.profile							 = test.getProfile();
401e5c31af7Sopenharmony_ci	params.context							 = devctx;
402e5c31af7Sopenharmony_ci	params.framebuffer						 = vkVideoFrameBuffer;
403e5c31af7Sopenharmony_ci	params.framesToCheck					 = test.framesToCheck();
404e5c31af7Sopenharmony_ci	params.queryDecodeStatus				 = test.hasOption(DecoderOption::UseStatusQueries);
405e5c31af7Sopenharmony_ci	params.outOfOrderDecoding				 = test.hasOption(DecoderOption::CachedDecoding);
406e5c31af7Sopenharmony_ci	params.alwaysRecreateDPB				 = test.hasOption(DecoderOption::RecreateDPBImages);
407e5c31af7Sopenharmony_ci	params.pictureParameterUpdateTriggerHack = test.getParamaterUpdateHackRequirement();
408e5c31af7Sopenharmony_ci
409e5c31af7Sopenharmony_ci	return MovePtr<VideoBaseDecoder>(new VideoBaseDecoder(std::move(params)));
410e5c31af7Sopenharmony_ci}
411e5c31af7Sopenharmony_ci
412e5c31af7Sopenharmony_ciclass FrameProcessor
413e5c31af7Sopenharmony_ci{
414e5c31af7Sopenharmony_cipublic:
415e5c31af7Sopenharmony_ci	static const int DECODER_QUEUE_SIZE = 6;
416e5c31af7Sopenharmony_ci
417e5c31af7Sopenharmony_ci	FrameProcessor(DeviceContext* devctx, const TestDefinition* params, VideoBaseDecoder* decoder, tcu::TestLog& log)
418e5c31af7Sopenharmony_ci		: m_devctx(devctx)
419e5c31af7Sopenharmony_ci		, m_demuxer(params->getClipFilename(), log)
420e5c31af7Sopenharmony_ci		, m_decoder(decoder)
421e5c31af7Sopenharmony_ci		, m_frameData(DECODER_QUEUE_SIZE)
422e5c31af7Sopenharmony_ci		, m_frameDataIdx(0)
423e5c31af7Sopenharmony_ci	{
424e5c31af7Sopenharmony_ci		createParser(params, m_decoder, m_parser);
425e5c31af7Sopenharmony_ci		for (auto& frame : m_frameData)
426e5c31af7Sopenharmony_ci			frame.Reset();
427e5c31af7Sopenharmony_ci	}
428e5c31af7Sopenharmony_ci
429e5c31af7Sopenharmony_ci	void parseNextChunk()
430e5c31af7Sopenharmony_ci	{
431e5c31af7Sopenharmony_ci		deUint8*				pData		   = 0;
432e5c31af7Sopenharmony_ci		deInt64					size		   = 0;
433e5c31af7Sopenharmony_ci		bool					demuxerSuccess = m_demuxer.Demux(&pData, &size);
434e5c31af7Sopenharmony_ci
435e5c31af7Sopenharmony_ci		VkParserBitstreamPacket pkt;
436e5c31af7Sopenharmony_ci		pkt.pByteStream			 = pData; // Ptr to byte stream data decode/display event
437e5c31af7Sopenharmony_ci		pkt.nDataLength			 = size; // Data length for this packet
438e5c31af7Sopenharmony_ci		pkt.llPTS				 = 0; // Presentation Time Stamp for this packet (clock rate specified at initialization)
439e5c31af7Sopenharmony_ci		pkt.bEOS				 = !demuxerSuccess; // true if this is an End-Of-Stream packet (flush everything)
440e5c31af7Sopenharmony_ci		pkt.bPTSValid			 = false; // true if llPTS is valid (also used to detect frame boundaries for VC1 SP/MP)
441e5c31af7Sopenharmony_ci		pkt.bDiscontinuity		 = false; // true if DecMFT is signalling a discontinuity
442e5c31af7Sopenharmony_ci		pkt.bPartialParsing		 = 0; // 0: parse entire packet, 1: parse until next
443e5c31af7Sopenharmony_ci		pkt.bEOP				 = false; // true if the packet in pByteStream is exactly one frame
444e5c31af7Sopenharmony_ci		pkt.pbSideData			 = nullptr; // Auxiliary encryption information
445e5c31af7Sopenharmony_ci		pkt.nSideDataLength		 = 0; // Auxiliary encrypton information length
446e5c31af7Sopenharmony_ci
447e5c31af7Sopenharmony_ci		size_t	   parsedBytes	 = 0;
448e5c31af7Sopenharmony_ci		const bool parserSuccess = m_parser->ParseByteStream(&pkt, &parsedBytes);
449e5c31af7Sopenharmony_ci		if (videoLoggingEnabled())
450e5c31af7Sopenharmony_ci			std::cout << "Parsed " << parsedBytes << " bytes from bitstream" << std::endl;
451e5c31af7Sopenharmony_ci
452e5c31af7Sopenharmony_ci		m_videoStreamHasEnded = !(demuxerSuccess && parserSuccess);
453e5c31af7Sopenharmony_ci	}
454e5c31af7Sopenharmony_ci
455e5c31af7Sopenharmony_ci	int getNextFrame(DecodedFrame* pFrame)
456e5c31af7Sopenharmony_ci	{
457e5c31af7Sopenharmony_ci		// The below call to DequeueDecodedPicture allows returning the next frame without parsing of the stream.
458e5c31af7Sopenharmony_ci		// Parsing is only done when there are no more frames in the queue.
459e5c31af7Sopenharmony_ci		int32_t framesInQueue = m_decoder->GetVideoFrameBuffer()->DequeueDecodedPicture(pFrame);
460e5c31af7Sopenharmony_ci
461e5c31af7Sopenharmony_ci		// Loop until a frame (or more) is parsed and added to the queue.
462e5c31af7Sopenharmony_ci		while ((framesInQueue == 0) && !m_videoStreamHasEnded)
463e5c31af7Sopenharmony_ci		{
464e5c31af7Sopenharmony_ci			parseNextChunk();
465e5c31af7Sopenharmony_ci			framesInQueue		= m_decoder->GetVideoFrameBuffer()->DequeueDecodedPicture(pFrame);
466e5c31af7Sopenharmony_ci		}
467e5c31af7Sopenharmony_ci
468e5c31af7Sopenharmony_ci		if ((framesInQueue == 0) && m_videoStreamHasEnded)
469e5c31af7Sopenharmony_ci		{
470e5c31af7Sopenharmony_ci			return -1;
471e5c31af7Sopenharmony_ci		}
472e5c31af7Sopenharmony_ci
473e5c31af7Sopenharmony_ci		return framesInQueue;
474e5c31af7Sopenharmony_ci	}
475e5c31af7Sopenharmony_ci
476e5c31af7Sopenharmony_ci	const DecodedFrame* decodeFrame()
477e5c31af7Sopenharmony_ci	{
478e5c31af7Sopenharmony_ci		auto&		  vk				= m_devctx->getDeviceDriver();
479e5c31af7Sopenharmony_ci		auto		  device			= m_devctx->device;
480e5c31af7Sopenharmony_ci		DecodedFrame* pLastDecodedFrame = &m_frameData[m_frameDataIdx];
481e5c31af7Sopenharmony_ci
482e5c31af7Sopenharmony_ci		// Make sure the frame complete fence signaled (video frame is processed) before returning the frame.
483e5c31af7Sopenharmony_ci		if (pLastDecodedFrame->frameCompleteFence != VK_NULL_HANDLE)
484e5c31af7Sopenharmony_ci		{
485e5c31af7Sopenharmony_ci			VK_CHECK(vk.waitForFences(device, 1, &pLastDecodedFrame->frameCompleteFence, true, TIMEOUT_100ms));
486e5c31af7Sopenharmony_ci			VK_CHECK(vk.getFenceStatus(device, pLastDecodedFrame->frameCompleteFence));
487e5c31af7Sopenharmony_ci		}
488e5c31af7Sopenharmony_ci
489e5c31af7Sopenharmony_ci		m_decoder->ReleaseDisplayedFrame(pLastDecodedFrame);
490e5c31af7Sopenharmony_ci		pLastDecodedFrame->Reset();
491e5c31af7Sopenharmony_ci
492e5c31af7Sopenharmony_ci		TCU_CHECK_MSG(getNextFrame(pLastDecodedFrame) > 0, "Unexpected decode result");
493e5c31af7Sopenharmony_ci		TCU_CHECK_MSG(pLastDecodedFrame, "Unexpected decode result");
494e5c31af7Sopenharmony_ci
495e5c31af7Sopenharmony_ci		if (videoLoggingEnabled())
496e5c31af7Sopenharmony_ci			std::cout << "<= Wait on picIdx: " << pLastDecodedFrame->pictureIndex
497e5c31af7Sopenharmony_ci					  << "\t\tdisplayWidth: " << pLastDecodedFrame->displayWidth
498e5c31af7Sopenharmony_ci					  << "\t\tdisplayHeight: " << pLastDecodedFrame->displayHeight
499e5c31af7Sopenharmony_ci					  << "\t\tdisplayOrder: " << pLastDecodedFrame->displayOrder
500e5c31af7Sopenharmony_ci					  << "\tdecodeOrder: " << pLastDecodedFrame->decodeOrder
501e5c31af7Sopenharmony_ci					  << "\ttimestamp " << pLastDecodedFrame->timestamp
502e5c31af7Sopenharmony_ci					  << "\tdstImageView " << (pLastDecodedFrame->outputImageView ? pLastDecodedFrame->outputImageView->GetImageResource()->GetImage() : VK_NULL_HANDLE)
503e5c31af7Sopenharmony_ci					  << std::endl;
504e5c31af7Sopenharmony_ci
505e5c31af7Sopenharmony_ci		m_frameDataIdx = (m_frameDataIdx + 1) % m_frameData.size();
506e5c31af7Sopenharmony_ci		return pLastDecodedFrame;
507e5c31af7Sopenharmony_ci	}
508e5c31af7Sopenharmony_ci
509e5c31af7Sopenharmony_ci	void bufferFrames(int framesToDecode)
510e5c31af7Sopenharmony_ci	{
511e5c31af7Sopenharmony_ci		// This loop is for the out-of-order submissions cases. First all the frame information is gathered from the parser<->decoder loop
512e5c31af7Sopenharmony_ci		// then the command buffers are recorded in a random order, as well as the queue submissions, depending on the configuration of
513e5c31af7Sopenharmony_ci		// the test.
514e5c31af7Sopenharmony_ci		// NOTE: For this sequence to work, the frame buffer must have enough decode surfaces for the GOP intended for decode, otherwise
515e5c31af7Sopenharmony_ci		// picture allocation will fail pretty quickly! See m_numDecodeSurfaces, m_maxDecodeFramesCount
516e5c31af7Sopenharmony_ci		// The previous CTS cases were not actually randomizing the queue submission order (despite claiming too!)
517e5c31af7Sopenharmony_ci		DE_ASSERT(m_decoder->m_outOfOrderDecoding);
518e5c31af7Sopenharmony_ci		do
519e5c31af7Sopenharmony_ci		{
520e5c31af7Sopenharmony_ci			parseNextChunk();
521e5c31af7Sopenharmony_ci			size_t decodedFrames	= m_decoder->GetVideoFrameBuffer()->GetDisplayedFrameCount();
522e5c31af7Sopenharmony_ci			if (decodedFrames == framesToDecode)
523e5c31af7Sopenharmony_ci				break;
524e5c31af7Sopenharmony_ci		}
525e5c31af7Sopenharmony_ci		while (!m_videoStreamHasEnded);
526e5c31af7Sopenharmony_ci		DE_ASSERT(m_decoder->m_cachedDecodeParams.size() == framesToDecode);
527e5c31af7Sopenharmony_ci	}
528e5c31af7Sopenharmony_ci
529e5c31af7Sopenharmony_ci	int getBufferedDisplayCount() const { return m_decoder->GetVideoFrameBuffer()->GetDisplayedFrameCount(); }
530e5c31af7Sopenharmony_ciprivate:
531e5c31af7Sopenharmony_ci	DeviceContext* m_devctx;
532e5c31af7Sopenharmony_ci	ESEDemuxer m_demuxer;
533e5c31af7Sopenharmony_ci	VkVideoParser m_parser;
534e5c31af7Sopenharmony_ci	VideoBaseDecoder* m_decoder;
535e5c31af7Sopenharmony_ci
536e5c31af7Sopenharmony_ci	std::vector<DecodedFrame> m_frameData;
537e5c31af7Sopenharmony_ci	size_t m_frameDataIdx{};
538e5c31af7Sopenharmony_ci
539e5c31af7Sopenharmony_ci	bool m_videoStreamHasEnded{false};
540e5c31af7Sopenharmony_ci};
541e5c31af7Sopenharmony_ci
542e5c31af7Sopenharmony_cide::MovePtr<vkt::ycbcr::MultiPlaneImageData> getDecodedImage(DeviceContext&		 devctx,
543e5c31af7Sopenharmony_ci															 VkImageLayout		 layout,
544e5c31af7Sopenharmony_ci															 const DecodedFrame* frame)
545e5c31af7Sopenharmony_ci{
546e5c31af7Sopenharmony_ci	auto&									 vkd					  = devctx.getDeviceDriver();
547e5c31af7Sopenharmony_ci	auto									 device					  = devctx.device;
548e5c31af7Sopenharmony_ci	auto									 queueFamilyIndexDecode	  = devctx.decodeQueueFamilyIdx();
549e5c31af7Sopenharmony_ci	auto									 queueFamilyIndexTransfer = devctx.transferQueueFamilyIdx();
550e5c31af7Sopenharmony_ci	const VkExtent2D						 imageExtent{(deUint32)frame->displayWidth, (deUint32)frame->displayHeight};
551e5c31af7Sopenharmony_ci	const VkImage							 image	= frame->outputImageView->GetImageResource()->GetImage();
552e5c31af7Sopenharmony_ci	const VkFormat							 format = frame->outputImageView->GetImageResource()->GetImageCreateInfo().format;
553e5c31af7Sopenharmony_ci	const uint32_t							 videoImageLayerIndex = frame->imageLayerIndex;
554e5c31af7Sopenharmony_ci
555e5c31af7Sopenharmony_ci	MovePtr<vkt::ycbcr::MultiPlaneImageData> multiPlaneImageData(new vkt::ycbcr::MultiPlaneImageData(format, tcu::UVec2(imageExtent.width, imageExtent.height)));
556e5c31af7Sopenharmony_ci	const VkQueue							 queueDecode				   = getDeviceQueue(vkd, device, queueFamilyIndexDecode, 0u);
557e5c31af7Sopenharmony_ci	const VkQueue							 queueTransfer				   = getDeviceQueue(vkd, device, queueFamilyIndexTransfer, 0u);
558e5c31af7Sopenharmony_ci	const VkImageSubresourceRange			 imageSubresourceRange		   = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, videoImageLayerIndex, 1);
559e5c31af7Sopenharmony_ci	const VkImageMemoryBarrier2KHR			 imageBarrierDecode			   = makeImageMemoryBarrier2(VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR,
560e5c31af7Sopenharmony_ci																				 VK_ACCESS_2_VIDEO_DECODE_WRITE_BIT_KHR,
561e5c31af7Sopenharmony_ci																				 VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR,
562e5c31af7Sopenharmony_ci																				 VK_ACCESS_NONE_KHR,
563e5c31af7Sopenharmony_ci																				 layout,
564e5c31af7Sopenharmony_ci																				 VK_IMAGE_LAYOUT_GENERAL,
565e5c31af7Sopenharmony_ci																				 image,
566e5c31af7Sopenharmony_ci																				 imageSubresourceRange);
567e5c31af7Sopenharmony_ci	const VkImageMemoryBarrier2KHR			 imageBarrierOwnershipDecode   = makeImageMemoryBarrier2(VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR,
568e5c31af7Sopenharmony_ci																						 VK_ACCESS_NONE_KHR,
569e5c31af7Sopenharmony_ci																						 VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR,
570e5c31af7Sopenharmony_ci																						 VK_ACCESS_NONE_KHR,
571e5c31af7Sopenharmony_ci																						 VK_IMAGE_LAYOUT_GENERAL,
572e5c31af7Sopenharmony_ci																						 VK_IMAGE_LAYOUT_GENERAL,
573e5c31af7Sopenharmony_ci																						 image,
574e5c31af7Sopenharmony_ci																						 imageSubresourceRange,
575e5c31af7Sopenharmony_ci																						 queueFamilyIndexDecode,
576e5c31af7Sopenharmony_ci																						 queueFamilyIndexTransfer);
577e5c31af7Sopenharmony_ci	const VkImageMemoryBarrier2KHR			 imageBarrierOwnershipTransfer = makeImageMemoryBarrier2(VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR,
578e5c31af7Sopenharmony_ci																							 VK_ACCESS_NONE_KHR,
579e5c31af7Sopenharmony_ci																							 VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR,
580e5c31af7Sopenharmony_ci																							 VK_ACCESS_NONE_KHR,
581e5c31af7Sopenharmony_ci																							 VK_IMAGE_LAYOUT_GENERAL,
582e5c31af7Sopenharmony_ci																							 VK_IMAGE_LAYOUT_GENERAL,
583e5c31af7Sopenharmony_ci																							 image,
584e5c31af7Sopenharmony_ci																							 imageSubresourceRange,
585e5c31af7Sopenharmony_ci																							 queueFamilyIndexDecode,
586e5c31af7Sopenharmony_ci																							 queueFamilyIndexTransfer);
587e5c31af7Sopenharmony_ci	const VkImageMemoryBarrier2KHR			 imageBarrierTransfer		   = makeImageMemoryBarrier2(VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR,
588e5c31af7Sopenharmony_ci																					 VK_ACCESS_2_TRANSFER_READ_BIT_KHR,
589e5c31af7Sopenharmony_ci																					 VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR,
590e5c31af7Sopenharmony_ci																					 VK_ACCESS_NONE_KHR,
591e5c31af7Sopenharmony_ci																					 VK_IMAGE_LAYOUT_GENERAL,
592e5c31af7Sopenharmony_ci																					 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
593e5c31af7Sopenharmony_ci																					 image,
594e5c31af7Sopenharmony_ci																					 imageSubresourceRange);
595e5c31af7Sopenharmony_ci	const Move<VkCommandPool>				 cmdDecodePool(makeCommandPool(vkd, device, queueFamilyIndexDecode));
596e5c31af7Sopenharmony_ci	const Move<VkCommandBuffer>				 cmdDecodeBuffer(allocateCommandBuffer(vkd, device, *cmdDecodePool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
597e5c31af7Sopenharmony_ci	const Move<VkCommandPool>				 cmdTransferPool(makeCommandPool(vkd, device, queueFamilyIndexTransfer));
598e5c31af7Sopenharmony_ci	const Move<VkCommandBuffer>				 cmdTransferBuffer(allocateCommandBuffer(vkd, device, *cmdTransferPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
599e5c31af7Sopenharmony_ci	Move<VkSemaphore>						 semaphore		  = createSemaphore(vkd, device);
600e5c31af7Sopenharmony_ci	Move<VkFence>							 decodeFence	  = createFence(vkd, device);
601e5c31af7Sopenharmony_ci	Move<VkFence>							 transferFence	  = createFence(vkd, device);
602e5c31af7Sopenharmony_ci	VkFence									 fences[]		  = {*decodeFence, *transferFence};
603e5c31af7Sopenharmony_ci	const VkPipelineStageFlags				 waitDstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
604e5c31af7Sopenharmony_ci	VkSubmitInfo							 decodeSubmitInfo{
605e5c31af7Sopenharmony_ci		VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType                              sType;
606e5c31af7Sopenharmony_ci		DE_NULL, // const void*                                  pNext;
607e5c31af7Sopenharmony_ci		0u, // deUint32                                             waitSemaphoreCount;
608e5c31af7Sopenharmony_ci		DE_NULL, // const VkSemaphore*                   pWaitSemaphores;
609e5c31af7Sopenharmony_ci		DE_NULL, // const VkPipelineStageFlags*  pWaitDstStageMask;
610e5c31af7Sopenharmony_ci		1u, // deUint32                                             commandBufferCount;
611e5c31af7Sopenharmony_ci		&*cmdDecodeBuffer, // const VkCommandBuffer*               pCommandBuffers;
612e5c31af7Sopenharmony_ci		1u, // deUint32                                             signalSemaphoreCount;
613e5c31af7Sopenharmony_ci		&*semaphore, // const VkSemaphore*                   pSignalSemaphores;
614e5c31af7Sopenharmony_ci	};
615e5c31af7Sopenharmony_ci	if (frame->frameCompleteSemaphore != VK_NULL_HANDLE)
616e5c31af7Sopenharmony_ci	{
617e5c31af7Sopenharmony_ci		decodeSubmitInfo.waitSemaphoreCount = 1;
618e5c31af7Sopenharmony_ci		decodeSubmitInfo.pWaitSemaphores	= &frame->frameCompleteSemaphore;
619e5c31af7Sopenharmony_ci		decodeSubmitInfo.pWaitDstStageMask	= &waitDstStageMask;
620e5c31af7Sopenharmony_ci	}
621e5c31af7Sopenharmony_ci	const VkSubmitInfo transferSubmitInfo{
622e5c31af7Sopenharmony_ci		VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType                              sType;
623e5c31af7Sopenharmony_ci		DE_NULL, // const void*                                  pNext;
624e5c31af7Sopenharmony_ci		1u, // deUint32                                             waitSemaphoreCount;
625e5c31af7Sopenharmony_ci		&*semaphore, // const VkSemaphore*                   pWaitSemaphores;
626e5c31af7Sopenharmony_ci		&waitDstStageMask, // const VkPipelineStageFlags*  pWaitDstStageMask;
627e5c31af7Sopenharmony_ci		1u, // deUint32                                             commandBufferCount;
628e5c31af7Sopenharmony_ci		&*cmdTransferBuffer, // const VkCommandBuffer*               pCommandBuffers;
629e5c31af7Sopenharmony_ci		0u, // deUint32                                             signalSemaphoreCount;
630e5c31af7Sopenharmony_ci		DE_NULL, // const VkSemaphore*                   pSignalSemaphores;
631e5c31af7Sopenharmony_ci	};
632e5c31af7Sopenharmony_ci
633e5c31af7Sopenharmony_ci	DEBUGLOG(std::cout << "getDecodedImage: " << image << " " << layout << std::endl);
634e5c31af7Sopenharmony_ci
635e5c31af7Sopenharmony_ci	beginCommandBuffer(vkd, *cmdDecodeBuffer, 0u);
636e5c31af7Sopenharmony_ci	cmdPipelineImageMemoryBarrier2(vkd, *cmdDecodeBuffer, &imageBarrierDecode);
637e5c31af7Sopenharmony_ci	cmdPipelineImageMemoryBarrier2(vkd, *cmdDecodeBuffer, &imageBarrierOwnershipDecode);
638e5c31af7Sopenharmony_ci	endCommandBuffer(vkd, *cmdDecodeBuffer);
639e5c31af7Sopenharmony_ci
640e5c31af7Sopenharmony_ci	beginCommandBuffer(vkd, *cmdTransferBuffer, 0u);
641e5c31af7Sopenharmony_ci	cmdPipelineImageMemoryBarrier2(vkd, *cmdTransferBuffer, &imageBarrierOwnershipTransfer);
642e5c31af7Sopenharmony_ci	cmdPipelineImageMemoryBarrier2(vkd, *cmdTransferBuffer, &imageBarrierTransfer);
643e5c31af7Sopenharmony_ci	endCommandBuffer(vkd, *cmdTransferBuffer);
644e5c31af7Sopenharmony_ci
645e5c31af7Sopenharmony_ci	VK_CHECK(vkd.queueSubmit(queueDecode, 1u, &decodeSubmitInfo, *decodeFence));
646e5c31af7Sopenharmony_ci	VK_CHECK(vkd.queueSubmit(queueTransfer, 1u, &transferSubmitInfo, *transferFence));
647e5c31af7Sopenharmony_ci
648e5c31af7Sopenharmony_ci	VK_CHECK(vkd.waitForFences(device, DE_LENGTH_OF_ARRAY(fences), fences, DE_TRUE, ~0ull));
649e5c31af7Sopenharmony_ci
650e5c31af7Sopenharmony_ci	vkt::ycbcr::downloadImage(vkd, device, queueFamilyIndexTransfer, devctx.allocator(), image,
651e5c31af7Sopenharmony_ci	                          multiPlaneImageData.get(), 0, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
652e5c31af7Sopenharmony_ci	                          videoImageLayerIndex);
653e5c31af7Sopenharmony_ci
654e5c31af7Sopenharmony_ci	const VkImageMemoryBarrier2KHR imageBarrierTransfer2 = makeImageMemoryBarrier2(VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR,
655e5c31af7Sopenharmony_ci																				   VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR,
656e5c31af7Sopenharmony_ci																				   VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR,
657e5c31af7Sopenharmony_ci																				   VK_ACCESS_NONE_KHR,
658e5c31af7Sopenharmony_ci																				   VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
659e5c31af7Sopenharmony_ci																				   layout,
660e5c31af7Sopenharmony_ci																				   image,
661e5c31af7Sopenharmony_ci																				   imageSubresourceRange);
662e5c31af7Sopenharmony_ci
663e5c31af7Sopenharmony_ci	vkd.resetCommandBuffer(*cmdTransferBuffer, 0u);
664e5c31af7Sopenharmony_ci	vkd.resetFences(device, 1, &*transferFence);
665e5c31af7Sopenharmony_ci	beginCommandBuffer(vkd, *cmdTransferBuffer, 0u);
666e5c31af7Sopenharmony_ci	cmdPipelineImageMemoryBarrier2(vkd, *cmdTransferBuffer, &imageBarrierTransfer2);
667e5c31af7Sopenharmony_ci	endCommandBuffer(vkd, *cmdTransferBuffer);
668e5c31af7Sopenharmony_ci
669e5c31af7Sopenharmony_ci	const VkSubmitInfo transferSubmitInfo2{
670e5c31af7Sopenharmony_ci		VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType                              sType;
671e5c31af7Sopenharmony_ci		DE_NULL, // const void*                                  pNext;
672e5c31af7Sopenharmony_ci		0u, // deUint32                                             waitSemaphoreCount;
673e5c31af7Sopenharmony_ci		DE_NULL, // const VkSemaphore*                   pWaitSemaphores;
674e5c31af7Sopenharmony_ci		DE_NULL, // const VkPipelineStageFlags*  pWaitDstStageMask;
675e5c31af7Sopenharmony_ci		1u, // deUint32                                             commandBufferCount;
676e5c31af7Sopenharmony_ci		&*cmdTransferBuffer, // const VkCommandBuffer*               pCommandBuffers;
677e5c31af7Sopenharmony_ci		0u, // deUint32                                             signalSemaphoreCount;
678e5c31af7Sopenharmony_ci		DE_NULL, // const VkSemaphore*                   pSignalSemaphores;
679e5c31af7Sopenharmony_ci	};
680e5c31af7Sopenharmony_ci
681e5c31af7Sopenharmony_ci	VK_CHECK(vkd.queueSubmit(queueTransfer, 1u, &transferSubmitInfo2, *transferFence));
682e5c31af7Sopenharmony_ci	VK_CHECK(vkd.waitForFences(device, 1, &*transferFence, DE_TRUE, ~0ull));
683e5c31af7Sopenharmony_ci
684e5c31af7Sopenharmony_ci	return multiPlaneImageData;
685e5c31af7Sopenharmony_ci}
686e5c31af7Sopenharmony_ci
687e5c31af7Sopenharmony_ci
688e5c31af7Sopenharmony_ciclass VideoDecodeTestInstance : public VideoBaseTestInstance
689e5c31af7Sopenharmony_ci{
690e5c31af7Sopenharmony_cipublic:
691e5c31af7Sopenharmony_ci	VideoDecodeTestInstance(Context& context, const TestDefinition* testDefinition);
692e5c31af7Sopenharmony_ci	tcu::TestStatus iterate(void);
693e5c31af7Sopenharmony_ci
694e5c31af7Sopenharmony_ciprotected:
695e5c31af7Sopenharmony_ci	const TestDefinition*	  m_testDefinition;
696e5c31af7Sopenharmony_ci	MovePtr<VideoBaseDecoder> m_decoder{};
697e5c31af7Sopenharmony_ci	static_assert(sizeof(DeviceContext) < 128, "DeviceContext has grown bigger than expected!");
698e5c31af7Sopenharmony_ci	DeviceContext m_deviceContext;
699e5c31af7Sopenharmony_ci};
700e5c31af7Sopenharmony_ci
701e5c31af7Sopenharmony_ciclass InterleavingDecodeTestInstance : public VideoBaseTestInstance
702e5c31af7Sopenharmony_ci{
703e5c31af7Sopenharmony_cipublic:
704e5c31af7Sopenharmony_ci	InterleavingDecodeTestInstance(Context& context, const std::vector<MovePtr<TestDefinition>>& testDefinitions);
705e5c31af7Sopenharmony_ci	tcu::TestStatus iterate(void);
706e5c31af7Sopenharmony_ci
707e5c31af7Sopenharmony_ciprotected:
708e5c31af7Sopenharmony_ci	const std::vector<MovePtr<TestDefinition>>& m_testDefinitions;
709e5c31af7Sopenharmony_ci	std::vector<MovePtr<VideoBaseDecoder>>		m_decoders{};
710e5c31af7Sopenharmony_ci	static_assert(sizeof(DeviceContext) < 128, "DeviceContext has grown bigger than expected!");
711e5c31af7Sopenharmony_ci	DeviceContext m_deviceContext;
712e5c31af7Sopenharmony_ci};
713e5c31af7Sopenharmony_ci
714e5c31af7Sopenharmony_ciInterleavingDecodeTestInstance::InterleavingDecodeTestInstance(Context& context, const std::vector<MovePtr<TestDefinition>>& testDefinitions)
715e5c31af7Sopenharmony_ci	: VideoBaseTestInstance(context), m_testDefinitions(std::move(testDefinitions))
716e5c31af7Sopenharmony_ci{
717e5c31af7Sopenharmony_ci	int							  requiredCodecs	  = VK_VIDEO_CODEC_OPERATION_NONE_KHR;
718e5c31af7Sopenharmony_ci	VideoDevice::VideoDeviceFlags requiredDeviceFlags = VideoDevice::VideoDeviceFlagBits::VIDEO_DEVICE_FLAG_NONE;
719e5c31af7Sopenharmony_ci	for (const auto& test : m_testDefinitions)
720e5c31af7Sopenharmony_ci	{
721e5c31af7Sopenharmony_ci		VkVideoCodecOperationFlagBitsKHR testBits = test->getCodecOperation();
722e5c31af7Sopenharmony_ci		requiredCodecs |= testBits;
723e5c31af7Sopenharmony_ci		requiredDeviceFlags |= test->requiredDeviceFlags();
724e5c31af7Sopenharmony_ci	}
725e5c31af7Sopenharmony_ci	VkDevice device			= getDeviceSupportingQueue(VK_QUEUE_VIDEO_DECODE_BIT_KHR | VK_QUEUE_TRANSFER_BIT, requiredCodecs, requiredDeviceFlags);
726e5c31af7Sopenharmony_ci
727e5c31af7Sopenharmony_ci	m_deviceContext.context = &m_context;
728e5c31af7Sopenharmony_ci	m_deviceContext.device	= device;
729e5c31af7Sopenharmony_ci	m_deviceContext.phys	= m_context.getPhysicalDevice();
730e5c31af7Sopenharmony_ci	m_deviceContext.vd		= &m_videoDevice;
731e5c31af7Sopenharmony_ci	// TODO: Support for multiple queues / multithreading
732e5c31af7Sopenharmony_ci	m_deviceContext.transferQueue =
733e5c31af7Sopenharmony_ci		getDeviceQueue(m_context.getDeviceInterface(), device, m_videoDevice.getQueueFamilyIndexTransfer(), 0);
734e5c31af7Sopenharmony_ci	m_deviceContext.decodeQueue =
735e5c31af7Sopenharmony_ci		getDeviceQueue(m_context.getDeviceInterface(), device, m_videoDevice.getQueueFamilyIndexDecode(), 0);
736e5c31af7Sopenharmony_ci
737e5c31af7Sopenharmony_ci	for (const auto& test : m_testDefinitions)
738e5c31af7Sopenharmony_ci		m_decoders.push_back(decoderFromTestDefinition(&m_deviceContext, *test));
739e5c31af7Sopenharmony_ci}
740e5c31af7Sopenharmony_ci
741e5c31af7Sopenharmony_ciVideoDecodeTestInstance::VideoDecodeTestInstance(Context& context, const TestDefinition* testDefinition)
742e5c31af7Sopenharmony_ci	: VideoBaseTestInstance(context), m_testDefinition(testDefinition)
743e5c31af7Sopenharmony_ci{
744e5c31af7Sopenharmony_ci	VkDevice device			= getDeviceSupportingQueue(VK_QUEUE_VIDEO_DECODE_BIT_KHR | VK_QUEUE_TRANSFER_BIT,
745e5c31af7Sopenharmony_ci											   m_testDefinition->getCodecOperation(),
746e5c31af7Sopenharmony_ci											   m_testDefinition->requiredDeviceFlags());
747e5c31af7Sopenharmony_ci
748e5c31af7Sopenharmony_ci	m_deviceContext.context = &m_context;
749e5c31af7Sopenharmony_ci	m_deviceContext.device	= device;
750e5c31af7Sopenharmony_ci	m_deviceContext.phys	= m_context.getPhysicalDevice();
751e5c31af7Sopenharmony_ci	m_deviceContext.vd		= &m_videoDevice;
752e5c31af7Sopenharmony_ci	// TODO: Support for multiple queues / multithreading
753e5c31af7Sopenharmony_ci	m_deviceContext.transferQueue =
754e5c31af7Sopenharmony_ci		getDeviceQueue(m_context.getDeviceInterface(), device, m_videoDevice.getQueueFamilyIndexTransfer(), 0);
755e5c31af7Sopenharmony_ci	m_deviceContext.decodeQueue =
756e5c31af7Sopenharmony_ci		getDeviceQueue(m_context.getDeviceInterface(), device, m_videoDevice.getQueueFamilyIndexDecode(), 0);
757e5c31af7Sopenharmony_ci
758e5c31af7Sopenharmony_ci	m_decoder = decoderFromTestDefinition(&m_deviceContext, *m_testDefinition);
759e5c31af7Sopenharmony_ci}
760e5c31af7Sopenharmony_ci
761e5c31af7Sopenharmony_citcu::TestStatus VideoDecodeTestInstance::iterate()
762e5c31af7Sopenharmony_ci{
763e5c31af7Sopenharmony_ci#if FRAME_DUMP_DEBUG
764e5c31af7Sopenharmony_ci#ifdef _WIN32
765e5c31af7Sopenharmony_ci	FILE* output = fopen("C:\\output.yuv", "wb");
766e5c31af7Sopenharmony_ci#else
767e5c31af7Sopenharmony_ci	FILE* output = fopen("/tmp/output.yuv", "wb");
768e5c31af7Sopenharmony_ci#endif
769e5c31af7Sopenharmony_ci#endif
770e5c31af7Sopenharmony_ci
771e5c31af7Sopenharmony_ci	FrameProcessor	 processor(&m_deviceContext, m_testDefinition, m_decoder.get(), m_context.getTestContext().getLog());
772e5c31af7Sopenharmony_ci	std::vector<int> incorrectFrames;
773e5c31af7Sopenharmony_ci	std::vector<int> correctFrames;
774e5c31af7Sopenharmony_ci
775e5c31af7Sopenharmony_ci	if (m_testDefinition->hasOption(DecoderOption::CachedDecoding))
776e5c31af7Sopenharmony_ci	{
777e5c31af7Sopenharmony_ci		processor.bufferFrames(m_testDefinition->framesToCheck());
778e5c31af7Sopenharmony_ci		m_decoder->decodeFramesOutOfOrder();
779e5c31af7Sopenharmony_ci	}
780e5c31af7Sopenharmony_ci
781e5c31af7Sopenharmony_ci	for (int frameNumber = 0; frameNumber < m_testDefinition->framesToCheck(); frameNumber++)
782e5c31af7Sopenharmony_ci	{
783e5c31af7Sopenharmony_ci		const DecodedFrame* decodedFrame = processor.decodeFrame();
784e5c31af7Sopenharmony_ci		TCU_CHECK_MSG(decodedFrame, "Decoder did not produce the expected amount of frames");
785e5c31af7Sopenharmony_ci		auto resultImage = getDecodedImage(m_deviceContext, m_decoder->dpbAndOutputCoincide() ? VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR : VK_IMAGE_LAYOUT_VIDEO_DECODE_DST_KHR, decodedFrame);
786e5c31af7Sopenharmony_ci
787e5c31af7Sopenharmony_ci#if FRAME_DUMP_DEBUG
788e5c31af7Sopenharmony_ci		auto bytes = semiplanarToYV12(*resultImage);
789e5c31af7Sopenharmony_ci		fwrite(bytes.data(), 1, bytes.size(), output);
790e5c31af7Sopenharmony_ci#endif
791e5c31af7Sopenharmony_ci		std::string checksum = checksumForClipFrame(m_testDefinition->getClipInfo(), frameNumber);
792e5c31af7Sopenharmony_ci		if (imageMatchesReferenceChecksum(*resultImage, checksum))
793e5c31af7Sopenharmony_ci		{
794e5c31af7Sopenharmony_ci			correctFrames.push_back(frameNumber);
795e5c31af7Sopenharmony_ci		}
796e5c31af7Sopenharmony_ci		else
797e5c31af7Sopenharmony_ci		{
798e5c31af7Sopenharmony_ci			incorrectFrames.push_back(frameNumber);
799e5c31af7Sopenharmony_ci		}
800e5c31af7Sopenharmony_ci	}
801e5c31af7Sopenharmony_ci
802e5c31af7Sopenharmony_ci#if FRAME_DUMP_DEBUG
803e5c31af7Sopenharmony_ci	fclose(output);
804e5c31af7Sopenharmony_ci#endif
805e5c31af7Sopenharmony_ci	if (!correctFrames.empty() && correctFrames.size() == m_testDefinition->framesToCheck())
806e5c31af7Sopenharmony_ci		return tcu::TestStatus::pass(de::toString(m_testDefinition->framesToCheck()) + " correctly decoded frames");
807e5c31af7Sopenharmony_ci	else
808e5c31af7Sopenharmony_ci	{
809e5c31af7Sopenharmony_ci		stringstream ss;
810e5c31af7Sopenharmony_ci		ss << correctFrames.size() << " out of " << m_testDefinition->framesToCheck() << " frames rendered correctly (";
811e5c31af7Sopenharmony_ci		if (correctFrames.size() < incorrectFrames.size())
812e5c31af7Sopenharmony_ci		{
813e5c31af7Sopenharmony_ci			ss << "correct frames: ";
814e5c31af7Sopenharmony_ci			for (int i : correctFrames)
815e5c31af7Sopenharmony_ci				ss << i << " ";
816e5c31af7Sopenharmony_ci		}
817e5c31af7Sopenharmony_ci		else
818e5c31af7Sopenharmony_ci		{
819e5c31af7Sopenharmony_ci			ss << "incorrect frames: ";
820e5c31af7Sopenharmony_ci			for (int i : incorrectFrames)
821e5c31af7Sopenharmony_ci				ss << i << " ";
822e5c31af7Sopenharmony_ci		}
823e5c31af7Sopenharmony_ci		ss << "\b)";
824e5c31af7Sopenharmony_ci		return tcu::TestStatus::fail(ss.str());
825e5c31af7Sopenharmony_ci	}
826e5c31af7Sopenharmony_ci}
827e5c31af7Sopenharmony_ci
828e5c31af7Sopenharmony_citcu::TestStatus InterleavingDecodeTestInstance::iterate(void)
829e5c31af7Sopenharmony_ci{
830e5c31af7Sopenharmony_ci	DE_ASSERT(m_testDefinitions.size() == m_decoders.size());
831e5c31af7Sopenharmony_ci	DE_ASSERT(m_decoders.size() > 1);
832e5c31af7Sopenharmony_ci
833e5c31af7Sopenharmony_ci	std::vector<MovePtr<FrameProcessor>> processors;
834e5c31af7Sopenharmony_ci	for (int i = 0; i < m_testDefinitions.size(); i++)
835e5c31af7Sopenharmony_ci	{
836e5c31af7Sopenharmony_ci		processors.push_back(MovePtr<FrameProcessor>(new FrameProcessor(&m_deviceContext, m_testDefinitions[i].get(), m_decoders[i].get(), m_context.getTestContext().getLog())));
837e5c31af7Sopenharmony_ci	}
838e5c31af7Sopenharmony_ci
839e5c31af7Sopenharmony_ci#if FRAME_DUMP_DEBUG
840e5c31af7Sopenharmony_ci#ifdef _WIN32
841e5c31af7Sopenharmony_ci	FILE* output = fopen("C:\\output.yuv", "wb");
842e5c31af7Sopenharmony_ci#else
843e5c31af7Sopenharmony_ci	FILE* output = fopen("/tmp/output.yuv", "wb");
844e5c31af7Sopenharmony_ci#endif
845e5c31af7Sopenharmony_ci#endif
846e5c31af7Sopenharmony_ci
847e5c31af7Sopenharmony_ci	// First cache up all the decoded frames from the various decode sessions
848e5c31af7Sopenharmony_ci	for (int i = 0; i < m_testDefinitions.size(); i++)
849e5c31af7Sopenharmony_ci	{
850e5c31af7Sopenharmony_ci		const auto& test	  = m_testDefinitions[i];
851e5c31af7Sopenharmony_ci		auto&		processor = processors[i];
852e5c31af7Sopenharmony_ci		processor->bufferFrames(test->framesToCheck());
853e5c31af7Sopenharmony_ci		DE_ASSERT(processor->getBufferedDisplayCount() == test->framesToCheck());
854e5c31af7Sopenharmony_ci	}
855e5c31af7Sopenharmony_ci
856e5c31af7Sopenharmony_ci	auto interleaveCacheSize	= m_decoders[0]->m_cachedDecodeParams.size();
857e5c31af7Sopenharmony_ci	auto firstStreamDecodeQueue = m_decoders[0]->m_deviceContext->decodeQueue;
858e5c31af7Sopenharmony_ci
859e5c31af7Sopenharmony_ci	size_t	 totalFrames			= 0;
860e5c31af7Sopenharmony_ci	for (auto& decoder : m_decoders)
861e5c31af7Sopenharmony_ci	{
862e5c31af7Sopenharmony_ci		DE_ASSERT(decoder->m_cachedDecodeParams.size() == interleaveCacheSize);
863e5c31af7Sopenharmony_ci		DE_ASSERT(decoder->m_deviceContext->decodeQueue == firstStreamDecodeQueue);
864e5c31af7Sopenharmony_ci		totalFrames += decoder->m_cachedDecodeParams.size();
865e5c31af7Sopenharmony_ci	}
866e5c31af7Sopenharmony_ci
867e5c31af7Sopenharmony_ci	DE_UNREF(firstStreamDecodeQueue);
868e5c31af7Sopenharmony_ci
869e5c31af7Sopenharmony_ci	// Interleave command buffer recording
870e5c31af7Sopenharmony_ci	for (int i = 0; i < interleaveCacheSize; i++)
871e5c31af7Sopenharmony_ci	{
872e5c31af7Sopenharmony_ci		for (auto& decoder : m_decoders)
873e5c31af7Sopenharmony_ci		{
874e5c31af7Sopenharmony_ci			decoder->WaitForFrameFences(decoder->m_cachedDecodeParams[i]);
875e5c31af7Sopenharmony_ci			decoder->ApplyPictureParameters(decoder->m_cachedDecodeParams[i]);
876e5c31af7Sopenharmony_ci			decoder->RecordCommandBuffer(decoder->m_cachedDecodeParams[i]);
877e5c31af7Sopenharmony_ci		}
878e5c31af7Sopenharmony_ci	}
879e5c31af7Sopenharmony_ci
880e5c31af7Sopenharmony_ci	// Interleave submissions
881e5c31af7Sopenharmony_ci	for (int i = 0; i < interleaveCacheSize; i++)
882e5c31af7Sopenharmony_ci	{
883e5c31af7Sopenharmony_ci		for (int decoderIdx = 0; decoderIdx < m_decoders.size(); decoderIdx++)
884e5c31af7Sopenharmony_ci		{
885e5c31af7Sopenharmony_ci			auto& decoder = m_decoders[decoderIdx];
886e5c31af7Sopenharmony_ci			auto& test	  = m_testDefinitions[decoderIdx];
887e5c31af7Sopenharmony_ci			decoder->SubmitQueue(decoder->m_cachedDecodeParams[i]);
888e5c31af7Sopenharmony_ci			if (test->hasOption(DecoderOption::UseStatusQueries))
889e5c31af7Sopenharmony_ci			{
890e5c31af7Sopenharmony_ci				decoder->QueryDecodeResults(decoder->m_cachedDecodeParams[i]);
891e5c31af7Sopenharmony_ci			}
892e5c31af7Sopenharmony_ci		}
893e5c31af7Sopenharmony_ci	}
894e5c31af7Sopenharmony_ci
895e5c31af7Sopenharmony_ci	struct InterleavedDecodeResults
896e5c31af7Sopenharmony_ci	{
897e5c31af7Sopenharmony_ci		std::vector<int> correctFrames;
898e5c31af7Sopenharmony_ci		std::vector<int> incorrectFrames;
899e5c31af7Sopenharmony_ci	};
900e5c31af7Sopenharmony_ci	std::vector<InterleavedDecodeResults> results(m_testDefinitions.size());
901e5c31af7Sopenharmony_ci
902e5c31af7Sopenharmony_ci	for (int i = 0; i < m_testDefinitions.size(); i++)
903e5c31af7Sopenharmony_ci	{
904e5c31af7Sopenharmony_ci		auto& test		= m_testDefinitions[i];
905e5c31af7Sopenharmony_ci		auto& decoder	= m_decoders[i];
906e5c31af7Sopenharmony_ci		auto& processor = processors[i];
907e5c31af7Sopenharmony_ci		for (int frameNumber = 0; frameNumber < m_testDefinitions[i]->framesToCheck(); frameNumber++)
908e5c31af7Sopenharmony_ci		{
909e5c31af7Sopenharmony_ci			const DecodedFrame* frame		= processor->decodeFrame();
910e5c31af7Sopenharmony_ci			auto				resultImage = getDecodedImage(m_deviceContext, decoder->dpbAndOutputCoincide() ? VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR : VK_IMAGE_LAYOUT_VIDEO_DECODE_DST_KHR, frame);
911e5c31af7Sopenharmony_ci#if FRAME_DUMP_DEBUG
912e5c31af7Sopenharmony_ci			auto bytes = semiplanarToYV12(*resultImage);
913e5c31af7Sopenharmony_ci			fwrite(bytes.data(), 1, bytes.size(), output);
914e5c31af7Sopenharmony_ci#endif
915e5c31af7Sopenharmony_ci			auto				checksum	= checksumForClipFrame(test->getClipInfo(), frameNumber);
916e5c31af7Sopenharmony_ci			if (imageMatchesReferenceChecksum(*resultImage, checksum))
917e5c31af7Sopenharmony_ci			{
918e5c31af7Sopenharmony_ci				results[i].correctFrames.push_back(frameNumber);
919e5c31af7Sopenharmony_ci			}
920e5c31af7Sopenharmony_ci			else
921e5c31af7Sopenharmony_ci			{
922e5c31af7Sopenharmony_ci				results[i].incorrectFrames.push_back(frameNumber);
923e5c31af7Sopenharmony_ci			}
924e5c31af7Sopenharmony_ci		}
925e5c31af7Sopenharmony_ci	}
926e5c31af7Sopenharmony_ci
927e5c31af7Sopenharmony_ci#if FRAME_DUMP_DEBUG
928e5c31af7Sopenharmony_ci	fclose(output);
929e5c31af7Sopenharmony_ci#endif
930e5c31af7Sopenharmony_ci
931e5c31af7Sopenharmony_ci	bool allTestsPassed	  = true;
932e5c31af7Sopenharmony_ci	int	 totalFramesCheck = 0;
933e5c31af7Sopenharmony_ci	for (const auto& res : results)
934e5c31af7Sopenharmony_ci	{
935e5c31af7Sopenharmony_ci		if (!res.incorrectFrames.empty())
936e5c31af7Sopenharmony_ci			allTestsPassed = false;
937e5c31af7Sopenharmony_ci		totalFramesCheck += (res.correctFrames.size() + res.incorrectFrames.size());
938e5c31af7Sopenharmony_ci	}
939e5c31af7Sopenharmony_ci	DE_ASSERT(totalFramesCheck == totalFrames);
940e5c31af7Sopenharmony_ci
941e5c31af7Sopenharmony_ci	if (allTestsPassed)
942e5c31af7Sopenharmony_ci		return tcu::TestStatus::pass(de::toString(totalFrames) + " correctly decoded frames");
943e5c31af7Sopenharmony_ci	else
944e5c31af7Sopenharmony_ci	{
945e5c31af7Sopenharmony_ci		stringstream ss;
946e5c31af7Sopenharmony_ci		ss << "Interleaving failure: ";
947e5c31af7Sopenharmony_ci		for (int i = 0; i < results.size(); i++)
948e5c31af7Sopenharmony_ci		{
949e5c31af7Sopenharmony_ci			const auto& result = results[i];
950e5c31af7Sopenharmony_ci			if (!result.incorrectFrames.empty())
951e5c31af7Sopenharmony_ci			{
952e5c31af7Sopenharmony_ci				ss << " (stream #" << i << " incorrect frames: ";
953e5c31af7Sopenharmony_ci				for (int frame : result.incorrectFrames)
954e5c31af7Sopenharmony_ci					ss << frame << " ";
955e5c31af7Sopenharmony_ci				ss << "\b)";
956e5c31af7Sopenharmony_ci			}
957e5c31af7Sopenharmony_ci		}
958e5c31af7Sopenharmony_ci		return tcu::TestStatus::fail(ss.str());
959e5c31af7Sopenharmony_ci	}
960e5c31af7Sopenharmony_ci}
961e5c31af7Sopenharmony_ci
962e5c31af7Sopenharmony_ci#endif // #ifdef DE_BUILD_VIDEO
963e5c31af7Sopenharmony_ci
964e5c31af7Sopenharmony_ciclass VideoDecodeTestCase : public vkt::TestCase
965e5c31af7Sopenharmony_ci{
966e5c31af7Sopenharmony_cipublic:
967e5c31af7Sopenharmony_ci	VideoDecodeTestCase(tcu::TestContext& context, const char* name, MovePtr<TestDefinition> testDefinition)
968e5c31af7Sopenharmony_ci		: vkt::TestCase(context, name), m_testDefinition(testDefinition)
969e5c31af7Sopenharmony_ci	{
970e5c31af7Sopenharmony_ci	}
971e5c31af7Sopenharmony_ci
972e5c31af7Sopenharmony_ci	TestInstance* createInstance(Context& context) const override;
973e5c31af7Sopenharmony_ci	void		  checkSupport(Context& context) const override;
974e5c31af7Sopenharmony_ci
975e5c31af7Sopenharmony_ciprivate:
976e5c31af7Sopenharmony_ci	MovePtr<TestDefinition> m_testDefinition;
977e5c31af7Sopenharmony_ci};
978e5c31af7Sopenharmony_ci
979e5c31af7Sopenharmony_ciclass InterleavingDecodeTestCase : public vkt::TestCase
980e5c31af7Sopenharmony_ci{
981e5c31af7Sopenharmony_cipublic:
982e5c31af7Sopenharmony_ci	InterleavingDecodeTestCase(tcu::TestContext& context, const char* name, std::vector<MovePtr<TestDefinition>>&& testDefinitions)
983e5c31af7Sopenharmony_ci		: vkt::TestCase(context, name), m_testDefinitions(std::move(testDefinitions))
984e5c31af7Sopenharmony_ci	{
985e5c31af7Sopenharmony_ci	}
986e5c31af7Sopenharmony_ci
987e5c31af7Sopenharmony_ci	TestInstance* createInstance(Context& context) const override
988e5c31af7Sopenharmony_ci	{
989e5c31af7Sopenharmony_ci#ifdef DE_BUILD_VIDEO
990e5c31af7Sopenharmony_ci		return new InterleavingDecodeTestInstance(context, m_testDefinitions);
991e5c31af7Sopenharmony_ci#endif
992e5c31af7Sopenharmony_ci		DE_UNREF(context);
993e5c31af7Sopenharmony_ci		return nullptr;
994e5c31af7Sopenharmony_ci	}
995e5c31af7Sopenharmony_ci	void checkSupport(Context& context) const override;
996e5c31af7Sopenharmony_ci
997e5c31af7Sopenharmony_ciprivate:
998e5c31af7Sopenharmony_ci	std::vector<MovePtr<TestDefinition>> m_testDefinitions;
999e5c31af7Sopenharmony_ci};
1000e5c31af7Sopenharmony_ci
1001e5c31af7Sopenharmony_ciTestInstance* VideoDecodeTestCase::createInstance(Context& context) const
1002e5c31af7Sopenharmony_ci{
1003e5c31af7Sopenharmony_ci#ifdef DE_BUILD_VIDEO
1004e5c31af7Sopenharmony_ci	return new VideoDecodeTestInstance(context, m_testDefinition.get());
1005e5c31af7Sopenharmony_ci#endif
1006e5c31af7Sopenharmony_ci
1007e5c31af7Sopenharmony_ci#ifndef DE_BUILD_VIDEO
1008e5c31af7Sopenharmony_ci	DE_UNREF(context);
1009e5c31af7Sopenharmony_ci	return nullptr;
1010e5c31af7Sopenharmony_ci#endif
1011e5c31af7Sopenharmony_ci}
1012e5c31af7Sopenharmony_ci
1013e5c31af7Sopenharmony_civoid VideoDecodeTestCase::checkSupport(Context& context) const
1014e5c31af7Sopenharmony_ci{
1015e5c31af7Sopenharmony_ci	context.requireDeviceFunctionality("VK_KHR_video_queue");
1016e5c31af7Sopenharmony_ci	context.requireDeviceFunctionality("VK_KHR_synchronization2");
1017e5c31af7Sopenharmony_ci
1018e5c31af7Sopenharmony_ci	switch (m_testDefinition->getTestType())
1019e5c31af7Sopenharmony_ci	{
1020e5c31af7Sopenharmony_ci		case TEST_TYPE_H264_DECODE_I:
1021e5c31af7Sopenharmony_ci		case TEST_TYPE_H264_DECODE_I_P:
1022e5c31af7Sopenharmony_ci		case TEST_TYPE_H264_DECODE_CLIP_A:
1023e5c31af7Sopenharmony_ci		case TEST_TYPE_H264_DECODE_I_P_NOT_MATCHING_ORDER:
1024e5c31af7Sopenharmony_ci		case TEST_TYPE_H264_DECODE_I_P_B_13:
1025e5c31af7Sopenharmony_ci		case TEST_TYPE_H264_DECODE_I_P_B_13_NOT_MATCHING_ORDER:
1026e5c31af7Sopenharmony_ci		case TEST_TYPE_H264_DECODE_QUERY_RESULT_WITH_STATUS:
1027e5c31af7Sopenharmony_ci		case TEST_TYPE_H264_DECODE_RESOLUTION_CHANGE:
1028e5c31af7Sopenharmony_ci		case TEST_TYPE_H264_DECODE_RESOLUTION_CHANGE_DPB:
1029e5c31af7Sopenharmony_ci		{
1030e5c31af7Sopenharmony_ci			context.requireDeviceFunctionality("VK_KHR_video_decode_h264");
1031e5c31af7Sopenharmony_ci			break;
1032e5c31af7Sopenharmony_ci		}
1033e5c31af7Sopenharmony_ci		case TEST_TYPE_H265_DECODE_I:
1034e5c31af7Sopenharmony_ci		case TEST_TYPE_H265_DECODE_I_P:
1035e5c31af7Sopenharmony_ci		case TEST_TYPE_H265_DECODE_CLIP_D:
1036e5c31af7Sopenharmony_ci		case TEST_TYPE_H265_DECODE_I_P_NOT_MATCHING_ORDER:
1037e5c31af7Sopenharmony_ci		case TEST_TYPE_H265_DECODE_I_P_B_13:
1038e5c31af7Sopenharmony_ci		case TEST_TYPE_H265_DECODE_I_P_B_13_NOT_MATCHING_ORDER:
1039e5c31af7Sopenharmony_ci		{
1040e5c31af7Sopenharmony_ci			context.requireDeviceFunctionality("VK_KHR_video_decode_h265");
1041e5c31af7Sopenharmony_ci			break;
1042e5c31af7Sopenharmony_ci		}
1043e5c31af7Sopenharmony_ci		default:
1044e5c31af7Sopenharmony_ci			TCU_THROW(InternalError, "Unknown TestType");
1045e5c31af7Sopenharmony_ci	}
1046e5c31af7Sopenharmony_ci}
1047e5c31af7Sopenharmony_ci
1048e5c31af7Sopenharmony_civoid InterleavingDecodeTestCase::checkSupport(Context& context) const
1049e5c31af7Sopenharmony_ci{
1050e5c31af7Sopenharmony_ci	context.requireDeviceFunctionality("VK_KHR_video_queue");
1051e5c31af7Sopenharmony_ci	context.requireDeviceFunctionality("VK_KHR_synchronization2");
1052e5c31af7Sopenharmony_ci
1053e5c31af7Sopenharmony_ci#ifdef DE_DEBUG
1054e5c31af7Sopenharmony_ci	DE_ASSERT(!m_testDefinitions.empty());
1055e5c31af7Sopenharmony_ci	TestType firstType = m_testDefinitions[0]->getTestType();
1056e5c31af7Sopenharmony_ci	for (const auto& test : m_testDefinitions)
1057e5c31af7Sopenharmony_ci		DE_ASSERT(test->getTestType() == firstType);
1058e5c31af7Sopenharmony_ci#endif
1059e5c31af7Sopenharmony_ci	switch (m_testDefinitions[0]->getTestType())
1060e5c31af7Sopenharmony_ci	{
1061e5c31af7Sopenharmony_ci		case TEST_TYPE_H264_DECODE_INTERLEAVED:
1062e5c31af7Sopenharmony_ci		{
1063e5c31af7Sopenharmony_ci			context.requireDeviceFunctionality("VK_KHR_video_decode_h264");
1064e5c31af7Sopenharmony_ci			break;
1065e5c31af7Sopenharmony_ci		}
1066e5c31af7Sopenharmony_ci		case TEST_TYPE_H264_H265_DECODE_INTERLEAVED:
1067e5c31af7Sopenharmony_ci		{
1068e5c31af7Sopenharmony_ci			context.requireDeviceFunctionality("VK_KHR_video_decode_h264");
1069e5c31af7Sopenharmony_ci			context.requireDeviceFunctionality("VK_KHR_video_decode_h265");
1070e5c31af7Sopenharmony_ci			break;
1071e5c31af7Sopenharmony_ci		}
1072e5c31af7Sopenharmony_ci		default:
1073e5c31af7Sopenharmony_ci			TCU_THROW(InternalError, "Unknown interleaving test type");
1074e5c31af7Sopenharmony_ci	}
1075e5c31af7Sopenharmony_ci}
1076e5c31af7Sopenharmony_ci
1077e5c31af7Sopenharmony_ci} // namespace
1078e5c31af7Sopenharmony_ci
1079e5c31af7Sopenharmony_citcu::TestCaseGroup* createVideoDecodeTests(tcu::TestContext& testCtx)
1080e5c31af7Sopenharmony_ci{
1081e5c31af7Sopenharmony_ci	const deUint32				baseSeed = static_cast<deUint32>(testCtx.getCommandLine().getBaseSeed());
1082e5c31af7Sopenharmony_ci	MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "decode"));
1083e5c31af7Sopenharmony_ci
1084e5c31af7Sopenharmony_ci	for (const auto& decodeTest : g_DecodeTests)
1085e5c31af7Sopenharmony_ci	{
1086e5c31af7Sopenharmony_ci		auto		defn	 = TestDefinition::create(decodeTest, baseSeed);
1087e5c31af7Sopenharmony_ci
1088e5c31af7Sopenharmony_ci		const char* testName = getTestName(defn->getTestType());
1089e5c31af7Sopenharmony_ci		deUint32	rngSeed	 = baseSeed ^ deStringHash(testName);
1090e5c31af7Sopenharmony_ci		defn->updateHash(rngSeed);
1091e5c31af7Sopenharmony_ci		group->addChild(new VideoDecodeTestCase(testCtx, testName, defn));
1092e5c31af7Sopenharmony_ci	}
1093e5c31af7Sopenharmony_ci
1094e5c31af7Sopenharmony_ci	for (const auto& interleavingTest : g_InterleavingTests)
1095e5c31af7Sopenharmony_ci	{
1096e5c31af7Sopenharmony_ci		const char*							 testName = getTestName(interleavingTest.type);
1097e5c31af7Sopenharmony_ci		std::vector<MovePtr<TestDefinition>> defns;
1098e5c31af7Sopenharmony_ci		DecodeTestParam						 streamA{interleavingTest.type, interleavingTest.streamA};
1099e5c31af7Sopenharmony_ci		defns.push_back(TestDefinition::create(streamA, baseSeed));
1100e5c31af7Sopenharmony_ci		DecodeTestParam streamB{interleavingTest.type, interleavingTest.streamB};
1101e5c31af7Sopenharmony_ci		defns.push_back(TestDefinition::create(streamB, baseSeed));
1102e5c31af7Sopenharmony_ci		group->addChild(new InterleavingDecodeTestCase(testCtx, testName, std::move(defns)));
1103e5c31af7Sopenharmony_ci	}
1104e5c31af7Sopenharmony_ci
1105e5c31af7Sopenharmony_ci	return group.release();
1106e5c31af7Sopenharmony_ci}
1107e5c31af7Sopenharmony_ci
1108e5c31af7Sopenharmony_ci} // namespace video
1109e5c31af7Sopenharmony_ci} // namespace vkt
1110