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