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