• 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/SkGLContext.h"
9 
10 #include <GLES2/gl2.h>
11 
12 #define EGL_EGLEXT_PROTOTYPES
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 SkEGLFenceSync : public SkGpuFenceSync {
23 public:
24     static SkEGLFenceSync* CreateIfSupported(EGLDisplay);
25 
26     SkPlatformGpuFence SK_WARN_UNUSED_RESULT insertFence() const override;
27     bool waitFence(SkPlatformGpuFence fence, bool flush) const override;
28     void deleteFence(SkPlatformGpuFence fence) const override;
29 
30 private:
SkEGLFenceSync(EGLDisplay display)31     SkEGLFenceSync(EGLDisplay display) : fDisplay(display) {}
32 
33     EGLDisplay                    fDisplay;
34 
35     typedef SkGpuFenceSync INHERITED;
36 };
37 
38 class EGLGLContext : public SkGLContext  {
39 public:
40     EGLGLContext(GrGLStandard forcedGpuAPI);
41     ~EGLGLContext() override;
42 
43     GrEGLImage texture2DToEGLImage(GrGLuint texID) const override;
44     void destroyEGLImage(GrEGLImage) const override;
45     GrGLuint eglImageToExternalTexture(GrEGLImage) const override;
46     SkGLContext* createNew() const override;
47 
48 private:
49     void destroyGLContext();
50 
51     void onPlatformMakeCurrent() const override;
52     void onPlatformSwapBuffers() const override;
53     GrGLFuncPtr onPlatformGetProcAddress(const char*) const override;
54 
55     EGLContext fContext;
56     EGLDisplay fDisplay;
57     EGLSurface fSurface;
58 };
59 
EGLGLContext(GrGLStandard forcedGpuAPI)60 EGLGLContext::EGLGLContext(GrGLStandard forcedGpuAPI)
61     : fContext(EGL_NO_CONTEXT)
62     , fDisplay(EGL_NO_DISPLAY)
63     , fSurface(EGL_NO_SURFACE) {
64     static const EGLint kEGLContextAttribsForOpenGL[] = {
65         EGL_NONE
66     };
67 
68     static const EGLint kEGLContextAttribsForOpenGLES[] = {
69         EGL_CONTEXT_CLIENT_VERSION, 2,
70         EGL_NONE
71     };
72 
73     static const struct {
74         const EGLint* fContextAttribs;
75         EGLenum fAPI;
76         EGLint  fRenderableTypeBit;
77         GrGLStandard fStandard;
78     } kAPIs[] = {
79         {   // OpenGL
80             kEGLContextAttribsForOpenGL,
81             EGL_OPENGL_API,
82             EGL_OPENGL_BIT,
83             kGL_GrGLStandard
84         },
85         {   // OpenGL ES. This seems to work for both ES2 and 3 (when available).
86             kEGLContextAttribsForOpenGLES,
87             EGL_OPENGL_ES_API,
88             EGL_OPENGL_ES2_BIT,
89             kGLES_GrGLStandard
90         },
91     };
92 
93     size_t apiLimit = SK_ARRAY_COUNT(kAPIs);
94     size_t api = 0;
95     if (forcedGpuAPI == kGL_GrGLStandard) {
96         apiLimit = 1;
97     } else if (forcedGpuAPI == kGLES_GrGLStandard) {
98         api = 1;
99     }
100     SkASSERT(forcedGpuAPI == kNone_GrGLStandard || kAPIs[api].fStandard == forcedGpuAPI);
101 
102     SkAutoTUnref<const GrGLInterface> gl;
103 
104     for (; nullptr == gl.get() && api < apiLimit; ++api) {
105         fDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
106 
107         EGLint majorVersion;
108         EGLint minorVersion;
109         eglInitialize(fDisplay, &majorVersion, &minorVersion);
110 
111 #if 0
112         SkDebugf("VENDOR: %s\n", eglQueryString(fDisplay, EGL_VENDOR));
113         SkDebugf("APIS: %s\n", eglQueryString(fDisplay, EGL_CLIENT_APIS));
114         SkDebugf("VERSION: %s\n", eglQueryString(fDisplay, EGL_VERSION));
115         SkDebugf("EXTENSIONS %s\n", eglQueryString(fDisplay, EGL_EXTENSIONS));
116 #endif
117 
118         if (!eglBindAPI(kAPIs[api].fAPI)) {
119             continue;
120         }
121 
122         EGLint numConfigs = 0;
123         const EGLint configAttribs[] = {
124             EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
125             EGL_RENDERABLE_TYPE, kAPIs[api].fRenderableTypeBit,
126             EGL_RED_SIZE, 8,
127             EGL_GREEN_SIZE, 8,
128             EGL_BLUE_SIZE, 8,
129             EGL_ALPHA_SIZE, 8,
130             EGL_NONE
131         };
132 
133         EGLConfig surfaceConfig;
134         if (!eglChooseConfig(fDisplay, configAttribs, &surfaceConfig, 1, &numConfigs)) {
135             SkDebugf("eglChooseConfig failed. EGL Error: 0x%08x\n", eglGetError());
136             continue;
137         }
138 
139         if (0 == numConfigs) {
140             SkDebugf("No suitable EGL config found.\n");
141             continue;
142         }
143 
144         fContext = eglCreateContext(fDisplay, surfaceConfig, nullptr, kAPIs[api].fContextAttribs);
145         if (EGL_NO_CONTEXT == fContext) {
146             SkDebugf("eglCreateContext failed.  EGL Error: 0x%08x\n", eglGetError());
147             continue;
148         }
149 
150         static const EGLint kSurfaceAttribs[] = {
151             EGL_WIDTH, 1,
152             EGL_HEIGHT, 1,
153             EGL_NONE
154         };
155 
156         fSurface = eglCreatePbufferSurface(fDisplay, surfaceConfig, kSurfaceAttribs);
157         if (EGL_NO_SURFACE == fSurface) {
158             SkDebugf("eglCreatePbufferSurface failed. EGL Error: 0x%08x\n", eglGetError());
159             this->destroyGLContext();
160             continue;
161         }
162 
163         if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
164             SkDebugf("eglMakeCurrent failed.  EGL Error: 0x%08x\n", eglGetError());
165             this->destroyGLContext();
166             continue;
167         }
168 
169         gl.reset(GrGLCreateNativeInterface());
170         if (nullptr == gl.get()) {
171             SkDebugf("Failed to create gl interface.\n");
172             this->destroyGLContext();
173             continue;
174         }
175 
176         if (!gl->validate()) {
177             SkDebugf("Failed to validate gl interface.\n");
178             this->destroyGLContext();
179             continue;
180         }
181 
182         this->init(gl.detach(), SkEGLFenceSync::CreateIfSupported(fDisplay));
183         break;
184     }
185 }
186 
~EGLGLContext()187 EGLGLContext::~EGLGLContext() {
188     this->teardown();
189     this->destroyGLContext();
190 }
191 
destroyGLContext()192 void EGLGLContext::destroyGLContext() {
193     if (fDisplay) {
194         eglMakeCurrent(fDisplay, 0, 0, 0);
195 
196         if (fContext) {
197             eglDestroyContext(fDisplay, fContext);
198             fContext = EGL_NO_CONTEXT;
199         }
200 
201         if (fSurface) {
202             eglDestroySurface(fDisplay, fSurface);
203             fSurface = EGL_NO_SURFACE;
204         }
205 
206         //TODO should we close the display?
207         fDisplay = EGL_NO_DISPLAY;
208     }
209 }
210 
texture2DToEGLImage(GrGLuint texID) const211 GrEGLImage EGLGLContext::texture2DToEGLImage(GrGLuint texID) const {
212     if (!this->gl()->hasExtension("EGL_KHR_gl_texture_2D_image")) {
213         return GR_EGL_NO_IMAGE;
214     }
215     GrEGLImage img;
216     GrEGLint attribs[] = { GR_EGL_GL_TEXTURE_LEVEL, 0, GR_EGL_NONE };
217     GrEGLClientBuffer clientBuffer = reinterpret_cast<GrEGLClientBuffer>(texID);
218     GR_GL_CALL_RET(this->gl(), img,
219                    EGLCreateImage(fDisplay, fContext, GR_EGL_GL_TEXTURE_2D, clientBuffer, attribs));
220     return img;
221 }
222 
destroyEGLImage(GrEGLImage image) const223 void EGLGLContext::destroyEGLImage(GrEGLImage image) const {
224     GR_GL_CALL(this->gl(), EGLDestroyImage(fDisplay, image));
225 }
226 
eglImageToExternalTexture(GrEGLImage image) const227 GrGLuint EGLGLContext::eglImageToExternalTexture(GrEGLImage image) const {
228     GrGLClearErr(this->gl());
229     if (!this->gl()->hasExtension("GL_OES_EGL_image_external")) {
230         return 0;
231     }
232     GrGLEGLImageTargetTexture2DProc glEGLImageTargetTexture2D =
233             (GrGLEGLImageTargetTexture2DProc) eglGetProcAddress("glEGLImageTargetTexture2DOES");
234     if (!glEGLImageTargetTexture2D) {
235         return 0;
236     }
237     GrGLuint texID;
238     glGenTextures(1, &texID);
239     if (!texID) {
240         return 0;
241     }
242     glBindTexture(GR_GL_TEXTURE_EXTERNAL, texID);
243     if (glGetError() != GR_GL_NO_ERROR) {
244         glDeleteTextures(1, &texID);
245         return 0;
246     }
247     glEGLImageTargetTexture2D(GR_GL_TEXTURE_EXTERNAL, image);
248     if (glGetError() != GR_GL_NO_ERROR) {
249         glDeleteTextures(1, &texID);
250         return 0;
251     }
252     return texID;
253 }
254 
createNew() const255 SkGLContext* EGLGLContext::createNew() const {
256     SkGLContext* ctx = SkCreatePlatformGLContext(this->gl()->fStandard);
257     if (ctx) {
258         ctx->makeCurrent();
259     }
260     return ctx;
261 }
262 
onPlatformMakeCurrent() const263 void EGLGLContext::onPlatformMakeCurrent() const {
264     if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
265         SkDebugf("Could not set the context.\n");
266     }
267 }
268 
onPlatformSwapBuffers() const269 void EGLGLContext::onPlatformSwapBuffers() const {
270     if (!eglSwapBuffers(fDisplay, fSurface)) {
271         SkDebugf("Could not complete eglSwapBuffers.\n");
272     }
273 }
274 
onPlatformGetProcAddress(const char * procName) const275 GrGLFuncPtr EGLGLContext::onPlatformGetProcAddress(const char* procName) const {
276     return eglGetProcAddress(procName);
277 }
278 
supports_egl_extension(EGLDisplay display,const char * extension)279 static bool supports_egl_extension(EGLDisplay display, const char* extension) {
280     size_t extensionLength = strlen(extension);
281     const char* extensionsStr = eglQueryString(display, EGL_EXTENSIONS);
282     while (const char* match = strstr(extensionsStr, extension)) {
283         // Ensure the string we found is its own extension, not a substring of a larger extension
284         // (e.g. GL_ARB_occlusion_query / GL_ARB_occlusion_query2).
285         if ((match == extensionsStr || match[-1] == ' ') &&
286             (match[extensionLength] == ' ' || match[extensionLength] == '\0')) {
287             return true;
288         }
289         extensionsStr = match + extensionLength;
290     }
291     return false;
292 }
293 
CreateIfSupported(EGLDisplay display)294 SkEGLFenceSync* SkEGLFenceSync::CreateIfSupported(EGLDisplay display) {
295     if (!display || !supports_egl_extension(display, "EGL_KHR_fence_sync")) {
296         return nullptr;
297     }
298     return new SkEGLFenceSync(display);
299 }
300 
insertFence() const301 SkPlatformGpuFence SkEGLFenceSync::insertFence() const {
302     return eglCreateSyncKHR(fDisplay, EGL_SYNC_FENCE_KHR, nullptr);
303 }
304 
waitFence(SkPlatformGpuFence platformFence,bool flush) const305 bool SkEGLFenceSync::waitFence(SkPlatformGpuFence platformFence, bool flush) const {
306     EGLSyncKHR eglsync = static_cast<EGLSyncKHR>(platformFence);
307     return EGL_CONDITION_SATISFIED_KHR ==
308             eglClientWaitSyncKHR(fDisplay,
309                                  eglsync,
310                                  flush ? EGL_SYNC_FLUSH_COMMANDS_BIT_KHR : 0,
311                                  EGL_FOREVER_KHR);
312 }
313 
deleteFence(SkPlatformGpuFence platformFence) const314 void SkEGLFenceSync::deleteFence(SkPlatformGpuFence platformFence) const {
315     EGLSyncKHR eglsync = static_cast<EGLSyncKHR>(platformFence);
316     eglDestroySyncKHR(fDisplay, eglsync);
317 }
318 
319 } // anonymous namespace
320 
SkCreatePlatformGLContext(GrGLStandard forcedGpuAPI,SkGLContext * shareContext)321 SkGLContext* SkCreatePlatformGLContext(GrGLStandard forcedGpuAPI, SkGLContext* shareContext) {
322     SkASSERT(!shareContext);
323     if (shareContext) {
324         return nullptr;
325     }
326     EGLGLContext* ctx = new EGLGLContext(forcedGpuAPI);
327     if (!ctx->isValid()) {
328         delete ctx;
329         return nullptr;
330     }
331     return ctx;
332 }
333 
334