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