• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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::__anon246767710111::test_common::TestParams::Iteration291 		inline constexpr Iteration() : variants{}, validators{} {}
Iterationvkt::pipeline::__anon246767710111::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 	const char*	   description;
303 	CacheType	   cacheType;
304 	IterationArray iterations;
305 };
306 
307 /*--------------------------------------------------------------------*//*!
308  * \brief Verify extension and feature support
309  *//*--------------------------------------------------------------------*/
checkSupport(Context & context,const TestParams &)310 void checkSupport(Context& context, const TestParams&)
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 
325 /*--------------------------------------------------------------------*//*!
326  * \brief Generate a random floating point number as a string
327  *//*--------------------------------------------------------------------*/
randomFloat()328 float randomFloat()
329 {
330 #if !defined(DE_DEBUG)
331 	static de::Random state = {::std::random_device{}()};
332 #else
333 	static de::Random state = {0xDEADBEEF};
334 #endif
335 
336 	return state.getFloat();
337 }
338 
339 /*--------------------------------------------------------------------*//*!
340  * \brief Get a string of VkResults from a vector
341  *//*--------------------------------------------------------------------*/
getResultsString(const vector<VkResult> & results)342 string getResultsString(const vector<VkResult>& results)
343 {
344 	using ::std::ostringstream;
345 
346 	ostringstream output;
347 
348 	output << "results[" << results.size() << "]={ ";
349 
350 	if (!results.empty())
351 	{
352 		output << results[0];
353 	}
354 
355 	for (size_t i = 1; i < results.size(); ++i)
356 	{
357 		output << ", " << results[i];
358 	}
359 
360 	output << " }";
361 
362 	return output.str();
363 }
364 
365 /*--------------------------------------------------------------------*//*!
366  * \brief Cast a pointer to an the expected SPIRV type
367  *//*--------------------------------------------------------------------*/
368 template <typename _t>
shader_cast(const _t * ptr)369 inline const deUint32* shader_cast(const _t* ptr)
370 {
371 	return reinterpret_cast<const deUint32*>(ptr);
372 }
373 
374 /*--------------------------------------------------------------------*//*!
375  * \brief Capture a container of Vulkan handles into Move<> types
376  *//*--------------------------------------------------------------------*/
377 template <typename input_container_t,
378 		  typename handle_t	 = typename input_container_t::value_type,
379 		  typename move_t	 = Move<handle_t>,
380 		  typename deleter_t = Deleter<handle_t>,
381 		  typename output_t	 = vector<move_t>>
wrapHandles(const DeviceInterface & vk,VkDevice device,const input_container_t & input,const VkAllocationCallbacks * allocator=DE_NULL)382 output_t wrapHandles(const DeviceInterface&		  vk,
383 					 VkDevice					  device,
384 					 const input_container_t&	  input,
385 					 const VkAllocationCallbacks* allocator = DE_NULL)
386 {
387 	using ::std::begin;
388 	using ::std::end;
389 	using ::std::transform;
390 
391 	auto output = output_t{};
392 	output.resize(input.size());
393 
394 	struct Predicate
395 	{
396 		deleter_t deleter;
397 		move_t	  operator()(handle_t v)
398 		{
399 			return (v != VK_NULL_HANDLE) ? move_t{check(v), deleter} : move_t{};
400 		}
401 	};
402 
403 	const auto wrapHandle = Predicate{deleter_t{vk, device, allocator}};
404 
405 	transform(begin(input), end(input), begin(output), wrapHandle);
406 
407 	return output;
408 }
409 
410 /*--------------------------------------------------------------------*//*!
411  * \brief create vkPipelineCache for test params
412  *//*--------------------------------------------------------------------*/
createPipelineCache(const DeviceInterface & vk,VkDevice device,const TestParams & params)413 Move<VkPipelineCache> createPipelineCache(const DeviceInterface& vk, VkDevice device, const TestParams& params)
414 {
415 	if (params.cacheType != TestParams::EXPLICIT_CACHE)
416 	{
417 		return {};
418 	}
419 
420 	static constexpr auto cacheInfo = VkPipelineCacheCreateInfo{
421 		VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, //sType
422 		DE_NULL,									  //pNext
423 		VkPipelineCacheCreateFlags{},				  //flags
424 		deUintptr{0},								  //initialDataSize
425 		DE_NULL										  //pInitialData
426 	};
427 
428 	return createPipelineCache(vk, device, &cacheInfo);
429 }
430 
431 /*--------------------------------------------------------------------*//*!
432  * \brief create VkPipelineLayout with descriptor sets from test parameters
433  *//*--------------------------------------------------------------------*/
createPipelineLayout(const DeviceInterface & vk,VkDevice device,const vector<VkDescriptorSetLayout> & setLayouts,const TestParams &)434 Move<VkPipelineLayout> createPipelineLayout(const DeviceInterface&				 vk,
435 											VkDevice							 device,
436 											const vector<VkDescriptorSetLayout>& setLayouts,
437 											const TestParams&)
438 {
439 	const auto layoutCreateInfo = VkPipelineLayoutCreateInfo{
440 		VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // sType
441 		DE_NULL,									   // pNext
442 		VkPipelineLayoutCreateFlags{},				   // flags
443 		static_cast<deUint32>(setLayouts.size()),	   // setLayoutCount
444 		setLayouts.data(),							   // pSetLayouts
445 		deUint32{0u},								   // pushConstantRangeCount
446 		DE_NULL,									   // pPushConstantRanges
447 	};
448 
449 	return createPipelineLayout(vk, device, &layoutCreateInfo);
450 }
451 
452 /*--------------------------------------------------------------------*//*!
453  * \brief create basic VkPipelineLayout from test parameters
454  *//*--------------------------------------------------------------------*/
createPipelineLayout(const DeviceInterface & vk,VkDevice device,const TestParams &)455 Move<VkPipelineLayout> createPipelineLayout(const DeviceInterface& vk, VkDevice device, const TestParams&)
456 {
457 	static constexpr auto layoutCreateInfo = VkPipelineLayoutCreateInfo{
458 		VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // sType
459 		DE_NULL,									   // pNext
460 		VkPipelineLayoutCreateFlags{},				   // flags
461 		deUint32{0u},								   // setLayoutCount
462 		DE_NULL,									   // pSetLayouts
463 		deUint32{0u},								   // pushConstantRangeCount
464 		DE_NULL,									   // pPushConstantRanges
465 	};
466 
467 	return createPipelineLayout(vk, device, &layoutCreateInfo);
468 }
469 
470 /*--------------------------------------------------------------------*//*!
471  * \brief Create array of shader modules
472  *//*--------------------------------------------------------------------*/
createShaderModules(const DeviceInterface & vk,VkDevice device,const BinaryCollection & collection,const vector<const char * > & names)473 vector<UniqueShaderModule> createShaderModules(const DeviceInterface&	  vk,
474 											   VkDevice					  device,
475 											   const BinaryCollection&	  collection,
476 											   const vector<const char*>& names)
477 {
478 	auto output = vector<UniqueShaderModule>{};
479 	output.reserve(names.size());
480 
481 	for (const auto& name : names)
482 	{
483 		const auto& binary	   = collection.get(name);
484 		const auto	createInfo = VkShaderModuleCreateInfo{
485 			 VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, // sType
486 			 DE_NULL,									  // pNext
487 			 VkShaderModuleCreateFlags{},				  // flags
488 			 binary.getSize(),							  // codeSize
489 			 shader_cast(binary.getBinary())			  // pCode
490 		 };
491 
492 		output.push_back(createShaderModule(vk, device, &createInfo));
493 	}
494 
495 	return output;
496 }
497 
498 /*--------------------------------------------------------------------*//*!
499  * \brief Create array of shader binding stages
500  *//*--------------------------------------------------------------------*/
createShaderStages(const vector<Move<VkShaderModule>> & modules,const vector<VkShaderStageFlagBits> & stages)501 vector<VkPipelineShaderStageCreateInfo> createShaderStages(const vector<Move<VkShaderModule>>&	modules,
502 														   const vector<VkShaderStageFlagBits>& stages)
503 {
504 	DE_ASSERT(modules.size() == stages.size());
505 
506 	auto output = vector<VkPipelineShaderStageCreateInfo>{};
507 	output.reserve(modules.size());
508 
509 	int i = 0;
510 
511 	for (const auto& module : modules)
512 	{
513 		const auto stageInfo = VkPipelineShaderStageCreateInfo{
514 			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // sType
515 			DE_NULL,											 // pNext
516 			VkPipelineShaderStageCreateFlags{},					 // flags
517 			stages[i++],										 // stage
518 			*module,											 // module
519 			"main",												 // pName
520 			DE_NULL												 // pSpecializationInfo
521 		};
522 
523 		output.push_back(stageInfo);
524 	}
525 
526 	return output;
527 }
528 
529 } // namespace test_common
530 
531 /*--------------------------------------------------------------------*//*!
532  * \brief Graphics pipeline specific testing
533  *//*--------------------------------------------------------------------*/
534 namespace graphics_tests
535 {
536 using namespace test_common;
537 
538 /*--------------------------------------------------------------------*//*!
539  * \brief Common graphics pipeline create info initialization
540  *//*--------------------------------------------------------------------*/
getPipelineCreateInfoCommon()541 VkGraphicsPipelineCreateInfo getPipelineCreateInfoCommon()
542 {
543 	static constexpr auto VERTEX_BINDING = VkVertexInputBindingDescription{
544 		deUint32{0u},				// binding
545 		sizeof(float[4]),			// stride
546 		VK_VERTEX_INPUT_RATE_VERTEX // inputRate
547 	};
548 
549 	static constexpr auto VERTEX_ATTRIBUTE = VkVertexInputAttributeDescription{
550 		deUint32{0u},				   // location
551 		deUint32{0u},				   // binding
552 		VK_FORMAT_R32G32B32A32_SFLOAT, // format
553 		deUint32{0u}				   // offset
554 	};
555 
556 	static constexpr auto VERTEX_INPUT_STATE = VkPipelineVertexInputStateCreateInfo{
557 		VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // sType
558 		DE_NULL,												   // pNext
559 		VkPipelineVertexInputStateCreateFlags{},				   // flags
560 		deUint32{1u},											   // vertexBindingDescriptionCount
561 		&VERTEX_BINDING,										   // pVertexBindingDescriptions
562 		deUint32{1u},											   // vertexAttributeDescriptionCount
563 		&VERTEX_ATTRIBUTE										   // pVertexAttributeDescriptions
564 	};
565 
566 	static constexpr auto IA_STATE = VkPipelineInputAssemblyStateCreateInfo{
567 		VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // sType
568 		DE_NULL,													 // pNext
569 		VkPipelineInputAssemblyStateCreateFlags{},					 // flags
570 		VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,						 // topology
571 		VK_TRUE														 // primitiveRestartEnable
572 	};
573 
574 	static constexpr auto TESSALATION_STATE = VkPipelineTessellationStateCreateInfo{
575 		VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO, // sType
576 		DE_NULL,																 // pNext
577 		VkPipelineTessellationStateCreateFlags{},								 // flags
578 		deUint32{0u}															 // patchControlPoints
579 	};
580 
581 	static constexpr auto VIEWPORT = VkViewport{
582 		0.f, // x
583 		0.f, // y
584 		1.f, // width
585 		1.f, // height
586 		0.f, // minDepth
587 		1.f	 // maxDept
588 	};
589 
590 	static constexpr auto SCISSOR_RECT = VkRect2D{
591 		{0, 0},	   // offset
592 		{256, 256} // extent
593 	};
594 
595 	static constexpr auto VIEWPORT_STATE = VkPipelineViewportStateCreateInfo{
596 		VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // sType
597 		DE_NULL,											   // pNext
598 		VkPipelineViewportStateCreateFlags{},				   // flags
599 		deUint32{1u},										   // viewportCount
600 		&VIEWPORT,											   // pViewports
601 		deUint32{1u},										   // scissorCount
602 		&SCISSOR_RECT										   // pScissors
603 	};
604 
605 	static constexpr auto RASTERIZATION_STATE = VkPipelineRasterizationStateCreateInfo{
606 		VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // sType
607 		DE_NULL,													// pNext
608 		VkPipelineRasterizationStateCreateFlags{},					// flags
609 		VK_FALSE,													// depthClampEnable
610 		VK_TRUE,													// rasterizerDiscardEnable
611 		VK_POLYGON_MODE_FILL,										// polygonMode
612 		VK_CULL_MODE_NONE,											// cullMode
613 		VK_FRONT_FACE_CLOCKWISE,									// frontFace
614 		VK_FALSE,													// depthBiasEnable
615 		0.f,														// depthBiasConstantFactor
616 		0.f,														// depthBiasClamp
617 		0.f,														// depthBiasSlopeFactor
618 		1.f															// lineWidth
619 	};
620 
621 	static constexpr auto SAMPLE_MASK = VkSampleMask{};
622 
623 	static constexpr auto MULTISAMPLE_STATE = VkPipelineMultisampleStateCreateInfo{
624 		VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // sType
625 		DE_NULL,												  // pNext
626 		VkPipelineMultisampleStateCreateFlags{},				  // flags
627 		VK_SAMPLE_COUNT_1_BIT,									  // rasterizationSamples
628 		VK_FALSE,												  // sampleShadingEnable
629 		0.f,													  // minSampleShading
630 		&SAMPLE_MASK,											  // pSampleMask
631 		VK_FALSE,												  // alphaToCoverageEnable
632 		VK_FALSE												  // alphaToOneEnable
633 	};
634 
635 	static constexpr auto STENCIL_OP_STATE = VkStencilOpState{
636 		VK_STENCIL_OP_ZERO,	  // failOp
637 		VK_STENCIL_OP_ZERO,	  // passOp
638 		VK_STENCIL_OP_ZERO,	  // depthFailOp
639 		VK_COMPARE_OP_ALWAYS, // compareOp
640 		deUint32{0u},		  // compareMask
641 		deUint32{0u},		  // writeMask
642 		deUint32{0u}		  // reference
643 	};
644 
645 	static constexpr auto DEPTH_STENCIL_STATE = VkPipelineDepthStencilStateCreateInfo{
646 		VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // sType
647 		DE_NULL,													// pNext
648 		VkPipelineDepthStencilStateCreateFlags{},					// flags
649 		VK_FALSE,													// depthTestEnable
650 		VK_FALSE,													// depthWriteEnable
651 		VK_COMPARE_OP_ALWAYS,										// depthCompareOp
652 		VK_FALSE,													// depthBoundsTestEnable
653 		VK_FALSE,													// stencilTestEnable
654 		STENCIL_OP_STATE,											// front
655 		STENCIL_OP_STATE,											// back
656 		0.f,														// minDepthBounds
657 		1.f															// maxDepthBounds
658 	};
659 
660 	static constexpr auto COLOR_FLAGS_ALL = VkColorComponentFlags{VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
661 																  VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT};
662 
663 	static constexpr auto COLOR_BLEND_ATTACH_STATE = VkPipelineColorBlendAttachmentState{
664 		VK_FALSE,			  // blendEnable
665 		VK_BLEND_FACTOR_ONE,  // srcColorBlendFactor
666 		VK_BLEND_FACTOR_ZERO, // dstColorBlendFactor
667 		VK_BLEND_OP_ADD,	  // colorBlendOp
668 		VK_BLEND_FACTOR_ONE,  // srcAlphaBlendFactor
669 		VK_BLEND_FACTOR_ZERO, // dstAlphaBlendFactor
670 		VK_BLEND_OP_ADD,	  // alphaBlendOp
671 		COLOR_FLAGS_ALL		  // colorWriteMask
672 	};
673 
674 	static constexpr auto COLOR_BLEND_STATE = VkPipelineColorBlendStateCreateInfo{
675 		VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // sType
676 		DE_NULL,												  // pNext
677 		VkPipelineColorBlendStateCreateFlags{},					  // flags
678 		VK_FALSE,												  // logicOpEnable
679 		VK_LOGIC_OP_SET,										  // logicOp
680 		deUint32{1u},											  // attachmentCount
681 		&COLOR_BLEND_ATTACH_STATE,								  // pAttachments
682 		{0.f, 0.f, 0.f, 0.f}									  // blendConstants[4]
683 	};
684 
685 	static constexpr auto DYNAMIC_STATE = VkPipelineDynamicStateCreateInfo{
686 		VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // sType;
687 		DE_NULL,											  // pNext;
688 		VkPipelineDynamicStateCreateFlags{},				  // flags;
689 		deUint32{0u},										  // dynamicStateCount;
690 		DE_NULL												  // pDynamicStates;
691 	};
692 
693 	return VkGraphicsPipelineCreateInfo{
694 		VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // sType
695 		DE_NULL,										 // pNext
696 		VkPipelineCreateFlags{},						 // flags
697 		deUint32{0u},									 // stageCount
698 		DE_NULL,										 // pStages
699 		&VERTEX_INPUT_STATE,							 // pVertexInputState
700 		&IA_STATE,										 // pInputAssemblyState
701 		&TESSALATION_STATE,								 // pTessellationState
702 		&VIEWPORT_STATE,								 // pViewportState
703 		&RASTERIZATION_STATE,							 // pRasterizationState
704 		&MULTISAMPLE_STATE,								 // pMultisampleState
705 		&DEPTH_STENCIL_STATE,							 // pDepthStencilState
706 		&COLOR_BLEND_STATE,								 // pColorBlendState
707 		&DYNAMIC_STATE,									 // pDynamicState
708 		VK_NULL_HANDLE,									 // layout
709 		VK_NULL_HANDLE,									 // renderPass
710 		deUint32{0u},									 // subpass
711 		VK_NULL_HANDLE,									 // basePipelineHandle
712 		deInt32{-1}										 // basePipelineIndex
713 	};
714 }
715 
716 /*--------------------------------------------------------------------*//*!
717  * \brief create VkGraphicsPipelineCreateInfo structs from test iteration
718  *//*--------------------------------------------------------------------*/
createPipelineCreateInfos(const TestParams::Iteration & iteration,const VkGraphicsPipelineCreateInfo & base,VkPipeline basePipeline,const TestParams & testParameter)719 vector<VkGraphicsPipelineCreateInfo> createPipelineCreateInfos(const TestParams::Iteration&		   iteration,
720 															   const VkGraphicsPipelineCreateInfo& base,
721 															   VkPipeline						   basePipeline,
722 															   const TestParams&				   testParameter)
723 {
724 	auto output = vector<VkGraphicsPipelineCreateInfo>{};
725 	output.reserve(iteration.variants.size());
726 
727 	deInt32 count			  = 0;
728 	deInt32 basePipelineIndex = -1;
729 
730 	for (VkPipelineCreateFlags flags : iteration.variants)
731 	{
732 		const auto curIndex	  = count++;
733 		auto	   createInfo = base;
734 
735 		if (testParameter.cacheType == TestParams::DERIVATIVE_INDEX)
736 		{
737 			if (flags & VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_EXT)
738 			{
739 				if (basePipelineIndex != -1)
740 				{
741 					flags |= VK_PIPELINE_CREATE_DERIVATIVE_BIT;
742 				}
743 			}
744 			else
745 			{
746 				flags |= VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT;
747 
748 				if (basePipelineIndex == -1)
749 				{
750 					basePipelineIndex = curIndex;
751 				}
752 			}
753 		}
754 
755 		createInfo.flags			  = flags;
756 		createInfo.basePipelineHandle = basePipeline;
757 		createInfo.basePipelineIndex  = basePipelineIndex;
758 
759 		output.push_back(createInfo);
760 	}
761 
762 	return output;
763 }
764 
765 /*--------------------------------------------------------------------*//*!
766  * \brief create VkRenderPass object for Graphics test
767  *//*--------------------------------------------------------------------*/
createRenderPass(const DeviceInterface & vk,VkDevice device,const TestParams &)768 Move<VkRenderPass> createRenderPass(const DeviceInterface& vk, VkDevice device, const TestParams&)
769 {
770 	static constexpr auto COLOR_FORMAT = VK_FORMAT_R8G8B8A8_UNORM;
771 
772 	static constexpr auto COLOR_ATTACHMENT_REF = VkAttachmentReference{
773 		deUint32{0u},							 // attachment
774 		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // layout
775 	};
776 
777 	static constexpr auto SUBPASS = VkSubpassDescription{
778 		VkSubpassDescriptionFlags{},	 // flags
779 		VK_PIPELINE_BIND_POINT_GRAPHICS, // pipelineBindPoint
780 		deUint32{0u},					 // inputAttachmentCount
781 		DE_NULL,						 // pInputAttachments
782 		deUint32{1u},					 // colorAttachmentCount
783 		&COLOR_ATTACHMENT_REF,			 // pColorAttachments
784 		DE_NULL,						 // pResolveAttachments
785 		DE_NULL,						 // pDepthStencilAttachment
786 		deUint32{0u},					 // preserveAttachmentCount
787 		DE_NULL							 // pPreserveAttachments
788 	};
789 
790 	static constexpr auto COLOR_ATTACHMENT = VkAttachmentDescription{
791 		VkAttachmentDescriptionFlags{},	  // flags
792 		COLOR_FORMAT,					  // format
793 		VK_SAMPLE_COUNT_1_BIT,			  // samples
794 		VK_ATTACHMENT_LOAD_OP_CLEAR,	  // loadOp
795 		VK_ATTACHMENT_STORE_OP_STORE,	  // storeOp
796 		VK_ATTACHMENT_LOAD_OP_DONT_CARE,  // stencilLoadOp
797 		VK_ATTACHMENT_STORE_OP_DONT_CARE, // stencilStoreOp
798 		VK_IMAGE_LAYOUT_UNDEFINED,		  // initialLayout
799 		VK_IMAGE_LAYOUT_PRESENT_SRC_KHR	  // finalLayout
800 	};
801 
802 	static constexpr auto RENDER_PASS_CREATE_INFO = VkRenderPassCreateInfo{
803 		VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // sType
804 		DE_NULL,								   // pNext
805 		VkRenderPassCreateFlags{},				   // flags
806 		deUint32{1u},							   // attachmentCount
807 		&COLOR_ATTACHMENT,						   // pAttachments
808 		deUint32{1u},							   // subpassCount
809 		&SUBPASS,								   // pSubpasses
810 		deUint32{0u},							   // dependencyCount
811 		DE_NULL									   // pDependencies
812 	};
813 
814 	return createRenderPass(vk, device, &RENDER_PASS_CREATE_INFO);
815 }
816 
817 /*--------------------------------------------------------------------*//*!
818  * \brief Initialize shader programs
819  *//*--------------------------------------------------------------------*/
initPrograms(SourceCollections & dst,const TestParams &)820 void initPrograms(SourceCollections& dst, const TestParams&)
821 {
822 	using ::glu::FragmentSource;
823 	using ::glu::VertexSource;
824 
825 	// Vertex Shader
826 	static const StringTemplate VS_TEXT = {"#version 310 es\n"
827 										   "layout(location = 0) in vec4 position;\n"
828 										   "layout(location = 0) out vec3 vertColor;\n"
829 										   "void main (void)\n"
830 										   "{\n"
831 										   "  gl_Position = position;\n"
832 										   "  vertColor = vec3(${0}, ${1}, ${2});\n"
833 										   "}\n"};
834 
835 	// Fragment Shader
836 	static const StringTemplate FS_TEXT = {"#version 310 es\n"
837 										   "precision highp float;\n"
838 										   "layout(location = 0) in vec3 vertColor;\n"
839 										   "layout(location = 0) out vec4 outColor;\n"
840 										   "void main (void)\n"
841 										   "{\n"
842 										   "  const vec3 fragColor = vec3(${0}, ${1}, ${2});\n"
843 										   "  outColor = vec4((fragColor + vertColor) * 0.5, 1.0);\n"
844 										   "}\n"};
845 
846 	dst.glslSources.add("vertex") << VertexSource{VS_TEXT.format(randomFloat(), randomFloat(), randomFloat())};
847 	dst.glslSources.add("fragment") << FragmentSource{FS_TEXT.format(randomFloat(), randomFloat(), randomFloat())};
848 }
849 
850 /*--------------------------------------------------------------------*//*!
851  * \brief return both result and elapsed time from pipeline creation
852  *//*--------------------------------------------------------------------*/
853 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)854 TimedResult timePipelineCreation(const DeviceInterface&		  vk,
855 								 const VkDevice				  device,
856 								 const VkPipelineCache		  cache,
857 								 const create_infos_t&		  createInfos,
858 								 pipelines_t&				  pipelines,
859 								 const VkAllocationCallbacks* pAllocator = DE_NULL)
860 {
861 	DE_ASSERT(createInfos.size() <= pipelines.size());
862 
863 	const auto timeStart = high_resolution_clock::now();
864 	const auto result	 = vk.createGraphicsPipelines(
865 		   device, cache, static_cast<deUint32>(createInfos.size()), createInfos.data(), pAllocator, pipelines.data());
866 	const auto elapsed = high_resolution_clock::now() - timeStart;
867 	return {result, elapsed};
868 }
869 
870 /*--------------------------------------------------------------------*//*!
871  * \brief Test instance function
872  *//*--------------------------------------------------------------------*/
testInstance(Context & context,const TestParams & testParameter)873 TestStatus testInstance(Context& context, const TestParams& testParameter)
874 {
875 	const auto& vk			  = context.getDeviceInterface();
876 	const auto	device		  = context.getDevice();
877 	const auto	pipelineCache = createPipelineCache(vk, device, testParameter);
878 	const auto	layout		  = createPipelineLayout(vk, device, testParameter);
879 	const auto	renderPass	  = createRenderPass(vk, device, testParameter);
880 	const auto	modules		  = createShaderModules(vk, device, context.getBinaryCollection(), {"vertex", "fragment"});
881 	const auto	shaderStages  = createShaderStages(modules, {VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_STAGE_FRAGMENT_BIT});
882 
883 	// Placeholder for base pipeline if using cacheType == DERIVATIVE_HANDLE
884 	auto basePipeline = UniquePipeline{};
885 
886 	auto baseCreateInfo		  = getPipelineCreateInfoCommon();
887 	baseCreateInfo.layout	  = layout.get();
888 	baseCreateInfo.renderPass = renderPass.get();
889 	baseCreateInfo.stageCount = static_cast<deUint32>(shaderStages.size());
890 	baseCreateInfo.pStages	  = shaderStages.data();
891 
892 	auto results = vector<VkResult>{};
893 	results.reserve(testParameter.iterations.size());
894 
895 	for (const auto& i : testParameter.iterations)
896 	{
897 		const auto createInfos = createPipelineCreateInfos(i, baseCreateInfo, basePipeline.get(), testParameter);
898 		auto	   created	   = vector<VkPipeline>{};
899 		created.resize(createInfos.size());
900 
901 		const auto timedResult = timePipelineCreation(vk, device, pipelineCache.get(), createInfos, created);
902 		auto	   pipelines   = wrapHandles(vk, device, created);
903 
904 		const auto status = validateResults(timedResult.result, pipelines, timedResult.elapsed, i.validators);
905 		if (status.getCode() != QP_TEST_RESULT_PASS)
906 		{
907 			return status;
908 		}
909 
910 		if ((testParameter.cacheType == TestParams::DERIVATIVE_HANDLE) && (*basePipeline == VK_NULL_HANDLE))
911 		{
912 			for (auto& pipeline : pipelines)
913 			{
914 				if (*pipeline != VK_NULL_HANDLE)
915 				{
916 					basePipeline = pipeline;
917 					break;
918 				}
919 			}
920 		}
921 
922 		results.push_back(timedResult.result);
923 	}
924 
925 	static const StringTemplate PASS_MSG = {"Test Passed. ${0}"};
926 	return TestStatus::pass(PASS_MSG.format(getResultsString(results)));
927 }
928 
929 } // namespace graphics_tests
930 
931 /*--------------------------------------------------------------------*//*!
932  * \brief Compute pipeline specific testing
933  *//*--------------------------------------------------------------------*/
934 namespace compute_tests
935 {
936 using namespace test_common;
937 
938 /*--------------------------------------------------------------------*//*!
939  * \brief create VkComputePipelineCreateInfo structs from test iteration
940  *//*--------------------------------------------------------------------*/
createPipelineCreateInfos(const TestParams::Iteration & iteration,const VkComputePipelineCreateInfo & base,VkPipeline basePipeline,const TestParams & testParameter)941 vector<VkComputePipelineCreateInfo> createPipelineCreateInfos(const TestParams::Iteration&		 iteration,
942 															  const VkComputePipelineCreateInfo& base,
943 															  VkPipeline						 basePipeline,
944 															  const TestParams&					 testParameter)
945 {
946 	auto output = vector<VkComputePipelineCreateInfo>{};
947 	output.reserve(iteration.variants.size());
948 
949 	deInt32 count			  = 0;
950 	deInt32 basePipelineIndex = -1;
951 
952 	for (VkPipelineCreateFlags flags : iteration.variants)
953 	{
954 		const auto curIndex	  = count++;
955 		auto	   createInfo = base;
956 
957 		if (testParameter.cacheType == TestParams::DERIVATIVE_INDEX)
958 		{
959 			if (flags & VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_EXT)
960 			{
961 				if (basePipelineIndex != -1)
962 				{
963 					flags |= VK_PIPELINE_CREATE_DERIVATIVE_BIT;
964 				}
965 			}
966 			else
967 			{
968 				flags |= VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT;
969 
970 				if (basePipelineIndex == -1)
971 				{
972 					basePipelineIndex = curIndex;
973 				}
974 			}
975 		}
976 
977 		createInfo.flags			  = flags;
978 		createInfo.basePipelineHandle = basePipeline;
979 		createInfo.basePipelineIndex  = basePipelineIndex;
980 
981 		output.push_back(createInfo);
982 	}
983 
984 	return output;
985 }
986 
987 /*--------------------------------------------------------------------*//*!
988  * \brief create compute descriptor set layout
989  *//*--------------------------------------------------------------------*/
createDescriptorSetLayout(const DeviceInterface & vk,VkDevice device,const TestParams &)990 Move<VkDescriptorSetLayout> createDescriptorSetLayout(const DeviceInterface& vk, VkDevice device, const TestParams&)
991 {
992 	static constexpr auto DESCRIPTOR_SET_LAYOUT_BINDING = VkDescriptorSetLayoutBinding{
993 		deUint32{0u},					   // binding
994 		VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, // descriptorType
995 		deUint32{1u},					   // descriptorCount
996 		VK_SHADER_STAGE_COMPUTE_BIT,	   // stageFlags
997 		DE_NULL							   // pImmutableSamplers
998 	};
999 
1000 	static constexpr auto DESCRIPTOR_SET_LAYOUT_CREATE_INFO = VkDescriptorSetLayoutCreateInfo{
1001 		VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, // sType
1002 		DE_NULL,											 // pNext
1003 		VkDescriptorSetLayoutCreateFlags{},					 // flags
1004 		deUint32{1u},										 // bindingCount
1005 		&DESCRIPTOR_SET_LAYOUT_BINDING						 // pBindings
1006 	};
1007 
1008 	return createDescriptorSetLayout(vk, device, &DESCRIPTOR_SET_LAYOUT_CREATE_INFO);
1009 }
1010 
1011 /*--------------------------------------------------------------------*//*!
1012  * \brief Initialize shader programs
1013  *//*--------------------------------------------------------------------*/
initPrograms(SourceCollections & dst,const TestParams &)1014 void initPrograms(SourceCollections& dst, const TestParams&)
1015 {
1016 	using ::glu::ComputeSource;
1017 
1018 	static const StringTemplate CS_TEXT = {"#version 450\n"
1019 										   "precision highp float;\n"
1020 										   "layout (local_size_x = 64, local_size_y = 1, local_size_z = 1) in;\n"
1021 										   "layout (std140, binding = 0) buffer buf { vec3 data[]; };\n"
1022 										   "void main (void)\n"
1023 										   "{\n"
1024 										   "  data[gl_GlobalInvocationID.x] = vec3(${0}, ${1}, ${2});\n"
1025 										   "}\n"};
1026 
1027 	dst.glslSources.add("compute")
1028 		<< ComputeSource{CS_TEXT.format(randomFloat(), randomFloat(), randomFloat())};
1029 }
1030 
1031 /*--------------------------------------------------------------------*//*!
1032  * \brief return both result and elapsed time from pipeline creation
1033  *//*--------------------------------------------------------------------*/
1034 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)1035 TimedResult timePipelineCreation(const DeviceInterface&		  vk,
1036 								 const VkDevice				  device,
1037 								 const VkPipelineCache		  cache,
1038 								 const create_infos_t&		  createInfos,
1039 								 pipelines_t&				  pipelines,
1040 								 const VkAllocationCallbacks* pAllocator = DE_NULL)
1041 {
1042 	DE_ASSERT(createInfos.size() <= pipelines.size());
1043 
1044 	const auto timeStart = high_resolution_clock::now();
1045 	const auto result	 = vk.createComputePipelines(
1046 		   device, cache, static_cast<deUint32>(createInfos.size()), createInfos.data(), pAllocator, pipelines.data());
1047 	const auto elapsed = high_resolution_clock::now() - timeStart;
1048 	return {result, elapsed};
1049 }
1050 
1051 /*--------------------------------------------------------------------*//*!
1052  * \brief Test instance function
1053  *//*--------------------------------------------------------------------*/
testInstance(Context & context,const TestParams & testParameter)1054 TestStatus testInstance(Context& context, const TestParams& testParameter)
1055 {
1056 	const auto& vk					= context.getDeviceInterface();
1057 	const auto	device				= context.getDevice();
1058 	const auto	pipelineCache		= createPipelineCache(vk, device, testParameter);
1059 	const auto	descriptorSetLayout = createDescriptorSetLayout(vk, device, testParameter);
1060 	const auto	pipelineLayout		= createPipelineLayout(vk, device, {descriptorSetLayout.get()}, testParameter);
1061 	const auto	modules				= createShaderModules(vk, device, context.getBinaryCollection(), {"compute"});
1062 	const auto	shaderStages		= createShaderStages(modules, {VK_SHADER_STAGE_COMPUTE_BIT});
1063 
1064 	// Placeholder for base pipeline if using cacheType == DERIVATIVE_HANDLE
1065 	auto basePipeline = UniquePipeline{};
1066 
1067 	const auto baseCreateInfo = VkComputePipelineCreateInfo{
1068 		VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, // sType
1069 		DE_NULL,										// pNext
1070 		VkPipelineCreateFlags{},						// flags
1071 		shaderStages[0],								// stage
1072 		pipelineLayout.get(),							// layout
1073 		VK_NULL_HANDLE,									// basePipelineHandle
1074 		deInt32{-1}										// basePipelineIndex
1075 	};
1076 
1077 	auto results = vector<VkResult>{};
1078 	results.reserve(testParameter.iterations.size());
1079 
1080 	for (const auto& i : testParameter.iterations)
1081 	{
1082 		const auto createInfos = createPipelineCreateInfos(i, baseCreateInfo, basePipeline.get(), testParameter);
1083 		auto	   created	   = vector<VkPipeline>{};
1084 		created.resize(createInfos.size());
1085 
1086 		const auto timedResult = timePipelineCreation(vk, device, pipelineCache.get(), createInfos, created);
1087 		auto	   pipelines   = wrapHandles(vk, device, created);
1088 
1089 		const auto status = validateResults(timedResult.result, pipelines, timedResult.elapsed, i.validators);
1090 		if (status.getCode() != QP_TEST_RESULT_PASS)
1091 		{
1092 			return status;
1093 		}
1094 
1095 		if ((testParameter.cacheType == TestParams::DERIVATIVE_HANDLE) && (*basePipeline == VK_NULL_HANDLE))
1096 		{
1097 			for (auto& pipeline : pipelines)
1098 			{
1099 				if (*pipeline != VK_NULL_HANDLE)
1100 				{
1101 					basePipeline = pipeline;
1102 					break;
1103 				}
1104 			}
1105 		}
1106 
1107 		results.push_back(timedResult.result);
1108 	}
1109 
1110 	static const StringTemplate PASS_MSG = {"Test Passed. ${0}"};
1111 	return TestStatus::pass(PASS_MSG.format(getResultsString(results)));
1112 }
1113 
1114 } // namespace compute_tests
1115 
1116 using namespace test_common;
1117 
1118 // Disable formatting on this next block for readability
1119 // clang-format off
1120 /*--------------------------------------------------------------------*//*!
1121  * \brief Duplicate single pipeline recreation with explicit caching
1122  *//*--------------------------------------------------------------------*/
1123 static constexpr TestParams DUPLICATE_SINGLE_RECREATE_EXPLICIT_CACHING =
1124 {
1125 	"duplicate_single_recreate_explicit_caching",
1126 	"Duplicate single pipeline recreation with explicit caching",
1127 	TestParams::EXPLICIT_CACHE,
1128 	TestParams::IterationArray
1129 	{
1130 		TestParams::Iteration{
1131 			// Iteration [0]: Force compilation of pipeline
1132 			TestParams::Iteration::SINGLE_NORMAL,
1133 			ValidatorArray{
1134 				// Fail if result is not VK_SUCCESS
1135 				checkResult<VK_SUCCESS>,
1136 				// Fail if pipeline is not valid
1137 				checkPipelineMustBeValid<0>
1138 			}
1139 		},
1140 		TestParams::Iteration{
1141 			// Iteration [1]: Request compilation of same pipeline without compile
1142 			TestParams::Iteration::SINGLE_NOCOMPILE,
1143 			ValidatorArray{
1144 				// Warn if result is not VK_SUCCESS
1145 				checkResult<VK_SUCCESS, QP_TEST_RESULT_COMPATIBILITY_WARNING>,
1146 				// Warn if pipeline is not valid
1147 				checkPipelineMustBeValid<0, QP_TEST_RESULT_COMPATIBILITY_WARNING>,
1148 				// Warn if pipeline took too long
1149 				checkElapsedTime<ELAPSED_TIME_FAST, QP_TEST_RESULT_QUALITY_WARNING>
1150 			}
1151 		}
1152 	}
1153 };
1154 
1155 /*--------------------------------------------------------------------*//*!
1156  * \brief Duplicate single pipeline recreation with no explicit cache
1157  *//*--------------------------------------------------------------------*/
1158 static constexpr TestParams DUPLICATE_SINGLE_RECREATE_NO_CACHING =
1159 {
1160 	"duplicate_single_recreate_no_caching",
1161 	"Duplicate single pipeline recreation with no explicit cache",
1162 	TestParams::NO_CACHE,
1163 	TestParams::IterationArray{
1164 		TestParams::Iteration{
1165 			// Iteration [0]: Force compilation of pipeline
1166 			TestParams::Iteration::SINGLE_NORMAL,
1167 			ValidatorArray{
1168 				// Fail if result is not VK_SUCCESS
1169 				checkResult<VK_SUCCESS>,
1170 				// Fail if pipeline is not valid
1171 				checkPipelineMustBeValid<0>
1172 			}
1173 		},
1174 		TestParams::Iteration{
1175 			// Iteration [1]: Request compilation of same pipeline without compile
1176 			TestParams::Iteration::SINGLE_NOCOMPILE,
1177 			ValidatorArray{
1178 				// Warn if pipeline took too long
1179 				checkElapsedTime<ELAPSED_TIME_FAST, QP_TEST_RESULT_QUALITY_WARNING>
1180 			}
1181 		}
1182 	}
1183 };
1184 
1185 /*--------------------------------------------------------------------*//*!
1186  * \brief Duplicate single pipeline recreation using derivative pipelines
1187  *//*--------------------------------------------------------------------*/
1188 static constexpr TestParams DUPLICATE_SINGLE_RECREATE_DERIVATIVE =
1189 {
1190 	"duplicate_single_recreate_derivative",
1191 	"Duplicate single pipeline recreation using derivative pipelines",
1192 	TestParams::DERIVATIVE_HANDLE,
1193 	TestParams::IterationArray{
1194 		TestParams::Iteration{
1195 			// Iteration [0]: Force compilation of pipeline
1196 			TestParams::Iteration::SINGLE_NORMAL,
1197 			ValidatorArray{
1198 				// Fail if result is not VK_SUCCESS
1199 				checkResult<VK_SUCCESS>,
1200 				// Fail if pipeline is not valid
1201 				checkPipelineMustBeValid<0>
1202 				}
1203 			},
1204 		TestParams::Iteration{
1205 			// Iteration [1]: Request compilation of same pipeline without compile
1206 			TestParams::Iteration::SINGLE_NOCOMPILE,
1207 			ValidatorArray{
1208 				// Warn if pipeline took too long
1209 				checkElapsedTime<ELAPSED_TIME_FAST, QP_TEST_RESULT_QUALITY_WARNING>
1210 			}
1211 		}
1212 	}
1213 };
1214 
1215 /*--------------------------------------------------------------------*//*!
1216  * \brief Single creation of never before seen pipeline without compile
1217  *//*--------------------------------------------------------------------*/
1218 static constexpr TestParams SINGLE_PIPELINE_NO_COMPILE =
1219 {
1220 	"single_pipeline_no_compile",
1221 	"Single creation of never before seen pipeline without compile",
1222 	TestParams::NO_CACHE,
1223 	TestParams::IterationArray{
1224 		TestParams::Iteration{
1225 			TestParams::Iteration::SINGLE_NOCOMPILE,
1226 			ValidatorArray{
1227 				// Warn if pipeline took too long
1228 				checkElapsedTime<ELAPSED_TIME_IMMEDIATE, QP_TEST_RESULT_QUALITY_WARNING>
1229 			}
1230 		}
1231 	}
1232 };
1233 
1234 /*--------------------------------------------------------------------*//*!
1235  * \brief Batch creation of duplicate pipelines with explicit caching
1236  *//*--------------------------------------------------------------------*/
1237 static constexpr TestParams DUPLICATE_BATCH_PIPELINES_EXPLICIT_CACHE =
1238 {
1239 	"duplicate_batch_pipelines_explicit_cache",
1240 	"Batch creation of duplicate pipelines with explicit caching",
1241 	TestParams::EXPLICIT_CACHE,
1242 	TestParams::IterationArray{
1243 		TestParams::Iteration{
1244 			TestParams::Iteration::BATCH_NOCOMPILE_COMPILE_NOCOMPILE,
1245 			ValidatorArray{
1246 				// Fail if pipeline[1] is not valid
1247 				checkPipelineMustBeValid<1>,
1248 				// Warn if result is not VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT
1249 				checkResult<VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT, QP_TEST_RESULT_COMPATIBILITY_WARNING>,
1250 				// Warn if pipelines[0] is not VK_NULL_HANDLE
1251 				checkPipelineMustBeNull<0, QP_TEST_RESULT_COMPATIBILITY_WARNING>,
1252 				// Warn if pipelines[2] is not valid
1253 				checkPipelineMustBeValid<2, QP_TEST_RESULT_COMPATIBILITY_WARNING>
1254 			}
1255 		}
1256 	}
1257 };
1258 
1259 /*--------------------------------------------------------------------*//*!
1260  * \brief Batch creation of duplicate pipelines with no caching
1261  *//*--------------------------------------------------------------------*/
1262 static constexpr TestParams DUPLICATE_BATCH_PIPELINES_NO_CACHE =
1263 {
1264 	"duplicate_batch_pipelines_no_cache",
1265 	"Batch creation of duplicate pipelines with no caching",
1266 	TestParams::NO_CACHE,
1267 	TestParams::IterationArray{
1268 		TestParams::Iteration{
1269 			TestParams::Iteration::BATCH_NOCOMPILE_COMPILE_NOCOMPILE,
1270 			ValidatorArray{
1271 				// Fail if pipeline[1] is not valid
1272 				checkPipelineMustBeValid<1>,
1273 				// Warn if result is not VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT
1274 				checkResult<VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT, QP_TEST_RESULT_COMPATIBILITY_WARNING>,
1275 				// Warn if pipelines[0] is not VK_NULL_HANDLE
1276 				checkPipelineMustBeNull<0, QP_TEST_RESULT_COMPATIBILITY_WARNING>
1277 			}
1278 		}
1279 	}
1280 };
1281 
1282 /*--------------------------------------------------------------------*//*!
1283  * \brief Batch creation of duplicate pipelines with derivative pipeline index
1284  *//*--------------------------------------------------------------------*/
1285 static constexpr TestParams DUPLICATE_BATCH_PIPELINES_DERIVATIVE_INDEX =
1286 {
1287 	"duplicate_batch_pipelines_derivative_index",
1288 	"Batch creation of duplicate pipelines with derivative pipeline index",
1289 	TestParams::DERIVATIVE_INDEX,
1290 	TestParams::IterationArray{
1291 		TestParams::Iteration{
1292 			TestParams::Iteration::BATCH_NOCOMPILE_COMPILE_NOCOMPILE,
1293 			ValidatorArray{
1294 				// Fail if pipeline[1] is not valid
1295 				checkPipelineMustBeValid<1>,
1296 				// Warn if result is not VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT
1297 				checkResult<VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT, QP_TEST_RESULT_COMPATIBILITY_WARNING>,
1298 				// Warn if pipelines[0] is not VK_NULL_HANDLE
1299 				checkPipelineMustBeNull<0, QP_TEST_RESULT_COMPATIBILITY_WARNING>
1300 			}
1301 		}
1302 	}
1303 };
1304 
1305 /*--------------------------------------------------------------------*//*!
1306  * \brief Batch creation of pipelines with early return
1307  *//*--------------------------------------------------------------------*/
1308 static constexpr TestParams BATCH_PIPELINES_EARLY_RETURN =
1309 {
1310 	"batch_pipelines_early_return",
1311 	"Batch creation of pipelines with early return",
1312 	TestParams::NO_CACHE,
1313 	TestParams::IterationArray{
1314 		TestParams::Iteration{
1315 			TestParams::Iteration::BATCH_RETURN_COMPILE_NOCOMPILE,
1316 			ValidatorArray{
1317 				// fail if a valid pipeline follows the early-return failure
1318 				checkPipelineNullAfterIndex<0>,
1319 				// Warn if return was not immediate
1320 				checkElapsedTime<ELAPSED_TIME_IMMEDIATE, QP_TEST_RESULT_QUALITY_WARNING>,
1321 				// Warn if pipelines[0] is not VK_NULL_HANDLE
1322 				checkPipelineMustBeNull<0, QP_TEST_RESULT_COMPATIBILITY_WARNING>,
1323 				// Warn if result is not VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT
1324 				checkResult<VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT, QP_TEST_RESULT_COMPATIBILITY_WARNING>
1325 			}
1326 		}
1327 	}
1328 };
1329 
1330 /*--------------------------------------------------------------------*//*!
1331  * \brief Full array of test cases
1332  *//*--------------------------------------------------------------------*/
1333 static constexpr TestParams TEST_CASES[] =
1334 {
1335 	SINGLE_PIPELINE_NO_COMPILE,
1336 	BATCH_PIPELINES_EARLY_RETURN,
1337 	DUPLICATE_SINGLE_RECREATE_EXPLICIT_CACHING,
1338 	DUPLICATE_SINGLE_RECREATE_NO_CACHING,
1339 	DUPLICATE_SINGLE_RECREATE_DERIVATIVE,
1340 	DUPLICATE_BATCH_PIPELINES_EXPLICIT_CACHE,
1341 	DUPLICATE_BATCH_PIPELINES_NO_CACHE,
1342 	DUPLICATE_BATCH_PIPELINES_DERIVATIVE_INDEX
1343 };
1344 // clang-format on
1345 
1346 /*--------------------------------------------------------------------*//*!
1347  * \brief Variadic version of de::newMovePtr
1348  *//*--------------------------------------------------------------------*/
1349 template <typename T, typename... args_t>
newMovePtr(args_t &&...args)1350 inline de::MovePtr<T> newMovePtr(args_t&&... args)
1351 {
1352 	return de::MovePtr<T>(new T(::std::forward<args_t>(args)...));
1353 }
1354 
1355 /*--------------------------------------------------------------------*//*!
1356  * \brief Make test group consisting of graphics pipeline tests
1357  *//*--------------------------------------------------------------------*/
addGraphicsPipelineTests(TestCaseGroup & group)1358 void addGraphicsPipelineTests(TestCaseGroup& group)
1359 {
1360 	using namespace graphics_tests;
1361 
1362 	auto tests = newMovePtr<TestCaseGroup>(
1363 		group.getTestContext(), "graphics_pipelines", "Test pipeline creation cache control with graphics pipelines");
1364 
1365 	for (const auto& params : TEST_CASES)
1366 	{
1367 		addFunctionCaseWithPrograms<const TestParams&>(
1368 			tests.get(), params.name, params.description, checkSupport, initPrograms, testInstance, params);
1369 	}
1370 
1371 	group.addChild(tests.release());
1372 }
1373 
1374 /*--------------------------------------------------------------------*//*!
1375  * \brief Make test group consisting of compute pipeline tests
1376  *//*--------------------------------------------------------------------*/
addComputePipelineTests(TestCaseGroup & group)1377 void addComputePipelineTests(TestCaseGroup& group)
1378 {
1379 	using namespace compute_tests;
1380 
1381 	auto tests = newMovePtr<TestCaseGroup>(
1382 		group.getTestContext(), "compute_pipelines", "Test pipeline creation cache control with compute pipelines");
1383 
1384 	for (const auto& params : TEST_CASES)
1385 	{
1386 		addFunctionCaseWithPrograms<const TestParams&>(
1387 			tests.get(), params.name, params.description, checkSupport, initPrograms, testInstance, params);
1388 	}
1389 
1390 	group.addChild(tests.release());
1391 }
1392 
1393 } // namespace
1394 
1395 /*--------------------------------------------------------------------*//*!
1396  * \brief Make pipeline creation cache control test group
1397  *//*--------------------------------------------------------------------*/
createCacheControlTests(TestContext & testCtx)1398 TestCaseGroup* createCacheControlTests(TestContext& testCtx)
1399 {
1400 	auto tests = newMovePtr<TestCaseGroup>(testCtx, "creation_cache_control", "pipeline creation cache control tests");
1401 
1402 	addGraphicsPipelineTests(*tests);
1403 	addComputePipelineTests(*tests);
1404 
1405 	return tests.release();
1406 }
1407 
1408 } // namespace pipeline
1409 
1410 } // namespace vkt
1411