xref: /aosp_15_r20/external/deqp/external/vulkancts/modules/vulkan/vktBuildPrograms.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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