1 /*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "tools/gpu/gl/angle/GLTestContext_angle.h"
9
10 #include "include/core/SkTime.h"
11 #include "include/gpu/gl/GrGLAssembleInterface.h"
12 #include "include/gpu/gl/GrGLInterface.h"
13 #include "src/core/SkTraceEvent.h"
14 #include "src/gpu/ganesh/gl/GrGLDefines_impl.h"
15 #include "src/gpu/ganesh/gl/GrGLUtil.h"
16 #include "src/ports/SkOSLibrary.h"
17 #include "third_party/externals/angle2/include/platform/PlatformMethods.h"
18
19 #include <vector>
20
21 #define EGL_EGL_PROTOTYPES 1
22 #include <EGL/egl.h>
23 #include <EGL/eglext.h>
24
25 #define EGL_PLATFORM_ANGLE_ANGLE 0x3202
26 #define EGL_PLATFORM_ANGLE_TYPE_ANGLE 0x3203
27 #define EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE 0x3207
28 #define EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE 0x3208
29 #define EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE 0x320D
30 #define EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE 0x3489
31
32 #define EGL_CONTEXT_OPENGL_BACKWARDS_COMPATIBLE_ANGLE 0x3483
33
34 using sk_gpu_test::ANGLEBackend;
35 using sk_gpu_test::ANGLEContextVersion;
36
37 namespace {
38 struct Libs {
39 void* fGLLib;
40 void* fEGLLib;
41 };
42
context_restorer()43 std::function<void()> context_restorer() {
44 auto display = eglGetCurrentDisplay();
45 auto dsurface = eglGetCurrentSurface(EGL_DRAW);
46 auto rsurface = eglGetCurrentSurface(EGL_READ);
47 auto context = eglGetCurrentContext();
48 return [display, dsurface, rsurface, context] {
49 eglMakeCurrent(display, dsurface, rsurface, context);
50 };
51 }
52
angle_get_gl_proc(void * ctx,const char name[])53 static GrGLFuncPtr angle_get_gl_proc(void* ctx, const char name[]) {
54 const Libs* libs = reinterpret_cast<const Libs*>(ctx);
55 GrGLFuncPtr proc = (GrGLFuncPtr) SkGetProcedureAddress(libs->fGLLib, name);
56 if (proc) {
57 return proc;
58 }
59 proc = (GrGLFuncPtr) SkGetProcedureAddress(libs->fEGLLib, name);
60 if (proc) {
61 return proc;
62 }
63 return eglGetProcAddress(name);
64 }
65
get_angle_egl_display(void * nativeDisplay,ANGLEBackend type)66 void* get_angle_egl_display(void* nativeDisplay, ANGLEBackend type) {
67 PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT;
68 eglGetPlatformDisplayEXT =
69 (PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress("eglGetPlatformDisplayEXT");
70
71 // We expect ANGLE to support this extension
72 if (!eglGetPlatformDisplayEXT) {
73 return EGL_NO_DISPLAY;
74 }
75
76 EGLint typeNum = 0;
77 switch (type) {
78 case ANGLEBackend::kD3D9:
79 typeNum = EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE;
80 break;
81 case ANGLEBackend::kD3D11:
82 typeNum = EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE;
83 break;
84 case ANGLEBackend::kOpenGL:
85 typeNum = EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE;
86 break;
87 case ANGLEBackend::kMetal:
88 typeNum = EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE;
89 break;
90 }
91 const EGLint attribs[] = { EGL_PLATFORM_ANGLE_TYPE_ANGLE, typeNum, EGL_NONE };
92 return eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, nativeDisplay, attribs);
93 }
94
95 class ANGLEGLContext : public sk_gpu_test::GLTestContext {
96 public:
97 ANGLEGLContext(ANGLEBackend, ANGLEContextVersion, ANGLEGLContext* shareContext, void* display);
98 ~ANGLEGLContext() override;
99
100 GrEGLImage texture2DToEGLImage(GrGLuint texID) const override;
101 void destroyEGLImage(GrEGLImage) const override;
102 GrGLuint eglImageToExternalTexture(GrEGLImage) const override;
103 std::unique_ptr<sk_gpu_test::GLTestContext> makeNew() const override;
104
105 private:
106 void destroyGLContext();
107
108 void onPlatformMakeNotCurrent() const override;
109 void onPlatformMakeCurrent() const override;
110 std::function<void()> onPlatformGetAutoContextRestore() const override;
111 GrGLFuncPtr onPlatformGetProcAddress(const char* name) const override;
112
113 void* fContext;
114 void* fDisplay;
115 void* fSurface;
116 ANGLEBackend fType;
117 ANGLEContextVersion fVersion;
118 bool fOwnsDisplay;
119
120 angle::ResetDisplayPlatformFunc fResetPlatform = nullptr;
121
122 PFNEGLCREATEIMAGEKHRPROC fCreateImage = nullptr;
123 PFNEGLDESTROYIMAGEKHRPROC fDestroyImage = nullptr;
124
125 #ifdef SK_BUILD_FOR_WIN
126 HWND fWindow;
127 HDC fDeviceContext;
128 static ATOM gWC;
129 #endif
130 };
131
132 #ifdef SK_BUILD_FOR_WIN
133 ATOM ANGLEGLContext::gWC = 0;
134
135 enum class IsWine { kUnknown, kNo, kYes };
136
is_wine()137 static IsWine is_wine() {
138 HMODULE ntdll = GetModuleHandle("ntdll.dll");
139 if (!ntdll) {
140 SkDebugf("No ntdll.dll on Windows?!\n");
141 return IsWine::kUnknown;
142 }
143 return GetProcAddress(ntdll, "wine_get_version") == nullptr ? IsWine::kNo : IsWine::kYes;
144 }
145
146 #endif
147
ANGLE_getTraceCategoryEnabledFlag(angle::PlatformMethods * platform,const char * category_group)148 static const unsigned char* ANGLE_getTraceCategoryEnabledFlag(angle::PlatformMethods* platform,
149 const char* category_group) {
150 return SkEventTracer::GetInstance()->getCategoryGroupEnabled(category_group);
151 }
152
ANGLE_addTraceEvent(angle::PlatformMethods * platform,char phase,const unsigned char * category_group_enabled,const char * name,unsigned long long id,double timestamp,int num_args,const char ** arg_names,const unsigned char * arg_types,const unsigned long long * arg_values,unsigned char flags)153 static angle::TraceEventHandle ANGLE_addTraceEvent(angle::PlatformMethods* platform,
154 char phase,
155 const unsigned char* category_group_enabled,
156 const char* name,
157 unsigned long long id,
158 double timestamp,
159 int num_args,
160 const char** arg_names,
161 const unsigned char* arg_types,
162 const unsigned long long* arg_values,
163 unsigned char flags) {
164 static_assert(sizeof(unsigned long long) == sizeof(uint64_t), "Non-64-bit trace event args!");
165 return SkEventTracer::GetInstance()->addTraceEvent(
166 phase, category_group_enabled, name, id, num_args, arg_names, arg_types,
167 reinterpret_cast<const uint64_t*>(arg_values), flags);
168 }
169
ANGLE_updateTraceEventDuration(angle::PlatformMethods * platform,const unsigned char * category_group_enabled,const char * name,angle::TraceEventHandle handle)170 static void ANGLE_updateTraceEventDuration(angle::PlatformMethods* platform,
171 const unsigned char* category_group_enabled,
172 const char* name,
173 angle::TraceEventHandle handle) {
174 SkEventTracer::GetInstance()->updateTraceEventDuration(category_group_enabled, name, handle);
175 }
176
ANGLE_monotonicallyIncreasingTime(angle::PlatformMethods * platform)177 static double ANGLE_monotonicallyIncreasingTime(angle::PlatformMethods* platform) {
178 return SkTime::GetSecs();
179 }
180
ANGLEGLContext(ANGLEBackend type,ANGLEContextVersion version,ANGLEGLContext * shareContext,void * display)181 ANGLEGLContext::ANGLEGLContext(ANGLEBackend type, ANGLEContextVersion version,
182 ANGLEGLContext* shareContext, void* display)
183 : fContext(EGL_NO_CONTEXT)
184 , fDisplay(display)
185 , fSurface(EGL_NO_SURFACE)
186 , fType(type)
187 , fVersion(version)
188 , fOwnsDisplay(false) {
189 #ifdef SK_BUILD_FOR_WIN
190 fWindow = nullptr;
191 fDeviceContext = nullptr;
192
193 static IsWine gIsWine = is_wine();
194 if (gIsWine == IsWine::kYes && type != ANGLEBackend::kOpenGL) {
195 // D3D backends of ANGLE don't really work well under Wine with our tests and are likely to
196 // crash. This makes it easier to test using the GL ANGLE backend under Wine on Linux
197 // without lots of spurious Wine debug spew and crashes.
198 return;
199 }
200
201 if (EGL_NO_DISPLAY == fDisplay) {
202 HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(nullptr);
203
204 if (!gWC) {
205 WNDCLASS wc;
206 wc.cbClsExtra = 0;
207 wc.cbWndExtra = 0;
208 wc.hbrBackground = nullptr;
209 wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
210 wc.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
211 wc.hInstance = hInstance;
212 wc.lpfnWndProc = (WNDPROC) DefWindowProc;
213 wc.lpszClassName = TEXT("ANGLE-win");
214 wc.lpszMenuName = nullptr;
215 wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
216
217 gWC = RegisterClass(&wc);
218 if (!gWC) {
219 SkDebugf("Could not register window class.\n");
220 return;
221 }
222 }
223 if (!(fWindow = CreateWindow(TEXT("ANGLE-win"),
224 TEXT("The Invisible Man"),
225 WS_OVERLAPPEDWINDOW,
226 0, 0, 1, 1,
227 nullptr, nullptr,
228 hInstance, nullptr))) {
229 SkDebugf("Could not create window.\n");
230 return;
231 }
232
233 if (!(fDeviceContext = GetDC(fWindow))) {
234 SkDebugf("Could not get device context.\n");
235 this->destroyGLContext();
236 return;
237 }
238
239 fDisplay = get_angle_egl_display(fDeviceContext, type);
240 fOwnsDisplay = true;
241 }
242 #else
243 SkASSERT(EGL_NO_DISPLAY == fDisplay);
244 fDisplay = get_angle_egl_display(reinterpret_cast<void*>(EGL_DEFAULT_DISPLAY), type);
245 fOwnsDisplay = true;
246 #endif
247 if (EGL_NO_DISPLAY == fDisplay) {
248 SkDebugf("Could not create ANGLE EGL display!\n");
249 return;
250 }
251
252 // Add ANGLE platform hooks to connect to Skia's tracing implementation
253 angle::GetDisplayPlatformFunc getPlatform = reinterpret_cast<angle::GetDisplayPlatformFunc>(
254 eglGetProcAddress("ANGLEGetDisplayPlatform"));
255 if (getPlatform) {
256 fResetPlatform = reinterpret_cast<angle::ResetDisplayPlatformFunc>(
257 eglGetProcAddress("ANGLEResetDisplayPlatform"));
258 SkASSERT(fResetPlatform);
259
260 angle::PlatformMethods* platformMethods = nullptr;
261 if (getPlatform(fDisplay, angle::g_PlatformMethodNames, angle::g_NumPlatformMethods,
262 nullptr, &platformMethods)) {
263 platformMethods->addTraceEvent = ANGLE_addTraceEvent;
264 platformMethods->getTraceCategoryEnabledFlag = ANGLE_getTraceCategoryEnabledFlag;
265 platformMethods->updateTraceEventDuration = ANGLE_updateTraceEventDuration;
266 platformMethods->monotonicallyIncreasingTime = ANGLE_monotonicallyIncreasingTime;
267 }
268 }
269
270 EGLint majorVersion;
271 EGLint minorVersion;
272 if (!eglInitialize(fDisplay, &majorVersion, &minorVersion)) {
273 SkDebugf("Could not initialize display!");
274 this->destroyGLContext();
275 return;
276 }
277
278 EGLint numConfigs;
279 static const EGLint configAttribs[] = {
280 EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
281 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
282 EGL_RED_SIZE, 8,
283 EGL_GREEN_SIZE, 8,
284 EGL_BLUE_SIZE, 8,
285 EGL_ALPHA_SIZE, 8,
286 EGL_NONE
287 };
288
289 EGLConfig surfaceConfig;
290 if (!eglChooseConfig(fDisplay, configAttribs, &surfaceConfig, 1, &numConfigs)) {
291 SkDebugf("Could not create choose config!");
292 this->destroyGLContext();
293 return;
294 }
295
296 int versionNum = ANGLEContextVersion::kES2 == version ? 2 : 3;
297 std::vector<EGLint> contextAttribs = {
298 EGL_CONTEXT_CLIENT_VERSION, versionNum,
299 };
300
301 const char* extensions = eglQueryString(fDisplay, EGL_EXTENSIONS);
302 if (strstr(extensions, "EGL_ANGLE_create_context_backwards_compatible")) {
303 contextAttribs.push_back(EGL_CONTEXT_OPENGL_BACKWARDS_COMPATIBLE_ANGLE);
304 contextAttribs.push_back(EGL_FALSE);
305 }
306
307 contextAttribs.push_back(EGL_NONE);
308
309 EGLContext eglShareContext = shareContext ? shareContext->fContext : nullptr;
310 fContext = eglCreateContext(fDisplay, surfaceConfig, eglShareContext, contextAttribs.data());
311 if (EGL_NO_CONTEXT == fContext) {
312 SkDebugf("Could not create context!");
313 this->destroyGLContext();
314 return;
315 }
316
317 static const EGLint surfaceAttribs[] = {
318 EGL_WIDTH, 1,
319 EGL_HEIGHT, 1,
320 EGL_NONE
321 };
322
323 fSurface = eglCreatePbufferSurface(fDisplay, surfaceConfig, surfaceAttribs);
324
325 SkScopeExit restorer(context_restorer());
326 if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
327 SkDebugf("Could not set the context.");
328 this->destroyGLContext();
329 return;
330 }
331
332 sk_sp<const GrGLInterface> gl = sk_gpu_test::CreateANGLEGLInterface();
333 if (nullptr == gl.get()) {
334 SkDebugf("Could not create ANGLE GL interface!\n");
335 this->destroyGLContext();
336 return;
337 }
338 if (!gl->validate()) {
339 SkDebugf("Could not validate ANGLE GL interface!\n");
340 this->destroyGLContext();
341 return;
342 }
343
344 #ifdef SK_DEBUG
345 // Verify that the interface we requested was actually returned to us
346 const GrGLubyte* rendererUByte;
347 GR_GL_CALL_RET(gl.get(), rendererUByte, GetString(GR_GL_RENDERER));
348 const char* renderer = reinterpret_cast<const char*>(rendererUByte);
349 switch (type) {
350 case ANGLEBackend::kD3D9:
351 SkASSERT(strstr(renderer, "Direct3D9"));
352 break;
353 case ANGLEBackend::kD3D11:
354 SkASSERT(strstr(renderer, "Direct3D11"));
355 break;
356 case ANGLEBackend::kOpenGL:
357 SkASSERT(strstr(renderer, "OpenGL"));
358 break;
359 case ANGLEBackend::kMetal:
360 SkASSERT(strstr(renderer, "Metal"));
361 break;
362 }
363 #endif
364 if (strstr(extensions, "EGL_KHR_image")) {
365 fCreateImage = (PFNEGLCREATEIMAGEKHRPROC)eglGetProcAddress("eglCreateImageKHR");
366 fDestroyImage = (PFNEGLDESTROYIMAGEKHRPROC)eglGetProcAddress("eglDestroyImageKHR");
367 }
368
369 this->init(std::move(gl));
370 }
371
~ANGLEGLContext()372 ANGLEGLContext::~ANGLEGLContext() {
373 this->teardown();
374 this->destroyGLContext();
375 }
376
texture2DToEGLImage(GrGLuint texID) const377 GrEGLImage ANGLEGLContext::texture2DToEGLImage(GrGLuint texID) const {
378 if (!this->gl()->hasExtension("EGL_KHR_gl_texture_2D_image")) {
379 return GR_EGL_NO_IMAGE;
380 }
381 EGLint attribs[] = { GR_EGL_GL_TEXTURE_LEVEL, 0,
382 GR_EGL_IMAGE_PRESERVED, GR_EGL_TRUE,
383 GR_EGL_NONE };
384 // 64 bit cast is to shut Visual C++ up about casting 32 bit value to a pointer.
385 GrEGLClientBuffer clientBuffer = reinterpret_cast<GrEGLClientBuffer>((uint64_t)texID);
386 return fCreateImage(fDisplay, fContext, GR_EGL_GL_TEXTURE_2D, clientBuffer, attribs);
387 }
388
destroyEGLImage(GrEGLImage image) const389 void ANGLEGLContext::destroyEGLImage(GrEGLImage image) const { fDestroyImage(fDisplay, image); }
390
eglImageToExternalTexture(GrEGLImage image) const391 GrGLuint ANGLEGLContext::eglImageToExternalTexture(GrEGLImage image) const {
392 while (this->gl()->fFunctions.fGetError() != GR_GL_NO_ERROR) {}
393 if (!this->gl()->hasExtension("GL_OES_EGL_image_external")) {
394 return 0;
395 }
396 typedef GrGLvoid (EGLAPIENTRY *EGLImageTargetTexture2DProc)(GrGLenum, GrGLeglImage);
397 EGLImageTargetTexture2DProc glEGLImageTargetTexture2D =
398 (EGLImageTargetTexture2DProc)eglGetProcAddress("glEGLImageTargetTexture2DOES");
399 if (!glEGLImageTargetTexture2D) {
400 return 0;
401 }
402 GrGLuint texID;
403 GR_GL_CALL(this->gl(), GenTextures(1, &texID));
404 if (!texID) {
405 return 0;
406 }
407 GR_GL_CALL(this->gl(), BindTexture(GR_GL_TEXTURE_EXTERNAL, texID));
408 if (this->gl()->fFunctions.fGetError() != GR_GL_NO_ERROR) {
409 GR_GL_CALL(this->gl(), DeleteTextures(1, &texID));
410 return 0;
411 }
412 glEGLImageTargetTexture2D(GR_GL_TEXTURE_EXTERNAL, image);
413 if (this->gl()->fFunctions.fGetError() != GR_GL_NO_ERROR) {
414 GR_GL_CALL(this->gl(), DeleteTextures(1, &texID));
415 return 0;
416 }
417 return texID;
418 }
419
makeNew() const420 std::unique_ptr<sk_gpu_test::GLTestContext> ANGLEGLContext::makeNew() const {
421 // For EGLImage sharing between contexts to work in ANGLE the two contexts
422 // need to share the same display
423 std::unique_ptr<sk_gpu_test::GLTestContext> ctx =
424 sk_gpu_test::MakeANGLETestContext(fType, fVersion, nullptr, fDisplay);
425 if (ctx) {
426 ctx->makeCurrent();
427 }
428 return ctx;
429 }
430
destroyGLContext()431 void ANGLEGLContext::destroyGLContext() {
432 if (EGL_NO_DISPLAY != fDisplay) {
433 if (eglGetCurrentContext() == fContext) {
434 // This will ensure that the context is immediately deleted.
435 eglMakeCurrent(fDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
436 }
437
438 if (EGL_NO_CONTEXT != fContext) {
439 eglDestroyContext(fDisplay, fContext);
440 fContext = EGL_NO_CONTEXT;
441 }
442
443 if (EGL_NO_SURFACE != fSurface) {
444 eglDestroySurface(fDisplay, fSurface);
445 fSurface = EGL_NO_SURFACE;
446 }
447
448 if (fResetPlatform) {
449 fResetPlatform(fDisplay);
450 }
451
452 if (fOwnsDisplay) {
453 // Only terminate the display if we created it. If we were a context created by makeNew,
454 // the parent context might still have work to do on the display. If we terminate now,
455 // that context might be deleted once it no longer becomes current, and we may hit
456 // undefined behavior in this destructor when calling eglDestroy[Context|Surface] on a
457 // terminated display.
458 eglTerminate(fDisplay);
459 }
460 fDisplay = EGL_NO_DISPLAY;
461 fOwnsDisplay = false;
462 }
463
464 #ifdef SK_BUILD_FOR_WIN
465 if (fWindow) {
466 if (fDeviceContext) {
467 ReleaseDC(fWindow, fDeviceContext);
468 fDeviceContext = 0;
469 }
470
471 DestroyWindow(fWindow);
472 fWindow = 0;
473 }
474 #endif
475 }
476
onPlatformMakeNotCurrent() const477 void ANGLEGLContext::onPlatformMakeNotCurrent() const {
478 if (!eglMakeCurrent(fDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
479 SkDebugf("Could not reset the context 0x%x.\n", eglGetError());
480 }
481 }
482
onPlatformMakeCurrent() const483 void ANGLEGLContext::onPlatformMakeCurrent() const {
484 if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
485 SkDebugf("Could not set the context 0x%x.\n", eglGetError());
486 }
487 }
488
onPlatformGetAutoContextRestore() const489 std::function<void()> ANGLEGLContext::onPlatformGetAutoContextRestore() const {
490 if (eglGetCurrentContext() == fContext) {
491 return nullptr;
492 }
493 return context_restorer();
494 }
495
onPlatformGetProcAddress(const char * name) const496 GrGLFuncPtr ANGLEGLContext::onPlatformGetProcAddress(const char* name) const {
497 return eglGetProcAddress(name);
498 }
499 } // anonymous namespace
500
501 namespace sk_gpu_test {
CreateANGLEGLInterface()502 sk_sp<const GrGLInterface> CreateANGLEGLInterface() {
503 static Libs gLibs = { nullptr, nullptr };
504
505 if (nullptr == gLibs.fGLLib) {
506 // We load the ANGLE library and never let it go
507 #if defined(SK_BUILD_FOR_WIN)
508 gLibs.fGLLib = SkLoadDynamicLibrary("libGLESv2.dll");
509 gLibs.fEGLLib = SkLoadDynamicLibrary("libEGL.dll");
510 #elif defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
511 gLibs.fGLLib = SkLoadDynamicLibrary("libGLESv2.dylib");
512 gLibs.fEGLLib = SkLoadDynamicLibrary("libEGL.dylib");
513 #else
514 gLibs.fGLLib = SkLoadDynamicLibrary("libGLESv2.so");
515 gLibs.fEGLLib = SkLoadDynamicLibrary("libEGL.so");
516 #endif
517 }
518
519 if (nullptr == gLibs.fGLLib || nullptr == gLibs.fEGLLib) {
520 // We can't setup the interface correctly w/o the so
521 return nullptr;
522 }
523
524 return GrGLMakeAssembledGLESInterface(&gLibs, angle_get_gl_proc);
525 }
526
MakeANGLETestContext(ANGLEBackend type,ANGLEContextVersion version,GLTestContext * shareContext,void * display)527 std::unique_ptr<GLTestContext> MakeANGLETestContext(ANGLEBackend type, ANGLEContextVersion version,
528 GLTestContext* shareContext, void* display) {
529 #if defined(SK_BUILD_FOR_WIN) && defined(_M_ARM64)
530 // Windows-on-ARM only has D3D11. This will fail correctly, but it produces huge amounts of
531 // debug output for every unit test from both ANGLE and our context factory.
532 if (ANGLEBackend::kD3D11 != type) {
533 return nullptr;
534 }
535 #endif
536
537 // These checks squelch spam when display creation predictably fails
538 #if defined(SK_BUILD_FOR_WIN)
539 if (ANGLEBackend::kMetal == type) {
540 return nullptr;
541 }
542 #endif
543
544 #if defined(SK_BUILD_FOR_MAC)
545 if (ANGLEBackend::kMetal != type) {
546 return nullptr;
547 }
548 #endif
549
550 ANGLEGLContext* angleShareContext = reinterpret_cast<ANGLEGLContext*>(shareContext);
551 std::unique_ptr<GLTestContext> ctx(new ANGLEGLContext(type, version,
552 angleShareContext, display));
553 if (!ctx->isValid()) {
554 return nullptr;
555 }
556 return ctx;
557 }
558 } // namespace sk_gpu_test
559