• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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