1/*------------------------------------------------------------------------- 2 * drawElements Quality Program Test Executor 3 * ------------------------------------------ 4 * 5 * Copyright 2014 The Android Open Source Project 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 Extract shader programs from log. 22 *//*--------------------------------------------------------------------*/ 23 24#include "xeTestLogParser.hpp" 25#include "xeTestResultParser.hpp" 26#include "deFilePath.hpp" 27#include "deStringUtil.hpp" 28#include "deString.h" 29 30#include <vector> 31#include <string> 32#include <cstdio> 33#include <cstdlib> 34#include <fstream> 35#include <iostream> 36#include <stdexcept> 37 38using std::vector; 39using std::string; 40using std::set; 41using std::map; 42 43struct CommandLine 44{ 45 CommandLine (void) 46 { 47 } 48 49 string filename; 50 string dstPath; 51}; 52 53static const char* getShaderTypeSuffix (const xe::ri::Shader::ShaderType shaderType) 54{ 55 switch (shaderType) 56 { 57 case xe::ri::Shader::SHADERTYPE_VERTEX: return "vert"; 58 case xe::ri::Shader::SHADERTYPE_FRAGMENT: return "frag"; 59 case xe::ri::Shader::SHADERTYPE_GEOMETRY: return "geom"; 60 case xe::ri::Shader::SHADERTYPE_TESS_CONTROL: return "tesc"; 61 case xe::ri::Shader::SHADERTYPE_TESS_EVALUATION: return "tese"; 62 case xe::ri::Shader::SHADERTYPE_COMPUTE: return "comp"; 63 case xe::ri::Shader::SHADERTYPE_RAYGEN: return "rgen"; 64 case xe::ri::Shader::SHADERTYPE_ANY_HIT: return "ahit"; 65 case xe::ri::Shader::SHADERTYPE_CLOSEST_HIT: return "chit"; 66 case xe::ri::Shader::SHADERTYPE_MISS: return "miss"; 67 case xe::ri::Shader::SHADERTYPE_INTERSECTION: return "sect"; 68 case xe::ri::Shader::SHADERTYPE_CALLABLE: return "call"; 69 case xe::ri::Shader::SHADERTYPE_TASK: return "task"; 70 case xe::ri::Shader::SHADERTYPE_MESH: return "mesh"; 71 72 default: 73 throw xe::Error("Invalid shader type"); 74 } 75} 76 77static void writeShaderProgram (const CommandLine& cmdLine, const std::string& casePath, const xe::ri::ShaderProgram& shaderProgram, int programNdx) 78{ 79 const string basePath = string(de::FilePath::join(cmdLine.dstPath, casePath).getPath()) + "." + de::toString(programNdx); 80 81 for (int shaderNdx = 0; shaderNdx < shaderProgram.shaders.getNumItems(); shaderNdx++) 82 { 83 const xe::ri::Shader& shader = dynamic_cast<const xe::ri::Shader&>(shaderProgram.shaders.getItem(shaderNdx)); 84 const string shaderPath = basePath + "." + getShaderTypeSuffix(shader.shaderType); 85 86 if (de::FilePath(shaderPath).exists()) 87 throw xe::Error("File '" + shaderPath + "' exists already"); 88 89 { 90 std::ofstream out(shaderPath.c_str(), std::ifstream::binary|std::ifstream::out); 91 92 if (!out.good()) 93 throw xe::Error("Failed to open '" + shaderPath + "'"); 94 95 out.write(shader.source.source.c_str(), shader.source.source.size()); 96 } 97 } 98} 99 100struct StackEntry 101{ 102 const xe::ri::List* list; 103 int curNdx; 104 105 explicit StackEntry (const xe::ri::List* list_) : list(list_), curNdx(0) {} 106}; 107 108static void extractShaderPrograms (const CommandLine& cmdLine, const std::string& casePath, const xe::TestCaseResult& result) 109{ 110 vector<StackEntry> itemListStack; 111 int programNdx = 0; 112 113 itemListStack.push_back(StackEntry(&result.resultItems)); 114 115 while (!itemListStack.empty()) 116 { 117 StackEntry& curEntry = itemListStack.back(); 118 119 if (curEntry.curNdx < curEntry.list->getNumItems()) 120 { 121 const xe::ri::Item& curItem = curEntry.list->getItem(curEntry.curNdx); 122 curEntry.curNdx += 1; 123 124 if (curItem.getType() == xe::ri::TYPE_SHADERPROGRAM) 125 { 126 writeShaderProgram(cmdLine, casePath, static_cast<const xe::ri::ShaderProgram&>(curItem), programNdx); 127 programNdx += 1; 128 } 129 else if (curItem.getType() == xe::ri::TYPE_SECTION) 130 itemListStack.push_back(StackEntry(&static_cast<const xe::ri::Section&>(curItem).items)); 131 } 132 else 133 itemListStack.pop_back(); 134 } 135 136 if (programNdx == 0) 137 std::cout << "WARNING: no shader programs found in '" << casePath << "'\n"; 138} 139 140class ShaderProgramExtractHandler : public xe::TestLogHandler 141{ 142public: 143 ShaderProgramExtractHandler (const CommandLine& cmdLine) 144 : m_cmdLine(cmdLine) 145 { 146 } 147 148 void setSessionInfo (const xe::SessionInfo&) 149 { 150 // Ignored. 151 } 152 153 xe::TestCaseResultPtr startTestCaseResult (const char* casePath) 154 { 155 return xe::TestCaseResultPtr(new xe::TestCaseResultData(casePath)); 156 } 157 158 void testCaseResultUpdated (const xe::TestCaseResultPtr&) 159 { 160 // Ignored. 161 } 162 163 void testCaseResultComplete (const xe::TestCaseResultPtr& caseData) 164 { 165 if (caseData->getDataSize() > 0) 166 { 167 xe::TestCaseResult fullResult; 168 xe::TestResultParser::ParseResult parseResult; 169 170 m_testResultParser.init(&fullResult); 171 parseResult = m_testResultParser.parse(caseData->getData(), caseData->getDataSize()); 172 DE_UNREF(parseResult); 173 174 extractShaderPrograms(m_cmdLine, caseData->getTestCasePath(), fullResult); 175 } 176 } 177 178private: 179 const CommandLine& m_cmdLine; 180 xe::TestResultParser m_testResultParser; 181}; 182 183static void extractShaderProgramsFromLogFile (const CommandLine& cmdLine) 184{ 185 std::ifstream in (cmdLine.filename.c_str(), std::ifstream::binary|std::ifstream::in); 186 ShaderProgramExtractHandler resultHandler (cmdLine); 187 xe::TestLogParser parser (&resultHandler); 188 deUint8 buf [1024]; 189 int numRead = 0; 190 191 if (!in.good()) 192 throw std::runtime_error(string("Failed to open '") + cmdLine.filename + "'"); 193 194 for (;;) 195 { 196 in.read((char*)&buf[0], DE_LENGTH_OF_ARRAY(buf)); 197 numRead = (int)in.gcount(); 198 199 if (numRead <= 0) 200 break; 201 202 parser.parse(&buf[0], numRead); 203 } 204 205 in.close(); 206} 207 208static void printHelp (const char* binName) 209{ 210 printf("%s: [filename] [dst path (optional)]\n", binName); 211} 212 213static bool parseCommandLine (CommandLine& cmdLine, int argc, const char* const* argv) 214{ 215 for (int argNdx = 1; argNdx < argc; argNdx++) 216 { 217 const char* arg = argv[argNdx]; 218 219 if (!deStringBeginsWith(arg, "--")) 220 { 221 if (cmdLine.filename.empty()) 222 cmdLine.filename = arg; 223 else if (cmdLine.dstPath.empty()) 224 cmdLine.dstPath = arg; 225 else 226 return false; 227 } 228 else 229 return false; 230 } 231 232 if (cmdLine.filename.empty()) 233 return false; 234 235 return true; 236} 237 238int main (int argc, const char* const* argv) 239{ 240 try 241 { 242 CommandLine cmdLine; 243 244 if (!parseCommandLine(cmdLine, argc, argv)) 245 { 246 printHelp(argv[0]); 247 return -1; 248 } 249 250 extractShaderProgramsFromLogFile(cmdLine); 251 } 252 catch (const std::exception& e) 253 { 254 printf("FATAL ERROR: %s\n", e.what()); 255 return -1; 256 } 257 258 return 0; 259} 260