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