DO NOT MERGE add running time hints for dEQP packages am: 75da7d236c -s ours am...
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / vktBuildPrograms.cpp
1 /*-------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2015 Google Inc.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and/or associated documentation files (the
9  * "Materials"), to deal in the Materials without restriction, including
10  * without limitation the rights to use, copy, modify, merge, publish,
11  * distribute, sublicense, and/or sell copies of the Materials, and to
12  * permit persons to whom the Materials are furnished to do so, subject to
13  * the following conditions:
14  *
15  * The above copyright notice(s) and this permission notice shall be
16  * included in all copies or substantial portions of the Materials.
17  *
18  * The Materials are Confidential Information as defined by the
19  * Khronos Membership Agreement until designated non-confidential by
20  * Khronos, at which point this condition clause shall be removed.
21  *
22  * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
25  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
26  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
27  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
28  * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
29  *
30  *//*!
31  * \file
32  * \brief Utility for pre-compiling source programs to SPIR-V
33  *//*--------------------------------------------------------------------*/
34
35 #include "tcuDefs.hpp"
36 #include "tcuCommandLine.hpp"
37 #include "tcuPlatform.hpp"
38 #include "tcuResource.hpp"
39 #include "tcuTestLog.hpp"
40 #include "tcuTestHierarchyIterator.hpp"
41 #include "deUniquePtr.hpp"
42 #include "vkPrograms.hpp"
43 #include "vkBinaryRegistry.hpp"
44 #include "vktTestCase.hpp"
45 #include "vktTestPackage.hpp"
46 #include "deUniquePtr.hpp"
47 #include "deCommandLine.hpp"
48
49 #include <iostream>
50
51 using std::vector;
52 using std::string;
53 using de::UniquePtr;
54 using de::MovePtr;
55
56 namespace vkt
57 {
58
59 tcu::TestPackageRoot* createRoot (tcu::TestContext& testCtx)
60 {
61         vector<tcu::TestNode*>  children;
62         children.push_back(new TestPackage(testCtx));
63         return new tcu::TestPackageRoot(testCtx, children);
64 }
65
66 enum BuildMode
67 {
68         BUILDMODE_BUILD = 0,
69         BUILDMODE_VERIFY,
70
71         BUILDMODE_LAST
72 };
73
74 struct BuildStats
75 {
76         int             numSucceeded;
77         int             numFailed;
78
79         BuildStats (void)
80                 : numSucceeded  (0)
81                 , numFailed             (0)
82         {
83         }
84 };
85
86 namespace // anonymous
87 {
88
89 vk::ProgramBinary* compileProgram (const glu::ProgramSources& source, glu::ShaderProgramInfo* buildInfo)
90 {
91         return vk::buildProgram(source, vk::PROGRAM_FORMAT_SPIRV, buildInfo);
92 }
93
94 vk::ProgramBinary* compileProgram (const vk::SpirVAsmSource& source, vk::SpirVProgramInfo* buildInfo)
95 {
96         return vk::assembleProgram(source, buildInfo);
97 }
98
99 void writeVerboseLogs (const glu::ShaderProgramInfo& buildInfo)
100 {
101         for (size_t shaderNdx = 0; shaderNdx < buildInfo.shaders.size(); shaderNdx++)
102         {
103                 const glu::ShaderInfo&  shaderInfo      = buildInfo.shaders[shaderNdx];
104                 const char* const               shaderName      = getShaderTypeName(shaderInfo.type);
105
106                 tcu::print("%s source:\n---\n%s\n---\n", shaderName, shaderInfo.source.c_str());
107                 tcu::print("%s compile log:\n---\n%s\n---\n", shaderName, shaderInfo.infoLog.c_str());
108         }
109 }
110
111 void writeVerboseLogs (const vk::SpirVProgramInfo& buildInfo)
112 {
113         tcu::print("source:\n---\n%s\n---\n", buildInfo.source->program.str().c_str());
114         tcu::print("compile log:\n---\n%s\n---\n", buildInfo.infoLog.c_str());
115 }
116
117 template <typename InfoType, typename IteratorType>
118 void buildProgram (const std::string&                   casePath,
119                                    bool                                                 printLogs,
120                                    IteratorType                                 iter,
121                                    BuildMode                                    mode,
122                                    BuildStats*                                  stats,
123                                    vk::BinaryRegistryReader*    reader,
124                                    vk::BinaryRegistryWriter*    writer)
125 {
126         InfoType                                                        buildInfo;
127         try
128         {
129                 const vk::ProgramIdentifier                     progId          (casePath, iter.getName());
130                 const UniquePtr<vk::ProgramBinary>      binary          (compileProgram(iter.getProgram(), &buildInfo));
131
132                 if (mode == BUILDMODE_BUILD)
133                         writer->storeProgram(progId, *binary);
134                 else
135                 {
136                         DE_ASSERT(mode == BUILDMODE_VERIFY);
137
138                         const UniquePtr<vk::ProgramBinary>      storedBinary    (reader->loadProgram(progId));
139
140                         if (binary->getSize() != storedBinary->getSize())
141                                 throw tcu::Exception("Binary size doesn't match");
142
143                         if (deMemCmp(binary->getBinary(), storedBinary->getBinary(), binary->getSize()))
144                                 throw tcu::Exception("Binary contents don't match");
145                 }
146
147                 tcu::print("  OK: %s\n", iter.getName().c_str());
148                 stats->numSucceeded += 1;
149         }
150         catch (const std::exception& e)
151         {
152                 tcu::print("  ERROR: %s: %s\n", iter.getName().c_str(), e.what());
153                 if (printLogs)
154                 {
155                         writeVerboseLogs(buildInfo);
156                 }
157                 stats->numFailed += 1;
158         }
159 }
160
161 } // anonymous
162 BuildStats buildPrograms (tcu::TestContext& testCtx, const std::string& dstPath, BuildMode mode, bool verbose)
163 {
164         const UniquePtr<tcu::TestPackageRoot>   root            (createRoot(testCtx));
165         tcu::DefaultHierarchyInflater                   inflater        (testCtx);
166         tcu::TestHierarchyIterator                              iterator        (*root, inflater, testCtx.getCommandLine());
167         const tcu::DirArchive                                   srcArchive      (dstPath.c_str());
168         UniquePtr<vk::BinaryRegistryWriter>             writer          (mode == BUILDMODE_BUILD        ? new vk::BinaryRegistryWriter(dstPath)                 : DE_NULL);
169         UniquePtr<vk::BinaryRegistryReader>             reader          (mode == BUILDMODE_VERIFY       ? new vk::BinaryRegistryReader(srcArchive, "")  : DE_NULL);
170         BuildStats                                                              stats;
171         const bool                                                              printLogs       = verbose;
172
173         while (iterator.getState() != tcu::TestHierarchyIterator::STATE_FINISHED)
174         {
175                 if (iterator.getState() == tcu::TestHierarchyIterator::STATE_ENTER_NODE &&
176                         tcu::isTestNodeTypeExecutable(iterator.getNode()->getNodeType()))
177                 {
178                         const TestCase* const           testCase        = dynamic_cast<TestCase*>(iterator.getNode());
179                         const string                            casePath        = iterator.getNodePath();
180                         vk::SourceCollections           progs;
181
182                         tcu::print("%s\n", casePath.c_str());
183
184                         testCase->initPrograms(progs);
185
186                         for (vk::GlslSourceCollection::Iterator progIter = progs.glslSources.begin(); progIter != progs.glslSources.end(); ++progIter)
187                         {
188                                 buildProgram<glu::ShaderProgramInfo, vk::GlslSourceCollection::Iterator>(casePath, printLogs, progIter, mode, &stats, reader.get(), writer.get());
189                         }
190
191                         for (vk::SpirVAsmCollection::Iterator progIter = progs.spirvAsmSources.begin(); progIter != progs.spirvAsmSources.end(); ++progIter)
192                         {
193                                 buildProgram<vk::SpirVProgramInfo, vk::SpirVAsmCollection::Iterator>(casePath, printLogs, progIter, mode, &stats, reader.get(), writer.get());
194                         }
195                 }
196
197                 iterator.next();
198         }
199
200         if (mode == BUILDMODE_BUILD)
201                 writer->writeIndex();
202
203         return stats;
204 }
205
206 } // vkt
207
208 namespace opt
209 {
210
211 DE_DECLARE_COMMAND_LINE_OPT(DstPath,    std::string);
212 DE_DECLARE_COMMAND_LINE_OPT(Mode,               vkt::BuildMode);
213 DE_DECLARE_COMMAND_LINE_OPT(Verbose,    bool);
214 DE_DECLARE_COMMAND_LINE_OPT(Cases,              std::string);
215
216 } // opt
217
218 void registerOptions (de::cmdline::Parser& parser)
219 {
220         using de::cmdline::Option;
221         using de::cmdline::NamedValue;
222
223         static const NamedValue<vkt::BuildMode> s_modes[] =
224         {
225                 { "build",      vkt::BUILDMODE_BUILD    },
226                 { "verify",     vkt::BUILDMODE_VERIFY   }
227         };
228
229         parser << Option<opt::DstPath>  ("d", "dst-path",       "Destination path",     "out")
230                    << Option<opt::Mode>         ("m", "mode",           "Build mode",           s_modes,        "build")
231                    << Option<opt::Verbose>      ("v", "verbose",        "Verbose output")
232                    << Option<opt::Cases>        ("n", "deqp-case",      "Case path filter (works as in test binaries)");
233 }
234
235 int main (int argc, const char* argv[])
236 {
237         de::cmdline::CommandLine        cmdLine;
238         tcu::CommandLine                        deqpCmdLine;
239
240         {
241                 de::cmdline::Parser             parser;
242                 registerOptions(parser);
243                 if (!parser.parse(argc, argv, &cmdLine, std::cerr))
244                 {
245                         parser.help(std::cout);
246                         return -1;
247                 }
248         }
249
250         {
251                 vector<const char*> deqpArgv;
252
253                 deqpArgv.push_back("unused");
254
255                 if (cmdLine.hasOption<opt::Cases>())
256                 {
257                         deqpArgv.push_back("--deqp-case");
258                         deqpArgv.push_back(cmdLine.getOption<opt::Cases>().c_str());
259                 }
260
261                 if (!deqpCmdLine.parse((int)deqpArgv.size(), &deqpArgv[0]))
262                         return -1;
263         }
264
265         try
266         {
267                 tcu::DirArchive                 archive                 (".");
268                 tcu::TestLog                    log                             (deqpCmdLine.getLogFileName(), deqpCmdLine.getLogFlags());
269                 tcu::Platform                   platform;
270                 tcu::TestContext                testCtx                 (platform, archive, log, deqpCmdLine, DE_NULL);
271
272                 const vkt::BuildStats   stats                   = vkt::buildPrograms(testCtx,
273                                                                                                                                          cmdLine.getOption<opt::DstPath>(),
274                                                                                                                                          cmdLine.getOption<opt::Mode>(),
275                                                                                                                                          cmdLine.getOption<opt::Verbose>());
276
277                 tcu::print("DONE: %d passed, %d failed\n", stats.numSucceeded, stats.numFailed);
278
279                 return stats.numFailed == 0 ? 0 : -1;
280         }
281         catch (const std::exception& e)
282         {
283                 tcu::die("%s", e.what());
284         }
285 }