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 {"webgpu", EGL_PLATFORM_ANGLE_TYPE_WEBGPU_ANGLE},
81 };
82 } // anonymous namespace
83
GetFileSize(const char * filePath,uint32_t * sizeOut)84 bool GetFileSize(const char *filePath, uint32_t *sizeOut)
85 {
86 std::ifstream stream(filePath);
87 if (!stream)
88 {
89 return false;
90 }
91
92 stream.seekg(0, std::ios::end);
93 *sizeOut = static_cast<uint32_t>(stream.tellg());
94 return true;
95 }
96
ReadEntireFileToString(const char * filePath,std::string * contentsOut)97 bool ReadEntireFileToString(const char *filePath, std::string *contentsOut)
98 {
99 std::ifstream stream(filePath);
100 if (!stream)
101 {
102 return false;
103 }
104
105 stream.seekg(0, std::ios::end);
106 contentsOut->reserve(static_cast<unsigned int>(stream.tellg()));
107 stream.seekg(0, std::ios::beg);
108
109 contentsOut->assign((std::istreambuf_iterator<char>(stream)), std::istreambuf_iterator<char>());
110
111 return true;
112 }
113
114 // static
115 Process::~Process() = default;
116
ProcessHandle()117 ProcessHandle::ProcessHandle() : mProcess(nullptr) {}
118
ProcessHandle(Process * process)119 ProcessHandle::ProcessHandle(Process *process) : mProcess(process) {}
120
ProcessHandle(const std::vector<const char * > & args,ProcessOutputCapture captureOutput)121 ProcessHandle::ProcessHandle(const std::vector<const char *> &args,
122 ProcessOutputCapture captureOutput)
123 : mProcess(LaunchProcess(args, captureOutput))
124 {}
125
~ProcessHandle()126 ProcessHandle::~ProcessHandle()
127 {
128 reset();
129 }
130
ProcessHandle(ProcessHandle && other)131 ProcessHandle::ProcessHandle(ProcessHandle &&other) : mProcess(other.mProcess)
132 {
133 other.mProcess = nullptr;
134 }
135
operator =(ProcessHandle && rhs)136 ProcessHandle &ProcessHandle::operator=(ProcessHandle &&rhs)
137 {
138 std::swap(mProcess, rhs.mProcess);
139 return *this;
140 }
141
reset()142 void ProcessHandle::reset()
143 {
144 if (mProcess)
145 {
146 delete mProcess;
147 mProcess = nullptr;
148 }
149 }
150
ParseIntArgWithHandling(const char * flag,int * argc,char ** argv,int argIndex,int * valueOut,ArgHandling handling)151 bool ParseIntArgWithHandling(const char *flag,
152 int *argc,
153 char **argv,
154 int argIndex,
155 int *valueOut,
156 ArgHandling handling)
157 {
158 const char *value = GetSingleArg(flag, argc, argv, argIndex, handling);
159 if (!value)
160 {
161 return false;
162 }
163
164 char *end = nullptr;
165 const long longValue = strtol(value, &end, 10);
166
167 if (*end != '\0')
168 {
169 printf("Error parsing integer flag value.\n");
170 exit(EXIT_FAILURE);
171 }
172
173 if (longValue == LONG_MAX || longValue == LONG_MIN || static_cast<int>(longValue) != longValue)
174 {
175 printf("Overflow when parsing integer flag value.\n");
176 exit(EXIT_FAILURE);
177 }
178
179 *valueOut = static_cast<int>(longValue);
180 // Note: return value is always false with ArgHandling::Preserve handling
181 return handling == ArgHandling::Delete;
182 }
183
ParseIntArg(const char * flag,int * argc,char ** argv,int argIndex,int * valueOut)184 bool ParseIntArg(const char *flag, int *argc, char **argv, int argIndex, int *valueOut)
185 {
186 return ParseIntArgWithHandling(flag, argc, argv, argIndex, valueOut, ArgHandling::Delete);
187 }
188
ParseFlag(const char * flag,int * argc,char ** argv,int argIndex,bool * flagOut)189 bool ParseFlag(const char *flag, int *argc, char **argv, int argIndex, bool *flagOut)
190 {
191 if (strcmp(flag, argv[argIndex]) == 0)
192 {
193 *flagOut = true;
194 DeleteArg(argc, argv, argIndex);
195 return true;
196 }
197 return false;
198 }
199
ParseStringArg(const char * flag,int * argc,char ** argv,int argIndex,std::string * valueOut)200 bool ParseStringArg(const char *flag, int *argc, char **argv, int argIndex, std::string *valueOut)
201 {
202 const char *value = GetSingleArg(flag, argc, argv, argIndex, ArgHandling::Delete);
203 if (!value)
204 {
205 return false;
206 }
207
208 *valueOut = value;
209 return true;
210 }
211
ParseCStringArgWithHandling(const char * flag,int * argc,char ** argv,int argIndex,const char ** valueOut,ArgHandling handling)212 bool ParseCStringArgWithHandling(const char *flag,
213 int *argc,
214 char **argv,
215 int argIndex,
216 const char **valueOut,
217 ArgHandling handling)
218 {
219 const char *value = GetSingleArg(flag, argc, argv, argIndex, handling);
220 if (!value)
221 {
222 return false;
223 }
224
225 *valueOut = value;
226 // Note: return value is always false with ArgHandling::Preserve handling
227 return handling == ArgHandling::Delete;
228 }
229
ParseCStringArg(const char * flag,int * argc,char ** argv,int argIndex,const char ** valueOut)230 bool ParseCStringArg(const char *flag, int *argc, char **argv, int argIndex, const char **valueOut)
231 {
232 return ParseCStringArgWithHandling(flag, argc, argv, argIndex, valueOut, ArgHandling::Delete);
233 }
234
AddArg(int * argc,char ** argv,const char * arg)235 void AddArg(int *argc, char **argv, const char *arg)
236 {
237 // This unsafe const_cast is necessary to work around gtest limitations.
238 argv[*argc] = const_cast<char *>(arg);
239 argv[*argc + 1] = nullptr;
240 (*argc)++;
241 }
242
GetPlatformANGLETypeFromArg(const char * useANGLEArg,uint32_t defaultPlatformType)243 uint32_t GetPlatformANGLETypeFromArg(const char *useANGLEArg, uint32_t defaultPlatformType)
244 {
245 if (!useANGLEArg)
246 {
247 return defaultPlatformType;
248 }
249
250 for (const DisplayTypeInfo &displayTypeInfo : kDisplayTypes)
251 {
252 if (strcmp(displayTypeInfo.first, useANGLEArg) == 0)
253 {
254 std::cout << "Using ANGLE back-end API: " << displayTypeInfo.first << std::endl;
255 return displayTypeInfo.second;
256 }
257 }
258
259 std::cout << "Unknown ANGLE back-end API: " << useANGLEArg << std::endl;
260 exit(EXIT_FAILURE);
261 }
262
GetANGLEDeviceTypeFromArg(const char * useANGLEArg,uint32_t defaultDeviceType)263 uint32_t GetANGLEDeviceTypeFromArg(const char *useANGLEArg, uint32_t defaultDeviceType)
264 {
265 if (useANGLEArg)
266 {
267 if (strcmp(useANGLEArg, "swiftshader") == 0)
268 {
269 return EGL_PLATFORM_ANGLE_DEVICE_TYPE_SWIFTSHADER_ANGLE;
270 }
271 if (strstr(useANGLEArg, "null") != 0)
272 {
273 return EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE;
274 }
275 }
276 return defaultDeviceType;
277 }
278 } // namespace angle
279