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