• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2016 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 // DisplayAndroid.cpp: Android implementation of egl::Display
8 
9 #include "libANGLE/renderer/gl/egl/android/DisplayAndroid.h"
10 
11 #include <android/log.h>
12 #include <android/native_window.h>
13 
14 #include "common/debug.h"
15 #include "libANGLE/Context.h"
16 #include "libANGLE/Display.h"
17 #include "libANGLE/Surface.h"
18 #include "libANGLE/renderer/gl/ContextGL.h"
19 #include "libANGLE/renderer/gl/RendererGL.h"
20 #include "libANGLE/renderer/gl/egl/ContextEGL.h"
21 #include "libANGLE/renderer/gl/egl/FunctionsEGLDL.h"
22 #include "libANGLE/renderer/gl/egl/RendererEGL.h"
23 #include "libANGLE/renderer/gl/egl/SurfaceEGL.h"
24 #include "libANGLE/renderer/gl/egl/android/NativeBufferImageSiblingAndroid.h"
25 #include "libANGLE/renderer/gl/renderergl_utils.h"
26 
27 namespace
28 {
GetEGLPath()29 const char *GetEGLPath()
30 {
31 #if defined(__LP64__)
32     return "/system/lib64/libEGL.so";
33 #else
34     return "/system/lib/libEGL.so";
35 #endif
36 }
37 }  // namespace
38 
39 namespace rx
40 {
41 
42 static constexpr bool kDefaultEGLVirtualizedContexts = true;
43 
DisplayAndroid(const egl::DisplayState & state)44 DisplayAndroid::DisplayAndroid(const egl::DisplayState &state)
45     : DisplayEGL(state),
46       mVirtualizedContexts(kDefaultEGLVirtualizedContexts),
47       mSupportsSurfaceless(false),
48       mDummyPbuffer(EGL_NO_SURFACE)
49 {}
50 
~DisplayAndroid()51 DisplayAndroid::~DisplayAndroid() {}
52 
initialize(egl::Display * display)53 egl::Error DisplayAndroid::initialize(egl::Display *display)
54 {
55     mDisplayAttributes = display->getAttributeMap();
56     mVirtualizedContexts =
57         ShouldUseVirtualizedContexts(mDisplayAttributes, kDefaultEGLVirtualizedContexts);
58 
59     FunctionsEGLDL *egl = new FunctionsEGLDL();
60     mEGL                = egl;
61     void *eglHandle =
62         reinterpret_cast<void *>(mDisplayAttributes.get(EGL_PLATFORM_ANGLE_EGL_HANDLE_ANGLE, 0));
63     ANGLE_TRY(egl->initialize(display->getNativeDisplayId(), GetEGLPath(), eglHandle));
64 
65     gl::Version eglVersion(mEGL->majorVersion, mEGL->minorVersion);
66     ASSERT(eglVersion >= gl::Version(1, 4));
67 
68     static_assert(EGL_OPENGL_ES3_BIT == EGL_OPENGL_ES3_BIT_KHR, "Extension define must match core");
69     EGLint esBit = (eglVersion >= gl::Version(1, 5) || mEGL->hasExtension("EGL_KHR_create_context"))
70                        ? EGL_OPENGL_ES3_BIT
71                        : EGL_OPENGL_ES2_BIT;
72 
73     // clang-format off
74     std::vector<EGLint> configAttribListBase =
75     {
76         EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER,
77         // Android doesn't support pixmaps
78         EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
79         EGL_CONFIG_CAVEAT, EGL_NONE,
80         EGL_CONFORMANT, esBit,
81         EGL_RENDERABLE_TYPE, esBit,
82     };
83     // clang-format on
84 
85     if (mEGL->hasExtension("EGL_EXT_pixel_format_float"))
86     {
87         // Don't request floating point configs
88         configAttribListBase.push_back(EGL_COLOR_COMPONENT_TYPE_EXT);
89         configAttribListBase.push_back(EGL_COLOR_COMPONENT_TYPE_FIXED_EXT);
90     }
91 
92     std::vector<EGLint> configAttribListWithFormat = configAttribListBase;
93     // EGL1.5 spec Section 2.2 says that depth, multisample and stencil buffer depths
94     // must match for contexts to be compatible.
95     // Choose RGBA8888
96     configAttribListWithFormat.push_back(EGL_RED_SIZE);
97     configAttribListWithFormat.push_back(8);
98     configAttribListWithFormat.push_back(EGL_GREEN_SIZE);
99     configAttribListWithFormat.push_back(8);
100     configAttribListWithFormat.push_back(EGL_BLUE_SIZE);
101     configAttribListWithFormat.push_back(8);
102     configAttribListWithFormat.push_back(EGL_ALPHA_SIZE);
103     configAttribListWithFormat.push_back(8);
104     // Choose DEPTH24_STENCIL8
105     configAttribListWithFormat.push_back(EGL_DEPTH_SIZE);
106     configAttribListWithFormat.push_back(24);
107     configAttribListWithFormat.push_back(EGL_STENCIL_SIZE);
108     configAttribListWithFormat.push_back(8);
109     // Choose no multisampling
110     configAttribListWithFormat.push_back(EGL_SAMPLE_BUFFERS);
111     configAttribListWithFormat.push_back(0);
112 
113     // Complete the attrib lists
114     configAttribListBase.push_back(EGL_NONE);
115     configAttribListWithFormat.push_back(EGL_NONE);
116 
117     EGLint numConfig;
118     EGLConfig configWithFormat;
119 
120     EGLBoolean success =
121         mEGL->chooseConfig(configAttribListWithFormat.data(), &configWithFormat, 1, &numConfig);
122     if (success == EGL_FALSE)
123     {
124         return egl::EglNotInitialized()
125                << "eglChooseConfig failed with " << egl::Error(mEGL->getError());
126     }
127 
128     // A dummy pbuffer is only needed if surfaceless contexts are not supported.
129     mSupportsSurfaceless = mEGL->hasExtension("EGL_KHR_surfaceless_context");
130     if (!mSupportsSurfaceless)
131     {
132         int dummyPbufferAttribs[] = {
133             EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE,
134         };
135         mDummyPbuffer = mEGL->createPbufferSurface(configWithFormat, dummyPbufferAttribs);
136         if (mDummyPbuffer == EGL_NO_SURFACE)
137         {
138             return egl::EglNotInitialized()
139                    << "eglCreatePbufferSurface failed with " << egl::Error(mEGL->getError());
140         }
141     }
142 
143     // Create mDummyPbuffer with a normal config, but create a no_config mContext, if possible
144     if (mEGL->hasExtension("EGL_KHR_no_config_context"))
145     {
146         mConfigAttribList = configAttribListBase;
147         mConfig           = EGL_NO_CONFIG_KHR;
148     }
149     else
150     {
151         mConfigAttribList = configAttribListWithFormat;
152         mConfig           = configWithFormat;
153     }
154 
155     ANGLE_TRY(createRenderer(EGL_NO_CONTEXT, true, &mRenderer));
156 
157     const gl::Version &maxVersion = mRenderer->getMaxSupportedESVersion();
158     if (maxVersion < gl::Version(2, 0))
159     {
160         return egl::EglNotInitialized() << "OpenGL ES 2.0 is not supportable.";
161     }
162 
163     ANGLE_TRY(DisplayGL::initialize(display));
164 
165     std::string rendererDescription = mRenderer->getRendererDescription();
166     __android_log_print(ANDROID_LOG_INFO, "ANGLE", "%s", rendererDescription.c_str());
167     return egl::NoError();
168 }
169 
terminate()170 void DisplayAndroid::terminate()
171 {
172     DisplayGL::terminate();
173 
174     EGLBoolean success = mEGL->makeCurrent(EGL_NO_SURFACE, EGL_NO_CONTEXT);
175     if (success == EGL_FALSE)
176     {
177         ERR() << "eglMakeCurrent error " << egl::Error(mEGL->getError());
178     }
179 
180     if (mDummyPbuffer != EGL_NO_SURFACE)
181     {
182         success       = mEGL->destroySurface(mDummyPbuffer);
183         mDummyPbuffer = EGL_NO_SURFACE;
184         if (success == EGL_FALSE)
185         {
186             ERR() << "eglDestroySurface error " << egl::Error(mEGL->getError());
187         }
188     }
189 
190     mRenderer.reset();
191     mCurrentNativeContext.clear();
192 
193     egl::Error result = mEGL->terminate();
194     if (result.isError())
195     {
196         ERR() << "eglTerminate error " << result;
197     }
198 
199     SafeDelete(mEGL);
200 }
201 
createContext(const gl::State & state,gl::ErrorSet * errorSet,const egl::Config * configuration,const gl::Context * shareContext,const egl::AttributeMap & attribs)202 ContextImpl *DisplayAndroid::createContext(const gl::State &state,
203                                            gl::ErrorSet *errorSet,
204                                            const egl::Config *configuration,
205                                            const gl::Context *shareContext,
206                                            const egl::AttributeMap &attribs)
207 {
208     std::shared_ptr<RendererEGL> renderer;
209     if (mVirtualizedContexts)
210     {
211         renderer = mRenderer;
212     }
213     else
214     {
215         EGLContext nativeShareContext = EGL_NO_CONTEXT;
216         if (shareContext)
217         {
218             ContextEGL *shareContextEGL = GetImplAs<ContextEGL>(shareContext);
219             nativeShareContext          = shareContextEGL->getContext();
220         }
221 
222         // Create a new renderer for this context.  It only needs to share with the user's requested
223         // share context because there are no internal resources in DisplayAndroid that are shared
224         // at the GL level.
225         egl::Error error = createRenderer(nativeShareContext, false, &renderer);
226         if (error.isError())
227         {
228             ERR() << "Failed to create a shared renderer: " << error.getMessage();
229             return nullptr;
230         }
231     }
232 
233     return new ContextEGL(state, errorSet, renderer);
234 }
235 
isValidNativeWindow(EGLNativeWindowType window) const236 bool DisplayAndroid::isValidNativeWindow(EGLNativeWindowType window) const
237 {
238     return ANativeWindow_getFormat(window) >= 0;
239 }
240 
validateImageClientBuffer(const gl::Context * context,EGLenum target,EGLClientBuffer clientBuffer,const egl::AttributeMap & attribs) const241 egl::Error DisplayAndroid::validateImageClientBuffer(const gl::Context *context,
242                                                      EGLenum target,
243                                                      EGLClientBuffer clientBuffer,
244                                                      const egl::AttributeMap &attribs) const
245 {
246     switch (target)
247     {
248         case EGL_NATIVE_BUFFER_ANDROID:
249             return egl::NoError();
250 
251         default:
252             return DisplayEGL::validateImageClientBuffer(context, target, clientBuffer, attribs);
253     }
254 }
255 
createExternalImageSibling(const gl::Context * context,EGLenum target,EGLClientBuffer buffer,const egl::AttributeMap & attribs)256 ExternalImageSiblingImpl *DisplayAndroid::createExternalImageSibling(
257     const gl::Context *context,
258     EGLenum target,
259     EGLClientBuffer buffer,
260     const egl::AttributeMap &attribs)
261 {
262     switch (target)
263     {
264         case EGL_NATIVE_BUFFER_ANDROID:
265             return new NativeBufferImageSiblingAndroid(buffer);
266 
267         default:
268             return DisplayEGL::createExternalImageSibling(context, target, buffer, attribs);
269     }
270 }
271 
makeCurrent(egl::Surface * drawSurface,egl::Surface * readSurface,gl::Context * context)272 egl::Error DisplayAndroid::makeCurrent(egl::Surface *drawSurface,
273                                        egl::Surface *readSurface,
274                                        gl::Context *context)
275 {
276     CurrentNativeContext &currentContext = mCurrentNativeContext[std::this_thread::get_id()];
277 
278     EGLSurface newSurface = EGL_NO_SURFACE;
279     if (drawSurface)
280     {
281         SurfaceEGL *drawSurfaceEGL = GetImplAs<SurfaceEGL>(drawSurface);
282         newSurface                 = drawSurfaceEGL->getSurface();
283     }
284 
285     EGLContext newContext = EGL_NO_CONTEXT;
286     if (context)
287     {
288         ContextEGL *contextEGL = GetImplAs<ContextEGL>(context);
289         newContext             = contextEGL->getContext();
290     }
291 
292     // The context should never change when context virtualization is being used, even when a null
293     // context is being bound.
294     if (mVirtualizedContexts)
295     {
296         ASSERT(newContext == EGL_NO_CONTEXT || currentContext.context == EGL_NO_CONTEXT ||
297                newContext == currentContext.context);
298 
299         newContext = mRenderer->getContext();
300 
301         // If we know that we're only running on one thread (mVirtualizedContexts == true) and
302         // EGL_NO_SURFACE is going to be bound, we can optimize this case by not changing the
303         // surface binding and emulate the surfaceless extension in the frontend.
304         if (newSurface == EGL_NO_SURFACE)
305         {
306             newSurface = currentContext.surface;
307         }
308 
309         // It's possible that no surface has been created yet and the driver doesn't support
310         // surfaceless, bind the dummy pbuffer.
311         if (newSurface == EGL_NO_SURFACE && !mSupportsSurfaceless)
312         {
313             newSurface = mDummyPbuffer;
314             ASSERT(newSurface != EGL_NO_SURFACE);
315         }
316     }
317 
318     if (newSurface != currentContext.surface || newContext != currentContext.context)
319     {
320         if (mEGL->makeCurrent(newSurface, newContext) == EGL_FALSE)
321         {
322             return egl::Error(mEGL->getError(), "eglMakeCurrent failed");
323         }
324         currentContext.surface = newSurface;
325         currentContext.context = newContext;
326     }
327 
328     return DisplayGL::makeCurrent(drawSurface, readSurface, context);
329 }
330 
destroyNativeContext(EGLContext context)331 void DisplayAndroid::destroyNativeContext(EGLContext context)
332 {
333     DisplayEGL::destroyNativeContext(context);
334 
335     // If this context is current, remove it from the tracking of current contexts to make sure we
336     // don't try to make it current again.
337     for (auto &currentContext : mCurrentNativeContext)
338     {
339         if (currentContext.second.context == context)
340         {
341             currentContext.second.surface = EGL_NO_SURFACE;
342             currentContext.second.context = EGL_NO_CONTEXT;
343         }
344     }
345 }
346 
generateExtensions(egl::DisplayExtensions * outExtensions) const347 void DisplayAndroid::generateExtensions(egl::DisplayExtensions *outExtensions) const
348 {
349     DisplayEGL::generateExtensions(outExtensions);
350 
351     // Surfaceless can be support if the native driver supports it or we know that we are running on
352     // a single thread (mVirtualizedContexts == true)
353     outExtensions->surfacelessContext = mSupportsSurfaceless || mVirtualizedContexts;
354 }
355 
createRenderer(EGLContext shareContext,bool makeNewContextCurrent,std::shared_ptr<RendererEGL> * outRenderer)356 egl::Error DisplayAndroid::createRenderer(EGLContext shareContext,
357                                           bool makeNewContextCurrent,
358                                           std::shared_ptr<RendererEGL> *outRenderer)
359 {
360     EGLContext context = EGL_NO_CONTEXT;
361     native_egl::AttributeVector attribs;
362     ANGLE_TRY(initializeContext(shareContext, mDisplayAttributes, &context, &attribs));
363 
364     if (mEGL->makeCurrent(mDummyPbuffer, context) == EGL_FALSE)
365     {
366         return egl::EglNotInitialized()
367                << "eglMakeCurrent failed with " << egl::Error(mEGL->getError());
368     }
369 
370     std::unique_ptr<FunctionsGL> functionsGL(mEGL->makeFunctionsGL());
371     functionsGL->initialize(mDisplayAttributes);
372 
373     outRenderer->reset(
374         new RendererEGL(std::move(functionsGL), mDisplayAttributes, this, context, attribs));
375 
376     CurrentNativeContext &currentContext = mCurrentNativeContext[std::this_thread::get_id()];
377     if (makeNewContextCurrent)
378     {
379         currentContext.surface = mDummyPbuffer;
380         currentContext.context = context;
381     }
382     else
383     {
384         // Reset the current context back to the previous state
385         if (mEGL->makeCurrent(currentContext.surface, currentContext.context) == EGL_FALSE)
386         {
387             return egl::EglNotInitialized()
388                    << "eglMakeCurrent failed with " << egl::Error(mEGL->getError());
389         }
390     }
391 
392     return egl::NoError();
393 }
394 
395 class WorkerContextAndroid final : public WorkerContext
396 {
397   public:
398     WorkerContextAndroid(EGLContext context, FunctionsEGL *functions, EGLSurface pbuffer);
399     ~WorkerContextAndroid() override;
400 
401     bool makeCurrent() override;
402     void unmakeCurrent() override;
403 
404   private:
405     EGLContext mContext;
406     FunctionsEGL *mFunctions;
407     EGLSurface mPbuffer;
408 };
409 
WorkerContextAndroid(EGLContext context,FunctionsEGL * functions,EGLSurface pbuffer)410 WorkerContextAndroid::WorkerContextAndroid(EGLContext context,
411                                            FunctionsEGL *functions,
412                                            EGLSurface pbuffer)
413     : mContext(context), mFunctions(functions), mPbuffer(pbuffer)
414 {}
415 
~WorkerContextAndroid()416 WorkerContextAndroid::~WorkerContextAndroid()
417 {
418     mFunctions->destroyContext(mContext);
419 }
420 
makeCurrent()421 bool WorkerContextAndroid::makeCurrent()
422 {
423     if (mFunctions->makeCurrent(mPbuffer, mContext) == EGL_FALSE)
424     {
425         ERR() << "Unable to make the EGL context current.";
426         return false;
427     }
428     return true;
429 }
430 
unmakeCurrent()431 void WorkerContextAndroid::unmakeCurrent()
432 {
433     mFunctions->makeCurrent(EGL_NO_SURFACE, EGL_NO_CONTEXT);
434 }
435 
createWorkerContext(std::string * infoLog,EGLContext sharedContext,const native_egl::AttributeVector workerAttribs)436 WorkerContext *DisplayAndroid::createWorkerContext(std::string *infoLog,
437                                                    EGLContext sharedContext,
438                                                    const native_egl::AttributeVector workerAttribs)
439 {
440     EGLContext context = mEGL->createContext(mConfig, sharedContext, workerAttribs.data());
441     if (context == EGL_NO_CONTEXT)
442     {
443         *infoLog += "Unable to create the EGL context.";
444         return nullptr;
445     }
446     return new WorkerContextAndroid(context, mEGL, mDummyPbuffer);
447 }
448 
449 }  // namespace rx
450