1/*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2020 The Khronos Group Inc.
6 * Copyright (c) 2020 Advanced Micro Devices, Inc.
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 *      http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 */
21/*!
22 * \file
23 * \brief Pipeline Cache Tests
24 */
25/*--------------------------------------------------------------------*/
26
27#include "vktPipelineCreationCacheControlTests.hpp"
28
29#include "deRandom.hpp"
30#include "deUniquePtr.hpp"
31#include "tcuStringTemplate.hpp"
32#include "vkDeviceUtil.hpp"
33#include "vkRefUtil.hpp"
34#include "vktConstexprVectorUtil.hpp"
35#include "vktTestCase.hpp"
36#include "vktTestCaseUtil.hpp"
37
38#include <chrono>
39#include <random>
40#include <string>
41#include <vector>
42
43namespace vkt
44{
45namespace pipeline
46{
47namespace
48{
49using namespace vk;
50
51using tcu::StringTemplate;
52using tcu::TestCaseGroup;
53using tcu::TestContext;
54using tcu::TestStatus;
55
56using ::std::array;
57using ::std::string;
58using ::std::vector;
59
60/*--------------------------------------------------------------------*//*!
61 * Elements common to all test types
62 *//*--------------------------------------------------------------------*/
63namespace test_common
64{
65using ::std::chrono::high_resolution_clock;
66using ::std::chrono::microseconds;
67
68using duration			 = high_resolution_clock::duration;
69using UniquePipeline	 = Move<VkPipeline>;
70using UniqueShaderModule = Move<VkShaderModule>;
71
72/*--------------------------------------------------------------------*//*!
73 * \brief Paired Vulkan API result with elapsed duration
74 *//*--------------------------------------------------------------------*/
75struct TimedResult
76{
77	VkResult result;
78	duration elapsed;
79};
80
81/*--------------------------------------------------------------------*//*!
82 * \brief Validation function type output from vkCreate*Pipelines()
83 *
84 * \param result - VkResult returned from API call
85 * \param pipeliens - vector of pipelines created
86 * \param elapsed - high_resolution_clock::duration of time elapsed in API
87 * \param reason - output string to give the reason for failure
88 *
89 * \return QP_TEST_RESULT_PASS on success QP_TEST_RESULT_FAIL otherwise
90 *//*--------------------------------------------------------------------*/
91using Validator = qpTestResult (*)(VkResult, const vector<UniquePipeline>&, duration, string&);
92
93static constexpr size_t VALIDATOR_ARRAY_MAX = 4;
94using ValidatorArray						= ConstexprVector<Validator, VALIDATOR_ARRAY_MAX>;
95
96/*--------------------------------------------------------------------*//*!
97 * \brief Run a loop of validation tests and return the result
98 *//*--------------------------------------------------------------------*/
99template <typename pipelines_t, qpTestResult FAIL_RESULT = QP_TEST_RESULT_FAIL>
100TestStatus validateResults(VkResult				 result,
101						   const pipelines_t&	 pipelines,
102						   duration				 elapsed,
103						   const ValidatorArray& validators)
104{
105	using de::contains;
106	static constexpr VkResult ALLOWED_RESULTS[] = {VK_SUCCESS, VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT};
107
108	string reason;
109
110	if (contains(DE_ARRAY_BEGIN(ALLOWED_RESULTS), DE_ARRAY_END(ALLOWED_RESULTS), result) == DE_FALSE)
111	{
112		static const StringTemplate ERROR_MSG = {"Pipeline creation returned an error result: ${0}"};
113		TCU_THROW(InternalError, ERROR_MSG.format(result).c_str());
114	}
115
116	for (const auto& validator : validators)
117	{
118		const auto qpResult = validator(result, pipelines, elapsed, reason);
119		if (qpResult != QP_TEST_RESULT_PASS)
120		{
121			return {qpResult, reason};
122		}
123	}
124
125	return TestStatus::pass("Test passed.");
126}
127
128/*--------------------------------------------------------------------*//*!
129 * \brief Generate an error if result does not match VK_RESULT
130 *//*--------------------------------------------------------------------*/
131template <VkResult VK_RESULT, qpTestResult FAIL_RESULT = QP_TEST_RESULT_FAIL>
132qpTestResult checkResult(VkResult result, const vector<UniquePipeline>&, duration, string& reason)
133{
134	if (VK_RESULT != result)
135	{
136		static const StringTemplate ERROR_MSG = {"Got ${0}, Expected ${1}"};
137		reason								  = ERROR_MSG.format(result, VK_RESULT);
138		return FAIL_RESULT;
139	}
140
141	return QP_TEST_RESULT_PASS;
142}
143
144/*--------------------------------------------------------------------*//*!
145 * \brief Generate an error if pipeline[INDEX] is not valid
146 *//*--------------------------------------------------------------------*/
147template <size_t INDEX, qpTestResult FAIL_RESULT = QP_TEST_RESULT_FAIL>
148qpTestResult checkPipelineMustBeValid(VkResult, const vector<UniquePipeline>& pipelines, duration, string& reason)
149{
150	if (pipelines.size() <= INDEX)
151	{
152		static const StringTemplate ERROR_MSG = {"Index ${0} is not in created pipelines (pipelines.size(): ${1})"};
153		TCU_THROW(TestError, ERROR_MSG.format(INDEX, pipelines.size()));
154	}
155
156	if (*pipelines[INDEX] == VK_NULL_HANDLE)
157	{
158		static const StringTemplate ERROR_MSG = {"pipelines[${0}] is not a valid VkPipeline object"};
159		reason								  = ERROR_MSG.format(INDEX);
160		return FAIL_RESULT;
161	}
162
163	return QP_TEST_RESULT_PASS;
164}
165
166/*--------------------------------------------------------------------*//*!
167 * \brief Generate an error if pipeline[INDEX] is not VK_NULL_HANDLE
168 *//*--------------------------------------------------------------------*/
169template <size_t INDEX, qpTestResult FAIL_RESULT = QP_TEST_RESULT_FAIL>
170qpTestResult checkPipelineMustBeNull(VkResult, const vector<UniquePipeline>& pipelines, duration, string& reason)
171{
172	if (pipelines.size() <= INDEX)
173	{
174		static const StringTemplate ERROR_MSG = {"Index ${0} is not in created pipelines (pipelines.size(): ${1})"};
175		TCU_THROW(TestError, ERROR_MSG.format(INDEX, pipelines.size()));
176	}
177
178	if (*pipelines[INDEX] != VK_NULL_HANDLE)
179	{
180		static const StringTemplate ERROR_MSG = {"pipelines[${0}] is not VK_NULL_HANDLE"};
181		reason								  = ERROR_MSG.format(INDEX);
182		return FAIL_RESULT;
183	}
184
185	return QP_TEST_RESULT_PASS;
186}
187
188/*--------------------------------------------------------------------*//*!
189 * \brief Generate an error if any pipeline is valid after an early-return failure
190 *//*--------------------------------------------------------------------*/
191template <size_t INDEX, qpTestResult FAIL_RESULT = QP_TEST_RESULT_FAIL>
192qpTestResult checkPipelineNullAfterIndex(VkResult, const vector<UniquePipeline>& pipelines, duration, string& reason)
193{
194	if (pipelines.size() <= INDEX)
195	{
196		static const StringTemplate ERROR_MSG = {"Index ${0} is not in created pipelines (pipelines.size(): ${1})"};
197		TCU_THROW(TestError, ERROR_MSG.format(INDEX, pipelines.size()));
198	}
199
200	if (pipelines.size() - 1 == INDEX)
201	{
202		static const StringTemplate ERROR_MSG = {"Index ${0} is the last pipeline, likely a malformed test case"};
203		TCU_THROW(TestError, ERROR_MSG.format(INDEX));
204	}
205
206	// Only have to iterate through if the requested index is null
207	if (*pipelines[INDEX] == VK_NULL_HANDLE)
208	{
209		for (size_t i = INDEX + 1; i < pipelines.size(); ++i)
210		{
211			if (*pipelines[i] != VK_NULL_HANDLE)
212			{
213				static const StringTemplate ERROR_MSG = {
214					"pipelines[${0}] is not VK_NULL_HANDLE after a explicit early return index"};
215				reason = ERROR_MSG.format(i);
216				return FAIL_RESULT;
217			}
218		}
219	}
220
221	return QP_TEST_RESULT_PASS;
222}
223
224/*--------------------------------------------------------------------*//*!
225 * Time limit constants
226 *//*--------------------------------------------------------------------*/
227enum ElapsedTime
228{
229	ELAPSED_TIME_INFINITE  = microseconds{-1}.count(),
230	ELAPSED_TIME_IMMEDIATE = microseconds{500}.count(),
231	ELAPSED_TIME_FAST	   = microseconds{1000}.count()
232};
233
234/*--------------------------------------------------------------------*//*!
235 * \brief Generate an error if elapsed time exceeds MAX_TIME
236 *//*--------------------------------------------------------------------*/
237template <ElapsedTime MAX_TIME, qpTestResult FAIL_RESULT = QP_TEST_RESULT_FAIL>
238qpTestResult checkElapsedTime(VkResult, const vector<UniquePipeline>&, duration elapsed, string& reason)
239{
240#if defined(DE_DEBUG)
241	DE_UNREF(elapsed);
242	DE_UNREF(reason);
243
244	// In debug mode timing is not likely to be accurate
245	return QP_TEST_RESULT_PASS;
246#else
247
248	using ::std::chrono::duration_cast;
249
250	static constexpr microseconds ALLOWED_TIME = microseconds{MAX_TIME};
251
252	if (elapsed > ALLOWED_TIME)
253	{
254		static const StringTemplate ERROR_MSG = {"pipeline creation took longer than ${0}us (actual time: ${1}us)"};
255		reason = ERROR_MSG.format(ALLOWED_TIME.count(), duration_cast<microseconds>(elapsed).count());
256		return FAIL_RESULT;
257	}
258
259	return QP_TEST_RESULT_PASS;
260#endif
261}
262
263/*--------------------------------------------------------------------*//*!
264 * \brief Test case parameters
265 *//*--------------------------------------------------------------------*/
266struct TestParams
267{
268	enum CacheType
269	{
270		NO_CACHE = 0,
271		EXPLICIT_CACHE,
272		DERIVATIVE_HANDLE,
273		DERIVATIVE_INDEX
274	};
275
276	struct Iteration
277	{
278		static constexpr size_t MAX_VARIANTS = 4;
279		using Variant						 = VkPipelineCreateFlags;
280		using VariantArray					 = ConstexprVector<Variant, MAX_VARIANTS>;
281
282		static constexpr Variant NORMAL		  = 0;
283		static constexpr Variant NO_COMPILE	  = VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_EXT;
284		static constexpr Variant EARLY_RETURN = NO_COMPILE | VK_PIPELINE_CREATE_EARLY_RETURN_ON_FAILURE_BIT_EXT;
285
286		static constexpr VariantArray SINGLE_NORMAL						= VariantArray{NORMAL};
287		static constexpr VariantArray SINGLE_NOCOMPILE					= VariantArray{NO_COMPILE};
288		static constexpr VariantArray BATCH_NOCOMPILE_COMPILE_NOCOMPILE = VariantArray{NO_COMPILE, NORMAL, NO_COMPILE};
289		static constexpr VariantArray BATCH_RETURN_COMPILE_NOCOMPILE = VariantArray{EARLY_RETURN, NORMAL, NO_COMPILE};
290
291		inline constexpr Iteration() : variants{}, validators{} {}
292		inline constexpr Iteration(const VariantArray& v, const ValidatorArray& f) : variants{v}, validators{f} {}
293
294		VariantArray   variants;
295		ValidatorArray validators;
296	};
297
298	static constexpr size_t MAX_ITERATIONS = 4;
299	using IterationArray				   = ConstexprVector<Iteration, MAX_ITERATIONS>;
300
301	const char*		name;
302	CacheType		cacheType;
303	IterationArray	iterations;
304	bool			useMaintenance5;
305};
306
307/*--------------------------------------------------------------------*//*!
308 * \brief Verify extension and feature support
309 *//*--------------------------------------------------------------------*/
310void checkSupport(Context& context, const TestParams& params)
311{
312	static constexpr char EXT_NAME[] = "VK_EXT_pipeline_creation_cache_control";
313	if (!context.requireDeviceFunctionality(EXT_NAME))
314	{
315		TCU_THROW(NotSupportedError, "Extension 'VK_EXT_pipeline_creation_cache_control' is not supported");
316	}
317
318	const auto features = context.getPipelineCreationCacheControlFeatures();
319	if (features.pipelineCreationCacheControl == DE_FALSE)
320	{
321		TCU_THROW(NotSupportedError, "Feature 'pipelineCreationCacheControl' is not enabled");
322	}
323
324	if (params.useMaintenance5)
325		context.requireDeviceFunctionality("VK_KHR_maintenance5");
326}
327
328/*--------------------------------------------------------------------*//*!
329 * \brief Generate a random floating point number as a string
330 *//*--------------------------------------------------------------------*/
331float randomFloat()
332{
333#if !defined(DE_DEBUG)
334	static de::Random state = {::std::random_device{}()};
335#else
336	static de::Random state = {0xDEADBEEF};
337#endif
338
339	return state.getFloat();
340}
341
342/*--------------------------------------------------------------------*//*!
343 * \brief Get a string of VkResults from a vector
344 *//*--------------------------------------------------------------------*/
345string getResultsString(const vector<VkResult>& results)
346{
347	using ::std::ostringstream;
348
349	ostringstream output;
350
351	output << "results[" << results.size() << "]={ ";
352
353	if (!results.empty())
354	{
355		output << results[0];
356	}
357
358	for (size_t i = 1; i < results.size(); ++i)
359	{
360		output << ", " << results[i];
361	}
362
363	output << " }";
364
365	return output.str();
366}
367
368/*--------------------------------------------------------------------*//*!
369 * \brief Cast a pointer to an the expected SPIRV type
370 *//*--------------------------------------------------------------------*/
371template <typename _t>
372inline const deUint32* shader_cast(const _t* ptr)
373{
374	return reinterpret_cast<const deUint32*>(ptr);
375}
376
377/*--------------------------------------------------------------------*//*!
378 * \brief Capture a container of Vulkan handles into Move<> types
379 *//*--------------------------------------------------------------------*/
380template <typename input_container_t,
381		  typename handle_t	 = typename input_container_t::value_type,
382		  typename move_t	 = Move<handle_t>,
383		  typename deleter_t = Deleter<handle_t>,
384		  typename output_t	 = vector<move_t>>
385output_t wrapHandles(const DeviceInterface&		  vk,
386					 VkDevice					  device,
387					 const input_container_t&	  input,
388					 const VkAllocationCallbacks* allocator = DE_NULL)
389{
390	using ::std::begin;
391	using ::std::end;
392	using ::std::transform;
393
394	auto output = output_t{};
395	output.resize(input.size());
396
397	struct Predicate
398	{
399		deleter_t deleter;
400		move_t	  operator()(handle_t v)
401		{
402			return (v != VK_NULL_HANDLE) ? move_t{check(v), deleter} : move_t{};
403		}
404	};
405
406	const auto wrapHandle = Predicate{deleter_t{vk, device, allocator}};
407
408	transform(begin(input), end(input), begin(output), wrapHandle);
409
410	return output;
411}
412
413/*--------------------------------------------------------------------*//*!
414 * \brief create vkPipelineCache for test params
415 *//*--------------------------------------------------------------------*/
416Move<VkPipelineCache> createPipelineCache(const DeviceInterface& vk, VkDevice device, const TestParams& params)
417{
418	if (params.cacheType != TestParams::EXPLICIT_CACHE)
419	{
420		return {};
421	}
422
423	static constexpr auto cacheInfo = VkPipelineCacheCreateInfo{
424		VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, //sType
425		DE_NULL,									  //pNext
426		VkPipelineCacheCreateFlags{},				  //flags
427		deUintptr{0},								  //initialDataSize
428		DE_NULL										  //pInitialData
429	};
430
431	return createPipelineCache(vk, device, &cacheInfo);
432}
433
434/*--------------------------------------------------------------------*//*!
435 * \brief create VkPipelineLayout with descriptor sets from test parameters
436 *//*--------------------------------------------------------------------*/
437Move<VkPipelineLayout> createPipelineLayout(const DeviceInterface&				 vk,
438											VkDevice							 device,
439											const vector<VkDescriptorSetLayout>& setLayouts,
440											const TestParams&)
441{
442	const auto layoutCreateInfo = VkPipelineLayoutCreateInfo{
443		VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // sType
444		DE_NULL,									   // pNext
445		VkPipelineLayoutCreateFlags{},				   // flags
446		static_cast<deUint32>(setLayouts.size()),	   // setLayoutCount
447		setLayouts.data(),							   // pSetLayouts
448		deUint32{0u},								   // pushConstantRangeCount
449		DE_NULL,									   // pPushConstantRanges
450	};
451
452	return createPipelineLayout(vk, device, &layoutCreateInfo);
453}
454
455/*--------------------------------------------------------------------*//*!
456 * \brief create basic VkPipelineLayout from test parameters
457 *//*--------------------------------------------------------------------*/
458Move<VkPipelineLayout> createPipelineLayout(const DeviceInterface& vk, VkDevice device, const TestParams&)
459{
460	static constexpr auto layoutCreateInfo = VkPipelineLayoutCreateInfo{
461		VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // sType
462		DE_NULL,									   // pNext
463		VkPipelineLayoutCreateFlags{},				   // flags
464		deUint32{0u},								   // setLayoutCount
465		DE_NULL,									   // pSetLayouts
466		deUint32{0u},								   // pushConstantRangeCount
467		DE_NULL,									   // pPushConstantRanges
468	};
469
470	return createPipelineLayout(vk, device, &layoutCreateInfo);
471}
472
473/*--------------------------------------------------------------------*//*!
474 * \brief Create array of shader modules
475 *//*--------------------------------------------------------------------*/
476vector<UniqueShaderModule> createShaderModules(const DeviceInterface&	  vk,
477											   VkDevice					  device,
478											   const BinaryCollection&	  collection,
479											   const vector<const char*>& names)
480{
481	auto output = vector<UniqueShaderModule>{};
482	output.reserve(names.size());
483
484	for (const auto& name : names)
485	{
486		const auto& binary	   = collection.get(name);
487		const auto	createInfo = VkShaderModuleCreateInfo{
488			 VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, // sType
489			 DE_NULL,									  // pNext
490			 VkShaderModuleCreateFlags{},				  // flags
491			 binary.getSize(),							  // codeSize
492			 shader_cast(binary.getBinary())			  // pCode
493		 };
494
495		output.push_back(createShaderModule(vk, device, &createInfo));
496	}
497
498	return output;
499}
500
501/*--------------------------------------------------------------------*//*!
502 * \brief Create array of shader binding stages
503 *//*--------------------------------------------------------------------*/
504vector<VkPipelineShaderStageCreateInfo> createShaderStages(const vector<Move<VkShaderModule>>&	modules,
505														   const vector<VkShaderStageFlagBits>& stages)
506{
507	DE_ASSERT(modules.size() == stages.size());
508
509	auto output = vector<VkPipelineShaderStageCreateInfo>{};
510	output.reserve(modules.size());
511
512	int i = 0;
513
514	for (const auto& module : modules)
515	{
516		const auto stageInfo = VkPipelineShaderStageCreateInfo{
517			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // sType
518			DE_NULL,											 // pNext
519			VkPipelineShaderStageCreateFlags{},					 // flags
520			stages[i++],										 // stage
521			*module,											 // module
522			"main",												 // pName
523			DE_NULL												 // pSpecializationInfo
524		};
525
526		output.push_back(stageInfo);
527	}
528
529	return output;
530}
531
532} // namespace test_common
533
534/*--------------------------------------------------------------------*//*!
535 * \brief Graphics pipeline specific testing
536 *//*--------------------------------------------------------------------*/
537namespace graphics_tests
538{
539using namespace test_common;
540
541/*--------------------------------------------------------------------*//*!
542 * \brief Common graphics pipeline create info initialization
543 *//*--------------------------------------------------------------------*/
544VkGraphicsPipelineCreateInfo getPipelineCreateInfoCommon()
545{
546	static constexpr auto VERTEX_BINDING = VkVertexInputBindingDescription{
547		deUint32{0u},				// binding
548		sizeof(float[4]),			// stride
549		VK_VERTEX_INPUT_RATE_VERTEX // inputRate
550	};
551
552	static constexpr auto VERTEX_ATTRIBUTE = VkVertexInputAttributeDescription{
553		deUint32{0u},				   // location
554		deUint32{0u},				   // binding
555		VK_FORMAT_R32G32B32A32_SFLOAT, // format
556		deUint32{0u}				   // offset
557	};
558
559	static constexpr auto VERTEX_INPUT_STATE = VkPipelineVertexInputStateCreateInfo{
560		VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // sType
561		DE_NULL,												   // pNext
562		VkPipelineVertexInputStateCreateFlags{},				   // flags
563		deUint32{1u},											   // vertexBindingDescriptionCount
564		&VERTEX_BINDING,										   // pVertexBindingDescriptions
565		deUint32{1u},											   // vertexAttributeDescriptionCount
566		&VERTEX_ATTRIBUTE										   // pVertexAttributeDescriptions
567	};
568
569	static constexpr auto IA_STATE = VkPipelineInputAssemblyStateCreateInfo{
570		VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // sType
571		DE_NULL,													 // pNext
572		VkPipelineInputAssemblyStateCreateFlags{},					 // flags
573		VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,						 // topology
574		VK_TRUE														 // primitiveRestartEnable
575	};
576
577	static constexpr auto TESSALATION_STATE = VkPipelineTessellationStateCreateInfo{
578		VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO, // sType
579		DE_NULL,																 // pNext
580		VkPipelineTessellationStateCreateFlags{},								 // flags
581		deUint32{0u}															 // patchControlPoints
582	};
583
584	static constexpr auto VIEWPORT = VkViewport{
585		0.f, // x
586		0.f, // y
587		1.f, // width
588		1.f, // height
589		0.f, // minDepth
590		1.f	 // maxDept
591	};
592
593	static constexpr auto SCISSOR_RECT = VkRect2D{
594		{0, 0},	   // offset
595		{256, 256} // extent
596	};
597
598	static constexpr auto VIEWPORT_STATE = VkPipelineViewportStateCreateInfo{
599		VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // sType
600		DE_NULL,											   // pNext
601		VkPipelineViewportStateCreateFlags{},				   // flags
602		deUint32{1u},										   // viewportCount
603		&VIEWPORT,											   // pViewports
604		deUint32{1u},										   // scissorCount
605		&SCISSOR_RECT										   // pScissors
606	};
607
608	static constexpr auto RASTERIZATION_STATE = VkPipelineRasterizationStateCreateInfo{
609		VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // sType
610		DE_NULL,													// pNext
611		VkPipelineRasterizationStateCreateFlags{},					// flags
612		VK_FALSE,													// depthClampEnable
613		VK_TRUE,													// rasterizerDiscardEnable
614		VK_POLYGON_MODE_FILL,										// polygonMode
615		VK_CULL_MODE_NONE,											// cullMode
616		VK_FRONT_FACE_CLOCKWISE,									// frontFace
617		VK_FALSE,													// depthBiasEnable
618		0.f,														// depthBiasConstantFactor
619		0.f,														// depthBiasClamp
620		0.f,														// depthBiasSlopeFactor
621		1.f															// lineWidth
622	};
623
624	static constexpr auto SAMPLE_MASK = VkSampleMask{};
625
626	static constexpr auto MULTISAMPLE_STATE = VkPipelineMultisampleStateCreateInfo{
627		VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // sType
628		DE_NULL,												  // pNext
629		VkPipelineMultisampleStateCreateFlags{},				  // flags
630		VK_SAMPLE_COUNT_1_BIT,									  // rasterizationSamples
631		VK_FALSE,												  // sampleShadingEnable
632		0.f,													  // minSampleShading
633		&SAMPLE_MASK,											  // pSampleMask
634		VK_FALSE,												  // alphaToCoverageEnable
635		VK_FALSE												  // alphaToOneEnable
636	};
637
638	static constexpr auto STENCIL_OP_STATE = VkStencilOpState{
639		VK_STENCIL_OP_ZERO,	  // failOp
640		VK_STENCIL_OP_ZERO,	  // passOp
641		VK_STENCIL_OP_ZERO,	  // depthFailOp
642		VK_COMPARE_OP_ALWAYS, // compareOp
643		deUint32{0u},		  // compareMask
644		deUint32{0u},		  // writeMask
645		deUint32{0u}		  // reference
646	};
647
648	static constexpr auto DEPTH_STENCIL_STATE = VkPipelineDepthStencilStateCreateInfo{
649		VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // sType
650		DE_NULL,													// pNext
651		VkPipelineDepthStencilStateCreateFlags{},					// flags
652		VK_FALSE,													// depthTestEnable
653		VK_FALSE,													// depthWriteEnable
654		VK_COMPARE_OP_ALWAYS,										// depthCompareOp
655		VK_FALSE,													// depthBoundsTestEnable
656		VK_FALSE,													// stencilTestEnable
657		STENCIL_OP_STATE,											// front
658		STENCIL_OP_STATE,											// back
659		0.f,														// minDepthBounds
660		1.f															// maxDepthBounds
661	};
662
663	static constexpr auto COLOR_FLAGS_ALL = VkColorComponentFlags{VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
664																  VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT};
665
666	static constexpr auto COLOR_BLEND_ATTACH_STATE = VkPipelineColorBlendAttachmentState{
667		VK_FALSE,			  // blendEnable
668		VK_BLEND_FACTOR_ONE,  // srcColorBlendFactor
669		VK_BLEND_FACTOR_ZERO, // dstColorBlendFactor
670		VK_BLEND_OP_ADD,	  // colorBlendOp
671		VK_BLEND_FACTOR_ONE,  // srcAlphaBlendFactor
672		VK_BLEND_FACTOR_ZERO, // dstAlphaBlendFactor
673		VK_BLEND_OP_ADD,	  // alphaBlendOp
674		COLOR_FLAGS_ALL		  // colorWriteMask
675	};
676
677	static constexpr auto COLOR_BLEND_STATE = VkPipelineColorBlendStateCreateInfo{
678		VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // sType
679		DE_NULL,												  // pNext
680		VkPipelineColorBlendStateCreateFlags{},					  // flags
681		VK_FALSE,												  // logicOpEnable
682		VK_LOGIC_OP_SET,										  // logicOp
683		deUint32{1u},											  // attachmentCount
684		&COLOR_BLEND_ATTACH_STATE,								  // pAttachments
685		{0.f, 0.f, 0.f, 0.f}									  // blendConstants[4]
686	};
687
688	static constexpr auto DYNAMIC_STATE = VkPipelineDynamicStateCreateInfo{
689		VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // sType;
690		DE_NULL,											  // pNext;
691		VkPipelineDynamicStateCreateFlags{},				  // flags;
692		deUint32{0u},										  // dynamicStateCount;
693		DE_NULL												  // pDynamicStates;
694	};
695
696	return VkGraphicsPipelineCreateInfo{
697		VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // sType
698		DE_NULL,										 // pNext
699		VkPipelineCreateFlags{},						 // flags
700		deUint32{0u},									 // stageCount
701		DE_NULL,										 // pStages
702		&VERTEX_INPUT_STATE,							 // pVertexInputState
703		&IA_STATE,										 // pInputAssemblyState
704		&TESSALATION_STATE,								 // pTessellationState
705		&VIEWPORT_STATE,								 // pViewportState
706		&RASTERIZATION_STATE,							 // pRasterizationState
707		&MULTISAMPLE_STATE,								 // pMultisampleState
708		&DEPTH_STENCIL_STATE,							 // pDepthStencilState
709		&COLOR_BLEND_STATE,								 // pColorBlendState
710		&DYNAMIC_STATE,									 // pDynamicState
711		VK_NULL_HANDLE,									 // layout
712		VK_NULL_HANDLE,									 // renderPass
713		deUint32{0u},									 // subpass
714		VK_NULL_HANDLE,									 // basePipelineHandle
715		deInt32{-1}										 // basePipelineIndex
716	};
717}
718
719/*--------------------------------------------------------------------*//*!
720 * \brief create VkGraphicsPipelineCreateInfo structs from test iteration
721 *//*--------------------------------------------------------------------*/
722vector<VkGraphicsPipelineCreateInfo> createPipelineCreateInfos(const TestParams::Iteration&		   iteration,
723															   const VkGraphicsPipelineCreateInfo& base,
724															   VkPipeline						   basePipeline,
725															   const TestParams&				   testParameter)
726{
727	auto output = vector<VkGraphicsPipelineCreateInfo>{};
728	output.reserve(iteration.variants.size());
729
730	deInt32 count			  = 0;
731	deInt32 basePipelineIndex = -1;
732
733	for (VkPipelineCreateFlags flags : iteration.variants)
734	{
735		const auto curIndex	  = count++;
736		auto	   createInfo = base;
737
738		if (testParameter.cacheType == TestParams::DERIVATIVE_INDEX)
739		{
740			if (flags & VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_EXT)
741			{
742				if (basePipelineIndex != -1)
743				{
744					flags |= VK_PIPELINE_CREATE_DERIVATIVE_BIT;
745				}
746			}
747			else
748			{
749				flags |= VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT;
750
751				if (basePipelineIndex == -1)
752				{
753					basePipelineIndex = curIndex;
754				}
755			}
756		}
757
758		createInfo.flags			  = flags;
759		createInfo.basePipelineHandle = basePipeline;
760		createInfo.basePipelineIndex  = basePipelineIndex;
761
762		output.push_back(createInfo);
763	}
764
765	return output;
766}
767
768/*--------------------------------------------------------------------*//*!
769 * \brief create VkRenderPass object for Graphics test
770 *//*--------------------------------------------------------------------*/
771Move<VkRenderPass> createRenderPass(const DeviceInterface& vk, VkDevice device, const TestParams&)
772{
773	static constexpr auto COLOR_FORMAT = VK_FORMAT_R8G8B8A8_UNORM;
774
775	static constexpr auto COLOR_ATTACHMENT_REF = VkAttachmentReference{
776		deUint32{0u},							 // attachment
777		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // layout
778	};
779
780	static constexpr auto SUBPASS = VkSubpassDescription{
781		VkSubpassDescriptionFlags{},	 // flags
782		VK_PIPELINE_BIND_POINT_GRAPHICS, // pipelineBindPoint
783		deUint32{0u},					 // inputAttachmentCount
784		DE_NULL,						 // pInputAttachments
785		deUint32{1u},					 // colorAttachmentCount
786		&COLOR_ATTACHMENT_REF,			 // pColorAttachments
787		DE_NULL,						 // pResolveAttachments
788		DE_NULL,						 // pDepthStencilAttachment
789		deUint32{0u},					 // preserveAttachmentCount
790		DE_NULL							 // pPreserveAttachments
791	};
792
793	static constexpr auto COLOR_ATTACHMENT = VkAttachmentDescription{
794		VkAttachmentDescriptionFlags{},	  // flags
795		COLOR_FORMAT,					  // format
796		VK_SAMPLE_COUNT_1_BIT,			  // samples
797		VK_ATTACHMENT_LOAD_OP_CLEAR,	  // loadOp
798		VK_ATTACHMENT_STORE_OP_STORE,	  // storeOp
799		VK_ATTACHMENT_LOAD_OP_DONT_CARE,  // stencilLoadOp
800		VK_ATTACHMENT_STORE_OP_DONT_CARE, // stencilStoreOp
801		VK_IMAGE_LAYOUT_UNDEFINED,		  // initialLayout
802		VK_IMAGE_LAYOUT_PRESENT_SRC_KHR	  // finalLayout
803	};
804
805	static constexpr auto RENDER_PASS_CREATE_INFO = VkRenderPassCreateInfo{
806		VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // sType
807		DE_NULL,								   // pNext
808		VkRenderPassCreateFlags{},				   // flags
809		deUint32{1u},							   // attachmentCount
810		&COLOR_ATTACHMENT,						   // pAttachments
811		deUint32{1u},							   // subpassCount
812		&SUBPASS,								   // pSubpasses
813		deUint32{0u},							   // dependencyCount
814		DE_NULL									   // pDependencies
815	};
816
817	return createRenderPass(vk, device, &RENDER_PASS_CREATE_INFO);
818}
819
820/*--------------------------------------------------------------------*//*!
821 * \brief Initialize shader programs
822 *//*--------------------------------------------------------------------*/
823void initPrograms(SourceCollections& dst, const TestParams&)
824{
825	using ::glu::FragmentSource;
826	using ::glu::VertexSource;
827
828	// Vertex Shader
829	static const StringTemplate VS_TEXT = {"#version 310 es\n"
830										   "layout(location = 0) in vec4 position;\n"
831										   "layout(location = 0) out vec3 vertColor;\n"
832										   "void main (void)\n"
833										   "{\n"
834										   "  gl_Position = position;\n"
835										   "  vertColor = vec3(${0}, ${1}, ${2});\n"
836										   "}\n"};
837
838	// Fragment Shader
839	static const StringTemplate FS_TEXT = {"#version 310 es\n"
840										   "precision highp float;\n"
841										   "layout(location = 0) in vec3 vertColor;\n"
842										   "layout(location = 0) out vec4 outColor;\n"
843										   "void main (void)\n"
844										   "{\n"
845										   "  const vec3 fragColor = vec3(${0}, ${1}, ${2});\n"
846										   "  outColor = vec4((fragColor + vertColor) * 0.5, 1.0);\n"
847										   "}\n"};
848
849	dst.glslSources.add("vertex") << VertexSource{VS_TEXT.format(randomFloat(), randomFloat(), randomFloat())};
850	dst.glslSources.add("fragment") << FragmentSource{FS_TEXT.format(randomFloat(), randomFloat(), randomFloat())};
851}
852
853/*--------------------------------------------------------------------*//*!
854 * \brief return both result and elapsed time from pipeline creation
855 *//*--------------------------------------------------------------------*/
856template <typename create_infos_t, typename pipelines_t>
857TimedResult timePipelineCreation(const DeviceInterface&		  vk,
858								 const VkDevice				  device,
859								 const VkPipelineCache		  cache,
860								 const create_infos_t&		  createInfos,
861								 pipelines_t&				  pipelines,
862								 const VkAllocationCallbacks* pAllocator = DE_NULL)
863{
864	DE_ASSERT(createInfos.size() <= pipelines.size());
865
866	const auto timeStart = high_resolution_clock::now();
867	const auto result	 = vk.createGraphicsPipelines(
868		   device, cache, static_cast<deUint32>(createInfos.size()), createInfos.data(), pAllocator, pipelines.data());
869	const auto elapsed = high_resolution_clock::now() - timeStart;
870	return {result, elapsed};
871}
872
873/*--------------------------------------------------------------------*//*!
874 * \brief Test instance function
875 *//*--------------------------------------------------------------------*/
876TestStatus testInstance(Context& context, const TestParams& testParameter)
877{
878	const auto& vk			  = context.getDeviceInterface();
879	const auto	device		  = context.getDevice();
880	const auto	pipelineCache = createPipelineCache(vk, device, testParameter);
881	const auto	layout		  = createPipelineLayout(vk, device, testParameter);
882	const auto	renderPass	  = createRenderPass(vk, device, testParameter);
883	// No fragment due to rasterizationDiscardEnabled
884	const auto	modules		  = createShaderModules(vk, device, context.getBinaryCollection(), std::vector<const char*>{"vertex"});
885	const auto	shaderStages  = createShaderStages(modules, std::vector<VkShaderStageFlagBits>{VK_SHADER_STAGE_VERTEX_BIT});
886
887	// Placeholder for base pipeline if using cacheType == DERIVATIVE_HANDLE
888	auto basePipeline = UniquePipeline{};
889
890	auto baseCreateInfo		  = getPipelineCreateInfoCommon();
891	baseCreateInfo.layout	  = layout.get();
892	baseCreateInfo.renderPass = renderPass.get();
893	baseCreateInfo.stageCount = static_cast<deUint32>(shaderStages.size());
894	baseCreateInfo.pStages	  = shaderStages.data();
895
896	auto results = vector<VkResult>{};
897	results.reserve(testParameter.iterations.size());
898
899	for (const auto& i : testParameter.iterations)
900	{
901		auto createInfos	= createPipelineCreateInfos(i, baseCreateInfo, basePipeline.get(), testParameter);
902		auto created		= vector<VkPipeline>{};
903		created.resize(createInfos.size());
904
905#ifndef CTS_USES_VULKANSC
906		std::vector<VkPipelineCreateFlags2CreateInfoKHR> flags2CreateInfo(created.size(), { VK_STRUCTURE_TYPE_PIPELINE_CREATE_FLAGS_2_CREATE_INFO_KHR, 0, 0 });
907		if (testParameter.useMaintenance5)
908		{
909			for (deUint32 ci = 0; ci < createInfos.size(); ++ci)
910			{
911				flags2CreateInfo[ci].flags	= translateCreateFlag(createInfos[ci].flags);
912				flags2CreateInfo[ci].pNext  = createInfos[ci].pNext;
913				createInfos[ci].flags		= 0;
914				createInfos[ci].pNext		= &flags2CreateInfo[ci];
915			}
916		}
917#endif // CTS_USES_VULKANSC
918
919		const auto timedResult = timePipelineCreation(vk, device, pipelineCache.get(), createInfos, created);
920		auto	   pipelines   = wrapHandles(vk, device, created);
921
922		const auto status = validateResults(timedResult.result, pipelines, timedResult.elapsed, i.validators);
923		if (status.getCode() != QP_TEST_RESULT_PASS)
924		{
925			return status;
926		}
927
928		if ((testParameter.cacheType == TestParams::DERIVATIVE_HANDLE) && (*basePipeline == VK_NULL_HANDLE))
929		{
930			for (auto& pipeline : pipelines)
931			{
932				if (*pipeline != VK_NULL_HANDLE)
933				{
934					basePipeline = pipeline;
935					break;
936				}
937			}
938		}
939
940		results.push_back(timedResult.result);
941	}
942
943	static const StringTemplate PASS_MSG = {"Test Passed. ${0}"};
944	return TestStatus::pass(PASS_MSG.format(getResultsString(results)));
945}
946
947} // namespace graphics_tests
948
949/*--------------------------------------------------------------------*//*!
950 * \brief Compute pipeline specific testing
951 *//*--------------------------------------------------------------------*/
952namespace compute_tests
953{
954using namespace test_common;
955
956/*--------------------------------------------------------------------*//*!
957 * \brief create VkComputePipelineCreateInfo structs from test iteration
958 *//*--------------------------------------------------------------------*/
959vector<VkComputePipelineCreateInfo> createPipelineCreateInfos(const TestParams::Iteration&		 iteration,
960															  const VkComputePipelineCreateInfo& base,
961															  VkPipeline						 basePipeline,
962															  const TestParams&					 testParameter)
963{
964	auto output = vector<VkComputePipelineCreateInfo>{};
965	output.reserve(iteration.variants.size());
966
967	deInt32 count			  = 0;
968	deInt32 basePipelineIndex = -1;
969
970	for (VkPipelineCreateFlags flags : iteration.variants)
971	{
972		const auto curIndex	  = count++;
973		auto	   createInfo = base;
974
975		if (testParameter.cacheType == TestParams::DERIVATIVE_INDEX)
976		{
977			if (flags & VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_EXT)
978			{
979				if (basePipelineIndex != -1)
980				{
981					flags |= VK_PIPELINE_CREATE_DERIVATIVE_BIT;
982				}
983			}
984			else
985			{
986				flags |= VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT;
987
988				if (basePipelineIndex == -1)
989				{
990					basePipelineIndex = curIndex;
991				}
992			}
993		}
994
995		createInfo.flags			  = flags;
996		createInfo.basePipelineHandle = basePipeline;
997		createInfo.basePipelineIndex  = basePipelineIndex;
998
999		output.push_back(createInfo);
1000	}
1001
1002	return output;
1003}
1004
1005/*--------------------------------------------------------------------*//*!
1006 * \brief create compute descriptor set layout
1007 *//*--------------------------------------------------------------------*/
1008Move<VkDescriptorSetLayout> createDescriptorSetLayout(const DeviceInterface& vk, VkDevice device, const TestParams&)
1009{
1010	static constexpr auto DESCRIPTOR_SET_LAYOUT_BINDING = VkDescriptorSetLayoutBinding{
1011		deUint32{0u},					   // binding
1012		VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, // descriptorType
1013		deUint32{1u},					   // descriptorCount
1014		VK_SHADER_STAGE_COMPUTE_BIT,	   // stageFlags
1015		DE_NULL							   // pImmutableSamplers
1016	};
1017
1018	static constexpr auto DESCRIPTOR_SET_LAYOUT_CREATE_INFO = VkDescriptorSetLayoutCreateInfo{
1019		VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, // sType
1020		DE_NULL,											 // pNext
1021		VkDescriptorSetLayoutCreateFlags{},					 // flags
1022		deUint32{1u},										 // bindingCount
1023		&DESCRIPTOR_SET_LAYOUT_BINDING						 // pBindings
1024	};
1025
1026	return createDescriptorSetLayout(vk, device, &DESCRIPTOR_SET_LAYOUT_CREATE_INFO);
1027}
1028
1029/*--------------------------------------------------------------------*//*!
1030 * \brief Initialize shader programs
1031 *//*--------------------------------------------------------------------*/
1032void initPrograms(SourceCollections& dst, const TestParams&)
1033{
1034	using ::glu::ComputeSource;
1035
1036	static const StringTemplate CS_TEXT = {"#version 450\n"
1037										   "precision highp float;\n"
1038										   "layout (local_size_x = 64, local_size_y = 1, local_size_z = 1) in;\n"
1039										   "layout (std140, binding = 0) buffer buf { vec3 data[]; };\n"
1040										   "void main (void)\n"
1041										   "{\n"
1042										   "  data[gl_GlobalInvocationID.x] = vec3(${0}, ${1}, ${2});\n"
1043										   "}\n"};
1044
1045	dst.glslSources.add("compute")
1046		<< ComputeSource{CS_TEXT.format(randomFloat(), randomFloat(), randomFloat())};
1047}
1048
1049/*--------------------------------------------------------------------*//*!
1050 * \brief return both result and elapsed time from pipeline creation
1051 *//*--------------------------------------------------------------------*/
1052template <typename create_infos_t, typename pipelines_t>
1053TimedResult timePipelineCreation(const DeviceInterface&		  vk,
1054								 const VkDevice				  device,
1055								 const VkPipelineCache		  cache,
1056								 const create_infos_t&		  createInfos,
1057								 pipelines_t&				  pipelines,
1058								 const VkAllocationCallbacks* pAllocator = DE_NULL)
1059{
1060	DE_ASSERT(createInfos.size() <= pipelines.size());
1061
1062	const auto timeStart = high_resolution_clock::now();
1063	const auto result	 = vk.createComputePipelines(
1064		   device, cache, static_cast<deUint32>(createInfos.size()), createInfos.data(), pAllocator, pipelines.data());
1065	const auto elapsed = high_resolution_clock::now() - timeStart;
1066	return {result, elapsed};
1067}
1068
1069/*--------------------------------------------------------------------*//*!
1070 * \brief Test instance function
1071 *//*--------------------------------------------------------------------*/
1072TestStatus testInstance(Context& context, const TestParams& testParameter)
1073{
1074	const auto& vk					= context.getDeviceInterface();
1075	const auto	device				= context.getDevice();
1076	const auto	pipelineCache		= createPipelineCache(vk, device, testParameter);
1077	const auto	descriptorSetLayout = createDescriptorSetLayout(vk, device, testParameter);
1078	const auto	pipelineLayout		= createPipelineLayout(vk, device, {descriptorSetLayout.get()}, testParameter);
1079	const auto	modules				= createShaderModules(vk, device, context.getBinaryCollection(), {"compute"});
1080	const auto	shaderStages		= createShaderStages(modules, {VK_SHADER_STAGE_COMPUTE_BIT});
1081
1082	// Placeholder for base pipeline if using cacheType == DERIVATIVE_HANDLE
1083	auto basePipeline = UniquePipeline{};
1084
1085	const auto baseCreateInfo = VkComputePipelineCreateInfo{
1086		VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, // sType
1087		DE_NULL,										// pNext
1088		VkPipelineCreateFlags{},						// flags
1089		shaderStages[0],								// stage
1090		pipelineLayout.get(),							// layout
1091		VK_NULL_HANDLE,									// basePipelineHandle
1092		deInt32{-1}										// basePipelineIndex
1093	};
1094
1095	auto results = vector<VkResult>{};
1096	results.reserve(testParameter.iterations.size());
1097
1098	for (const auto& i : testParameter.iterations)
1099	{
1100		const auto createInfos = createPipelineCreateInfos(i, baseCreateInfo, basePipeline.get(), testParameter);
1101		auto	   created	   = vector<VkPipeline>{};
1102		created.resize(createInfos.size());
1103
1104		const auto timedResult = timePipelineCreation(vk, device, pipelineCache.get(), createInfos, created);
1105		auto	   pipelines   = wrapHandles(vk, device, created);
1106
1107		const auto status = validateResults(timedResult.result, pipelines, timedResult.elapsed, i.validators);
1108		if (status.getCode() != QP_TEST_RESULT_PASS)
1109		{
1110			return status;
1111		}
1112
1113		if ((testParameter.cacheType == TestParams::DERIVATIVE_HANDLE) && (*basePipeline == VK_NULL_HANDLE))
1114		{
1115			for (auto& pipeline : pipelines)
1116			{
1117				if (*pipeline != VK_NULL_HANDLE)
1118				{
1119					basePipeline = pipeline;
1120					break;
1121				}
1122			}
1123		}
1124
1125		results.push_back(timedResult.result);
1126	}
1127
1128	static const StringTemplate PASS_MSG = {"Test Passed. ${0}"};
1129	return TestStatus::pass(PASS_MSG.format(getResultsString(results)));
1130}
1131
1132} // namespace compute_tests
1133
1134using namespace test_common;
1135
1136/*--------------------------------------------------------------------*//*!
1137 * \brief Duplicate single pipeline recreation with explicit caching
1138 *//*--------------------------------------------------------------------*/
1139static constexpr TestParams DUPLICATE_SINGLE_RECREATE_EXPLICIT_CACHING =
1140{
1141	"duplicate_single_recreate_explicit_caching",
1142	TestParams::EXPLICIT_CACHE,
1143	TestParams::IterationArray
1144	{
1145		TestParams::Iteration{
1146			// Iteration [0]: Force compilation of pipeline
1147			TestParams::Iteration::SINGLE_NORMAL,
1148			ValidatorArray{
1149				// Fail if result is not VK_SUCCESS
1150				checkResult<VK_SUCCESS>,
1151				// Fail if pipeline is not valid
1152				checkPipelineMustBeValid<0>
1153			}
1154		},
1155		TestParams::Iteration{
1156			// Iteration [1]: Request compilation of same pipeline without compile
1157			TestParams::Iteration::SINGLE_NOCOMPILE,
1158			ValidatorArray{
1159				// Warn if result is not VK_SUCCESS
1160				checkResult<VK_SUCCESS, QP_TEST_RESULT_COMPATIBILITY_WARNING>,
1161				// Warn if pipeline is not valid
1162				checkPipelineMustBeValid<0, QP_TEST_RESULT_COMPATIBILITY_WARNING>,
1163				// Warn if pipeline took too long
1164				checkElapsedTime<ELAPSED_TIME_FAST, QP_TEST_RESULT_QUALITY_WARNING>
1165			}
1166		}
1167	},
1168	false
1169};
1170
1171/*--------------------------------------------------------------------*//*!
1172 * \brief Duplicate single pipeline recreation with no explicit cache
1173 *//*--------------------------------------------------------------------*/
1174static constexpr TestParams DUPLICATE_SINGLE_RECREATE_NO_CACHING =
1175{
1176	"duplicate_single_recreate_no_caching",
1177	TestParams::NO_CACHE,
1178	TestParams::IterationArray{
1179		TestParams::Iteration{
1180			// Iteration [0]: Force compilation of pipeline
1181			TestParams::Iteration::SINGLE_NORMAL,
1182			ValidatorArray{
1183				// Fail if result is not VK_SUCCESS
1184				checkResult<VK_SUCCESS>,
1185				// Fail if pipeline is not valid
1186				checkPipelineMustBeValid<0>
1187			}
1188		},
1189		TestParams::Iteration{
1190			// Iteration [1]: Request compilation of same pipeline without compile
1191			TestParams::Iteration::SINGLE_NOCOMPILE,
1192			ValidatorArray{
1193				// Warn if pipeline took too long
1194				checkElapsedTime<ELAPSED_TIME_FAST, QP_TEST_RESULT_QUALITY_WARNING>
1195			}
1196		}
1197	},
1198	false
1199};
1200
1201/*--------------------------------------------------------------------*//*!
1202 * \brief Duplicate single pipeline recreation using derivative pipelines
1203 *//*--------------------------------------------------------------------*/
1204static constexpr TestParams DUPLICATE_SINGLE_RECREATE_DERIVATIVE =
1205{
1206	"duplicate_single_recreate_derivative",
1207	TestParams::DERIVATIVE_HANDLE,
1208	TestParams::IterationArray{
1209		TestParams::Iteration{
1210			// Iteration [0]: Force compilation of pipeline
1211			TestParams::Iteration::SINGLE_NORMAL,
1212			ValidatorArray{
1213				// Fail if result is not VK_SUCCESS
1214				checkResult<VK_SUCCESS>,
1215				// Fail if pipeline is not valid
1216				checkPipelineMustBeValid<0>
1217				}
1218			},
1219		TestParams::Iteration{
1220			// Iteration [1]: Request compilation of same pipeline without compile
1221			TestParams::Iteration::SINGLE_NOCOMPILE,
1222			ValidatorArray{
1223				// Warn if pipeline took too long
1224				checkElapsedTime<ELAPSED_TIME_FAST, QP_TEST_RESULT_QUALITY_WARNING>
1225			}
1226		}
1227	},
1228	false
1229};
1230
1231/*--------------------------------------------------------------------*//*!
1232 * \brief Single creation of never before seen pipeline without compile
1233 *//*--------------------------------------------------------------------*/
1234static constexpr TestParams SINGLE_PIPELINE_NO_COMPILE =
1235{
1236	"single_pipeline_no_compile",
1237	TestParams::NO_CACHE,
1238	TestParams::IterationArray{
1239		TestParams::Iteration{
1240			TestParams::Iteration::SINGLE_NOCOMPILE,
1241			ValidatorArray{
1242				// Warn if pipeline took too long
1243				checkElapsedTime<ELAPSED_TIME_IMMEDIATE, QP_TEST_RESULT_QUALITY_WARNING>
1244			}
1245		}
1246	},
1247	false
1248};
1249
1250/*--------------------------------------------------------------------*//*!
1251 * \brief Batch creation of duplicate pipelines with explicit caching
1252 *//*--------------------------------------------------------------------*/
1253static constexpr TestParams DUPLICATE_BATCH_PIPELINES_EXPLICIT_CACHE =
1254{
1255	"duplicate_batch_pipelines_explicit_cache",
1256	TestParams::EXPLICIT_CACHE,
1257	TestParams::IterationArray{
1258		TestParams::Iteration{
1259			TestParams::Iteration::BATCH_NOCOMPILE_COMPILE_NOCOMPILE,
1260			ValidatorArray{
1261				// Fail if pipeline[1] is not valid
1262				checkPipelineMustBeValid<1>,
1263				// Warn if result is not VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT
1264				checkResult<VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT, QP_TEST_RESULT_COMPATIBILITY_WARNING>,
1265				// Warn if pipelines[0] is not VK_NULL_HANDLE
1266				checkPipelineMustBeNull<0, QP_TEST_RESULT_COMPATIBILITY_WARNING>,
1267				// Warn if pipelines[2] is not valid
1268				checkPipelineMustBeValid<2, QP_TEST_RESULT_COMPATIBILITY_WARNING>
1269			}
1270		}
1271	},
1272	false
1273};
1274
1275/*--------------------------------------------------------------------*//*!
1276 * \brief Batch creation of duplicate pipelines with no caching
1277 *//*--------------------------------------------------------------------*/
1278static constexpr TestParams DUPLICATE_BATCH_PIPELINES_NO_CACHE =
1279{
1280	"duplicate_batch_pipelines_no_cache",
1281	TestParams::NO_CACHE,
1282	TestParams::IterationArray{
1283		TestParams::Iteration{
1284			TestParams::Iteration::BATCH_NOCOMPILE_COMPILE_NOCOMPILE,
1285			ValidatorArray{
1286				// Fail if pipeline[1] is not valid
1287				checkPipelineMustBeValid<1>,
1288				// Warn if result is not VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT
1289				checkResult<VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT, QP_TEST_RESULT_COMPATIBILITY_WARNING>,
1290				// Warn if pipelines[0] is not VK_NULL_HANDLE
1291				checkPipelineMustBeNull<0, QP_TEST_RESULT_COMPATIBILITY_WARNING>
1292			}
1293		}
1294	},
1295	false
1296};
1297
1298/*--------------------------------------------------------------------*//*!
1299 * \brief Batch creation of duplicate pipelines with derivative pipeline index
1300 *//*--------------------------------------------------------------------*/
1301static constexpr TestParams DUPLICATE_BATCH_PIPELINES_DERIVATIVE_INDEX =
1302{
1303	"duplicate_batch_pipelines_derivative_index",
1304	TestParams::DERIVATIVE_INDEX,
1305	TestParams::IterationArray{
1306		TestParams::Iteration{
1307			TestParams::Iteration::BATCH_NOCOMPILE_COMPILE_NOCOMPILE,
1308			ValidatorArray{
1309				// Fail if pipeline[1] is not valid
1310				checkPipelineMustBeValid<1>,
1311				// Warn if result is not VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT
1312				checkResult<VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT, QP_TEST_RESULT_COMPATIBILITY_WARNING>,
1313				// Warn if pipelines[0] is not VK_NULL_HANDLE
1314				checkPipelineMustBeNull<0, QP_TEST_RESULT_COMPATIBILITY_WARNING>
1315			}
1316		}
1317	},
1318	false
1319};
1320
1321/*--------------------------------------------------------------------*//*!
1322 * \brief Batch creation of pipelines with early return
1323 *//*--------------------------------------------------------------------*/
1324static constexpr TestParams BATCH_PIPELINES_EARLY_RETURN =
1325{
1326	"batch_pipelines_early_return",
1327	TestParams::NO_CACHE,
1328	TestParams::IterationArray{
1329		TestParams::Iteration{
1330			TestParams::Iteration::BATCH_RETURN_COMPILE_NOCOMPILE,
1331			ValidatorArray{
1332				// fail if a valid pipeline follows the early-return failure
1333				checkPipelineNullAfterIndex<0>,
1334				// Warn if return was not immediate
1335				checkElapsedTime<ELAPSED_TIME_IMMEDIATE, QP_TEST_RESULT_QUALITY_WARNING>,
1336				// Warn if pipelines[0] is not VK_NULL_HANDLE
1337				checkPipelineMustBeNull<0, QP_TEST_RESULT_COMPATIBILITY_WARNING>,
1338				// Warn if result is not VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT
1339				checkResult<VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT, QP_TEST_RESULT_COMPATIBILITY_WARNING>
1340			}
1341		}
1342	},
1343	false
1344};
1345
1346/*--------------------------------------------------------------------*//*!
1347 * \brief Batch creation of pipelines with early return using VkPipelineCreateFlagBits2KHR from maintenance5
1348 *//*--------------------------------------------------------------------*/
1349static constexpr TestParams BATCH_PIPELINES_EARLY_RETURN_MAINTENANCE_5
1350{
1351	"batch_pipelines_early_return_maintenance5",
1352	TestParams::NO_CACHE,
1353	TestParams::IterationArray{
1354		TestParams::Iteration{
1355			TestParams::Iteration::BATCH_RETURN_COMPILE_NOCOMPILE,
1356			ValidatorArray{
1357				// fail if a valid pipeline follows the early-return failure
1358				checkPipelineNullAfterIndex<0>,
1359				// Warn if return was not immediate
1360				checkElapsedTime<ELAPSED_TIME_IMMEDIATE, QP_TEST_RESULT_QUALITY_WARNING>,
1361				// Warn if pipelines[0] is not VK_NULL_HANDLE
1362				checkPipelineMustBeNull<0, QP_TEST_RESULT_COMPATIBILITY_WARNING>,
1363				// Warn if result is not VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT
1364				checkResult<VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT, QP_TEST_RESULT_COMPATIBILITY_WARNING>
1365			}
1366		}
1367	},
1368	true,
1369};
1370
1371/*--------------------------------------------------------------------*//*!
1372 * \brief Full array of test cases
1373 *//*--------------------------------------------------------------------*/
1374static constexpr TestParams TEST_CASES[] =
1375{
1376	SINGLE_PIPELINE_NO_COMPILE,
1377	BATCH_PIPELINES_EARLY_RETURN,
1378	DUPLICATE_SINGLE_RECREATE_EXPLICIT_CACHING,
1379	DUPLICATE_SINGLE_RECREATE_NO_CACHING,
1380	DUPLICATE_SINGLE_RECREATE_DERIVATIVE,
1381	DUPLICATE_BATCH_PIPELINES_EXPLICIT_CACHE,
1382	DUPLICATE_BATCH_PIPELINES_NO_CACHE,
1383	DUPLICATE_BATCH_PIPELINES_DERIVATIVE_INDEX,
1384
1385#ifndef CTS_USES_VULKANSC
1386	BATCH_PIPELINES_EARLY_RETURN_MAINTENANCE_5,
1387#endif // CTS_USES_VULKANSC
1388
1389};
1390
1391/*--------------------------------------------------------------------*//*!
1392 * \brief Variadic version of de::newMovePtr
1393 *//*--------------------------------------------------------------------*/
1394template <typename T, typename... args_t>
1395inline de::MovePtr<T> newMovePtr(args_t&&... args)
1396{
1397	return de::MovePtr<T>(new T(::std::forward<args_t>(args)...));
1398}
1399
1400/*--------------------------------------------------------------------*//*!
1401 * \brief Make test group consisting of graphics pipeline tests
1402 *//*--------------------------------------------------------------------*/
1403void addGraphicsPipelineTests(TestCaseGroup& group)
1404{
1405	using namespace graphics_tests;
1406
1407	auto tests = newMovePtr<TestCaseGroup>(
1408		group.getTestContext(), "graphics_pipelines", "Test pipeline creation cache control with graphics pipelines");
1409
1410	for (const auto& params : TEST_CASES)
1411	{
1412		addFunctionCaseWithPrograms<const TestParams&>(
1413			tests.get(), params.name, checkSupport, initPrograms, testInstance, params);
1414	}
1415
1416	group.addChild(tests.release());
1417}
1418
1419/*--------------------------------------------------------------------*//*!
1420 * \brief Make test group consisting of compute pipeline tests
1421 *//*--------------------------------------------------------------------*/
1422void addComputePipelineTests(TestCaseGroup& group)
1423{
1424	using namespace compute_tests;
1425
1426	auto tests = newMovePtr<TestCaseGroup>(
1427		group.getTestContext(), "compute_pipelines", "Test pipeline creation cache control with compute pipelines");
1428
1429	for (const auto& params : TEST_CASES)
1430	{
1431		addFunctionCaseWithPrograms<const TestParams&>(
1432			tests.get(), params.name, checkSupport, initPrograms, testInstance, params);
1433	}
1434
1435	group.addChild(tests.release());
1436}
1437
1438} // namespace
1439
1440/*--------------------------------------------------------------------*//*!
1441 * \brief Make pipeline creation cache control test group
1442 *//*--------------------------------------------------------------------*/
1443TestCaseGroup* createCacheControlTests(TestContext& testCtx)
1444{
1445	auto tests = newMovePtr<TestCaseGroup>(testCtx, "creation_cache_control");
1446
1447	addGraphicsPipelineTests(*tests);
1448	addComputePipelineTests(*tests);
1449
1450	return tests.release();
1451}
1452
1453} // namespace pipeline
1454
1455} // namespace vkt
1456