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 de::MovePtr;
45 using de::SharedPtr;
46 using de::UniquePtr;
47 using std::string;
48 using std::vector;
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:
~Task()63 virtual ~Task()
64 {
65 }
66
67 virtual void execute(void) = 0;
68 };
69
70 typedef de::ThreadSafeRingBuffer<Task *> TaskQueue;
71
72 class TaskExecutorThread : public de::Thread
73 {
74 public:
TaskExecutorThread(TaskQueue & tasks)75 TaskExecutorThread(TaskQueue &tasks) : m_tasks(tasks)
76 {
77 start();
78 }
79
run(void)80 void run(void)
81 {
82 for (;;)
83 {
84 Task *const task = m_tasks.popBack();
85
86 if (task)
87 task->execute();
88 else
89 break; // End of tasks - time to terminate
90 }
91 }
92
93 private:
94 TaskQueue &m_tasks;
95 };
96
97 class TaskExecutor
98 {
99 public:
100 TaskExecutor(uint32_t numThreads);
101 ~TaskExecutor(void);
102
103 void submit(Task *task);
104 void waitForComplete(void);
105
106 private:
107 typedef de::SharedPtr<TaskExecutorThread> ExecThreadSp;
108
109 std::vector<ExecThreadSp> m_threads;
110 TaskQueue m_tasks;
111 };
112
TaskExecutor(uint32_t numThreads)113 TaskExecutor::TaskExecutor(uint32_t numThreads) : m_threads(numThreads), m_tasks(m_threads.size() * 1024u)
114 {
115 for (size_t ndx = 0; ndx < m_threads.size(); ++ndx)
116 m_threads[ndx] = ExecThreadSp(new TaskExecutorThread(m_tasks));
117 }
118
~TaskExecutor(void)119 TaskExecutor::~TaskExecutor(void)
120 {
121 for (size_t ndx = 0; ndx < m_threads.size(); ++ndx)
122 m_tasks.pushFront(DE_NULL);
123
124 for (size_t ndx = 0; ndx < m_threads.size(); ++ndx)
125 m_threads[ndx]->join();
126 }
127
submit(Task * task)128 void TaskExecutor::submit(Task *task)
129 {
130 DE_ASSERT(task);
131 m_tasks.pushFront(task);
132 }
133
134 class SyncTask : public Task
135 {
136 public:
SyncTask(de::Semaphore * enterBarrier,de::Semaphore * inBarrier,de::Semaphore * leaveBarrier)137 SyncTask(de::Semaphore *enterBarrier, de::Semaphore *inBarrier, de::Semaphore *leaveBarrier)
138 : m_enterBarrier(enterBarrier)
139 , m_inBarrier(inBarrier)
140 , m_leaveBarrier(leaveBarrier)
141 {
142 }
143
SyncTask(void)144 SyncTask(void) : m_enterBarrier(DE_NULL), m_inBarrier(DE_NULL), m_leaveBarrier(DE_NULL)
145 {
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::__anond133cb850111::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 {
212 }
Programvkt::__anond133cb850111::Program213 Program(void)
214 : id("", "")
215 , buildStatus(STATUS_NOT_COMPLETED)
216 , validationStatus(STATUS_NOT_COMPLETED)
217 , validatorOptions()
218 {
219 }
220 };
221
writeBuildLogs(const glu::ShaderProgramInfo & buildInfo,std::ostream & dst)222 void writeBuildLogs(const glu::ShaderProgramInfo &buildInfo, std::ostream &dst)
223 {
224 for (size_t shaderNdx = 0; shaderNdx < buildInfo.shaders.size(); shaderNdx++)
225 {
226 const glu::ShaderInfo &shaderInfo = buildInfo.shaders[shaderNdx];
227 const char *const shaderName = getShaderTypeName(shaderInfo.type);
228
229 dst << shaderName << " source:\n"
230 << "---\n"
231 << shaderInfo.source << "\n"
232 << "---\n"
233 << shaderName << " compile log:\n"
234 << "---\n"
235 << shaderInfo.infoLog << "\n"
236 << "---\n";
237 }
238
239 dst << "link log:\n"
240 << "---\n"
241 << buildInfo.program.infoLog << "\n"
242 << "---\n";
243 }
244
245 template <typename Source>
246 class BuildHighLevelShaderTask : public Task
247 {
248 public:
BuildHighLevelShaderTask(const Source & source,Program * program)249 BuildHighLevelShaderTask(const Source &source, Program *program)
250 : m_source(source)
251 , m_program(program)
252 , m_commandLine(0)
253 {
254 }
255
BuildHighLevelShaderTask(void)256 BuildHighLevelShaderTask(void) : m_program(DE_NULL)
257 {
258 }
259
setCommandline(const tcu::CommandLine & commandLine)260 void setCommandline(const tcu::CommandLine &commandLine)
261 {
262 m_commandLine = &commandLine;
263 }
264
execute(void)265 void execute(void)
266 {
267 glu::ShaderProgramInfo buildInfo;
268
269 try
270 {
271 DE_ASSERT(m_source.buildOptions.targetVersion < vk::SPIRV_VERSION_LAST);
272 DE_ASSERT(m_commandLine != DE_NULL);
273 m_program->binary = ProgramBinarySp(vk::buildProgram(m_source, &buildInfo, *m_commandLine));
274 m_program->buildStatus = Program::STATUS_PASSED;
275 m_program->validatorOptions = m_source.buildOptions.getSpirvValidatorOptions();
276 }
277 catch (const tcu::Exception &)
278 {
279 std::ostringstream log;
280
281 writeBuildLogs(buildInfo, log);
282
283 m_program->buildStatus = Program::STATUS_FAILED;
284 m_program->buildLog = log.str();
285 }
286 }
287
288 private:
289 Source m_source;
290 Program *m_program;
291 const tcu::CommandLine *m_commandLine;
292 };
293
writeBuildLogs(const vk::SpirVProgramInfo & buildInfo,std::ostream & dst)294 void writeBuildLogs(const vk::SpirVProgramInfo &buildInfo, std::ostream &dst)
295 {
296 dst << "source:\n"
297 << "---\n"
298 << buildInfo.source << "\n"
299 << "---\n"
300 << buildInfo.infoLog << "\n"
301 << "---\n";
302 }
303
304 class BuildSpirVAsmTask : public Task
305 {
306 public:
BuildSpirVAsmTask(const vk::SpirVAsmSource & source,Program * program)307 BuildSpirVAsmTask(const vk::SpirVAsmSource &source, Program *program)
308 : m_source(source)
309 , m_program(program)
310 , m_commandLine(0)
311 {
312 }
313
BuildSpirVAsmTask(void)314 BuildSpirVAsmTask(void) : m_program(DE_NULL), m_commandLine(0)
315 {
316 }
317
setCommandline(const tcu::CommandLine & commandLine)318 void setCommandline(const tcu::CommandLine &commandLine)
319 {
320 m_commandLine = &commandLine;
321 }
322
execute(void)323 void execute(void)
324 {
325 vk::SpirVProgramInfo buildInfo;
326
327 try
328 {
329 DE_ASSERT(m_source.buildOptions.targetVersion < vk::SPIRV_VERSION_LAST);
330 DE_ASSERT(m_commandLine != DE_NULL);
331 m_program->binary = ProgramBinarySp(vk::assembleProgram(m_source, &buildInfo, *m_commandLine));
332 m_program->buildStatus = Program::STATUS_PASSED;
333 }
334 catch (const tcu::Exception &)
335 {
336 std::ostringstream log;
337
338 writeBuildLogs(buildInfo, log);
339
340 m_program->buildStatus = Program::STATUS_FAILED;
341 m_program->buildLog = log.str();
342 }
343 }
344
345 private:
346 vk::SpirVAsmSource m_source;
347 Program *m_program;
348 const tcu::CommandLine *m_commandLine;
349 };
350
351 class ValidateBinaryTask : public Task
352 {
353 public:
ValidateBinaryTask(Program * program)354 ValidateBinaryTask(Program *program) : m_program(program)
355 {
356 }
357
execute(void)358 void execute(void)
359 {
360 DE_ASSERT(m_program->buildStatus == Program::STATUS_PASSED);
361 DE_ASSERT(m_program->binary->getFormat() == vk::PROGRAM_FORMAT_SPIRV);
362
363 std::ostringstream validationLogStream;
364
365 if (vk::validateProgram(*m_program->binary, &validationLogStream, m_program->validatorOptions))
366 m_program->validationStatus = Program::STATUS_PASSED;
367 else
368 m_program->validationStatus = Program::STATUS_FAILED;
369 m_program->validationLog = validationLogStream.str();
370 }
371
372 private:
373 Program *m_program;
374 };
375
createRoot(tcu::TestContext & testCtx)376 tcu::TestPackageRoot *createRoot(tcu::TestContext &testCtx)
377 {
378 vector<tcu::TestNode *> children;
379 children.push_back(new TestPackage(testCtx));
380 return new tcu::TestPackageRoot(testCtx, children);
381 }
382
383 } // namespace
384
385 struct BuildStats
386 {
387 int numSucceeded;
388 int numFailed;
389 int notSupported;
390
BuildStatsvkt::BuildStats391 BuildStats(void) : numSucceeded(0), numFailed(0), notSupported(0)
392 {
393 }
394 };
395
buildPrograms(tcu::TestContext & testCtx,const std::string & dstPath,const bool validateBinaries,const uint32_t usedVulkanVersion,const vk::SpirvVersion baselineSpirvVersion,const vk::SpirvVersion maxSpirvVersion,const bool allowSpirV14)396 BuildStats buildPrograms(tcu::TestContext &testCtx, const std::string &dstPath, const bool validateBinaries,
397 const uint32_t usedVulkanVersion, const vk::SpirvVersion baselineSpirvVersion,
398 const vk::SpirvVersion maxSpirvVersion, const bool allowSpirV14)
399 {
400 const uint32_t 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(
406 testCtx.getCommandLine().createCaseListFilter(testCtx.getArchive()));
407 tcu::TestHierarchyIterator iterator(*root, inflater, *caseListFilter);
408 BuildStats stats;
409 int notSupported = 0;
410
411 while (iterator.getState() != tcu::TestHierarchyIterator::STATE_FINISHED)
412 {
413
414 TaskExecutor executor(numThreads);
415
416 // de::PoolArray<> is faster to build than std::vector
417 de::MemPool programPool;
418 de::PoolArray<Program> programs(&programPool);
419
420 de::MemPool tmpPool;
421 de::PoolArray<BuildHighLevelShaderTask<vk::GlslSource>> buildGlslTasks(&tmpPool);
422 de::PoolArray<BuildHighLevelShaderTask<vk::HlslSource>> buildHlslTasks(&tmpPool);
423 de::PoolArray<BuildSpirVAsmTask> buildSpirvAsmTasks(&tmpPool);
424
425 // Collect build tasks. We perform tests in chunks to reduce memory usage
426 size_t numNodesAdded = 0;
427 while (iterator.getState() != tcu::TestHierarchyIterator::STATE_FINISHED && numNodesAdded < numNodesInChunk)
428 {
429 if (iterator.getState() == tcu::TestHierarchyIterator::STATE_ENTER_NODE &&
430 tcu::isTestNodeTypeExecutable(iterator.getNode()->getNodeType()))
431 {
432 numNodesAdded++;
433 TestCase *const testCase = dynamic_cast<TestCase *>(iterator.getNode());
434 const string casePath = iterator.getNodePath();
435 vk::ShaderBuildOptions defaultGlslBuildOptions(usedVulkanVersion, baselineSpirvVersion, 0u);
436 vk::ShaderBuildOptions defaultHlslBuildOptions(usedVulkanVersion, baselineSpirvVersion, 0u);
437 vk::SpirVAsmBuildOptions defaultSpirvAsmBuildOptions(usedVulkanVersion, baselineSpirvVersion);
438 vk::SourceCollections sourcePrograms(usedVulkanVersion, defaultGlslBuildOptions,
439 defaultHlslBuildOptions, defaultSpirvAsmBuildOptions);
440
441 try
442 {
443 testCase->delayedInit();
444 testCase->initPrograms(sourcePrograms);
445 }
446 catch (const tcu::NotSupportedError &)
447 {
448 notSupported++;
449 iterator.next();
450 continue;
451 }
452
453 for (vk::GlslSourceCollection::Iterator progIter = sourcePrograms.glslSources.begin();
454 progIter != sourcePrograms.glslSources.end(); ++progIter)
455 {
456 // Source program requires higher SPIR-V version than available: skip it to avoid fail
457 // Unless this is SPIR-V 1.4 and is explicitly allowed.
458 if (progIter.getProgram().buildOptions.targetVersion > maxSpirvVersion &&
459 !(allowSpirV14 && progIter.getProgram().buildOptions.supports_VK_KHR_spirv_1_4 &&
460 progIter.getProgram().buildOptions.targetVersion == vk::SPIRV_VERSION_1_4))
461 continue;
462
463 programs.pushBack(Program(vk::ProgramIdentifier(casePath, progIter.getName()),
464 progIter.getProgram().buildOptions.getSpirvValidatorOptions()));
465 buildGlslTasks.pushBack(
466 BuildHighLevelShaderTask<vk::GlslSource>(progIter.getProgram(), &programs.back()));
467 buildGlslTasks.back().setCommandline(testCtx.getCommandLine());
468 executor.submit(&buildGlslTasks.back());
469 }
470
471 for (vk::HlslSourceCollection::Iterator progIter = sourcePrograms.hlslSources.begin();
472 progIter != sourcePrograms.hlslSources.end(); ++progIter)
473 {
474 // Source program requires higher SPIR-V version than available: skip it to avoid fail
475 // Unless this is SPIR-V 1.4 and is explicitly allowed.
476 if (progIter.getProgram().buildOptions.targetVersion > maxSpirvVersion &&
477 !(allowSpirV14 && progIter.getProgram().buildOptions.supports_VK_KHR_spirv_1_4 &&
478 progIter.getProgram().buildOptions.targetVersion == vk::SPIRV_VERSION_1_4))
479 continue;
480
481 programs.pushBack(Program(vk::ProgramIdentifier(casePath, progIter.getName()),
482 progIter.getProgram().buildOptions.getSpirvValidatorOptions()));
483 buildHlslTasks.pushBack(
484 BuildHighLevelShaderTask<vk::HlslSource>(progIter.getProgram(), &programs.back()));
485 buildHlslTasks.back().setCommandline(testCtx.getCommandLine());
486 executor.submit(&buildHlslTasks.back());
487 }
488
489 for (vk::SpirVAsmCollection::Iterator progIter = sourcePrograms.spirvAsmSources.begin();
490 progIter != sourcePrograms.spirvAsmSources.end(); ++progIter)
491 {
492 // Source program requires higher SPIR-V version than available: skip it to avoid fail
493 // Unless this is SPIR-V 1.4 and is explicitly allowed.
494 if (progIter.getProgram().buildOptions.targetVersion > maxSpirvVersion &&
495 !(allowSpirV14 && progIter.getProgram().buildOptions.supports_VK_KHR_spirv_1_4 &&
496 progIter.getProgram().buildOptions.targetVersion == vk::SPIRV_VERSION_1_4))
497 continue;
498
499 programs.pushBack(Program(vk::ProgramIdentifier(casePath, progIter.getName()),
500 progIter.getProgram().buildOptions.getSpirvValidatorOptions()));
501 buildSpirvAsmTasks.pushBack(BuildSpirVAsmTask(progIter.getProgram(), &programs.back()));
502 buildSpirvAsmTasks.back().setCommandline(testCtx.getCommandLine());
503 executor.submit(&buildSpirvAsmTasks.back());
504 }
505 }
506
507 iterator.next();
508 }
509
510 // Need to wait until tasks completed before freeing task memory
511 executor.waitForComplete();
512
513 if (validateBinaries)
514 {
515 std::vector<ValidateBinaryTask> validationTasks;
516
517 validationTasks.reserve(programs.size());
518
519 for (de::PoolArray<Program>::iterator progIter = programs.begin(); progIter != programs.end(); ++progIter)
520 {
521 if (progIter->buildStatus == Program::STATUS_PASSED)
522 {
523 validationTasks.push_back(ValidateBinaryTask(&*progIter));
524 executor.submit(&validationTasks.back());
525 }
526 }
527
528 executor.waitForComplete();
529 }
530
531 {
532 vk::BinaryRegistryWriter registryWriter(dstPath);
533
534 for (de::PoolArray<Program>::iterator progIter = programs.begin(); progIter != programs.end(); ++progIter)
535 {
536 if (progIter->buildStatus == Program::STATUS_PASSED)
537 registryWriter.addProgram(progIter->id, *progIter->binary);
538 }
539
540 registryWriter.write();
541 }
542
543 {
544 stats.notSupported = notSupported;
545 for (de::PoolArray<Program>::iterator progIter = programs.begin(); progIter != programs.end(); ++progIter)
546 {
547 const bool buildOk = progIter->buildStatus == Program::STATUS_PASSED;
548 const bool validationOk = progIter->validationStatus != Program::STATUS_FAILED;
549
550 if (buildOk && validationOk)
551 stats.numSucceeded += 1;
552 else
553 {
554 stats.numFailed += 1;
555 tcu::print("ERROR: %s / %s: %s failed\n", progIter->id.testCasePath.c_str(),
556 progIter->id.programName.c_str(), (buildOk ? "validation" : "build"));
557 tcu::print("%s\n", (buildOk ? progIter->validationLog.c_str() : progIter->buildLog.c_str()));
558 }
559 }
560 }
561 }
562
563 return stats;
564 }
565
566 } // namespace vkt
567
568 namespace opt
569 {
570
571 DE_DECLARE_COMMAND_LINE_OPT(DstPath, std::string);
572 DE_DECLARE_COMMAND_LINE_OPT(Cases, std::string);
573 DE_DECLARE_COMMAND_LINE_OPT(Validate, bool);
574 DE_DECLARE_COMMAND_LINE_OPT(VulkanVersion, uint32_t);
575 DE_DECLARE_COMMAND_LINE_OPT(ShaderCache, bool);
576 DE_DECLARE_COMMAND_LINE_OPT(ShaderCacheFilename, std::string);
577 DE_DECLARE_COMMAND_LINE_OPT(ShaderCacheTruncate, bool);
578 DE_DECLARE_COMMAND_LINE_OPT(SpirvOptimize, bool);
579 DE_DECLARE_COMMAND_LINE_OPT(SpirvOptimizationRecipe, std::string);
580 DE_DECLARE_COMMAND_LINE_OPT(SpirvAllow14, bool);
581
582 static const de::cmdline::NamedValue<bool> s_enableNames[] = {{"enable", true}, {"disable", false}};
583
registerOptions(de::cmdline::Parser & parser)584 void registerOptions(de::cmdline::Parser &parser)
585 {
586 using de::cmdline::NamedValue;
587 using de::cmdline::Option;
588
589 static const NamedValue<uint32_t> s_vulkanVersion[] = {
590 {"1.0", VK_MAKE_API_VERSION(0, 1, 0, 0)},
591 {"1.1", VK_MAKE_API_VERSION(0, 1, 1, 0)},
592 {"1.2", VK_MAKE_API_VERSION(0, 1, 2, 0)},
593 {"1.3", VK_MAKE_API_VERSION(0, 1, 3, 0)},
594 };
595
596 DE_STATIC_ASSERT(vk::SPIRV_VERSION_1_6 + 1 == vk::SPIRV_VERSION_LAST);
597
598 parser << Option<opt::DstPath>("d", "dst-path", "Destination path", "out")
599 << Option<opt::Cases>("n", "deqp-case", "Case path filter (works as in test binaries)")
600 << Option<opt::Validate>("v", "validate-spv", "Validate generated SPIR-V binaries")
601 << Option<opt::VulkanVersion>("t", "target-vulkan-version", "Target Vulkan version", s_vulkanVersion, "1.2")
602 << Option<opt::ShaderCache>("s", "shadercache", "Enable or disable shader cache", s_enableNames, "enable")
603 << Option<opt::ShaderCacheFilename>("r", "shadercache-filename", "Write shader cache to given file",
604 "shadercache.bin")
605 << Option<opt::ShaderCacheTruncate>("x", "shadercache-truncate", "Truncate shader cache before running",
606 s_enableNames, "enable")
607 << Option<opt::SpirvOptimize>("o", "deqp-optimize-spirv", "Enable optimization for SPIR-V", s_enableNames,
608 "disable")
609 << Option<opt::SpirvOptimizationRecipe>("p", "deqp-optimization-recipe", "Shader optimization recipe")
610 << Option<opt::SpirvAllow14>("e", "allow-spirv-14", "Allow SPIR-V 1.4 with Vulkan 1.1");
611 }
612
613 } // namespace opt
614
main(int argc,const char * argv[])615 int main(int argc, const char *argv[])
616 {
617 de::cmdline::CommandLine cmdLine;
618 tcu::CommandLine deqpCmdLine;
619
620 {
621 de::cmdline::Parser parser;
622 opt::registerOptions(parser);
623 if (!parser.parse(argc, argv, &cmdLine, std::cerr))
624 {
625 parser.help(std::cout);
626 return -1;
627 }
628 }
629
630 {
631 vector<const char *> deqpArgv;
632
633 deqpArgv.push_back("unused");
634
635 if (cmdLine.hasOption<opt::Cases>())
636 {
637 deqpArgv.push_back("--deqp-case");
638 deqpArgv.push_back(cmdLine.getOption<opt::Cases>().c_str());
639 }
640
641 if (cmdLine.hasOption<opt::ShaderCacheFilename>())
642 {
643 deqpArgv.push_back("--deqp-shadercache-filename");
644 deqpArgv.push_back(cmdLine.getOption<opt::ShaderCacheFilename>().c_str());
645 }
646
647 if (cmdLine.hasOption<opt::ShaderCache>())
648 {
649 deqpArgv.push_back("--deqp-shadercache");
650 if (cmdLine.getOption<opt::ShaderCache>())
651 deqpArgv.push_back("enable");
652 else
653 deqpArgv.push_back("disable");
654 }
655
656 if (cmdLine.hasOption<opt::ShaderCacheTruncate>())
657 {
658 deqpArgv.push_back("--deqp-shadercache-truncate");
659 if (cmdLine.getOption<opt::ShaderCacheTruncate>())
660 deqpArgv.push_back("enable");
661 else
662 deqpArgv.push_back("disable");
663 }
664
665 if (cmdLine.hasOption<opt::SpirvOptimize>())
666 {
667 deqpArgv.push_back("--deqp-optimize-spirv");
668 if (cmdLine.getOption<opt::SpirvOptimize>())
669 deqpArgv.push_back("enable");
670 else
671 deqpArgv.push_back("disable");
672 }
673
674 if (cmdLine.hasOption<opt::SpirvOptimizationRecipe>())
675 {
676 deqpArgv.push_back("--deqp-optimization-recipe");
677 deqpArgv.push_back(cmdLine.getOption<opt::SpirvOptimizationRecipe>().c_str());
678 }
679
680 if (!deqpCmdLine.parse((int)deqpArgv.size(), &deqpArgv[0]))
681 return -1;
682 }
683
684 try
685 {
686 tcu::DirArchive archive(".");
687 tcu::TestLog log(deqpCmdLine.getLogFileName(), deqpCmdLine.getLogFlags());
688 tcu::Platform platform;
689 tcu::TestContext testCtx(platform, archive, log, deqpCmdLine, DE_NULL);
690 vk::SpirvVersion baselineSpirvVersion = vk::getBaselineSpirvVersion(cmdLine.getOption<opt::VulkanVersion>());
691 vk::SpirvVersion maxSpirvVersion = vk::getMaxSpirvVersionForGlsl(cmdLine.getOption<opt::VulkanVersion>());
692
693 testCtx.writeSessionInfo();
694
695 tcu::print("SPIR-V versions: baseline: %s, max supported: %s\n",
696 getSpirvVersionName(baselineSpirvVersion).c_str(), getSpirvVersionName(maxSpirvVersion).c_str());
697
698 const vkt::BuildStats stats =
699 vkt::buildPrograms(testCtx, cmdLine.getOption<opt::DstPath>(), cmdLine.getOption<opt::Validate>(),
700 cmdLine.getOption<opt::VulkanVersion>(), baselineSpirvVersion, maxSpirvVersion,
701 cmdLine.getOption<opt::SpirvAllow14>());
702
703 tcu::print("DONE: %d passed, %d failed, %d not supported\n", stats.numSucceeded, stats.numFailed,
704 stats.notSupported);
705
706 return stats.numFailed == 0 ? 0 : -1;
707 }
708 catch (const std::exception &e)
709 {
710 tcu::die("%s", e.what());
711 }
712
713 return -1;
714 }
715