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