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