1 //
2 // Copyright 2002 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 // angleutils.h: Common ANGLE utilities.
8
9 #ifndef COMMON_ANGLEUTILS_H_
10 #define COMMON_ANGLEUTILS_H_
11
12 #include "common/platform.h"
13
14 #if defined(ANGLE_USE_ABSEIL)
15 # include "absl/container/flat_hash_map.h"
16 # include "absl/container/flat_hash_set.h"
17 #endif // defined(ANGLE_USE_ABSEIL)
18
19 #if defined(ANGLE_WITH_LSAN)
20 # include <sanitizer/lsan_interface.h>
21 #endif // defined(ANGLE_WITH_LSAN)
22
23 #include <climits>
24 #include <cstdarg>
25 #include <cstddef>
26 #include <fstream>
27 #include <set>
28 #include <sstream>
29 #include <string>
30 #include <unordered_map>
31 #include <unordered_set>
32 #include <vector>
33
34 // A helper class to disallow copy and assignment operators
35 namespace angle
36 {
37
38 #if defined(ANGLE_ENABLE_D3D9) || defined(ANGLE_ENABLE_D3D11)
39 using Microsoft::WRL::ComPtr;
40 #endif // defined(ANGLE_ENABLE_D3D9) || defined(ANGLE_ENABLE_D3D11)
41
42 #if defined(ANGLE_USE_ABSEIL)
43 template <typename Key, typename T, class Hash = absl::container_internal::hash_default_hash<Key>>
44 using HashMap = absl::flat_hash_map<Key, T, Hash>;
45 template <typename Key, class Hash = absl::container_internal::hash_default_hash<Key>>
46 using HashSet = absl::flat_hash_set<Key, Hash>;
47 #else
48 template <typename Key, typename T, class Hash = std::hash<Key>>
49 using HashMap = std::unordered_map<Key, T, Hash>;
50 template <typename Key, class Hash = std::hash<Key>>
51 using HashSet = std::unordered_set<Key, Hash>;
52 #endif // defined(ANGLE_USE_ABSEIL)
53
54 class NonCopyable
55 {
56 protected:
57 constexpr NonCopyable() = default;
58 ~NonCopyable() = default;
59
60 private:
61 NonCopyable(const NonCopyable &) = delete;
62 void operator=(const NonCopyable &) = delete;
63 };
64
65 extern const uintptr_t DirtyPointer;
66
67 struct SaveFileHelper
68 {
69 public:
70 // We always use ios::binary to avoid inconsistent line endings when captured on Linux vs Win.
71 SaveFileHelper(const std::string &filePathIn);
72 ~SaveFileHelper();
73
74 template <typename T>
75 SaveFileHelper &operator<<(const T &value)
76 {
77 mOfs << value;
78 checkError();
79 return *this;
80 }
81
82 void write(const uint8_t *data, size_t size);
83
84 private:
85 void checkError();
86
87 std::ofstream mOfs;
88 std::string mFilePath;
89 };
90
91 } // namespace angle
92
93 template <typename T, size_t N>
ArraySize(T (&)[N])94 constexpr inline size_t ArraySize(T (&)[N])
95 {
96 return N;
97 }
98
99 template <typename T>
100 class WrappedArray final : angle::NonCopyable
101 {
102 public:
103 template <size_t N>
WrappedArray(const T (& data)[N])104 constexpr WrappedArray(const T (&data)[N]) : mArray(&data[0]), mSize(N)
105 {}
106
WrappedArray()107 constexpr WrappedArray() : mArray(nullptr), mSize(0) {}
WrappedArray(const T * data,size_t size)108 constexpr WrappedArray(const T *data, size_t size) : mArray(data), mSize(size) {}
109
WrappedArray(WrappedArray && other)110 WrappedArray(WrappedArray &&other) : WrappedArray()
111 {
112 std::swap(mArray, other.mArray);
113 std::swap(mSize, other.mSize);
114 }
115
~WrappedArray()116 ~WrappedArray() {}
117
get()118 constexpr const T *get() const { return mArray; }
size()119 constexpr size_t size() const { return mSize; }
120
121 private:
122 const T *mArray;
123 size_t mSize;
124 };
125
126 template <typename T, unsigned int N>
SafeRelease(T (& resourceBlock)[N])127 void SafeRelease(T (&resourceBlock)[N])
128 {
129 for (unsigned int i = 0; i < N; i++)
130 {
131 SafeRelease(resourceBlock[i]);
132 }
133 }
134
135 template <typename T>
SafeRelease(T & resource)136 void SafeRelease(T &resource)
137 {
138 if (resource)
139 {
140 resource->Release();
141 resource = nullptr;
142 }
143 }
144
145 template <typename T>
SafeDelete(T * & resource)146 void SafeDelete(T *&resource)
147 {
148 delete resource;
149 resource = nullptr;
150 }
151
152 template <typename T>
SafeDeleteContainer(T & resource)153 void SafeDeleteContainer(T &resource)
154 {
155 for (auto &element : resource)
156 {
157 SafeDelete(element);
158 }
159 resource.clear();
160 }
161
162 template <typename T>
SafeDeleteArray(T * & resource)163 void SafeDeleteArray(T *&resource)
164 {
165 delete[] resource;
166 resource = nullptr;
167 }
168
169 // Provide a less-than function for comparing structs
170 // Note: struct memory must be initialized to zero, because of packing gaps
171 template <typename T>
StructLessThan(const T & a,const T & b)172 inline bool StructLessThan(const T &a, const T &b)
173 {
174 return (memcmp(&a, &b, sizeof(T)) < 0);
175 }
176
177 // Provide a less-than function for comparing structs
178 // Note: struct memory must be initialized to zero, because of packing gaps
179 template <typename T>
StructEquals(const T & a,const T & b)180 inline bool StructEquals(const T &a, const T &b)
181 {
182 return (memcmp(&a, &b, sizeof(T)) == 0);
183 }
184
185 template <typename T>
StructZero(T * obj)186 inline void StructZero(T *obj)
187 {
188 memset(obj, 0, sizeof(T));
189 }
190
191 template <typename T>
IsMaskFlagSet(T mask,T flag)192 inline bool IsMaskFlagSet(T mask, T flag)
193 {
194 // Handles multibit flags as well
195 return (mask & flag) == flag;
196 }
197
MakeStaticString(const std::string & str)198 inline const char *MakeStaticString(const std::string &str)
199 {
200 // On the heap so that no destructor runs on application exit.
201 static std::set<std::string> *strings = new std::set<std::string>;
202 std::set<std::string>::iterator it = strings->find(str);
203 if (it != strings->end())
204 {
205 return it->c_str();
206 }
207
208 return strings->insert(str).first->c_str();
209 }
210
211 std::string ArrayString(unsigned int i);
212
213 // Indices are stored in vectors with the outermost index in the back. In the output of the function
214 // the indices are reversed.
215 std::string ArrayIndexString(const std::vector<unsigned int> &indices);
216
Str(int i)217 inline std::string Str(int i)
218 {
219 std::stringstream strstr;
220 strstr << i;
221 return strstr.str();
222 }
223
224 size_t FormatStringIntoVector(const char *fmt, va_list vararg, std::vector<char> &buffer);
225
226 template <typename T>
ToString(const T & value)227 std::string ToString(const T &value)
228 {
229 std::ostringstream o;
230 o << value;
231 return o.str();
232 }
233
IsLittleEndian()234 inline bool IsLittleEndian()
235 {
236 constexpr uint32_t kEndiannessTest = 1;
237 const bool isLittleEndian = *reinterpret_cast<const uint8_t *>(&kEndiannessTest) == 1;
238 return isLittleEndian;
239 }
240
241 // snprintf is not defined with MSVC prior to to msvc14
242 #if defined(_MSC_VER) && _MSC_VER < 1900
243 # define snprintf _snprintf
244 #endif
245
246 #define GL_A1RGB5_ANGLEX 0x6AC5
247 #define GL_BGRX8_ANGLEX 0x6ABA
248 #define GL_BGR565_ANGLEX 0x6ABB
249 #define GL_BGRA4_ANGLEX 0x6ABC
250 #define GL_BGR5_A1_ANGLEX 0x6ABD
251 #define GL_INT_64_ANGLEX 0x6ABE
252 #define GL_UINT_64_ANGLEX 0x6ABF
253 #define GL_BGRA8_SRGB_ANGLEX 0x6AC0
254 #define GL_BGR10_A2_ANGLEX 0x6AF9
255
256 // These are fake formats used to fit typeless D3D textures that can be bound to EGL pbuffers into
257 // the format system (for extension EGL_ANGLE_d3d_texture_client_buffer):
258 #define GL_RGBA8_TYPELESS_ANGLEX 0x6AC1
259 #define GL_RGBA8_TYPELESS_SRGB_ANGLEX 0x6AC2
260 #define GL_BGRA8_TYPELESS_ANGLEX 0x6AC3
261 #define GL_BGRA8_TYPELESS_SRGB_ANGLEX 0x6AC4
262
263 #define GL_R8_SSCALED_ANGLEX 0x6AC6
264 #define GL_RG8_SSCALED_ANGLEX 0x6AC7
265 #define GL_RGB8_SSCALED_ANGLEX 0x6AC8
266 #define GL_RGBA8_SSCALED_ANGLEX 0x6AC9
267 #define GL_R8_USCALED_ANGLEX 0x6ACA
268 #define GL_RG8_USCALED_ANGLEX 0x6ACB
269 #define GL_RGB8_USCALED_ANGLEX 0x6ACC
270 #define GL_RGBA8_USCALED_ANGLEX 0x6ACD
271
272 #define GL_R16_SSCALED_ANGLEX 0x6ACE
273 #define GL_RG16_SSCALED_ANGLEX 0x6ACF
274 #define GL_RGB16_SSCALED_ANGLEX 0x6AD0
275 #define GL_RGBA16_SSCALED_ANGLEX 0x6AD1
276 #define GL_R16_USCALED_ANGLEX 0x6AD2
277 #define GL_RG16_USCALED_ANGLEX 0x6AD3
278 #define GL_RGB16_USCALED_ANGLEX 0x6AD4
279 #define GL_RGBA16_USCALED_ANGLEX 0x6AD5
280
281 #define GL_R32_SSCALED_ANGLEX 0x6AD6
282 #define GL_RG32_SSCALED_ANGLEX 0x6AD7
283 #define GL_RGB32_SSCALED_ANGLEX 0x6AD8
284 #define GL_RGBA32_SSCALED_ANGLEX 0x6AD9
285 #define GL_R32_USCALED_ANGLEX 0x6ADA
286 #define GL_RG32_USCALED_ANGLEX 0x6ADB
287 #define GL_RGB32_USCALED_ANGLEX 0x6ADC
288 #define GL_RGBA32_USCALED_ANGLEX 0x6ADD
289
290 #define GL_R32_SNORM_ANGLEX 0x6ADE
291 #define GL_RG32_SNORM_ANGLEX 0x6ADF
292 #define GL_RGB32_SNORM_ANGLEX 0x6AE0
293 #define GL_RGBA32_SNORM_ANGLEX 0x6AE1
294 #define GL_R32_UNORM_ANGLEX 0x6AE2
295 #define GL_RG32_UNORM_ANGLEX 0x6AE3
296 #define GL_RGB32_UNORM_ANGLEX 0x6AE4
297 #define GL_RGBA32_UNORM_ANGLEX 0x6AE5
298
299 #define GL_R32_FIXED_ANGLEX 0x6AE6
300 #define GL_RG32_FIXED_ANGLEX 0x6AE7
301 #define GL_RGB32_FIXED_ANGLEX 0x6AE8
302 #define GL_RGBA32_FIXED_ANGLEX 0x6AE9
303
304 #define GL_RGB10_A2_SINT_ANGLEX 0x6AEA
305 #define GL_RGB10_A2_SNORM_ANGLEX 0x6AEB
306 #define GL_RGB10_A2_SSCALED_ANGLEX 0x6AEC
307 #define GL_RGB10_A2_USCALED_ANGLEX 0x6AED
308
309 // EXT_texture_type_2_10_10_10_REV
310 #define GL_RGB10_UNORM_ANGLEX 0x6AEE
311
312 // These are fake formats for OES_vertex_type_10_10_10_2
313 #define GL_A2_RGB10_UNORM_ANGLEX 0x6AEF
314 #define GL_A2_RGB10_SNORM_ANGLEX 0x6AF0
315 #define GL_A2_RGB10_USCALED_ANGLEX 0x6AF1
316 #define GL_A2_RGB10_SSCALED_ANGLEX 0x6AF2
317 #define GL_X2_RGB10_UINT_ANGLEX 0x6AF3
318 #define GL_X2_RGB10_SINT_ANGLEX 0x6AF4
319 #define GL_X2_RGB10_USCALED_ANGLEX 0x6AF5
320 #define GL_X2_RGB10_SSCALED_ANGLEX 0x6AF6
321 #define GL_X2_RGB10_UNORM_ANGLEX 0x6AF7
322 #define GL_X2_RGB10_SNORM_ANGLEX 0x6AF8
323
324 #define ANGLE_CHECK_GL_ALLOC(context, result) \
325 ANGLE_CHECK(context, result, "Failed to allocate host memory", GL_OUT_OF_MEMORY)
326
327 #define ANGLE_CHECK_GL_MATH(context, result) \
328 ANGLE_CHECK(context, result, "Integer overflow.", GL_INVALID_OPERATION)
329
330 #define ANGLE_GL_UNREACHABLE(context) \
331 UNREACHABLE(); \
332 ANGLE_CHECK(context, false, "Unreachable Code.", GL_INVALID_OPERATION)
333
334 #if defined(ANGLE_WITH_LSAN)
335 # define ANGLE_SCOPED_DISABLE_LSAN() __lsan::ScopedDisabler lsanDisabler
336 #else
337 # define ANGLE_SCOPED_DISABLE_LSAN()
338 #endif
339
340 // The ANGLE_NO_SANITIZE_MEMORY macro suppresses MemorySanitizer checks for
341 // use-of-uninitialized-data. It can be used to decorate functions with known
342 // false positives.
343 #ifdef __clang__
344 # define ANGLE_NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory))
345 #else
346 # define ANGLE_NO_SANITIZE_MEMORY
347 #endif
348
349 // Similar to the above, but for thread sanitization.
350 #ifdef __clang__
351 # define ANGLE_NO_SANITIZE_THREAD __attribute__((no_sanitize_thread))
352 #else
353 # define ANGLE_NO_SANITIZE_THREAD
354 #endif
355
356 // The below inlining code lifted from V8.
357 #if defined(__clang__) || (defined(__GNUC__) && defined(__has_attribute))
358 # define ANGLE_HAS_ATTRIBUTE_ALWAYS_INLINE (__has_attribute(always_inline))
359 # define ANGLE_HAS___FORCEINLINE 0
360 #elif defined(_MSC_VER)
361 # define ANGLE_HAS_ATTRIBUTE_ALWAYS_INLINE 0
362 # define ANGLE_HAS___FORCEINLINE 1
363 #else
364 # define ANGLE_HAS_ATTRIBUTE_ALWAYS_INLINE 0
365 # define ANGLE_HAS___FORCEINLINE 0
366 #endif
367
368 #if defined(NDEBUG) && ANGLE_HAS_ATTRIBUTE_ALWAYS_INLINE
369 # define ANGLE_INLINE inline __attribute__((always_inline))
370 #elif defined(NDEBUG) && ANGLE_HAS___FORCEINLINE
371 # define ANGLE_INLINE __forceinline
372 #else
373 # define ANGLE_INLINE inline
374 #endif
375
376 #if defined(__clang__) || (defined(__GNUC__) && defined(__has_attribute))
377 # if __has_attribute(noinline)
378 # define ANGLE_NOINLINE __attribute__((noinline))
379 # else
380 # define ANGLE_NOINLINE
381 # endif
382 #elif defined(_MSC_VER)
383 # define ANGLE_NOINLINE __declspec(noinline)
384 #else
385 # define ANGLE_NOINLINE
386 #endif
387
388 #if defined(__clang__) || (defined(__GNUC__) && defined(__has_attribute))
389 # if __has_attribute(format)
390 # define ANGLE_FORMAT_PRINTF(fmt, args) __attribute__((format(__printf__, fmt, args)))
391 # else
392 # define ANGLE_FORMAT_PRINTF(fmt, args)
393 # endif
394 #else
395 # define ANGLE_FORMAT_PRINTF(fmt, args)
396 #endif
397
398 // Format messes up the # inside the macro.
399 // clang-format off
400 #ifndef ANGLE_STRINGIFY
401 # define ANGLE_STRINGIFY(x) #x
402 #endif
403 // clang-format on
404
405 #ifndef ANGLE_MACRO_STRINGIFY
406 # define ANGLE_MACRO_STRINGIFY(x) ANGLE_STRINGIFY(x)
407 #endif
408
409 // Detect support for C++17 [[nodiscard]]
410 #if !defined(__has_cpp_attribute)
411 # define __has_cpp_attribute(name) 0
412 #endif // !defined(__has_cpp_attribute)
413
414 #if __has_cpp_attribute(nodiscard)
415 # define ANGLE_NO_DISCARD [[nodiscard]]
416 #else
417 # define ANGLE_NO_DISCARD
418 #endif // __has_cpp_attribute(nodiscard)
419
420 #if __has_cpp_attribute(maybe_unused)
421 # define ANGLE_MAYBE_UNUSED [[maybe_unused]]
422 #else
423 # define ANGLE_MAYBE_UNUSED
424 #endif // __has_cpp_attribute(maybe_unused)
425
426 #if __has_cpp_attribute(require_constant_initialization)
427 # define ANGLE_REQUIRE_CONSTANT_INIT [[require_constant_initialization]]
428 #else
429 # define ANGLE_REQUIRE_CONSTANT_INIT
430 #endif // __has_cpp_attribute(require_constant_initialization)
431
432 #if __has_cpp_attribute(clang::fallthrough)
433 # define ANGLE_FALLTHROUGH [[clang::fallthrough]]
434 #else
435 # define ANGLE_FALLTHROUGH
436 #endif
437
438 // Compiler configs.
IsASan()439 inline bool IsASan()
440 {
441 #if defined(ANGLE_WITH_ASAN)
442 return true;
443 #else
444 return false;
445 #endif // defined(ANGLE_WITH_ASAN)
446 }
447
IsTSan()448 inline bool IsTSan()
449 {
450 #if defined(ANGLE_WITH_TSAN)
451 return true;
452 #else
453 return false;
454 #endif // defined(ANGLE_WITH_TSAN)
455 }
456
IsUBSan()457 inline bool IsUBSan()
458 {
459 #if defined(ANGLE_WITH_UBSAN)
460 return true;
461 #else
462 return false;
463 #endif // defined(ANGLE_WITH_UBSAN)
464 }
465 #endif // COMMON_ANGLEUTILS_H_
466