• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*-------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2016 Google Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Utility for pre-compiling source programs to SPIR-V
22  *//*--------------------------------------------------------------------*/
23 
24 #include "tcuDefs.hpp"
25 #include "tcuCommandLine.hpp"
26 #include "tcuPlatform.hpp"
27 #include "tcuResource.hpp"
28 #include "tcuTestLog.hpp"
29 #include "tcuTestHierarchyIterator.hpp"
30 #include "deUniquePtr.hpp"
31 #include "vkPrograms.hpp"
32 #include "vkBinaryRegistry.hpp"
33 #include "vktTestCase.hpp"
34 #include "vktTestPackage.hpp"
35 #include "deUniquePtr.hpp"
36 #include "deCommandLine.hpp"
37 #include "deSharedPtr.hpp"
38 #include "deThread.hpp"
39 #include "deThreadSafeRingBuffer.hpp"
40 #include "dePoolArray.hpp"
41 
42 #include <iostream>
43 
44 using std::vector;
45 using std::string;
46 using de::UniquePtr;
47 using de::MovePtr;
48 using de::SharedPtr;
49 
50 namespace vkt
51 {
52 
53 namespace // anonymous
54 {
55 
56 typedef de::SharedPtr<glu::ProgramSources>	ProgramSourcesSp;
57 typedef de::SharedPtr<vk::SpirVAsmSource>	SpirVAsmSourceSp;
58 typedef de::SharedPtr<vk::ProgramBinary>	ProgramBinarySp;
59 
60 class Task
61 {
62 public:
63 	virtual void	execute		(void) = 0;
64 };
65 
66 typedef de::ThreadSafeRingBuffer<Task*>	TaskQueue;
67 
68 class TaskExecutorThread : public de::Thread
69 {
70 public:
TaskExecutorThread(TaskQueue & tasks)71 	TaskExecutorThread (TaskQueue& tasks)
72 		: m_tasks(tasks)
73 	{
74 		start();
75 	}
76 
run(void)77 	void run (void)
78 	{
79 		for (;;)
80 		{
81 			Task* const	task	= m_tasks.popBack();
82 
83 			if (task)
84 				task->execute();
85 			else
86 				break; // End of tasks - time to terminate
87 		}
88 	}
89 
90 private:
91 	TaskQueue&	m_tasks;
92 };
93 
94 class TaskExecutor
95 {
96 public:
97 								TaskExecutor		(deUint32 numThreads);
98 								~TaskExecutor		(void);
99 
100 	void						submit				(Task* task);
101 	void						waitForComplete		(void);
102 
103 private:
104 	typedef de::SharedPtr<TaskExecutorThread>	ExecThreadSp;
105 
106 	std::vector<ExecThreadSp>	m_threads;
107 	TaskQueue					m_tasks;
108 };
109 
TaskExecutor(deUint32 numThreads)110 TaskExecutor::TaskExecutor (deUint32 numThreads)
111 	: m_threads	(numThreads)
112 	, m_tasks	(m_threads.size() * 1024u)
113 {
114 	for (size_t ndx = 0; ndx < m_threads.size(); ++ndx)
115 		m_threads[ndx] = ExecThreadSp(new TaskExecutorThread(m_tasks));
116 }
117 
~TaskExecutor(void)118 TaskExecutor::~TaskExecutor (void)
119 {
120 	for (size_t ndx = 0; ndx < m_threads.size(); ++ndx)
121 		m_tasks.pushFront(DE_NULL);
122 
123 	for (size_t ndx = 0; ndx < m_threads.size(); ++ndx)
124 		m_threads[ndx]->join();
125 }
126 
submit(Task * task)127 void TaskExecutor::submit (Task* task)
128 {
129 	DE_ASSERT(task);
130 	m_tasks.pushFront(task);
131 }
132 
133 class SyncTask : public Task
134 {
135 public:
SyncTask(de::Semaphore * enterBarrier,de::Semaphore * inBarrier,de::Semaphore * leaveBarrier)136 	SyncTask (de::Semaphore* enterBarrier, de::Semaphore* inBarrier, de::Semaphore* leaveBarrier)
137 		: m_enterBarrier	(enterBarrier)
138 		, m_inBarrier		(inBarrier)
139 		, m_leaveBarrier	(leaveBarrier)
140 	{}
141 
SyncTask(void)142 	SyncTask (void)
143 		: m_enterBarrier	(DE_NULL)
144 		, m_inBarrier		(DE_NULL)
145 		, m_leaveBarrier	(DE_NULL)
146 	{}
147 
execute(void)148 	void execute (void)
149 	{
150 		m_enterBarrier->increment();
151 		m_inBarrier->decrement();
152 		m_leaveBarrier->increment();
153 	}
154 
155 private:
156 	de::Semaphore*	m_enterBarrier;
157 	de::Semaphore*	m_inBarrier;
158 	de::Semaphore*	m_leaveBarrier;
159 };
160 
waitForComplete(void)161 void TaskExecutor::waitForComplete (void)
162 {
163 	de::Semaphore			enterBarrier	(0);
164 	de::Semaphore			inBarrier		(0);
165 	de::Semaphore			leaveBarrier	(0);
166 	std::vector<SyncTask>	syncTasks		(m_threads.size());
167 
168 	for (size_t ndx = 0; ndx < m_threads.size(); ++ndx)
169 	{
170 		syncTasks[ndx] = SyncTask(&enterBarrier, &inBarrier, &leaveBarrier);
171 		submit(&syncTasks[ndx]);
172 	}
173 
174 	for (size_t ndx = 0; ndx < m_threads.size(); ++ndx)
175 		enterBarrier.decrement();
176 
177 	for (size_t ndx = 0; ndx < m_threads.size(); ++ndx)
178 		inBarrier.increment();
179 
180 	for (size_t ndx = 0; ndx < m_threads.size(); ++ndx)
181 		leaveBarrier.decrement();
182 }
183 
184 struct Program
185 {
186 	enum Status
187 	{
188 		STATUS_NOT_COMPLETED = 0,
189 		STATUS_FAILED,
190 		STATUS_PASSED,
191 
192 		STATUS_LAST
193 	};
194 
195 	vk::ProgramIdentifier	id;
196 
197 	Status					buildStatus;
198 	std::string				buildLog;
199 	ProgramBinarySp			binary;
200 
201 	Status					validationStatus;
202 	std::string				validationLog;
203 
204 	vk::SpirvValidatorOptions	validatorOptions;
205 
Programvkt::__anon1d453d900111::Program206 	explicit				Program		(const vk::ProgramIdentifier& id_, const vk::SpirvValidatorOptions& valOptions_)
207 								: id				(id_)
208 								, buildStatus		(STATUS_NOT_COMPLETED)
209 								, validationStatus	(STATUS_NOT_COMPLETED)
210 								, validatorOptions	(valOptions_)
211 							{}
Programvkt::__anon1d453d900111::Program212 							Program		(void)
213 								: id				("", "")
214 								, buildStatus		(STATUS_NOT_COMPLETED)
215 								, validationStatus	(STATUS_NOT_COMPLETED)
216 								, validatorOptions()
217 							{}
218 };
219 
writeBuildLogs(const glu::ShaderProgramInfo & buildInfo,std::ostream & dst)220 void writeBuildLogs (const glu::ShaderProgramInfo& buildInfo, std::ostream& dst)
221 {
222 	for (size_t shaderNdx = 0; shaderNdx < buildInfo.shaders.size(); shaderNdx++)
223 	{
224 		const glu::ShaderInfo&	shaderInfo	= buildInfo.shaders[shaderNdx];
225 		const char* const		shaderName	= getShaderTypeName(shaderInfo.type);
226 
227 		dst << shaderName << " source:\n"
228 			<< "---\n"
229 			<< shaderInfo.source << "\n"
230 			<< "---\n"
231 			<< shaderName << " compile log:\n"
232 			<< "---\n"
233 			<< shaderInfo.infoLog << "\n"
234 			<< "---\n";
235 	}
236 
237 	dst << "link log:\n"
238 		<< "---\n"
239 		<< buildInfo.program.infoLog << "\n"
240 		<< "---\n";
241 }
242 
243 template <typename Source>
244 class BuildHighLevelShaderTask : public Task
245 {
246 public:
247 
BuildHighLevelShaderTask(const Source & source,Program * program)248 	BuildHighLevelShaderTask (const Source& source, Program* program)
249 		: m_source		(source)
250 		, m_program		(program)
251 		, m_commandLine	(0)
252 	{}
253 
BuildHighLevelShaderTask(void)254 	BuildHighLevelShaderTask (void) : m_program(DE_NULL) {}
255 
setCommandline(const tcu::CommandLine & commandLine)256 	void setCommandline (const tcu::CommandLine &commandLine)
257 	{
258 		m_commandLine = &commandLine;
259 	}
260 
execute(void)261 	void execute (void)
262 	{
263 		glu::ShaderProgramInfo buildInfo;
264 
265 		try
266 		{
267 			DE_ASSERT(m_source.buildOptions.targetVersion < vk::SPIRV_VERSION_LAST);
268 			DE_ASSERT(m_commandLine != DE_NULL);
269 			m_program->binary			= ProgramBinarySp(vk::buildProgram(m_source, &buildInfo, *m_commandLine));
270 			m_program->buildStatus		= Program::STATUS_PASSED;
271 			m_program->validatorOptions	= m_source.buildOptions.getSpirvValidatorOptions();
272 		}
273 		catch (const tcu::Exception&)
274 		{
275 			std::ostringstream log;
276 
277 			writeBuildLogs(buildInfo, log);
278 
279 			m_program->buildStatus	= Program::STATUS_FAILED;
280 			m_program->buildLog		= log.str();
281 		}
282 	}
283 
284 private:
285 	Source					m_source;
286 	Program*				m_program;
287 	const tcu::CommandLine*	m_commandLine;
288 };
289 
writeBuildLogs(const vk::SpirVProgramInfo & buildInfo,std::ostream & dst)290 void writeBuildLogs (const vk::SpirVProgramInfo& buildInfo, std::ostream& dst)
291 {
292 	dst << "source:\n"
293 		<< "---\n"
294 		<< buildInfo.source << "\n"
295 		<< "---\n"
296 		<< buildInfo.infoLog << "\n"
297 		<< "---\n";
298 }
299 
300 class BuildSpirVAsmTask : public Task
301 {
302 public:
BuildSpirVAsmTask(const vk::SpirVAsmSource & source,Program * program)303 	BuildSpirVAsmTask (const vk::SpirVAsmSource& source, Program* program)
304 		: m_source		(source)
305 		, m_program		(program)
306 		, m_commandLine	(0)
307 	{}
308 
BuildSpirVAsmTask(void)309 	BuildSpirVAsmTask (void) : m_program(DE_NULL), m_commandLine(0) {}
310 
setCommandline(const tcu::CommandLine & commandLine)311 	void setCommandline (const tcu::CommandLine &commandLine)
312 	{
313 		m_commandLine = &commandLine;
314 	}
315 
execute(void)316 	void execute (void)
317 	{
318 		vk::SpirVProgramInfo buildInfo;
319 
320 		try
321 		{
322 			DE_ASSERT(m_source.buildOptions.targetVersion < vk::SPIRV_VERSION_LAST);
323 			DE_ASSERT(m_commandLine != DE_NULL);
324 			m_program->binary		= ProgramBinarySp(vk::assembleProgram(m_source, &buildInfo, *m_commandLine));
325 			m_program->buildStatus	= Program::STATUS_PASSED;
326 		}
327 		catch (const tcu::Exception&)
328 		{
329 			std::ostringstream log;
330 
331 			writeBuildLogs(buildInfo, log);
332 
333 			m_program->buildStatus	= Program::STATUS_FAILED;
334 			m_program->buildLog		= log.str();
335 		}
336 	}
337 
338 private:
339 	vk::SpirVAsmSource		m_source;
340 	Program*				m_program;
341 	const tcu::CommandLine*	m_commandLine;
342 };
343 
344 class ValidateBinaryTask : public Task
345 {
346 public:
ValidateBinaryTask(Program * program)347 	ValidateBinaryTask (Program* program)
348 		: m_program(program)
349 	{}
350 
execute(void)351 	void execute (void)
352 	{
353 		DE_ASSERT(m_program->buildStatus == Program::STATUS_PASSED);
354 		DE_ASSERT(m_program->binary->getFormat() == vk::PROGRAM_FORMAT_SPIRV);
355 
356 		std::ostringstream			validationLogStream;
357 
358 		if (vk::validateProgram(*m_program->binary, &validationLogStream, m_program->validatorOptions))
359 			m_program->validationStatus = Program::STATUS_PASSED;
360 		else
361 			m_program->validationStatus = Program::STATUS_FAILED;
362 		m_program->validationLog = validationLogStream.str();
363 	}
364 
365 private:
366 	Program*	m_program;
367 };
368 
createRoot(tcu::TestContext & testCtx)369 tcu::TestPackageRoot* createRoot (tcu::TestContext& testCtx)
370 {
371 	vector<tcu::TestNode*>	children;
372 	children.push_back(new TestPackage(testCtx));
373 	return new tcu::TestPackageRoot(testCtx, children);
374 }
375 
376 } // anonymous
377 
378 struct BuildStats
379 {
380 	int		numSucceeded;
381 	int		numFailed;
382 	int		notSupported;
383 
BuildStatsvkt::BuildStats384 	BuildStats (void)
385 		: numSucceeded	(0)
386 		, numFailed		(0)
387 		, notSupported	(0)
388 	{
389 	}
390 };
391 
buildPrograms(tcu::TestContext & testCtx,const std::string & dstPath,const bool validateBinaries,const deUint32 usedVulkanVersion,const vk::SpirvVersion baselineSpirvVersion,const vk::SpirvVersion maxSpirvVersion,const bool allowSpirV14)392 BuildStats buildPrograms (tcu::TestContext&			testCtx,
393 						  const std::string&		dstPath,
394 						  const bool				validateBinaries,
395 						  const deUint32			usedVulkanVersion,
396 						  const vk::SpirvVersion	baselineSpirvVersion,
397 						  const vk::SpirvVersion	maxSpirvVersion,
398 						  const bool				allowSpirV14)
399 {
400 	const deUint32						numThreads			= deGetNumAvailableLogicalCores();
401 	const size_t						numNodesInChunk		= 500000;
402 
403 	const UniquePtr<tcu::TestPackageRoot>	root			(createRoot(testCtx));
404 	tcu::DefaultHierarchyInflater			inflater		(testCtx);
405 	de::MovePtr<tcu::CaseListFilter>		caseListFilter	(testCtx.getCommandLine().createCaseListFilter(testCtx.getArchive()));
406 	tcu::TestHierarchyIterator				iterator		(*root, inflater, *caseListFilter);
407 	BuildStats	stats;
408 	int notSupported = 0;
409 
410 	while (iterator.getState() != tcu::TestHierarchyIterator::STATE_FINISHED)
411 	{
412 
413 		TaskExecutor						executor			(numThreads);
414 
415 		// de::PoolArray<> is faster to build than std::vector
416 		de::MemPool							programPool;
417 		de::PoolArray<Program>				programs			(&programPool);
418 
419 		de::MemPool							tmpPool;
420 		de::PoolArray<BuildHighLevelShaderTask<vk::GlslSource> >	buildGlslTasks		(&tmpPool);
421 		de::PoolArray<BuildHighLevelShaderTask<vk::HlslSource> >	buildHlslTasks		(&tmpPool);
422 		de::PoolArray<BuildSpirVAsmTask>	buildSpirvAsmTasks	(&tmpPool);
423 
424 		// Collect build tasks. We perform tests in chunks to reduce memory usage
425 		size_t numNodesAdded = 0;
426 		while (iterator.getState() != tcu::TestHierarchyIterator::STATE_FINISHED && numNodesAdded < numNodesInChunk)
427 		{
428 			if (iterator.getState() == tcu::TestHierarchyIterator::STATE_ENTER_NODE &&
429 				tcu::isTestNodeTypeExecutable(iterator.getNode()->getNodeType()))
430 			{
431 				numNodesAdded++;
432 				TestCase* const				testCase					= dynamic_cast<TestCase*>(iterator.getNode());
433 				const string				casePath					= iterator.getNodePath();
434 				vk::ShaderBuildOptions		defaultGlslBuildOptions		(usedVulkanVersion, baselineSpirvVersion, 0u);
435 				vk::ShaderBuildOptions		defaultHlslBuildOptions		(usedVulkanVersion, baselineSpirvVersion, 0u);
436 				vk::SpirVAsmBuildOptions	defaultSpirvAsmBuildOptions	(usedVulkanVersion, baselineSpirvVersion);
437 				vk::SourceCollections		sourcePrograms				(usedVulkanVersion, defaultGlslBuildOptions, defaultHlslBuildOptions, defaultSpirvAsmBuildOptions);
438 
439 				try
440 				{
441 					testCase->delayedInit();
442 					testCase->initPrograms(sourcePrograms);
443 				}
444 				catch (const tcu::NotSupportedError& )
445 				{
446 					notSupported++;
447 					iterator.next();
448 					continue;
449 				}
450 
451 				for (vk::GlslSourceCollection::Iterator progIter = sourcePrograms.glslSources.begin();
452 						progIter != sourcePrograms.glslSources.end();
453 						++progIter)
454 				{
455 					// Source program requires higher SPIR-V version than available: skip it to avoid fail
456 					// Unless this is SPIR-V 1.4 and is explicitly allowed.
457 					if (progIter.getProgram().buildOptions.targetVersion > maxSpirvVersion && !(allowSpirV14 && progIter.getProgram().buildOptions.supports_VK_KHR_spirv_1_4 && progIter.getProgram().buildOptions.targetVersion == vk::SPIRV_VERSION_1_4))
458 						continue;
459 
460 					programs.pushBack(Program(vk::ProgramIdentifier(casePath, progIter.getName()), progIter.getProgram().buildOptions.getSpirvValidatorOptions()));
461 					buildGlslTasks.pushBack(BuildHighLevelShaderTask<vk::GlslSource>(progIter.getProgram(), &programs.back()));
462 					buildGlslTasks.back().setCommandline(testCtx.getCommandLine());
463 					executor.submit(&buildGlslTasks.back());
464 				}
465 
466 				for (vk::HlslSourceCollection::Iterator progIter = sourcePrograms.hlslSources.begin();
467 						progIter != sourcePrograms.hlslSources.end();
468 						++progIter)
469 				{
470 					// Source program requires higher SPIR-V version than available: skip it to avoid fail
471 					// Unless this is SPIR-V 1.4 and is explicitly allowed.
472 					if (progIter.getProgram().buildOptions.targetVersion > maxSpirvVersion && !(allowSpirV14 && progIter.getProgram().buildOptions.supports_VK_KHR_spirv_1_4 && progIter.getProgram().buildOptions.targetVersion == vk::SPIRV_VERSION_1_4))
473 						continue;
474 
475 					programs.pushBack(Program(vk::ProgramIdentifier(casePath, progIter.getName()), progIter.getProgram().buildOptions.getSpirvValidatorOptions()));
476 					buildHlslTasks.pushBack(BuildHighLevelShaderTask<vk::HlslSource>(progIter.getProgram(), &programs.back()));
477 					buildHlslTasks.back().setCommandline(testCtx.getCommandLine());
478 					executor.submit(&buildHlslTasks.back());
479 				}
480 
481 				for (vk::SpirVAsmCollection::Iterator progIter = sourcePrograms.spirvAsmSources.begin();
482 						progIter != sourcePrograms.spirvAsmSources.end();
483 						++progIter)
484 				{
485 					// Source program requires higher SPIR-V version than available: skip it to avoid fail
486 					// Unless this is SPIR-V 1.4 and is explicitly allowed.
487 					if (progIter.getProgram().buildOptions.targetVersion > maxSpirvVersion && !(allowSpirV14 && progIter.getProgram().buildOptions.supports_VK_KHR_spirv_1_4 && progIter.getProgram().buildOptions.targetVersion == vk::SPIRV_VERSION_1_4))
488 						continue;
489 
490 					programs.pushBack(Program(vk::ProgramIdentifier(casePath, progIter.getName()), progIter.getProgram().buildOptions.getSpirvValidatorOptions()));
491 					buildSpirvAsmTasks.pushBack(BuildSpirVAsmTask(progIter.getProgram(), &programs.back()));
492 					buildSpirvAsmTasks.back().setCommandline(testCtx.getCommandLine());
493 					executor.submit(&buildSpirvAsmTasks.back());
494 				}
495 			}
496 
497 			iterator.next();
498 		}
499 
500 		// Need to wait until tasks completed before freeing task memory
501 		executor.waitForComplete();
502 
503 		if (validateBinaries)
504 		{
505 			std::vector<ValidateBinaryTask>	validationTasks;
506 
507 			validationTasks.reserve(programs.size());
508 
509 			for (de::PoolArray<Program>::iterator progIter = programs.begin(); progIter != programs.end(); ++progIter)
510 			{
511 				if (progIter->buildStatus == Program::STATUS_PASSED)
512 				{
513 					validationTasks.push_back(ValidateBinaryTask(&*progIter));
514 					executor.submit(&validationTasks.back());
515 				}
516 			}
517 
518 			executor.waitForComplete();
519 		}
520 
521 		{
522 			vk::BinaryRegistryWriter	registryWriter		(dstPath);
523 
524 			for (de::PoolArray<Program>::iterator progIter = programs.begin(); progIter != programs.end(); ++progIter)
525 			{
526 				if (progIter->buildStatus == Program::STATUS_PASSED)
527 					registryWriter.addProgram(progIter->id, *progIter->binary);
528 			}
529 
530 			registryWriter.write();
531 		}
532 
533 		{
534 			stats.notSupported = notSupported;
535 			for (de::PoolArray<Program>::iterator progIter = programs.begin(); progIter != programs.end(); ++progIter)
536 			{
537 				const bool	buildOk			= progIter->buildStatus == Program::STATUS_PASSED;
538 				const bool	validationOk	= progIter->validationStatus != Program::STATUS_FAILED;
539 
540 				if (buildOk && validationOk)
541 					stats.numSucceeded += 1;
542 				else
543 				{
544 					stats.numFailed += 1;
545 					tcu::print("ERROR: %s / %s: %s failed\n",
546 							progIter->id.testCasePath.c_str(),
547 							progIter->id.programName.c_str(),
548 							(buildOk ? "validation" : "build"));
549 					tcu::print("%s\n", (buildOk ? progIter->validationLog.c_str() : progIter->buildLog.c_str()));
550 				}
551 			}
552 
553 		}
554 	}
555 
556 	return stats;
557 }
558 
559 } // vkt
560 
561 namespace opt
562 {
563 
564 DE_DECLARE_COMMAND_LINE_OPT(DstPath,				std::string);
565 DE_DECLARE_COMMAND_LINE_OPT(Cases,					std::string);
566 DE_DECLARE_COMMAND_LINE_OPT(Validate,				bool);
567 DE_DECLARE_COMMAND_LINE_OPT(VulkanVersion,			deUint32);
568 DE_DECLARE_COMMAND_LINE_OPT(ShaderCache,			bool);
569 DE_DECLARE_COMMAND_LINE_OPT(ShaderCacheFilename,	std::string);
570 DE_DECLARE_COMMAND_LINE_OPT(ShaderCacheTruncate,	bool);
571 DE_DECLARE_COMMAND_LINE_OPT(SpirvOptimize,			bool);
572 DE_DECLARE_COMMAND_LINE_OPT(SpirvOptimizationRecipe,std::string);
573 DE_DECLARE_COMMAND_LINE_OPT(SpirvAllow14,			bool);
574 
575 static const de::cmdline::NamedValue<bool> s_enableNames[] =
576 {
577 	{ "enable",		true },
578 	{ "disable",	false }
579 };
580 
registerOptions(de::cmdline::Parser & parser)581 void registerOptions (de::cmdline::Parser& parser)
582 {
583 	using de::cmdline::Option;
584 	using de::cmdline::NamedValue;
585 
586 	static const NamedValue<deUint32> s_vulkanVersion[] =
587 	{
588 		{ "1.0",	VK_MAKE_API_VERSION(0, 1, 0, 0)	},
589 		{ "1.1",	VK_MAKE_API_VERSION(0, 1, 1, 0)	},
590 		{ "1.2",	VK_MAKE_API_VERSION(0, 1, 2, 0)	},
591 		{ "1.3",	VK_MAKE_API_VERSION(0, 1, 3, 0)	},
592 	};
593 
594 	DE_STATIC_ASSERT(vk::SPIRV_VERSION_1_6 + 1 == vk::SPIRV_VERSION_LAST);
595 
596 	parser << Option<opt::DstPath>("d", "dst-path", "Destination path", "out")
597 		<< Option<opt::Cases>("n", "deqp-case", "Case path filter (works as in test binaries)")
598 		<< Option<opt::Validate>("v", "validate-spv", "Validate generated SPIR-V binaries")
599 		<< Option<opt::VulkanVersion>("t", "target-vulkan-version", "Target Vulkan version", s_vulkanVersion, "1.2")
600 		<< Option<opt::ShaderCache>("s", "shadercache", "Enable or disable shader cache", s_enableNames, "enable")
601 		<< Option<opt::ShaderCacheFilename>("r", "shadercache-filename", "Write shader cache to given file", "shadercache.bin")
602 		<< Option<opt::ShaderCacheTruncate>("x", "shadercache-truncate", "Truncate shader cache before running", s_enableNames, "enable")
603 		<< Option<opt::SpirvOptimize>("o", "deqp-optimize-spirv", "Enable optimization for SPIR-V", s_enableNames, "disable")
604 		<< Option<opt::SpirvOptimizationRecipe>("p","deqp-optimization-recipe", "Shader optimization recipe")
605 		<< Option<opt::SpirvAllow14>("e","allow-spirv-14", "Allow SPIR-V 1.4 with Vulkan 1.1");
606 }
607 
608 } // opt
609 
main(int argc,const char * argv[])610 int main (int argc, const char* argv[])
611 {
612 	de::cmdline::CommandLine	cmdLine;
613 	tcu::CommandLine			deqpCmdLine;
614 
615 	{
616 		de::cmdline::Parser		parser;
617 		opt::registerOptions(parser);
618 		if (!parser.parse(argc, argv, &cmdLine, std::cerr))
619 		{
620 			parser.help(std::cout);
621 			return -1;
622 		}
623 	}
624 
625 	{
626 		vector<const char*> deqpArgv;
627 
628 		deqpArgv.push_back("unused");
629 
630 		if (cmdLine.hasOption<opt::Cases>())
631 		{
632 			deqpArgv.push_back("--deqp-case");
633 			deqpArgv.push_back(cmdLine.getOption<opt::Cases>().c_str());
634 		}
635 
636 		if (cmdLine.hasOption<opt::ShaderCacheFilename>())
637 		{
638 			deqpArgv.push_back("--deqp-shadercache-filename");
639 			deqpArgv.push_back(cmdLine.getOption<opt::ShaderCacheFilename>().c_str());
640 		}
641 
642 		if (cmdLine.hasOption<opt::ShaderCache>())
643 		{
644 			deqpArgv.push_back("--deqp-shadercache");
645 			if (cmdLine.getOption<opt::ShaderCache>())
646 				deqpArgv.push_back("enable");
647 			else
648 				deqpArgv.push_back("disable");
649 		}
650 
651 		if (cmdLine.hasOption<opt::ShaderCacheTruncate>())
652 		{
653 			deqpArgv.push_back("--deqp-shadercache-truncate");
654 			if (cmdLine.getOption<opt::ShaderCacheTruncate>())
655 				deqpArgv.push_back("enable");
656 			else
657 				deqpArgv.push_back("disable");
658 		}
659 
660 		if (cmdLine.hasOption<opt::SpirvOptimize>())
661 		{
662 			deqpArgv.push_back("--deqp-optimize-spirv");
663 			if (cmdLine.getOption<opt::SpirvOptimize>())
664 				deqpArgv.push_back("enable");
665 			 else
666 				deqpArgv.push_back("disable");
667 		}
668 
669 		if (cmdLine.hasOption<opt::SpirvOptimizationRecipe>())
670 		{
671 			deqpArgv.push_back("--deqp-optimization-recipe");
672 			deqpArgv.push_back(cmdLine.getOption<opt::SpirvOptimizationRecipe>().c_str());
673 		}
674 
675 		if (!deqpCmdLine.parse((int)deqpArgv.size(), &deqpArgv[0]))
676 			return -1;
677 	}
678 
679 	try
680 	{
681 		tcu::DirArchive			archive					(".");
682 		tcu::TestLog			log						(deqpCmdLine.getLogFileName(), deqpCmdLine.getLogFlags());
683 		tcu::Platform			platform;
684 		tcu::TestContext		testCtx					(platform, archive, log, deqpCmdLine, DE_NULL);
685 		vk::SpirvVersion		baselineSpirvVersion	= vk::getBaselineSpirvVersion(cmdLine.getOption<opt::VulkanVersion>());
686 		vk::SpirvVersion		maxSpirvVersion			= vk::getMaxSpirvVersionForGlsl(cmdLine.getOption<opt::VulkanVersion>());
687 
688 		testCtx.writeSessionInfo();
689 
690 		tcu::print("SPIR-V versions: baseline: %s, max supported: %s\n",
691 					getSpirvVersionName(baselineSpirvVersion).c_str(),
692 					getSpirvVersionName(maxSpirvVersion).c_str());
693 
694 		const vkt::BuildStats	stats		= vkt::buildPrograms(testCtx,
695 																 cmdLine.getOption<opt::DstPath>(),
696 																 cmdLine.getOption<opt::Validate>(),
697 																 cmdLine.getOption<opt::VulkanVersion>(),
698 																 baselineSpirvVersion,
699 																 maxSpirvVersion,
700 																 cmdLine.getOption<opt::SpirvAllow14>());
701 
702 		tcu::print("DONE: %d passed, %d failed, %d not supported\n", stats.numSucceeded, stats.numFailed, stats.notSupported);
703 
704 		return stats.numFailed == 0 ? 0 : -1;
705 	}
706 	catch (const std::exception& e)
707 	{
708 		tcu::die("%s", e.what());
709 	}
710 
711 	return -1;
712 }
713