1 /*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "src/gpu/gl/GrGLDefines.h"
9 #include "src/gpu/gl/GrGLUtil.h"
10 #include "tools/gpu/gl/GLTestContext.h"
11
12 #define GL_GLEXT_PROTOTYPES
13 #include <EGL/egl.h>
14 #include <EGL/eglext.h>
15
16 namespace {
17
context_restorer()18 std::function<void()> context_restorer() {
19 auto display = eglGetCurrentDisplay();
20 auto dsurface = eglGetCurrentSurface(EGL_DRAW);
21 auto rsurface = eglGetCurrentSurface(EGL_READ);
22 auto context = eglGetCurrentContext();
23 return [display, dsurface, rsurface, context] {
24 eglMakeCurrent(display, dsurface, rsurface, context);
25 };
26 }
27
28 class EGLGLTestContext : public sk_gpu_test::GLTestContext {
29 public:
30 EGLGLTestContext(GrGLStandard forcedGpuAPI, EGLGLTestContext* shareContext);
31 ~EGLGLTestContext() override;
32
33 GrEGLImage texture2DToEGLImage(GrGLuint texID) const override;
34 void destroyEGLImage(GrEGLImage) const override;
35 GrGLuint eglImageToExternalTexture(GrEGLImage) const override;
36 std::unique_ptr<sk_gpu_test::GLTestContext> makeNew() const override;
37
38 private:
39 void destroyGLContext();
40
41 void onPlatformMakeNotCurrent() const override;
42 void onPlatformMakeCurrent() const override;
43 std::function<void()> onPlatformGetAutoContextRestore() const override;
44 GrGLFuncPtr onPlatformGetProcAddress(const char*) const override;
45
46 PFNEGLCREATEIMAGEKHRPROC fEglCreateImageProc = nullptr;
47 PFNEGLDESTROYIMAGEKHRPROC fEglDestroyImageProc = nullptr;
48
49 EGLContext fContext;
50 EGLDisplay fDisplay;
51 EGLSurface fSurface;
52 };
53
create_gles_egl_context(EGLDisplay display,EGLConfig surfaceConfig,EGLContext eglShareContext,EGLint eglContextClientVersion)54 static EGLContext create_gles_egl_context(EGLDisplay display,
55 EGLConfig surfaceConfig,
56 EGLContext eglShareContext,
57 EGLint eglContextClientVersion) {
58 const EGLint contextAttribsForOpenGLES[] = {
59 EGL_CONTEXT_CLIENT_VERSION,
60 eglContextClientVersion,
61 EGL_NONE
62 };
63 return eglCreateContext(display, surfaceConfig, eglShareContext, contextAttribsForOpenGLES);
64 }
create_gl_egl_context(EGLDisplay display,EGLConfig surfaceConfig,EGLContext eglShareContext)65 static EGLContext create_gl_egl_context(EGLDisplay display,
66 EGLConfig surfaceConfig,
67 EGLContext eglShareContext) {
68 const EGLint contextAttribsForOpenGL[] = {
69 EGL_NONE
70 };
71 return eglCreateContext(display, surfaceConfig, eglShareContext, contextAttribsForOpenGL);
72 }
73
EGLGLTestContext(GrGLStandard forcedGpuAPI,EGLGLTestContext * shareContext)74 EGLGLTestContext::EGLGLTestContext(GrGLStandard forcedGpuAPI, EGLGLTestContext* shareContext)
75 : fContext(EGL_NO_CONTEXT)
76 , fDisplay(EGL_NO_DISPLAY)
77 , fSurface(EGL_NO_SURFACE) {
78
79 EGLContext eglShareContext = shareContext ? shareContext->fContext : nullptr;
80
81 static const GrGLStandard kStandards[] = {
82 kGL_GrGLStandard,
83 kGLES_GrGLStandard,
84 };
85
86 size_t apiLimit = SK_ARRAY_COUNT(kStandards);
87 size_t api = 0;
88 if (forcedGpuAPI == kGL_GrGLStandard) {
89 apiLimit = 1;
90 } else if (forcedGpuAPI == kGLES_GrGLStandard) {
91 api = 1;
92 }
93 SkASSERT(forcedGpuAPI == kNone_GrGLStandard || kStandards[api] == forcedGpuAPI);
94
95 sk_sp<const GrGLInterface> gl;
96
97 for (; nullptr == gl.get() && api < apiLimit; ++api) {
98 fDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
99
100 EGLint majorVersion;
101 EGLint minorVersion;
102 eglInitialize(fDisplay, &majorVersion, &minorVersion);
103
104 #if 0
105 SkDebugf("VENDOR: %s\n", eglQueryString(fDisplay, EGL_VENDOR));
106 SkDebugf("APIS: %s\n", eglQueryString(fDisplay, EGL_CLIENT_APIS));
107 SkDebugf("VERSION: %s\n", eglQueryString(fDisplay, EGL_VERSION));
108 SkDebugf("EXTENSIONS %s\n", eglQueryString(fDisplay, EGL_EXTENSIONS));
109 #endif
110 bool gles = kGLES_GrGLStandard == kStandards[api];
111
112 if (!eglBindAPI(gles ? EGL_OPENGL_ES_API : EGL_OPENGL_API)) {
113 continue;
114 }
115
116 EGLint numConfigs = 0;
117 const EGLint configAttribs[] = {
118 EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
119 EGL_RENDERABLE_TYPE, gles ? EGL_OPENGL_ES2_BIT : EGL_OPENGL_BIT,
120 EGL_RED_SIZE, 8,
121 EGL_GREEN_SIZE, 8,
122 EGL_BLUE_SIZE, 8,
123 EGL_ALPHA_SIZE, 8,
124 EGL_NONE
125 };
126
127 EGLConfig surfaceConfig;
128 if (!eglChooseConfig(fDisplay, configAttribs, &surfaceConfig, 1, &numConfigs)) {
129 SkDebugf("eglChooseConfig failed. EGL Error: 0x%08x\n", eglGetError());
130 continue;
131 }
132
133 if (0 == numConfigs) {
134 SkDebugf("No suitable EGL config found.\n");
135 continue;
136 }
137
138 if (gles) {
139 #ifdef GR_EGL_TRY_GLES3_THEN_GLES2
140 // Some older devices (Nexus7/Tegra3) crash when you try this. So it is (for now)
141 // hidden behind this flag.
142 fContext = create_gles_egl_context(fDisplay, surfaceConfig, eglShareContext, 3);
143 if (EGL_NO_CONTEXT == fContext) {
144 fContext = create_gles_egl_context(fDisplay, surfaceConfig, eglShareContext, 2);
145 }
146 #else
147 fContext = create_gles_egl_context(fDisplay, surfaceConfig, eglShareContext, 2);
148 #endif
149 } else {
150 fContext = create_gl_egl_context(fDisplay, surfaceConfig, eglShareContext);
151 }
152 if (EGL_NO_CONTEXT == fContext) {
153 SkDebugf("eglCreateContext failed. EGL Error: 0x%08x\n", eglGetError());
154 continue;
155 }
156
157 static const EGLint kSurfaceAttribs[] = {
158 EGL_WIDTH, 1,
159 EGL_HEIGHT, 1,
160 EGL_NONE
161 };
162
163 fSurface = eglCreatePbufferSurface(fDisplay, surfaceConfig, kSurfaceAttribs);
164 if (EGL_NO_SURFACE == fSurface) {
165 SkDebugf("eglCreatePbufferSurface failed. EGL Error: 0x%08x\n", eglGetError());
166 this->destroyGLContext();
167 continue;
168 }
169
170 SkScopeExit restorer(context_restorer());
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 #ifdef SK_GL
178 gl = GrGLMakeNativeInterface();
179 if (!gl) {
180 SkDebugf("Failed to create gl interface.\n");
181 this->destroyGLContext();
182 continue;
183 }
184
185 if (!gl->validate()) {
186 SkDebugf("Failed to validate gl interface.\n");
187 this->destroyGLContext();
188 continue;
189 }
190 const char* extensions = eglQueryString(fDisplay, EGL_EXTENSIONS);
191 if (strstr(extensions, "EGL_KHR_image")) {
192 fEglCreateImageProc = (PFNEGLCREATEIMAGEKHRPROC)eglGetProcAddress("eglCreateImageKHR");
193 fEglDestroyImageProc =
194 (PFNEGLDESTROYIMAGEKHRPROC)eglGetProcAddress("eglDestroyImageKHR");
195 }
196
197 this->init(std::move(gl));
198 #else
199 // Allow the GLTestContext creation to succeed without a GrGLInterface to support
200 // GrContextFactory's persistent GL context workaround for Vulkan. We won't need the
201 // GrGLInterface since we're not running the GL backend.
202 this->init(nullptr);
203 #endif
204 break;
205 }
206 }
207
~EGLGLTestContext()208 EGLGLTestContext::~EGLGLTestContext() {
209 this->teardown();
210 this->destroyGLContext();
211 }
212
destroyGLContext()213 void EGLGLTestContext::destroyGLContext() {
214 if (fDisplay) {
215 if (fContext) {
216 if (eglGetCurrentContext() == fContext) {
217 // This will ensure that the context is immediately deleted.
218 eglMakeCurrent(fDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
219 }
220 eglDestroyContext(fDisplay, fContext);
221 fContext = EGL_NO_CONTEXT;
222 }
223
224 if (fSurface) {
225 eglDestroySurface(fDisplay, fSurface);
226 fSurface = EGL_NO_SURFACE;
227 }
228
229 //TODO should we close the display?
230 fDisplay = EGL_NO_DISPLAY;
231 }
232 }
233
texture2DToEGLImage(GrGLuint texID) const234 GrEGLImage EGLGLTestContext::texture2DToEGLImage(GrGLuint texID) const {
235 #ifdef SK_GL
236 if (!this->gl()->hasExtension("EGL_KHR_gl_texture_2D_image") || !fEglCreateImageProc) {
237 return GR_EGL_NO_IMAGE;
238 }
239 EGLint attribs[] = { GR_EGL_GL_TEXTURE_LEVEL, 0, GR_EGL_NONE };
240 GrEGLClientBuffer clientBuffer = reinterpret_cast<GrEGLClientBuffer>(texID);
241 return fEglCreateImageProc(fDisplay, fContext, GR_EGL_GL_TEXTURE_2D, clientBuffer, attribs);
242 #else
243 (void)fEglCreateImageProc;
244 return nullptr;
245 #endif
246 }
247
destroyEGLImage(GrEGLImage image) const248 void EGLGLTestContext::destroyEGLImage(GrEGLImage image) const {
249 fEglDestroyImageProc(fDisplay, image);
250 }
251
eglImageToExternalTexture(GrEGLImage image) const252 GrGLuint EGLGLTestContext::eglImageToExternalTexture(GrEGLImage image) const {
253 #ifdef SK_GL
254 while (this->gl()->fFunctions.fGetError() != GR_GL_NO_ERROR) {}
255 if (!this->gl()->hasExtension("GL_OES_EGL_image_external")) {
256 return 0;
257 }
258 typedef GrGLvoid (*EGLImageTargetTexture2DProc)(GrGLenum, GrGLeglImage);
259
260 EGLImageTargetTexture2DProc glEGLImageTargetTexture2D =
261 (EGLImageTargetTexture2DProc) eglGetProcAddress("glEGLImageTargetTexture2DOES");
262 if (!glEGLImageTargetTexture2D) {
263 return 0;
264 }
265 GrGLuint texID;
266 GR_GL_CALL(this->gl(), GenTextures(1, &texID));
267 if (!texID) {
268 return 0;
269 }
270 GR_GL_CALL_NOERRCHECK(this->gl(), BindTexture(GR_GL_TEXTURE_EXTERNAL, texID));
271 if (this->gl()->fFunctions.fGetError() != GR_GL_NO_ERROR) {
272 GR_GL_CALL(this->gl(), DeleteTextures(1, &texID));
273 return 0;
274 }
275 glEGLImageTargetTexture2D(GR_GL_TEXTURE_EXTERNAL, image);
276 if (this->gl()->fFunctions.fGetError() != GR_GL_NO_ERROR) {
277 GR_GL_CALL(this->gl(), DeleteTextures(1, &texID));
278 return 0;
279 }
280 return texID;
281 #else
282 return 0;
283 #endif
284 }
285
makeNew() const286 std::unique_ptr<sk_gpu_test::GLTestContext> EGLGLTestContext::makeNew() const {
287 std::unique_ptr<sk_gpu_test::GLTestContext> ctx(new EGLGLTestContext(this->gl()->fStandard,
288 nullptr));
289 if (ctx) {
290 ctx->makeCurrent();
291 }
292 return ctx;
293 }
294
onPlatformMakeNotCurrent() const295 void EGLGLTestContext::onPlatformMakeNotCurrent() const {
296 if (!eglMakeCurrent(fDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT )) {
297 SkDebugf("Could not reset the context.\n");
298 }
299 }
300
onPlatformMakeCurrent() const301 void EGLGLTestContext::onPlatformMakeCurrent() const {
302 if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
303 SkDebugf("Could not set the context.\n");
304 }
305 }
306
onPlatformGetAutoContextRestore() const307 std::function<void()> EGLGLTestContext::onPlatformGetAutoContextRestore() const {
308 if (eglGetCurrentContext() == fContext) {
309 return nullptr;
310 }
311 return context_restorer();
312 }
313
onPlatformGetProcAddress(const char * procName) const314 GrGLFuncPtr EGLGLTestContext::onPlatformGetProcAddress(const char* procName) const {
315 return eglGetProcAddress(procName);
316 }
317
318 } // anonymous namespace
319
320 namespace sk_gpu_test {
CreatePlatformGLTestContext(GrGLStandard forcedGpuAPI,GLTestContext * shareContext)321 GLTestContext *CreatePlatformGLTestContext(GrGLStandard forcedGpuAPI,
322 GLTestContext *shareContext) {
323 EGLGLTestContext* eglShareContext = reinterpret_cast<EGLGLTestContext*>(shareContext);
324 EGLGLTestContext *ctx = new EGLGLTestContext(forcedGpuAPI, eglShareContext);
325 if (!ctx->isValid()) {
326 delete ctx;
327 return nullptr;
328 }
329 return ctx;
330 }
331 } // namespace sk_gpu_test
332