• 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::NamedValue;
52     using de::cmdline::Option;
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 } // namespace opt
64 
Log()65 void Log()
66 {
67     std::cout << std::endl;
68 }
69 template <typename ARG>
Log(ARG && arg)70 void Log(ARG &&arg)
71 {
72     std::cout << arg << ' ' << std::endl;
73 }
74 template <typename ARG, typename... ARGs>
Log(ARG && first,ARGs &&...args)75 void Log(ARG &&first, ARGs &&...args)
76 {
77     std::cout << first << ' ';
78     Log(args...);
79 }
80 
81 #ifdef _DEBUG
82 template <typename... ARGs>
Debug(ARGs &&...args)83 void Debug(ARGs &&...args)
84 {
85     Log("[DEBUG]", std::forward<ARGs>(args)...);
86 }
87 #else
88 template <typename... ARGs>
Debug(ARGs &&...)89 void Debug(ARGs &&...)
90 {
91 }
92 #endif
93 
94 struct Client
95 {
96     int id;
97     std::unique_ptr<de::Socket> socket;
98     std::atomic<bool> &appactive;
99     vector<u8> recvb;
100     CmdLineParams cmdLineParams;
101     std::string logFile;
102 };
103 
104 std::future<void> CreateClientThread(Client client);
105 
main(int argc,char ** argv)106 int main(int argc, char **argv)
107 {
108     de::cmdline::CommandLine cmdLine;
109 
110     // Parse command line.
111     {
112         de::cmdline::Parser parser;
113         opt::registerOptions(parser);
114 
115         if (!parser.parse(argc, argv, &cmdLine, std::cerr))
116         {
117             parser.help(std::cout);
118             return EXIT_FAILURE;
119         }
120     }
121 
122     std::atomic<bool> appActive{true};
123 
124     try
125     {
126         de::SocketAddress addr;
127         addr.setHost("0.0.0.0");
128         addr.setPort(cmdLine.getOption<opt::Port>());
129         de::Socket listener;
130         int id{};
131 
132         vector<std::future<void>> clients;
133 
134         listener.listen(addr);
135         Log("Listening on port", addr.getPort());
136 
137         while (appActive)
138         {
139             remove_erase_if(clients, [](const std::future<void> &c) { return is_ready(c); });
140             Client client{
141                 ++id,
142                 std::unique_ptr<de::Socket>(listener.accept()),
143                 appActive,
144                 vector<u8>{},
145                 {cmdLine.getOption<opt::PipelineCompilerPath>(), cmdLine.getOption<opt::PipelineCompilerDataDir>(),
146                  cmdLine.getOption<opt::PipelineCompilerOutputFile>(),
147                  cmdLine.getOption<opt::PipelineCompilerLogFile>(), cmdLine.getOption<opt::PipelineCompilerArgs>()},
148                 cmdLine.getOption<opt::LogFile>()};
149             Debug("New client with id", id - 1, "connected");
150             clients.push_back(CreateClientThread(std::move(client)));
151         }
152     }
153     catch (const std::exception &e)
154     {
155         Log(e.what());
156         appActive = false;
157     }
158 
159     return EXIT_SUCCESS;
160 }
161 
162 template <typename T>
SendResponse(Client & c,T & data)163 void SendResponse(Client &c, T &data)
164 {
165     SendPayloadWithHeader(c.socket.get(), T::Type(), Serialize(data));
166 }
167 
ProcessPacketsOnServer(Client & client,u32 type,vector<u8> packet)168 void ProcessPacketsOnServer(Client &client, u32 type, vector<u8> packet)
169 {
170     switch (type)
171     {
172     case LogRequest::Type():
173     {
174         auto req = Deserialize<LogRequest>(packet);
175         std::cout << req.message;
176     }
177     break;
178     case CompileShaderRequest::Type():
179     {
180         auto req = Deserialize<CompileShaderRequest>(packet);
181 
182         vector<u8> result;
183         bool ok = CompileShader(req.source, req.commandLine, result);
184 
185         CompileShaderResponse res;
186         res.status = ok;
187         res.binary = std::move(result);
188         SendResponse(client, res);
189     }
190     break;
191     case StoreContentRequest::Type():
192     {
193         auto req = Deserialize<StoreContentRequest>(packet);
194         bool ok  = StoreFile(req.name, req.data);
195 
196         StoreContentResponse res;
197         res.status = ok;
198         SendResponse(client, res);
199     }
200     break;
201     case GetContentRequest::Type():
202     {
203         auto req = Deserialize<GetContentRequest>(packet);
204 
205         vector<u8> content;
206         bool ok = GetFile(req.path, content, req.removeAfter);
207 
208         GetContentResponse res;
209         res.status = ok;
210         res.data   = std::move(content);
211         SendResponse(client, res);
212     }
213     break;
214     case AppendRequest::Type():
215     {
216         auto req = Deserialize<AppendRequest>(packet);
217 
218         bool result = AppendFile(req.fileName, req.data, req.clear);
219         if (!result)
220             Log("[WARNING] Can't append file", req.fileName);
221     }
222     break;
223     case CreateCacheRequest::Type():
224     {
225         auto req = Deserialize<CreateCacheRequest>(packet);
226 
227         vector<u8> binary;
228         bool ok = false;
229         try
230         {
231             CreateVulkanSCCache(req.input, req.caseFraction, binary, client.cmdLineParams, client.logFile);
232             ok = true;
233         }
234         catch (const std::exception &e)
235         {
236             Log("[ERROR] Can't create cache:", e.what());
237             binary = {};
238         }
239 
240         CreateCacheResponse res;
241         res.status = ok;
242         res.binary = std::move(binary);
243         SendResponse(client, res);
244     }
245     break;
246 
247     default:
248         throw std::runtime_error("communication error");
249     }
250 }
251 
252 struct PacketsLoop
253 {
254     Client client;
255 
LoopPacketsLoop256     void Loop()
257     {
258         while (client.socket->isConnected() && client.appactive)
259         {
260             RecvSome(client.socket.get(), client.recvb);
261             auto interpret = [this](u32 type, vector<u8> packet)
262             { ProcessPacketsOnServer(client, type, std::move(packet)); };
263             while (ProccessNetworkData(client.recvb, interpret))
264             {
265             }
266         }
267     }
268 
operator ()PacketsLoop269     void operator()()
270     {
271         try
272         {
273             Loop();
274         }
275         catch (const std::exception &e)
276         {
277             client.socket->close();
278             Debug(e.what(), "from client with id", client.id);
279         }
280         Debug("Client with id", client.id, "disconnected.");
281     }
282 };
283 
CreateClientThread(Client client)284 std::future<void> CreateClientThread(Client client)
285 {
286     return std::async(PacketsLoop{std::move(client)});
287 }
288