~ubuntu-branches/ubuntu/wily/kwin/wily-proposed

« back to all changes in this revision

Viewing changes to egl_wayland_backend.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2015-08-10 23:16:37 UTC
  • mfrom: (1.1.10)
  • Revision ID: package-import@ubuntu.com-20150810231637-5zb2tstjkez93hml
Tags: 4:5.3.95-0ubuntu1
new upstream beta release

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
 
2
 
/********************************************************************
3
 
 KWin - the KDE window manager
4
 
 This file is part of the KDE project.
5
 
 
6
 
Copyright (C) 2013 Martin Gräßlin <mgraesslin@kde.org>
7
 
 
8
 
This program is free software; you can redistribute it and/or modify
9
 
it under the terms of the GNU General Public License as published by
10
 
the Free Software Foundation; either version 2 of the License, or
11
 
(at your option) any later version.
12
 
 
13
 
This program is distributed in the hope that it will be useful,
14
 
but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 
GNU General Public License for more details.
17
 
 
18
 
You should have received a copy of the GNU General Public License
19
 
along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
 
*********************************************************************/
21
 
#define WL_EGL_PLATFORM 1
22
 
#include "egl_wayland_backend.h"
23
 
// kwin
24
 
#include "composite.h"
25
 
#include "options.h"
26
 
#include "wayland_backend.h"
27
 
#include "wayland_server.h"
28
 
#include <KWayland/Client/surface.h>
29
 
// kwin libs
30
 
#include <kwinglplatform.h>
31
 
// KDE
32
 
#include <KWayland/Server/buffer_interface.h>
33
 
#include <KWayland/Server/display.h>
34
 
// Qt
35
 
#include <QOpenGLContext>
36
 
 
37
 
namespace KWin
38
 
