• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     PFNEGLCREATEIMAGEKHRPROC fEglCreateImageProc = nullptr;
47     PFNEGLDESTROYIMAGEKHRPROC fEglDestroyImageProc = nullptr;
48 
49     EGLContext fContext;
50     EGLDisplay fDisplay;
51     EGLSurface fSurface;
52 };
53 
create_gles_egl_context(EGLDisplay display,EGLConfig surfaceConfig,EGLContext eglShareContext,EGLint eglContextClientVersion)54 static EGLContext create_gles_egl_context(EGLDisplay display,
55                                           EGLConfig surfaceConfig,
56                                           EGLContext eglShareContext,
57                                           EGLint eglContextClientVersion) {
58     const EGLint contextAttribsForOpenGLES[] = {
59         EGL_CONTEXT_CLIENT_VERSION,
60         eglContextClientVersion,
61         EGL_NONE
62     };
63     return eglCreateContext(display, surfaceConfig, eglShareContext, contextAttribsForOpenGLES);
64 }
create_gl_egl_context(EGLDisplay display,EGLConfig surfaceConfig,EGLContext eglShareContext)65 static EGLContext create_gl_egl_context(EGLDisplay display,
66                                         EGLConfig surfaceConfig,
67                                         EGLContext eglShareContext) {
68     const EGLint contextAttribsForOpenGL[] = {
69         EGL_NONE
70     };
71     return eglCreateContext(display, surfaceConfig, eglShareContext, contextAttribsForOpenGL);
72 }
73 
EGLGLTestContext(GrGLStandard forcedGpuAPI,EGLGLTestContext * shareContext)74 EGLGLTestContext::EGLGLTestContext(GrGLStandard forcedGpuAPI, EGLGLTestContext* shareContext)
75     : fContext(EGL_NO_CONTEXT)
76     , fDisplay(EGL_NO_DISPLAY)
77     , fSurface(EGL_NO_SURFACE) {
78 
79     EGLContext eglShareContext = shareContext ? shareContext->fContext : nullptr;
80 
81     static const GrGLStandard kStandards[] = {
82         kGL_GrGLStandard,
83         kGLES_GrGLStandard,
84     };
85 
86     size_t apiLimit = SK_ARRAY_COUNT(kStandards);
87     size_t api = 0;
88     if (forcedGpuAPI == kGL_GrGLStandard) {
89         apiLimit = 1;
90     } else if (forcedGpuAPI == kGLES_GrGLStandard) {
91         api = 1;
92     }
93     SkASSERT(forcedGpuAPI == kNone_GrGLStandard || kStandards[api] == forcedGpuAPI);
94 
95     sk_sp<const GrGLInterface> gl;
96 
97     for (; nullptr == gl.get() && api < apiLimit; ++api) {
98         fDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
99 
100         EGLint majorVersion;
101         EGLint minorVersion;
102         eglInitialize(fDisplay, &majorVersion, &minorVersion);
103 
104 #if 0
105         SkDebugf("VENDOR: %s\n", eglQueryString(fDisplay, EGL_VENDOR));
106         SkDebugf("APIS: %s\n", eglQueryString(fDisplay, EGL_CLIENT_APIS));
107         SkDebugf("VERSION: %s\n", eglQueryString(fDisplay, EGL_VERSION));
108         SkDebugf("EXTENSIONS %s\n", eglQueryString(fDisplay, EGL_EXTENSIONS));
109 #endif
110         bool gles = kGLES_GrGLStandard == kStandards[api];
111 
112         if (!eglBindAPI(gles ? EGL_OPENGL_ES_API : EGL_OPENGL_API)) {
113             continue;
114         }
115 
116         EGLint numConfigs = 0;
117         const EGLint configAttribs[] = {
118             EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
119             EGL_RENDERABLE_TYPE, gles ? EGL_OPENGL_ES2_BIT : EGL_OPENGL_BIT,
120             EGL_RED_SIZE, 8,
121             EGL_GREEN_SIZE, 8,
122             EGL_BLUE_SIZE, 8,
123             EGL_ALPHA_SIZE, 8,
124             EGL_NONE
125         };
126 
127         EGLConfig surfaceConfig;
128         if (!eglChooseConfig(fDisplay, configAttribs, &surfaceConfig, 1, &numConfigs)) {
129             SkDebugf("eglChooseConfig failed. EGL Error: 0x%08x\n", eglGetError());
130             continue;
131         }
132 
133         if (0 == numConfigs) {
134             SkDebugf("No suitable EGL config found.\n");
135             continue;
136         }
137 
138         if (gles) {
139 #ifdef GR_EGL_TRY_GLES3_THEN_GLES2
140             // Some older devices (Nexus7/Tegra3) crash when you try this.  So it is (for now)
141             // hidden behind this flag.
142             fContext = create_gles_egl_context(fDisplay, surfaceConfig, eglShareContext, 3);
143             if (EGL_NO_CONTEXT == fContext) {
144                 fContext = create_gles_egl_context(fDisplay, surfaceConfig, eglShareContext, 2);
145             }
146 #else
147             fContext = create_gles_egl_context(fDisplay, surfaceConfig, eglShareContext, 2);
148 #endif
149         } else {
150             fContext = create_gl_egl_context(fDisplay, surfaceConfig, eglShareContext);
151         }
152         if (EGL_NO_CONTEXT == fContext) {
153             SkDebugf("eglCreateContext failed.  EGL Error: 0x%08x\n", eglGetError());
154             continue;
155         }
156 
157         static const EGLint kSurfaceAttribs[] = {
158             EGL_WIDTH, 1,
159             EGL_HEIGHT, 1,
160             EGL_NONE
161         };
162 
163         fSurface = eglCreatePbufferSurface(fDisplay, surfaceConfig, kSurfaceAttribs);
164         if (EGL_NO_SURFACE == fSurface) {
165             SkDebugf("eglCreatePbufferSurface failed. EGL Error: 0x%08x\n", eglGetError());
166             this->destroyGLContext();
167             continue;
168         }
169 
170         SkScopeExit restorer(context_restorer());
171         if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
172             SkDebugf("eglMakeCurrent failed.  EGL Error: 0x%08x\n", eglGetError());
173             this->destroyGLContext();
174             continue;
175         }
176 
177 #ifdef SK_GL
178         gl = GrGLMakeNativeInterface();
179         if (!gl) {
180             SkDebugf("Failed to create gl interface.\n");
181             this->destroyGLContext();
182             continue;
183         }
184 
185         if (!gl->validate()) {
186             SkDebugf("Failed to validate gl interface.\n");
187             this->destroyGLContext();
188             continue;
189         }
190         const char* extensions = eglQueryString(fDisplay, EGL_EXTENSIONS);
191         if (strstr(extensions, "EGL_KHR_image")) {
192             fEglCreateImageProc = (PFNEGLCREATEIMAGEKHRPROC)eglGetProcAddress("eglCreateImageKHR");
193             fEglDestroyImageProc =
194                     (PFNEGLDESTROYIMAGEKHRPROC)eglGetProcAddress("eglDestroyImageKHR");
195         }
196 
197         this->init(std::move(gl));
198 #else
199         // Allow the GLTestContext creation to succeed without a GrGLInterface to support
200         // GrContextFactory's persistent GL context workaround for Vulkan. We won't need the
201         // GrGLInterface since we're not running the GL backend.
202         this->init(nullptr);
203 #endif
204         break;
205     }
206 }
207 
~EGLGLTestContext()208 EGLGLTestContext::~EGLGLTestContext() {
209     this->teardown();
210     this->destroyGLContext();
211 }
212 
destroyGLContext()213 void EGLGLTestContext::destroyGLContext() {
214     if (fDisplay) {
215         if (fContext) {
216             if (eglGetCurrentContext() == fContext) {
217                 // This will ensure that the context is immediately deleted.
218                 eglMakeCurrent(fDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
219             }
220             eglDestroyContext(fDisplay, fContext);
221             fContext = EGL_NO_CONTEXT;
222         }
223 
224         if (fSurface) {
225             eglDestroySurface(fDisplay, fSurface);
226             fSurface = EGL_NO_SURFACE;
227         }
228 
229         //TODO should we close the display?
230         fDisplay = EGL_NO_DISPLAY;
231     }
232 }
233 
texture2DToEGLImage(GrGLuint texID) const234 GrEGLImage EGLGLTestContext::texture2DToEGLImage(GrGLuint texID) const {
235 #ifdef SK_GL
236     if (!this->gl()->hasExtension("EGL_KHR_gl_texture_2D_image") || !fEglCreateImageProc) {
237         return GR_EGL_NO_IMAGE;
238     }
239     EGLint attribs[] = { GR_EGL_GL_TEXTURE_LEVEL, 0, GR_EGL_NONE };
240     GrEGLClientBuffer clientBuffer = reinterpret_cast<GrEGLClientBuffer>(texID);
241     return fEglCreateImageProc(fDisplay, fContext, GR_EGL_GL_TEXTURE_2D, clientBuffer, attribs);
242 #else
243     (void)fEglCreateImageProc;
244     return nullptr;
245 #endif
246 }
247 
destroyEGLImage(GrEGLImage image) const248 void EGLGLTestContext::destroyEGLImage(GrEGLImage image) const {
249     fEglDestroyImageProc(fDisplay, image);
250 }
251 
eglImageToExternalTexture(GrEGLImage image) const252 GrGLuint EGLGLTestContext::eglImageToExternalTexture(GrEGLImage image) const {
253 #ifdef SK_GL
254     while (this->gl()->fFunctions.fGetError() != GR_GL_NO_ERROR) {}
255     if (!this->gl()->hasExtension("GL_OES_EGL_image_external")) {
256         return 0;
257     }
258     typedef GrGLvoid (*EGLImageTargetTexture2DProc)(GrGLenum, GrGLeglImage);
259 
260     EGLImageTargetTexture2DProc glEGLImageTargetTexture2D =
261         (EGLImageTargetTexture2DProc) eglGetProcAddress("glEGLImageTargetTexture2DOES");
262     if (!glEGLImageTargetTexture2D) {
263         return 0;
264     }
265     GrGLuint texID;
266     GR_GL_CALL(this->gl(), GenTextures(1, &texID));
267     if (!texID) {
268         return 0;
269     }
270     GR_GL_CALL_NOERRCHECK(this->gl(), BindTexture(GR_GL_TEXTURE_EXTERNAL, texID));
271     if (this->gl()->fFunctions.fGetError() != GR_GL_NO_ERROR) {
272         GR_GL_CALL(this->gl(), DeleteTextures(1, &texID));
273         return 0;
274     }
275     glEGLImageTargetTexture2D(GR_GL_TEXTURE_EXTERNAL, image);
276     if (this->gl()->fFunctions.fGetError() != GR_GL_NO_ERROR) {
277         GR_GL_CALL(this->gl(), DeleteTextures(1, &texID));
278         return 0;
279     }
280     return texID;
281 #else
282     return 0;
283 #endif
284 }
285 
makeNew() const286 std::unique_ptr<sk_gpu_test::GLTestContext> EGLGLTestContext::makeNew() const {
287     std::unique_ptr<sk_gpu_test::GLTestContext> ctx(new EGLGLTestContext(this->gl()->fStandard,
288                                                                          nullptr));
289     if (ctx) {
290         ctx->makeCurrent();
291     }
292     return ctx;
293 }
294 
onPlatformMakeNotCurrent() const295 void EGLGLTestContext::onPlatformMakeNotCurrent() const {
296     if (!eglMakeCurrent(fDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT )) {
297         SkDebugf("Could not reset the context.\n");
298     }
299 }
300 
onPlatformMakeCurrent() const301 void EGLGLTestContext::onPlatformMakeCurrent() const {
302     if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
303         SkDebugf("Could not set the context.\n");
304     }
305 }
306 
onPlatformGetAutoContextRestore() const307 std::function<void()> EGLGLTestContext::onPlatformGetAutoContextRestore() const {
308     if (eglGetCurrentContext() == fContext) {
309         return nullptr;
310     }
311     return context_restorer();
312 }
313 
onPlatformGetProcAddress(const char * procName) const314 GrGLFuncPtr EGLGLTestContext::onPlatformGetProcAddress(const char* procName) const {
315     return eglGetProcAddress(procName);
316 }
317 
318 }  // anonymous namespace
319 
320 namespace sk_gpu_test {
CreatePlatformGLTestContext(GrGLStandard forcedGpuAPI,GLTestContext * shareContext)321 GLTestContext *CreatePlatformGLTestContext(GrGLStandard forcedGpuAPI,
322                                            GLTestContext *shareContext) {
323     EGLGLTestContext* eglShareContext = reinterpret_cast<EGLGLTestContext*>(shareContext);
324     EGLGLTestContext *ctx = new EGLGLTestContext(forcedGpuAPI, eglShareContext);
325     if (!ctx->isValid()) {
326         delete ctx;
327         return nullptr;
328     }
329     return ctx;
330 }
331 }  // namespace sk_gpu_test
332