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