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
create_gles_egl_context(EGLDisplay display,EGLConfig surfaceConfig,EGLContext eglShareContext,EGLint eglContextClientVersion)75 static EGLContext create_gles_egl_context(EGLDisplay display,
76 EGLConfig surfaceConfig,
77 EGLContext eglShareContext,
78 EGLint eglContextClientVersion) {
79 const EGLint contextAttribsForOpenGLES[] = {
80 EGL_CONTEXT_CLIENT_VERSION,
81 eglContextClientVersion,
82 EGL_NONE
83 };
84 return eglCreateContext(display, surfaceConfig, eglShareContext, contextAttribsForOpenGLES);
85 }
create_gl_egl_context(EGLDisplay display,EGLConfig surfaceConfig,EGLContext eglShareContext)86 static EGLContext create_gl_egl_context(EGLDisplay display,
87 EGLConfig surfaceConfig,
88 EGLContext eglShareContext) {
89 const EGLint contextAttribsForOpenGL[] = {
90 EGL_NONE
91 };
92 return eglCreateContext(display, surfaceConfig, eglShareContext, contextAttribsForOpenGL);
93 }
94
EGLGLTestContext(GrGLStandard forcedGpuAPI,EGLGLTestContext * shareContext)95 EGLGLTestContext::EGLGLTestContext(GrGLStandard forcedGpuAPI, EGLGLTestContext* shareContext)
96 : fContext(EGL_NO_CONTEXT)
97 , fDisplay(EGL_NO_DISPLAY)
98 , fSurface(EGL_NO_SURFACE) {
99
100 EGLContext eglShareContext = shareContext ? shareContext->fContext : nullptr;
101
102 static const GrGLStandard kStandards[] = {
103 kGL_GrGLStandard,
104 kGLES_GrGLStandard,
105 };
106
107 size_t apiLimit = SK_ARRAY_COUNT(kStandards);
108 size_t api = 0;
109 if (forcedGpuAPI == kGL_GrGLStandard) {
110 apiLimit = 1;
111 } else if (forcedGpuAPI == kGLES_GrGLStandard) {
112 api = 1;
113 }
114 SkASSERT(forcedGpuAPI == kNone_GrGLStandard || kStandards[api] == forcedGpuAPI);
115
116 sk_sp<const GrGLInterface> gl;
117
118 for (; nullptr == gl.get() && api < apiLimit; ++api) {
119 fDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
120
121 EGLint majorVersion;
122 EGLint minorVersion;
123 eglInitialize(fDisplay, &majorVersion, &minorVersion);
124
125 #if 0
126 SkDebugf("VENDOR: %s\n", eglQueryString(fDisplay, EGL_VENDOR));
127 SkDebugf("APIS: %s\n", eglQueryString(fDisplay, EGL_CLIENT_APIS));
128 SkDebugf("VERSION: %s\n", eglQueryString(fDisplay, EGL_VERSION));
129 SkDebugf("EXTENSIONS %s\n", eglQueryString(fDisplay, EGL_EXTENSIONS));
130 #endif
131 bool gles = kGLES_GrGLStandard == kStandards[api];
132
133 if (!eglBindAPI(gles ? EGL_OPENGL_ES_API : EGL_OPENGL_API)) {
134 continue;
135 }
136
137 EGLint numConfigs = 0;
138 const EGLint configAttribs[] = {
139 EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
140 EGL_RENDERABLE_TYPE, gles ? EGL_OPENGL_ES2_BIT : EGL_OPENGL_BIT,
141 EGL_RED_SIZE, 8,
142 EGL_GREEN_SIZE, 8,
143 EGL_BLUE_SIZE, 8,
144 EGL_ALPHA_SIZE, 8,
145 EGL_NONE
146 };
147
148 EGLConfig surfaceConfig;
149 if (!eglChooseConfig(fDisplay, configAttribs, &surfaceConfig, 1, &numConfigs)) {
150 SkDebugf("eglChooseConfig failed. EGL Error: 0x%08x\n", eglGetError());
151 continue;
152 }
153
154 if (0 == numConfigs) {
155 SkDebugf("No suitable EGL config found.\n");
156 continue;
157 }
158
159 if (gles) {
160 #ifdef GR_EGL_TRY_GLES3_THEN_GLES2
161 // Some older devices (Nexus7/Tegra3) crash when you try this. So it is (for now)
162 // hidden behind this flag.
163 fContext = create_gles_egl_context(fDisplay, surfaceConfig, eglShareContext, 3);
164 if (EGL_NO_CONTEXT == fContext) {
165 fContext = create_gles_egl_context(fDisplay, surfaceConfig, eglShareContext, 2);
166 }
167 #else
168 fContext = create_gles_egl_context(fDisplay, surfaceConfig, eglShareContext, 2);
169 #endif
170 } else {
171 fContext = create_gl_egl_context(fDisplay, surfaceConfig, eglShareContext);
172 }
173 if (EGL_NO_CONTEXT == fContext) {
174 SkDebugf("eglCreateContext failed. EGL Error: 0x%08x\n", eglGetError());
175 continue;
176 }
177
178 static const EGLint kSurfaceAttribs[] = {
179 EGL_WIDTH, 1,
180 EGL_HEIGHT, 1,
181 EGL_NONE
182 };
183
184 fSurface = eglCreatePbufferSurface(fDisplay, surfaceConfig, kSurfaceAttribs);
185 if (EGL_NO_SURFACE == fSurface) {
186 SkDebugf("eglCreatePbufferSurface failed. EGL Error: 0x%08x\n", eglGetError());
187 this->destroyGLContext();
188 continue;
189 }
190
191 SkScopeExit restorer(context_restorer());
192 if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
193 SkDebugf("eglMakeCurrent failed. EGL Error: 0x%08x\n", eglGetError());
194 this->destroyGLContext();
195 continue;
196 }
197
198 gl = GrGLMakeNativeInterface();
199 if (!gl) {
200 SkDebugf("Failed to create gl interface.\n");
201 this->destroyGLContext();
202 continue;
203 }
204
205 if (!gl->validate()) {
206 SkDebugf("Failed to validate gl interface.\n");
207 this->destroyGLContext();
208 continue;
209 }
210
211 this->init(std::move(gl), EGLFenceSync::MakeIfSupported(fDisplay));
212 break;
213 }
214 }
215
~EGLGLTestContext()216 EGLGLTestContext::~EGLGLTestContext() {
217 this->teardown();
218 this->destroyGLContext();
219 }
220
destroyGLContext()221 void EGLGLTestContext::destroyGLContext() {
222 if (fDisplay) {
223 if (fContext) {
224 if (eglGetCurrentContext() == fContext) {
225 // This will ensure that the context is immediately deleted.
226 eglMakeCurrent(fDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
227 }
228 eglDestroyContext(fDisplay, fContext);
229 fContext = EGL_NO_CONTEXT;
230 }
231
232 if (fSurface) {
233 eglDestroySurface(fDisplay, fSurface);
234 fSurface = EGL_NO_SURFACE;
235 }
236
237 //TODO should we close the display?
238 fDisplay = EGL_NO_DISPLAY;
239 }
240 }
241
texture2DToEGLImage(GrGLuint texID) const242 GrEGLImage EGLGLTestContext::texture2DToEGLImage(GrGLuint texID) const {
243 if (!this->gl()->hasExtension("EGL_KHR_gl_texture_2D_image")) {
244 return GR_EGL_NO_IMAGE;
245 }
246 GrEGLImage img;
247 GrEGLint attribs[] = { GR_EGL_GL_TEXTURE_LEVEL, 0, GR_EGL_NONE };
248 GrEGLClientBuffer clientBuffer = reinterpret_cast<GrEGLClientBuffer>(texID);
249 GR_GL_CALL_RET(this->gl(), img,
250 EGLCreateImage(fDisplay, fContext, GR_EGL_GL_TEXTURE_2D, clientBuffer, attribs));
251 return img;
252 }
253
destroyEGLImage(GrEGLImage image) const254 void EGLGLTestContext::destroyEGLImage(GrEGLImage image) const {
255 GR_GL_CALL(this->gl(), EGLDestroyImage(fDisplay, image));
256 }
257
eglImageToExternalTexture(GrEGLImage image) const258 GrGLuint EGLGLTestContext::eglImageToExternalTexture(GrEGLImage image) const {
259 GrGLClearErr(this->gl());
260 if (!this->gl()->hasExtension("GL_OES_EGL_image_external")) {
261 return 0;
262 }
263 typedef GrGLvoid (*EGLImageTargetTexture2DProc)(GrGLenum, GrGLeglImage);
264
265 EGLImageTargetTexture2DProc glEGLImageTargetTexture2D =
266 (EGLImageTargetTexture2DProc) eglGetProcAddress("glEGLImageTargetTexture2DOES");
267 if (!glEGLImageTargetTexture2D) {
268 return 0;
269 }
270 GrGLuint texID;
271 GR_GL_CALL(this->gl(), GenTextures(1, &texID));
272 if (!texID) {
273 return 0;
274 }
275 GR_GL_CALL_NOERRCHECK(this->gl(), BindTexture(GR_GL_TEXTURE_EXTERNAL, texID));
276 if (GR_GL_GET_ERROR(this->gl()) != GR_GL_NO_ERROR) {
277 GR_GL_CALL(this->gl(), DeleteTextures(1, &texID));
278 return 0;
279 }
280 glEGLImageTargetTexture2D(GR_GL_TEXTURE_EXTERNAL, image);
281 if (GR_GL_GET_ERROR(this->gl()) != GR_GL_NO_ERROR) {
282 GR_GL_CALL(this->gl(), DeleteTextures(1, &texID));
283 return 0;
284 }
285 return texID;
286 }
287
makeNew() const288 std::unique_ptr<sk_gpu_test::GLTestContext> EGLGLTestContext::makeNew() const {
289 std::unique_ptr<sk_gpu_test::GLTestContext> ctx(new EGLGLTestContext(this->gl()->fStandard,
290 nullptr));
291 if (ctx) {
292 ctx->makeCurrent();
293 }
294 return ctx;
295 }
296
onPlatformMakeCurrent() const297 void EGLGLTestContext::onPlatformMakeCurrent() const {
298 if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
299 SkDebugf("Could not set the context.\n");
300 }
301 }
302
onPlatformGetAutoContextRestore() const303 std::function<void()> EGLGLTestContext::onPlatformGetAutoContextRestore() const {
304 if (eglGetCurrentContext() == fContext) {
305 return nullptr;
306 }
307 return context_restorer();
308 }
309
onPlatformSwapBuffers() const310 void EGLGLTestContext::onPlatformSwapBuffers() const {
311 if (!eglSwapBuffers(fDisplay, fSurface)) {
312 SkDebugf("Could not complete eglSwapBuffers.\n");
313 }
314 }
315
onPlatformGetProcAddress(const char * procName) const316 GrGLFuncPtr EGLGLTestContext::onPlatformGetProcAddress(const char* procName) const {
317 return eglGetProcAddress(procName);
318 }
319
supports_egl_extension(EGLDisplay display,const char * extension)320 static bool supports_egl_extension(EGLDisplay display, const char* extension) {
321 size_t extensionLength = strlen(extension);
322 const char* extensionsStr = eglQueryString(display, EGL_EXTENSIONS);
323 while (const char* match = strstr(extensionsStr, extension)) {
324 // Ensure the string we found is its own extension, not a substring of a larger extension
325 // (e.g. GL_ARB_occlusion_query / GL_ARB_occlusion_query2).
326 if ((match == extensionsStr || match[-1] == ' ') &&
327 (match[extensionLength] == ' ' || match[extensionLength] == '\0')) {
328 return true;
329 }
330 extensionsStr = match + extensionLength;
331 }
332 return false;
333 }
334
MakeIfSupported(EGLDisplay display)335 std::unique_ptr<EGLFenceSync> EGLFenceSync::MakeIfSupported(EGLDisplay display) {
336 if (!display || !supports_egl_extension(display, "EGL_KHR_fence_sync")) {
337 return nullptr;
338 }
339 return std::unique_ptr<EGLFenceSync>(new EGLFenceSync(display));
340 }
341
EGLFenceSync(EGLDisplay display)342 EGLFenceSync::EGLFenceSync(EGLDisplay display)
343 : fDisplay(display) {
344 fEGLCreateSyncKHR = (PFNEGLCREATESYNCKHRPROC) eglGetProcAddress("eglCreateSyncKHR");
345 fEGLClientWaitSyncKHR = (PFNEGLCLIENTWAITSYNCKHRPROC) eglGetProcAddress("eglClientWaitSyncKHR");
346 fEGLDestroySyncKHR = (PFNEGLDESTROYSYNCKHRPROC) eglGetProcAddress("eglDestroySyncKHR");
347 SkASSERT(fEGLCreateSyncKHR && fEGLClientWaitSyncKHR && fEGLDestroySyncKHR);
348 }
349
insertFence() const350 sk_gpu_test::PlatformFence EGLFenceSync::insertFence() const {
351 EGLSyncKHR eglsync = fEGLCreateSyncKHR(fDisplay, EGL_SYNC_FENCE_KHR, nullptr);
352 return reinterpret_cast<sk_gpu_test::PlatformFence>(eglsync);
353 }
354
waitFence(sk_gpu_test::PlatformFence platformFence) const355 bool EGLFenceSync::waitFence(sk_gpu_test::PlatformFence platformFence) const {
356 EGLSyncKHR eglsync = reinterpret_cast<EGLSyncKHR>(platformFence);
357 return EGL_CONDITION_SATISFIED_KHR ==
358 fEGLClientWaitSyncKHR(fDisplay,
359 eglsync,
360 EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
361 EGL_FOREVER_KHR);
362 }
363
deleteFence(sk_gpu_test::PlatformFence platformFence) const364 void EGLFenceSync::deleteFence(sk_gpu_test::PlatformFence platformFence) const {
365 EGLSyncKHR eglsync = reinterpret_cast<EGLSyncKHR>(platformFence);
366 fEGLDestroySyncKHR(fDisplay, eglsync);
367 }
368
369 GR_STATIC_ASSERT(sizeof(EGLSyncKHR) <= sizeof(sk_gpu_test::PlatformFence));
370
371 } // anonymous namespace
372
373 namespace sk_gpu_test {
CreatePlatformGLTestContext(GrGLStandard forcedGpuAPI,GLTestContext * shareContext)374 GLTestContext *CreatePlatformGLTestContext(GrGLStandard forcedGpuAPI,
375 GLTestContext *shareContext) {
376 EGLGLTestContext* eglShareContext = reinterpret_cast<EGLGLTestContext*>(shareContext);
377 EGLGLTestContext *ctx = new EGLGLTestContext(forcedGpuAPI, eglShareContext);
378 if (!ctx->isValid()) {
379 delete ctx;
380 return nullptr;
381 }
382 return ctx;
383 }
384 } // namespace sk_gpu_test
385