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 "EglOsApi.h"
17 
18 #include "aemu/base/synchronization/Lock.h"
19 #include "aemu/base/SharedLibrary.h"
20 #include "host-common/logging.h"
21 
22 #include "CoreProfileConfigs.h"
23 #include "GLcommon/GLLibrary.h"
24 #include "X11ErrorHandler.h"
25 
26 #include "X11Support.h"
27 
28 #include <string.h>
29 #include <X11/Xlib.h>
30 #include <GL/glx.h>
31 
32 #include <EGL/eglext.h>
33 
34 #include <algorithm>
35 #include <unordered_map>
36 #include <vector>
37 
38 #define DEBUG_PBUF_POOL 0
39 
40 // TODO: Replace with latency tracker.
41 #define PROFILE_SLOW(tag)
42 
43 namespace {
44 
45 typedef Display X11Display;
46 
47 #define IS_SUCCESS(a) \
48         do { if (a != Success) return 0; } while (0)
49 
50 #define EXIT_IF_FALSE(a) \
51         do { if (a != Success) return; } while (0)
52 
53 class GlxLibrary : public GlLibrary {
54 public:
55     typedef GlFunctionPointer (ResolverFunc)(const char* name);
56 
57     // Important: Use libGL.so.1 explicitly, because it will always link to
58     // the vendor-specific version of the library. libGL.so might in some
59     // cases, depending on bad ldconfig configurations, link to the wrapper
60     // lib that doesn't behave the same.
GlxLibrary()61     GlxLibrary() {
62         static const char kLibName[] = "libGL.so.1";
63         char error[256];
64         mLib = android::base::SharedLibrary::open(kLibName, error, sizeof(error));
65         if (!mLib) {
66             ERR("%s: Could not open GL library %s [%s]\n",
67                 __func__, kLibName, error);
68             return;
69         }
70         // NOTE: Don't use glXGetProcAddress here, only glXGetProcAddressARB
71         // is guaranteed to be supported by vendor-specific libraries.
72         static const char kResolverName[] = "glXGetProcAddressARB";
73         mResolver = reinterpret_cast<ResolverFunc*>(
74                 mLib->findSymbol(kResolverName));
75         if (!mResolver) {
76             ERR("%s: Could not find resolver %s in %s\n",
77                 __func__, kResolverName, kLibName);
78             mLib = NULL;
79         }
80     }
81 
~GlxLibrary()82     ~GlxLibrary() {
83     }
84 
85     // override
findSymbol(const char * name)86     virtual GlFunctionPointer findSymbol(const char* name) {
87         if (!mLib) {
88             return NULL;
89         }
90         GlFunctionPointer ret = (*mResolver)(name);
91         if (!ret) {
92             ret = reinterpret_cast<GlFunctionPointer>(mLib->findSymbol(name));
93         }
94         return ret;
95     }
96 
97 private:
98     android::base::SharedLibrary* mLib = nullptr;
99     ResolverFunc* mResolver = nullptr;
100 };
101 
sGlxLibrary()102 static GlxLibrary* sGlxLibrary() {
103     static GlxLibrary* l = new GlxLibrary;
104     return l;
105 }
106 
107 // Implementation of EglOS::PixelFormat based on GLX.
108 class GlxPixelFormat : public EglOS::PixelFormat {
109 public:
GlxPixelFormat(GLXFBConfig fbconfig)110     explicit GlxPixelFormat(GLXFBConfig fbconfig) : mFbConfig(fbconfig) {}
111 
clone()112     virtual EglOS::PixelFormat* clone() {
113         return new GlxPixelFormat(mFbConfig);
114     }
115 
fbConfig() const116     GLXFBConfig fbConfig() const { return mFbConfig; }
117 
from(const EglOS::PixelFormat * f)118     static GLXFBConfig from(const EglOS::PixelFormat* f) {
119         return static_cast<const GlxPixelFormat*>(f)->fbConfig();
120     }
121 
122 private:
123     GLXFBConfig mFbConfig = nullptr;
124 };
125 
126 // Implementation of EglOS::Surface based on GLX.
127 class GlxSurface : public EglOS::Surface {
128 public:
GlxSurface(GLXDrawable drawable,GLXFBConfig fbConfig,SurfaceType type)129     GlxSurface(GLXDrawable drawable, GLXFBConfig fbConfig, SurfaceType type) :
130             Surface(type), mFbConfig(fbConfig), mDrawable(drawable) {}
131 
drawable() const132     GLXDrawable drawable() const { return mDrawable; }
config() const133     GLXFBConfig config() const { return mFbConfig; }
134 
135     // Helper routine to down-cast an EglOS::Surface and extract
136     // its drawable.
drawableFor(EglOS::Surface * surface)137     static GLXDrawable drawableFor(EglOS::Surface* surface) {
138         return static_cast<GlxSurface*>(surface)->drawable();
139     }
140 
141     // Helper routine to down-cast an EglOS::Surface and extract
142     // its config.
configFor(EglOS::Surface * surface)143     static GLXFBConfig configFor(EglOS::Surface* surface) {
144         return static_cast<GlxSurface*>(surface)->config();
145     }
146 
147 private:
148     GLXFBConfig mFbConfig = 0;
149     GLXDrawable mDrawable = 0;
150 };
151 
pixelFormatToConfig(EGLNativeDisplayType dpy,int renderableType,GLXFBConfig frmt,EglOS::AddConfigCallback * addConfigFunc,void * addConfigOpaque)152 void pixelFormatToConfig(EGLNativeDisplayType dpy,
153                          int renderableType,
154                          GLXFBConfig frmt,
155                          EglOS::AddConfigCallback* addConfigFunc,
156                          void* addConfigOpaque) {
157     EglOS::ConfigInfo info;
158     int  tmp;
159 
160     memset(&info, 0, sizeof(info));
161 
162     auto glx = getGlxApi();
163 
164     EXIT_IF_FALSE(glx->glXGetFBConfigAttrib((Display*)dpy, frmt, GLX_TRANSPARENT_TYPE, &tmp));
165     if (tmp == GLX_TRANSPARENT_INDEX) {
166         return; // not supporting transparent index
167     } else if (tmp == GLX_NONE) {
168         info.transparent_type = EGL_NONE;
169         info.trans_red_val = 0;
170         info.trans_green_val = 0;
171         info.trans_blue_val = 0;
172     } else {
173         info.transparent_type = EGL_TRANSPARENT_RGB;
174 
175         EXIT_IF_FALSE(glx->glXGetFBConfigAttrib((Display*)dpy, frmt, GLX_TRANSPARENT_RED_VALUE,
176                                                 &info.trans_red_val));
177         EXIT_IF_FALSE(glx->glXGetFBConfigAttrib((Display*)dpy, frmt, GLX_TRANSPARENT_GREEN_VALUE,
178                                                 &info.trans_green_val));
179         EXIT_IF_FALSE(glx->glXGetFBConfigAttrib((Display*)dpy, frmt, GLX_TRANSPARENT_BLUE_VALUE,
180                                                 &info.trans_blue_val));
181     }
182 
183     //
184     // filter out single buffer configurations
185     //
186     int doubleBuffer = 0;
187     EXIT_IF_FALSE(glx->glXGetFBConfigAttrib((Display*)dpy, frmt, GLX_DOUBLEBUFFER, &doubleBuffer));
188     if (!doubleBuffer) {
189         return;
190     }
191 
192     EXIT_IF_FALSE(glx->glXGetFBConfigAttrib((Display*)dpy, frmt, GLX_RED_SIZE, &info.red_size));
193     EXIT_IF_FALSE(glx->glXGetFBConfigAttrib((Display*)dpy, frmt, GLX_GREEN_SIZE, &info.green_size));
194     EXIT_IF_FALSE(glx->glXGetFBConfigAttrib((Display*)dpy, frmt, GLX_BLUE_SIZE, &info.blue_size));
195     EXIT_IF_FALSE(glx->glXGetFBConfigAttrib((Display*)dpy, frmt, GLX_ALPHA_SIZE, &info.alpha_size));
196     EXIT_IF_FALSE(glx->glXGetFBConfigAttrib((Display*)dpy, frmt, GLX_DEPTH_SIZE, &info.depth_size));
197     EXIT_IF_FALSE(
198         glx->glXGetFBConfigAttrib((Display*)dpy, frmt, GLX_STENCIL_SIZE, &info.stencil_size));
199 
200     info.renderable_type = renderableType;
201     int nativeRenderable = 0;
202     EXIT_IF_FALSE(
203         glx->glXGetFBConfigAttrib((Display*)dpy, frmt, GLX_X_RENDERABLE, &nativeRenderable));
204     info.native_renderable = !!nativeRenderable;
205 
206     EXIT_IF_FALSE(glx->glXGetFBConfigAttrib((Display*)dpy, frmt, GLX_X_VISUAL_TYPE,
207                                             &info.native_visual_type));
208 
209     EXIT_IF_FALSE(
210         glx->glXGetFBConfigAttrib((Display*)dpy, frmt, GLX_VISUAL_ID, &info.native_visual_id));
211 
212     //supported surfaces types
213     info.surface_type = 0;
214     EXIT_IF_FALSE(glx->glXGetFBConfigAttrib((Display*)dpy, frmt, GLX_DRAWABLE_TYPE, &tmp));
215     if (tmp & GLX_WINDOW_BIT && info.native_visual_id != 0) {
216         info.surface_type |= EGL_WINDOW_BIT;
217     } else {
218         info.native_visual_id = 0;
219         info.native_visual_type = EGL_NONE;
220     }
221     if (tmp & GLX_PBUFFER_BIT) {
222         info.surface_type |= EGL_PBUFFER_BIT;
223     }
224 
225     info.caveat = 0;
226     EXIT_IF_FALSE(glx->glXGetFBConfigAttrib((Display*)dpy, frmt, GLX_CONFIG_CAVEAT, &tmp));
227     if (tmp == GLX_NONE) {
228         info.caveat = EGL_NONE;
229     } else if (tmp == GLX_SLOW_CONFIG) {
230         info.caveat = EGL_SLOW_CONFIG;
231     } else if (tmp == GLX_NON_CONFORMANT_CONFIG) {
232         info.caveat = EGL_NON_CONFORMANT_CONFIG;
233     }
234     EXIT_IF_FALSE(glx->glXGetFBConfigAttrib((Display*)dpy, frmt, GLX_MAX_PBUFFER_WIDTH,
235                                             &info.max_pbuffer_width));
236     EXIT_IF_FALSE(glx->glXGetFBConfigAttrib((Display*)dpy, frmt, GLX_MAX_PBUFFER_HEIGHT,
237                                             &info.max_pbuffer_height));
238     EXIT_IF_FALSE(glx->glXGetFBConfigAttrib((Display*)dpy, frmt, GLX_MAX_PBUFFER_HEIGHT,
239                                             &info.max_pbuffer_size));
240 
241     EXIT_IF_FALSE(
242         glx->glXGetFBConfigAttrib((Display*)dpy, frmt, GLX_LEVEL, &info.frame_buffer_level));
243 
244     EXIT_IF_FALSE(
245         glx->glXGetFBConfigAttrib((Display*)dpy, frmt, GLX_SAMPLES, &info.samples_per_pixel));
246 
247     // Filter out configs that do not support RGBA
248     EXIT_IF_FALSE(glx->glXGetFBConfigAttrib((Display*)dpy, frmt, GLX_RENDER_TYPE, &tmp));
249     if (!(tmp & GLX_RGBA_BIT)) {
250         return;
251     }
252     // Filter out configs that do not support depthstencil buffers
253     // For dEQP-GLES2.functional.depth_stencil_clear
254     // and dEQP-GLES2.usecases.*
255     if (info.depth_size == 0 || info.stencil_size == 0) {
256         return;
257     }
258 
259     info.frmt = new GlxPixelFormat(frmt);
260     (*addConfigFunc)(addConfigOpaque, &info);
261 }
262 
263 // Implementation of EglOS::Context based on GLX.
264 class GlxContext : public EglOS::Context {
265 public:
GlxContext(X11Display * display,GLXContext context)266     explicit GlxContext(X11Display* display,
267                         GLXContext context) :
268         mDisplay(display),
269         mContext(context) {}
270 
context() const271     GLXContext context() const { return mContext; }
272 
~GlxContext()273     virtual ~GlxContext() {
274         PROFILE_SLOW("~GlxContext()");
275         getGlxApi()->glXDestroyContext(mDisplay, mContext);
276     }
277 
contextFor(EglOS::Context * context)278     static GLXContext contextFor(EglOS::Context* context) {
279         return static_cast<GlxContext*>(context)->context();
280     }
281 private:
282     X11Display* mDisplay = nullptr;
283     GLXContext mContext = nullptr;
284 };
285 
286 
287 // Implementation of EglOS::Display based on GLX.
288 class GlxDisplay : public EglOS::Display {
289 public:
GlxDisplay(X11Display * disp)290     explicit GlxDisplay(X11Display* disp) : mDisplay(disp) {}
291 
~GlxDisplay()292     virtual ~GlxDisplay() {
293         PROFILE_SLOW("displayCleanup");
294 
295         for (auto it : mLivePbufs)  {
296             for (auto surf : it.second) {
297                 getGlxApi()->glXDestroyPbuffer(mDisplay,
298                         GlxSurface::drawableFor(surf));
299             }
300         }
301 
302         for (auto it : mFreePbufs)  {
303             for (auto surf : it.second) {
304                 getGlxApi()->glXDestroyPbuffer(mDisplay,
305                         GlxSurface::drawableFor(surf));
306             }
307         }
308 
309         getX11Api()->XCloseDisplay(mDisplay);
310     }
311 
getMaxGlesVersion()312     virtual EglOS::GlesVersion getMaxGlesVersion() {
313         if (!mCoreProfileSupported) {
314             return EglOS::GlesVersion::ES2;
315         }
316 
317         return EglOS::calcMaxESVersionFromCoreVersion(
318                    mCoreMajorVersion, mCoreMinorVersion);
319     }
320 
queryConfigs(int renderableType,EglOS::AddConfigCallback * addConfigFunc,void * addConfigOpaque)321     virtual void queryConfigs(int renderableType,
322                               EglOS::AddConfigCallback* addConfigFunc,
323                               void* addConfigOpaque) {
324         int n;
325         auto glx = getGlxApi();
326 
327         GLXFBConfig* frmtList = glx->glXGetFBConfigs(mDisplay, DefaultScreen(mDisplay), &n);
328         if (frmtList) {
329             mFBConfigs.assign(frmtList, frmtList + n);
330             for(int i = 0; i < n; i++) {
331                 pixelFormatToConfig(
332                         mDisplay,
333                         renderableType,
334                         frmtList[i],
335                         addConfigFunc,
336                         addConfigOpaque);
337             }
338             getX11Api()->XFree(frmtList);
339         }
340 
341         int glxMaj, glxMin;
342         bool successQueryVersion =
343             glx->glXQueryVersion(mDisplay,
344                             &glxMaj,
345                             &glxMin);
346 
347         if (successQueryVersion) {
348             if (glxMaj < 1 || (glxMaj >= 1 && glxMin < 4)) {
349                 // core profile not supported in this GLX.
350                 mCoreProfileSupported = false;
351             } else {
352                 queryCoreProfileSupport();
353             }
354         } else {
355             ERR("%s: Could not query GLX version!\n", __func__);
356         }
357     }
358 
isValidNativeWin(EglOS::Surface * win)359     virtual bool isValidNativeWin(EglOS::Surface* win) {
360         if (!win) {
361             return false;
362         } else {
363             return isValidNativeWin(GlxSurface::drawableFor(win));
364         }
365     }
366 
isValidNativeWin(EGLNativeWindowType win)367     virtual bool isValidNativeWin(EGLNativeWindowType win) {
368         Window root;
369         int t;
370         unsigned int u;
371         X11ErrorHandler handler(mDisplay);
372         if (!getX11Api()->XGetGeometry(mDisplay, win, &root, &t, &t, &u, &u, &u, &u)) {
373             return false;
374         }
375         return handler.getLastError() == 0;
376     }
377 
checkWindowPixelFormatMatch(EGLNativeWindowType win,const EglOS::PixelFormat * pixelFormat,unsigned int * width,unsigned int * height)378     virtual bool checkWindowPixelFormatMatch(
379             EGLNativeWindowType win,
380             const EglOS::PixelFormat* pixelFormat,
381             unsigned int* width,
382             unsigned int* height) {
383         //TODO: to check what does ATI & NVIDIA enforce on win pixelformat
384         unsigned int depth, configDepth, border;
385         int r, g, b, x, y;
386         GLXFBConfig fbconfig = GlxPixelFormat::from(pixelFormat);
387         auto glx = getGlxApi();
388 
389         IS_SUCCESS(glx->glXGetFBConfigAttrib(
390                 mDisplay, fbconfig, GLX_RED_SIZE, &r));
391         IS_SUCCESS(glx->glXGetFBConfigAttrib(
392                 mDisplay, fbconfig, GLX_GREEN_SIZE, &g));
393         IS_SUCCESS(glx->glXGetFBConfigAttrib(
394                 mDisplay, fbconfig, GLX_BLUE_SIZE, &b));
395         configDepth = r + g + b;
396         Window root;
397         if (!getX11Api()->XGetGeometry(
398                 mDisplay, win, &root, &x, &y, width, height, &border, &depth)) {
399             return false;
400         }
401         return depth >= configDepth;
402     }
403 
createContext(EGLint profileMask,const EglOS::PixelFormat * pixelFormat,EglOS::Context * sharedContext)404     virtual std::shared_ptr<EglOS::Context> createContext(
405             EGLint profileMask,
406             const EglOS::PixelFormat* pixelFormat,
407             EglOS::Context* sharedContext) {
408         PROFILE_SLOW("createContext");
409 
410         bool useCoreProfile = mCoreProfileSupported &&
411            (profileMask & EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR);
412 
413         X11ErrorHandler handler(mDisplay);
414 
415         auto glx = getGlxApi();
416 
417         GLXContext ctx;
418         if (useCoreProfile) {
419             ctx = mCreateContextAttribs(
420                         mDisplay,
421                         GlxPixelFormat::from(pixelFormat),
422                         sharedContext ? GlxContext::contextFor(sharedContext) : NULL,
423                         True /* try direct (supposed to fall back to indirect) */,
424                         mCoreProfileCtxAttribs);
425         } else {
426             ctx = glx->glXCreateNewContext(
427                     mDisplay,
428                     GlxPixelFormat::from(pixelFormat),
429                     GLX_RGBA_TYPE,
430                     sharedContext ? GlxContext::contextFor(sharedContext) : NULL,
431                     true);
432         }
433 
434         if (handler.getLastError()) {
435             return NULL;
436         }
437 
438         return std::make_shared<GlxContext>(mDisplay, ctx);
439     }
440 
destroyContext(EglOS::Context * context)441     virtual bool destroyContext(EglOS::Context* context) {
442         PROFILE_SLOW("destroyContext");
443         getGlxApi()->glXDestroyContext(mDisplay, GlxContext::contextFor(context));
444         return true;
445     }
446 
debugCountPbufs(const char * eventName,GLXFBConfig config)447     void debugCountPbufs(const char* eventName, GLXFBConfig config) {
448 #if DEBUG_PBUF_POOL
449         size_t pbufsFree = 0;
450         size_t pbufsLive = 0;
451 
452         for (const auto it: mFreePbufs) {
453             pbufsFree += it.second.size();
454         }
455 
456         for (const auto it: mLivePbufs) {
457             pbufsLive += it.second.size();
458         }
459 
460         fprintf(stderr, "event: %s config: %p Pbuffer counts: free: %zu live: %zu\n",
461                 eventName, config, pbufsFree, pbufsLive);
462 #endif
463     }
464 
createPbufferSurface(const EglOS::PixelFormat * pixelFormat,const EglOS::PbufferInfo * info)465     virtual EglOS::Surface* createPbufferSurface(
466             const EglOS::PixelFormat* pixelFormat,
467             const EglOS::PbufferInfo* info) {
468 
469         android::base::AutoLock lock(mPbufLock);
470 
471         GLXFBConfig config = GlxPixelFormat::from(pixelFormat);
472 
473         debugCountPbufs("about to create", config);
474 
475         bool needPrime = false;
476         if (mFreePbufs.find(config) == mFreePbufs.end()) {
477             needPrime = true;
478         }
479 
480         auto& freeElts = mFreePbufs[config];
481 
482         if (freeElts.size() == 0) {
483             needPrime = true;
484         }
485 
486         if (needPrime) {
487             PROFILE_SLOW("createPbufferSurface (slow path)");
488             // Double the # pbufs of this config, or create |mPbufPrimingCount|
489             // of them, whichever is higher.
490             int toCreate = std::max((int)mLivePbufs[config].size(),
491                                     mPbufPrimingCount);
492             for (int i = 0; i < toCreate; i++) {
493                 freeElts.push_back(createPbufferSurfaceImpl(config));
494             }
495         }
496 
497         PROFILE_SLOW("createPbufferSurface (fast path)");
498         EglOS::Surface* surf = freeElts.back();
499         freeElts.pop_back();
500 
501         auto& forLive = mLivePbufs[config];
502         forLive.push_back(surf);
503 
504         return surf;
505     }
506 
releasePbuffer(EglOS::Surface * pb)507     virtual bool releasePbuffer(EglOS::Surface* pb) {
508 
509         android::base::AutoLock lock(mPbufLock);
510 
511         PROFILE_SLOW("releasePbuffer");
512         if (!pb) {
513             return false;
514         } else {
515             GLXFBConfig config = GlxSurface::configFor(pb);
516 
517             debugCountPbufs("about to release", config);
518 
519             auto& frees = mFreePbufs[config];
520             frees.push_back(pb);
521 
522             auto& forLive = mLivePbufs[config];
523             forLive.erase(std::remove(forLive.begin(), forLive.end(), pb), forLive.end());
524             return true;
525         }
526     }
527 
makeCurrent(EglOS::Surface * read,EglOS::Surface * draw,EglOS::Context * context)528     virtual bool makeCurrent(EglOS::Surface* read,
529                              EglOS::Surface* draw,
530                              EglOS::Context* context) {
531         PROFILE_SLOW("makeCurrent");
532         X11ErrorHandler handler(mDisplay);
533         bool retval = false;
534         auto glx = getGlxApi();
535 
536         if (!context && !read && !draw) {
537             // unbind
538             retval = glx->glXMakeContextCurrent(mDisplay, 0, 0, NULL);
539         }
540         else if (context && read && draw) {
541             retval = glx->glXMakeContextCurrent(
542                     mDisplay,
543                     GlxSurface::drawableFor(draw),
544                     GlxSurface::drawableFor(read),
545                     GlxContext::contextFor(context));
546             if (mSwapInterval && draw->type() == GlxSurface::SurfaceType::WINDOW) {
547                 android::base::AutoLock lock(mPbufLock);
548                 auto it = mDisabledVsyncWindows.find(draw);
549                 bool notPresent = it == mDisabledVsyncWindows.end();
550                 if (notPresent || !it->second) {
551                     mSwapInterval(mDisplay, GlxSurface::drawableFor(draw), 0);
552                     if (notPresent) {
553                         mDisabledVsyncWindows[draw] = true;
554                     } else {
555                         it->second = true;
556                     }
557                 }
558             }
559         }
560         int err = handler.getLastError();
561         return (err == 0) && retval;
562     }
563 
swapBuffers(EglOS::Surface * srfc)564     virtual void swapBuffers(EglOS::Surface* srfc) {
565         if (srfc) {
566             getGlxApi()->glXSwapBuffers(mDisplay, GlxSurface::drawableFor(srfc));
567         }
568     }
569 
570 private:
571     using CreateContextAttribs =
572         GLXContext (*)(X11Display*, GLXFBConfig, GLXContext, Bool, const int*);
573     using SwapInterval =
574         void (*)(X11Display*, GLXDrawable, int);
575 
576     // Returns the highest level of OpenGL core profile support in
577     // this GLX implementation.
queryCoreProfileSupport()578     void queryCoreProfileSupport() {
579         mCoreProfileSupported = false;
580         X11ErrorHandler handler(mDisplay);
581 
582         GlxLibrary* lib = sGlxLibrary();
583         mCreateContextAttribs =
584             (CreateContextAttribs)lib->findSymbol("glXCreateContextAttribsARB");
585         mSwapInterval =
586             (SwapInterval)lib->findSymbol("glXSwapIntervalEXT");
587 
588         if (!mCreateContextAttribs || mFBConfigs.size() == 0) return;
589 
590         if (!mSwapInterval) {
591             fprintf(stderr, "%s: swap interval not found\n", __func__);
592         }
593 
594         // Ascending index order of context attribs :
595         // decreasing GL major/minor version
596         GLXContext testContext = nullptr;
597 
598         for (int i = 0; i < getNumCoreProfileCtxAttribs(); i++) {
599             const int* attribs = getCoreProfileCtxAttribs(i);
600             testContext =
601                 mCreateContextAttribs(
602                         mDisplay, mFBConfigs[0],
603                         nullptr /* no shared context */,
604                         True /* try direct (supposed to fall back to indirect) */,
605                         attribs);
606 
607             if (testContext) {
608                 mCoreProfileSupported = true;
609                 mCoreProfileCtxAttribs = attribs;
610                 getCoreProfileCtxAttribsVersion(
611                     attribs, &mCoreMajorVersion, &mCoreMinorVersion);
612                 getGlxApi()->glXDestroyContext(mDisplay, testContext);
613                 return;
614             }
615         }
616     }
617 
createPbufferSurfaceImpl(GLXFBConfig config)618     EglOS::Surface* createPbufferSurfaceImpl(GLXFBConfig config) {
619         // we never care about width or height, since we just use
620         // opengl fbos anyway.
621         static const int pbufferImplAttribs[] = {
622             GLX_PBUFFER_WIDTH, 1,
623             GLX_PBUFFER_HEIGHT, 1,
624             GLX_LARGEST_PBUFFER, 0,
625             None
626         };
627 
628         GLXPbuffer pb;
629         pb = getGlxApi()->glXCreatePbuffer(
630             mDisplay,
631             config,
632             pbufferImplAttribs);
633 
634         return new GlxSurface(pb, config, GlxSurface::PBUFFER);
635     }
636 
637     CreateContextAttribs mCreateContextAttribs = nullptr;
638     SwapInterval mSwapInterval = nullptr;
639 
640     bool mCoreProfileSupported = false;
641     int mCoreMajorVersion = 4;
642     int mCoreMinorVersion = 5;
643     const int* mCoreProfileCtxAttribs = nullptr;
644 
645     X11Display* mDisplay = nullptr;
646     std::vector<GLXFBConfig> mFBConfigs;
647     std::unordered_map<GLXFBConfig, std::vector<EglOS::Surface* > > mFreePbufs;
648     std::unordered_map<GLXFBConfig, std::vector<EglOS::Surface* > > mLivePbufs;
649     int mPbufPrimingCount = 8;
650     android::base::Lock mPbufLock;
651     std::unordered_map<EglOS::Surface*, bool> mDisabledVsyncWindows;
652 };
653 
654 class GlxEngine : public EglOS::Engine {
655 public:
getDefaultDisplay()656     virtual EglOS::Display* getDefaultDisplay() {
657         Display* disp =
658             getX11Api()->XOpenDisplay(0 /* default display or $DISPLAY env var */);
659         if (!disp) {
660             fprintf(stderr,
661                     "GlxEngine%s: Failed to open display 0. DISPLAY: [%s]\n",
662                     __func__, getenv("DISPLAY"));
663             return nullptr;
664         }
665         return new GlxDisplay(disp);
666     }
667 
getGlLibrary()668     virtual GlLibrary* getGlLibrary() {
669         return sGlxLibrary();
670     }
671 
eglGetProcAddress(const char *)672     virtual void* eglGetProcAddress(const char*) {
673         return 0;
674     }
675 
createWindowSurface(EglOS::PixelFormat * pf,EGLNativeWindowType wnd)676     virtual EglOS::Surface* createWindowSurface(EglOS::PixelFormat* pf,
677                                                 EGLNativeWindowType wnd) {
678         return new GlxSurface(wnd, 0, GlxSurface::WINDOW);
679     }
680 };
681 
sHostEngine()682 static GlxEngine* sHostEngine() {
683     static GlxEngine* e = new GlxEngine;
684     return e;
685 }
686 
687 }  // namespace
688 
689 // static
getHostInstance()690 EglOS::Engine* EglOS::Engine::getHostInstance() {
691     return sHostEngine();
692 }
693