1 /*
2  * Copyright 2011 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 "src/gpu/gl/GrGLDefines.h"
9 #include "src/gpu/gl/GrGLUtil.h"
10 #include "tools/gpu/gl/GLTestContext.h"
11 
12 #define GL_GLEXT_PROTOTYPES
13 #include <EGL/egl.h>
14 #include <EGL/eglext.h>
15 
16 namespace {
17 
context_restorer()18 std::function<void()> context_restorer() {
19     auto display = eglGetCurrentDisplay();
20     auto dsurface = eglGetCurrentSurface(EGL_DRAW);
21     auto rsurface = eglGetCurrentSurface(EGL_READ);
22     auto context = eglGetCurrentContext();
23     return [display, dsurface, rsurface, context] {
24         eglMakeCurrent(display, dsurface, rsurface, context);
25     };
26 }
27 
28 class EGLGLTestContext : public sk_gpu_test::GLTestContext {
29 public:
30     EGLGLTestContext(GrGLStandard forcedGpuAPI, EGLGLTestContext* shareContext);
31     ~EGLGLTestContext() override;
32 
33     GrEGLImage texture2DToEGLImage(GrGLuint texID) const override;
34     void destroyEGLImage(GrEGLImage) const override;
35     GrGLuint eglImageToExternalTexture(GrEGLImage) const override;
36     std::unique_ptr<sk_gpu_test::GLTestContext> makeNew() const override;
37 
38 private:
39     void destroyGLContext();
40 
41     void onPlatformMakeNotCurrent() const override;
42     void onPlatformMakeCurrent() const override;
43     std::function<void()> onPlatformGetAutoContextRestore() const override;
44     GrGLFuncPtr onPlatformGetProcAddress(const char*) const override;
45 
46     void setupFenceSync(sk_sp<const GrGLInterface>);
47 
48     PFNEGLCREATEIMAGEKHRPROC fEglCreateImageProc = nullptr;
49     PFNEGLDESTROYIMAGEKHRPROC fEglDestroyImageProc = nullptr;
50 
51     EGLContext fContext;
52     EGLDisplay fDisplay;
53     EGLSurface fSurface;
54 };
55 
create_gles_egl_context(EGLDisplay display,EGLConfig surfaceConfig,EGLContext eglShareContext,EGLint eglContextClientVersion)56 static EGLContext create_gles_egl_context(EGLDisplay display,
57                                           EGLConfig surfaceConfig,
58                                           EGLContext eglShareContext,
59                                           EGLint eglContextClientVersion) {
60     const EGLint contextAttribsForOpenGLES[] = {
61         EGL_CONTEXT_CLIENT_VERSION,
62         eglContextClientVersion,
63         EGL_NONE
64     };
65     return eglCreateContext(display, surfaceConfig, eglShareContext, contextAttribsForOpenGLES);
66 }
create_gl_egl_context(EGLDisplay display,EGLConfig surfaceConfig,EGLContext eglShareContext)67 static EGLContext create_gl_egl_context(EGLDisplay display,
68                                         EGLConfig surfaceConfig,
69                                         EGLContext eglShareContext) {
70     const EGLint contextAttribsForOpenGL[] = {
71         EGL_NONE
72     };
73     return eglCreateContext(display, surfaceConfig, eglShareContext, contextAttribsForOpenGL);
74 }
75 
EGLGLTestContext(GrGLStandard forcedGpuAPI,EGLGLTestContext * shareContext)76 EGLGLTestContext::EGLGLTestContext(GrGLStandard forcedGpuAPI, EGLGLTestContext* shareContext)
77     : fContext(EGL_NO_CONTEXT)
78     , fDisplay(EGL_NO_DISPLAY)
79     , fSurface(EGL_NO_SURFACE) {
80 
81     EGLContext eglShareContext = shareContext ? shareContext->fContext : nullptr;
82 
83     static const GrGLStandard kStandards[] = {
84         kGL_GrGLStandard,
85         kGLES_GrGLStandard,
86     };
87 
88     size_t apiLimit = SK_ARRAY_COUNT(kStandards);
89     size_t api = 0;
90     if (forcedGpuAPI == kGL_GrGLStandard) {
91         apiLimit = 1;
92     } else if (forcedGpuAPI == kGLES_GrGLStandard) {
93         api = 1;
94     }
95     SkASSERT(forcedGpuAPI == kNone_GrGLStandard || kStandards[api] == forcedGpuAPI);
96 
97     sk_sp<const GrGLInterface> gl;
98 
99     for (; nullptr == gl.get() && api < apiLimit; ++api) {
100         fDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
101 
102         EGLint majorVersion;
103         EGLint minorVersion;
104         eglInitialize(fDisplay, &majorVersion, &minorVersion);
105 
106 #if 0
107         SkDebugf("VENDOR: %s\n", eglQueryString(fDisplay, EGL_VENDOR));
108         SkDebugf("APIS: %s\n", eglQueryString(fDisplay, EGL_CLIENT_APIS));
109         SkDebugf("VERSION: %s\n", eglQueryString(fDisplay, EGL_VERSION));
110         SkDebugf("EXTENSIONS %s\n", eglQueryString(fDisplay, EGL_EXTENSIONS));
111 #endif
112         bool gles = kGLES_GrGLStandard == kStandards[api];
113 
114         if (!eglBindAPI(gles ? EGL_OPENGL_ES_API : EGL_OPENGL_API)) {
115             continue;
116         }
117 
118         EGLint numConfigs = 0;
119         const EGLint configAttribs[] = {
120             EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
121             EGL_RENDERABLE_TYPE, gles ? EGL_OPENGL_ES2_BIT : EGL_OPENGL_BIT,
122             EGL_RED_SIZE, 8,
123             EGL_GREEN_SIZE, 8,
124             EGL_BLUE_SIZE, 8,
125             EGL_ALPHA_SIZE, 8,
126             EGL_NONE
127         };
128 
129         EGLConfig surfaceConfig;
130         if (!eglChooseConfig(fDisplay, configAttribs, &surfaceConfig, 1, &numConfigs)) {
131             SkDebugf("eglChooseConfig failed. EGL Error: 0x%08x\n", eglGetError());
132             continue;
133         }
134 
135         if (0 == numConfigs) {
136             SkDebugf("No suitable EGL config found.\n");
137             continue;
138         }
139 
140         if (gles) {
141 #ifdef GR_EGL_TRY_GLES3_THEN_GLES2
142             // Some older devices (Nexus7/Tegra3) crash when you try this.  So it is (for now)
143             // hidden behind this flag.
144             fContext = create_gles_egl_context(fDisplay, surfaceConfig, eglShareContext, 3);
145             if (EGL_NO_CONTEXT == fContext) {
146                 fContext = create_gles_egl_context(fDisplay, surfaceConfig, eglShareContext, 2);
147             }
148 #else
149             fContext = create_gles_egl_context(fDisplay, surfaceConfig, eglShareContext, 2);
150 #endif
151         } else {
152             fContext = create_gl_egl_context(fDisplay, surfaceConfig, eglShareContext);
153         }
154         if (EGL_NO_CONTEXT == fContext) {
155             SkDebugf("eglCreateContext failed.  EGL Error: 0x%08x\n", eglGetError());
156             continue;
157         }
158 
159         static const EGLint kSurfaceAttribs[] = {
160             EGL_WIDTH, 1,
161             EGL_HEIGHT, 1,
162             EGL_NONE
163         };
164 
165         fSurface = eglCreatePbufferSurface(fDisplay, surfaceConfig, kSurfaceAttribs);
166         if (EGL_NO_SURFACE == fSurface) {
167             SkDebugf("eglCreatePbufferSurface failed. EGL Error: 0x%08x\n", eglGetError());
168             this->destroyGLContext();
169             continue;
170         }
171 
172         SkScopeExit restorer(context_restorer());
173         if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
174             SkDebugf("eglMakeCurrent failed.  EGL Error: 0x%08x\n", eglGetError());
175             this->destroyGLContext();
176             continue;
177         }
178 
179 #ifdef SK_GL
180         gl = GrGLMakeNativeInterface();
181         if (!gl) {
182             SkDebugf("Failed to create gl interface.\n");
183             this->destroyGLContext();
184             continue;
185         }
186 
187         this->setupFenceSync(gl);
188 
189         if (!gl->validate()) {
190             SkDebugf("Failed to validate gl interface.\n");
191             this->destroyGLContext();
192             continue;
193         }
194         const char* extensions = eglQueryString(fDisplay, EGL_EXTENSIONS);
195         if (strstr(extensions, "EGL_KHR_image")) {
196             fEglCreateImageProc = (PFNEGLCREATEIMAGEKHRPROC)eglGetProcAddress("eglCreateImageKHR");
197             fEglDestroyImageProc =
198                     (PFNEGLDESTROYIMAGEKHRPROC)eglGetProcAddress("eglDestroyImageKHR");
199         }
200 
201         this->init(std::move(gl));
202 #else
203         // Allow the GLTestContext creation to succeed without a GrGLInterface to support
204         // GrContextFactory's persistent GL context workaround for Vulkan. We won't need the
205         // GrGLInterface since we're not running the GL backend.
206         this->init(nullptr);
207 #endif
208         break;
209     }
210 }
211 
supports_egl_extension(EGLDisplay display,const char * extension)212 static bool supports_egl_extension(EGLDisplay display, const char* extension) {
213     size_t extensionLength = strlen(extension);
214     const char* extensionsStr = eglQueryString(display, EGL_EXTENSIONS);
215     while (const char* match = strstr(extensionsStr, extension)) {
216         // Ensure the string we found is its own extension, not a substring of a larger extension
217         // (e.g. GL_ARB_occlusion_query / GL_ARB_occlusion_query2).
218         if ((match == extensionsStr || match[-1] == ' ') &&
219             (match[extensionLength] == ' ' || match[extensionLength] == '\0')) {
220             return true;
221         }
222         extensionsStr = match + extensionLength;
223     }
224     return false;
225 }
226 
setupFenceSync(sk_sp<const GrGLInterface> interface)227 void EGLGLTestContext::setupFenceSync(sk_sp<const GrGLInterface> interface) {
228     GrGLInterface* glInt = const_cast<GrGLInterface*>(interface.get());
229 
230 
231     if (kGL_GrGLStandard == glInt->fStandard) {
232         if (GrGLGetVersion(glInt) >= GR_GL_VER(3,2) || glInt->hasExtension("GL_ARB_sync")) {
233             return;
234         }
235     } else {
236         if (glInt->hasExtension("GL_APPLE_sync") || glInt->hasExtension("GL_NV_fence") ||
237             GrGLGetVersion(glInt) >= GR_GL_VER(3, 0)) {
238             return;
239         }
240     }
241 
242     if (!supports_egl_extension(fDisplay, "EGL_KHR_fence_sync")) {
243         return;
244     }
245 
246     auto grEGLCreateSyncKHR = (PFNEGLCREATESYNCKHRPROC) eglGetProcAddress("eglCreateSyncKHR");
247     auto grEGLClientWaitSyncKHR =
248             (PFNEGLCLIENTWAITSYNCKHRPROC) eglGetProcAddress("eglClientWaitSyncKHR");
249     auto grEGLDestroySyncKHR = (PFNEGLDESTROYSYNCKHRPROC) eglGetProcAddress("eglDestroySyncKHR");
250     auto grEGLGetSyncAttribKHR =
251             (PFNEGLGETSYNCATTRIBKHRPROC) eglGetProcAddress("eglGetSyncAttribKHR");
252     SkASSERT(grEGLCreateSyncKHR && grEGLClientWaitSyncKHR && grEGLDestroySyncKHR &&
253              grEGLGetSyncAttribKHR);
254 
255     PFNEGLWAITSYNCKHRPROC grEGLWaitSyncKHR = nullptr;
256     if (supports_egl_extension(fDisplay, "EGL_KHR_wait_sync")) {
257         grEGLWaitSyncKHR = (PFNEGLWAITSYNCKHRPROC)eglGetProcAddress("eglWaitSyncKHR");
258         SkASSERT(grEGLWaitSyncKHR);
259     }
260 
261     // Fake out glSync using eglSync
262     glInt->fExtensions.add("GL_APPLE_sync");
263 
264     glInt->fFunctions.fFenceSync =
265             [grEGLCreateSyncKHR, display = fDisplay](GrGLenum condition, GrGLbitfield flags) {
266         SkASSERT(condition == GR_GL_SYNC_GPU_COMMANDS_COMPLETE);
267         SkASSERT(flags == 0);
268 
269         EGLSyncKHR sync = grEGLCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr);
270 
271         return reinterpret_cast<GrGLsync>(sync);
272     };
273 
274     glInt->fFunctions.fDeleteSync = [grEGLDestroySyncKHR, display = fDisplay](GrGLsync sync) {
275         EGLSyncKHR eglSync = reinterpret_cast<EGLSyncKHR>(sync);
276         grEGLDestroySyncKHR(display, eglSync);
277     };
278 
279     glInt->fFunctions.fClientWaitSync =
280             [grEGLClientWaitSyncKHR, display = fDisplay] (GrGLsync sync, GrGLbitfield flags,
281                                                           GrGLuint64 timeout) -> GrGLenum {
282         EGLSyncKHR eglSync = reinterpret_cast<EGLSyncKHR>(sync);
283 
284         EGLint egl_flags = 0;
285 
286         if (flags & GR_GL_SYNC_FLUSH_COMMANDS_BIT) {
287             egl_flags |= EGL_SYNC_FLUSH_COMMANDS_BIT_KHR;
288         }
289 
290         EGLint result = grEGLClientWaitSyncKHR(display, eglSync, egl_flags, timeout);
291 
292         switch (result) {
293             case EGL_CONDITION_SATISFIED_KHR:
294                 return GR_GL_CONDITION_SATISFIED;
295             case EGL_TIMEOUT_EXPIRED_KHR:
296                 return GR_GL_TIMEOUT_EXPIRED;
297             case EGL_FALSE:
298                 return GR_GL_WAIT_FAILED;
299         }
300         SkUNREACHABLE;
301     };
302 
303     glInt->fFunctions.fWaitSync =
304             [grEGLClientWaitSyncKHR, grEGLWaitSyncKHR, display = fDisplay](GrGLsync sync,
305                                                                            GrGLbitfield flags,
306                                                                            GrGLuint64 timeout) {
307         EGLSyncKHR eglSync = reinterpret_cast<EGLSyncKHR>(sync);
308 
309         SkASSERT(timeout == GR_GL_TIMEOUT_IGNORED);
310         SkASSERT(flags == 0);
311 
312         if (!grEGLWaitSyncKHR) {
313             grEGLClientWaitSyncKHR(display, eglSync, 0, EGL_FOREVER_KHR);
314             return;
315         }
316 
317         SkDEBUGCODE(EGLint result =) grEGLWaitSyncKHR(display, eglSync, 0);
318         SkASSERT(result);
319     };
320 
321     glInt->fFunctions.fIsSync =
322             [grEGLGetSyncAttribKHR, display = fDisplay](GrGLsync sync) -> GrGLboolean {
323         EGLSyncKHR eglSync = reinterpret_cast<EGLSyncKHR>(sync);
324         EGLint value;
325         if (grEGLGetSyncAttribKHR(display, eglSync, EGL_SYNC_TYPE_KHR, &value)) {
326             return true;
327         }
328         return false;
329     };
330 }
331 
~EGLGLTestContext()332 EGLGLTestContext::~EGLGLTestContext() {
333     this->teardown();
334     this->destroyGLContext();
335 }
336 
destroyGLContext()337 void EGLGLTestContext::destroyGLContext() {
338     if (fDisplay) {
339         if (fContext) {
340             if (eglGetCurrentContext() == fContext) {
341                 // This will ensure that the context is immediately deleted.
342                 eglMakeCurrent(fDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
343             }
344             eglDestroyContext(fDisplay, fContext);
345             fContext = EGL_NO_CONTEXT;
346         }
347 
348         if (fSurface) {
349             eglDestroySurface(fDisplay, fSurface);
350             fSurface = EGL_NO_SURFACE;
351         }
352 
353         //TODO should we close the display?
354         fDisplay = EGL_NO_DISPLAY;
355     }
356 }
357 
texture2DToEGLImage(GrGLuint texID) const358 GrEGLImage EGLGLTestContext::texture2DToEGLImage(GrGLuint texID) const {
359 #ifdef SK_GL
360     if (!this->gl()->hasExtension("EGL_KHR_gl_texture_2D_image") || !fEglCreateImageProc) {
361         return GR_EGL_NO_IMAGE;
362     }
363     EGLint attribs[] = { GR_EGL_GL_TEXTURE_LEVEL, 0, GR_EGL_NONE };
364     GrEGLClientBuffer clientBuffer = reinterpret_cast<GrEGLClientBuffer>(texID);
365     return fEglCreateImageProc(fDisplay, fContext, GR_EGL_GL_TEXTURE_2D, clientBuffer, attribs);
366 #else
367     (void)fEglCreateImageProc;
368     return nullptr;
369 #endif
370 }
371 
destroyEGLImage(GrEGLImage image) const372 void EGLGLTestContext::destroyEGLImage(GrEGLImage image) const {
373     fEglDestroyImageProc(fDisplay, image);
374 }
375 
eglImageToExternalTexture(GrEGLImage image) const376 GrGLuint EGLGLTestContext::eglImageToExternalTexture(GrEGLImage image) const {
377 #ifdef SK_GL
378     GrGLClearErr(this->gl());
379     if (!this->gl()->hasExtension("GL_OES_EGL_image_external")) {
380         return 0;
381     }
382     typedef GrGLvoid (*EGLImageTargetTexture2DProc)(GrGLenum, GrGLeglImage);
383 
384     EGLImageTargetTexture2DProc glEGLImageTargetTexture2D =
385         (EGLImageTargetTexture2DProc) eglGetProcAddress("glEGLImageTargetTexture2DOES");
386     if (!glEGLImageTargetTexture2D) {
387         return 0;
388     }
389     GrGLuint texID;
390     GR_GL_CALL(this->gl(), GenTextures(1, &texID));
391     if (!texID) {
392         return 0;
393     }
394     GR_GL_CALL_NOERRCHECK(this->gl(), BindTexture(GR_GL_TEXTURE_EXTERNAL, texID));
395     if (GR_GL_GET_ERROR(this->gl()) != GR_GL_NO_ERROR) {
396         GR_GL_CALL(this->gl(), DeleteTextures(1, &texID));
397         return 0;
398     }
399     glEGLImageTargetTexture2D(GR_GL_TEXTURE_EXTERNAL, image);
400     if (GR_GL_GET_ERROR(this->gl()) != GR_GL_NO_ERROR) {
401         GR_GL_CALL(this->gl(), DeleteTextures(1, &texID));
402         return 0;
403     }
404     return texID;
405 #else
406     return 0;
407 #endif
408 }
409 
makeNew() const410 std::unique_ptr<sk_gpu_test::GLTestContext> EGLGLTestContext::makeNew() const {
411     std::unique_ptr<sk_gpu_test::GLTestContext> ctx(new EGLGLTestContext(this->gl()->fStandard,
412                                                                          nullptr));
413     if (ctx) {
414         ctx->makeCurrent();
415     }
416     return ctx;
417 }
418 
onPlatformMakeNotCurrent() const419 void EGLGLTestContext::onPlatformMakeNotCurrent() const {
420     if (!eglMakeCurrent(fDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT )) {
421         SkDebugf("Could not reset the context.\n");
422     }
423 }
424 
onPlatformMakeCurrent() const425 void EGLGLTestContext::onPlatformMakeCurrent() const {
426     if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
427         SkDebugf("Could not set the context.\n");
428     }
429 }
430 
onPlatformGetAutoContextRestore() const431 std::function<void()> EGLGLTestContext::onPlatformGetAutoContextRestore() const {
432     if (eglGetCurrentContext() == fContext) {
433         return nullptr;
434     }
435     return context_restorer();
436 }
437 
onPlatformGetProcAddress(const char * procName) const438 GrGLFuncPtr EGLGLTestContext::onPlatformGetProcAddress(const char* procName) const {
439     return eglGetProcAddress(procName);
440 }
441 
442 }  // anonymous namespace
443 
444 namespace sk_gpu_test {
CreatePlatformGLTestContext(GrGLStandard forcedGpuAPI,GLTestContext * shareContext)445 GLTestContext *CreatePlatformGLTestContext(GrGLStandard forcedGpuAPI,
446                                            GLTestContext *shareContext) {
447     EGLGLTestContext* eglShareContext = reinterpret_cast<EGLGLTestContext*>(shareContext);
448     EGLGLTestContext *ctx = new EGLGLTestContext(forcedGpuAPI, eglShareContext);
449     if (!ctx->isValid()) {
450         delete ctx;
451         return nullptr;
452     }
453     return ctx;
454 }
455 }  // namespace sk_gpu_test
456