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