1 | /******************************************************************** |
2 | KWin - the KDE window manager |
3 | This file is part of the KDE project. |
4 | |
5 | Copyright (C) 2007 Rivo Laks <rivolaks@hot.ee> |
6 | |
7 | This program is free software; you can redistribute it and/or modify |
8 | it under the terms of the GNU General Public License as published by |
9 | the Free Software Foundation; either version 2 of the License, or |
10 | (at your option) any later version. |
11 | |
12 | This program is distributed in the hope that it will be useful, |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | GNU General Public License for more details. |
16 | |
17 | You should have received a copy of the GNU General Public License |
18 | along with this program. If not, see <http://www.gnu.org/licenses/>. |
19 | *********************************************************************/ |
20 | |
21 | #include "compositingprefs.h" |
22 | |
23 | #include "xcbutils.h" |
24 | #include "kwinglplatform.h" |
25 | |
26 | #include <kconfiggroup.h> |
27 | #include <kdebug.h> |
28 | #include <kxerrorhandler.h> |
29 | #include <KDE/KGlobal> |
30 | #include <KDE/KLocalizedString> |
31 | #include <kdeversion.h> |
32 | #include <ksharedconfig.h> |
33 | #include <kstandarddirs.h> |
34 | |
35 | #include <qprocess.h> |
36 | |
37 | |
38 | namespace KWin |
39 | { |
40 | |
41 | extern int screen_number; // main.cpp |
42 | extern bool is_multihead; |
43 | |
44 | CompositingPrefs::CompositingPrefs() |
45 | : mEnableDirectRendering(true) |
46 | { |
47 | } |
48 | |
49 | CompositingPrefs::~CompositingPrefs() |
50 | { |
51 | } |
52 | |
53 | bool CompositingPrefs::openGlIsBroken() |
54 | { |
55 | const QString unsafeKey("OpenGLIsUnsafe" + (is_multihead ? QString::number(screen_number) : "" )); |
56 | return KConfigGroup(KGlobal::config(), "Compositing" ).readEntry(unsafeKey, false); |
57 | } |
58 | |
59 | bool CompositingPrefs::compositingPossible() |
60 | { |
61 | // first off, check whether we figured that we'll crash on detection because of a buggy driver |
62 | KConfigGroup gl_workaround_group(KGlobal::config(), "Compositing" ); |
63 | const QString unsafeKey("OpenGLIsUnsafe" + (is_multihead ? QString::number(screen_number) : "" )); |
64 | if (gl_workaround_group.readEntry("Backend" , "OpenGL" ) == "OpenGL" && |
65 | gl_workaround_group.readEntry(unsafeKey, false)) |
66 | return false; |
67 | |
68 | if (!Xcb::Extensions::self()->isCompositeAvailable()) { |
69 | kDebug(1212) << "No composite extension available" ; |
70 | return false; |
71 | } |
72 | if (!Xcb::Extensions::self()->isDamageAvailable()) { |
73 | kDebug(1212) << "No damage extension available" ; |
74 | return false; |
75 | } |
76 | if (hasGlx()) |
77 | return true; |
78 | #ifdef KWIN_HAVE_XRENDER_COMPOSITING |
79 | if (Xcb::Extensions::self()->isRenderAvailable() && Xcb::Extensions::self()->isFixesAvailable()) |
80 | return true; |
81 | #endif |
82 | #ifdef KWIN_HAVE_OPENGLES |
83 | return true; |
84 | #endif |
85 | kDebug(1212) << "No OpenGL or XRender/XFixes support" ; |
86 | return false; |
87 | } |
88 | |
89 | QString CompositingPrefs::compositingNotPossibleReason() |
90 | { |
91 | // first off, check whether we figured that we'll crash on detection because of a buggy driver |
92 | KConfigGroup gl_workaround_group(KGlobal::config(), "Compositing" ); |
93 | const QString unsafeKey("OpenGLIsUnsafe" + (is_multihead ? QString::number(screen_number) : "" )); |
94 | if (gl_workaround_group.readEntry("Backend" , "OpenGL" ) == "OpenGL" && |
95 | gl_workaround_group.readEntry(unsafeKey, false)) |
96 | return i18n("<b>OpenGL compositing (the default) has crashed KWin in the past.</b><br>" |
97 | "This was most likely due to a driver bug." |
98 | "<p>If you think that you have meanwhile upgraded to a stable driver,<br>" |
99 | "you can reset this protection but <b>be aware that this might result in an immediate crash!</b></p>" |
100 | "<p>Alternatively, you might want to use the XRender backend instead.</p>" ); |
101 | |
102 | if (!Xcb::Extensions::self()->isCompositeAvailable() || !Xcb::Extensions::self()->isDamageAvailable()) { |
103 | return i18n("Required X extensions (XComposite and XDamage) are not available." ); |
104 | } |
105 | #if !defined( KWIN_HAVE_XRENDER_COMPOSITING ) |
106 | if (!hasGlx()) |
107 | return i18n("GLX/OpenGL are not available and only OpenGL support is compiled." ); |
108 | #else |
109 | if (!(hasGlx() |
110 | || (Xcb::Extensions::self()->isRenderAvailable() && Xcb::Extensions::self()->isFixesAvailable()))) { |
111 | return i18n("GLX/OpenGL and XRender/XFixes are not available." ); |
112 | } |
113 | #endif |
114 | return QString(); |
115 | } |
116 | |
117 | static bool s_glxDetected = false; |
118 | static bool s_hasGlx = false; |
119 | |
120 | bool CompositingPrefs::hasGlx() |
121 | { |
122 | if (s_glxDetected) { |
123 | return s_hasGlx; |
124 | } |
125 | #ifndef KWIN_HAVE_OPENGLES |
126 | int event_base, error_base; |
127 | s_hasGlx = glXQueryExtension(display(), &event_base, &error_base); |
128 | #endif |
129 | s_glxDetected = true; |
130 | return s_hasGlx; |
131 | } |
132 | |
133 | void CompositingPrefs::detect() |
134 | { |
135 | if (!compositingPossible() || openGlIsBroken()) { |
136 | return; |
137 | } |
138 | |
139 | #ifndef KWIN_HAVE_OPENGLES |
140 | // HACK: This is needed for AIGLX |
141 | const bool forceIndirect = qstrcmp(qgetenv("LIBGL_ALWAYS_INDIRECT" ), "1" ) == 0; |
142 | const bool forceEgl = qstrcmp(qgetenv("KWIN_OPENGL_INTERFACE" ), "egl" ) == 0 || |
143 | qstrcmp(qgetenv("KWIN_OPENGL_INTERFACE" ), "egl_wayland" ) == 0; |
144 | if (!forceIndirect && !forceEgl && qstrcmp(qgetenv("KWIN_DIRECT_GL" ), "1" ) != 0) { |
145 | // Start an external helper program that initializes GLX and returns |
146 | // 0 if we can use direct rendering, and 1 otherwise. |
147 | // The reason we have to use an external program is that after GLX |
148 | // has been initialized, it's too late to set the LIBGL_ALWAYS_INDIRECT |
149 | // environment variable. |
150 | // Direct rendering is preferred, since not all OpenGL extensions are |
151 | // available with indirect rendering. |
152 | const QString opengl_test = KStandardDirs::findExe("kwin_opengl_test" ); |
153 | if (QProcess::execute(opengl_test) != 0) { |
154 | mEnableDirectRendering = false; |
155 | setenv("LIBGL_ALWAYS_INDIRECT" , "1" , true); |
156 | } else { |
157 | mEnableDirectRendering = true; |
158 | } |
159 | } else { |
160 | mEnableDirectRendering = !forceIndirect; |
161 | } |
162 | #endif |
163 | } |
164 | |
165 | } // namespace |
166 | |
167 | |