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