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
38 using std::vector;
39 using std::string;
40 using std::set;
41 using std::map;
42
43 struct CommandLine
44 {
CommandLineCommandLine45 CommandLine (void)
46 {
47 }
48
49 string filename;
50 string dstPath;
51 };
52
getShaderTypeSuffix(const xe::ri::Shader::ShaderType shaderType)53 static 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
writeShaderProgram(const CommandLine & cmdLine,const std::string & casePath,const xe::ri::ShaderProgram & shaderProgram,int programNdx)77 static 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
100 struct StackEntry
101 {
102 const xe::ri::List* list;
103 int curNdx;
104
StackEntryStackEntry105 explicit StackEntry (const xe::ri::List* list_) : list(list_), curNdx(0) {}
106 };
107
extractShaderPrograms(const CommandLine & cmdLine,const std::string & casePath,const xe::TestCaseResult & result)108 static 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
140 class ShaderProgramExtractHandler : public xe::TestLogHandler
141 {
142 public:
ShaderProgramExtractHandler(const CommandLine & cmdLine)143 ShaderProgramExtractHandler (const CommandLine& cmdLine)
144 : m_cmdLine(cmdLine)
145 {
146 }
147
setSessionInfo(const xe::SessionInfo &)148 void setSessionInfo (const xe::SessionInfo&)
149 {
150 // Ignored.
151 }
152
startTestCaseResult(const char * casePath)153 xe::TestCaseResultPtr startTestCaseResult (const char* casePath)
154 {
155 return xe::TestCaseResultPtr(new xe::TestCaseResultData(casePath));
156 }
157
testCaseResultUpdated(const xe::TestCaseResultPtr &)158 void testCaseResultUpdated (const xe::TestCaseResultPtr&)
159 {
160 // Ignored.
161 }
162
testCaseResultComplete(const xe::TestCaseResultPtr & caseData)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
178 private:
179 const CommandLine& m_cmdLine;
180 xe::TestResultParser m_testResultParser;
181 };
182
extractShaderProgramsFromLogFile(const CommandLine & cmdLine)183 static 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
printHelp(const char * binName)208 static void printHelp (const char* binName)
209 {
210 printf("%s: [filename] [dst path (optional)]\n", binName);
211 }
212
parseCommandLine(CommandLine & cmdLine,int argc,const char * const * argv)213 static 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
main(int argc,const char * const * argv)238 int 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