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