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