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