• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "apigen-codec-common/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(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(
176                 dpy, frmt, GLX_TRANSPARENT_RED_VALUE, &info.trans_red_val));
177         EXIT_IF_FALSE(glx->glXGetFBConfigAttrib(
178                 dpy, frmt, GLX_TRANSPARENT_GREEN_VALUE, &info.trans_green_val));
179         EXIT_IF_FALSE(glx->glXGetFBConfigAttrib(
180                 dpy, frmt, GLX_TRANSPARENT_BLUE_VALUE, &info.trans_blue_val));
181     }
182 
183     //
184     // filter out single buffer configurations
185     //
186     int doubleBuffer = 0;
187     EXIT_IF_FALSE(glx->glXGetFBConfigAttrib(
188             dpy, frmt, GLX_DOUBLEBUFFER, &doubleBuffer));
189     if (!doubleBuffer) {
190         return;
191     }
192 
193     EXIT_IF_FALSE(glx->glXGetFBConfigAttrib(
194             dpy ,frmt, GLX_RED_SIZE, &info.red_size));
195     EXIT_IF_FALSE(glx->glXGetFBConfigAttrib(
196             dpy ,frmt, GLX_GREEN_SIZE, &info.green_size));
197     EXIT_IF_FALSE(glx->glXGetFBConfigAttrib(
198             dpy ,frmt, GLX_BLUE_SIZE, &info.blue_size));
199     EXIT_IF_FALSE(glx->glXGetFBConfigAttrib(
200             dpy ,frmt, GLX_ALPHA_SIZE, &info.alpha_size));
201     EXIT_IF_FALSE(glx->glXGetFBConfigAttrib(
202             dpy ,frmt, GLX_DEPTH_SIZE, &info.depth_size));
203     EXIT_IF_FALSE(glx->glXGetFBConfigAttrib(
204             dpy ,frmt, GLX_STENCIL_SIZE, &info.stencil_size));
205 
206     info.renderable_type = renderableType;
207     int nativeRenderable = 0;
208     EXIT_IF_FALSE(glx->glXGetFBConfigAttrib(
209             dpy, frmt, GLX_X_RENDERABLE, &nativeRenderable));
210     info.native_renderable = !!nativeRenderable;
211 
212     EXIT_IF_FALSE(glx->glXGetFBConfigAttrib(
213             dpy, frmt, GLX_X_VISUAL_TYPE, &info.native_visual_type));
214 
215     EXIT_IF_FALSE(glx->glXGetFBConfigAttrib(
216             dpy, frmt, GLX_VISUAL_ID, &info.native_visual_id));
217 
218     //supported surfaces types
219     info.surface_type = 0;
220     EXIT_IF_FALSE(glx->glXGetFBConfigAttrib(dpy, frmt, GLX_DRAWABLE_TYPE, &tmp));
221     if (tmp & GLX_WINDOW_BIT && info.native_visual_id != 0) {
222         info.surface_type |= EGL_WINDOW_BIT;
223     } else {
224         info.native_visual_id = 0;
225         info.native_visual_type = EGL_NONE;
226     }
227     if (tmp & GLX_PBUFFER_BIT) {
228         info.surface_type |= EGL_PBUFFER_BIT;
229     }
230 
231     info.caveat = 0;
232     EXIT_IF_FALSE(glx->glXGetFBConfigAttrib(dpy, frmt, GLX_CONFIG_CAVEAT, &tmp));
233     if (tmp == GLX_NONE) {
234         info.caveat = EGL_NONE;
235     } else if (tmp == GLX_SLOW_CONFIG) {
236         info.caveat = EGL_SLOW_CONFIG;
237     } else if (tmp == GLX_NON_CONFORMANT_CONFIG) {
238         info.caveat = EGL_NON_CONFORMANT_CONFIG;
239     }
240     EXIT_IF_FALSE(glx->glXGetFBConfigAttrib(
241             dpy, frmt, GLX_MAX_PBUFFER_WIDTH, &info.max_pbuffer_width));
242     EXIT_IF_FALSE(glx->glXGetFBConfigAttrib(
243             dpy, frmt, GLX_MAX_PBUFFER_HEIGHT, &info.max_pbuffer_height));
244     EXIT_IF_FALSE(glx->glXGetFBConfigAttrib(
245             dpy, frmt, GLX_MAX_PBUFFER_HEIGHT, &info.max_pbuffer_size));
246 
247     EXIT_IF_FALSE(glx->glXGetFBConfigAttrib(
248             dpy, frmt, GLX_LEVEL, &info.frame_buffer_level));
249 
250     EXIT_IF_FALSE(glx->glXGetFBConfigAttrib(
251             dpy, frmt, GLX_SAMPLES, &info.samples_per_pixel));
252 
253     // Filter out configs that do not support RGBA
254     EXIT_IF_FALSE(glx->glXGetFBConfigAttrib(dpy, frmt, GLX_RENDER_TYPE, &tmp));
255     if (!(tmp & GLX_RGBA_BIT)) {
256         return;
257     }
258     // Filter out configs that do not support depthstencil buffers
259     // For dEQP-GLES2.functional.depth_stencil_clear
260     // and dEQP-GLES2.usecases.*
261     if (info.depth_size == 0 || info.stencil_size == 0) {
262         return;
263     }
264 
265     info.frmt = new GlxPixelFormat(frmt);
266     (*addConfigFunc)(addConfigOpaque, &info);
267 }
268 
269 // Implementation of EglOS::Context based on GLX.
270 class GlxContext : public EglOS::Context {
271 public:
GlxContext(X11Display * display,GLXContext context)272     explicit GlxContext(X11Display* display,
273                         GLXContext context) :
274         mDisplay(display),
275         mContext(context) {}
276 
context() const277     GLXContext context() const { return mContext; }
278 
~GlxContext()279     virtual ~GlxContext() {
280         PROFILE_SLOW("~GlxContext()");
281         getGlxApi()->glXDestroyContext(mDisplay, mContext);
282     }
283 
contextFor(EglOS::Context * context)284     static GLXContext contextFor(EglOS::Context* context) {
285         return static_cast<GlxContext*>(context)->context();
286     }
287 private:
288     X11Display* mDisplay = nullptr;
289     GLXContext mContext = nullptr;
290 };
291 
292 
293 // Implementation of EglOS::Display based on GLX.
294 class GlxDisplay : public EglOS::Display {
295 public:
GlxDisplay(X11Display * disp)296     explicit GlxDisplay(X11Display* disp) : mDisplay(disp) {}
297 
~GlxDisplay()298     virtual ~GlxDisplay() {
299         PROFILE_SLOW("displayCleanup");
300 
301         for (auto it : mLivePbufs)  {
302             for (auto surf : it.second) {
303                 getGlxApi()->glXDestroyPbuffer(mDisplay,
304                         GlxSurface::drawableFor(surf));
305             }
306         }
307 
308         for (auto it : mFreePbufs)  {
309             for (auto surf : it.second) {
310                 getGlxApi()->glXDestroyPbuffer(mDisplay,
311                         GlxSurface::drawableFor(surf));
312             }
313         }
314 
315         getX11Api()->XCloseDisplay(mDisplay);
316     }
317 
getMaxGlesVersion()318     virtual EglOS::GlesVersion getMaxGlesVersion() {
319         if (!mCoreProfileSupported) {
320             return EglOS::GlesVersion::ES2;
321         }
322 
323         return EglOS::calcMaxESVersionFromCoreVersion(
324                    mCoreMajorVersion, mCoreMinorVersion);
325     }
326 
queryConfigs(int renderableType,EglOS::AddConfigCallback * addConfigFunc,void * addConfigOpaque)327     virtual void queryConfigs(int renderableType,
328                               EglOS::AddConfigCallback* addConfigFunc,
329                               void* addConfigOpaque) {
330         int n;
331         auto glx = getGlxApi();
332 
333         GLXFBConfig* frmtList = glx->glXGetFBConfigs(mDisplay, DefaultScreen(mDisplay), &n);
334         if (frmtList) {
335             mFBConfigs.assign(frmtList, frmtList + n);
336             for(int i = 0; i < n; i++) {
337                 pixelFormatToConfig(
338                         mDisplay,
339                         renderableType,
340                         frmtList[i],
341                         addConfigFunc,
342                         addConfigOpaque);
343             }
344             getX11Api()->XFree(frmtList);
345         }
346 
347         int glxMaj, glxMin;
348         bool successQueryVersion =
349             glx->glXQueryVersion(mDisplay,
350                             &glxMaj,
351                             &glxMin);
352 
353         if (successQueryVersion) {
354             if (glxMaj < 1 || (glxMaj >= 1 && glxMin < 4)) {
355                 // core profile not supported in this GLX.
356                 mCoreProfileSupported = false;
357             } else {
358                 queryCoreProfileSupport();
359             }
360         } else {
361             ERR("%s: Could not query GLX version!\n", __func__);
362         }
363     }
364 
isValidNativeWin(EglOS::Surface * win)365     virtual bool isValidNativeWin(EglOS::Surface* win) {
366         if (!win) {
367             return false;
368         } else {
369             return isValidNativeWin(GlxSurface::drawableFor(win));
370         }
371     }
372 
isValidNativeWin(EGLNativeWindowType win)373     virtual bool isValidNativeWin(EGLNativeWindowType win) {
374         Window root;
375         int t;
376         unsigned int u;
377         X11ErrorHandler handler(mDisplay);
378         if (!getX11Api()->XGetGeometry(mDisplay, win, &root, &t, &t, &u, &u, &u, &u)) {
379             return false;
380         }
381         return handler.getLastError() == 0;
382     }
383 
checkWindowPixelFormatMatch(EGLNativeWindowType win,const EglOS::PixelFormat * pixelFormat,unsigned int * width,unsigned int * height)384     virtual bool checkWindowPixelFormatMatch(
385             EGLNativeWindowType win,
386             const EglOS::PixelFormat* pixelFormat,
387             unsigned int* width,
388             unsigned int* height) {
389         //TODO: to check what does ATI & NVIDIA enforce on win pixelformat
390         unsigned int depth, configDepth, border;
391         int r, g, b, x, y;
392         GLXFBConfig fbconfig = GlxPixelFormat::from(pixelFormat);
393         auto glx = getGlxApi();
394 
395         IS_SUCCESS(glx->glXGetFBConfigAttrib(
396                 mDisplay, fbconfig, GLX_RED_SIZE, &r));
397         IS_SUCCESS(glx->glXGetFBConfigAttrib(
398                 mDisplay, fbconfig, GLX_GREEN_SIZE, &g));
399         IS_SUCCESS(glx->glXGetFBConfigAttrib(
400                 mDisplay, fbconfig, GLX_BLUE_SIZE, &b));
401         configDepth = r + g + b;
402         Window root;
403         if (!getX11Api()->XGetGeometry(
404                 mDisplay, win, &root, &x, &y, width, height, &border, &depth)) {
405             return false;
406         }
407         return depth >= configDepth;
408     }
409 
createContext(EGLint profileMask,const EglOS::PixelFormat * pixelFormat,EglOS::Context * sharedContext)410     virtual std::shared_ptr<EglOS::Context> createContext(
411             EGLint profileMask,
412             const EglOS::PixelFormat* pixelFormat,
413             EglOS::Context* sharedContext) {
414         PROFILE_SLOW("createContext");
415 
416         bool useCoreProfile = mCoreProfileSupported &&
417            (profileMask & EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR);
418 
419         X11ErrorHandler handler(mDisplay);
420 
421         auto glx = getGlxApi();
422 
423         GLXContext ctx;
424         if (useCoreProfile) {
425             ctx = mCreateContextAttribs(
426                         mDisplay,
427                         GlxPixelFormat::from(pixelFormat),
428                         sharedContext ? GlxContext::contextFor(sharedContext) : NULL,
429                         True /* try direct (supposed to fall back to indirect) */,
430                         mCoreProfileCtxAttribs);
431         } else {
432             ctx = glx->glXCreateNewContext(
433                     mDisplay,
434                     GlxPixelFormat::from(pixelFormat),
435                     GLX_RGBA_TYPE,
436                     sharedContext ? GlxContext::contextFor(sharedContext) : NULL,
437                     true);
438         }
439 
440         if (handler.getLastError()) {
441             return NULL;
442         }
443 
444         return std::make_shared<GlxContext>(mDisplay, ctx);
445     }
446 
destroyContext(EglOS::Context * context)447     virtual bool destroyContext(EglOS::Context* context) {
448         PROFILE_SLOW("destroyContext");
449         getGlxApi()->glXDestroyContext(mDisplay, GlxContext::contextFor(context));
450         return true;
451     }
452 
debugCountPbufs(const char * eventName,GLXFBConfig config)453     void debugCountPbufs(const char* eventName, GLXFBConfig config) {
454 #if DEBUG_PBUF_POOL
455         size_t pbufsFree = 0;
456         size_t pbufsLive = 0;
457 
458         for (const auto it: mFreePbufs) {
459             pbufsFree += it.second.size();
460         }
461 
462         for (const auto it: mLivePbufs) {
463             pbufsLive += it.second.size();
464         }
465 
466         fprintf(stderr, "event: %s config: %p Pbuffer counts: free: %zu live: %zu\n",
467                 eventName, config, pbufsFree, pbufsLive);
468 #endif
469     }
470 
createPbufferSurface(const EglOS::PixelFormat * pixelFormat,const EglOS::PbufferInfo * info)471     virtual EglOS::Surface* createPbufferSurface(
472             const EglOS::PixelFormat* pixelFormat,
473             const EglOS::PbufferInfo* info) {
474 
475         android::base::AutoLock lock(mPbufLock);
476 
477         GLXFBConfig config = GlxPixelFormat::from(pixelFormat);
478 
479         debugCountPbufs("about to create", config);
480 
481         bool needPrime = false;
482         if (mFreePbufs.find(config) == mFreePbufs.end()) {
483             needPrime = true;
484         }
485 
486         auto& freeElts = mFreePbufs[config];
487 
488         if (freeElts.size() == 0) {
489             needPrime = true;
490         }
491 
492         if (needPrime) {
493             PROFILE_SLOW("createPbufferSurface (slow path)");
494             // Double the # pbufs of this config, or create |mPbufPrimingCount|
495             // of them, whichever is higher.
496             int toCreate = std::max((int)mLivePbufs[config].size(),
497                                     mPbufPrimingCount);
498             for (int i = 0; i < toCreate; i++) {
499                 freeElts.push_back(createPbufferSurfaceImpl(config));
500             }
501         }
502 
503         PROFILE_SLOW("createPbufferSurface (fast path)");
504         EglOS::Surface* surf = freeElts.back();
505         freeElts.pop_back();
506 
507         auto& forLive = mLivePbufs[config];
508         forLive.push_back(surf);
509 
510         return surf;
511     }
512 
releasePbuffer(EglOS::Surface * pb)513     virtual bool releasePbuffer(EglOS::Surface* pb) {
514 
515         android::base::AutoLock lock(mPbufLock);
516 
517         PROFILE_SLOW("releasePbuffer");
518         if (!pb) {
519             return false;
520         } else {
521             GLXFBConfig config = GlxSurface::configFor(pb);
522 
523             debugCountPbufs("about to release", config);
524 
525             auto& frees = mFreePbufs[config];
526             frees.push_back(pb);
527 
528             auto& forLive = mLivePbufs[config];
529             forLive.erase(std::remove(forLive.begin(), forLive.end(), pb), forLive.end());
530             return true;
531         }
532     }
533 
makeCurrent(EglOS::Surface * read,EglOS::Surface * draw,EglOS::Context * context)534     virtual bool makeCurrent(EglOS::Surface* read,
535                              EglOS::Surface* draw,
536                              EglOS::Context* context) {
537         PROFILE_SLOW("makeCurrent");
538         X11ErrorHandler handler(mDisplay);
539         bool retval = false;
540         auto glx = getGlxApi();
541 
542         if (!context && !read && !draw) {
543             // unbind
544             retval = glx->glXMakeContextCurrent(mDisplay, 0, 0, NULL);
545         }
546         else if (context && read && draw) {
547             retval = glx->glXMakeContextCurrent(
548                     mDisplay,
549                     GlxSurface::drawableFor(draw),
550                     GlxSurface::drawableFor(read),
551                     GlxContext::contextFor(context));
552             if (mSwapInterval && draw->type() == GlxSurface::SurfaceType::WINDOW) {
553                 android::base::AutoLock lock(mPbufLock);
554                 auto it = mDisabledVsyncWindows.find(draw);
555                 bool notPresent = it == mDisabledVsyncWindows.end();
556                 if (notPresent || !it->second) {
557                     mSwapInterval(mDisplay, GlxSurface::drawableFor(draw), 0);
558                     if (notPresent) {
559                         mDisabledVsyncWindows[draw] = true;
560                     } else {
561                         it->second = true;
562                     }
563                 }
564             }
565         }
566         int err = handler.getLastError();
567         return (err == 0) && retval;
568     }
569 
swapBuffers(EglOS::Surface * srfc)570     virtual void swapBuffers(EglOS::Surface* srfc) {
571         if (srfc) {
572             getGlxApi()->glXSwapBuffers(mDisplay, GlxSurface::drawableFor(srfc));
573         }
574     }
575 
576 private:
577     using CreateContextAttribs =
578         GLXContext (*)(X11Display*, GLXFBConfig, GLXContext, Bool, const int*);
579     using SwapInterval =
580         void (*)(X11Display*, GLXDrawable, int);
581 
582     // Returns the highest level of OpenGL core profile support in
583     // this GLX implementation.
queryCoreProfileSupport()584     void queryCoreProfileSupport() {
585         mCoreProfileSupported = false;
586         X11ErrorHandler handler(mDisplay);
587 
588         GlxLibrary* lib = sGlxLibrary();
589         mCreateContextAttribs =
590             (CreateContextAttribs)lib->findSymbol("glXCreateContextAttribsARB");
591         mSwapInterval =
592             (SwapInterval)lib->findSymbol("glXSwapIntervalEXT");
593 
594         if (!mCreateContextAttribs || mFBConfigs.size() == 0) return;
595 
596         if (!mSwapInterval) {
597             fprintf(stderr, "%s: swap interval not found\n", __func__);
598         }
599 
600         // Ascending index order of context attribs :
601         // decreasing GL major/minor version
602         GLXContext testContext = nullptr;
603 
604         for (int i = 0; i < getNumCoreProfileCtxAttribs(); i++) {
605             const int* attribs = getCoreProfileCtxAttribs(i);
606             testContext =
607                 mCreateContextAttribs(
608                         mDisplay, mFBConfigs[0],
609                         nullptr /* no shared context */,
610                         True /* try direct (supposed to fall back to indirect) */,
611                         attribs);
612 
613             if (testContext) {
614                 mCoreProfileSupported = true;
615                 mCoreProfileCtxAttribs = attribs;
616                 getCoreProfileCtxAttribsVersion(
617                     attribs, &mCoreMajorVersion, &mCoreMinorVersion);
618                 getGlxApi()->glXDestroyContext(mDisplay, testContext);
619                 return;
620             }
621         }
622     }
623 
createPbufferSurfaceImpl(GLXFBConfig config)624     EglOS::Surface* createPbufferSurfaceImpl(GLXFBConfig config) {
625         // we never care about width or height, since we just use
626         // opengl fbos anyway.
627         static const int pbufferImplAttribs[] = {
628             GLX_PBUFFER_WIDTH, 1,
629             GLX_PBUFFER_HEIGHT, 1,
630             GLX_LARGEST_PBUFFER, 0,
631             None
632         };
633 
634         GLXPbuffer pb;
635         pb = getGlxApi()->glXCreatePbuffer(
636             mDisplay,
637             config,
638             pbufferImplAttribs);
639 
640         return new GlxSurface(pb, config, GlxSurface::PBUFFER);
641     }
642 
643     CreateContextAttribs mCreateContextAttribs = nullptr;
644     SwapInterval mSwapInterval = nullptr;
645 
646     bool mCoreProfileSupported = false;
647     int mCoreMajorVersion = 4;
648     int mCoreMinorVersion = 5;
649     const int* mCoreProfileCtxAttribs = nullptr;
650 
651     X11Display* mDisplay = nullptr;
652     std::vector<GLXFBConfig> mFBConfigs;
653     std::unordered_map<GLXFBConfig, std::vector<EglOS::Surface* > > mFreePbufs;
654     std::unordered_map<GLXFBConfig, std::vector<EglOS::Surface* > > mLivePbufs;
655     int mPbufPrimingCount = 8;
656     android::base::Lock mPbufLock;
657     std::unordered_map<EglOS::Surface*, bool> mDisabledVsyncWindows;
658 };
659 
660 class GlxEngine : public EglOS::Engine {
661 public:
getDefaultDisplay()662     virtual EglOS::Display* getDefaultDisplay() {
663         Display* disp =
664             getX11Api()->XOpenDisplay(0 /* default display or $DISPLAY env var */);
665         if (!disp) {
666             fprintf(stderr,
667                     "GlxEngine%s: Failed to open display 0. DISPLAY: [%s]\n",
668                     __func__, getenv("DISPLAY"));
669             return nullptr;
670         }
671         return new GlxDisplay(disp);
672     }
673 
getGlLibrary()674     virtual GlLibrary* getGlLibrary() {
675         return sGlxLibrary();
676     }
677 
eglGetProcAddress(const char *)678     virtual void* eglGetProcAddress(const char*) {
679         return 0;
680     }
681 
createWindowSurface(EglOS::PixelFormat * pf,EGLNativeWindowType wnd)682     virtual EglOS::Surface* createWindowSurface(EglOS::PixelFormat* pf,
683                                                 EGLNativeWindowType wnd) {
684         return new GlxSurface(wnd, 0, GlxSurface::WINDOW);
685     }
686 };
687 
sHostEngine()688 static GlxEngine* sHostEngine() {
689     static GlxEngine* e = new GlxEngine;
690     return e;
691 }
692 
693 }  // namespace
694 
695 // static
getHostInstance()696 EglOS::Engine* EglOS::Engine::getHostInstance() {
697     return sHostEngine();
698 }
699