1 /*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include "EglDisplay.h"
17
18 #include "aemu/base/containers/Lookup.h"
19 #include "aemu/base/files/StreamSerializing.h"
20 #include "EglConfig.h"
21 #include "EglGlobalInfo.h"
22 #include "EglOsApi.h"
23 #include <GLcommon/GLutils.h>
24
25 #include <algorithm>
26
EglDisplay(EGLNativeDisplayType dpy,EglOS::Display * idpy)27 EglDisplay::EglDisplay(EGLNativeDisplayType dpy,
28 EglOS::Display* idpy) :
29 m_dpy(dpy),
30 m_idpy(idpy)
31 {
32 m_manager[GLES_1_1] = new ObjectNameManager(&m_globalNameSpace);
33 m_manager[GLES_2_0] = new ObjectNameManager(&m_globalNameSpace);
34 m_manager[GLES_3_0] = m_manager[GLES_2_0];
35 m_manager[GLES_3_1] = m_manager[GLES_2_0];
36 };
37
~EglDisplay()38 EglDisplay::~EglDisplay() {
39 android::base::AutoLock mutex(m_lock);
40
41 m_configs.clear();
42
43 delete m_manager[GLES_1_1];
44 delete m_manager[GLES_2_0];
45
46 delete m_idpy;
47 }
48
initialize(int renderableType)49 void EglDisplay::initialize(int renderableType) {
50 android::base::AutoLock mutex(m_lock);
51 m_initialized = true;
52 initConfigurations(renderableType);
53 m_configInitialized = true;
54 }
55
isInitialize()56 bool EglDisplay::isInitialize() {
57 android::base::AutoLock mutex(m_lock);
58 return m_initialized;
59 }
60
terminate()61 void EglDisplay::terminate(){
62 android::base::AutoLock mutex(m_lock);
63 m_contexts.clear();
64 m_surfaces.clear();
65 m_initialized = false;
66 }
67
68 namespace CompareEglConfigs {
69
70 // Old compare function used to initialize to something decently sorted.
71 struct StaticCompare {
operator ()CompareEglConfigs::StaticCompare72 bool operator()(const std::unique_ptr<EglConfig>& first,
73 const std::unique_ptr<EglConfig>& second) const {
74 return *first < *second;
75 }
76 };
77
78 // In actual usage, we need to dynamically re-sort configs
79 // that are returned to the user.
80 struct DynamicCompare;
81 // This is because the sorting order of configs is affected
82 // based on dynamic properties.
83 //
84 // See https://www.khronos.org/registry/egl/sdk/docs/man/html/eglChooseConfig.xhtml
85 // and the section on config sorting.
86 //
87 // If the user requests an EGL config with a particular EGL_RED_SIZE,
88 // for example, we must sort configs based on that criteria, while if that
89 // was not specified, we would just skip right on to sorting by buffer size.
90 // Below is an implementation of EGL config sorting according
91 // to spec, that takes the dynamic properties into account.
ColorBufferTypeVal(EGLenum type)92 static int ColorBufferTypeVal(EGLenum type) {
93 switch (type) {
94 case EGL_RGB_BUFFER: return 0;
95 case EGL_LUMINANCE_BUFFER: return 1;
96 case EGL_YUV_BUFFER_EXT: return 2;
97 }
98 return 3;
99 }
100
nonTrivialAttribVal(EGLint val)101 static bool nonTrivialAttribVal(EGLint val) {
102 return val != 0 && val != EGL_DONT_CARE;
103 }
104
105 struct DynamicCompare {
106 public:
DynamicCompareCompareEglConfigs::DynamicCompare107 DynamicCompare(const EglConfig& wantedAttribs) {
108
109 EGLint wantedRVal = wantedAttribs.getConfAttrib(EGL_RED_SIZE);
110 EGLint wantedGVal = wantedAttribs.getConfAttrib(EGL_GREEN_SIZE);
111 EGLint wantedBVal = wantedAttribs.getConfAttrib(EGL_BLUE_SIZE);
112 EGLint wantedLVal = wantedAttribs.getConfAttrib(EGL_LUMINANCE_SIZE);
113 EGLint wantedAVal = wantedAttribs.getConfAttrib(EGL_ALPHA_SIZE);
114
115 wantedR = wantedAttribs.isWantedAttrib(EGL_RED_SIZE) && nonTrivialAttribVal(wantedRVal);
116 wantedG = wantedAttribs.isWantedAttrib(EGL_GREEN_SIZE) && nonTrivialAttribVal(wantedGVal);
117 wantedB = wantedAttribs.isWantedAttrib(EGL_BLUE_SIZE) && nonTrivialAttribVal(wantedBVal);
118 wantedL = wantedAttribs.isWantedAttrib(EGL_LUMINANCE_SIZE) && nonTrivialAttribVal(wantedLVal);
119 wantedA = wantedAttribs.isWantedAttrib(EGL_ALPHA_SIZE) && nonTrivialAttribVal(wantedAVal);
120 }
121
operator ()CompareEglConfigs::DynamicCompare122 bool operator()(EglConfig* a, EglConfig* b) const {
123 EGLint aConformant = a->getConfAttrib(EGL_CONFORMANT);
124 EGLint bConformant = b->getConfAttrib(EGL_CONFORMANT);
125
126 if (aConformant != bConformant) {
127 return aConformant != 0;
128 }
129
130 EGLint aCaveat = a->getConfAttrib(EGL_CONFIG_CAVEAT);
131 EGLint bCaveat = b->getConfAttrib(EGL_CONFIG_CAVEAT);
132 if (aCaveat != bCaveat) {
133 return aCaveat < bCaveat;
134 }
135
136 EGLint aCbType = a->getConfAttrib(EGL_COLOR_BUFFER_TYPE);
137 EGLint bCbType = b->getConfAttrib(EGL_COLOR_BUFFER_TYPE);
138 if (aCbType != bCbType) {
139 return ColorBufferTypeVal(aCbType) <
140 ColorBufferTypeVal(bCbType);
141 }
142
143 EGLint aCbSize = 0;
144 EGLint bCbSize = 0;
145
146 if (wantedR) {
147 aCbSize += a->getConfAttrib(EGL_RED_SIZE);
148 bCbSize += b->getConfAttrib(EGL_RED_SIZE);
149 }
150 if (wantedG) {
151 aCbSize += a->getConfAttrib(EGL_GREEN_SIZE);
152 bCbSize += b->getConfAttrib(EGL_GREEN_SIZE);
153 }
154 if (wantedB) {
155 aCbSize += a->getConfAttrib(EGL_BLUE_SIZE);
156 bCbSize += b->getConfAttrib(EGL_BLUE_SIZE);
157 }
158 if (wantedL) {
159 aCbSize += a->getConfAttrib(EGL_LUMINANCE_SIZE);
160 bCbSize += b->getConfAttrib(EGL_LUMINANCE_SIZE);
161 }
162 if (wantedA) {
163 aCbSize += a->getConfAttrib(EGL_ALPHA_SIZE);
164 bCbSize += b->getConfAttrib(EGL_ALPHA_SIZE);
165 }
166
167 if (aCbSize != bCbSize) {
168 return aCbSize > bCbSize;
169 }
170
171 EGLint aBufferSize = a->getConfAttrib(EGL_BUFFER_SIZE);
172 EGLint bBufferSize = b->getConfAttrib(EGL_BUFFER_SIZE);
173 if (aBufferSize != bBufferSize) {
174 return aBufferSize < bBufferSize;
175 }
176
177 EGLint aSampleBuffersNum = a->getConfAttrib(EGL_SAMPLE_BUFFERS);
178 EGLint bSampleBuffersNum = b->getConfAttrib(EGL_SAMPLE_BUFFERS);
179 if (aSampleBuffersNum != bSampleBuffersNum) {
180 return aSampleBuffersNum < bSampleBuffersNum;
181 }
182
183 EGLint aSPP = a->getConfAttrib(EGL_SAMPLES);
184 EGLint bSPP = b->getConfAttrib(EGL_SAMPLES);
185 if (aSPP != bSPP) {
186 return aSPP < bSPP;
187 }
188
189 EGLint aDepthSize = a->getConfAttrib(EGL_DEPTH_SIZE);
190 EGLint bDepthSize = b->getConfAttrib(EGL_DEPTH_SIZE);
191 if (aDepthSize != bDepthSize) {
192 return aDepthSize < bDepthSize;
193 }
194
195 EGLint aStencilSize = a->getConfAttrib(EGL_STENCIL_SIZE);
196 EGLint bStencilSize = b->getConfAttrib(EGL_STENCIL_SIZE);
197 if (aStencilSize != bStencilSize) {
198 return aStencilSize < bStencilSize;
199 }
200
201 return a->getConfAttrib(EGL_CONFIG_ID) < b->getConfAttrib(EGL_CONFIG_ID);
202 }
203
204 bool wantedR;
205 bool wantedG;
206 bool wantedB;
207 bool wantedL;
208 bool wantedA;
209 };
210
211 }
212
addSimplePixelFormat(int red_size,int green_size,int blue_size,int alpha_size,int sample_per_pixel)213 EglConfig* EglDisplay::addSimplePixelFormat(int red_size,
214 int green_size,
215 int blue_size,
216 int alpha_size,
217 int sample_per_pixel) {
218 std::sort(m_configs.begin(), m_configs.end(), CompareEglConfigs::StaticCompare());
219
220 EGLConfig match;
221
222 EglConfig dummy(red_size,
223 green_size,
224 blue_size,
225 alpha_size, // RGB_565
226 EGL_DONT_CARE,
227 EGL_DONT_CARE,
228 16, // Depth
229 EGL_DONT_CARE,
230 EGL_DONT_CARE,
231 EGL_DONT_CARE,
232 EGL_DONT_CARE,
233 EGL_DONT_CARE,
234 EGL_DONT_CARE,
235 EGL_DONT_CARE,
236 EGL_DONT_CARE,
237 sample_per_pixel,
238 EGL_DONT_CARE,
239 EGL_DONT_CARE,
240 EGL_DONT_CARE,
241 EGL_DONT_CARE,
242 EGL_DONT_CARE,
243 EGL_DONT_CARE,
244 EGL_DONT_CARE,
245 NULL);
246
247 if(!doChooseConfigs(dummy, &match, 1))
248 {
249 return nullptr;
250 }
251
252 EglConfig* config = (EglConfig*)match;
253
254 int bSize;
255 config->getConfAttrib(EGL_BUFFER_SIZE,&bSize);
256
257 if(bSize == 16)
258 {
259 return config;
260 }
261
262 std::unique_ptr<EglConfig> newConfig(
263 new EglConfig(*config,
264 red_size, green_size, blue_size,
265 alpha_size));
266
267 if (m_uniqueConfigs.insert(*newConfig).second) {
268 config = newConfig.release();
269 m_configs.emplace_back(config);
270 }
271 return config;
272 }
273
274 // BUG: 246999412
275 // We might want to deprecate this list.
276 static const EGLint kCommonCfgs[][5] = {
277 {8, 8, 8, 0, EGL_DONT_CARE},
278 {8, 8, 8, 8, EGL_DONT_CARE},
279 // 565 fails with ANGLE on Mac
280 // {5, 6, 5, 0, EGL_DONT_CARE},
281 // The following are multi-sample configs. They have issues with CTS test:
282 // (API26) run cts -m CtsOpenGLTestCases -t
283 // android.opengl.cts.EglConfigTest#testEglConfigs
284 // We disable them until we figure out how to fix that test properly
285 // BUG: 69421199
286 // {5, 6, 5, 0, 2},
287 // {8, 8, 8, 0, 2},
288 // {8, 8, 8, 8, 2},
289 // {5, 6, 5, 0, 4},
290 // {8, 8, 8, 0, 4},
291 // {8, 8, 8, 8, 4},
292 };
293
294 static constexpr int kReservedIdNum = sizeof(kCommonCfgs) / 5 / sizeof(EGLint);
295
addReservedConfigs()296 void EglDisplay::addReservedConfigs() {
297 for (int i = 0; i < kReservedIdNum; i++) {
298 EglConfig* cfg = nullptr;
299 cfg = addSimplePixelFormat(kCommonCfgs[i][0],
300 kCommonCfgs[i][1],
301 kCommonCfgs[i][2],
302 kCommonCfgs[i][3],
303 kCommonCfgs[i][4]);
304 // ID starts with 1
305 if (cfg) {
306 cfg->setId(i + 1);
307 }
308 }
309 }
310
initConfigurations(int renderableType)311 void EglDisplay::initConfigurations(int renderableType) {
312 if (m_configInitialized) {
313 return;
314 }
315 m_idpy->queryConfigs(renderableType, addConfig, this);
316
317 for (size_t i = 0; i < m_configs.size(); i++) {
318 // ID starts with 1
319 m_configs[i]->setId(static_cast<EGLint>(i + 1 + kReservedIdNum));
320 }
321 addReservedConfigs();
322 // It is ok if config id is not continual.
323 std::sort(m_configs.begin(), m_configs.end(), CompareEglConfigs::StaticCompare());
324
325 #if EMUGL_DEBUG
326 for (ConfigsList::const_iterator it = m_configs.begin();
327 it != m_configs.end();
328 ++it) {
329 EglConfig* config = it->get();
330 EGLint red, green, blue, alpha, depth, stencil, renderable, surface;
331 config->getConfAttrib(EGL_RED_SIZE, &red);
332 config->getConfAttrib(EGL_GREEN_SIZE, &green);
333 config->getConfAttrib(EGL_BLUE_SIZE, &blue);
334 config->getConfAttrib(EGL_ALPHA_SIZE, &alpha);
335 config->getConfAttrib(EGL_DEPTH_SIZE, &depth);
336 config->getConfAttrib(EGL_STENCIL_SIZE, &stencil);
337 config->getConfAttrib(EGL_RENDERABLE_TYPE, &renderable);
338 config->getConfAttrib(EGL_SURFACE_TYPE, &surface);
339 }
340 #endif // EMUGL_DEBUG
341 }
342
getConfig(EGLConfig conf) const343 EglConfig* EglDisplay::getConfig(EGLConfig conf) const {
344 android::base::AutoLock mutex(m_lock);
345
346 for(ConfigsList::const_iterator it = m_configs.begin();
347 it != m_configs.end();
348 ++it) {
349 if(static_cast<EGLConfig>(it->get()) == conf) {
350 return it->get();
351 }
352 }
353 return NULL;
354 }
355
getSurface(EGLSurface surface) const356 SurfacePtr EglDisplay::getSurface(EGLSurface surface) const {
357 android::base::AutoLock mutex(m_lock);
358 /* surface is "key" in map<unsigned int, SurfacePtr>. */
359 unsigned int hndl = SafeUIntFromPointer(surface);
360 SurfacesHndlMap::const_iterator it = m_surfaces.find(hndl);
361 return it != m_surfaces.end() ?
362 (*it).second :
363 SurfacePtr();
364 }
365
getContext(EGLContext ctx) const366 ContextPtr EglDisplay::getContext(EGLContext ctx) const {
367 android::base::AutoLock mutex(m_lock);
368 /* ctx is "key" in map<unsigned int, ContextPtr>. */
369 unsigned int hndl = SafeUIntFromPointer(ctx);
370 ContextsHndlMap::const_iterator it = m_contexts.find(hndl);
371 return it != m_contexts.end() ?
372 (*it).second :
373 ContextPtr();
374 }
375
getLowLevelContext(EGLContext ctx) const376 void* EglDisplay::getLowLevelContext(EGLContext ctx) const {
377 auto lctx = getContext(ctx);
378 if (lctx) {
379 return lctx->nativeType()->lowLevelContext();
380 }
381 return nullptr;
382 }
383
removeSurface(EGLSurface s)384 bool EglDisplay::removeSurface(EGLSurface s) {
385 android::base::AutoLock mutex(m_lock);
386 /* s is "key" in map<unsigned int, SurfacePtr>. */
387 unsigned int hndl = SafeUIntFromPointer(s);
388 SurfacesHndlMap::iterator it = m_surfaces.find(hndl);
389 if(it != m_surfaces.end()) {
390 m_surfaces.erase(it);
391 return true;
392 }
393 return false;
394 }
395
removeContext(EGLContext ctx)396 bool EglDisplay::removeContext(EGLContext ctx) {
397 android::base::AutoLock mutex(m_lock);
398 /* ctx is "key" in map<unsigned int, ContextPtr>. */
399 unsigned int hndl = SafeUIntFromPointer(ctx);
400 ContextsHndlMap::iterator it = m_contexts.find(hndl);
401 if(it != m_contexts.end()) {
402 m_contexts.erase(it);
403 return true;
404 }
405 return false;
406 }
407
removeContext(ContextPtr ctx)408 bool EglDisplay::removeContext(ContextPtr ctx) {
409 android::base::AutoLock mutex(m_lock);
410
411 ContextsHndlMap::iterator it;
412 for(it = m_contexts.begin(); it != m_contexts.end();++it) {
413 if((*it).second.get() == ctx.get()){
414 break;
415 }
416 }
417 if(it != m_contexts.end()) {
418 m_contexts.erase(it);
419 return true;
420 }
421 return false;
422 }
423
getConfig(EGLint id) const424 EglConfig* EglDisplay::getConfig(EGLint id) const {
425 android::base::AutoLock mutex(m_lock);
426
427 for(ConfigsList::const_iterator it = m_configs.begin();
428 it != m_configs.end();
429 ++it) {
430 if((*it)->id() == id) {
431 return it->get();
432 }
433 }
434 return NULL;
435 }
436
getDefaultConfig() const437 EglConfig* EglDisplay::getDefaultConfig() const {
438 return getConfig(2); // rgba8888
439 }
440
getConfigs(EGLConfig * configs,int config_size) const441 int EglDisplay::getConfigs(EGLConfig* configs,int config_size) const {
442 android::base::AutoLock mutex(m_lock);
443 int i = 0;
444 for(ConfigsList::const_iterator it = m_configs.begin();
445 it != m_configs.end() && i < config_size;
446 i++, ++it) {
447 configs[i] = static_cast<EGLConfig>(it->get());
448 }
449 return i;
450 }
451
chooseConfigs(const EglConfig & dummy,EGLConfig * configs,int config_size) const452 int EglDisplay::chooseConfigs(const EglConfig& dummy,
453 EGLConfig* configs,
454 int config_size) const {
455 android::base::AutoLock mutex(m_lock);
456 return doChooseConfigs(dummy, configs, config_size);
457 }
458
doChooseConfigs(const EglConfig & dummy,EGLConfig * configs,int config_size) const459 int EglDisplay::doChooseConfigs(const EglConfig& dummy,
460 EGLConfig* configs,
461 int config_size) const {
462 int added = 0;
463
464 std::vector<EglConfig*> validConfigs;
465
466 CHOOSE_CONFIG_DLOG("returning configs. ids: {");
467 for(ConfigsList::const_iterator it = m_configs.begin();
468 it != m_configs.end() && (added < config_size || !configs);
469 ++it) {
470 if( (*it)->chosen(dummy)){
471 if(configs) {
472 CHOOSE_CONFIG_DLOG("valid config: id=0x%x", it->get()->id());
473 validConfigs.push_back(it->get());
474 }
475 added++;
476 }
477 }
478
479 CHOOSE_CONFIG_DLOG("sorting valid configs...");
480
481 std::sort(validConfigs.begin(),
482 validConfigs.end(),
483 CompareEglConfigs::DynamicCompare(dummy));
484
485 for (int i = 0; configs && i < added; i++) {
486 configs[i] = static_cast<EGLConfig>(validConfigs[i]);
487 }
488
489 CHOOSE_CONFIG_DLOG("returning configs. ids end }");
490 return added;
491 }
492
addSurface(SurfacePtr s)493 EGLSurface EglDisplay::addSurface(SurfacePtr s ) {
494 android::base::AutoLock mutex(m_lock);
495 unsigned int hndl = s.get()->getHndl();
496 EGLSurface ret =reinterpret_cast<EGLSurface> (hndl);
497
498 if(m_surfaces.find(hndl) != m_surfaces.end()) {
499 return ret;
500 }
501
502 m_surfaces[hndl] = s;
503 return ret;
504 }
505
addContext(ContextPtr ctx)506 EGLContext EglDisplay::addContext(ContextPtr ctx ) {
507 android::base::AutoLock mutex(m_lock);
508
509 unsigned int hndl = ctx.get()->getHndl();
510 EGLContext ret = reinterpret_cast<EGLContext> (hndl);
511
512 if(m_contexts.find(hndl) != m_contexts.end()) {
513 return ret;
514 }
515 m_contexts[hndl] = ctx;
516 return ret;
517 }
518
519
addImageKHR(ImagePtr img)520 EGLImageKHR EglDisplay::addImageKHR(ImagePtr img) {
521 android::base::AutoLock mutex(m_lock);
522 do {
523 ++m_nextEglImageId;
524 } while(m_nextEglImageId == 0
525 || android::base::contains(m_eglImages, m_nextEglImageId));
526 img->imageId = m_nextEglImageId;
527 m_eglImages[m_nextEglImageId] = img;
528 return reinterpret_cast<EGLImageKHR>(m_nextEglImageId);
529 }
530
touchEglImage(EglImage * eglImage,SaveableTexture::restorer_t restorer)531 static void touchEglImage(EglImage* eglImage,
532 SaveableTexture::restorer_t restorer) {
533 if (eglImage->needRestore) {
534 if (eglImage->saveableTexture.get()) {
535 restorer(eglImage->saveableTexture.get());
536 eglImage->saveableTexture->fillEglImage(eglImage);
537 }
538 eglImage->needRestore = false;
539 }
540 }
541
getImage(EGLImageKHR img,SaveableTexture::restorer_t restorer) const542 ImagePtr EglDisplay::getImage(EGLImageKHR img,
543 SaveableTexture::restorer_t restorer) const {
544 android::base::AutoLock mutex(m_lock);
545 /* img is "key" in map<unsigned int, ImagePtr>. */
546 unsigned int hndl = SafeUIntFromPointer(img);
547 ImagesHndlMap::const_iterator i( m_eglImages.find(hndl) );
548 if (i == m_eglImages.end()) {
549 return ImagePtr();
550 }
551 touchEglImage(i->second.get(), restorer);
552 return i->second;
553 }
554
destroyImageKHR(EGLImageKHR img)555 bool EglDisplay:: destroyImageKHR(EGLImageKHR img) {
556 android::base::AutoLock mutex(m_lock);
557 /* img is "key" in map<unsigned int, ImagePtr>. */
558 unsigned int hndl = SafeUIntFromPointer(img);
559 ImagesHndlMap::iterator i( m_eglImages.find(hndl) );
560 if (i != m_eglImages.end())
561 {
562 m_eglImages.erase(i);
563 return true;
564 }
565 return false;
566 }
567
getGlobalSharedContext() const568 EglOS::Context* EglDisplay::getGlobalSharedContext() const {
569 android::base::AutoLock mutex(m_lock);
570 #ifndef _WIN32
571 // find an existing OpenGL context to share with, if exist
572 EglOS::Context* ret =
573 (EglOS::Context*)m_manager[GLES_1_1]->getGlobalContext();
574 if (!ret)
575 ret = (EglOS::Context*)m_manager[GLES_2_0]->getGlobalContext();
576 return ret;
577 #else
578 if (!m_globalSharedContext) {
579 //
580 // On windows we create a dummy context to serve as the
581 // "global context" which all contexts share with.
582 // This is because on windows it is not possible to share
583 // with a context which is already current. This dummy context
584 // will never be current to any thread so it is safe to share with.
585 // Create that context using the first config
586 if (m_configs.empty()) {
587 // Should not happen! config list should be initialized at this point
588 return NULL;
589 }
590 EglConfig *cfg = m_configs.front().get();
591 m_globalSharedContext = m_idpy->createContext(
592 isCoreProfile() ? EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR : 0,
593 cfg->nativeFormat(), NULL);
594 }
595
596 return m_globalSharedContext.get();
597 #endif
598 }
599
600 // static
addConfig(void * opaque,const EglOS::ConfigInfo * info)601 void EglDisplay::addConfig(void* opaque, const EglOS::ConfigInfo* info) {
602 EglDisplay* display = static_cast<EglDisplay*>(opaque);
603
604 // Greater than 24 bits of color,
605 // or having no depth/stencil causes some
606 // unexpected behavior in real usage, such
607 // as frame corruption and wrong drawing order.
608 // Just don't use those configs.
609 if (info->red_size > 8 ||
610 info->green_size > 8 ||
611 info->blue_size > 8 ||
612 info->depth_size < 24 ||
613 info->stencil_size < 8 ||
614 info->samples_per_pixel > 2) {
615 return;
616 }
617
618 std::unique_ptr<EglConfig> config(new EglConfig(
619 info->red_size,
620 info->green_size,
621 info->blue_size,
622 info->alpha_size,
623 info->alpha_mask_size,
624 info->caveat,
625 info->depth_size,
626 info->frame_buffer_level,
627 info->max_pbuffer_width,
628 info->max_pbuffer_height,
629 info->max_pbuffer_size,
630 info->native_renderable,
631 info->renderable_type,
632 info->native_visual_id,
633 info->native_visual_type,
634 info->samples_per_pixel,
635 info->stencil_size,
636 info->surface_type,
637 info->transparent_type,
638 info->trans_red_val,
639 info->trans_green_val,
640 info->trans_blue_val,
641 info->recordable_android,
642 info->frmt));
643
644 if (display->m_uniqueConfigs.insert(*config).second) {
645 display->m_configs.emplace_back(config.release());
646 }
647 }
648
onSaveAllImages(android::base::Stream * stream,const android::snapshot::ITextureSaverPtr & textureSaver,SaveableTexture::saver_t saver,SaveableTexture::restorer_t restorer)649 void EglDisplay::onSaveAllImages(android::base::Stream* stream,
650 const android::snapshot::ITextureSaverPtr& textureSaver,
651 SaveableTexture::saver_t saver,
652 SaveableTexture::restorer_t restorer) {
653 // we could consider calling presave for all ShareGroups from here
654 // but it would introduce overheads because not all share groups need to be
655 // saved
656 android::base::AutoLock mutex(m_lock);
657 for (auto& image : m_eglImages) {
658 // In case we loaded textures from a previous snapshot and have not
659 // yet restore them to GPU, we do the restoration here.
660 // TODO: skip restoration and write saveableTexture directly to the
661 // new snapshot for better performance
662 touchEglImage(image.second.get(), restorer);
663 getGlobalNameSpace()->preSaveAddEglImage(image.second.get());
664 }
665 m_globalNameSpace.onSave(stream, textureSaver, saver);
666 saveCollection(stream, m_eglImages, [](
667 android::base::Stream* stream,
668 const ImagesHndlMap::value_type& img) {
669 stream->putBe32(img.first);
670 stream->putBe32(img.second->globalTexObj->getGlobalName());
671 // We do not need to save other fields in EglImage. We can load them
672 // from SaveableTexture.
673 });
674 }
675
onLoadAllImages(android::base::Stream * stream,const android::snapshot::ITextureLoaderPtr & textureLoader,SaveableTexture::creator_t creator)676 void EglDisplay::onLoadAllImages(android::base::Stream* stream,
677 const android::snapshot::ITextureLoaderPtr& textureLoader,
678 SaveableTexture::creator_t creator) {
679 if (!m_eglImages.empty()) {
680 // Could be triggered by this bug:
681 // b/36654917
682 fprintf(stderr, "Warning: unreleased EGL image handles\n");
683 }
684 m_eglImages.clear();
685 android::base::AutoLock mutex(m_lock);
686 m_globalNameSpace.setIfaces(
687 EglGlobalInfo::getInstance()->getEglIface(),
688 EglGlobalInfo::getInstance()->getIface(GLES_2_0));
689 m_globalNameSpace.onLoad(stream, textureLoader, creator);
690
691 loadCollection(stream, &m_eglImages, [this](
692 android::base::Stream* stream) {
693 unsigned int hndl = stream->getBe32();
694 unsigned int globalName = stream->getBe32();
695 ImagePtr eglImg(new EglImage);
696 eglImg->imageId = hndl;
697 eglImg->saveableTexture =
698 m_globalNameSpace.getSaveableTextureFromLoad(globalName);
699 eglImg->needRestore = true;
700 return std::make_pair(hndl, std::move(eglImg));
701 });
702 }
703
postLoadAllImages(android::base::Stream * stream)704 void EglDisplay::postLoadAllImages(android::base::Stream* stream) {
705 m_globalNameSpace.postLoad(stream);
706 }
707
nativeTextureDecompressionEnabled() const708 bool EglDisplay::nativeTextureDecompressionEnabled() const {
709 return m_nativeTextureDecompressionEnabled;
710 }
711
setNativeTextureDecompressionEnabled(bool enabled)712 void EglDisplay::setNativeTextureDecompressionEnabled(bool enabled) {
713 m_nativeTextureDecompressionEnabled = enabled;
714 }
715
programBinaryLinkStatusEnabled() const716 bool EglDisplay::programBinaryLinkStatusEnabled() const {
717 return m_programBinaryLinkStatusEnabled;
718 }
719
setProgramBinaryLinkStatusEnabled(bool enabled)720 void EglDisplay::setProgramBinaryLinkStatusEnabled(bool enabled) {
721 m_programBinaryLinkStatusEnabled = enabled;
722 }
723