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
78namespace vkt
79{
80namespace pipeline
81{
82
83using namespace vk;
84
85namespace
86{
87enum
88{
89	VK_MAX_SHADER_STAGES = 6,
90};
91
92enum
93{
94	PIPELINE_CACHE_NDX_INITIAL = 0,
95	PIPELINE_CACHE_NDX_CACHED = 1,
96	PIPELINE_CACHE_NDX_COUNT,
97};
98
99// helper functions
100
101std::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
124std::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
154class ExecutablePropertiesTestParam
155{
156public:
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;
163	PipelineConstructionType	getPipelineConstructionType		(void)	const	{ return m_pipelineConstructionType; }
164	VkShaderStageFlags			getShaderFlags					(void)	const	{ return m_shaders; }
165	deBool						getTestStatistics				(void)	const	{ return m_testStatistics; }
166	deBool						getTestInternalRepresentations	(void)	const	{ return m_testInternalRepresentations; }
167
168protected:
169	PipelineConstructionType	m_pipelineConstructionType;
170	VkShaderStageFlags			m_shaders;
171	bool						m_testStatistics;
172	bool						m_testInternalRepresentations;
173};
174
175ExecutablePropertiesTestParam::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
183const 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
195template <class Test>
196vkt::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
205class ExecutablePropertiesTest : public vkt::TestCase
206{
207public:
208							ExecutablePropertiesTest(tcu::TestContext&		testContext,
209										   const std::string&		name,
210										   const ExecutablePropertiesTestParam*	param)
211								: vkt::TestCase (testContext, name)
212								, m_param (*param)
213								{ }
214	virtual					~ExecutablePropertiesTest (void) { }
215protected:
216	const ExecutablePropertiesTestParam	m_param;
217};
218
219class ExecutablePropertiesTestInstance : public vkt::TestInstance
220{
221public:
222							ExecutablePropertiesTestInstance			(Context&				context,
223															 const ExecutablePropertiesTestParam*	param);
224	virtual					~ExecutablePropertiesTestInstance			(void);
225	virtual tcu::TestStatus iterate							(void);
226protected:
227	virtual tcu::TestStatus verifyStatistics				(deUint32 binaryNdx);
228	virtual tcu::TestStatus verifyInternalRepresentations	(deUint32 binaryNdx);
229	virtual tcu::TestStatus verifyTestResult				(void);
230protected:
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
238	virtual VkPipeline		getPipeline(deUint32 ndx) { return m_pipeline[ndx].get(); }
239};
240
241ExecutablePropertiesTestInstance::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
262ExecutablePropertiesTestInstance::~ExecutablePropertiesTestInstance (void)
263{
264}
265
266tcu::TestStatus ExecutablePropertiesTestInstance::iterate (void)
267{
268	return verifyTestResult();
269}
270
271bool
272checkString(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
292tcu::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
450tcu::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
578tcu::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
728class GraphicsExecutablePropertiesTest : public ExecutablePropertiesTest
729{
730public:
731							GraphicsExecutablePropertiesTest	(tcu::TestContext&		testContext,
732													 const std::string&	name,
733													 const ExecutablePropertiesTestParam*	param)
734								: ExecutablePropertiesTest (testContext, name, param)
735								{ }
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
742class GraphicsExecutablePropertiesTestInstance : public ExecutablePropertiesTestInstance
743{
744public:
745							GraphicsExecutablePropertiesTestInstance	(Context&								context,
746																		 const ExecutablePropertiesTestParam*	param);
747	virtual					~GraphicsExecutablePropertiesTestInstance	(void);
748
749protected:
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
762protected:
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
771void 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
864TestInstance* GraphicsExecutablePropertiesTest::createInstance (Context& context) const
865{
866	return new GraphicsExecutablePropertiesTestInstance(context, &m_param);
867}
868
869void 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
885GraphicsExecutablePropertiesTestInstance::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
943GraphicsExecutablePropertiesTestInstance::~GraphicsExecutablePropertiesTestInstance (void)
944{
945}
946
947void 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
1073class ComputeExecutablePropertiesTest : public ExecutablePropertiesTest
1074{
1075public:
1076							ComputeExecutablePropertiesTest	(tcu::TestContext&		testContext,
1077													 const std::string&		name,
1078													 const ExecutablePropertiesTestParam*	param)
1079								: ExecutablePropertiesTest	(testContext, name, param)
1080								{ }
1081	virtual					~ComputeExecutablePropertiesTest	(void) { }
1082	virtual void			initPrograms			(SourceCollections&	programCollection) const;
1083	virtual TestInstance*	createInstance			(Context&				context) const;
1084};
1085
1086class ComputeExecutablePropertiesTestInstance : public ExecutablePropertiesTestInstance
1087{
1088public:
1089							ComputeExecutablePropertiesTestInstance	(Context&				context,
1090															 const ExecutablePropertiesTestParam*	param);
1091	virtual					~ComputeExecutablePropertiesTestInstance	(void);
1092protected:
1093	void					buildDescriptorSets				(deUint32 ndx);
1094	void					buildShader						(deUint32 ndx);
1095	void					buildPipeline					(deUint32 ndx);
1096protected:
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
1111void 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
1132TestInstance* ComputeExecutablePropertiesTest::createInstance (Context& context) const
1133{
1134	return new ComputeExecutablePropertiesTestInstance(context, &m_param);
1135}
1136
1137void 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
1149void 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
1166void 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
1224ComputeExecutablePropertiesTestInstance::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
1236ComputeExecutablePropertiesTestInstance::~ComputeExecutablePropertiesTestInstance (void)
1237{
1238}
1239
1240} // anonymous
1241
1242tcu::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