1
/********************************************************************
2
KWin - the KDE window manager
3
This file is part of the KDE project.
5
Copyright (C) 2007 Rivo Laks <rivolaks@hot.ee>
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.
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.
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
*********************************************************************/
21
#include "compositingprefs.h"
23
#include "kwinglobals.h"
24
#include "kwinglplatform.h"
26
#include <kconfiggroup.h>
28
#include <kxerrorhandler.h>
30
#include <kdeversion.h>
31
#include <ksharedconfig.h>
32
#include <kstandarddirs.h>
40
CompositingPrefs::CompositingPrefs()
41
: mRecommendCompositing(false)
43
, mEnableDirectRendering(true)
44
, mStrictBinding(true)
48
CompositingPrefs::~CompositingPrefs()
52
bool CompositingPrefs::recommendCompositing() const
54
return mRecommendCompositing;
57
bool CompositingPrefs::openGlIsBroken()
59
KSharedConfigPtr config = KSharedConfig::openConfig("kwinrc");
60
return KConfigGroup(config, "Compositing").readEntry("OpenGLIsUnsafe", false);
63
bool CompositingPrefs::compositingPossible()
65
// first off, check whether we figured that we'll crash on detection because of a buggy driver
66
KSharedConfigPtr config = KSharedConfig::openConfig("kwinrc");
67
KConfigGroup gl_workaround_group(config, "Compositing");
68
if (gl_workaround_group.readEntry("Backend", "OpenGL") == "OpenGL" &&
69
gl_workaround_group.readEntry("OpenGLIsUnsafe", false))
72
#ifdef KWIN_HAVE_COMPOSITING
74
if (!Extensions::compositeAvailable()) {
75
kDebug(1212) << "No composite extension available";
78
if (!Extensions::damageAvailable()) {
79
kDebug(1212) << "No damage extension available";
82
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
83
if (Extensions::glxAvailable())
86
#ifdef KWIN_HAVE_XRENDER_COMPOSITING
87
if (Extensions::renderAvailable() && Extensions::fixesAvailable())
90
#ifdef KWIN_HAVE_OPENGLES
93
kDebug(1212) << "No OpenGL or XRender/XFixes support";
100
QString CompositingPrefs::compositingNotPossibleReason()
102
#ifdef KWIN_HAVE_COMPOSITING
103
// first off, check whether we figured that we'll crash on detection because of a buggy driver
104
KSharedConfigPtr config = KSharedConfig::openConfig("kwinrc");
105
KConfigGroup gl_workaround_group(config, "Compositing");
106
if (gl_workaround_group.readEntry("Backend", "OpenGL") == "OpenGL" &&
107
gl_workaround_group.readEntry("OpenGLIsUnsafe", false))
108
return i18n("<b>OpenGL compositing (the default) has crashed KWin in the past.</b><br>"
109
"This was most likely due to a driver bug."
110
"<p>If you think that you have meanwhile upgraded to a stable driver,<br>"
111
"you can reset this protection but <b>be aware that this might result in an immediate crash!</b></p>"
112
"<p>Alternatively, you might want to use the XRender backend instead.</p>");
115
if (!Extensions::compositeAvailable() || !Extensions::damageAvailable()) {
116
return i18n("Required X extensions (XComposite and XDamage) are not available.");
118
#if defined( KWIN_HAVE_OPENGL_COMPOSITING ) && !defined( KWIN_HAVE_XRENDER_COMPOSITING )
119
if (!Extensions::glxAvailable())
120
return i18n("GLX/OpenGL are not available and only OpenGL support is compiled.");
121
#elif !defined( KWIN_HAVE_OPENGL_COMPOSITING ) && defined( KWIN_HAVE_XRENDER_COMPOSITING )
122
if (!(Extensions::renderAvailable() && Extensions::fixesAvailable()))
123
return i18n("XRender/XFixes extensions are not available and only XRender support"
126
if (!(Extensions::glxAvailable()
127
|| (Extensions::renderAvailable() && Extensions::fixesAvailable()))) {
128
return i18n("GLX/OpenGL and XRender/XFixes are not available.");
133
return i18n("Compositing was disabled at compile time.\n"
134
"It is likely Xorg development headers were not installed.");
138
void CompositingPrefs::detect()
140
if (!compositingPossible() || openGlIsBroken()) {
144
// NOTICE: this is intended to workaround broken GL implementations that successfully segfault
146
// we tag GL as unsafe. It *must* be reset before every return, and in case we "unexpectedly"
147
// end (aka "segfaulted") we know that we shall not try again
148
KSharedConfigPtr config = KSharedConfig::openConfig("kwinrc");
149
KConfigGroup gl_workaround_config = KConfigGroup(config, "Compositing");
150
gl_workaround_config.writeEntry("OpenGLIsUnsafe", true);
151
gl_workaround_config.sync();
153
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
154
#ifdef KWIN_HAVE_OPENGLES
155
bool haveContext = false;
156
bool canDetect = false;
157
EGLDisplay dpy = eglGetCurrentDisplay();
158
if (dpy != EGL_NO_DISPLAY) {
159
EGLContext ctx = eglGetCurrentContext();
160
if (ctx != EGL_NO_CONTEXT) {
166
canDetect = initEGLContext();
169
detectDriverAndVersion();
170
applyDriverSpecificOptions();
176
// HACK: This is needed for AIGLX
177
if (qstrcmp(qgetenv("KWIN_DIRECT_GL"), "1") != 0) {
178
// Start an external helper program that initializes GLX and returns
179
// 0 if we can use direct rendering, and 1 otherwise.
180
// The reason we have to use an external program is that after GLX
181
// has been initialized, it's too late to set the LIBGL_ALWAYS_INDIRECT
182
// environment variable.
183
// Direct rendering is preferred, since not all OpenGL extensions are
184
// available with indirect rendering.
185
const QString opengl_test = KStandardDirs::findExe("kwin_opengl_test");
186
if (QProcess::execute(opengl_test) != 0)
187
setenv("LIBGL_ALWAYS_INDIRECT", "1", true);
189
if (!Extensions::glxAvailable()) {
190
kDebug(1212) << "No GLX available";
191
gl_workaround_config.writeEntry("OpenGLIsUnsafe", false);
192
gl_workaround_config.sync();
195
int glxmajor, glxminor;
196
glXQueryVersion(display(), &glxmajor, &glxminor);
197
kDebug(1212) << "glx version is " << glxmajor << "." << glxminor;
198
bool hasglx13 = (glxmajor > 1 || (glxmajor == 1 && glxminor >= 3));
200
// remember and later restore active context
201
GLXContext oldcontext = glXGetCurrentContext();
202
GLXDrawable olddrawable = glXGetCurrentDrawable();
203
GLXDrawable oldreaddrawable = None;
205
oldreaddrawable = glXGetCurrentReadDrawable();
207
if (initGLXContext()) {
208
detectDriverAndVersion();
209
applyDriverSpecificOptions();
212
glXMakeContextCurrent(display(), olddrawable, oldreaddrawable, oldcontext);
214
glXMakeCurrent(display(), olddrawable, oldcontext);
217
gl_workaround_config.writeEntry("OpenGLIsUnsafe", false);
218
gl_workaround_config.sync();
222
bool CompositingPrefs::initGLXContext()
224
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
225
#ifndef KWIN_HAVE_OPENGLES
227
KXErrorHandler handler;
228
// Most of this code has been taken from glxinfo.c
229
QVector<int> attribs;
231
attribs << GLX_RED_SIZE << 1;
232
attribs << GLX_GREEN_SIZE << 1;
233
attribs << GLX_BLUE_SIZE << 1;
236
XVisualInfo* visinfo = glXChooseVisual(display(), DefaultScreen(display()), attribs.data());
238
attribs.last() = GLX_DOUBLEBUFFER;
240
visinfo = glXChooseVisual(display(), DefaultScreen(display()), attribs.data());
242
kDebug(1212) << "Error: couldn't find RGB GLX visual";
247
mGLContext = glXCreateContext(display(), visinfo, NULL, True);
249
kDebug(1212) << "glXCreateContext failed";
250
XDestroyWindow(display(), mGLWindow);
254
XSetWindowAttributes attr;
255
attr.background_pixel = 0;
256
attr.border_pixel = 0;
257
attr.colormap = XCreateColormap(display(), rootWindow(), visinfo->visual, AllocNone);
258
attr.event_mask = StructureNotifyMask | ExposureMask;
259
unsigned long mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
260
int width = 100, height = 100;
261
mGLWindow = XCreateWindow(display(), rootWindow(), 0, 0, width, height,
262
0, visinfo->depth, InputOutput,
263
visinfo->visual, mask, &attr);
265
return glXMakeCurrent(display(), mGLWindow, mGLContext) && !handler.error(true);
274
void CompositingPrefs::deleteGLXContext()
276
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
277
#ifndef KWIN_HAVE_OPENGLES
278
if (mGLContext == NULL)
280
glXDestroyContext(display(), mGLContext);
281
XDestroyWindow(display(), mGLWindow);
286
bool CompositingPrefs::initEGLContext()
288
#ifdef KWIN_HAVE_OPENGLES
289
mEGLDisplay = eglGetDisplay(display());
290
if (mEGLDisplay == EGL_NO_DISPLAY) {
293
if (eglInitialize(mEGLDisplay, 0, 0) == EGL_FALSE) {
296
eglBindAPI(EGL_OPENGL_ES_API);
298
const EGLint config_attribs[] = {
299
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
304
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
305
EGL_CONFIG_CAVEAT, EGL_NONE,
310
EGLConfig configs[1024];
311
eglChooseConfig(mEGLDisplay, config_attribs, configs, 1024, &count);
313
EGLint visualId = XVisualIDFromVisual((Visual*)QX11Info::appVisual());
315
EGLConfig config = configs[0];
316
for (int i = 0; i < count; i++) {
318
eglGetConfigAttrib(mEGLDisplay, configs[i], EGL_NATIVE_VISUAL_ID, &val);
319
if (visualId == val) {
325
XSetWindowAttributes attr;
326
attr.background_pixel = 0;
327
attr.border_pixel = 0;
328
attr.colormap = XCreateColormap(display(), rootWindow(), (Visual*)QX11Info::appVisual(), AllocNone);
329
attr.event_mask = StructureNotifyMask | ExposureMask;
330
unsigned long mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
331
int width = 100, height = 100;
332
mGLWindow = XCreateWindow(display(), rootWindow(), 0, 0, width, height,
333
0, QX11Info::appDepth(), InputOutput,
334
(Visual*)QX11Info::appVisual(), mask, &attr);
336
mEGLSurface = eglCreateWindowSurface(mEGLDisplay, config, mGLWindow, 0);
338
const EGLint context_attribs[] = {
339
EGL_CONTEXT_CLIENT_VERSION, 2,
343
mEGLContext = eglCreateContext(mEGLDisplay, config, EGL_NO_CONTEXT, context_attribs);
344
if (mEGLContext == EGL_NO_CONTEXT) {
347
if (eglMakeCurrent(mEGLDisplay, mEGLSurface, mEGLSurface, mEGLContext) == EGL_FALSE) {
350
EGLint error = eglGetError();
351
if (error != EGL_SUCCESS) {
360
void CompositingPrefs::deleteEGLContext()
362
#ifdef KWIN_HAVE_OPENGLES
363
eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
364
eglDestroyContext(mEGLDisplay, mEGLContext);
365
eglDestroySurface(mEGLDisplay, mEGLSurface);
366
eglTerminate(mEGLDisplay);
368
XDestroyWindow(display(), mGLWindow);
372
void CompositingPrefs::detectDriverAndVersion()
374
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
375
GLPlatform *gl = GLPlatform::instance();
381
// See http://techbase.kde.org/Projects/KWin/HW for a list of some cards that are known to work.
382
void CompositingPrefs::applyDriverSpecificOptions()
384
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
386
mRecommendCompositing = true;
388
GLPlatform *gl = GLPlatform::instance();
389
mStrictBinding = !gl->supports(LooseBinding);
390
if (gl->driver() == Driver_Intel)
391
mEnableVSync = false;