1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2019 The Khronos Group Inc.
6  * Copyright (c) 2019 Intel Corporation.
7  * Copyright (c) 2023 LunarG, Inc.
8  * Copyright (c) 2023 Nintendo
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *      http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  *
22  *//*!
23  * \file
24  * \brief VK_KHR_pipeline_executable_properties
25  *
26  * These tests creates compute and graphics pipelines with a variety of
27  * stages both with and without a pipeline cache and exercise the new
28  * queries provided by VK_KHR_pipeline_executable_properties.
29  *
30  * For each query type, it asserts that the query works and doesn't crash
31  * and returns consistent results:
32  *
33  *  - The tests assert that the same set of pipeline executables is
34  *    reported regardless of whether or not a pipeline cache is used.
35  *
36  *  - For each pipeline executable, the tests assert that the same set of
37  *    statistics is returned regardless of whether or not a pipeline cache
38  *    is used.
39  *
40  *  - For each pipeline executable, the tests assert that the same set of
41  *    statistics is returned regardless of whether or not
42  *    CAPTURE_INTERNAL_REPRESENTATIONS_BIT is set.
43  *
44  *  - For each pipeline executable, the tests assert that the same set of
45  *    internal representations is returned regardless of whether or not a
46  *    pipeline cache is used.
47  *
48  *  - For each string returned (statistic names, etc.) the tests assert
49  *    that the string is NULL terminated.
50  *
51  *  - For each statistic, the tests compare the results of the two
52  *    compilations and report any differences.  (Statistics differing
53  *    between two compilations is not considered a failure.)
54  *
55  *  - For each binary internal representation, the tests attempt to assert
56  *    that the amount of data returned by the implementation matches the
57  *    amount the implementation claims.  (It's impossible to exactly do
58  *    this but the tests give it a good try.)
59  *
60  * All of the returned data is recorded in the output file.
61  *
62  *//*--------------------------------------------------------------------*/
63 
64 #include "vktPipelineExecutablePropertiesTests.hpp"
65 #include "vktPipelineVertexUtil.hpp"
66 #include "vktTestCase.hpp"
67 #include "vktTestCaseUtil.hpp"
68 #include "vkMemUtil.hpp"
69 #include "vkBuilderUtil.hpp"
70 #include "vkRefUtil.hpp"
71 #include "vkTypeUtil.hpp"
72 #include "vkObjUtil.hpp"
73 #include "tcuTestLog.hpp"
74 
75 #include <sstream>
76 #include <vector>
77 
78 namespace vkt
79 {
80 namespace pipeline
81 {
82 
83 using namespace vk;
84 
85 namespace
86 {
87 enum
88 {
89 	VK_MAX_SHADER_STAGES = 6,
90 };
91 
92 enum
93 {
94 	PIPELINE_CACHE_NDX_INITIAL = 0,
95 	PIPELINE_CACHE_NDX_CACHED = 1,
96 	PIPELINE_CACHE_NDX_COUNT,
97 };
98 
99 // helper functions
100 
getShaderFlagStr(const VkShaderStageFlags shader, bool isDescription)101 std::string getShaderFlagStr(const VkShaderStageFlags	shader,
102 							 bool						isDescription)
103 {
104 	std::ostringstream desc;
105 	if (shader & VK_SHADER_STAGE_COMPUTE_BIT)
106 	{
107 		desc << ((isDescription) ? "compute stage" : "compute_stage");
108 	}
109 	else
110 	{
111 		desc << ((isDescription) ? "vertex stage" : "vertex_stage");
112 		if (shader & VK_SHADER_STAGE_GEOMETRY_BIT)
113 			desc << ((isDescription) ? " geometry stage" : "_geometry_stage");
114 		if (shader & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)
115 			desc << ((isDescription) ? " tessellation control stage" : "_tessellation_control_stage");
116 		if (shader & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)
117 			desc << ((isDescription) ? " tessellation evaluation stage" : "_tessellation_evaluation_stage");
118 		desc << ((isDescription) ? " fragment stage" : "_fragment_stage");
119 	}
120 
121 	return desc.str();
122 }
123 
getShaderFlagsStr(const VkShaderStageFlags flags)124 std::string getShaderFlagsStr (const VkShaderStageFlags flags)
125 {
126 	std::ostringstream stream;
127 	bool empty = true;
128 	for (deUint32 b = 0; b < 8 * sizeof(flags); b++)
129 	{
130 		if (flags & (1u << b))
131 		{
132 			if (empty)
133 			{
134 				empty = false;
135 			}
136 			else
137 			{
138 				stream << ", ";
139 			}
140 
141 			stream << getShaderFlagStr((VkShaderStageFlagBits)(1u << b), true);
142 		}
143 	}
144 
145 	if (empty)
146 	{
147 		stream << "none";
148 	}
149 
150 	return stream.str();
151 }
152 
153 // helper classes
154 class ExecutablePropertiesTestParam
155 {
156 public:
157 								ExecutablePropertiesTestParam	(PipelineConstructionType		pipelineConstructionType,
158 																 const VkShaderStageFlags		shaders,
159 																 deBool							testStatistics,
160 																 deBool							testInternalRepresentations);
161 	virtual						~ExecutablePropertiesTestParam	(void)	= default;
162 	virtual const std::string	generateTestName				(void)	const;
getPipelineConstructionType(void) const163 	PipelineConstructionType	getPipelineConstructionType		(void)	const	{ return m_pipelineConstructionType; }
getShaderFlags(void) const164 	VkShaderStageFlags			getShaderFlags					(void)	const	{ return m_shaders; }
getTestStatistics(void) const165 	deBool						getTestStatistics				(void)	const	{ return m_testStatistics; }
getTestInternalRepresentations(void) const166 	deBool						getTestInternalRepresentations	(void)	const	{ return m_testInternalRepresentations; }
167 
168 protected:
169 	PipelineConstructionType	m_pipelineConstructionType;
170 	VkShaderStageFlags			m_shaders;
171 	bool						m_testStatistics;
172 	bool						m_testInternalRepresentations;
173 };
174 
ExecutablePropertiesTestParam(PipelineConstructionType pipelineConstructionType, const VkShaderStageFlags shaders, deBool testStatistics, deBool testInternalRepresentations)175 ExecutablePropertiesTestParam::ExecutablePropertiesTestParam (PipelineConstructionType pipelineConstructionType, const VkShaderStageFlags shaders, deBool testStatistics, deBool testInternalRepresentations)
176 	: m_pipelineConstructionType	(pipelineConstructionType)
177 	, m_shaders						(shaders)
178 	, m_testStatistics				(testStatistics)
179 	, m_testInternalRepresentations	(testInternalRepresentations)
180 {
181 }
182 
generateTestName(void) const183 const std::string ExecutablePropertiesTestParam::generateTestName (void) const
184 {
185 	std::string result(getShaderFlagStr(m_shaders, false));
186 
187 	if (m_testStatistics)
188 		result += "_statistics";
189 	if (m_testInternalRepresentations)
190 		result += "_internal_representations";
191 
192 	return result;
193 }
194 
195 template <class Test>
newTestCase(tcu::TestContext& testContext, const ExecutablePropertiesTestParam* testParam)196 vkt::TestCase* newTestCase (tcu::TestContext&		testContext,
197 							const ExecutablePropertiesTestParam*	testParam)
198 {
199 	return new Test(testContext,
200 					testParam->generateTestName().c_str(),
201 					testParam);
202 }
203 
204 // Test Classes
205 class ExecutablePropertiesTest : public vkt::TestCase
206 {
207 public:
ExecutablePropertiesTest(tcu::TestContext& testContext, const std::string& name, const ExecutablePropertiesTestParam* param)208 							ExecutablePropertiesTest(tcu::TestContext&		testContext,
209 										   const std::string&		name,
210 										   const ExecutablePropertiesTestParam*	param)
211 								: vkt::TestCase (testContext, name)
212 								, m_param (*param)
213 								{ }
~ExecutablePropertiesTest(void)214 	virtual					~ExecutablePropertiesTest (void) { }
215 protected:
216 	const ExecutablePropertiesTestParam	m_param;
217 };
218 
219 class ExecutablePropertiesTestInstance : public vkt::TestInstance
220 {
221 public:
222 							ExecutablePropertiesTestInstance			(Context&				context,
223 															 const ExecutablePropertiesTestParam*	param);
224 	virtual					~ExecutablePropertiesTestInstance			(void);
225 	virtual tcu::TestStatus iterate							(void);
226 protected:
227 	virtual tcu::TestStatus verifyStatistics				(deUint32 binaryNdx);
228 	virtual tcu::TestStatus verifyInternalRepresentations	(deUint32 binaryNdx);
229 	virtual tcu::TestStatus verifyTestResult				(void);
230 protected:
231 	const ExecutablePropertiesTestParam*	m_param;
232 
233 	Move<VkPipelineCache>	m_cache;
234 	deBool					m_extensions;
235 
236 	Move<VkPipeline>		m_pipeline[PIPELINE_CACHE_NDX_COUNT];
237 
getPipeline(deUint32 ndx)238 	virtual VkPipeline		getPipeline(deUint32 ndx) { return m_pipeline[ndx].get(); }
239 };
240 
ExecutablePropertiesTestInstance(Context& context, const ExecutablePropertiesTestParam* param)241 ExecutablePropertiesTestInstance::ExecutablePropertiesTestInstance (Context&					context,
242 												const ExecutablePropertiesTestParam*	param)
243 	: TestInstance		(context)
244 	, m_param			(param)
245 	, m_extensions		(m_context.requireDeviceFunctionality("VK_KHR_pipeline_executable_properties"))
246 {
247 	const DeviceInterface&	vk				= m_context.getDeviceInterface();
248 	const VkDevice			vkDevice		= m_context.getDevice();
249 
250 	const VkPipelineCacheCreateInfo pipelineCacheCreateInfo =
251 	{
252 		VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO,			// VkStructureType				sType;
253 		DE_NULL,												// const void*					pNext;
254 		0u,														// VkPipelineCacheCreateFlags	flags;
255 		0u,														// deUintptr					initialDataSize;
256 		DE_NULL,												// const void*					pInitialData;
257 	};
258 
259 	m_cache = createPipelineCache(vk, vkDevice, &pipelineCacheCreateInfo);
260 }
261 
~ExecutablePropertiesTestInstance(void)262 ExecutablePropertiesTestInstance::~ExecutablePropertiesTestInstance (void)
263 {
264 }
265 
iterate(void)266 tcu::TestStatus ExecutablePropertiesTestInstance::iterate (void)
267 {
268 	return verifyTestResult();
269 }
270 
271 bool
checkString(const char *string, size_t size)272 checkString(const char *string, size_t size)
273 {
274 	size_t i = 0;
275 	for (; i < size; i++)
276 	{
277 		if (string[i] == 0)
278 		{
279 			break;
280 		}
281 	}
282 
283 	// The string needs to be non-empty and null terminated
284 	if (i == 0 || i >= size)
285 	{
286 		return false;
287 	}
288 
289 	return true;
290 }
291 
verifyStatistics(deUint32 executableNdx)292 tcu::TestStatus ExecutablePropertiesTestInstance::verifyStatistics (deUint32 executableNdx)
293 {
294 	const DeviceInterface&		vk			= m_context.getDeviceInterface();
295 	const VkDevice				vkDevice	= m_context.getDevice();
296 	tcu::TestLog				&log		= m_context.getTestContext().getLog();
297 
298 	std::vector<VkPipelineExecutableStatisticKHR> statistics[PIPELINE_CACHE_NDX_COUNT];
299 
300 	for (deUint32 ndx = 0; ndx < PIPELINE_CACHE_NDX_COUNT; ndx++)
301 	{
302 		const VkPipelineExecutableInfoKHR pipelineExecutableInfo =
303 		{
304 			VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_INFO_KHR,	// VkStructureType					sType;
305 			DE_NULL,										// const void*						pNext;
306 			getPipeline(ndx),								// VkPipeline						pipeline;
307 			executableNdx,									// uint32_t							executableIndex;
308 		};
309 
310 		deUint32 statisticCount = 0;
311 		VK_CHECK(vk.getPipelineExecutableStatisticsKHR(vkDevice, &pipelineExecutableInfo, &statisticCount, DE_NULL));
312 
313 		if (statisticCount == 0)
314 		{
315 			continue;
316 		}
317 
318 		statistics[ndx].resize(statisticCount);
319 		for (deUint32 statNdx = 0; statNdx < statisticCount; statNdx++)
320 		{
321 			deMemset(&statistics[ndx][statNdx], 0, sizeof(statistics[ndx][statNdx]));
322 			statistics[ndx][statNdx].sType = VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_STATISTIC_KHR;
323 			statistics[ndx][statNdx].pNext = DE_NULL;
324 		}
325 		VK_CHECK(vk.getPipelineExecutableStatisticsKHR(vkDevice, &pipelineExecutableInfo, &statisticCount, &statistics[ndx][0]));
326 
327 		for (deUint32 statNdx = 0; statNdx < statisticCount; statNdx++)
328 		{
329 			if (!checkString(statistics[ndx][statNdx].name, DE_LENGTH_OF_ARRAY(statistics[ndx][statNdx].name)))
330 			{
331 				return tcu::TestStatus::fail("Invalid statistic name string");
332 			}
333 
334 			for (deUint32 otherNdx = 0; otherNdx < statNdx; otherNdx++)
335 			{
336 				if (deMemCmp(statistics[ndx][statNdx].name, statistics[ndx][otherNdx].name,
337 							 DE_LENGTH_OF_ARRAY(statistics[ndx][statNdx].name)) == 0)
338 				{
339 					return tcu::TestStatus::fail("Statistic name string not unique within the executable");
340 				}
341 			}
342 
343 			if (!checkString(statistics[ndx][statNdx].description, DE_LENGTH_OF_ARRAY(statistics[ndx][statNdx].description)))
344 			{
345 				return tcu::TestStatus::fail("Invalid statistic description string");
346 			}
347 
348 			if (statistics[ndx][statNdx].format == VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_BOOL32_KHR)
349 			{
350 				if (statistics[ndx][statNdx].value.b32 != VK_TRUE && statistics[ndx][statNdx].value.b32 != VK_FALSE)
351 				{
352 					return tcu::TestStatus::fail("Boolean statistic is neither VK_TRUE nor VK_FALSE");
353 				}
354 			}
355 		}
356 	}
357 
358 	if (statistics[0].size() != statistics[1].size())
359 	{
360 		return tcu::TestStatus::fail("Identical pipelines have different numbers of statistics");
361 	}
362 
363 	if (statistics[0].size() == 0)
364 	{
365 		return tcu::TestStatus::pass("No statistics reported");
366 	}
367 
368 	// Both compiles had better have specified the same infos
369 	for (deUint32 statNdx0 = 0; statNdx0 < statistics[0].size(); statNdx0++)
370 	{
371 		deUint32 statNdx1 = 0;
372 		for (; statNdx1 < statistics[1].size(); statNdx1++)
373 		{
374 			if (deMemCmp(statistics[0][statNdx0].name, statistics[1][statNdx1].name,
375 						 DE_LENGTH_OF_ARRAY(statistics[0][statNdx0].name)) == 0)
376 			{
377 				break;
378 			}
379 		}
380 		if (statNdx1 >= statistics[1].size())
381 		{
382 			return tcu::TestStatus::fail("Identical pipelines have different statistics");
383 		}
384 
385 		if (deMemCmp(statistics[0][statNdx0].description, statistics[1][statNdx1].description,
386 					 DE_LENGTH_OF_ARRAY(statistics[0][statNdx0].description)) != 0)
387 		{
388 			return tcu::TestStatus::fail("Invalid binary description string");
389 		}
390 
391 		if (statistics[0][statNdx0].format != statistics[1][statNdx1].format)
392 		{
393 			return tcu::TestStatus::fail("Identical pipelines have statistics with different formats");
394 		}
395 
396 		switch (statistics[0][statNdx0].format)
397 		{
398 			case VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_BOOL32_KHR:
399 			{
400 				bool match = statistics[0][statNdx0].value.b32 == statistics[1][statNdx1].value.b32;
401 				log << tcu::TestLog::Message
402 					<< statistics[0][statNdx0].name << ": "
403 					<< (statistics[0][statNdx0].value.b32 ? "VK_TRUE" : "VK_FALSE")
404 					<< (match ? "" : " (non-deterministic)")
405 					<< " (" << statistics[0][statNdx0].description << ")"
406 					<< tcu::TestLog::EndMessage;
407 				break;
408 			}
409 			case VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_INT64_KHR:
410 			{
411 				bool match = statistics[0][statNdx0].value.i64 == statistics[1][statNdx1].value.i64;
412 				log << tcu::TestLog::Message
413 					<< statistics[0][statNdx0].name << ": "
414 					<< statistics[0][statNdx0].value.i64
415 					<< (match ? "" : " (non-deterministic)")
416 					<< " (" << statistics[0][statNdx0].description << ")"
417 					<< tcu::TestLog::EndMessage;
418 				break;
419 			}
420 			case VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_UINT64_KHR:
421 			{
422 				bool match = statistics[0][statNdx0].value.u64 == statistics[1][statNdx1].value.u64;
423 				log << tcu::TestLog::Message
424 					<< statistics[0][statNdx0].name << ": "
425 					<< statistics[0][statNdx0].value.u64
426 					<< (match ? "" : " (non-deterministic)")
427 					<< " (" << statistics[0][statNdx0].description << ")"
428 					<< tcu::TestLog::EndMessage;
429 				break;
430 			}
431 			case VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_FLOAT64_KHR:
432 			{
433 				bool match = statistics[0][statNdx0].value.f64 == statistics[1][statNdx1].value.f64;
434 				log << tcu::TestLog::Message
435 					<< statistics[0][statNdx0].name << ": "
436 					<< statistics[0][statNdx0].value.f64
437 					<< (match ? "" : " (non-deterministic)")
438 					<< " (" << statistics[0][statNdx0].description << ")"
439 					<< tcu::TestLog::EndMessage;
440 				break;
441 			}
442 			default:
443 				return tcu::TestStatus::fail("Invalid statistic format");
444 		}
445 	}
446 
447 	return tcu::TestStatus::pass("Pass");
448 }
449 
verifyInternalRepresentations(deUint32 executableNdx)450 tcu::TestStatus ExecutablePropertiesTestInstance::verifyInternalRepresentations (deUint32 executableNdx)
451 {
452 	const DeviceInterface&		vk			= m_context.getDeviceInterface();
453 	const VkDevice				vkDevice	= m_context.getDevice();
454 	tcu::TestLog				&log		= m_context.getTestContext().getLog();
455 
456 	// We only care about internal representations on the second pipeline.
457 	// We still compile twice to ensure that we still get the right thing
458 	// even if the pipeline is hot in the cache.
459 	const VkPipelineExecutableInfoKHR pipelineExecutableInfo =
460 	{
461 		VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_INFO_KHR,	// VkStructureType					sType;
462 		DE_NULL,										// const void*						pNext;
463 		getPipeline(1),									// VkPipeline						pipeline;
464 		executableNdx,									// uint32_t							executableIndex;
465 	};
466 
467 	std::vector<VkPipelineExecutableInternalRepresentationKHR> irs;
468 	std::vector<std::vector<deUint8>> irDatas;
469 
470 	deUint32 irCount = 0;
471 	VK_CHECK(vk.getPipelineExecutableInternalRepresentationsKHR(vkDevice, &pipelineExecutableInfo, &irCount, DE_NULL));
472 
473 	if (irCount == 0)
474 	{
475 		return tcu::TestStatus::pass("No internal representations reported");
476 	}
477 
478 	irs.resize(irCount);
479 	irDatas.resize(irCount);
480 	for (deUint32 irNdx = 0; irNdx < irCount; irNdx++)
481 	{
482 		deMemset(&irs[irNdx], 0, sizeof(irs[irNdx]));
483 		irs[irNdx].sType = VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_INTERNAL_REPRESENTATION_KHR;
484 		irs[irNdx].pNext = DE_NULL;
485 	}
486 	VK_CHECK(vk.getPipelineExecutableInternalRepresentationsKHR(vkDevice, &pipelineExecutableInfo, &irCount, &irs[0]));
487 
488 	for (deUint32 irNdx = 0; irNdx < irCount; irNdx++)
489 	{
490 		if (!checkString(irs[irNdx].name, DE_LENGTH_OF_ARRAY(irs[irNdx].name)))
491 		{
492 			return tcu::TestStatus::fail("Invalid internal representation name string");
493 		}
494 
495 		for (deUint32 otherNdx = 0; otherNdx < irNdx; otherNdx++)
496 		{
497 			if (deMemCmp(irs[irNdx].name, irs[otherNdx].name,
498 						 DE_LENGTH_OF_ARRAY(irs[irNdx].name)) == 0)
499 			{
500 				return tcu::TestStatus::fail("Internal representation name string not unique within the executable");
501 			}
502 		}
503 
504 		if (!checkString(irs[irNdx].description, DE_LENGTH_OF_ARRAY(irs[irNdx].description)))
505 		{
506 			return tcu::TestStatus::fail("Invalid binary description string");
507 		}
508 
509 		if (irs[irNdx].dataSize == 0)
510 		{
511 			return tcu::TestStatus::fail("Internal representation has no data");
512 		}
513 
514 		irDatas[irNdx].resize(irs[irNdx].dataSize);
515 		irs[irNdx].pData = &irDatas[irNdx][0];
516 		if (irs[irNdx].isText)
517 		{
518 			// For binary data the size is important.  We check that the
519 			// implementation fills the whole buffer by filling it with
520 			// garbage first and then looking for that same garbage later.
521 			for (size_t i = 0; i < irs[irNdx].dataSize; i++)
522 			{
523 				irDatas[irNdx][i] = (deUint8)(37 * (17 + i));
524 			}
525 		}
526 	}
527 
528 	VK_CHECK(vk.getPipelineExecutableInternalRepresentationsKHR(vkDevice, &pipelineExecutableInfo, &irCount, &irs[0]));
529 
530 	for (deUint32 irNdx = 0; irNdx < irCount; irNdx++)
531 	{
532 		if (irs[irNdx].isText)
533 		{
534 			if (!checkString((char *)irs[irNdx].pData, irs[irNdx].dataSize))
535 			{
536 				return tcu::TestStatus::fail("Textual internal representation isn't a valid string");
537 			}
538 			log << tcu::TestLog::Section(irs[irNdx].name, irs[irNdx].description)
539 				<< tcu::LogKernelSource((char *)irs[irNdx].pData)
540 				<< tcu::TestLog::EndSection;
541 		}
542 		else
543 		{
544 			size_t maxMatchingChunkSize = 0;
545 			size_t matchingChunkSize = 0;
546 			for (size_t i = 0; i < irs[irNdx].dataSize; i++)
547 			{
548 				if (irDatas[irNdx][i] == (deUint8)(37 * (17 + i)))
549 				{
550 					matchingChunkSize++;
551 					if (matchingChunkSize > maxMatchingChunkSize)
552 					{
553 						maxMatchingChunkSize = matchingChunkSize;
554 					}
555 				}
556 				else
557 				{
558 					matchingChunkSize = 0;
559 				}
560 			}
561 
562 			// 64 bytes of our random data still being in the buffer probably
563 			// isn't a coincidence
564 			if (matchingChunkSize == irs[irNdx].dataSize || matchingChunkSize >= 64)
565 			{
566 				return tcu::TestStatus::fail("Implementation didn't fill the whole internal representation data buffer");
567 			}
568 
569 			log << tcu::TestLog::Section(irs[irNdx].name, irs[irNdx].description)
570 				<< tcu::TestLog::Message << "Received " << irs[irNdx].dataSize << "B of binary data" << tcu::TestLog::EndMessage
571 				<< tcu::TestLog::EndSection;
572 		}
573 	}
574 
575 	return tcu::TestStatus::pass("Pass");
576 }
577 
verifyTestResult(void)578 tcu::TestStatus ExecutablePropertiesTestInstance::verifyTestResult (void)
579 {
580 	const DeviceInterface&		vk			= m_context.getDeviceInterface();
581 	const VkDevice				vkDevice	= m_context.getDevice();
582 	tcu::TestLog				&log		= m_context.getTestContext().getLog();
583 
584 	std::vector<VkPipelineExecutablePropertiesKHR> props[PIPELINE_CACHE_NDX_COUNT];
585 
586 	for (deUint32 ndx = 0; ndx < PIPELINE_CACHE_NDX_COUNT; ndx++)
587 	{
588 		const VkPipelineInfoKHR pipelineInfo =
589 		{
590 			VK_STRUCTURE_TYPE_PIPELINE_INFO_KHR,	// VkStructureType					sType;
591 			DE_NULL,								// const void*						pNext;
592 			getPipeline(ndx),						// VkPipeline						pipeline;
593 
594 		};
595 		deUint32 executableCount = 0;
596 		VK_CHECK(vk.getPipelineExecutablePropertiesKHR(vkDevice, &pipelineInfo, &executableCount, DE_NULL));
597 
598 		if (executableCount == 0)
599 		{
600 			continue;
601 		}
602 
603 		props[ndx].resize(executableCount);
604 		for (deUint32 execNdx = 0; execNdx < executableCount; execNdx++)
605 		{
606 			deMemset(&props[ndx][execNdx], 0, sizeof(props[ndx][execNdx]));
607 			props[ndx][execNdx].sType = VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_PROPERTIES_KHR;
608 			props[ndx][execNdx].pNext = DE_NULL;
609 		}
610 		VK_CHECK(vk.getPipelineExecutablePropertiesKHR(vkDevice, &pipelineInfo, &executableCount, &props[ndx][0]));
611 
612 		for (deUint32 execNdx = 0; execNdx < executableCount; execNdx++)
613 		{
614 			if (!checkString(props[ndx][execNdx].name, DE_LENGTH_OF_ARRAY(props[ndx][execNdx].name)))
615 			{
616 				return tcu::TestStatus::fail("Invalid binary name string");
617 			}
618 
619 			for (deUint32 otherNdx = 0; otherNdx < execNdx; otherNdx++)
620 			{
621 				if (deMemCmp(props[ndx][execNdx].name, props[ndx][otherNdx].name,
622 							 DE_LENGTH_OF_ARRAY(props[ndx][execNdx].name)) == 0)
623 				{
624 					return tcu::TestStatus::fail("Binary name string not unique within the pipeline");
625 				}
626 			}
627 
628 			if (!checkString(props[ndx][execNdx].description, DE_LENGTH_OF_ARRAY(props[ndx][execNdx].description)))
629 			{
630 				return tcu::TestStatus::fail("Invalid binary description string");
631 			}
632 
633 			// Check that the binary only contains stages actually used to
634 			// compile the pipeline
635 			VkShaderStageFlags stages = props[ndx][execNdx].stages;
636 			stages &= ~m_param->getShaderFlags();
637 			if (stages != 0)
638 			{
639 				return tcu::TestStatus::fail("Binary uses unprovided stage");
640 			}
641 		}
642 	}
643 
644 	if (props[0].size() != props[1].size())
645 	{
646 		return tcu::TestStatus::fail("Identical pipelines have different numbers of props");
647 	}
648 
649 	if (props[0].size() == 0)
650 	{
651 		return tcu::TestStatus::pass("No executables reported");
652 	}
653 
654 	// Both compiles had better have specified the same infos
655 	for (deUint32 execNdx0 = 0; execNdx0 < props[0].size(); execNdx0++)
656 	{
657 		deUint32 execNdx1 = 0;
658 		for (; execNdx1 < props[1].size(); execNdx1++)
659 		{
660 			if (deMemCmp(props[0][execNdx0].name, props[1][execNdx1].name,
661 						 DE_LENGTH_OF_ARRAY(props[0][execNdx0].name)) == 0)
662 			{
663 				break;
664 			}
665 		}
666 		if (execNdx1 >= props[1].size())
667 		{
668 			return tcu::TestStatus::fail("Identical pipelines have different sets of executables");
669 		}
670 
671 		if (deMemCmp(props[0][execNdx0].description, props[1][execNdx1].description,
672 					 DE_LENGTH_OF_ARRAY(props[0][execNdx0].description)) != 0)
673 		{
674 			return tcu::TestStatus::fail("Same binary has different descriptions");
675 		}
676 
677 		if (props[0][execNdx0].stages != props[1][execNdx1].stages)
678 		{
679 			return tcu::TestStatus::fail("Same binary has different stages");
680 		}
681 
682 		if (props[0][execNdx0].subgroupSize != props[1][execNdx1].subgroupSize)
683 		{
684 			return tcu::TestStatus::fail("Same binary has different subgroup sizes");
685 		}
686 	}
687 
688 	log << tcu::TestLog::Section("Binaries", "Binaries reported for this pipeline");
689 	log << tcu::TestLog::Message << "Pipeline reported " << props[0].size() << " props" << tcu::TestLog::EndMessage;
690 
691 	tcu::TestStatus status = tcu::TestStatus::pass("Pass");
692 	for (deUint32 execNdx = 0; execNdx < props[0].size(); execNdx++)
693 	{
694 		log << tcu::TestLog::Section(props[0][execNdx].name, props[0][execNdx].description);
695 		log << tcu::TestLog::Message << "Name: " << props[0][execNdx].name << tcu::TestLog::EndMessage;
696 		log << tcu::TestLog::Message << "Description: " << props[0][execNdx].description << tcu::TestLog::EndMessage;
697 		log << tcu::TestLog::Message << "Stages: " << getShaderFlagsStr(props[0][execNdx].stages) << tcu::TestLog::EndMessage;
698 		log << tcu::TestLog::Message << "Subgroup Size: " << props[0][execNdx].subgroupSize << tcu::TestLog::EndMessage;
699 
700 		if (m_param->getTestStatistics())
701 		{
702 			status = verifyStatistics(execNdx);
703 			if (status.getCode() != QP_TEST_RESULT_PASS)
704 			{
705 				log << tcu::TestLog::EndSection;
706 				break;
707 			}
708 		}
709 
710 		if (m_param->getTestInternalRepresentations())
711 		{
712 			status = verifyInternalRepresentations(execNdx);
713 			if (status.getCode() != QP_TEST_RESULT_PASS)
714 			{
715 				log << tcu::TestLog::EndSection;
716 				break;
717 			}
718 		}
719 
720 		log << tcu::TestLog::EndSection;
721 	}
722 
723 	log << tcu::TestLog::EndSection;
724 
725 	return status;
726 }
727 
728 class GraphicsExecutablePropertiesTest : public ExecutablePropertiesTest
729 {
730 public:
GraphicsExecutablePropertiesTest(tcu::TestContext& testContext, const std::string& name, const ExecutablePropertiesTestParam* param)731 							GraphicsExecutablePropertiesTest	(tcu::TestContext&		testContext,
732 													 const std::string&	name,
733 													 const ExecutablePropertiesTestParam*	param)
734 								: ExecutablePropertiesTest (testContext, name, param)
735 								{ }
~GraphicsExecutablePropertiesTest(void)736 	virtual					~GraphicsExecutablePropertiesTest	(void) { }
737 	virtual void			initPrograms		(SourceCollections&	programCollection) const;
738 	virtual TestInstance*	createInstance		(Context&				context) const;
739 	void					checkSupport		(Context& context) const;
740 };
741 
742 class GraphicsExecutablePropertiesTestInstance : public ExecutablePropertiesTestInstance
743 {
744 public:
745 							GraphicsExecutablePropertiesTestInstance	(Context&								context,
746 																		 const ExecutablePropertiesTestParam*	param);
747 	virtual					~GraphicsExecutablePropertiesTestInstance	(void);
748 
749 protected:
750 	void					preparePipelineWrapper						(GraphicsPipelineWrapper&	gpw,
751 																		 ShaderWrapper				vertShaderModule,
752 																		 ShaderWrapper				tescShaderModule,
753 																		 ShaderWrapper				teseShaderModule,
754 																		 ShaderWrapper				geomShaderModule,
755 																		 ShaderWrapper				fragShaderModule);
756 
757 	VkPipeline				getPipeline									(deUint32 ndx) override
758 	{
759 		return m_pipelineWrapper[ndx].getPipeline();
760 	};
761 
762 protected:
763 	const tcu::UVec2					m_renderSize;
764 	const VkFormat						m_colorFormat;
765 	const VkFormat						m_depthFormat;
766 	PipelineLayoutWrapper				m_pipelineLayout;
767 	GraphicsPipelineWrapper				m_pipelineWrapper[PIPELINE_CACHE_NDX_COUNT];
768 	Move<VkRenderPass>					m_renderPass;
769 };
770 
initPrograms(SourceCollections& programCollection) const771 void GraphicsExecutablePropertiesTest::initPrograms (SourceCollections& programCollection) const
772 {
773 	programCollection.glslSources.add("color_vert") << glu::VertexSource(
774 				"#version 310 es\n"
775 				"layout(location = 0) in vec4 position;\n"
776 				"layout(location = 1) in vec4 color;\n"
777 				"layout(location = 0) out highp vec4 vtxColor;\n"
778 				"void main (void)\n"
779 				"{\n"
780 				"  gl_Position = position;\n"
781 				"  vtxColor = color;\n"
782 				"}\n");
783 
784 	programCollection.glslSources.add("color_frag") << glu::FragmentSource(
785 				"#version 310 es\n"
786 				"layout(location = 0) in highp vec4 vtxColor;\n"
787 				"layout(location = 0) out highp vec4 fragColor;\n"
788 				"void main (void)\n"
789 				"{\n"
790 				"  fragColor = vtxColor;\n"
791 				"}\n");
792 
793 	if (m_param.getShaderFlags() & VK_SHADER_STAGE_GEOMETRY_BIT)
794 	{
795 		programCollection.glslSources.add("dummy_geo") << glu::GeometrySource(
796 					"#version 450 \n"
797 					"layout(triangles) in;\n"
798 					"layout(triangle_strip, max_vertices = 3) out;\n"
799 					"layout(location = 0) in highp vec4 in_vtxColor[];\n"
800 					"layout(location = 0) out highp vec4 vtxColor;\n"
801 					"out gl_PerVertex { vec4 gl_Position; float gl_PointSize; };\n"
802 					"in gl_PerVertex { vec4 gl_Position; float gl_PointSize; } gl_in[];\n"
803 					"void main (void)\n"
804 					"{\n"
805 					"  for(int ndx=0; ndx<3; ndx++)\n"
806 					"  {\n"
807 					"    gl_Position = gl_in[ndx].gl_Position;\n"
808 					"    gl_PointSize = gl_in[ndx].gl_PointSize;\n"
809 					"    vtxColor    = in_vtxColor[ndx];\n"
810 					"    EmitVertex();\n"
811 					"  }\n"
812 					"  EndPrimitive();\n"
813 						"}\n");
814 	}
815 	if (m_param.getShaderFlags() & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)
816 	{
817 		programCollection.glslSources.add("basic_tcs") << glu::TessellationControlSource(
818 					"#version 450 \n"
819 					"layout(vertices = 3) out;\n"
820 					"layout(location = 0) in highp vec4 color[];\n"
821 					"layout(location = 0) out highp vec4 vtxColor[];\n"
822 					"out gl_PerVertex { vec4 gl_Position; float gl_PointSize; } gl_out[3];\n"
823 					"in gl_PerVertex { vec4 gl_Position; float gl_PointSize; } gl_in[gl_MaxPatchVertices];\n"
824 					"void main()\n"
825 					"{\n"
826 					"  gl_TessLevelOuter[0] = 4.0;\n"
827 					"  gl_TessLevelOuter[1] = 4.0;\n"
828 					"  gl_TessLevelOuter[2] = 4.0;\n"
829 					"  gl_TessLevelInner[0] = 4.0;\n"
830 					"  gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
831 					"  gl_out[gl_InvocationID].gl_PointSize = gl_in[gl_InvocationID].gl_PointSize;\n"
832 					"  vtxColor[gl_InvocationID] = color[gl_InvocationID];\n"
833 					"}\n");
834 
835 		programCollection.glslSources.add("basic_tes") << glu::TessellationEvaluationSource(
836 					"#version 450 \n"
837 					"layout(triangles, fractional_even_spacing, ccw) in;\n"
838 					"layout(location = 0) in highp vec4 colors[];\n"
839 					"layout(location = 0) out highp vec4 vtxColor;\n"
840 					"out gl_PerVertex { vec4 gl_Position; float gl_PointSize; };\n"
841 					"in gl_PerVertex { vec4 gl_Position; float gl_PointSize; } gl_in[gl_MaxPatchVertices];\n"
842 					"void main() \n"
843 					"{\n"
844 					"  float u = gl_TessCoord.x;\n"
845 					"  float v = gl_TessCoord.y;\n"
846 					"  float w = gl_TessCoord.z;\n"
847 					"  vec4 pos = vec4(0);\n"
848 					"  vec4 color = vec4(0);\n"
849 					"  pos.xyz += u * gl_in[0].gl_Position.xyz;\n"
850 					"  color.xyz += u * colors[0].xyz;\n"
851 					"  pos.xyz += v * gl_in[1].gl_Position.xyz;\n"
852 					"  color.xyz += v * colors[1].xyz;\n"
853 					"  pos.xyz += w * gl_in[2].gl_Position.xyz;\n"
854 					"  color.xyz += w * colors[2].xyz;\n"
855 					"  pos.w = 1.0;\n"
856 					"  color.w = 1.0;\n"
857 					"  gl_Position = pos;\n"
858 					"  gl_PointSize = gl_in[0].gl_PointSize;"
859 					"  vtxColor = color;\n"
860 					"}\n");
861 	}
862 }
863 
createInstance(Context& context) const864 TestInstance* GraphicsExecutablePropertiesTest::createInstance (Context& context) const
865 {
866 	return new GraphicsExecutablePropertiesTestInstance(context, &m_param);
867 }
868 
checkSupport(Context& context) const869 void GraphicsExecutablePropertiesTest::checkSupport(Context& context) const
870 {
871 	VkShaderStageFlags			shaderFlags	= m_param.getShaderFlags();
872 	VkPhysicalDeviceFeatures	features	= context.getDeviceFeatures();
873 	if ((shaderFlags & VK_SHADER_STAGE_GEOMETRY_BIT) && (features.geometryShader == VK_FALSE))
874 		TCU_THROW(NotSupportedError, "Geometry Shader Not Supported");
875 	if ((shaderFlags & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) ||
876 		(shaderFlags & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT))
877 	{
878 		if (features.tessellationShader == VK_FALSE)
879 			TCU_THROW(NotSupportedError, "Tessellation Not Supported");
880 	}
881 
882 	checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(), m_param.getPipelineConstructionType());
883 }
884 
GraphicsExecutablePropertiesTestInstance(Context& context, const ExecutablePropertiesTestParam* param)885 GraphicsExecutablePropertiesTestInstance::GraphicsExecutablePropertiesTestInstance (Context&					context,
886 																const ExecutablePropertiesTestParam*	param)
887 	: ExecutablePropertiesTestInstance		(context, param)
888 	, m_renderSize							(32u, 32u)
889 	, m_colorFormat							(VK_FORMAT_R8G8B8A8_UNORM)
890 	, m_depthFormat							(VK_FORMAT_D16_UNORM)
891 	, m_pipelineWrapper
892 	{
893 		{ m_context.getInstanceInterface(), m_context.getDeviceInterface(), m_context.getPhysicalDevice(), m_context.getDevice(), m_context.getDeviceExtensions(), param->getPipelineConstructionType(),
894 						(param->getTestStatistics() ? deUint32(VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR) : 0u) },
895 		{ m_context.getInstanceInterface(), m_context.getDeviceInterface(), m_context.getPhysicalDevice(), m_context.getDevice(), m_context.getDeviceExtensions(),param->getPipelineConstructionType(),
896 						(param->getTestStatistics() ? deUint32(VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR) : 0u) |
897 						// Only check gather internal representations on the second pipeline.
898 						// This way, it's more obvious if they failed to capture due to the pipeline being cached.
899 						(param->getTestInternalRepresentations() ? deUint32(VK_PIPELINE_CREATE_CAPTURE_INTERNAL_REPRESENTATIONS_BIT_KHR) : 0u) },
900 	}
901 {
902 	const DeviceInterface&	vk				= m_context.getDeviceInterface();
903 	const VkDevice			vkDevice		= m_context.getDevice();
904 
905 	// Create pipeline layout
906 	{
907 		const VkPipelineLayoutCreateInfo pipelineLayoutParams =
908 		{
909 			VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,		// VkStructureType					sType;
910 			DE_NULL,											// const void*						pNext;
911 			0u,													// VkPipelineLayoutCreateFlags		flags;
912 			0u,													// deUint32							setLayoutCount;
913 			DE_NULL,											// const VkDescriptorSetLayout*		pSetLayouts;
914 			0u,													// deUint32							pushConstantRangeCount;
915 			DE_NULL												// const VkPushConstantRange*		pPushConstantRanges;
916 		};
917 
918 		m_pipelineLayout = PipelineLayoutWrapper(m_param->getPipelineConstructionType(), vk, vkDevice, &pipelineLayoutParams);
919 	}
920 
921 	// Create render pass
922 	m_renderPass = makeRenderPass(vk, vkDevice, m_colorFormat, m_depthFormat);
923 
924 	// Bind shader stages
925 	ShaderWrapper vertShaderModule = ShaderWrapper(vk, vkDevice, context.getBinaryCollection().get("color_vert"), 0);
926 	ShaderWrapper fragShaderModule = ShaderWrapper(vk, vkDevice, context.getBinaryCollection().get("color_frag"), 0);
927 	ShaderWrapper tescShaderModule;
928 	ShaderWrapper teseShaderModule;
929 	ShaderWrapper geomShaderModule;
930 
931 	VkShaderStageFlags shaderFlags = m_param->getShaderFlags();
932 	if (shaderFlags & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)
933 		tescShaderModule = ShaderWrapper(vk, vkDevice, context.getBinaryCollection().get("basic_tcs"), 0);
934 	if (shaderFlags & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)
935 		teseShaderModule = ShaderWrapper(vk, vkDevice, context.getBinaryCollection().get("basic_tes"), 0);
936 	if (shaderFlags & VK_SHADER_STAGE_GEOMETRY_BIT)
937 		geomShaderModule = ShaderWrapper(vk, vkDevice, context.getBinaryCollection().get("dummy_geo"), 0);
938 
939 	for (deUint32 ndx = 0; ndx < PIPELINE_CACHE_NDX_COUNT; ndx++)
940 		preparePipelineWrapper(m_pipelineWrapper[ndx], vertShaderModule, tescShaderModule, teseShaderModule, geomShaderModule, fragShaderModule);
941 }
942 
~GraphicsExecutablePropertiesTestInstance(void)943 GraphicsExecutablePropertiesTestInstance::~GraphicsExecutablePropertiesTestInstance (void)
944 {
945 }
946 
preparePipelineWrapper(GraphicsPipelineWrapper& gpw, ShaderWrapper vertShaderModule, ShaderWrapper tescShaderModule, ShaderWrapper teseShaderModule, ShaderWrapper geomShaderModule, ShaderWrapper fragShaderModule)947 void GraphicsExecutablePropertiesTestInstance::preparePipelineWrapper(GraphicsPipelineWrapper&		gpw,
948 																	  ShaderWrapper					vertShaderModule,
949 																	  ShaderWrapper					tescShaderModule,
950 																	  ShaderWrapper					teseShaderModule,
951 																	  ShaderWrapper					geomShaderModule,
952 																	  ShaderWrapper					fragShaderModule)
953 {
954 	// Create pipeline
955 	const VkVertexInputBindingDescription vertexInputBindingDescription =
956 	{
957 		0u,									// deUint32				binding;
958 		sizeof(Vertex4RGBA),				// deUint32				strideInBytes;
959 		VK_VERTEX_INPUT_RATE_VERTEX,		// VkVertexInputRate	inputRate;
960 	};
961 
962 	const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[2] =
963 	{
964 		{
965 			0u,									// deUint32 location;
966 			0u,									// deUint32 binding;
967 			VK_FORMAT_R32G32B32A32_SFLOAT,		// VkFormat format;
968 			0u									// deUint32 offsetInBytes;
969 		},
970 		{
971 			1u,									// deUint32 location;
972 			0u,									// deUint32 binding;
973 			VK_FORMAT_R32G32B32A32_SFLOAT,		// VkFormat format;
974 			DE_OFFSET_OF(Vertex4RGBA, color),	// deUint32 offsetInBytes;
975 		}
976 	};
977 
978 	const VkPipelineVertexInputStateCreateInfo vertexInputStateParams
979 	{
980 		VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,		// VkStructureType							sType;
981 		DE_NULL,														// const void*								pNext;
982 		0u,																// VkPipelineVertexInputStateCreateFlags	flags;
983 		1u,																// deUint32									vertexBindingDescriptionCount;
984 		&vertexInputBindingDescription,									// const VkVertexInputBindingDescription*	pVertexBindingDescriptions;
985 		2u,																// deUint32									vertexAttributeDescriptionCount;
986 		vertexInputAttributeDescriptions,								// const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
987 	};
988 
989 	const std::vector<VkViewport>	viewport{ makeViewport(m_renderSize) };
990 	const std::vector<VkRect2D>		scissor{ makeRect2D(m_renderSize) };
991 
992 	const VkPipelineColorBlendAttachmentState colorBlendAttachmentState
993 	{
994 		VK_FALSE,														// VkBool32		blendEnable;
995 		VK_BLEND_FACTOR_ONE,											// VkBlendFactor	srcColorBlendFactor;
996 		VK_BLEND_FACTOR_ZERO,											// VkBlendFactor	dstColorBlendFactor;
997 		VK_BLEND_OP_ADD,												// VkBlendOp		colorBlendOp;
998 		VK_BLEND_FACTOR_ONE,											// VkBlendFactor	srcAlphaBlendFactor;
999 		VK_BLEND_FACTOR_ZERO,											// VkBlendFactor	dstAlphaBlendFactor;
1000 		VK_BLEND_OP_ADD,												// VkBlendOp		alphaBlendOp;
1001 		VK_COLOR_COMPONENT_R_BIT |
1002 		VK_COLOR_COMPONENT_G_BIT |
1003 		VK_COLOR_COMPONENT_B_BIT |
1004 		VK_COLOR_COMPONENT_A_BIT										// VkColorComponentFlags    colorWriteMask;
1005 	};
1006 
1007 	const VkPipelineColorBlendStateCreateInfo colorBlendStateParams
1008 	{
1009 		VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,	// VkStructureType								sType;
1010 		DE_NULL,													// const void*									pNext;
1011 		0u,															// VkPipelineColorBlendStateCreateFlags			flags;
1012 		VK_FALSE,													// VkBool32										logicOpEnable;
1013 		VK_LOGIC_OP_COPY,											// VkLogicOp									logicOp;
1014 		1u,															// deUint32										attachmentCount;
1015 		&colorBlendAttachmentState,									// const VkPipelineColorBlendAttachmentState*	pAttachments;
1016 		{ 0.0f, 0.0f, 0.0f, 0.0f },									// float										blendConst[4];
1017 	};
1018 
1019 	VkPipelineDepthStencilStateCreateInfo depthStencilStateParams
1020 	{
1021 		VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType							sType;
1022 		DE_NULL,													// const void*								pNext;
1023 		0u,															// VkPipelineDepthStencilStateCreateFlags	flags;
1024 		VK_TRUE,													// VkBool32									depthTestEnable;
1025 		VK_TRUE,													// VkBool32									depthWriteEnable;
1026 		VK_COMPARE_OP_LESS_OR_EQUAL,								// VkCompareOp								depthCompareOp;
1027 		VK_FALSE,													// VkBool32									depthBoundsTestEnable;
1028 		VK_FALSE,													// VkBool32									stencilTestEnable;
1029 		// VkStencilOpState front;
1030 		{
1031 			VK_STENCIL_OP_KEEP,		// VkStencilOp	failOp;
1032 			VK_STENCIL_OP_KEEP,		// VkStencilOp	passOp;
1033 			VK_STENCIL_OP_KEEP,		// VkStencilOp	depthFailOp;
1034 			VK_COMPARE_OP_NEVER,	// VkCompareOp	compareOp;
1035 			0u,						// deUint32		compareMask;
1036 			0u,						// deUint32		writeMask;
1037 			0u,						// deUint32		reference;
1038 		},
1039 		// VkStencilOpState back;
1040 		{
1041 			VK_STENCIL_OP_KEEP,		// VkStencilOp	failOp;
1042 			VK_STENCIL_OP_KEEP,		// VkStencilOp	passOp;
1043 			VK_STENCIL_OP_KEEP,		// VkStencilOp	depthFailOp;
1044 			VK_COMPARE_OP_NEVER,	// VkCompareOp	compareOp;
1045 			0u,						// deUint32		compareMask;
1046 			0u,						// deUint32		writeMask;
1047 			0u,						// deUint32		reference;
1048 		},
1049 		0.0f,														// float									minDepthBounds;
1050 		1.0f,														// float									maxDepthBounds;
1051 	};
1052 
1053 	gpw.setDefaultTopology((!tescShaderModule.isSet()) ? VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST : VK_PRIMITIVE_TOPOLOGY_PATCH_LIST)
1054 	   .setDefaultRasterizationState()
1055 	   .setDefaultMultisampleState()
1056 	   .setupVertexInputState(&vertexInputStateParams)
1057 	   .setupPreRasterizationShaderState(viewport,
1058 			scissor,
1059 			m_pipelineLayout,
1060 			*m_renderPass,
1061 			0u,
1062 			vertShaderModule,
1063 			DE_NULL,
1064 			tescShaderModule,
1065 			teseShaderModule,
1066 			geomShaderModule)
1067 	   .setupFragmentShaderState(m_pipelineLayout, *m_renderPass, 0u, fragShaderModule, &depthStencilStateParams)
1068 	   .setupFragmentOutputState(*m_renderPass, 0u, &colorBlendStateParams)
1069 	   .setMonolithicPipelineLayout(m_pipelineLayout)
1070 	   .buildPipeline(*m_cache);
1071 }
1072 
1073 class ComputeExecutablePropertiesTest : public ExecutablePropertiesTest
1074 {
1075 public:
ComputeExecutablePropertiesTest(tcu::TestContext& testContext, const std::string& name, const ExecutablePropertiesTestParam* param)1076 							ComputeExecutablePropertiesTest	(tcu::TestContext&		testContext,
1077 													 const std::string&		name,
1078 													 const ExecutablePropertiesTestParam*	param)
1079 								: ExecutablePropertiesTest	(testContext, name, param)
1080 								{ }
~ComputeExecutablePropertiesTest(void)1081 	virtual					~ComputeExecutablePropertiesTest	(void) { }
1082 	virtual void			initPrograms			(SourceCollections&	programCollection) const;
1083 	virtual TestInstance*	createInstance			(Context&				context) const;
1084 };
1085 
1086 class ComputeExecutablePropertiesTestInstance : public ExecutablePropertiesTestInstance
1087 {
1088 public:
1089 							ComputeExecutablePropertiesTestInstance	(Context&				context,
1090 															 const ExecutablePropertiesTestParam*	param);
1091 	virtual					~ComputeExecutablePropertiesTestInstance	(void);
1092 protected:
1093 	void					buildDescriptorSets				(deUint32 ndx);
1094 	void					buildShader						(deUint32 ndx);
1095 	void					buildPipeline					(deUint32 ndx);
1096 protected:
1097 	Move<VkBuffer>					m_inputBuf;
1098 	de::MovePtr<Allocation>			m_inputBufferAlloc;
1099 	Move<VkShaderModule>			m_computeShaderModule[PIPELINE_CACHE_NDX_COUNT];
1100 
1101 	Move<VkBuffer>					m_outputBuf[PIPELINE_CACHE_NDX_COUNT];
1102 	de::MovePtr<Allocation>			m_outputBufferAlloc[PIPELINE_CACHE_NDX_COUNT];
1103 
1104 	Move<VkDescriptorPool>			m_descriptorPool[PIPELINE_CACHE_NDX_COUNT];
1105 	Move<VkDescriptorSetLayout>		m_descriptorSetLayout[PIPELINE_CACHE_NDX_COUNT];
1106 	Move<VkDescriptorSet>			m_descriptorSet[PIPELINE_CACHE_NDX_COUNT];
1107 
1108 	Move<VkPipelineLayout>			m_pipelineLayout[PIPELINE_CACHE_NDX_COUNT];
1109 };
1110 
initPrograms(SourceCollections& programCollection) const1111 void ComputeExecutablePropertiesTest::initPrograms (SourceCollections& programCollection) const
1112 {
1113 	programCollection.glslSources.add("basic_compute") << glu::ComputeSource(
1114 		"#version 310 es\n"
1115 		"layout(local_size_x = 1) in;\n"
1116 		"layout(std430) buffer;\n"
1117 		"layout(binding = 0) readonly buffer Input0\n"
1118 		"{\n"
1119 		"  vec4 elements[];\n"
1120 		"} input_data0;\n"
1121 		"layout(binding = 1) writeonly buffer Output\n"
1122 		"{\n"
1123 		"  vec4 elements[];\n"
1124 		"} output_data;\n"
1125 		"void main()\n"
1126 		"{\n"
1127 		"  uint ident = gl_GlobalInvocationID.x;\n"
1128 		"  output_data.elements[ident] = input_data0.elements[ident] * input_data0.elements[ident];\n"
1129 		"}");
1130 }
1131 
createInstance(Context& context) const1132 TestInstance* ComputeExecutablePropertiesTest::createInstance (Context& context) const
1133 {
1134 	return new ComputeExecutablePropertiesTestInstance(context, &m_param);
1135 }
1136 
buildDescriptorSets(deUint32 ndx)1137 void ComputeExecutablePropertiesTestInstance::buildDescriptorSets (deUint32 ndx)
1138 {
1139 	const DeviceInterface&	vk				= m_context.getDeviceInterface();
1140 	const VkDevice			vkDevice		= m_context.getDevice();
1141 
1142 	// Create descriptor set layout
1143 	DescriptorSetLayoutBuilder descLayoutBuilder;
1144 	for (deUint32 bindingNdx = 0u; bindingNdx < 2u; bindingNdx++)
1145 		descLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT);
1146 	m_descriptorSetLayout[ndx] = descLayoutBuilder.build(vk, vkDevice);
1147 }
1148 
buildShader(deUint32 ndx)1149 void ComputeExecutablePropertiesTestInstance::buildShader (deUint32 ndx)
1150 {
1151 	const DeviceInterface&	vk				= m_context.getDeviceInterface();
1152 	const VkDevice			vkDevice		= m_context.getDevice();
1153 
1154 	// Create compute shader
1155 	VkShaderModuleCreateInfo shaderModuleCreateInfo =
1156 	{
1157 		VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,									// VkStructureType				sType;
1158 		DE_NULL,																		// const void*					pNext;
1159 		0u,																				// VkShaderModuleCreateFlags	flags;
1160 		m_context.getBinaryCollection().get("basic_compute").getSize(),					// deUintptr					codeSize;
1161 		(deUint32*)m_context.getBinaryCollection().get("basic_compute").getBinary(),	// const deUint32*				pCode;
1162 	};
1163 	m_computeShaderModule[ndx] = createShaderModule(vk, vkDevice, &shaderModuleCreateInfo);
1164 }
1165 
buildPipeline(deUint32 ndx)1166 void ComputeExecutablePropertiesTestInstance::buildPipeline (deUint32 ndx)
1167 {
1168 	const DeviceInterface&	vk				 = m_context.getDeviceInterface();
1169 	const VkDevice			vkDevice		 = m_context.getDevice();
1170 
1171 	// Create compute pipeline layout
1172 	const VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo =
1173 	{
1174 		VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,					// VkStructureType					sType;
1175 		DE_NULL,														// const void*						pNext;
1176 		0u,																// VkPipelineLayoutCreateFlags		flags;
1177 		1u,																// deUint32							setLayoutCount;
1178 		&m_descriptorSetLayout[ndx].get(),								// const VkDescriptorSetLayout*		pSetLayouts;
1179 		0u,																// deUint32							pushConstantRangeCount;
1180 		DE_NULL,														// const VkPushConstantRange*		pPushConstantRanges;
1181 	};
1182 
1183 	m_pipelineLayout[ndx] = createPipelineLayout(vk, vkDevice, &pipelineLayoutCreateInfo);
1184 
1185 	const VkPipelineShaderStageCreateInfo stageCreateInfo =
1186 	{
1187 		VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,			// VkStructureType					sType;
1188 		DE_NULL,														// const void*						pNext;
1189 		0u,																// VkPipelineShaderStageCreateFlags	flags;
1190 		VK_SHADER_STAGE_COMPUTE_BIT,									// VkShaderStageFlagBits			stage;
1191 		*m_computeShaderModule[ndx],									// VkShaderModule					module;
1192 		"main",															// const char*						pName;
1193 		DE_NULL,														// const VkSpecializationInfo*		pSpecializationInfo;
1194 	};
1195 
1196 	VkPipelineCreateFlags flags = 0;
1197 	if (m_param->getTestStatistics())
1198 	{
1199 		flags |= VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR;
1200 	}
1201 
1202 	// Only check gather internal representations on the second
1203 	// pipeline.  This way, it's more obvious if they failed to capture
1204 	// due to the pipeline being cached.
1205 	if (ndx == PIPELINE_CACHE_NDX_CACHED && m_param->getTestInternalRepresentations())
1206 	{
1207 		flags |= VK_PIPELINE_CREATE_CAPTURE_INTERNAL_REPRESENTATIONS_BIT_KHR;
1208 	}
1209 
1210 	const VkComputePipelineCreateInfo pipelineCreateInfo =
1211 	{
1212 		VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,				// VkStructureType					sType;
1213 		DE_NULL,													// const void*						pNext;
1214 		flags,														// VkPipelineCreateFlags			flags;
1215 		stageCreateInfo,											// VkPipelineShaderStageCreateInfo	stage;
1216 		*m_pipelineLayout[ndx],										// VkPipelineLayout					layout;
1217 		(VkPipeline)0,												// VkPipeline						basePipelineHandle;
1218 		0u,															// deInt32							basePipelineIndex;
1219 	};
1220 
1221 	m_pipeline[ndx] = createComputePipeline(vk, vkDevice, *m_cache, &pipelineCreateInfo, DE_NULL);
1222 }
1223 
ComputeExecutablePropertiesTestInstance(Context& context, const ExecutablePropertiesTestParam* param)1224 ComputeExecutablePropertiesTestInstance::ComputeExecutablePropertiesTestInstance (Context&				context,
1225 													const ExecutablePropertiesTestParam*	param)
1226 	: ExecutablePropertiesTestInstance (context, param)
1227 {
1228 	for (deUint32 ndx = 0; ndx < PIPELINE_CACHE_NDX_COUNT; ndx++)
1229 	{
1230 		buildDescriptorSets(ndx);
1231 		buildShader(ndx);
1232 		buildPipeline(ndx);
1233 	}
1234 }
1235 
~ComputeExecutablePropertiesTestInstance(void)1236 ComputeExecutablePropertiesTestInstance::~ComputeExecutablePropertiesTestInstance (void)
1237 {
1238 }
1239 
1240 } // anonymous
1241 
createExecutablePropertiesTests(tcu::TestContext& testCtx, PipelineConstructionType pipelineConstructionType)1242 tcu::TestCaseGroup* createExecutablePropertiesTests (tcu::TestContext& testCtx, PipelineConstructionType pipelineConstructionType)
1243 {
1244 
1245 	de::MovePtr<tcu::TestCaseGroup> binaryInfoTests (new tcu::TestCaseGroup(testCtx, "executable_properties"));
1246 
1247 	// Graphics Pipeline Tests
1248 	{
1249 		de::MovePtr<tcu::TestCaseGroup> graphicsTests (new tcu::TestCaseGroup(testCtx, "graphics"));
1250 
1251 		const VkShaderStageFlags vertFragStages		= VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
1252 		const VkShaderStageFlags vertGeomFragStages	= vertFragStages | VK_SHADER_STAGE_GEOMETRY_BIT;
1253 		const VkShaderStageFlags vertTessFragStages	= vertFragStages | VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
1254 
1255 		const ExecutablePropertiesTestParam testParams[]
1256 		{
1257 			{ pipelineConstructionType, vertFragStages,		DE_FALSE, DE_FALSE },
1258 			{ pipelineConstructionType, vertGeomFragStages,	DE_FALSE, DE_FALSE },
1259 			{ pipelineConstructionType, vertTessFragStages,	DE_FALSE, DE_FALSE },
1260 			{ pipelineConstructionType, vertFragStages,		DE_TRUE, DE_FALSE },
1261 			{ pipelineConstructionType, vertGeomFragStages,	DE_TRUE, DE_FALSE },
1262 			{ pipelineConstructionType, vertTessFragStages,	DE_TRUE, DE_FALSE },
1263 			{ pipelineConstructionType, vertFragStages,		DE_FALSE, DE_TRUE },
1264 			{ pipelineConstructionType, vertGeomFragStages,	DE_FALSE, DE_TRUE },
1265 			{ pipelineConstructionType, vertTessFragStages,	DE_FALSE, DE_TRUE },
1266 			{ pipelineConstructionType, vertFragStages,		DE_TRUE, DE_TRUE },
1267 			{ pipelineConstructionType, vertGeomFragStages,	DE_TRUE, DE_TRUE },
1268 			{ pipelineConstructionType, vertTessFragStages,	DE_TRUE, DE_TRUE },
1269 		};
1270 
1271 		for (deUint32 i = 0; i < DE_LENGTH_OF_ARRAY(testParams); i++)
1272 			graphicsTests->addChild(newTestCase<GraphicsExecutablePropertiesTest>(testCtx, &testParams[i]));
1273 
1274 		binaryInfoTests->addChild(graphicsTests.release());
1275 	}
1276 
1277 	// Compute Pipeline Tests - don't repeat those tests for graphics pipeline library
1278 	if (pipelineConstructionType == PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC)
1279 	{
1280 		de::MovePtr<tcu::TestCaseGroup> computeTests (new tcu::TestCaseGroup(testCtx, "compute"));
1281 
1282 		const ExecutablePropertiesTestParam testParams[]
1283 		{
1284 			{ pipelineConstructionType, VK_SHADER_STAGE_COMPUTE_BIT, DE_FALSE, DE_FALSE },
1285 			{ pipelineConstructionType, VK_SHADER_STAGE_COMPUTE_BIT, DE_TRUE, DE_FALSE },
1286 			{ pipelineConstructionType, VK_SHADER_STAGE_COMPUTE_BIT, DE_FALSE, DE_TRUE },
1287 			{ pipelineConstructionType, VK_SHADER_STAGE_COMPUTE_BIT, DE_TRUE, DE_TRUE },
1288 		};
1289 
1290 		for (deUint32 i = 0; i < DE_LENGTH_OF_ARRAY(testParams); i++)
1291 			computeTests->addChild(newTestCase<ComputeExecutablePropertiesTest>(testCtx, &testParams[i]));
1292 
1293 		binaryInfoTests->addChild(computeTests.release());
1294 	}
1295 
1296 	return binaryInfoTests.release();
1297 }
1298 
1299 } // pipeline
1300 
1301 } // vkt
1302