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