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::__anon2d146aef0111::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::__anon2d146aef0111::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