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