{
39
 
 
40
 
EglWaylandBackend::EglWaylandBackend(Wayland::WaylandBackend *b)
41
 
    : QObject(NULL)
42
 
    , AbstractEglBackend()
43
 
    , m_bufferAge(0)
44
 
    , m_wayland(b)
45
 
    , m_overlay(NULL)
46
 
{
47
 
    if (!m_wayland) {
48
 
        setFailed("Wayland Backend has not been created");
49
 
        return;
50
 
    }
51
 
    qCDebug(KWIN_CORE) << "Connected to Wayland display?" << (m_wayland->display() ? "yes" : "no" );
52
 
    if (!m_wayland->display()) {
53
 
        setFailed("Could not connect to Wayland compositor");
54
 
        return;
55
 
    }
56
 
    connect(m_wayland, SIGNAL(shellSurfaceSizeChanged(QSize)), SLOT(overlaySizeChanged(QSize)));
57
 
    initializeEgl();
58
 
    init();
59
 
    // Egl is always direct rendering
60
 
    setIsDirectRendering(true);
61
 
 
62
 
    qCWarning(KWIN_CORE) << "Using Wayland rendering backend";
63
 
    qCWarning(KWIN_CORE) << "This is a highly experimental backend, do not use for productive usage!";
64
 
    qCWarning(KWIN_CORE) << "Please do not report any issues you might encounter when using this backend!";
65
 
}
66
 
 
67
 
EglWaylandBackend::~EglWaylandBackend()
68
 
{
69
 
    cleanup();
70
 
    if (m_overlay) {
71
 
        wl_egl_window_destroy(m_overlay);
72
 
    }
73
 
}
74
 
 
75
 
bool EglWaylandBackend::initializeEgl()
76
 
{
77
 
    initClientExtensions();
78
 
    EGLDisplay display = EGL_NO_DISPLAY;
79
 
 
80
 
    // Use eglGetPlatformDisplayEXT() to get the display pointer
81
 
    // if the implementation supports it.
82
 
    m_havePlatformBase = hasClientExtension(QByteArrayLiteral("EGL_EXT_platform_base"));
83
 
    if (m_havePlatformBase) {
84
 
        // Make sure that the wayland platform is supported
85
 
        if (!hasClientExtension(QByteArrayLiteral("EGL_EXT_platform_wayland")))
86
 
            return false;
87
 
 
88
 
        display = eglGetPlatformDisplayEXT(EGL_PLATFORM_WAYLAND_EXT, m_wayland->display(), nullptr);
89
 
    } else {
90
 
        display = eglGetDisplay(m_wayland->display());
91
 
    }
92
 
 
93
 
    if (display == EGL_NO_DISPLAY)
94
 
        return false;
95
 
    setEglDisplay(display);
96
 
    return initEglAPI();
97
 
}
98
 
 
99
 
void EglWaylandBackend::init()
100
 
{
101
 
    if (!initRenderingContext()) {
102
 
        setFailed("Could not initialize rendering context");
103
 
        return;
104
 
    }
105
 
 
106
 
    initKWinGL();
107
 
    initBufferAge();
108
 
    initWayland();
109
 
}
110
 
 
111
 
bool EglWaylandBackend::initRenderingContext()
112
 
{
113
 
    initBufferConfigs();
114
 
 
115
 
    EGLContext context = EGL_NO_CONTEXT;
116
 
#ifdef KWIN_HAVE_OPENGLES
117
 
    const EGLint context_attribs[] = {
118
 
        EGL_CONTEXT_CLIENT_VERSION, 2,
119
 
        EGL_NONE
120
 
    };
121
 
 
122
 
    context = eglCreateContext(eglDisplay(), config(), EGL_NO_CONTEXT, context_attribs);
123
 
#else
124
 
    const EGLint context_attribs_31_core[] = {
125
 
        EGL_CONTEXT_MAJOR_VERSION_KHR, 3,
126
 
        EGL_CONTEXT_MINOR_VERSION_KHR, 1,
127
 
        EGL_CONTEXT_FLAGS_KHR,         EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR,
128
 
        EGL_NONE
129
 
    };
130
 
 
131
 
    const EGLint context_attribs_legacy[] = {
132
 
        EGL_NONE
133
 
    };
134
 
 
135
 
    const char* eglExtensionsCString = eglQueryString(eglDisplay(), EGL_EXTENSIONS);
136
 
    const QList<QByteArray> extensions = QByteArray::fromRawData(eglExtensionsCString, qstrlen(eglExtensionsCString)).split(' ');
137
 
 
138
 
    // Try to create a 3.1 core context
139
 
    if (options->glCoreProfile() && extensions.contains(QByteArrayLiteral("EGL_KHR_create_context")))
140
 
        context = eglCreateContext(eglDisplay(), config(), EGL_NO_CONTEXT, context_attribs_31_core);
141
 
 
142
 
    if (context == EGL_NO_CONTEXT)
143
 
        context = eglCreateContext(eglDisplay(), config(), EGL_NO_CONTEXT, context_attribs_legacy);
144
 
#endif
145
 
 
146
 
    if (context == EGL_NO_CONTEXT) {
147
 
        qCCritical(KWIN_CORE) << "Create Context failed";
148
 
        return false;
149
 
    }
150
 
    setContext(context);
151
 
 
152
 
    if (!m_wayland->surface()) {
153
 
        return false;
154
 
    }
155
 
 
156
 
    const QSize &size = m_wayland->shellSurfaceSize();
157
 
    auto s = m_wayland->surface();
158
 
    connect(s, &KWayland::Client::Surface::frameRendered, Compositor::self(), &Compositor::bufferSwapComplete);
159
 
    m_overlay = wl_egl_window_create(*s, size.width(), size.height());
160
 
    if (!m_overlay) {
161
 
        qCCritical(KWIN_CORE) << "Creating Wayland Egl window failed";
162
 
        return false;
163
 
    }
164
 
 
165
 
    EGLSurface surface = EGL_NO_SURFACE;
166
 
    if (m_havePlatformBase)
167
 
        surface = eglCreatePlatformWindowSurfaceEXT(eglDisplay(), config(), (void *) m_overlay, nullptr);
168
 
    else
169
 
        surface = eglCreateWindowSurface(eglDisplay(), config(), m_overlay, nullptr);
170
 
 
171
 
    if (surface == EGL_NO_SURFACE) {
172
 
        qCCritical(KWIN_CORE) << "Create Window Surface failed";
173
 
        return false;
174
 
    }
175
 
    setSurface(surface);
176
 
 
177
 
    return makeContextCurrent();
178
 
}
179
 
 
180
 
bool EglWaylandBackend::makeContextCurrent()
181
 
{
182
 
    if (eglMakeCurrent(eglDisplay(), surface(), surface(), context()) == EGL_FALSE) {
183
 
        qCCritical(KWIN_CORE) << "Make Context Current failed";
184
 
        return false;
185
 
    }
186
 
 
187
 
    EGLint error = eglGetError();
188
 
    if (error != EGL_SUCCESS) {
189
 
        qCWarning(KWIN_CORE) << "Error occurred while creating context " << error;
190
 
        return false;
191
 
    }
192
 
    return true;
193
 
}
194
 
 
195
 
bool EglWaylandBackend::initBufferConfigs()
196
 
{
197
 
    const EGLint config_attribs[] = {
198
 
        EGL_SURFACE_TYPE,         EGL_WINDOW_BIT,
199
 
        EGL_RED_SIZE,             1,
200
 
        EGL_GREEN_SIZE,           1,
201
 
        EGL_BLUE_SIZE,            1,
202
 
        EGL_ALPHA_SIZE,           0,
203
 
#ifdef KWIN_HAVE_OPENGLES
204
 
        EGL_RENDERABLE_TYPE,      EGL_OPENGL_ES2_BIT,
205
 
#else
206
 
        EGL_RENDERABLE_TYPE,      EGL_OPENGL_BIT,
207
 
#endif
208
 
        EGL_CONFIG_CAVEAT,        EGL_NONE,
209
 
        EGL_NONE,
210
 
    };
211
 
 
212
 
    EGLint count;
213
 
    EGLConfig configs[1024];
214
 
    if (eglChooseConfig(eglDisplay(), config_attribs, configs, 1, &count) == EGL_FALSE) {
215
 
        qCCritical(KWIN_CORE) << "choose config failed";
216
 
        return false;
217
 
    }
218
 
    if (count != 1) {
219
 
        qCCritical(KWIN_CORE) << "choose config did not return a config" << count;
220
 
        return false;
221
 
    }
222
 
    setConfig(configs[0]);
223
 
 
224
 
    return true;
225
 
}
226
 
 
227
 
void EglWaylandBackend::present()
228
 
{
229
 
    m_wayland->surface()->setupFrameCallback();
230
 
    Compositor::self()->aboutToSwapBuffers();
231
 
 
232
 
    if (supportsBufferAge()) {
233
 
        eglSwapBuffers(eglDisplay(), surface());
234
 
        eglQuerySurface(eglDisplay(), surface(), EGL_BUFFER_AGE_EXT, &m_bufferAge);
235
 
        setLastDamage(QRegion());
236
 
        return;
237
 
    } else {
238
 
        eglSwapBuffers(eglDisplay(), surface());
239
 
        setLastDamage(QRegion());
240
 
    }
241
 
}
242
 
 
243
 
void EglWaylandBackend::screenGeometryChanged(const QSize &size)
244
 
{
245
 
    Q_UNUSED(size)
246
 
    // no backend specific code needed
247
 
    // TODO: base implementation in OpenGLBackend
248
 
 
249
 
    // The back buffer contents are now undefined
250
 
    m_bufferAge = 0;
251
 
}
252
 
 
253
 
SceneOpenGL::TexturePrivate *EglWaylandBackend::createBackendTexture(SceneOpenGL::Texture *texture)
254
 
{
255
 
    return new EglWaylandTexture(texture, this);
256
 
}
257
 
 
258
 
QRegion EglWaylandBackend::prepareRenderingFrame()
259
 
{
260
 
    if (!lastDamage().isEmpty())
261
 
        present();
262
 
    QRegion repaint;
263
 
    if (supportsBufferAge())
264
 
        repaint = accumulatedDamageHistory(m_bufferAge);
265
 
    eglWaitNative(EGL_CORE_NATIVE_ENGINE);
266
 
    startRenderTimer();
267
 
    return repaint;
268
 
}
269
 
 
270
 
void EglWaylandBackend::endRenderingFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
271
 
{
272
 
    if (damagedRegion.isEmpty()) {
273
 
        setLastDamage(QRegion());
274
 
 
275
 
        // If the damaged region of a window is fully occluded, the only
276
 
        // rendering done, if any, will have been to repair a reused back
277
 
        // buffer, making it identical to the front buffer.
278
 
        //
279
 
        // In this case we won't post the back buffer. Instead we'll just
280
 
        // set the buffer age to 1, so the repaired regions won't be
281
 
        // rendered again in the next frame.
282
 
        if (!renderedRegion.isEmpty())
283
 
            glFlush();
284
 
 
285
 
        m_bufferAge = 1;
286
 
        return;
287
 
    }
288
 
 
289
 
    setLastDamage(renderedRegion);
290
 
 
291
 
    if (!blocksForRetrace()) {
292
 
        // This also sets lastDamage to empty which prevents the frame from
293
 
        // being posted again when prepareRenderingFrame() is called.
294
 
        present();
295
 
    } else {
296
 
        // Make sure that the GPU begins processing the command stream
297
 
        // now and not the next time prepareRenderingFrame() is called.
298
 
        glFlush();
299
 
    }
300
 
 
301
 
    // Save the damaged region to history
302
 
    if (supportsBufferAge())
303
 
        addToDamageHistory(damagedRegion);
304
 
}
305
 
 
306
 
void EglWaylandBackend::overlaySizeChanged(const QSize &size)
307
 
{
308
 
    wl_egl_window_resize(m_overlay, size.width(), size.height(), 0, 0);
309
 
}
310
 
 
311
 
bool EglWaylandBackend::usesOverlayWindow() const
312
 
{
313
 
    return false;
314
 
}
315
 
 
316
 
/************************************************
317
 
 * EglTexture
318
 
 ************************************************/
319
 
 
320
 
EglWaylandTexture::EglWaylandTexture(KWin::SceneOpenGL::Texture *texture, KWin::EglWaylandBackend *backend)
321
 
    : AbstractEglTexture(texture, backend)
322
 
{
323
 
}
324
 
 
325
 
EglWaylandTexture::~EglWaylandTexture() = default;
326
 
 
327
 
} // namespace