• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /*
3  * Copyright 2011 Google Inc.
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8 #include "tools/gpu/gl/GLTestContext.h"
9 
10 #define GL_GLEXT_PROTOTYPES
11 
12 #include <GLES2/gl2.h>
13 
14 #include <EGL/egl.h>
15 #include <EGL/eglext.h>
16 
17 #include "src/gpu/gl/GrGLDefines.h"
18 #include "src/gpu/gl/GrGLUtil.h"
19 
20 namespace {
21 
22 // TODO: Share this class with ANGLE if/when it gets support for EGL_KHR_fence_sync.
23 class EGLFenceSync : public sk_gpu_test::FenceSync {
24 public:
25     static std::unique_ptr<EGLFenceSync> MakeIfSupported(EGLDisplay);
26 
27     sk_gpu_test::PlatformFence SK_WARN_UNUSED_RESULT insertFence() const override;
28     bool waitFence(sk_gpu_test::PlatformFence fence) const override;
29     void deleteFence(sk_gpu_test::PlatformFence fence) const override;
30 
31 private:
32     EGLFenceSync(EGLDisplay display);
33 
34     PFNEGLCREATESYNCKHRPROC       fEGLCreateSyncKHR;
35     PFNEGLCLIENTWAITSYNCKHRPROC   fEGLClientWaitSyncKHR;
36     PFNEGLDESTROYSYNCKHRPROC      fEGLDestroySyncKHR;
37 
38     EGLDisplay                    fDisplay;
39 
40     typedef sk_gpu_test::FenceSync INHERITED;
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 
53 class EGLGLTestContext : public sk_gpu_test::GLTestContext {
54 public:
55     EGLGLTestContext(GrGLStandard forcedGpuAPI, EGLGLTestContext* shareContext);
56     ~EGLGLTestContext() override;
57 
58     GrEGLImage texture2DToEGLImage(GrGLuint texID) const override;
59     void destroyEGLImage(GrEGLImage) const override;
60     GrGLuint eglImageToExternalTexture(GrEGLImage) const override;
61     std::unique_ptr<sk_gpu_test::GLTestContext> makeNew() const override;
62 
63 private:
64     void destroyGLContext();
65 
66     void onPlatformMakeCurrent() const override;
67     std::function<void()> onPlatformGetAutoContextRestore() const override;
68     void onPlatformSwapBuffers() const override;
69     GrGLFuncPtr onPlatformGetProcAddress(const char*) const override;
70 
71     PFNEGLCREATEIMAGEKHRPROC fEglCreateImageProc = nullptr;
72     PFNEGLDESTROYIMAGEKHRPROC fEglDestroyImageProc = nullptr;
73 
74     EGLContext fContext;
75     EGLDisplay fDisplay;
76     EGLSurface fSurface;
77 };
78 
create_gles_egl_context(EGLDisplay display,EGLConfig surfaceConfig,EGLContext eglShareContext,EGLint eglContextClientVersion)79 static EGLContext create_gles_egl_context(EGLDisplay display,
80                                           EGLConfig surfaceConfig,
81                                           EGLContext eglShareContext,
82                                           EGLint eglContextClientVersion) {
83     const EGLint contextAttribsForOpenGLES[] = {
84         EGL_CONTEXT_CLIENT_VERSION,
85         eglContextClientVersion,
86         EGL_NONE
87     };
88     return eglCreateContext(display, surfaceConfig, eglShareContext, contextAttribsForOpenGLES);
89 }
create_gl_egl_context(EGLDisplay display,EGLConfig surfaceConfig,EGLContext eglShareContext)90 static EGLContext create_gl_egl_context(EGLDisplay display,
91                                         EGLConfig surfaceConfig,
92                                         EGLContext eglShareContext) {
93     const EGLint contextAttribsForOpenGL[] = {
94         EGL_NONE
95     };
96     return eglCreateContext(display, surfaceConfig, eglShareContext, contextAttribsForOpenGL);
97 }
98 
EGLGLTestContext(GrGLStandard forcedGpuAPI,EGLGLTestContext * shareContext)99 EGLGLTestContext::EGLGLTestContext(GrGLStandard forcedGpuAPI, EGLGLTestContext* shareContext)
100     : fContext(EGL_NO_CONTEXT)
101     , fDisplay(EGL_NO_DISPLAY)
102     , fSurface(EGL_NO_SURFACE) {
103 
104     EGLContext eglShareContext = shareContext ? shareContext->fContext : nullptr;
105 
106     static const GrGLStandard kStandards[] = {
107         kGL_GrGLStandard,
108         kGLES_GrGLStandard,
109     };
110 
111     size_t apiLimit = SK_ARRAY_COUNT(kStandards);
112     size_t api = 0;
113     if (forcedGpuAPI == kGL_GrGLStandard) {
114         apiLimit = 1;
115     } else if (forcedGpuAPI == kGLES_GrGLStandard) {
116         api = 1;
117     }
118     SkASSERT(forcedGpuAPI == kNone_GrGLStandard || kStandards[api] == forcedGpuAPI);
119 
120     sk_sp<const GrGLInterface> gl;
121 
122     for (; nullptr == gl.get() && api < apiLimit; ++api) {
123         fDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
124 
125         EGLint majorVersion;
126         EGLint minorVersion;
127         eglInitialize(fDisplay, &majorVersion, &minorVersion);
128 
129 #if 0
130         SkDebugf("VENDOR: %s\n", eglQueryString(fDisplay, EGL_VENDOR));
131         SkDebugf("APIS: %s\n", eglQueryString(fDisplay, EGL_CLIENT_APIS));
132         SkDebugf("VERSION: %s\n", eglQueryString(fDisplay, EGL_VERSION));
133         SkDebugf("EXTENSIONS %s\n", eglQueryString(fDisplay, EGL_EXTENSIONS));
134 #endif
135         bool gles = kGLES_GrGLStandard == kStandards[api];
136 
137         if (!eglBindAPI(gles ? EGL_OPENGL_ES_API : EGL_OPENGL_API)) {
138             continue;
139         }
140 
141         EGLint numConfigs = 0;
142         const EGLint configAttribs[] = {
143             EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
144             EGL_RENDERABLE_TYPE, gles ? EGL_OPENGL_ES2_BIT : EGL_OPENGL_BIT,
145             EGL_RED_SIZE, 8,
146             EGL_GREEN_SIZE, 8,
147             EGL_BLUE_SIZE, 8,
148             EGL_ALPHA_SIZE, 8,
149             EGL_NONE
150         };
151 
152         EGLConfig surfaceConfig;
153         if (!eglChooseConfig(fDisplay, configAttribs, &surfaceConfig, 1, &numConfigs)) {
154             SkDebugf("eglChooseConfig failed. EGL Error: 0x%08x\n", eglGetError());
155             continue;
156         }
157 
158         if (0 == numConfigs) {
159             SkDebugf("No suitable EGL config found.\n");
160             continue;
161         }
162 
163         if (gles) {
164 #ifdef GR_EGL_TRY_GLES3_THEN_GLES2
165             // Some older devices (Nexus7/Tegra3) crash when you try this.  So it is (for now)
166             // hidden behind this flag.
167             fContext = create_gles_egl_context(fDisplay, surfaceConfig, eglShareContext, 3);
168             if (EGL_NO_CONTEXT == fContext) {
169                 fContext = create_gles_egl_context(fDisplay, surfaceConfig, eglShareContext, 2);
170             }
171 #else
172             fContext = create_gles_egl_context(fDisplay, surfaceConfig, eglShareContext, 2);
173 #endif
174         } else {
175             fContext = create_gl_egl_context(fDisplay, surfaceConfig, eglShareContext);
176         }
177         if (EGL_NO_CONTEXT == fContext) {
178             SkDebugf("eglCreateContext failed.  EGL Error: 0x%08x\n", eglGetError());
179             continue;
180         }
181 
182         static const EGLint kSurfaceAttribs[] = {
183             EGL_WIDTH, 1,
184             EGL_HEIGHT, 1,
185             EGL_NONE
186         };
187 
188         fSurface = eglCreatePbufferSurface(fDisplay, surfaceConfig, kSurfaceAttribs);
189         if (EGL_NO_SURFACE == fSurface) {
190             SkDebugf("eglCreatePbufferSurface failed. EGL Error: 0x%08x\n", eglGetError());
191             this->destroyGLContext();
192             continue;
193         }
194 
195         SkScopeExit restorer(context_restorer());
196         if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
197             SkDebugf("eglMakeCurrent failed.  EGL Error: 0x%08x\n", eglGetError());
198             this->destroyGLContext();
199             continue;
200         }
201 
202         gl = GrGLMakeNativeInterface();
203         if (!gl) {
204             SkDebugf("Failed to create gl interface.\n");
205             this->destroyGLContext();
206             continue;
207         }
208 
209         if (!gl->validate()) {
210             SkDebugf("Failed to validate gl interface.\n");
211             this->destroyGLContext();
212             continue;
213         }
214         const char* extensions = eglQueryString(fDisplay, EGL_EXTENSIONS);
215         if (strstr(extensions, "EGL_KHR_image")) {
216             fEglCreateImageProc = (PFNEGLCREATEIMAGEKHRPROC)eglGetProcAddress("eglCreateImageKHR");
217             fEglDestroyImageProc =
218                     (PFNEGLDESTROYIMAGEKHRPROC)eglGetProcAddress("eglDestroyImageKHR");
219         }
220 
221         this->init(std::move(gl), EGLFenceSync::MakeIfSupported(fDisplay));
222         break;
223     }
224 }
225 
~EGLGLTestContext()226 EGLGLTestContext::~EGLGLTestContext() {
227     this->teardown();
228     this->destroyGLContext();
229 }
230 
destroyGLContext()231 void EGLGLTestContext::destroyGLContext() {
232     if (fDisplay) {
233         if (fContext) {
234             if (eglGetCurrentContext() == fContext) {
235                 // This will ensure that the context is immediately deleted.
236                 eglMakeCurrent(fDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
237             }
238             eglDestroyContext(fDisplay, fContext);
239             fContext = EGL_NO_CONTEXT;
240         }
241 
242         if (fSurface) {
243             eglDestroySurface(fDisplay, fSurface);
244             fSurface = EGL_NO_SURFACE;
245         }
246 
247         //TODO should we close the display?
248         fDisplay = EGL_NO_DISPLAY;
249     }
250 }
251 
texture2DToEGLImage(GrGLuint texID) const252 GrEGLImage EGLGLTestContext::texture2DToEGLImage(GrGLuint texID) const {
253     if (!this->gl()->hasExtension("EGL_KHR_gl_texture_2D_image") || !fEglCreateImageProc) {
254         return GR_EGL_NO_IMAGE;
255     }
256     EGLint attribs[] = { GR_EGL_GL_TEXTURE_LEVEL, 0, GR_EGL_NONE };
257     GrEGLClientBuffer clientBuffer = reinterpret_cast<GrEGLClientBuffer>(texID);
258     return fEglCreateImageProc(fDisplay, fContext, GR_EGL_GL_TEXTURE_2D, clientBuffer, attribs);
259 }
260 
destroyEGLImage(GrEGLImage image) const261 void EGLGLTestContext::destroyEGLImage(GrEGLImage image) const {
262     fEglDestroyImageProc(fDisplay, image);
263 }
264 
eglImageToExternalTexture(GrEGLImage image) const265 GrGLuint EGLGLTestContext::eglImageToExternalTexture(GrEGLImage image) const {
266     GrGLClearErr(this->gl());
267     if (!this->gl()->hasExtension("GL_OES_EGL_image_external")) {
268         return 0;
269     }
270     typedef GrGLvoid (*EGLImageTargetTexture2DProc)(GrGLenum, GrGLeglImage);
271 
272     EGLImageTargetTexture2DProc glEGLImageTargetTexture2D =
273         (EGLImageTargetTexture2DProc) eglGetProcAddress("glEGLImageTargetTexture2DOES");
274     if (!glEGLImageTargetTexture2D) {
275         return 0;
276     }
277     GrGLuint texID;
278     GR_GL_CALL(this->gl(), GenTextures(1, &texID));
279     if (!texID) {
280         return 0;
281     }
282     GR_GL_CALL_NOERRCHECK(this->gl(), BindTexture(GR_GL_TEXTURE_EXTERNAL, texID));
283     if (GR_GL_GET_ERROR(this->gl()) != GR_GL_NO_ERROR) {
284         GR_GL_CALL(this->gl(), DeleteTextures(1, &texID));
285         return 0;
286     }
287     glEGLImageTargetTexture2D(GR_GL_TEXTURE_EXTERNAL, image);
288     if (GR_GL_GET_ERROR(this->gl()) != GR_GL_NO_ERROR) {
289         GR_GL_CALL(this->gl(), DeleteTextures(1, &texID));
290         return 0;
291     }
292     return texID;
293 }
294 
makeNew() const295 std::unique_ptr<sk_gpu_test::GLTestContext> EGLGLTestContext::makeNew() const {
296     std::unique_ptr<sk_gpu_test::GLTestContext> ctx(new EGLGLTestContext(this->gl()->fStandard,
297                                                                          nullptr));
298     if (ctx) {
299         ctx->makeCurrent();
300     }
301     return ctx;
302 }
303 
onPlatformMakeCurrent() const304 void EGLGLTestContext::onPlatformMakeCurrent() const {
305     if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
306         SkDebugf("Could not set the context.\n");
307     }
308 }
309 
onPlatformGetAutoContextRestore() const310 std::function<void()> EGLGLTestContext::onPlatformGetAutoContextRestore() const {
311     if (eglGetCurrentContext() == fContext) {
312         return nullptr;
313     }
314     return context_restorer();
315 }
316 
onPlatformSwapBuffers() const317 void EGLGLTestContext::onPlatformSwapBuffers() const {
318     if (!eglSwapBuffers(fDisplay, fSurface)) {
319         SkDebugf("Could not complete eglSwapBuffers.\n");
320     }
321 }
322 
onPlatformGetProcAddress(const char * procName) const323 GrGLFuncPtr EGLGLTestContext::onPlatformGetProcAddress(const char* procName) const {
324     return eglGetProcAddress(procName);
325 }
326 
supports_egl_extension(EGLDisplay display,const char * extension)327 static bool supports_egl_extension(EGLDisplay display, const char* extension) {
328     size_t extensionLength = strlen(extension);
329     const char* extensionsStr = eglQueryString(display, EGL_EXTENSIONS);
330     while (const char* match = strstr(extensionsStr, extension)) {
331         // Ensure the string we found is its own extension, not a substring of a larger extension
332         // (e.g. GL_ARB_occlusion_query / GL_ARB_occlusion_query2).
333         if ((match == extensionsStr || match[-1] == ' ') &&
334             (match[extensionLength] == ' ' || match[extensionLength] == '\0')) {
335             return true;
336         }
337         extensionsStr = match + extensionLength;
338     }
339     return false;
340 }
341 
MakeIfSupported(EGLDisplay display)342 std::unique_ptr<EGLFenceSync> EGLFenceSync::MakeIfSupported(EGLDisplay display) {
343     if (!display || !supports_egl_extension(display, "EGL_KHR_fence_sync")) {
344         return nullptr;
345     }
346     return std::unique_ptr<EGLFenceSync>(new EGLFenceSync(display));
347 }
348 
EGLFenceSync(EGLDisplay display)349 EGLFenceSync::EGLFenceSync(EGLDisplay display)
350     : fDisplay(display) {
351     fEGLCreateSyncKHR = (PFNEGLCREATESYNCKHRPROC) eglGetProcAddress("eglCreateSyncKHR");
352     fEGLClientWaitSyncKHR = (PFNEGLCLIENTWAITSYNCKHRPROC) eglGetProcAddress("eglClientWaitSyncKHR");
353     fEGLDestroySyncKHR = (PFNEGLDESTROYSYNCKHRPROC) eglGetProcAddress("eglDestroySyncKHR");
354     SkASSERT(fEGLCreateSyncKHR && fEGLClientWaitSyncKHR && fEGLDestroySyncKHR);
355 }
356 
insertFence() const357 sk_gpu_test::PlatformFence EGLFenceSync::insertFence() const {
358     EGLSyncKHR eglsync = fEGLCreateSyncKHR(fDisplay, EGL_SYNC_FENCE_KHR, nullptr);
359     return reinterpret_cast<sk_gpu_test::PlatformFence>(eglsync);
360 }
361 
waitFence(sk_gpu_test::PlatformFence platformFence) const362 bool EGLFenceSync::waitFence(sk_gpu_test::PlatformFence platformFence) const {
363     EGLSyncKHR eglsync = reinterpret_cast<EGLSyncKHR>(platformFence);
364     return EGL_CONDITION_SATISFIED_KHR ==
365             fEGLClientWaitSyncKHR(fDisplay,
366                                   eglsync,
367                                   EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
368                                   EGL_FOREVER_KHR);
369 }
370 
deleteFence(sk_gpu_test::PlatformFence platformFence) const371 void EGLFenceSync::deleteFence(sk_gpu_test::PlatformFence platformFence) const {
372     EGLSyncKHR eglsync = reinterpret_cast<EGLSyncKHR>(platformFence);
373     fEGLDestroySyncKHR(fDisplay, eglsync);
374 }
375 
376 GR_STATIC_ASSERT(sizeof(EGLSyncKHR) <= sizeof(sk_gpu_test::PlatformFence));
377 
378 }  // anonymous namespace
379 
380 namespace sk_gpu_test {
CreatePlatformGLTestContext(GrGLStandard forcedGpuAPI,GLTestContext * shareContext)381 GLTestContext *CreatePlatformGLTestContext(GrGLStandard forcedGpuAPI,
382                                            GLTestContext *shareContext) {
383     EGLGLTestContext* eglShareContext = reinterpret_cast<EGLGLTestContext*>(shareContext);
384     EGLGLTestContext *ctx = new EGLGLTestContext(forcedGpuAPI, eglShareContext);
385     if (!ctx->isValid()) {
386         delete ctx;
387         return nullptr;
388     }
389     return ctx;
390 }
391 }  // namespace sk_gpu_test
392