• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*-------------------------------------------------------------------------
2  * Vulkan CTS Framework
3  * --------------------
4  *
5  * Copyright (c) 2021 The Khronos Group Inc.
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 
21 #include "vksNetwork.hpp"
22 #include "vksProtocol.hpp"
23 #include "vksServices.hpp"
24 
25 #include <iostream>
26 #include <fstream>
27 #include <future>
28 #include <atomic>
29 #include <initializer_list>
30 
31 #include "deSocket.hpp"
32 #include "deCommandLine.hpp"
33 
34 using namespace vksc_server;
35 
36 namespace opt
37 {
38 
39 DE_DECLARE_COMMAND_LINE_OPT(Port,						int);
40 DE_DECLARE_COMMAND_LINE_OPT(LogFile,					std::string);
41 DE_DECLARE_COMMAND_LINE_OPT(PipelineCompilerPath,		std::string);
42 DE_DECLARE_COMMAND_LINE_OPT(PipelineCompilerDataDir,	std::string);
43 DE_DECLARE_COMMAND_LINE_OPT(PipelineCompilerOutputFile,	std::string);
44 DE_DECLARE_COMMAND_LINE_OPT(PipelineCompilerLogFile,	std::string);
45 DE_DECLARE_COMMAND_LINE_OPT(PipelineCompilerArgs,		std::string);
46 
47 const auto DefaultPortStr = std::to_string(DefaultPort);
48 
registerOptions(de::cmdline::Parser & parser)49 void registerOptions (de::cmdline::Parser& parser)
50 {
51 	using de::cmdline::Option;
52 	using de::cmdline::NamedValue;
53 
54 	parser << Option<Port>							(DE_NULL, "port",				"Port",									DefaultPortStr.c_str());
55 	parser << Option<LogFile>						(DE_NULL, "log",				"Log filename",							"dummy.log");
56 	parser << Option<PipelineCompilerPath>			(DE_NULL, "pipeline-compiler",	"Path to offline pipeline compiler",	"");
57 	parser << Option<PipelineCompilerDataDir>		(DE_NULL, "pipeline-dir",		"Offline pipeline data directory",		"");
58 	parser << Option<PipelineCompilerOutputFile>	(DE_NULL, "pipeline-file",		"Output file with pipeline cache",		"");
59 	parser << Option<PipelineCompilerLogFile>		(DE_NULL, "pipeline-log",		"Compiler log file",					"compiler.log");
60 	parser << Option<PipelineCompilerArgs>			(DE_NULL, "pipeline-args",		"Additional compiler parameters",		"");
61 }
62 
63 }
64 
Log()65 void Log () { std::cout << std::endl; }
66 template <typename ARG>
Log(ARG && arg)67 void Log (ARG&& arg) { std::cout << arg << ' ' << std::endl;  }
68 template <typename ARG, typename... ARGs>
Log(ARG && first,ARGs &&...args)69 void Log (ARG&& first, ARGs&&... args)	{ std::cout << first << ' '; Log(args...); }
70 
71 #ifdef _DEBUG
72 template <typename... ARGs>
Debug(ARGs &&...args)73 void Debug (ARGs&&... args)
74 {
75 	Log("[DEBUG]", std::forward<ARGs>(args)...);
76 }
77 #else
78 template <typename... ARGs>
Debug(ARGs &&...)79 void Debug (ARGs&&...) { }
80 #endif
81 
82 struct Client
83 {
84 	int							id;
85 	std::unique_ptr<de::Socket>	socket;
86 	std::atomic<bool>&			appactive;
87 	vector<u8>					recvb;
88 	CmdLineParams				cmdLineParams;
89 	std::string					logFile;
90 };
91 
92 std::future<void> CreateClientThread (Client client);
93 
main(int argc,char ** argv)94 int main (int argc, char** argv)
95 {
96 	de::cmdline::CommandLine	cmdLine;
97 
98 	// Parse command line.
99 	{
100 		de::cmdline::Parser	parser;
101 		opt::registerOptions(parser);
102 
103 		if (!parser.parse(argc, argv, &cmdLine, std::cerr))
104 		{
105 			parser.help(std::cout);
106 			return EXIT_FAILURE;
107 		}
108 	}
109 
110 	std::atomic<bool> appActive{true};
111 
112 	try
113 	{
114 		de::SocketAddress addr;
115 		addr.setHost("0.0.0.0");
116 		addr.setPort(cmdLine.getOption<opt::Port>());
117 		de::Socket listener;
118 		int id{};
119 
120 		vector<std::future<void>> clients;
121 
122 		listener.listen(addr);
123 		Log("Listening on port", addr.getPort());
124 
125 		while (appActive)
126 		{
127 			remove_erase_if(clients, [](const std::future<void>& c) { return is_ready(c); });
128 			Client client{ ++id, std::unique_ptr<de::Socket>(listener.accept()), appActive, vector<u8>{},
129 			{
130 				cmdLine.getOption<opt::PipelineCompilerPath>(),
131 				cmdLine.getOption<opt::PipelineCompilerDataDir>(),
132 				cmdLine.getOption<opt::PipelineCompilerOutputFile>(),
133 				cmdLine.getOption<opt::PipelineCompilerLogFile>(),
134 				cmdLine.getOption<opt::PipelineCompilerArgs>()
135 			},
136 			cmdLine.getOption<opt::LogFile>() };
137 			Debug("New client with id", id - 1, "connected");
138 			clients.push_back(CreateClientThread(std::move(client)));
139 		}
140 	}
141 	catch (const std::exception& e) { Log(e.what()); appActive = false; }
142 
143 	return EXIT_SUCCESS;
144 }
145 
146 template <typename T>
SendResponse(Client & c,T & data)147 void SendResponse (Client& c, T& data)
148 {
149 	SendPayloadWithHeader(c.socket.get(), T::Type(), Serialize(data));
150 }
151 
ProcessPacketsOnServer(Client & client,u32 type,vector<u8> packet)152 void ProcessPacketsOnServer (Client& client, u32 type, vector<u8> packet)
153 {
154 	switch (type)
155 	{
156 		case LogRequest::Type():
157 		{
158 			auto req = Deserialize<LogRequest>(packet);
159 			std::cout << req.message;
160 		}
161 		break;
162 		case CompileShaderRequest::Type():
163 		{
164 			auto req = Deserialize<CompileShaderRequest>(packet);
165 
166 			vector<u8> result;
167 			bool ok = CompileShader(req.source, req.commandLine, result);
168 
169 			CompileShaderResponse res;
170 			res.status = ok;
171 			res.binary = std::move(result);
172 			SendResponse(client, res);
173 		}
174 		break;
175 		case StoreContentRequest::Type():
176 		{
177 			auto req = Deserialize<StoreContentRequest>(packet);
178 			bool ok = StoreFile(req.name, req.data);
179 
180 			StoreContentResponse res;
181 			res.status = ok;
182 			SendResponse(client, res);
183 		}
184 		break;
185 		case GetContentRequest::Type():
186 		{
187 			auto req = Deserialize<GetContentRequest>(packet);
188 
189 			vector<u8> content;
190 			bool ok = GetFile(req.path, content, req.removeAfter);
191 
192 			GetContentResponse res;
193 			res.status = ok;
194 			res.data = std::move(content);
195 			SendResponse(client, res);
196 		}
197 		break;
198 		case AppendRequest::Type():
199 		{
200 			auto req = Deserialize<AppendRequest>(packet);
201 
202 			bool result = AppendFile(req.fileName, req.data, req.clear);
203 			if (!result) Log("[WARNING] Can't append file", req.fileName);
204 		}
205 		break;
206 		case CreateCacheRequest::Type():
207 		{
208 			auto req = Deserialize<CreateCacheRequest>(packet);
209 
210 			vector<u8>							binary;
211 			bool ok = false;
212 			try
213 			{
214 				CreateVulkanSCCache(req.input, req.caseFraction, binary, client.cmdLineParams, client.logFile);
215 				ok = true;
216 			}
217 			catch (const std::exception& e)
218 			{
219 				Log("[ERROR] Can't create cache:", e.what());
220 				binary = {};
221 			}
222 
223 			CreateCacheResponse res;
224 			res.status			= ok;
225 			res.binary			= std::move(binary);
226 			SendResponse(client, res);
227 		}
228 		break;
229 
230 		default:
231 			throw std::runtime_error("communication error");
232 	}
233 }
234 
235 struct PacketsLoop
236 {
237 	Client client;
238 
LoopPacketsLoop239 	void Loop ()
240 	{
241 		while (client.socket->isConnected() && client.appactive)
242 		{
243 			RecvSome(client.socket.get(), client.recvb);
244 			auto interpret = [this](u32 type, vector<u8> packet) { ProcessPacketsOnServer(client, type, std::move(packet)); };
245 			while (ProccessNetworkData(client.recvb, interpret)) {}
246 		}
247 	}
248 
operator ()PacketsLoop249 	void operator() ()
250 	{
251 		try { Loop(); }
252 		catch (const std::exception& e)
253 		{
254 			client.socket->close();
255 			Debug(e.what(), "from client with id", client.id);
256 		}
257 		Debug("Client with id", client.id, "disconnected.");
258 	}
259 };
260 
CreateClientThread(Client client)261 std::future<void> CreateClientThread (Client client)
262 {
263 	return std::async( PacketsLoop{ std::move(client) } );
264 }
265