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