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 
43 namespace vkt
44 {
45 namespace pipeline
46 {
47 namespace
48 {
49 using namespace vk;
50 
51 using tcu::StringTemplate;
52 using tcu::TestCaseGroup;
53 using tcu::TestContext;
54 using tcu::TestStatus;
55 
56 using ::std::array;
57 using ::std::string;
58 using ::std::vector;
59 
60 /*--------------------------------------------------------------------*//*!
61  * Elements common to all test types
62  *//*--------------------------------------------------------------------*/
63 namespace test_common
64 {
65 using ::std::chrono::high_resolution_clock;
66 using ::std::chrono::microseconds;
67 
68 using duration			 = high_resolution_clock::duration;
69 using UniquePipeline	 = Move<VkPipeline>;
70 using UniqueShaderModule = Move<VkShaderModule>;
71 
72 /*--------------------------------------------------------------------*//*!
73  * \brief Paired Vulkan API result with elapsed duration
74  *//*--------------------------------------------------------------------*/
75 struct 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  *//*--------------------------------------------------------------------*/
91 using Validator = qpTestResult (*)(VkResult, const vector<UniquePipeline>&, duration, string&);
92 
93 static constexpr size_t VALIDATOR_ARRAY_MAX = 4;
94 using ValidatorArray						= ConstexprVector<Validator, VALIDATOR_ARRAY_MAX>;
95 
96 /*--------------------------------------------------------------------*//*!
97  * \brief Run a loop of validation tests and return the result
98  *//*--------------------------------------------------------------------*/
99 template <typename pipelines_t, qpTestResult FAIL_RESULT = QP_TEST_RESULT_FAIL>
validateResults(VkResult result, const pipelines_t& pipelines, duration elapsed, const ValidatorArray& validators)100 TestStatus 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  *//*--------------------------------------------------------------------*/
131 template <VkResult VK_RESULT, qpTestResult FAIL_RESULT = QP_TEST_RESULT_FAIL>
checkResult(VkResult result, const vector<UniquePipeline>&, duration, string& reason)132 qpTestResult 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  *//*--------------------------------------------------------------------*/
147 template <size_t INDEX, qpTestResult FAIL_RESULT = QP_TEST_RESULT_FAIL>
checkPipelineMustBeValid(VkResult, const vector<UniquePipeline>& pipelines, duration, string& reason)148 qpTestResult 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  *//*--------------------------------------------------------------------*/
169 template <size_t INDEX, qpTestResult FAIL_RESULT = QP_TEST_RESULT_FAIL>
checkPipelineMustBeNull(VkResult, const vector<UniquePipeline>& pipelines, duration, string& reason)170 qpTestResult 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  *//*--------------------------------------------------------------------*/
191 template <size_t INDEX, qpTestResult FAIL_RESULT = QP_TEST_RESULT_FAIL>
checkPipelineNullAfterIndex(VkResult, const vector<UniquePipeline>& pipelines, duration, string& reason)192 qpTestResult 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  *//*--------------------------------------------------------------------*/
227 enum 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  *//*--------------------------------------------------------------------*/
237 template <ElapsedTime MAX_TIME, qpTestResult FAIL_RESULT = QP_TEST_RESULT_FAIL>
checkElapsedTime(VkResult, const vector<UniquePipeline>&, duration elapsed, string& reason)238 qpTestResult 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  *//*--------------------------------------------------------------------*/
266 struct 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 
Iterationvkt::pipeline::__anon28165::test_common::TestParams::Iteration291 		inline constexpr Iteration() : variants{}, validators{} {}
Iterationvkt::pipeline::__anon28165::test_common::TestParams::Iteration292 		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  *//*--------------------------------------------------------------------*/
checkSupport(Context& context, const TestParams& params)310 void 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  *//*--------------------------------------------------------------------*/
randomFloat()331 float 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  *//*--------------------------------------------------------------------*/
getResultsString(const vector<VkResult>& results)345 string 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  *//*--------------------------------------------------------------------*/
371 template <typename _t>
shader_cast(const _t* ptr)372 inline 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  *//*--------------------------------------------------------------------*/
380 template <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>>
wrapHandles(const DeviceInterface& vk, VkDevice device, const input_container_t& input, const VkAllocationCallbacks* allocator = DE_NULL)385 output_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  *//*--------------------------------------------------------------------*/
createPipelineCache(const DeviceInterface& vk, VkDevice device, const TestParams& params)416 Move<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  *//*--------------------------------------------------------------------*/
createPipelineLayout(const DeviceInterface& vk, VkDevice device, const vector<VkDescriptorSetLayout>& setLayouts, const TestParams&)437 Move<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  *//*--------------------------------------------------------------------*/
createPipelineLayout(const DeviceInterface& vk, VkDevice device, const TestParams&)458 Move<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  *//*--------------------------------------------------------------------*/
createShaderModules(const DeviceInterface& vk, VkDevice device, const BinaryCollection& collection, const vector<const char*>& names)476 vector<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  *//*--------------------------------------------------------------------*/
createShaderStages(const vector<Move<VkShaderModule>>& modules, const vector<VkShaderStageFlagBits>& stages)504 vector<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  *//*--------------------------------------------------------------------*/
537 namespace graphics_tests
538 {
539 using namespace test_common;
540 
541 /*--------------------------------------------------------------------*//*!
542  * \brief Common graphics pipeline create info initialization
543  *//*--------------------------------------------------------------------*/
getPipelineCreateInfoCommon()544 VkGraphicsPipelineCreateInfo 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  *//*--------------------------------------------------------------------*/
createPipelineCreateInfos(const TestParams::Iteration& iteration, const VkGraphicsPipelineCreateInfo& base, VkPipeline basePipeline, const TestParams& testParameter)722 vector<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  *//*--------------------------------------------------------------------*/
createRenderPass(const DeviceInterface& vk, VkDevice device, const TestParams&)771 Move<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  *//*--------------------------------------------------------------------*/
initPrograms(SourceCollections& dst, const TestParams&)823 void 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  *//*--------------------------------------------------------------------*/
856 template <typename create_infos_t, typename pipelines_t>
timePipelineCreation(const DeviceInterface& vk, const VkDevice device, const VkPipelineCache cache, const create_infos_t& createInfos, pipelines_t& pipelines, const VkAllocationCallbacks* pAllocator = DE_NULL)857 TimedResult 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  *//*--------------------------------------------------------------------*/
testInstance(Context& context, const TestParams& testParameter)876 TestStatus 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  *//*--------------------------------------------------------------------*/
952 namespace compute_tests
953 {
954 using namespace test_common;
955 
956 /*--------------------------------------------------------------------*//*!
957  * \brief create VkComputePipelineCreateInfo structs from test iteration
958  *//*--------------------------------------------------------------------*/
createPipelineCreateInfos(const TestParams::Iteration& iteration, const VkComputePipelineCreateInfo& base, VkPipeline basePipeline, const TestParams& testParameter)959 vector<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  *//*--------------------------------------------------------------------*/
createDescriptorSetLayout(const DeviceInterface& vk, VkDevice device, const TestParams&)1008 Move<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  *//*--------------------------------------------------------------------*/
initPrograms(SourceCollections& dst, const TestParams&)1032 void 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  *//*--------------------------------------------------------------------*/
1052 template <typename create_infos_t, typename pipelines_t>
timePipelineCreation(const DeviceInterface& vk, const VkDevice device, const VkPipelineCache cache, const create_infos_t& createInfos, pipelines_t& pipelines, const VkAllocationCallbacks* pAllocator = DE_NULL)1053 TimedResult 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  *//*--------------------------------------------------------------------*/
testInstance(Context& context, const TestParams& testParameter)1072 TestStatus 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 
1134 using namespace test_common;
1135 
1136 /*--------------------------------------------------------------------*//*!
1137  * \brief Duplicate single pipeline recreation with explicit caching
1138  *//*--------------------------------------------------------------------*/
1139 static 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  *//*--------------------------------------------------------------------*/
1174 static 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  *//*--------------------------------------------------------------------*/
1204 static 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  *//*--------------------------------------------------------------------*/
1234 static 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  *//*--------------------------------------------------------------------*/
1253 static 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  *//*--------------------------------------------------------------------*/
1278 static 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  *//*--------------------------------------------------------------------*/
1301 static 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  *//*--------------------------------------------------------------------*/
1324 static 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  *//*--------------------------------------------------------------------*/
1349 static 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  *//*--------------------------------------------------------------------*/
1374 static 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  *//*--------------------------------------------------------------------*/
1394 template <typename T, typename... args_t>
newMovePtr(args_t&&.... args)1395 inline 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  *//*--------------------------------------------------------------------*/
addGraphicsPipelineTests(TestCaseGroup& group)1403 void 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  *//*--------------------------------------------------------------------*/
addComputePipelineTests(TestCaseGroup& group)1422 void 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  *//*--------------------------------------------------------------------*/
createCacheControlTests(TestContext& testCtx)1443 TestCaseGroup* 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