• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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