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 mMockPbuffer(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 std::vector<EGLint> renderableTypes;
69 static_assert(EGL_OPENGL_ES3_BIT == EGL_OPENGL_ES3_BIT_KHR, "Extension define must match core");
70 if (eglVersion >= gl::Version(1, 5) || mEGL->hasExtension("EGL_KHR_create_context"))
71 {
72 renderableTypes.push_back(EGL_OPENGL_ES3_BIT);
73 }
74 renderableTypes.push_back(EGL_OPENGL_ES2_BIT);
75
76 egl::AttributeMap baseConfigAttribs;
77 baseConfigAttribs.insert(EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER);
78 // Android doesn't support pixmaps
79 baseConfigAttribs.insert(EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT);
80
81 egl::AttributeMap configAttribsWithFormat(baseConfigAttribs);
82 // Choose RGBA8888
83 configAttribsWithFormat.insert(EGL_RED_SIZE, 8);
84 configAttribsWithFormat.insert(EGL_GREEN_SIZE, 8);
85 configAttribsWithFormat.insert(EGL_BLUE_SIZE, 8);
86 configAttribsWithFormat.insert(EGL_ALPHA_SIZE, 8);
87
88 // Choose D24S8
89 // EGL1.5 spec Section 2.2 says that depth, multisample and stencil buffer depths
90 // must match for contexts to be compatible.
91 configAttribsWithFormat.insert(EGL_DEPTH_SIZE, 24);
92 configAttribsWithFormat.insert(EGL_STENCIL_SIZE, 8);
93
94 EGLConfig configWithFormat = EGL_NO_CONFIG_KHR;
95 for (EGLint renderableType : renderableTypes)
96 {
97 baseConfigAttribs.insert(EGL_RENDERABLE_TYPE, renderableType);
98 configAttribsWithFormat.insert(EGL_RENDERABLE_TYPE, renderableType);
99
100 std::vector<EGLint> attribVector = configAttribsWithFormat.toIntVector();
101
102 EGLint numConfig = 0;
103 if (mEGL->chooseConfig(attribVector.data(), &configWithFormat, 1, &numConfig) == EGL_TRUE)
104 {
105 break;
106 }
107 }
108
109 if (configWithFormat == EGL_NO_CONFIG_KHR)
110 {
111 return egl::EglNotInitialized()
112 << "eglChooseConfig failed with " << egl::Error(mEGL->getError());
113 }
114
115 // A mock pbuffer is only needed if surfaceless contexts are not supported.
116 mSupportsSurfaceless = mEGL->hasExtension("EGL_KHR_surfaceless_context");
117 if (!mSupportsSurfaceless)
118 {
119 int mockPbufferAttribs[] = {
120 EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE,
121 };
122 mMockPbuffer = mEGL->createPbufferSurface(configWithFormat, mockPbufferAttribs);
123 if (mMockPbuffer == EGL_NO_SURFACE)
124 {
125 return egl::EglNotInitialized()
126 << "eglCreatePbufferSurface failed with " << egl::Error(mEGL->getError());
127 }
128 }
129
130 // Create mMockPbuffer with a normal config, but create a no_config mContext, if possible
131 if (mEGL->hasExtension("EGL_KHR_no_config_context"))
132 {
133 mConfigAttribList = baseConfigAttribs.toIntVector();
134 mConfig = EGL_NO_CONFIG_KHR;
135 }
136 else
137 {
138 mConfigAttribList = configAttribsWithFormat.toIntVector();
139 mConfig = configWithFormat;
140 }
141
142 ANGLE_TRY(createRenderer(EGL_NO_CONTEXT, true, false, &mRenderer));
143
144 const gl::Version &maxVersion = mRenderer->getMaxSupportedESVersion();
145 if (maxVersion < gl::Version(2, 0))
146 {
147 return egl::EglNotInitialized() << "OpenGL ES 2.0 is not supportable.";
148 }
149
150 ANGLE_TRY(DisplayGL::initialize(display));
151
152 std::string rendererDescription = getRendererDescription();
153 __android_log_print(ANDROID_LOG_INFO, "ANGLE", "%s", rendererDescription.c_str());
154 return egl::NoError();
155 }
156
terminate()157 void DisplayAndroid::terminate()
158 {
159 DisplayGL::terminate();
160
161 EGLBoolean success = mEGL->makeCurrent(EGL_NO_SURFACE, EGL_NO_CONTEXT);
162 if (success == EGL_FALSE)
163 {
164 ERR() << "eglMakeCurrent error " << egl::Error(mEGL->getError());
165 }
166
167 if (mMockPbuffer != EGL_NO_SURFACE)
168 {
169 success = mEGL->destroySurface(mMockPbuffer);
170 mMockPbuffer = EGL_NO_SURFACE;
171 if (success == EGL_FALSE)
172 {
173 ERR() << "eglDestroySurface error " << egl::Error(mEGL->getError());
174 }
175 }
176
177 mRenderer.reset();
178
179 egl::Error result = mEGL->terminate();
180 if (result.isError())
181 {
182 ERR() << "eglTerminate error " << result;
183 }
184
185 SafeDelete(mEGL);
186 }
187
createContext(const gl::State & state,gl::ErrorSet * errorSet,const egl::Config * configuration,const gl::Context * shareContext,const egl::AttributeMap & attribs)188 ContextImpl *DisplayAndroid::createContext(const gl::State &state,
189 gl::ErrorSet *errorSet,
190 const egl::Config *configuration,
191 const gl::Context *shareContext,
192 const egl::AttributeMap &attribs)
193 {
194 std::shared_ptr<RendererEGL> renderer;
195 bool usingExternalContext = attribs.get(EGL_EXTERNAL_CONTEXT_ANGLE, EGL_FALSE) == EGL_TRUE;
196 if (mVirtualizedContexts && !usingExternalContext)
197 {
198 renderer = mRenderer;
199 }
200 else
201 {
202 EGLContext nativeShareContext = EGL_NO_CONTEXT;
203 if (usingExternalContext)
204 {
205 ASSERT(!shareContext);
206 }
207 else if (shareContext)
208 {
209 ContextEGL *shareContextEGL = GetImplAs<ContextEGL>(shareContext);
210 nativeShareContext = shareContextEGL->getContext();
211 }
212
213 // Create a new renderer for this context. It only needs to share with the user's requested
214 // share context because there are no internal resources in DisplayAndroid that are shared
215 // at the GL level.
216 egl::Error error =
217 createRenderer(nativeShareContext, false, usingExternalContext, &renderer);
218 if (error.isError())
219 {
220 ERR() << "Failed to create a shared renderer: " << error.getMessage();
221 return nullptr;
222 }
223 }
224
225 return new ContextEGL(state, errorSet, renderer,
226 RobustnessVideoMemoryPurgeStatus::NOT_REQUESTED);
227 }
228
229 class ExternalSurfaceEGL : public SurfaceEGL
230 {
231 public:
ExternalSurfaceEGL(const egl::SurfaceState & state,const FunctionsEGL * egl,EGLConfig config,EGLint width,EGLint height)232 ExternalSurfaceEGL(const egl::SurfaceState &state,
233 const FunctionsEGL *egl,
234 EGLConfig config,
235 EGLint width,
236 EGLint height)
237 : SurfaceEGL(state, egl, config), mWidth(width), mHeight(height)
238 {}
239 ~ExternalSurfaceEGL() override = default;
240
initialize(const egl::Display * display)241 egl::Error initialize(const egl::Display *display) override { return egl::NoError(); }
getSwapBehavior() const242 EGLint getSwapBehavior() const override { return EGL_BUFFER_DESTROYED; }
getWidth() const243 EGLint getWidth() const override { return mWidth; }
getHeight() const244 EGLint getHeight() const override { return mHeight; }
isExternal() const245 bool isExternal() const override { return true; }
246
247 private:
248 const EGLint mWidth;
249 const EGLint mHeight;
250 };
251
createPbufferFromClientBuffer(const egl::SurfaceState & state,EGLenum buftype,EGLClientBuffer clientBuffer,const egl::AttributeMap & attribs)252 SurfaceImpl *DisplayAndroid::createPbufferFromClientBuffer(const egl::SurfaceState &state,
253 EGLenum buftype,
254 EGLClientBuffer clientBuffer,
255 const egl::AttributeMap &attribs)
256 {
257 if (buftype == EGL_EXTERNAL_SURFACE_ANGLE)
258 {
259 ASSERT(clientBuffer == nullptr);
260
261 EGLint width = static_cast<EGLint>(attribs.get(EGL_WIDTH, 0));
262 EGLint height = static_cast<EGLint>(attribs.get(EGL_HEIGHT, 0));
263
264 // Use the ExternalSurfaceEGL, so ANGLE can know the framebuffer size.
265 return new ExternalSurfaceEGL(state, mEGL, EGL_NO_CONFIG_KHR, width, height);
266 }
267
268 return DisplayEGL::createPbufferFromClientBuffer(state, buftype, clientBuffer, attribs);
269 }
270
isValidNativeWindow(EGLNativeWindowType window) const271 bool DisplayAndroid::isValidNativeWindow(EGLNativeWindowType window) const
272 {
273 return ANativeWindow_getFormat(window) >= 0;
274 }
275
validateClientBuffer(const egl::Config * configuration,EGLenum buftype,EGLClientBuffer clientBuffer,const egl::AttributeMap & attribs) const276 egl::Error DisplayAndroid::validateClientBuffer(const egl::Config *configuration,
277 EGLenum buftype,
278 EGLClientBuffer clientBuffer,
279 const egl::AttributeMap &attribs) const
280 {
281
282 if (buftype == EGL_EXTERNAL_SURFACE_ANGLE)
283 {
284 ASSERT(clientBuffer == nullptr);
285 return egl::NoError();
286 }
287 return DisplayEGL::validateClientBuffer(configuration, buftype, clientBuffer, attribs);
288 }
289
validateImageClientBuffer(const gl::Context * context,EGLenum target,EGLClientBuffer clientBuffer,const egl::AttributeMap & attribs) const290 egl::Error DisplayAndroid::validateImageClientBuffer(const gl::Context *context,
291 EGLenum target,
292 EGLClientBuffer clientBuffer,
293 const egl::AttributeMap &attribs) const
294 {
295 switch (target)
296 {
297 case EGL_NATIVE_BUFFER_ANDROID:
298 return egl::NoError();
299
300 default:
301 return DisplayEGL::validateImageClientBuffer(context, target, clientBuffer, attribs);
302 }
303 }
304
createExternalImageSibling(const gl::Context * context,EGLenum target,EGLClientBuffer buffer,const egl::AttributeMap & attribs)305 ExternalImageSiblingImpl *DisplayAndroid::createExternalImageSibling(
306 const gl::Context *context,
307 EGLenum target,
308 EGLClientBuffer buffer,
309 const egl::AttributeMap &attribs)
310 {
311 switch (target)
312 {
313 case EGL_NATIVE_BUFFER_ANDROID:
314 return new NativeBufferImageSiblingAndroid(buffer);
315
316 default:
317 return DisplayEGL::createExternalImageSibling(context, target, buffer, attribs);
318 }
319 }
320
makeCurrent(egl::Display * display,egl::Surface * drawSurface,egl::Surface * readSurface,gl::Context * context)321 egl::Error DisplayAndroid::makeCurrent(egl::Display *display,
322 egl::Surface *drawSurface,
323 egl::Surface *readSurface,
324 gl::Context *context)
325 {
326 CurrentNativeContext ¤tContext = mCurrentNativeContexts[std::this_thread::get_id()];
327
328 EGLSurface newSurface = EGL_NO_SURFACE;
329 if (drawSurface)
330 {
331 SurfaceEGL *drawSurfaceEGL = GetImplAs<SurfaceEGL>(drawSurface);
332 newSurface = drawSurfaceEGL->getSurface();
333 }
334
335 EGLContext newContext = EGL_NO_CONTEXT;
336 if (context)
337 {
338 ContextEGL *contextEGL = GetImplAs<ContextEGL>(context);
339 newContext = contextEGL->getContext();
340 }
341
342 if (currentContext.isExternalContext || (context && context->isExternal()))
343 {
344 ASSERT(currentContext.surface == EGL_NO_SURFACE);
345 if (!currentContext.isExternalContext)
346 {
347 // Switch to an ANGLE external context.
348 ASSERT(context);
349 ASSERT(currentContext.context == EGL_NO_CONTEXT);
350 currentContext.context = newContext;
351 currentContext.isExternalContext = true;
352
353 // We only support using external surface with external context.
354 ASSERT(GetImplAs<SurfaceEGL>(drawSurface)->isExternal());
355 ASSERT(GetImplAs<SurfaceEGL>(drawSurface)->getSurface() == EGL_NO_SURFACE);
356 }
357 else if (context)
358 {
359 // Switch surface but not context.
360 ASSERT(currentContext.context == newContext);
361 ASSERT(newSurface == EGL_NO_SURFACE);
362 ASSERT(newContext != EGL_NO_CONTEXT);
363 // We only support using external surface with external context.
364 ASSERT(GetImplAs<SurfaceEGL>(drawSurface)->isExternal());
365 ASSERT(GetImplAs<SurfaceEGL>(drawSurface)->getSurface() == EGL_NO_SURFACE);
366 }
367 else
368 {
369 // Release the ANGLE external context.
370 ASSERT(newSurface == EGL_NO_SURFACE);
371 ASSERT(newContext == EGL_NO_CONTEXT);
372 ASSERT(currentContext.context != EGL_NO_CONTEXT);
373 currentContext.context = EGL_NO_CONTEXT;
374 currentContext.isExternalContext = false;
375 }
376
377 // Do not need to call eglMakeCurrent(), since we don't support swtiching EGLSurface for
378 // external context.
379 return DisplayGL::makeCurrent(display, drawSurface, readSurface, context);
380 }
381
382 // The context should never change when context virtualization is being used unless binding a
383 // null context.
384 if (mVirtualizedContexts && newContext != EGL_NO_CONTEXT)
385 {
386 ASSERT(currentContext.context == EGL_NO_CONTEXT || newContext == currentContext.context);
387
388 newContext = mRenderer->getContext();
389
390 // If we know that we're only running on one thread (mVirtualizedContexts == true) and
391 // EGL_NO_SURFACE is going to be bound, we can optimize this case by not changing the
392 // surface binding and emulate the surfaceless extension in the frontend.
393 if (newSurface == EGL_NO_SURFACE)
394 {
395 newSurface = currentContext.surface;
396 }
397
398 // It's possible that no surface has been created yet and the driver doesn't support
399 // surfaceless, bind the mock pbuffer.
400 if (newSurface == EGL_NO_SURFACE && !mSupportsSurfaceless)
401 {
402 newSurface = mMockPbuffer;
403 ASSERT(newSurface != EGL_NO_SURFACE);
404 }
405 }
406
407 if (newSurface != currentContext.surface || newContext != currentContext.context)
408 {
409 if (mEGL->makeCurrent(newSurface, newContext) == EGL_FALSE)
410 {
411 return egl::Error(mEGL->getError(), "eglMakeCurrent failed");
412 }
413 currentContext.surface = newSurface;
414 currentContext.context = newContext;
415 }
416
417 return DisplayGL::makeCurrent(display, drawSurface, readSurface, context);
418 }
419
destroyNativeContext(EGLContext context)420 void DisplayAndroid::destroyNativeContext(EGLContext context)
421 {
422 DisplayEGL::destroyNativeContext(context);
423 }
424
generateExtensions(egl::DisplayExtensions * outExtensions) const425 void DisplayAndroid::generateExtensions(egl::DisplayExtensions *outExtensions) const
426 {
427 DisplayEGL::generateExtensions(outExtensions);
428
429 // Surfaceless can be support if the native driver supports it or we know that we are running on
430 // a single thread (mVirtualizedContexts == true)
431 outExtensions->surfacelessContext = mSupportsSurfaceless || mVirtualizedContexts;
432
433 outExtensions->externalContextAndSurface = true;
434 }
435
createRenderer(EGLContext shareContext,bool makeNewContextCurrent,bool isExternalContext,std::shared_ptr<RendererEGL> * outRenderer)436 egl::Error DisplayAndroid::createRenderer(EGLContext shareContext,
437 bool makeNewContextCurrent,
438 bool isExternalContext,
439 std::shared_ptr<RendererEGL> *outRenderer)
440 {
441 EGLContext context = EGL_NO_CONTEXT;
442 native_egl::AttributeVector attribs;
443
444 // If isExternalContext is true, the external context is current, so we don't need to make the
445 // mMockPbuffer current.
446 if (isExternalContext)
447 {
448 ASSERT(shareContext == EGL_NO_CONTEXT);
449 ASSERT(!makeNewContextCurrent);
450 // Should we consider creating a share context to avoid querying and restoring GL context
451 // state?
452 context = mEGL->getCurrentContext();
453 ASSERT(context != EGL_NO_CONTEXT);
454 // TODO: get the version from the current context.
455 attribs = {EGL_CONTEXT_MAJOR_VERSION, 2, EGL_CONTEXT_MINOR_VERSION, 0, EGL_NONE};
456 }
457 else
458 {
459 ANGLE_TRY(initializeContext(shareContext, mDisplayAttributes, &context, &attribs));
460 if (mEGL->makeCurrent(mMockPbuffer, context) == EGL_FALSE)
461 {
462 return egl::EglNotInitialized()
463 << "eglMakeCurrent failed with " << egl::Error(mEGL->getError());
464 }
465 }
466
467 std::unique_ptr<FunctionsGL> functionsGL(mEGL->makeFunctionsGL());
468 functionsGL->initialize(mDisplayAttributes);
469
470 outRenderer->reset(new RendererEGL(std::move(functionsGL), mDisplayAttributes, this, context,
471 attribs, isExternalContext));
472
473 CurrentNativeContext ¤tContext = mCurrentNativeContexts[std::this_thread::get_id()];
474 if (makeNewContextCurrent)
475 {
476 currentContext.surface = mMockPbuffer;
477 currentContext.context = context;
478 }
479 else if (!isExternalContext)
480 {
481 // Reset the current context back to the previous state
482 if (mEGL->makeCurrent(currentContext.surface, currentContext.context) == EGL_FALSE)
483 {
484 return egl::EglNotInitialized()
485 << "eglMakeCurrent failed with " << egl::Error(mEGL->getError());
486 }
487 }
488
489 return egl::NoError();
490 }
491
492 class WorkerContextAndroid final : public WorkerContext
493 {
494 public:
495 WorkerContextAndroid(EGLContext context, FunctionsEGL *functions, EGLSurface pbuffer);
496 ~WorkerContextAndroid() override;
497
498 bool makeCurrent() override;
499 void unmakeCurrent() override;
500
501 private:
502 EGLContext mContext;
503 FunctionsEGL *mFunctions;
504 EGLSurface mPbuffer;
505 };
506
WorkerContextAndroid(EGLContext context,FunctionsEGL * functions,EGLSurface pbuffer)507 WorkerContextAndroid::WorkerContextAndroid(EGLContext context,
508 FunctionsEGL *functions,
509 EGLSurface pbuffer)
510 : mContext(context), mFunctions(functions), mPbuffer(pbuffer)
511 {}
512
~WorkerContextAndroid()513 WorkerContextAndroid::~WorkerContextAndroid()
514 {
515 mFunctions->destroyContext(mContext);
516 }
517
makeCurrent()518 bool WorkerContextAndroid::makeCurrent()
519 {
520 if (mFunctions->makeCurrent(mPbuffer, mContext) == EGL_FALSE)
521 {
522 ERR() << "Unable to make the EGL context current.";
523 return false;
524 }
525 return true;
526 }
527
unmakeCurrent()528 void WorkerContextAndroid::unmakeCurrent()
529 {
530 mFunctions->makeCurrent(EGL_NO_SURFACE, EGL_NO_CONTEXT);
531 }
532
createWorkerContext(std::string * infoLog,EGLContext sharedContext,const native_egl::AttributeVector workerAttribs)533 WorkerContext *DisplayAndroid::createWorkerContext(std::string *infoLog,
534 EGLContext sharedContext,
535 const native_egl::AttributeVector workerAttribs)
536 {
537 EGLContext context = mEGL->createContext(mConfig, sharedContext, workerAttribs.data());
538 if (context == EGL_NO_CONTEXT)
539 {
540 *infoLog += "Unable to create the EGL context.";
541 return nullptr;
542 }
543 return new WorkerContextAndroid(context, mEGL, mMockPbuffer);
544 }
545
546 } // namespace rx
547