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