• 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 
EGLGLTestContext(GrGLStandard forcedGpuAPI,EGLGLTestContext * shareContext)75 EGLGLTestContext::EGLGLTestContext(GrGLStandard forcedGpuAPI, EGLGLTestContext* shareContext)
76     : fContext(EGL_NO_CONTEXT)
77     , fDisplay(EGL_NO_DISPLAY)
78     , fSurface(EGL_NO_SURFACE) {
79 
80     EGLContext eglShareContext = shareContext ? shareContext->fContext : nullptr;
81 
82     static const EGLint kEGLContextAttribsForOpenGL[] = {
83         EGL_NONE
84     };
85 
86     static const EGLint kEGLContextAttribsForOpenGLES[] = {
87         EGL_CONTEXT_CLIENT_VERSION, 2,
88         EGL_NONE
89     };
90 
91     static const struct {
92         const EGLint* fContextAttribs;
93         EGLenum fAPI;
94         EGLint  fRenderableTypeBit;
95         GrGLStandard fStandard;
96     } kAPIs[] = {
97         {   // OpenGL
98             kEGLContextAttribsForOpenGL,
99             EGL_OPENGL_API,
100             EGL_OPENGL_BIT,
101             kGL_GrGLStandard
102         },
103         {   // OpenGL ES. This seems to work for both ES2 and 3 (when available).
104             kEGLContextAttribsForOpenGLES,
105             EGL_OPENGL_ES_API,
106             EGL_OPENGL_ES2_BIT,
107             kGLES_GrGLStandard
108         },
109     };
110 
111     size_t apiLimit = SK_ARRAY_COUNT(kAPIs);
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 || kAPIs[api].fStandard == 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 
136         if (!eglBindAPI(kAPIs[api].fAPI)) {
137             continue;
138         }
139 
140         EGLint numConfigs = 0;
141         const EGLint configAttribs[] = {
142             EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
143             EGL_RENDERABLE_TYPE, kAPIs[api].fRenderableTypeBit,
144             EGL_RED_SIZE, 8,
145             EGL_GREEN_SIZE, 8,
146             EGL_BLUE_SIZE, 8,
147             EGL_ALPHA_SIZE, 8,
148             EGL_NONE
149         };
150 
151         EGLConfig surfaceConfig;
152         if (!eglChooseConfig(fDisplay, configAttribs, &surfaceConfig, 1, &numConfigs)) {
153             SkDebugf("eglChooseConfig failed. EGL Error: 0x%08x\n", eglGetError());
154             continue;
155         }
156 
157         if (0 == numConfigs) {
158             SkDebugf("No suitable EGL config found.\n");
159             continue;
160         }
161 
162         fContext = eglCreateContext(fDisplay, surfaceConfig, eglShareContext,
163                                     kAPIs[api].fContextAttribs);
164         if (EGL_NO_CONTEXT == fContext) {
165             SkDebugf("eglCreateContext failed.  EGL Error: 0x%08x\n", eglGetError());
166             continue;
167         }
168 
169         static const EGLint kSurfaceAttribs[] = {
170             EGL_WIDTH, 1,
171             EGL_HEIGHT, 1,
172             EGL_NONE
173         };
174 
175         fSurface = eglCreatePbufferSurface(fDisplay, surfaceConfig, kSurfaceAttribs);
176         if (EGL_NO_SURFACE == fSurface) {
177             SkDebugf("eglCreatePbufferSurface failed. EGL Error: 0x%08x\n", eglGetError());
178             this->destroyGLContext();
179             continue;
180         }
181 
182         SkScopeExit restorer(context_restorer());
183         if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
184             SkDebugf("eglMakeCurrent failed.  EGL Error: 0x%08x\n", eglGetError());
185             this->destroyGLContext();
186             continue;
187         }
188 
189         gl = GrGLMakeNativeInterface();
190         if (!gl) {
191             SkDebugf("Failed to create gl interface.\n");
192             this->destroyGLContext();
193             continue;
194         }
195 
196         if (!gl->validate()) {
197             SkDebugf("Failed to validate gl interface.\n");
198             this->destroyGLContext();
199             continue;
200         }
201 
202         this->init(std::move(gl), EGLFenceSync::MakeIfSupported(fDisplay));
203         break;
204     }
205 }
206 
~EGLGLTestContext()207 EGLGLTestContext::~EGLGLTestContext() {
208     this->teardown();
209     this->destroyGLContext();
210 }
211 
destroyGLContext()212 void EGLGLTestContext::destroyGLContext() {
213     if (fDisplay) {
214         if (fContext) {
215             if (eglGetCurrentContext() == fContext) {
216                 // This will ensure that the context is immediately deleted.
217                 eglMakeCurrent(fDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
218             }
219             eglDestroyContext(fDisplay, fContext);
220             fContext = EGL_NO_CONTEXT;
221         }
222 
223         if (fSurface) {
224             eglDestroySurface(fDisplay, fSurface);
225             fSurface = EGL_NO_SURFACE;
226         }
227 
228         //TODO should we close the display?
229         fDisplay = EGL_NO_DISPLAY;
230     }
231 }
232 
texture2DToEGLImage(GrGLuint texID) const233 GrEGLImage EGLGLTestContext::texture2DToEGLImage(GrGLuint texID) const {
234     if (!this->gl()->hasExtension("EGL_KHR_gl_texture_2D_image")) {
235         return GR_EGL_NO_IMAGE;
236     }
237     GrEGLImage img;
238     GrEGLint attribs[] = { GR_EGL_GL_TEXTURE_LEVEL, 0, GR_EGL_NONE };
239     GrEGLClientBuffer clientBuffer = reinterpret_cast<GrEGLClientBuffer>(texID);
240     GR_GL_CALL_RET(this->gl(), img,
241                    EGLCreateImage(fDisplay, fContext, GR_EGL_GL_TEXTURE_2D, clientBuffer, attribs));
242     return img;
243 }
244 
destroyEGLImage(GrEGLImage image) const245 void EGLGLTestContext::destroyEGLImage(GrEGLImage image) const {
246     GR_GL_CALL(this->gl(), EGLDestroyImage(fDisplay, image));
247 }
248 
eglImageToExternalTexture(GrEGLImage image) const249 GrGLuint EGLGLTestContext::eglImageToExternalTexture(GrEGLImage image) const {
250     GrGLClearErr(this->gl());
251     if (!this->gl()->hasExtension("GL_OES_EGL_image_external")) {
252         return 0;
253     }
254     typedef GrGLvoid (*EGLImageTargetTexture2DProc)(GrGLenum, GrGLeglImage);
255 
256     EGLImageTargetTexture2DProc glEGLImageTargetTexture2D =
257         (EGLImageTargetTexture2DProc) eglGetProcAddress("glEGLImageTargetTexture2DOES");
258     if (!glEGLImageTargetTexture2D) {
259         return 0;
260     }
261     GrGLuint texID;
262     GR_GL_CALL(this->gl(), GenTextures(1, &texID));
263     if (!texID) {
264         return 0;
265     }
266     GR_GL_CALL_NOERRCHECK(this->gl(), BindTexture(GR_GL_TEXTURE_EXTERNAL, texID));
267     if (GR_GL_GET_ERROR(this->gl()) != GR_GL_NO_ERROR) {
268         GR_GL_CALL(this->gl(), DeleteTextures(1, &texID));
269         return 0;
270     }
271     glEGLImageTargetTexture2D(GR_GL_TEXTURE_EXTERNAL, image);
272     if (GR_GL_GET_ERROR(this->gl()) != GR_GL_NO_ERROR) {
273         GR_GL_CALL(this->gl(), DeleteTextures(1, &texID));
274         return 0;
275     }
276     return texID;
277 }
278 
makeNew() const279 std::unique_ptr<sk_gpu_test::GLTestContext> EGLGLTestContext::makeNew() const {
280     std::unique_ptr<sk_gpu_test::GLTestContext> ctx(new EGLGLTestContext(this->gl()->fStandard,
281                                                                          nullptr));
282     if (ctx) {
283         ctx->makeCurrent();
284     }
285     return ctx;
286 }
287 
onPlatformMakeCurrent() const288 void EGLGLTestContext::onPlatformMakeCurrent() const {
289     if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
290         SkDebugf("Could not set the context.\n");
291     }
292 }
293 
onPlatformGetAutoContextRestore() const294 std::function<void()> EGLGLTestContext::onPlatformGetAutoContextRestore() const {
295     if (eglGetCurrentContext() == fContext) {
296         return nullptr;
297     }
298     return context_restorer();
299 }
300 
onPlatformSwapBuffers() const301 void EGLGLTestContext::onPlatformSwapBuffers() const {
302     if (!eglSwapBuffers(fDisplay, fSurface)) {
303         SkDebugf("Could not complete eglSwapBuffers.\n");
304     }
305 }
306 
onPlatformGetProcAddress(const char * procName) const307 GrGLFuncPtr EGLGLTestContext::onPlatformGetProcAddress(const char* procName) const {
308     return eglGetProcAddress(procName);
309 }
310 
supports_egl_extension(EGLDisplay display,const char * extension)311 static bool supports_egl_extension(EGLDisplay display, const char* extension) {
312     size_t extensionLength = strlen(extension);
313     const char* extensionsStr = eglQueryString(display, EGL_EXTENSIONS);
314     while (const char* match = strstr(extensionsStr, extension)) {
315         // Ensure the string we found is its own extension, not a substring of a larger extension
316         // (e.g. GL_ARB_occlusion_query / GL_ARB_occlusion_query2).
317         if ((match == extensionsStr || match[-1] == ' ') &&
318             (match[extensionLength] == ' ' || match[extensionLength] == '\0')) {
319             return true;
320         }
321         extensionsStr = match + extensionLength;
322     }
323     return false;
324 }
325 
MakeIfSupported(EGLDisplay display)326 std::unique_ptr<EGLFenceSync> EGLFenceSync::MakeIfSupported(EGLDisplay display) {
327     if (!display || !supports_egl_extension(display, "EGL_KHR_fence_sync")) {
328         return nullptr;
329     }
330     return std::unique_ptr<EGLFenceSync>(new EGLFenceSync(display));
331 }
332 
EGLFenceSync(EGLDisplay display)333 EGLFenceSync::EGLFenceSync(EGLDisplay display)
334     : fDisplay(display) {
335     fEGLCreateSyncKHR = (PFNEGLCREATESYNCKHRPROC) eglGetProcAddress("eglCreateSyncKHR");
336     fEGLClientWaitSyncKHR = (PFNEGLCLIENTWAITSYNCKHRPROC) eglGetProcAddress("eglClientWaitSyncKHR");
337     fEGLDestroySyncKHR = (PFNEGLDESTROYSYNCKHRPROC) eglGetProcAddress("eglDestroySyncKHR");
338     SkASSERT(fEGLCreateSyncKHR && fEGLClientWaitSyncKHR && fEGLDestroySyncKHR);
339 }
340 
insertFence() const341 sk_gpu_test::PlatformFence EGLFenceSync::insertFence() const {
342     EGLSyncKHR eglsync = fEGLCreateSyncKHR(fDisplay, EGL_SYNC_FENCE_KHR, nullptr);
343     return reinterpret_cast<sk_gpu_test::PlatformFence>(eglsync);
344 }
345 
waitFence(sk_gpu_test::PlatformFence platformFence) const346 bool EGLFenceSync::waitFence(sk_gpu_test::PlatformFence platformFence) const {
347     EGLSyncKHR eglsync = reinterpret_cast<EGLSyncKHR>(platformFence);
348     return EGL_CONDITION_SATISFIED_KHR ==
349             fEGLClientWaitSyncKHR(fDisplay,
350                                   eglsync,
351                                   EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
352                                   EGL_FOREVER_KHR);
353 }
354 
deleteFence(sk_gpu_test::PlatformFence platformFence) const355 void EGLFenceSync::deleteFence(sk_gpu_test::PlatformFence platformFence) const {
356     EGLSyncKHR eglsync = reinterpret_cast<EGLSyncKHR>(platformFence);
357     fEGLDestroySyncKHR(fDisplay, eglsync);
358 }
359 
360 GR_STATIC_ASSERT(sizeof(EGLSyncKHR) <= sizeof(sk_gpu_test::PlatformFence));
361 
362 }  // anonymous namespace
363 
364 namespace sk_gpu_test {
CreatePlatformGLTestContext(GrGLStandard forcedGpuAPI,GLTestContext * shareContext)365 GLTestContext *CreatePlatformGLTestContext(GrGLStandard forcedGpuAPI,
366                                            GLTestContext *shareContext) {
367     EGLGLTestContext* eglShareContext = reinterpret_cast<EGLGLTestContext*>(shareContext);
368     EGLGLTestContext *ctx = new EGLGLTestContext(forcedGpuAPI, eglShareContext);
369     if (!ctx->isValid()) {
370         delete ctx;
371         return nullptr;
372     }
373     return ctx;
374 }
375 }  // namespace sk_gpu_test
376