1 //
2 // Copyright 2019 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 // system_utils: Defines common utility functions
8
9 #include "util/test_utils.h"
10
11 #include <EGL/egl.h>
12 #include <EGL/eglext.h>
13
14 #include <cstring>
15 #include <fstream>
16 #include <iostream>
17
18 namespace angle
19 {
20
21 namespace
22 {
DeleteArg(int * argc,char ** argv,int argIndex)23 void DeleteArg(int *argc, char **argv, int argIndex)
24 {
25 // Shift the remainder of the argv list left by one. Note that argv has (*argc + 1) elements,
26 // the last one always being NULL. The following loop moves the trailing NULL element as well.
27 for (int index = argIndex; index < *argc; ++index)
28 {
29 argv[index] = argv[index + 1];
30 }
31 (*argc)--;
32 }
33
GetSingleArg(const char * flag,int * argc,char ** argv,int argIndex,ArgHandling handling)34 const char *GetSingleArg(const char *flag,
35 int *argc,
36 char **argv,
37 int argIndex,
38 ArgHandling handling)
39 {
40 if (strstr(argv[argIndex], flag) == argv[argIndex])
41 {
42 const char *ptr = argv[argIndex] + strlen(flag);
43
44 if (*ptr == '=')
45 {
46 if (handling == ArgHandling::Delete)
47 {
48 DeleteArg(argc, argv, argIndex);
49 }
50 return ptr + 1;
51 }
52
53 if (*ptr == '\0' && argIndex < *argc - 1)
54 {
55 ptr = argv[argIndex + 1];
56 if (handling == ArgHandling::Delete)
57 {
58 DeleteArg(argc, argv, argIndex);
59 DeleteArg(argc, argv, argIndex);
60 }
61 return ptr;
62 }
63 }
64
65 return nullptr;
66 }
67
68 using DisplayTypeInfo = std::pair<const char *, EGLint>;
69
70 const DisplayTypeInfo kDisplayTypes[] = {
71 {"d3d9", EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE},
72 {"d3d11", EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE},
73 {"gl", EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE},
74 {"gles", EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE},
75 {"metal", EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE},
76 {"null", EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE},
77 {"swiftshader", EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE},
78 {"vulkan", EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE},
79 {"vulkan-null", EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE},
80 };
81 } // anonymous namespace
82
GetFileSize(const char * filePath,uint32_t * sizeOut)83 bool GetFileSize(const char *filePath, uint32_t *sizeOut)
84 {
85 std::ifstream stream(filePath);
86 if (!stream)
87 {
88 return false;
89 }
90
91 stream.seekg(0, std::ios::end);
92 *sizeOut = static_cast<uint32_t>(stream.tellg());
93 return true;
94 }
95
ReadEntireFileToString(const char * filePath,std::string * contentsOut)96 bool ReadEntireFileToString(const char *filePath, std::string *contentsOut)
97 {
98 std::ifstream stream(filePath);
99 if (!stream)
100 {
101 return false;
102 }
103
104 stream.seekg(0, std::ios::end);
105 contentsOut->reserve(static_cast<unsigned int>(stream.tellg()));
106 stream.seekg(0, std::ios::beg);
107
108 contentsOut->assign((std::istreambuf_iterator<char>(stream)), std::istreambuf_iterator<char>());
109
110 return true;
111 }
112
113 // static
114 Process::~Process() = default;
115
ProcessHandle()116 ProcessHandle::ProcessHandle() : mProcess(nullptr) {}
117
ProcessHandle(Process * process)118 ProcessHandle::ProcessHandle(Process *process) : mProcess(process) {}
119
ProcessHandle(const std::vector<const char * > & args,ProcessOutputCapture captureOutput)120 ProcessHandle::ProcessHandle(const std::vector<const char *> &args,
121 ProcessOutputCapture captureOutput)
122 : mProcess(LaunchProcess(args, captureOutput))
123 {}
124
~ProcessHandle()125 ProcessHandle::~ProcessHandle()
126 {
127 reset();
128 }
129
ProcessHandle(ProcessHandle && other)130 ProcessHandle::ProcessHandle(ProcessHandle &&other) : mProcess(other.mProcess)
131 {
132 other.mProcess = nullptr;
133 }
134
operator =(ProcessHandle && rhs)135 ProcessHandle &ProcessHandle::operator=(ProcessHandle &&rhs)
136 {
137 std::swap(mProcess, rhs.mProcess);
138 return *this;
139 }
140
reset()141 void ProcessHandle::reset()
142 {
143 if (mProcess)
144 {
145 delete mProcess;
146 mProcess = nullptr;
147 }
148 }
149
ParseIntArgWithHandling(const char * flag,int * argc,char ** argv,int argIndex,int * valueOut,ArgHandling handling)150 bool ParseIntArgWithHandling(const char *flag,
151 int *argc,
152 char **argv,
153 int argIndex,
154 int *valueOut,
155 ArgHandling handling)
156 {
157 const char *value = GetSingleArg(flag, argc, argv, argIndex, handling);
158 if (!value)
159 {
160 return false;
161 }
162
163 char *end = nullptr;
164 const long longValue = strtol(value, &end, 10);
165
166 if (*end != '\0')
167 {
168 printf("Error parsing integer flag value.\n");
169 exit(EXIT_FAILURE);
170 }
171
172 if (longValue == LONG_MAX || longValue == LONG_MIN || static_cast<int>(longValue) != longValue)
173 {
174 printf("Overflow when parsing integer flag value.\n");
175 exit(EXIT_FAILURE);
176 }
177
178 *valueOut = static_cast<int>(longValue);
179 // Note: return value is always false with ArgHandling::Preserve handling
180 return handling == ArgHandling::Delete;
181 }
182
ParseIntArg(const char * flag,int * argc,char ** argv,int argIndex,int * valueOut)183 bool ParseIntArg(const char *flag, int *argc, char **argv, int argIndex, int *valueOut)
184 {
185 return ParseIntArgWithHandling(flag, argc, argv, argIndex, valueOut, ArgHandling::Delete);
186 }
187
ParseFlag(const char * flag,int * argc,char ** argv,int argIndex,bool * flagOut)188 bool ParseFlag(const char *flag, int *argc, char **argv, int argIndex, bool *flagOut)
189 {
190 if (strcmp(flag, argv[argIndex]) == 0)
191 {
192 *flagOut = true;
193 DeleteArg(argc, argv, argIndex);
194 return true;
195 }
196 return false;
197 }
198
ParseStringArg(const char * flag,int * argc,char ** argv,int argIndex,std::string * valueOut)199 bool ParseStringArg(const char *flag, int *argc, char **argv, int argIndex, std::string *valueOut)
200 {
201 const char *value = GetSingleArg(flag, argc, argv, argIndex, ArgHandling::Delete);
202 if (!value)
203 {
204 return false;
205 }
206
207 *valueOut = value;
208 return true;
209 }
210
ParseCStringArgWithHandling(const char * flag,int * argc,char ** argv,int argIndex,const char ** valueOut,ArgHandling handling)211 bool ParseCStringArgWithHandling(const char *flag,
212 int *argc,
213 char **argv,
214 int argIndex,
215 const char **valueOut,
216 ArgHandling handling)
217 {
218 const char *value = GetSingleArg(flag, argc, argv, argIndex, handling);
219 if (!value)
220 {
221 return false;
222 }
223
224 *valueOut = value;
225 // Note: return value is always false with ArgHandling::Preserve handling
226 return handling == ArgHandling::Delete;
227 }
228
ParseCStringArg(const char * flag,int * argc,char ** argv,int argIndex,const char ** valueOut)229 bool ParseCStringArg(const char *flag, int *argc, char **argv, int argIndex, const char **valueOut)
230 {
231 return ParseCStringArgWithHandling(flag, argc, argv, argIndex, valueOut, ArgHandling::Delete);
232 }
233
AddArg(int * argc,char ** argv,const char * arg)234 void AddArg(int *argc, char **argv, const char *arg)
235 {
236 // This unsafe const_cast is necessary to work around gtest limitations.
237 argv[*argc] = const_cast<char *>(arg);
238 argv[*argc + 1] = nullptr;
239 (*argc)++;
240 }
241
GetPlatformANGLETypeFromArg(const char * useANGLEArg,uint32_t defaultPlatformType)242 uint32_t GetPlatformANGLETypeFromArg(const char *useANGLEArg, uint32_t defaultPlatformType)
243 {
244 if (!useANGLEArg)
245 {
246 return defaultPlatformType;
247 }
248
249 for (const DisplayTypeInfo &displayTypeInfo : kDisplayTypes)
250 {
251 if (strcmp(displayTypeInfo.first, useANGLEArg) == 0)
252 {
253 std::cout << "Using ANGLE back-end API: " << displayTypeInfo.first << std::endl;
254 return displayTypeInfo.second;
255 }
256 }
257
258 std::cout << "Unknown ANGLE back-end API: " << useANGLEArg << std::endl;
259 exit(EXIT_FAILURE);
260 }
261
GetANGLEDeviceTypeFromArg(const char * useANGLEArg,uint32_t defaultDeviceType)262 uint32_t GetANGLEDeviceTypeFromArg(const char *useANGLEArg, uint32_t defaultDeviceType)
263 {
264 if (useANGLEArg)
265 {
266 if (strcmp(useANGLEArg, "swiftshader") == 0)
267 {
268 return EGL_PLATFORM_ANGLE_DEVICE_TYPE_SWIFTSHADER_ANGLE;
269 }
270 if (strstr(useANGLEArg, "null") != 0)
271 {
272 return EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE;
273 }
274 }
275 return defaultDeviceType;
276 }
277 } // namespace angle
278