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 ¤tContext = 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 ¤tContext : 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 ¤tContext = 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