• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2015 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 // DisplayGLX.cpp: GLX implementation of egl::Display
8 
9 #include "libANGLE/renderer/gl/glx/DisplayGLX.h"
10 
11 #include <EGL/eglext.h>
12 #include <algorithm>
13 #include <cstring>
14 #include <fstream>
15 
16 #include "common/debug.h"
17 #include "libANGLE/Config.h"
18 #include "libANGLE/Context.h"
19 #include "libANGLE/Display.h"
20 #include "libANGLE/Surface.h"
21 #include "libANGLE/renderer/gl/ContextGL.h"
22 #include "libANGLE/renderer/gl/glx/PbufferSurfaceGLX.h"
23 #include "libANGLE/renderer/gl/glx/RendererGLX.h"
24 #include "libANGLE/renderer/gl/glx/WindowSurfaceGLX.h"
25 #include "libANGLE/renderer/gl/renderergl_utils.h"
26 
27 namespace
28 {
29 
HasParallelShaderCompileExtension(const rx::FunctionsGL * functions)30 bool HasParallelShaderCompileExtension(const rx::FunctionsGL *functions)
31 {
32     return functions->maxShaderCompilerThreadsKHR != nullptr ||
33            functions->maxShaderCompilerThreadsARB != nullptr;
34 }
35 
36 }  // anonymous namespace
37 
38 namespace rx
39 {
40 
IgnoreX11Errors(Display *,XErrorEvent *)41 static int IgnoreX11Errors(Display *, XErrorEvent *)
42 {
43     return 0;
44 }
45 
46 class FunctionsGLGLX : public FunctionsGL
47 {
48   public:
FunctionsGLGLX(PFNGETPROCPROC getProc)49     FunctionsGLGLX(PFNGETPROCPROC getProc) : mGetProc(getProc) {}
50 
~FunctionsGLGLX()51     ~FunctionsGLGLX() override {}
52 
53   private:
loadProcAddress(const std::string & function) const54     void *loadProcAddress(const std::string &function) const override
55     {
56         return reinterpret_cast<void *>(mGetProc(function.c_str()));
57     }
58 
59     PFNGETPROCPROC mGetProc;
60 };
61 
DisplayGLX(const egl::DisplayState & state)62 DisplayGLX::DisplayGLX(const egl::DisplayState &state)
63     : DisplayGL(state),
64       mRequestedVisual(-1),
65       mContextConfig(nullptr),
66       mVisuals(nullptr),
67       mContext(nullptr),
68       mSharedContext(nullptr),
69       mDummyPbuffer(0),
70       mUsesNewXDisplay(false),
71       mIsMesa(false),
72       mHasMultisample(false),
73       mHasARBCreateContext(false),
74       mHasARBCreateContextProfile(false),
75       mHasARBCreateContextRobustness(false),
76       mHasEXTCreateContextES2Profile(false),
77       mSwapControl(SwapControl::Absent),
78       mMinSwapInterval(0),
79       mMaxSwapInterval(0),
80       mCurrentSwapInterval(-1),
81       mCurrentDrawable(0),
82       mXDisplay(nullptr),
83       mEGLDisplay(nullptr)
84 {}
85 
~DisplayGLX()86 DisplayGLX::~DisplayGLX() {}
87 
initialize(egl::Display * display)88 egl::Error DisplayGLX::initialize(egl::Display *display)
89 {
90     mEGLDisplay           = display;
91     mXDisplay             = reinterpret_cast<Display *>(display->getNativeDisplayId());
92     const auto &attribMap = display->getAttributeMap();
93 
94     // ANGLE_platform_angle allows the creation of a default display
95     // using EGL_DEFAULT_DISPLAY (= nullptr). In this case just open
96     // the display specified by the DISPLAY environment variable.
97     if (mXDisplay == reinterpret_cast<Display *>(EGL_DEFAULT_DISPLAY))
98     {
99         mUsesNewXDisplay = true;
100         mXDisplay        = XOpenDisplay(nullptr);
101         if (!mXDisplay)
102         {
103             return egl::EglNotInitialized() << "Could not open the default X display.";
104         }
105     }
106 
107     std::string glxInitError;
108     if (!mGLX.initialize(mXDisplay, DefaultScreen(mXDisplay), &glxInitError))
109     {
110         return egl::EglNotInitialized() << glxInitError;
111     }
112 
113     mHasMultisample             = mGLX.minorVersion > 3 || mGLX.hasExtension("GLX_ARB_multisample");
114     mHasARBCreateContext        = mGLX.hasExtension("GLX_ARB_create_context");
115     mHasARBCreateContextProfile = mGLX.hasExtension("GLX_ARB_create_context_profile");
116     mHasARBCreateContextRobustness = mGLX.hasExtension("GLX_ARB_create_context_robustness");
117     mHasEXTCreateContextES2Profile = mGLX.hasExtension("GLX_EXT_create_context_es2_profile");
118 
119     std::string clientVendor = mGLX.getClientString(GLX_VENDOR);
120     mIsMesa                  = clientVendor.find("Mesa") != std::string::npos;
121 
122     // Choose the swap_control extension to use, if any.
123     // The EXT version is better as it allows glXSwapInterval to be called per
124     // window, while we'll potentially need to change the swap interval on each
125     // swap buffers when using the SGI or MESA versions.
126     if (mGLX.hasExtension("GLX_EXT_swap_control"))
127     {
128         mSwapControl = SwapControl::EXT;
129 
130         // In GLX_EXT_swap_control querying these is done on a GLXWindow so we just
131         // set default values.
132         mMinSwapInterval = 0;
133         mMaxSwapInterval = 4;
134     }
135     else if (mGLX.hasExtension("GLX_MESA_swap_control"))
136     {
137         // If we have the Mesa or SGI extension, assume that you can at least set
138         // a swap interval of 0 or 1.
139         mSwapControl     = SwapControl::Mesa;
140         mMinSwapInterval = 0;
141         mMinSwapInterval = 1;
142     }
143     else if (mGLX.hasExtension("GLX_SGI_swap_control"))
144     {
145         mSwapControl     = SwapControl::SGI;
146         mMinSwapInterval = 0;
147         mMinSwapInterval = 1;
148     }
149     else
150     {
151         mSwapControl     = SwapControl::Absent;
152         mMinSwapInterval = 1;
153         mMinSwapInterval = 1;
154     }
155 
156     if (attribMap.contains(EGL_X11_VISUAL_ID_ANGLE))
157     {
158         mRequestedVisual = static_cast<EGLint>(attribMap.get(EGL_X11_VISUAL_ID_ANGLE, -1));
159 
160         // There is no direct way to get the GLXFBConfig matching an X11 visual ID
161         // so we have to iterate over all the GLXFBConfigs to find the right one.
162         int nConfigs;
163         int attribList[] = {
164             None,
165         };
166         glx::FBConfig *allConfigs = mGLX.chooseFBConfig(attribList, &nConfigs);
167 
168         for (int i = 0; i < nConfigs; ++i)
169         {
170             if (getGLXFBConfigAttrib(allConfigs[i], GLX_VISUAL_ID) == mRequestedVisual)
171             {
172                 mContextConfig = allConfigs[i];
173                 break;
174             }
175         }
176         XFree(allConfigs);
177 
178         if (mContextConfig == nullptr)
179         {
180             return egl::EglNotInitialized() << "Invalid visual ID requested.";
181         }
182     }
183     else
184     {
185         // When glXMakeCurrent is called, the context and the surface must be
186         // compatible which in glX-speak means that their config have the same
187         // color buffer type, are both RGBA or ColorIndex, and their buffers have
188         // the same depth, if they exist.
189         // Since our whole EGL implementation is backed by only one GL context, this
190         // context must be compatible with all the GLXFBConfig corresponding to the
191         // EGLconfigs that we will be exposing.
192         int nConfigs;
193         int attribList[]          = {// We want RGBA8 and DEPTH24_STENCIL8
194                             GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, GLX_ALPHA_SIZE, 8,
195                             GLX_DEPTH_SIZE, 24, GLX_STENCIL_SIZE, 8,
196                             // We want RGBA rendering (vs COLOR_INDEX) and doublebuffer
197                             GLX_RENDER_TYPE, GLX_RGBA_BIT,
198                             // Double buffer is not strictly required as a non-doublebuffer
199                             // context can work with a doublebuffered surface, but it still
200                             // flickers and all applications want doublebuffer anyway.
201                             GLX_DOUBLEBUFFER, True,
202                             // All of these must be supported for full EGL support
203                             GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT | GLX_PBUFFER_BIT | GLX_PIXMAP_BIT,
204                             // This makes sure the config have an associated visual Id
205                             GLX_X_RENDERABLE, True, GLX_CONFIG_CAVEAT, GLX_NONE, None};
206         glx::FBConfig *candidates = mGLX.chooseFBConfig(attribList, &nConfigs);
207         if (nConfigs == 0)
208         {
209             XFree(candidates);
210             return egl::EglNotInitialized()
211                    << "Could not find a decent GLX FBConfig to create the context.";
212         }
213         mContextConfig = candidates[0];
214         XFree(candidates);
215     }
216 
217     const auto &eglAttributes = display->getAttributeMap();
218     if (mHasARBCreateContext)
219     {
220         egl::Error error = initializeContext(mContextConfig, eglAttributes, &mContext);
221         if (error.isError())
222         {
223             return error;
224         }
225     }
226     else
227     {
228         if (eglAttributes.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE,
229                               EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE) ==
230             EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE)
231         {
232             return egl::EglNotInitialized() << "Cannot create an OpenGL ES platform on GLX without "
233                                                "the GLX_ARB_create_context extension.";
234         }
235 
236         XVisualInfo visualTemplate;
237         visualTemplate.visualid = getGLXFBConfigAttrib(mContextConfig, GLX_VISUAL_ID);
238 
239         int numVisuals = 0;
240         mVisuals       = XGetVisualInfo(mXDisplay, VisualIDMask, &visualTemplate, &numVisuals);
241         if (numVisuals <= 0)
242         {
243             return egl::EglNotInitialized() << "Could not get the visual info from the fb config";
244         }
245         ASSERT(numVisuals == 1);
246 
247         mContext = mGLX.createContext(&mVisuals[0], nullptr, true);
248 
249         if (!mContext)
250         {
251             return egl::EglNotInitialized() << "Could not create GL context.";
252         }
253 
254         mSharedContext = mGLX.createContext(&mVisuals[0], mContext, True);
255     }
256     ASSERT(mContext);
257 
258     // FunctionsGL and DisplayGL need to make a few GL calls, for example to
259     // query the version of the context so we need to make the context current.
260     // glXMakeCurrent requires a GLXDrawable so we create a temporary Pbuffer
261     // (of size 1, 1) for the duration of these calls.
262     // Ideally we would want to unset the current context and destroy the pbuffer
263     // before going back to the application but this is TODO
264     // We could use a pbuffer of size (0, 0) but it fails on the Intel Mesa driver
265     // as commented on https://bugs.freedesktop.org/show_bug.cgi?id=38869 so we
266     // use (1, 1) instead.
267 
268     int dummyPbufferAttribs[] = {
269         GLX_PBUFFER_WIDTH, 1, GLX_PBUFFER_HEIGHT, 1, None,
270     };
271     mDummyPbuffer = mGLX.createPbuffer(mContextConfig, dummyPbufferAttribs);
272     if (!mDummyPbuffer)
273     {
274         return egl::EglNotInitialized() << "Could not create the dummy pbuffer.";
275     }
276 
277     if (!mGLX.makeCurrent(mDummyPbuffer, mContext))
278     {
279         return egl::EglNotInitialized() << "Could not make the dummy pbuffer current.";
280     }
281 
282     std::unique_ptr<FunctionsGL> functionsGL(new FunctionsGLGLX(mGLX.getProc));
283     functionsGL->initialize(eglAttributes);
284 
285     // TODO(cwallez, angleproject:1303) Disable the OpenGL ES backend on Linux NVIDIA and Intel as
286     // it has problems on our automated testing. An OpenGL ES backend might not trigger this test if
287     // there is no Desktop OpenGL support, but that's not the case in our automated testing.
288     VendorID vendor = GetVendorID(functionsGL.get());
289     bool isOpenGLES =
290         eglAttributes.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE) ==
291         EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE;
292     if (isOpenGLES && (IsIntel(vendor) || IsNvidia(vendor)))
293     {
294         return egl::EglNotInitialized() << "Intel or NVIDIA OpenGL ES drivers are not supported.";
295     }
296 
297     if (mSharedContext)
298     {
299         if (HasParallelShaderCompileExtension(functionsGL.get()))
300         {
301             mGLX.destroyContext(mSharedContext);
302             mSharedContext = nullptr;
303         }
304         else
305         {
306             for (unsigned int i = 0; i < RendererGL::getMaxWorkerContexts(); ++i)
307             {
308                 glx::Pbuffer workerPbuffer =
309                     mGLX.createPbuffer(mContextConfig, dummyPbufferAttribs);
310                 if (!workerPbuffer)
311                 {
312                     return egl::EglNotInitialized() << "Could not create the worker pbuffers.";
313                 }
314                 mWorkerPbufferPool.push_back(workerPbuffer);
315             }
316         }
317     }
318 
319     syncXCommands();
320 
321     mRenderer.reset(new RendererGLX(std::move(functionsGL), eglAttributes, this));
322     const gl::Version &maxVersion = mRenderer->getMaxSupportedESVersion();
323     if (maxVersion < gl::Version(2, 0))
324     {
325         return egl::EglNotInitialized() << "OpenGL ES 2.0 is not supportable.";
326     }
327 
328     return DisplayGL::initialize(display);
329 }
330 
terminate()331 void DisplayGLX::terminate()
332 {
333     DisplayGL::terminate();
334 
335     if (mVisuals)
336     {
337         XFree(mVisuals);
338         mVisuals = 0;
339     }
340 
341     if (mDummyPbuffer)
342     {
343         mGLX.destroyPbuffer(mDummyPbuffer);
344         mDummyPbuffer = 0;
345     }
346 
347     for (auto &workerPbuffer : mWorkerPbufferPool)
348     {
349         mGLX.destroyPbuffer(workerPbuffer);
350     }
351     mWorkerPbufferPool.clear();
352 
353     if (mContext)
354     {
355         mGLX.destroyContext(mContext);
356         mContext = nullptr;
357     }
358 
359     if (mSharedContext)
360     {
361         mGLX.destroyContext(mSharedContext);
362         mSharedContext = nullptr;
363     }
364 
365     mGLX.terminate();
366 
367     mRenderer.reset();
368 
369     if (mUsesNewXDisplay)
370     {
371         XCloseDisplay(mXDisplay);
372     }
373 }
374 
makeCurrent(egl::Surface * drawSurface,egl::Surface * readSurface,gl::Context * context)375 egl::Error DisplayGLX::makeCurrent(egl::Surface *drawSurface,
376                                    egl::Surface *readSurface,
377                                    gl::Context *context)
378 {
379     glx::Drawable drawable =
380         (drawSurface ? GetImplAs<SurfaceGLX>(drawSurface)->getDrawable() : mDummyPbuffer);
381     if (drawable != mCurrentDrawable)
382     {
383         if (mGLX.makeCurrent(drawable, mContext) != True)
384         {
385             return egl::EglContextLost() << "Failed to make the GLX context current";
386         }
387         mCurrentDrawable = drawable;
388     }
389 
390     return DisplayGL::makeCurrent(drawSurface, readSurface, context);
391 }
392 
createWindowSurface(const egl::SurfaceState & state,EGLNativeWindowType window,const egl::AttributeMap & attribs)393 SurfaceImpl *DisplayGLX::createWindowSurface(const egl::SurfaceState &state,
394                                              EGLNativeWindowType window,
395                                              const egl::AttributeMap &attribs)
396 {
397     ASSERT(configIdToGLXConfig.count(state.config->configID) > 0);
398     glx::FBConfig fbConfig = configIdToGLXConfig[state.config->configID];
399 
400     return new WindowSurfaceGLX(state, mGLX, this, window, mGLX.getDisplay(), fbConfig);
401 }
402 
createPbufferSurface(const egl::SurfaceState & state,const egl::AttributeMap & attribs)403 SurfaceImpl *DisplayGLX::createPbufferSurface(const egl::SurfaceState &state,
404                                               const egl::AttributeMap &attribs)
405 {
406     ASSERT(configIdToGLXConfig.count(state.config->configID) > 0);
407     glx::FBConfig fbConfig = configIdToGLXConfig[state.config->configID];
408 
409     EGLint width  = static_cast<EGLint>(attribs.get(EGL_WIDTH, 0));
410     EGLint height = static_cast<EGLint>(attribs.get(EGL_HEIGHT, 0));
411     bool largest  = (attribs.get(EGL_LARGEST_PBUFFER, EGL_FALSE) == EGL_TRUE);
412 
413     return new PbufferSurfaceGLX(state, width, height, largest, mGLX, fbConfig);
414 }
415 
createPbufferFromClientBuffer(const egl::SurfaceState & state,EGLenum buftype,EGLClientBuffer clientBuffer,const egl::AttributeMap & attribs)416 SurfaceImpl *DisplayGLX::createPbufferFromClientBuffer(const egl::SurfaceState &state,
417                                                        EGLenum buftype,
418                                                        EGLClientBuffer clientBuffer,
419                                                        const egl::AttributeMap &attribs)
420 {
421     UNIMPLEMENTED();
422     return nullptr;
423 }
424 
createPixmapSurface(const egl::SurfaceState & state,NativePixmapType nativePixmap,const egl::AttributeMap & attribs)425 SurfaceImpl *DisplayGLX::createPixmapSurface(const egl::SurfaceState &state,
426                                              NativePixmapType nativePixmap,
427                                              const egl::AttributeMap &attribs)
428 {
429     UNIMPLEMENTED();
430     return nullptr;
431 }
432 
createContext(const gl::State & state,gl::ErrorSet * errorSet,const egl::Config * configuration,const gl::Context * shareContext,const egl::AttributeMap & attribs)433 ContextImpl *DisplayGLX::createContext(const gl::State &state,
434                                        gl::ErrorSet *errorSet,
435                                        const egl::Config *configuration,
436                                        const gl::Context *shareContext,
437                                        const egl::AttributeMap &attribs)
438 {
439     return new ContextGL(state, errorSet, mRenderer);
440 }
441 
createDevice()442 DeviceImpl *DisplayGLX::createDevice()
443 {
444     UNIMPLEMENTED();
445     return nullptr;
446 }
447 
initializeContext(glx::FBConfig config,const egl::AttributeMap & eglAttributes,glx::Context * context)448 egl::Error DisplayGLX::initializeContext(glx::FBConfig config,
449                                          const egl::AttributeMap &eglAttributes,
450                                          glx::Context *context)
451 {
452     int profileMask = 0;
453 
454     EGLint requestedDisplayType = static_cast<EGLint>(
455         eglAttributes.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE));
456     if (requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE)
457     {
458         if (!mHasEXTCreateContextES2Profile)
459         {
460             return egl::EglNotInitialized() << "Cannot create an OpenGL ES platform on GLX without "
461                                                "the GLX_EXT_create_context_es_profile extension.";
462         }
463 
464         ASSERT(mHasARBCreateContextProfile);
465         profileMask |= GLX_CONTEXT_ES2_PROFILE_BIT_EXT;
466     }
467 
468     // Create a context of the requested version, if any.
469     gl::Version requestedVersion(static_cast<EGLint>(eglAttributes.get(
470                                      EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, EGL_DONT_CARE)),
471                                  static_cast<EGLint>(eglAttributes.get(
472                                      EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, EGL_DONT_CARE)));
473     if (static_cast<EGLint>(requestedVersion.major) != EGL_DONT_CARE &&
474         static_cast<EGLint>(requestedVersion.minor) != EGL_DONT_CARE)
475     {
476         if (!(profileMask & GLX_CONTEXT_ES2_PROFILE_BIT_EXT) &&
477             requestedVersion >= gl::Version(3, 2))
478         {
479             profileMask |= GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
480         }
481         return createContextAttribs(config, requestedVersion, profileMask, context);
482     }
483 
484     // The only way to get a core profile context of the highest version using
485     // glXCreateContextAttrib is to try creationg contexts in decreasing version
486     // numbers. It might look that asking for a core context of version (0, 0)
487     // works on some driver but it create a _compatibility_ context of the highest
488     // version instead. The cost of failing a context creation is small (< 0.1 ms)
489     // on Mesa but is unfortunately a bit expensive on the Nvidia driver (~3ms).
490     // Also try to get any Desktop GL context, but if that fails fallback to
491     // asking for OpenGL ES contexts.
492 
493     // NOTE: below we return as soon as we're able to create a context so the
494     // "error" variable is EGL_SUCCESS when returned contrary to the common idiom
495     // of returning "error" when there is an actual error.
496     for (const auto &info : GenerateContextCreationToTry(requestedDisplayType, mIsMesa))
497     {
498         int profileFlag = 0;
499         if (info.type == ContextCreationTry::Type::DESKTOP_CORE)
500         {
501             profileFlag |= GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
502         }
503         else if (info.type == ContextCreationTry::Type::ES)
504         {
505             profileFlag |= GLX_CONTEXT_ES2_PROFILE_BIT_EXT;
506         }
507 
508         egl::Error error = createContextAttribs(config, info.version, profileFlag, context);
509         if (!error.isError())
510         {
511             return error;
512         }
513     }
514 
515     return egl::EglNotInitialized() << "Could not create a backing OpenGL context.";
516 }
517 
generateConfigs()518 egl::ConfigSet DisplayGLX::generateConfigs()
519 {
520     egl::ConfigSet configs;
521     configIdToGLXConfig.clear();
522 
523     const gl::Version &maxVersion = getMaxSupportedESVersion();
524     ASSERT(maxVersion >= gl::Version(2, 0));
525     bool supportsES3 = maxVersion >= gl::Version(3, 0);
526 
527     int contextRedSize   = getGLXFBConfigAttrib(mContextConfig, GLX_RED_SIZE);
528     int contextGreenSize = getGLXFBConfigAttrib(mContextConfig, GLX_GREEN_SIZE);
529     int contextBlueSize  = getGLXFBConfigAttrib(mContextConfig, GLX_BLUE_SIZE);
530     int contextAlphaSize = getGLXFBConfigAttrib(mContextConfig, GLX_ALPHA_SIZE);
531 
532     int contextDepthSize   = getGLXFBConfigAttrib(mContextConfig, GLX_DEPTH_SIZE);
533     int contextStencilSize = getGLXFBConfigAttrib(mContextConfig, GLX_STENCIL_SIZE);
534 
535     int contextSamples = mHasMultisample ? getGLXFBConfigAttrib(mContextConfig, GLX_SAMPLES) : 0;
536     int contextSampleBuffers =
537         mHasMultisample ? getGLXFBConfigAttrib(mContextConfig, GLX_SAMPLE_BUFFERS) : 0;
538 
539     int contextAccumRedSize   = getGLXFBConfigAttrib(mContextConfig, GLX_ACCUM_RED_SIZE);
540     int contextAccumGreenSize = getGLXFBConfigAttrib(mContextConfig, GLX_ACCUM_GREEN_SIZE);
541     int contextAccumBlueSize  = getGLXFBConfigAttrib(mContextConfig, GLX_ACCUM_BLUE_SIZE);
542     int contextAccumAlphaSize = getGLXFBConfigAttrib(mContextConfig, GLX_ACCUM_ALPHA_SIZE);
543 
544     int attribList[] = {
545         GLX_RENDER_TYPE, GLX_RGBA_BIT, GLX_X_RENDERABLE, True, GLX_DOUBLEBUFFER, True, None,
546     };
547 
548     int glxConfigCount;
549     glx::FBConfig *glxConfigs = mGLX.chooseFBConfig(attribList, &glxConfigCount);
550 
551     for (int i = 0; i < glxConfigCount; i++)
552     {
553         glx::FBConfig glxConfig = glxConfigs[i];
554         egl::Config config;
555 
556         // Native stuff
557         config.nativeVisualID   = getGLXFBConfigAttrib(glxConfig, GLX_VISUAL_ID);
558         config.nativeVisualType = getGLXFBConfigAttrib(glxConfig, GLX_X_VISUAL_TYPE);
559         config.nativeRenderable = EGL_TRUE;
560 
561         // When a visual ID has been specified with EGL_ANGLE_x11_visual we should
562         // only return configs with this visual: it will maximize performance by avoid
563         // blits in the driver when showing the window on the screen.
564         if (mRequestedVisual != -1 && config.nativeVisualID != mRequestedVisual)
565         {
566             continue;
567         }
568 
569         // Buffer sizes
570         config.redSize     = getGLXFBConfigAttrib(glxConfig, GLX_RED_SIZE);
571         config.greenSize   = getGLXFBConfigAttrib(glxConfig, GLX_GREEN_SIZE);
572         config.blueSize    = getGLXFBConfigAttrib(glxConfig, GLX_BLUE_SIZE);
573         config.alphaSize   = getGLXFBConfigAttrib(glxConfig, GLX_ALPHA_SIZE);
574         config.depthSize   = getGLXFBConfigAttrib(glxConfig, GLX_DEPTH_SIZE);
575         config.stencilSize = getGLXFBConfigAttrib(glxConfig, GLX_STENCIL_SIZE);
576 
577         // We require RGBA8 and the D24S8 (or no DS buffer)
578         if (config.redSize != contextRedSize || config.greenSize != contextGreenSize ||
579             config.blueSize != contextBlueSize || config.alphaSize != contextAlphaSize)
580         {
581             continue;
582         }
583         // The GLX spec says that it is ok for a whole buffer to not be present
584         // however the Mesa Intel driver (and probably on other Mesa drivers)
585         // fails to make current when the Depth stencil doesn't exactly match the
586         // configuration.
587         bool hasSameDepthStencil =
588             config.depthSize == contextDepthSize && config.stencilSize == contextStencilSize;
589         bool hasNoDepthStencil = config.depthSize == 0 && config.stencilSize == 0;
590         if (!hasSameDepthStencil && (mIsMesa || !hasNoDepthStencil))
591         {
592             continue;
593         }
594 
595         config.colorBufferType = EGL_RGB_BUFFER;
596         config.luminanceSize   = 0;
597         config.alphaMaskSize   = 0;
598 
599         config.bufferSize = config.redSize + config.greenSize + config.blueSize + config.alphaSize;
600 
601         // Multisample and accumulation buffers
602         int samples = mHasMultisample ? getGLXFBConfigAttrib(glxConfig, GLX_SAMPLES) : 0;
603         int sampleBuffers =
604             mHasMultisample ? getGLXFBConfigAttrib(glxConfig, GLX_SAMPLE_BUFFERS) : 0;
605 
606         int accumRedSize   = getGLXFBConfigAttrib(glxConfig, GLX_ACCUM_RED_SIZE);
607         int accumGreenSize = getGLXFBConfigAttrib(glxConfig, GLX_ACCUM_GREEN_SIZE);
608         int accumBlueSize  = getGLXFBConfigAttrib(glxConfig, GLX_ACCUM_BLUE_SIZE);
609         int accumAlphaSize = getGLXFBConfigAttrib(glxConfig, GLX_ACCUM_ALPHA_SIZE);
610 
611         if (samples != contextSamples || sampleBuffers != contextSampleBuffers ||
612             accumRedSize != contextAccumRedSize || accumGreenSize != contextAccumGreenSize ||
613             accumBlueSize != contextAccumBlueSize || accumAlphaSize != contextAccumAlphaSize)
614         {
615             continue;
616         }
617 
618         config.samples       = samples;
619         config.sampleBuffers = sampleBuffers;
620 
621         // Transparency
622         if (getGLXFBConfigAttrib(glxConfig, GLX_TRANSPARENT_TYPE) == GLX_TRANSPARENT_RGB)
623         {
624             config.transparentType     = EGL_TRANSPARENT_RGB;
625             config.transparentRedValue = getGLXFBConfigAttrib(glxConfig, GLX_TRANSPARENT_RED_VALUE);
626             config.transparentGreenValue =
627                 getGLXFBConfigAttrib(glxConfig, GLX_TRANSPARENT_GREEN_VALUE);
628             config.transparentBlueValue =
629                 getGLXFBConfigAttrib(glxConfig, GLX_TRANSPARENT_BLUE_VALUE);
630         }
631         else
632         {
633             config.transparentType = EGL_NONE;
634         }
635 
636         // Pbuffer
637         config.maxPBufferWidth  = getGLXFBConfigAttrib(glxConfig, GLX_MAX_PBUFFER_WIDTH);
638         config.maxPBufferHeight = getGLXFBConfigAttrib(glxConfig, GLX_MAX_PBUFFER_HEIGHT);
639         config.maxPBufferPixels = getGLXFBConfigAttrib(glxConfig, GLX_MAX_PBUFFER_PIXELS);
640 
641         // Caveat
642         config.configCaveat = EGL_NONE;
643 
644         int caveat = getGLXFBConfigAttrib(glxConfig, GLX_CONFIG_CAVEAT);
645         if (caveat == GLX_SLOW_CONFIG)
646         {
647             config.configCaveat = EGL_SLOW_CONFIG;
648         }
649         else if (caveat == GLX_NON_CONFORMANT_CONFIG)
650         {
651             continue;
652         }
653 
654         // Misc
655         config.level = getGLXFBConfigAttrib(glxConfig, GLX_LEVEL);
656 
657         config.bindToTextureRGB  = EGL_FALSE;
658         config.bindToTextureRGBA = EGL_FALSE;
659 
660         int glxDrawable    = getGLXFBConfigAttrib(glxConfig, GLX_DRAWABLE_TYPE);
661         config.surfaceType = 0 | (glxDrawable & GLX_WINDOW_BIT ? EGL_WINDOW_BIT : 0) |
662                              (glxDrawable & GLX_PBUFFER_BIT ? EGL_PBUFFER_BIT : 0) |
663                              (glxDrawable & GLX_PIXMAP_BIT ? EGL_PIXMAP_BIT : 0);
664 
665         config.minSwapInterval = mMinSwapInterval;
666         config.maxSwapInterval = mMaxSwapInterval;
667 
668         // TODO(cwallez) wildly guessing these formats, another TODO says they should be removed
669         // anyway
670         config.renderTargetFormat = GL_RGBA8;
671         config.depthStencilFormat = GL_DEPTH24_STENCIL8;
672 
673         config.conformant     = EGL_OPENGL_ES2_BIT | (supportsES3 ? EGL_OPENGL_ES3_BIT_KHR : 0);
674         config.renderableType = config.conformant;
675 
676         // TODO(cwallez) I have no idea what this is
677         config.matchNativePixmap = EGL_NONE;
678 
679         config.colorComponentType = EGL_COLOR_COMPONENT_TYPE_FIXED_EXT;
680 
681         int id                  = configs.add(config);
682         configIdToGLXConfig[id] = glxConfig;
683     }
684 
685     XFree(glxConfigs);
686 
687     return configs;
688 }
689 
testDeviceLost()690 bool DisplayGLX::testDeviceLost()
691 {
692     if (mHasARBCreateContextRobustness)
693     {
694         return mRenderer->getResetStatus() != gl::GraphicsResetStatus::NoError;
695     }
696 
697     return false;
698 }
699 
restoreLostDevice(const egl::Display * display)700 egl::Error DisplayGLX::restoreLostDevice(const egl::Display *display)
701 {
702     return egl::EglBadDisplay();
703 }
704 
isValidNativeWindow(EGLNativeWindowType window) const705 bool DisplayGLX::isValidNativeWindow(EGLNativeWindowType window) const
706 {
707 
708     // Check the validity of the window by calling a getter function on the window that
709     // returns a status code. If the window is bad the call return a status of zero. We
710     // need to set a temporary X11 error handler while doing this because the default
711     // X11 error handler exits the program on any error.
712     auto oldErrorHandler = XSetErrorHandler(IgnoreX11Errors);
713     XWindowAttributes attributes;
714     int status = XGetWindowAttributes(mXDisplay, window, &attributes);
715     XSetErrorHandler(oldErrorHandler);
716 
717     return status != 0;
718 }
719 
getVendorString() const720 std::string DisplayGLX::getVendorString() const
721 {
722     // UNIMPLEMENTED();
723     return "";
724 }
725 
waitClient(const gl::Context * context)726 egl::Error DisplayGLX::waitClient(const gl::Context *context)
727 {
728     mGLX.waitGL();
729     return egl::NoError();
730 }
731 
waitNative(const gl::Context * context,EGLint engine)732 egl::Error DisplayGLX::waitNative(const gl::Context *context, EGLint engine)
733 {
734     // eglWaitNative is used to notice the driver of changes in X11 for the current surface, such as
735     // changes of the window size. We use this event to update the child window of WindowSurfaceGLX
736     // to match its parent window's size.
737     // Handling eglWaitNative this way helps the application control when resize happens. This is
738     // important because drivers have a tendency to clobber the back buffer when the windows are
739     // resized. See http://crbug.com/326995
740     egl::Surface *drawSurface = context->getCurrentDrawSurface();
741     egl::Surface *readSurface = context->getCurrentReadSurface();
742     if (drawSurface != nullptr)
743     {
744         SurfaceGLX *glxDrawSurface = GetImplAs<SurfaceGLX>(drawSurface);
745         ANGLE_TRY(glxDrawSurface->checkForResize());
746     }
747 
748     if (readSurface != drawSurface && readSurface != nullptr)
749     {
750         SurfaceGLX *glxReadSurface = GetImplAs<SurfaceGLX>(readSurface);
751         ANGLE_TRY(glxReadSurface->checkForResize());
752     }
753 
754     // We still need to forward the resizing of the child window to the driver.
755     mGLX.waitX();
756     return egl::NoError();
757 }
758 
getMaxSupportedESVersion() const759 gl::Version DisplayGLX::getMaxSupportedESVersion() const
760 {
761     return mRenderer->getMaxSupportedESVersion();
762 }
763 
syncXCommands() const764 void DisplayGLX::syncXCommands() const
765 {
766     if (mUsesNewXDisplay)
767     {
768         XSync(mGLX.getDisplay(), False);
769     }
770 }
771 
setSwapInterval(glx::Drawable drawable,SwapControlData * data)772 void DisplayGLX::setSwapInterval(glx::Drawable drawable, SwapControlData *data)
773 {
774     ASSERT(data != nullptr);
775 
776     // TODO(cwallez) error checking?
777     if (mSwapControl == SwapControl::EXT)
778     {
779         // Prefer the EXT extension, it gives per-drawable swap intervals, which will
780         // minimize the number of driver calls.
781         if (data->maxSwapInterval < 0)
782         {
783             unsigned int maxSwapInterval = 0;
784             mGLX.queryDrawable(drawable, GLX_MAX_SWAP_INTERVAL_EXT, &maxSwapInterval);
785             data->maxSwapInterval = static_cast<int>(maxSwapInterval);
786         }
787 
788         // When the egl configs were generated we had to guess what the max swap interval
789         // was because we didn't have a window to query it one (and that this max could
790         // depend on the monitor). This means that the target interval might be higher
791         // than the max interval and needs to be clamped.
792         const int realInterval = std::min(data->targetSwapInterval, data->maxSwapInterval);
793         if (data->currentSwapInterval != realInterval)
794         {
795             mGLX.swapIntervalEXT(drawable, realInterval);
796             data->currentSwapInterval = realInterval;
797         }
798     }
799     else if (mCurrentSwapInterval != data->targetSwapInterval)
800     {
801         // With the Mesa or SGI extensions we can still do per-drawable swap control
802         // manually but it is more expensive in number of driver calls.
803         if (mSwapControl == SwapControl::Mesa)
804         {
805             mGLX.swapIntervalMESA(data->targetSwapInterval);
806         }
807         else if (mSwapControl == SwapControl::SGI)
808         {
809             mGLX.swapIntervalSGI(data->targetSwapInterval);
810         }
811         mCurrentSwapInterval = data->targetSwapInterval;
812     }
813 }
814 
isValidWindowVisualId(unsigned long visualId) const815 bool DisplayGLX::isValidWindowVisualId(unsigned long visualId) const
816 {
817     return mRequestedVisual == -1 || static_cast<unsigned long>(mRequestedVisual) == visualId;
818 }
819 
generateExtensions(egl::DisplayExtensions * outExtensions) const820 void DisplayGLX::generateExtensions(egl::DisplayExtensions *outExtensions) const
821 {
822     outExtensions->createContextRobustness = mHasARBCreateContextRobustness;
823 
824     // Contexts are virtualized so textures can be shared globally
825     outExtensions->displayTextureShareGroup = true;
826 
827     outExtensions->surfacelessContext = true;
828 
829     const bool hasSyncControlOML        = mGLX.hasExtension("GLX_OML_sync_control");
830     outExtensions->syncControlCHROMIUM  = hasSyncControlOML;
831     outExtensions->syncControlRateANGLE = hasSyncControlOML;
832 
833     DisplayGL::generateExtensions(outExtensions);
834 }
835 
generateCaps(egl::Caps * outCaps) const836 void DisplayGLX::generateCaps(egl::Caps *outCaps) const
837 {
838     outCaps->textureNPOT = true;
839 }
840 
makeCurrentSurfaceless(gl::Context * context)841 egl::Error DisplayGLX::makeCurrentSurfaceless(gl::Context *context)
842 {
843     // Nothing to do because GLX always uses the same context and the previous surface can be left
844     // current.
845     return egl::NoError();
846 }
847 
getGLXFBConfigAttrib(glx::FBConfig config,int attrib) const848 int DisplayGLX::getGLXFBConfigAttrib(glx::FBConfig config, int attrib) const
849 {
850     int result;
851     mGLX.getFBConfigAttrib(config, attrib, &result);
852     return result;
853 }
854 
createContextAttribs(glx::FBConfig,const Optional<gl::Version> & version,int profileMask,glx::Context * context)855 egl::Error DisplayGLX::createContextAttribs(glx::FBConfig,
856                                             const Optional<gl::Version> &version,
857                                             int profileMask,
858                                             glx::Context *context)
859 {
860     mAttribs.clear();
861 
862     if (mHasARBCreateContextRobustness)
863     {
864         mAttribs.push_back(GLX_CONTEXT_FLAGS_ARB);
865         mAttribs.push_back(GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB);
866         mAttribs.push_back(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB);
867         mAttribs.push_back(GLX_LOSE_CONTEXT_ON_RESET_ARB);
868     }
869 
870     if (version.valid())
871     {
872         mAttribs.push_back(GLX_CONTEXT_MAJOR_VERSION_ARB);
873         mAttribs.push_back(version.value().major);
874 
875         mAttribs.push_back(GLX_CONTEXT_MINOR_VERSION_ARB);
876         mAttribs.push_back(version.value().minor);
877     }
878 
879     if (profileMask != 0 && mHasARBCreateContextProfile)
880     {
881         mAttribs.push_back(GLX_CONTEXT_PROFILE_MASK_ARB);
882         mAttribs.push_back(profileMask);
883     }
884 
885     mAttribs.push_back(None);
886 
887     // When creating a context with glXCreateContextAttribsARB, a variety of X11 errors can
888     // be generated. To prevent these errors from crashing our process, we simply ignore
889     // them and only look if GLXContext was created.
890     // Process all events before setting the error handler to avoid desynchronizing XCB instances
891     // (the error handler is NOT per-display).
892     XSync(mXDisplay, False);
893     auto oldErrorHandler = XSetErrorHandler(IgnoreX11Errors);
894     *context = mGLX.createContextAttribsARB(mContextConfig, nullptr, True, mAttribs.data());
895     XSetErrorHandler(oldErrorHandler);
896 
897     if (!*context)
898     {
899         return egl::EglNotInitialized() << "Could not create GL context.";
900     }
901 
902     mSharedContext = mGLX.createContextAttribsARB(mContextConfig, mContext, True, mAttribs.data());
903 
904     return egl::NoError();
905 }
906 
907 class WorkerContextGLX final : public WorkerContext
908 {
909   public:
910     WorkerContextGLX(glx::Context context, FunctionsGLX *functions, glx::Pbuffer buffer);
911     ~WorkerContextGLX() override;
912 
913     bool makeCurrent() override;
914     void unmakeCurrent() override;
915 
916   private:
917     glx::Context mContext;
918     FunctionsGLX *mFunctions;
919     glx::Pbuffer mBuffer;
920 };
921 
WorkerContextGLX(glx::Context context,FunctionsGLX * functions,glx::Pbuffer buffer)922 WorkerContextGLX::WorkerContextGLX(glx::Context context,
923                                    FunctionsGLX *functions,
924                                    glx::Pbuffer buffer)
925     : mContext(context), mFunctions(functions), mBuffer(buffer)
926 {}
927 
~WorkerContextGLX()928 WorkerContextGLX::~WorkerContextGLX()
929 {
930     mFunctions->destroyContext(mContext);
931     mFunctions->destroyPbuffer(mBuffer);
932 }
933 
makeCurrent()934 bool WorkerContextGLX::makeCurrent()
935 {
936     Bool result = mFunctions->makeCurrent(mBuffer, mContext);
937     if (result != True)
938     {
939         ERR() << "Unable to make the GLX context current.";
940         return false;
941     }
942     return true;
943 }
944 
unmakeCurrent()945 void WorkerContextGLX::unmakeCurrent()
946 {
947     mFunctions->makeCurrent(0, nullptr);
948 }
949 
createWorkerContext(std::string * infoLog)950 WorkerContext *DisplayGLX::createWorkerContext(std::string *infoLog)
951 {
952     if (!mSharedContext)
953     {
954         *infoLog += "No shared context.";
955         return nullptr;
956     }
957     if (mWorkerPbufferPool.empty())
958     {
959         *infoLog += "No worker pbuffers.";
960         return nullptr;
961     }
962     glx::Context context = nullptr;
963     if (mHasARBCreateContext)
964     {
965         context =
966             mGLX.createContextAttribsARB(mContextConfig, mSharedContext, True, mAttribs.data());
967     }
968     else
969     {
970         context = mGLX.createContext(&mVisuals[0], mSharedContext, True);
971     }
972 
973     if (!context)
974     {
975         *infoLog += "Unable to create the glx context.";
976         return nullptr;
977     }
978 
979     glx::Pbuffer workerPbuffer = mWorkerPbufferPool.back();
980     mWorkerPbufferPool.pop_back();
981 
982     return new WorkerContextGLX(context, &mGLX, workerPbuffer);
983 }
984 
initializeFrontendFeatures(angle::FrontendFeatures * features) const985 void DisplayGLX::initializeFrontendFeatures(angle::FrontendFeatures *features) const
986 {
987     mRenderer->initializeFrontendFeatures(features);
988 }
989 
populateFeatureList(angle::FeatureList * features)990 void DisplayGLX::populateFeatureList(angle::FeatureList *features)
991 {
992     mRenderer->getFeatures().populateFeatureList(features);
993 }
994 
995 }  // namespace rx
996