Tobin Ehlis | 96a184d | 2018-07-18 16:14:07 -0600 | [diff] [blame] | 1 | // |
| 2 | // Copyright (c) 2015 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 | // Platform.h: The public interface ANGLE exposes to the API layer, for |
| 7 | // doing platform-specific tasks like gathering data, or for tracing. |
| 8 | |
| 9 | #ifndef ANGLE_PLATFORM_H |
| 10 | #define ANGLE_PLATFORM_H |
| 11 | |
| 12 | #include <stdint.h> |
| 13 | #include <array> |
| 14 | |
| 15 | #define EGL_PLATFORM_ANGLE_PLATFORM_METHODS_ANGLEX 0x3482 |
| 16 | |
| 17 | #if defined(_WIN32) |
| 18 | # if !defined(LIBANGLE_IMPLEMENTATION) |
| 19 | # define ANGLE_PLATFORM_EXPORT __declspec(dllimport) |
| 20 | # else |
| 21 | # define ANGLE_PLATFORM_EXPORT __declspec(dllexport) |
| 22 | # endif |
| 23 | #elif defined(__GNUC__) || defined(__clang__) |
| 24 | # define ANGLE_PLATFORM_EXPORT __attribute__((visibility ("default"))) |
| 25 | #endif |
| 26 | #if !defined(ANGLE_PLATFORM_EXPORT) |
| 27 | # define ANGLE_PLATFORM_EXPORT |
| 28 | #endif |
| 29 | |
| 30 | #if defined(_WIN32) |
| 31 | # define ANGLE_APIENTRY __stdcall |
| 32 | #else |
| 33 | # define ANGLE_APIENTRY |
| 34 | #endif |
| 35 | |
| 36 | namespace angle |
| 37 | { |
| 38 | struct WorkaroundsD3D; |
Tobin Ehlis | f95bf34 | 2018-11-13 12:56:01 -0700 | [diff] [blame] | 39 | struct FeaturesVk; |
Tobin Ehlis | 96a184d | 2018-07-18 16:14:07 -0600 | [diff] [blame] | 40 | using TraceEventHandle = uint64_t; |
| 41 | using EGLDisplayType = void *; |
| 42 | struct PlatformMethods; |
| 43 | |
| 44 | // Use a C-like API to not trigger undefined calling behaviour. |
| 45 | // Avoid using decltype here to work around sanitizer limitations. |
| 46 | // TODO(jmadill): Use decltype here if/when UBSAN is fixed. |
| 47 | |
| 48 | // System -------------------------------------------------------------- |
| 49 | |
| 50 | // Wall clock time in seconds since the epoch. |
| 51 | // TODO(jmadill): investigate using an ANGLE internal time library |
| 52 | using CurrentTimeFunc = double (*)(PlatformMethods *platform); |
| 53 | inline double DefaultCurrentTime(PlatformMethods *platform) |
| 54 | { |
| 55 | return 0.0; |
| 56 | } |
| 57 | |
| 58 | // Monotonically increasing time in seconds from an arbitrary fixed point in the past. |
| 59 | // This function is expected to return at least millisecond-precision values. For this reason, |
| 60 | // it is recommended that the fixed point be no further in the past than the epoch. |
| 61 | using MonotonicallyIncreasingTimeFunc = double (*)(PlatformMethods *platform); |
| 62 | inline double DefaultMonotonicallyIncreasingTime(PlatformMethods *platform) |
| 63 | { |
| 64 | return 0.0; |
| 65 | } |
| 66 | |
| 67 | // Logging ------------------------------------------------------------ |
| 68 | |
| 69 | // Log an error message within the platform implementation. |
| 70 | using LogErrorFunc = void (*)(PlatformMethods *platform, const char *errorMessage); |
| 71 | inline void DefaultLogError(PlatformMethods *platform, const char *errorMessage) |
| 72 | { |
| 73 | } |
| 74 | |
| 75 | // Log a warning message within the platform implementation. |
| 76 | using LogWarningFunc = void (*)(PlatformMethods *platform, const char *warningMessage); |
| 77 | inline void DefaultLogWarning(PlatformMethods *platform, const char *warningMessage) |
| 78 | { |
| 79 | } |
| 80 | |
| 81 | // Log an info message within the platform implementation. |
| 82 | using LogInfoFunc = void (*)(PlatformMethods *platform, const char *infoMessage); |
| 83 | inline void DefaultLogInfo(PlatformMethods *platform, const char *infoMessage) |
| 84 | { |
| 85 | } |
| 86 | |
| 87 | // Tracing -------- |
| 88 | |
| 89 | // Get a pointer to the enabled state of the given trace category. The |
| 90 | // embedder can dynamically change the enabled state as trace event |
| 91 | // recording is started and stopped by the application. Only long-lived |
| 92 | // literal strings should be given as the category name. The implementation |
| 93 | // expects the returned pointer to be held permanently in a local static. If |
| 94 | // the unsigned char is non-zero, tracing is enabled. If tracing is enabled, |
| 95 | // addTraceEvent is expected to be called by the trace event macros. |
| 96 | using GetTraceCategoryEnabledFlagFunc = const unsigned char *(*)(PlatformMethods *platform, |
| 97 | const char *categoryName); |
| 98 | inline const unsigned char *DefaultGetTraceCategoryEnabledFlag(PlatformMethods *platform, |
| 99 | const char *categoryName) |
| 100 | { |
| 101 | return nullptr; |
| 102 | } |
| 103 | |
| 104 | // |
| 105 | // Add a trace event to the platform tracing system. Depending on the actual |
| 106 | // enabled state, this event may be recorded or dropped. |
| 107 | // - phase specifies the type of event: |
| 108 | // - BEGIN ('B'): Marks the beginning of a scoped event. |
| 109 | // - END ('E'): Marks the end of a scoped event. |
| 110 | // - COMPLETE ('X'): Marks the beginning of a scoped event, but doesn't |
| 111 | // need a matching END event. Instead, at the end of the scope, |
| 112 | // updateTraceEventDuration() must be called with the TraceEventHandle |
| 113 | // returned from addTraceEvent(). |
| 114 | // - INSTANT ('I'): Standalone, instantaneous event. |
| 115 | // - START ('S'): Marks the beginning of an asynchronous event (the end |
| 116 | // event can occur in a different scope or thread). The id parameter is |
| 117 | // used to match START/FINISH pairs. |
| 118 | // - FINISH ('F'): Marks the end of an asynchronous event. |
| 119 | // - COUNTER ('C'): Used to trace integer quantities that change over |
| 120 | // time. The argument values are expected to be of type int. |
| 121 | // - METADATA ('M'): Reserved for internal use. |
| 122 | // - categoryEnabled is the pointer returned by getTraceCategoryEnabledFlag. |
| 123 | // - name is the name of the event. Also used to match BEGIN/END and |
| 124 | // START/FINISH pairs. |
| 125 | // - id optionally allows events of the same name to be distinguished from |
| 126 | // each other. For example, to trace the construction and destruction of |
| 127 | // objects, specify the pointer as the id parameter. |
| 128 | // - timestamp should be a time value returned from monotonicallyIncreasingTime. |
| 129 | // - numArgs specifies the number of elements in argNames, argTypes, and |
| 130 | // argValues. |
| 131 | // - argNames is the array of argument names. Use long-lived literal strings |
| 132 | // or specify the COPY flag. |
| 133 | // - argTypes is the array of argument types: |
| 134 | // - BOOL (1): bool |
| 135 | // - UINT (2): unsigned long long |
| 136 | // - INT (3): long long |
| 137 | // - DOUBLE (4): double |
| 138 | // - POINTER (5): void* |
| 139 | // - STRING (6): char* (long-lived null-terminated char* string) |
| 140 | // - COPY_STRING (7): char* (temporary null-terminated char* string) |
| 141 | // - CONVERTABLE (8): WebConvertableToTraceFormat |
| 142 | // - argValues is the array of argument values. Each value is the unsigned |
| 143 | // long long member of a union of all supported types. |
| 144 | // - flags can be 0 or one or more of the following, ORed together: |
| 145 | // - COPY (0x1): treat all strings (name, argNames and argValues of type |
| 146 | // string) as temporary so that they will be copied by addTraceEvent. |
| 147 | // - HAS_ID (0x2): use the id argument to uniquely identify the event for |
| 148 | // matching with other events of the same name. |
| 149 | // - MANGLE_ID (0x4): specify this flag if the id parameter is the value |
| 150 | // of a pointer. |
| 151 | using AddTraceEventFunc = angle::TraceEventHandle (*)(PlatformMethods *platform, |
| 152 | char phase, |
| 153 | const unsigned char *categoryEnabledFlag, |
| 154 | const char *name, |
| 155 | unsigned long long id, |
| 156 | double timestamp, |
| 157 | int numArgs, |
| 158 | const char **argNames, |
| 159 | const unsigned char *argTypes, |
| 160 | const unsigned long long *argValues, |
| 161 | unsigned char flags); |
| 162 | inline angle::TraceEventHandle DefaultAddTraceEvent(PlatformMethods *platform, |
| 163 | char phase, |
| 164 | const unsigned char *categoryEnabledFlag, |
| 165 | const char *name, |
| 166 | unsigned long long id, |
| 167 | double timestamp, |
| 168 | int numArgs, |
| 169 | const char **argNames, |
| 170 | const unsigned char *argTypes, |
| 171 | const unsigned long long *argValues, |
| 172 | unsigned char flags) |
| 173 | { |
| 174 | return 0; |
| 175 | } |
| 176 | |
| 177 | // Set the duration field of a COMPLETE trace event. |
| 178 | using UpdateTraceEventDurationFunc = void (*)(PlatformMethods *platform, |
| 179 | const unsigned char *categoryEnabledFlag, |
| 180 | const char *name, |
| 181 | angle::TraceEventHandle eventHandle); |
| 182 | inline void DefaultUpdateTraceEventDuration(PlatformMethods *platform, |
| 183 | const unsigned char *categoryEnabledFlag, |
| 184 | const char *name, |
| 185 | angle::TraceEventHandle eventHandle) |
| 186 | { |
| 187 | } |
| 188 | |
| 189 | // Callbacks for reporting histogram data. |
| 190 | // CustomCounts histogram has exponential bucket sizes, so that min=1, max=1000000, bucketCount=50 |
| 191 | // would do. |
| 192 | using HistogramCustomCountsFunc = void (*)(PlatformMethods *platform, |
| 193 | const char *name, |
| 194 | int sample, |
| 195 | int min, |
| 196 | int max, |
| 197 | int bucketCount); |
| 198 | inline void DefaultHistogramCustomCounts(PlatformMethods *platform, |
| 199 | const char *name, |
| 200 | int sample, |
| 201 | int min, |
| 202 | int max, |
| 203 | int bucketCount) |
| 204 | { |
| 205 | } |
| 206 | // Enumeration histogram buckets are linear, boundaryValue should be larger than any possible sample |
| 207 | // value. |
| 208 | using HistogramEnumerationFunc = void (*)(PlatformMethods *platform, |
| 209 | const char *name, |
| 210 | int sample, |
| 211 | int boundaryValue); |
| 212 | inline void DefaultHistogramEnumeration(PlatformMethods *platform, |
| 213 | const char *name, |
| 214 | int sample, |
| 215 | int boundaryValue) |
| 216 | { |
| 217 | } |
| 218 | // Unlike enumeration histograms, sparse histograms only allocate memory for non-empty buckets. |
| 219 | using HistogramSparseFunc = void (*)(PlatformMethods *platform, const char *name, int sample); |
| 220 | inline void DefaultHistogramSparse(PlatformMethods *platform, const char *name, int sample) |
| 221 | { |
| 222 | } |
| 223 | // Boolean histograms track two-state variables. |
| 224 | using HistogramBooleanFunc = void (*)(PlatformMethods *platform, const char *name, bool sample); |
| 225 | inline void DefaultHistogramBoolean(PlatformMethods *platform, const char *name, bool sample) |
| 226 | { |
| 227 | } |
| 228 | |
| 229 | // Allows us to programatically override ANGLE's default workarounds for testing purposes. |
| 230 | using OverrideWorkaroundsD3DFunc = void (*)(PlatformMethods *platform, |
| 231 | angle::WorkaroundsD3D *workaroundsD3D); |
| 232 | inline void DefaultOverrideWorkaroundsD3D(PlatformMethods *platform, |
| 233 | angle::WorkaroundsD3D *workaroundsD3D) |
| 234 | { |
| 235 | } |
| 236 | |
Tobin Ehlis | f95bf34 | 2018-11-13 12:56:01 -0700 | [diff] [blame] | 237 | using OverrideFeaturesVkFunc = void (*)(PlatformMethods *platform, |
| 238 | angle::FeaturesVk *workaroundsVulkan); |
| 239 | inline void DefaultOverrideFeaturesVk(PlatformMethods *platform, |
| 240 | angle::FeaturesVk *workaroundsVulkan) |
| 241 | { |
| 242 | } |
| 243 | |
Tobin Ehlis | 96a184d | 2018-07-18 16:14:07 -0600 | [diff] [blame] | 244 | // Callback on a successful program link with the program binary. Can be used to store |
| 245 | // shaders to disk. Keys are a 160-bit SHA-1 hash. |
| 246 | using ProgramKeyType = std::array<uint8_t, 20>; |
| 247 | using CacheProgramFunc = void (*)(PlatformMethods *platform, |
| 248 | const ProgramKeyType &key, |
| 249 | size_t programSize, |
| 250 | const uint8_t *programBytes); |
| 251 | inline void DefaultCacheProgram(PlatformMethods *platform, |
| 252 | const ProgramKeyType &key, |
| 253 | size_t programSize, |
| 254 | const uint8_t *programBytes) |
| 255 | { |
| 256 | } |
| 257 | |
| 258 | // Platform methods are enumerated here once. |
| 259 | #define ANGLE_PLATFORM_OP(OP) \ |
| 260 | OP(currentTime, CurrentTime) \ |
| 261 | OP(monotonicallyIncreasingTime, MonotonicallyIncreasingTime) \ |
| 262 | OP(logError, LogError) \ |
| 263 | OP(logWarning, LogWarning) \ |
| 264 | OP(logInfo, LogInfo) \ |
| 265 | OP(getTraceCategoryEnabledFlag, GetTraceCategoryEnabledFlag) \ |
| 266 | OP(addTraceEvent, AddTraceEvent) \ |
| 267 | OP(updateTraceEventDuration, UpdateTraceEventDuration) \ |
| 268 | OP(histogramCustomCounts, HistogramCustomCounts) \ |
| 269 | OP(histogramEnumeration, HistogramEnumeration) \ |
| 270 | OP(histogramSparse, HistogramSparse) \ |
| 271 | OP(histogramBoolean, HistogramBoolean) \ |
| 272 | OP(overrideWorkaroundsD3D, OverrideWorkaroundsD3D) \ |
Tobin Ehlis | f95bf34 | 2018-11-13 12:56:01 -0700 | [diff] [blame] | 273 | OP(overrideFeaturesVk, OverrideFeaturesVk) \ |
Tobin Ehlis | 96a184d | 2018-07-18 16:14:07 -0600 | [diff] [blame] | 274 | OP(cacheProgram, CacheProgram) |
| 275 | |
| 276 | #define ANGLE_PLATFORM_METHOD_DEF(Name, CapsName) CapsName##Func Name = Default##CapsName; |
| 277 | |
| 278 | struct ANGLE_PLATFORM_EXPORT PlatformMethods |
| 279 | { |
| 280 | PlatformMethods() {} |
| 281 | |
| 282 | // User data pointer for any implementation specific members. Put it at the start of the |
| 283 | // platform structure so it doesn't become overwritten if one version of the platform |
| 284 | // adds or removes new members. |
| 285 | void *context = 0; |
| 286 | |
| 287 | ANGLE_PLATFORM_OP(ANGLE_PLATFORM_METHOD_DEF); |
| 288 | }; |
| 289 | |
| 290 | #undef ANGLE_PLATFORM_METHOD_DEF |
| 291 | |
| 292 | // Subtract one to account for the context pointer. |
| 293 | constexpr unsigned int g_NumPlatformMethods = (sizeof(PlatformMethods) / sizeof(uintptr_t)) - 1; |
| 294 | |
| 295 | #define ANGLE_PLATFORM_METHOD_STRING(Name) #Name |
| 296 | #define ANGLE_PLATFORM_METHOD_STRING2(Name, CapsName) ANGLE_PLATFORM_METHOD_STRING(Name), |
| 297 | |
| 298 | constexpr const char *const g_PlatformMethodNames[g_NumPlatformMethods] = { |
| 299 | ANGLE_PLATFORM_OP(ANGLE_PLATFORM_METHOD_STRING2)}; |
| 300 | |
| 301 | #undef ANGLE_PLATFORM_METHOD_STRING2 |
| 302 | #undef ANGLE_PLATFORM_METHOD_STRING |
| 303 | |
| 304 | } // namespace angle |
| 305 | |
| 306 | extern "C" { |
| 307 | |
| 308 | // Gets the platform methods on the passed-in EGL display. If the method name signature does not |
| 309 | // match the compiled signature for this ANGLE, false is returned. On success true is returned. |
| 310 | // The application should set any platform methods it cares about on the returned pointer. |
| 311 | // If display is not valid, behaviour is undefined. |
| 312 | |
| 313 | ANGLE_PLATFORM_EXPORT bool ANGLE_APIENTRY ANGLEGetDisplayPlatform(angle::EGLDisplayType display, |
| 314 | const char *const methodNames[], |
| 315 | unsigned int methodNameCount, |
| 316 | void *context, |
| 317 | void *platformMethodsOut); |
| 318 | |
| 319 | // Sets the platform methods back to their defaults. |
| 320 | // If display is not valid, behaviour is undefined. |
| 321 | ANGLE_PLATFORM_EXPORT void ANGLE_APIENTRY ANGLEResetDisplayPlatform(angle::EGLDisplayType display); |
| 322 | |
| 323 | } // extern "C" |
| 324 | |
| 325 | namespace angle |
| 326 | { |
| 327 | typedef bool(ANGLE_APIENTRY *GetDisplayPlatformFunc)(angle::EGLDisplayType, |
| 328 | const char *const *, |
| 329 | unsigned int, |
| 330 | void *, |
| 331 | void *); |
| 332 | typedef void(ANGLE_APIENTRY *ResetDisplayPlatformFunc)(angle::EGLDisplayType); |
| 333 | } // namespace angle |
| 334 | |
| 335 | // This function is not exported |
| 336 | angle::PlatformMethods *ANGLEPlatformCurrent(); |
| 337 | |
| 338 | #endif // ANGLE_PLATFORM_H |