1 /*-------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
5 * Copyright (c) 2015 Google Inc.
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:
15 * The above copyright notice(s) and this permission notice shall be
16 * included in all copies or substantial portions of the Materials.
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.
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.
32 * \brief Utility for pre-compiling source programs to SPIR-V
33 *//*--------------------------------------------------------------------*/
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"
59 tcu::TestPackageRoot* createRoot (tcu::TestContext& testCtx)
61 vector<tcu::TestNode*> children;
62 children.push_back(new TestPackage(testCtx));
63 return new tcu::TestPackageRoot(testCtx, children);
86 namespace // anonymous
89 vk::ProgramBinary* compileProgram (const glu::ProgramSources& source, glu::ShaderProgramInfo* buildInfo)
91 return vk::buildProgram(source, vk::PROGRAM_FORMAT_SPIRV, buildInfo);
94 vk::ProgramBinary* compileProgram (const vk::SpirVAsmSource& source, vk::SpirVProgramInfo* buildInfo)
96 return vk::assembleProgram(source, buildInfo);
99 void writeVerboseLogs (const glu::ShaderProgramInfo& buildInfo)
101 for (size_t shaderNdx = 0; shaderNdx < buildInfo.shaders.size(); shaderNdx++)
103 const glu::ShaderInfo& shaderInfo = buildInfo.shaders[shaderNdx];
104 const char* const shaderName = getShaderTypeName(shaderInfo.type);
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());
111 void writeVerboseLogs (const vk::SpirVProgramInfo& buildInfo)
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());
117 template <typename InfoType, typename IteratorType>
118 void buildProgram (const std::string& casePath,
123 vk::BinaryRegistryReader* reader,
124 vk::BinaryRegistryWriter* writer)
129 const vk::ProgramIdentifier progId (casePath, iter.getName());
130 const UniquePtr<vk::ProgramBinary> binary (compileProgram(iter.getProgram(), &buildInfo));
132 if (mode == BUILDMODE_BUILD)
133 writer->storeProgram(progId, *binary);
136 DE_ASSERT(mode == BUILDMODE_VERIFY);
138 const UniquePtr<vk::ProgramBinary> storedBinary (reader->loadProgram(progId));
140 if (binary->getSize() != storedBinary->getSize())
141 throw tcu::Exception("Binary size doesn't match");
143 if (deMemCmp(binary->getBinary(), storedBinary->getBinary(), binary->getSize()))
144 throw tcu::Exception("Binary contents don't match");
147 tcu::print(" OK: %s\n", iter.getName().c_str());
148 stats->numSucceeded += 1;
150 catch (const std::exception& e)
152 tcu::print(" ERROR: %s: %s\n", iter.getName().c_str(), e.what());
155 writeVerboseLogs(buildInfo);
157 stats->numFailed += 1;
162 BuildStats buildPrograms (tcu::TestContext& testCtx, const std::string& dstPath, BuildMode mode, bool verbose)
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);
171 const bool printLogs = verbose;
173 while (iterator.getState() != tcu::TestHierarchyIterator::STATE_FINISHED)
175 if (iterator.getState() == tcu::TestHierarchyIterator::STATE_ENTER_NODE &&
176 tcu::isTestNodeTypeExecutable(iterator.getNode()->getNodeType()))
178 const TestCase* const testCase = dynamic_cast<TestCase*>(iterator.getNode());
179 const string casePath = iterator.getNodePath();
180 vk::SourceCollections progs;
182 tcu::print("%s\n", casePath.c_str());
184 testCase->initPrograms(progs);
186 for (vk::GlslSourceCollection::Iterator progIter = progs.glslSources.begin(); progIter != progs.glslSources.end(); ++progIter)
188 buildProgram<glu::ShaderProgramInfo, vk::GlslSourceCollection::Iterator>(casePath, printLogs, progIter, mode, &stats, reader.get(), writer.get());
191 for (vk::SpirVAsmCollection::Iterator progIter = progs.spirvAsmSources.begin(); progIter != progs.spirvAsmSources.end(); ++progIter)
193 buildProgram<vk::SpirVProgramInfo, vk::SpirVAsmCollection::Iterator>(casePath, printLogs, progIter, mode, &stats, reader.get(), writer.get());
200 if (mode == BUILDMODE_BUILD)
201 writer->writeIndex();
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);
218 void registerOptions (de::cmdline::Parser& parser)
220 using de::cmdline::Option;
221 using de::cmdline::NamedValue;
223 static const NamedValue<vkt::BuildMode> s_modes[] =
225 { "build", vkt::BUILDMODE_BUILD },
226 { "verify", vkt::BUILDMODE_VERIFY }
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)");
235 int main (int argc, const char* argv[])
237 de::cmdline::CommandLine cmdLine;
238 tcu::CommandLine deqpCmdLine;
241 de::cmdline::Parser parser;
242 registerOptions(parser);
243 if (!parser.parse(argc, argv, &cmdLine, std::cerr))
245 parser.help(std::cout);
251 vector<const char*> deqpArgv;
253 deqpArgv.push_back("unused");
255 if (cmdLine.hasOption<opt::Cases>())
257 deqpArgv.push_back("--deqp-case");
258 deqpArgv.push_back(cmdLine.getOption<opt::Cases>().c_str());
261 if (!deqpCmdLine.parse((int)deqpArgv.size(), &deqpArgv[0]))
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);
272 const vkt::BuildStats stats = vkt::buildPrograms(testCtx,
273 cmdLine.getOption<opt::DstPath>(),
274 cmdLine.getOption<opt::Mode>(),
275 cmdLine.getOption<opt::Verbose>());
277 tcu::print("DONE: %d passed, %d failed\n", stats.numSucceeded, stats.numFailed);
279 return stats.numFailed == 0 ? 0 : -1;
281 catch (const std::exception& e)
283 tcu::die("%s", e.what());