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