1 //
2 // Copyright 2014 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 // angle_test_instantiate.h: Adds support for filtering parameterized
8 // tests by platform, so we skip unsupported configs.
9 
10 #ifndef ANGLE_TEST_INSTANTIATE_H_
11 #define ANGLE_TEST_INSTANTIATE_H_
12 
13 #include <gtest/gtest.h>
14 
15 #include "common/platform.h"
16 
17 namespace angle
18 {
19 struct SystemInfo;
20 struct PlatformParameters;
21 
22 // Operating systems
23 bool IsAndroid();
24 bool IsLinux();
25 bool IsOSX();
26 bool IsOzone();
27 bool IsWindows();
28 bool IsWindows7();
29 bool IsFuchsia();
30 
31 // CPU architectures
32 bool IsARM64();
33 
34 // Android devices
35 bool IsNexus5X();
36 bool IsNexus6P();
37 bool IsNexus9();
38 bool IsPixelXL();
39 bool IsPixel2();
40 bool IsPixel2XL();
41 bool IsNVIDIAShield();
42 
43 // GPU vendors.
44 bool IsIntel();
45 bool IsAMD();
46 bool IsARM();
47 bool IsNVIDIA();
48 
49 // GPU devices.
50 bool IsSwiftshaderDevice();
51 bool IsIntelUHD630Mobile();
52 
53 // Compiler configs.
IsASan()54 inline bool IsASan()
55 {
56 #if defined(ANGLE_WITH_ASAN)
57     return true;
58 #else
59     return false;
60 #endif  // defined(ANGLE_WITH_ASAN)
61 }
62 
IsTSan()63 inline bool IsTSan()
64 {
65 #if defined(THREAD_SANITIZER)
66     return true;
67 #else
68     return false;
69 #endif  // defined(THREAD_SANITIZER)
70 }
71 
72 bool IsPlatformAvailable(const PlatformParameters &param);
73 
74 // This functions is used to filter which tests should be registered,
75 // T must be or inherit from angle::PlatformParameters.
76 template <typename T>
FilterTestParams(const T * params,size_t numParams)77 std::vector<T> FilterTestParams(const T *params, size_t numParams)
78 {
79     std::vector<T> filtered;
80 
81     for (size_t i = 0; i < numParams; i++)
82     {
83         if (IsPlatformAvailable(params[i]))
84         {
85             filtered.push_back(params[i]);
86         }
87     }
88 
89     return filtered;
90 }
91 
92 template <typename T>
FilterTestParams(const std::vector<T> & params)93 std::vector<T> FilterTestParams(const std::vector<T> &params)
94 {
95     return FilterTestParams(params.data(), params.size());
96 }
97 
98 // Used to generate valid test names out of testing::PrintToStringParamName used in combined tests.
99 struct CombinedPrintToStringParamName
100 {
101     template <class ParamType>
operatorCombinedPrintToStringParamName102     std::string operator()(const testing::TestParamInfo<ParamType> &info) const
103     {
104         std::string name = testing::PrintToStringParamName()(info);
105         std::string sanitized;
106         for (const char c : name)
107         {
108             if (c == ',')
109             {
110                 sanitized += '_';
111             }
112             else if (isalnum(c) || c == '_')
113             {
114                 sanitized += c;
115             }
116         }
117         return sanitized;
118     }
119 };
120 
121 #define ANGLE_INSTANTIATE_TEST_PLATFORMS(testName, ...)                        \
122     testing::ValuesIn(::angle::FilterTestParams(testName##__VA_ARGS__##params, \
123                                                 ArraySize(testName##__VA_ARGS__##params)))
124 
125 // Instantiate the test once for each extra argument. The types of all the
126 // arguments must match, and getRenderer must be implemented for that type.
127 #define ANGLE_INSTANTIATE_TEST(testName, first, ...)                                 \
128     const decltype(first) testName##params[] = {first, ##__VA_ARGS__};               \
129     INSTANTIATE_TEST_SUITE_P(, testName, ANGLE_INSTANTIATE_TEST_PLATFORMS(testName), \
130                              testing::PrintToStringParamName())
131 
132 #define ANGLE_INSTANTIATE_TEST_ARRAY(testName, valuesin)                                         \
133     INSTANTIATE_TEST_SUITE_P(, testName, testing::ValuesIn(::angle::FilterTestParams(valuesin)), \
134                              testing::PrintToStringParamName())
135 
136 #define ANGLE_ALL_TEST_PLATFORMS_ES1                                                   \
137     ES1_D3D11(), ES1_OPENGL(), ES1_OPENGLES(), ES1_VULKAN(), ES1_VULKAN_SWIFTSHADER(), \
138         WithAsyncCommandQueueFeatureVulkan(ES1_VULKAN())
139 
140 #define ANGLE_ALL_TEST_PLATFORMS_ES2                                                               \
141     ES2_D3D9(), ES2_D3D11(), ES2_OPENGL(), ES2_OPENGLES(), ES2_VULKAN(), ES2_VULKAN_SWIFTSHADER(), \
142         ES2_METAL(), WithAsyncCommandQueueFeatureVulkan(ES2_VULKAN())
143 
144 #define ANGLE_ALL_TEST_PLATFORMS_ES3                                                   \
145     ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES(), ES3_VULKAN(), ES3_VULKAN_SWIFTSHADER(), \
146         ES3_METAL(), WithAsyncCommandQueueFeatureVulkan(ES3_VULKAN())
147 
148 #define ANGLE_ALL_TEST_PLATFORMS_ES31                                                       \
149     ES31_D3D11(), ES31_OPENGL(), ES31_OPENGLES(), ES31_VULKAN(), ES31_VULKAN_SWIFTSHADER(), \
150         WithAsyncCommandQueueFeatureVulkan(ES31_VULKAN())
151 
152 #define ANGLE_ALL_TEST_PLATFORMS_NULL ES2_NULL(), ES3_NULL(), ES31_NULL()
153 
154 // Instantiate the test once for each GLES1 platform
155 #define ANGLE_INSTANTIATE_TEST_ES1(testName)                                         \
156     const PlatformParameters testName##params[] = {ANGLE_ALL_TEST_PLATFORMS_ES1};    \
157     INSTANTIATE_TEST_SUITE_P(, testName, ANGLE_INSTANTIATE_TEST_PLATFORMS(testName), \
158                              testing::PrintToStringParamName())
159 
160 // Instantiate the test once for each GLES2 platform
161 #define ANGLE_INSTANTIATE_TEST_ES2(testName)                                         \
162     const PlatformParameters testName##params[] = {ANGLE_ALL_TEST_PLATFORMS_ES2};    \
163     INSTANTIATE_TEST_SUITE_P(, testName, ANGLE_INSTANTIATE_TEST_PLATFORMS(testName), \
164                              testing::PrintToStringParamName())
165 
166 // Instantiate the test once for each GLES3 platform
167 #define ANGLE_INSTANTIATE_TEST_ES3(testName)                                         \
168     const PlatformParameters testName##params[] = {ANGLE_ALL_TEST_PLATFORMS_ES3};    \
169     INSTANTIATE_TEST_SUITE_P(, testName, ANGLE_INSTANTIATE_TEST_PLATFORMS(testName), \
170                              testing::PrintToStringParamName())
171 
172 #define ANGLE_INSTANTIATE_TEST_ES3_AND(testName, ...)                                          \
173     const PlatformParameters testName##params[] = {ANGLE_ALL_TEST_PLATFORMS_ES3, __VA_ARGS__}; \
174     INSTANTIATE_TEST_SUITE_P(, testName, ANGLE_INSTANTIATE_TEST_PLATFORMS(testName),           \
175                              testing::PrintToStringParamName())
176 
177 // Instantiate the test once for each GLES31 platform
178 #define ANGLE_INSTANTIATE_TEST_ES31(testName)                                        \
179     const PlatformParameters testName##params[] = {ANGLE_ALL_TEST_PLATFORMS_ES31};   \
180     INSTANTIATE_TEST_SUITE_P(, testName, ANGLE_INSTANTIATE_TEST_PLATFORMS(testName), \
181                              testing::PrintToStringParamName())
182 
183 #define ANGLE_INSTANTIATE_TEST_ES31_AND(testName, ...)                                          \
184     const PlatformParameters testName##params[] = {ANGLE_ALL_TEST_PLATFORMS_ES31, __VA_ARGS__}; \
185     INSTANTIATE_TEST_SUITE_P(, testName, ANGLE_INSTANTIATE_TEST_PLATFORMS(testName),            \
186                              testing::PrintToStringParamName())
187 
188 // Multiple ES Version macros
189 #define ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(testName)                                 \
190     const PlatformParameters testName##params[] = {ANGLE_ALL_TEST_PLATFORMS_ES2,     \
191                                                    ANGLE_ALL_TEST_PLATFORMS_ES3};    \
192     INSTANTIATE_TEST_SUITE_P(, testName, ANGLE_INSTANTIATE_TEST_PLATFORMS(testName), \
193                              testing::PrintToStringParamName())
194 
195 #define ANGLE_INSTANTIATE_TEST_ES2_AND_ES3_AND(testName, ...)                                  \
196     const PlatformParameters testName##params[] = {ANGLE_ALL_TEST_PLATFORMS_ES2,               \
197                                                    ANGLE_ALL_TEST_PLATFORMS_ES3, __VA_ARGS__}; \
198     INSTANTIATE_TEST_SUITE_P(, testName, ANGLE_INSTANTIATE_TEST_PLATFORMS(testName),           \
199                              testing::PrintToStringParamName())
200 
201 #define ANGLE_INSTANTIATE_TEST_ES2_AND_ES3_AND_ES31(testName)                        \
202     const PlatformParameters testName##params[] = {ANGLE_ALL_TEST_PLATFORMS_ES2,     \
203                                                    ANGLE_ALL_TEST_PLATFORMS_ES3,     \
204                                                    ANGLE_ALL_TEST_PLATFORMS_ES31};   \
205     INSTANTIATE_TEST_SUITE_P(, testName, ANGLE_INSTANTIATE_TEST_PLATFORMS(testName), \
206                              testing::PrintToStringParamName())
207 
208 #define ANGLE_INSTANTIATE_TEST_ES2_AND_ES3_AND_ES31_AND_NULL(testName)                             \
209     const PlatformParameters testName##params[] = {                                                \
210         ANGLE_ALL_TEST_PLATFORMS_ES2, ANGLE_ALL_TEST_PLATFORMS_ES3, ANGLE_ALL_TEST_PLATFORMS_ES31, \
211         ANGLE_ALL_TEST_PLATFORMS_NULL};                                                            \
212     INSTANTIATE_TEST_SUITE_P(, testName, ANGLE_INSTANTIATE_TEST_PLATFORMS(testName),               \
213                              testing::PrintToStringParamName())
214 
215 #define ANGLE_INSTANTIATE_TEST_ES3_AND_ES31(testName)                                \
216     const PlatformParameters testName##params[] = {ANGLE_ALL_TEST_PLATFORMS_ES3,     \
217                                                    ANGLE_ALL_TEST_PLATFORMS_ES31};   \
218     INSTANTIATE_TEST_SUITE_P(, testName, ANGLE_INSTANTIATE_TEST_PLATFORMS(testName), \
219                              testing::PrintToStringParamName())
220 
221 #define ANGLE_INSTANTIATE_TEST_ES3_AND_ES31_AND(testName, ...)                                  \
222     const PlatformParameters testName##params[] = {ANGLE_ALL_TEST_PLATFORMS_ES3,                \
223                                                    ANGLE_ALL_TEST_PLATFORMS_ES31, __VA_ARGS__}; \
224     INSTANTIATE_TEST_SUITE_P(, testName, ANGLE_INSTANTIATE_TEST_PLATFORMS(testName),            \
225                              testing::PrintToStringParamName())
226 
227 // Instantiate the test for a combination of N parameters and the
228 // enumeration of platforms in the extra args, similar to
229 // ANGLE_INSTANTIATE_TEST.  The macros are defined only for the Ns
230 // currently in use, and can be expanded as necessary.
231 #define ANGLE_INSTANTIATE_TEST_COMBINE_1(testName, print, combine1, first, ...) \
232     const decltype(first) testName##params[] = {first, ##__VA_ARGS__};          \
233     INSTANTIATE_TEST_SUITE_P(                                                   \
234         , testName, testing::Combine(ANGLE_INSTANTIATE_TEST_PLATFORMS(testName), combine1), print)
235 #define ANGLE_INSTANTIATE_TEST_COMBINE_4(testName, print, combine1, combine2, combine3, combine4, \
236                                          first, ...)                                              \
237     const decltype(first) testName##params[] = {first, ##__VA_ARGS__};                            \
238     INSTANTIATE_TEST_SUITE_P(, testName,                                                          \
239                              testing::Combine(ANGLE_INSTANTIATE_TEST_PLATFORMS(testName),         \
240                                               combine1, combine2, combine3, combine4),            \
241                              print)
242 #define ANGLE_INSTANTIATE_TEST_COMBINE_5(testName, print, combine1, combine2, combine3, combine4, \
243                                          combine5, first, ...)                                    \
244     const decltype(first) testName##params[] = {first, ##__VA_ARGS__};                            \
245     INSTANTIATE_TEST_SUITE_P(, testName,                                                          \
246                              testing::Combine(ANGLE_INSTANTIATE_TEST_PLATFORMS(testName),         \
247                                               combine1, combine2, combine3, combine4, combine5),  \
248                              print)
249 
250 // Checks if a config is expected to be supported by checking a system-based allow list.
251 bool IsConfigAllowlisted(const SystemInfo &systemInfo, const PlatformParameters &param);
252 
253 // Determines if a config is supported by trying to initialize it. Does
254 // not require SystemInfo.
255 bool IsConfigSupported(const PlatformParameters &param);
256 
257 // Returns shared test system information. Can be used globally in the
258 // tests.
259 SystemInfo *GetTestSystemInfo();
260 
261 // Returns a list of all enabled test platform names. For use in
262 // configuration enumeration.
263 std::vector<std::string> GetAvailableTestPlatformNames();
264 
265 // Active config (e.g. ES2_Vulkan).
266 void SetSelectedConfig(const char *selectedConfig);
267 bool IsConfigSelected();
268 
269 // Check whether texture swizzle is natively supported on Metal device.
270 bool IsMetalTextureSwizzleAvailable();
271 
272 extern bool gEnableANGLEPerTestCaptureLabel;
273 
274 // For use with ANGLE_INSTANTIATE_TEST_ARRAY
275 template <typename ParamsT>
276 using ModifierFunc = std::function<ParamsT(const ParamsT &)>;
277 
278 template <typename ParamsT>
CombineWithFuncs(const std::vector<ParamsT> & in,const std::vector<ModifierFunc<ParamsT>> & modifiers)279 std::vector<ParamsT> CombineWithFuncs(const std::vector<ParamsT> &in,
280                                       const std::vector<ModifierFunc<ParamsT>> &modifiers)
281 {
282     std::vector<ParamsT> out;
283     for (const ParamsT &paramsIn : in)
284     {
285         for (ModifierFunc<ParamsT> modifier : modifiers)
286         {
287             out.push_back(modifier(paramsIn));
288         }
289     }
290     return out;
291 }
292 
293 template <typename ParamT, typename RangeT, typename ModifierT>
CombineWithValues(const std::vector<ParamT> & in,RangeT begin,RangeT end,ParamT combine (const ParamT &,ModifierT))294 std::vector<ParamT> CombineWithValues(const std::vector<ParamT> &in,
295                                       RangeT begin,
296                                       RangeT end,
297                                       ParamT combine(const ParamT &, ModifierT))
298 {
299     std::vector<ParamT> out;
300     for (const ParamT &paramsIn : in)
301     {
302         for (auto iter = begin; iter != end; ++iter)
303         {
304             out.push_back(combine(paramsIn, *iter));
305         }
306     }
307     return out;
308 }
309 
310 template <typename ParamT, typename ModifierT>
CombineWithValues(const std::vector<ParamT> & in,const std::initializer_list<ModifierT> & modifiers,ParamT combine (const ParamT &,ModifierT))311 std::vector<ParamT> CombineWithValues(const std::vector<ParamT> &in,
312                                       const std::initializer_list<ModifierT> &modifiers,
313                                       ParamT combine(const ParamT &, ModifierT))
314 {
315     return CombineWithValues(in, modifiers.begin(), modifiers.end(), combine);
316 }
317 
318 template <typename ParamT, typename ModifiersT, typename ModifierT>
CombineWithValues(const std::vector<ParamT> & in,const ModifiersT & modifiers,ParamT combine (const ParamT &,ModifierT))319 std::vector<ParamT> CombineWithValues(const std::vector<ParamT> &in,
320                                       const ModifiersT &modifiers,
321                                       ParamT combine(const ParamT &, ModifierT))
322 {
323     return CombineWithValues(in, std::begin(modifiers), std::end(modifiers), combine);
324 }
325 
326 template <typename ParamT, typename FilterFunc>
FilterWithFunc(const std::vector<ParamT> & in,FilterFunc filter)327 std::vector<ParamT> FilterWithFunc(const std::vector<ParamT> &in, FilterFunc filter)
328 {
329     std::vector<ParamT> out;
330     for (const ParamT &param : in)
331     {
332         if (filter(param))
333         {
334             out.push_back(param);
335         }
336     }
337     return out;
338 }
339 }  // namespace angle
340 
341 #define ANGLE_SKIP_TEST_IF(COND)                                  \
342     do                                                            \
343     {                                                             \
344         if (COND)                                                 \
345         {                                                         \
346             std::cout << "Test skipped: " #COND "." << std::endl; \
347             return;                                               \
348         }                                                         \
349     } while (0)
350 
351 #endif  // ANGLE_TEST_INSTANTIATE_H_
352