/*------------------------------------------------------------------------- * drawElements Quality Program Test Executor * ------------------------------------------ * * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *//*! * \file * \brief Extract shader programs from log. *//*--------------------------------------------------------------------*/ #include "xeTestLogParser.hpp" #include "xeTestResultParser.hpp" #include "deFilePath.hpp" #include "deStringUtil.hpp" #include "deString.h" #include <vector> #include <string> #include <cstdio> #include <cstdlib> #include <fstream> #include <iostream> #include <stdexcept> using std::vector; using std::string; using std::set; using std::map; struct CommandLine { CommandLine (void) { } string filename; string dstPath; }; static const char* getShaderTypeSuffix (const xe::ri::Shader::ShaderType shaderType) { switch (shaderType) { case xe::ri::Shader::SHADERTYPE_VERTEX: return "vert"; case xe::ri::Shader::SHADERTYPE_FRAGMENT: return "frag"; case xe::ri::Shader::SHADERTYPE_GEOMETRY: return "geom"; case xe::ri::Shader::SHADERTYPE_TESS_CONTROL: return "tesc"; case xe::ri::Shader::SHADERTYPE_TESS_EVALUATION: return "tese"; case xe::ri::Shader::SHADERTYPE_COMPUTE: return "comp"; default: throw xe::Error("Invalid shader type"); } } static void writeShaderProgram (const CommandLine& cmdLine, const std::string& casePath, const xe::ri::ShaderProgram& shaderProgram, int programNdx) { const string basePath = string(de::FilePath::join(cmdLine.dstPath, casePath).getPath()) + "." + de::toString(programNdx); for (int shaderNdx = 0; shaderNdx < shaderProgram.shaders.getNumItems(); shaderNdx++) { const xe::ri::Shader& shader = dynamic_cast<const xe::ri::Shader&>(shaderProgram.shaders.getItem(shaderNdx)); const string shaderPath = basePath + "." + getShaderTypeSuffix(shader.shaderType); if (de::FilePath(shaderPath).exists()) throw xe::Error("File '" + shaderPath + "' exists already"); { std::ofstream out(shaderPath.c_str(), std::ifstream::binary|std::ifstream::out); if (!out.good()) throw xe::Error("Failed to open '" + shaderPath + "'"); out.write(shader.source.source.c_str(), shader.source.source.size()); } } } struct StackEntry { const xe::ri::List* list; int curNdx; explicit StackEntry (const xe::ri::List* list_) : list(list_), curNdx(0) {} }; static void extractShaderPrograms (const CommandLine& cmdLine, const std::string& casePath, const xe::TestCaseResult& result) { vector<StackEntry> itemListStack; int programNdx = 0; itemListStack.push_back(StackEntry(&result.resultItems)); while (!itemListStack.empty()) { StackEntry& curEntry = itemListStack.back(); if (curEntry.curNdx < curEntry.list->getNumItems()) { const xe::ri::Item& curItem = curEntry.list->getItem(curEntry.curNdx); curEntry.curNdx += 1; if (curItem.getType() == xe::ri::TYPE_SHADERPROGRAM) { writeShaderProgram(cmdLine, casePath, static_cast<const xe::ri::ShaderProgram&>(curItem), programNdx); programNdx += 1; } else if (curItem.getType() == xe::ri::TYPE_SECTION) itemListStack.push_back(StackEntry(&static_cast<const xe::ri::Section&>(curItem).items)); } else itemListStack.pop_back(); } if (programNdx == 0) std::cout << "WARNING: no shader programs found in '" << casePath << "'\n"; } class ShaderProgramExtractHandler : public xe::TestLogHandler { public: ShaderProgramExtractHandler (const CommandLine& cmdLine) : m_cmdLine(cmdLine) { } void setSessionInfo (const xe::SessionInfo&) { // Ignored. } xe::TestCaseResultPtr startTestCaseResult (const char* casePath) { return xe::TestCaseResultPtr(new xe::TestCaseResultData(casePath)); } void testCaseResultUpdated (const xe::TestCaseResultPtr&) { // Ignored. } void testCaseResultComplete (const xe::TestCaseResultPtr& caseData) { if (caseData->getDataSize() > 0) { xe::TestCaseResult fullResult; xe::TestResultParser::ParseResult parseResult; m_testResultParser.init(&fullResult); parseResult = m_testResultParser.parse(caseData->getData(), caseData->getDataSize()); DE_UNREF(parseResult); extractShaderPrograms(m_cmdLine, caseData->getTestCasePath(), fullResult); } } private: const CommandLine& m_cmdLine; xe::TestResultParser m_testResultParser; }; static void extractShaderProgramsFromLogFile (const CommandLine& cmdLine) { std::ifstream in (cmdLine.filename.c_str(), std::ifstream::binary|std::ifstream::in); ShaderProgramExtractHandler resultHandler (cmdLine); xe::TestLogParser parser (&resultHandler); deUint8 buf [1024]; int numRead = 0; if (!in.good()) throw std::runtime_error(string("Failed to open '") + cmdLine.filename + "'"); for (;;) { in.read((char*)&buf[0], DE_LENGTH_OF_ARRAY(buf)); numRead = (int)in.gcount(); if (numRead <= 0) break; parser.parse(&buf[0], numRead); } in.close(); } static void printHelp (const char* binName) { printf("%s: [filename] [dst path (optional)]\n", binName); } static bool parseCommandLine (CommandLine& cmdLine, int argc, const char* const* argv) { for (int argNdx = 1; argNdx < argc; argNdx++) { const char* arg = argv[argNdx]; if (!deStringBeginsWith(arg, "--")) { if (cmdLine.filename.empty()) cmdLine.filename = arg; else if (cmdLine.dstPath.empty()) cmdLine.dstPath = arg; else return false; } else return false; } if (cmdLine.filename.empty()) return false; return true; } int main (int argc, const char* const* argv) { try { CommandLine cmdLine; if (!parseCommandLine(cmdLine, argc, argv)) { printHelp(argv[0]); return -1; } extractShaderProgramsFromLogFile(cmdLine); } catch (const std::exception& e) { printf("FATAL ERROR: %s\n", e.what()); return -1; } return 0; }