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