[kwin] Re-enable the optional and experimental Wayland support

* Find Wayland was missing in CMakeLists.txt
* Wayland Backend is adjusted for new virtual methods (makeCurrent, doneCurrent)
* Buffer Age is implemented
icc-effect-5.14.5
Martin Gräßlin 2014-01-07 11:57:29 +01:00
parent afbc5222e1
commit f1a9dc4d25
2 changed files with 80 additions and 11 deletions

View File

@ -29,6 +29,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// Qt // Qt
#include <QSocketNotifier> #include <QSocketNotifier>
#include <QTemporaryFile> #include <QTemporaryFile>
#include <QOpenGLContext>
// xcb // xcb
#include <xcb/xtest.h> #include <xcb/xtest.h>
// Wayland // Wayland
@ -627,6 +628,7 @@ void WaylandBackend::ping(uint32_t serial)
EglWaylandBackend::EglWaylandBackend() EglWaylandBackend::EglWaylandBackend()
: OpenGLBackend() : OpenGLBackend()
, m_context(EGL_NO_CONTEXT) , m_context(EGL_NO_CONTEXT)
, m_bufferAge(0)
, m_wayland(new Wayland::WaylandBackend) , m_wayland(new Wayland::WaylandBackend)
{ {
qDebug() << "Connected to Wayland display?" << (m_wayland->display() ? "yes" : "no" ); qDebug() << "Connected to Wayland display?" << (m_wayland->display() ? "yes" : "no" );
@ -647,7 +649,7 @@ EglWaylandBackend::EglWaylandBackend()
EglWaylandBackend::~EglWaylandBackend() EglWaylandBackend::~EglWaylandBackend()
{ {
cleanupGL(); cleanupGL();
eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); doneCurrent();
eglDestroyContext(m_display, m_context); eglDestroyContext(m_display, m_context);
eglDestroySurface(m_display, m_surface); eglDestroySurface(m_display, m_surface);
eglTerminate(m_display); eglTerminate(m_display);
@ -694,6 +696,15 @@ void EglWaylandBackend::init()
glPlatform->detect(EglPlatformInterface); glPlatform->detect(EglPlatformInterface);
glPlatform->printResults(); glPlatform->printResults();
initGL(EglPlatformInterface); initGL(EglPlatformInterface);
setSupportsBufferAge(false);
if (hasGLExtension("EGL_EXT_buffer_age")) {
const QByteArray useBufferAge = qgetenv("KWIN_USE_BUFFER_AGE");
if (useBufferAge != "0")
setSupportsBufferAge(true);
}
} }
bool EglWaylandBackend::initRenderingContext() bool EglWaylandBackend::initRenderingContext()
@ -797,14 +808,19 @@ bool EglWaylandBackend::initBufferConfigs()
void EglWaylandBackend::present() void EglWaylandBackend::present()
{ {
setLastDamage(QRegion());
// need to dispatch pending events as eglSwapBuffers can block // need to dispatch pending events as eglSwapBuffers can block
wl_display_dispatch_pending(m_wayland->display()); wl_display_dispatch_pending(m_wayland->display());
wl_display_flush(m_wayland->display()); wl_display_flush(m_wayland->display());
// a different context might have been current if (supportsBufferAge()) {
eglMakeCurrent(m_display, m_surface, m_surface, m_context);
eglSwapBuffers(m_display, m_surface); eglSwapBuffers(m_display, m_surface);
eglQuerySurface(m_display, m_surface, EGL_BUFFER_AGE_EXT, &m_bufferAge);
setLastDamage(QRegion());
return;
} else {
eglSwapBuffers(m_display, m_surface);
setLastDamage(QRegion());
}
} }
void EglWaylandBackend::screenGeometryChanged(const QSize &size) void EglWaylandBackend::screenGeometryChanged(const QSize &size)
@ -812,6 +828,9 @@ void EglWaylandBackend::screenGeometryChanged(const QSize &size)
Q_UNUSED(size) Q_UNUSED(size)
// no backend specific code needed // no backend specific code needed
// TODO: base implementation in OpenGLBackend // TODO: base implementation in OpenGLBackend
// The back buffer contents are now undefined
m_bufferAge = 0;
} }
SceneOpenGL::TexturePrivate *EglWaylandBackend::createBackendTexture(SceneOpenGL::Texture *texture) SceneOpenGL::TexturePrivate *EglWaylandBackend::createBackendTexture(SceneOpenGL::Texture *texture)
@ -819,20 +838,67 @@ SceneOpenGL::TexturePrivate *EglWaylandBackend::createBackendTexture(SceneOpenGL
return new EglWaylandTexture(texture, this); return new EglWaylandTexture(texture, this);
} }
void EglWaylandBackend::prepareRenderingFrame() QRegion EglWaylandBackend::prepareRenderingFrame()
{ {
if (!lastDamage().isEmpty()) if (!lastDamage().isEmpty())
present(); present();
// different context might have been bound as present() can block QRegion repaint;
eglMakeCurrent(m_display, m_surface, m_surface, m_context); if (supportsBufferAge())
repaint = accumulatedDamageHistory(m_bufferAge);
eglWaitNative(EGL_CORE_NATIVE_ENGINE); eglWaitNative(EGL_CORE_NATIVE_ENGINE);
startRenderTimer(); startRenderTimer();
return repaint;
} }
void EglWaylandBackend::endRenderingFrame(const QRegion &damage) void EglWaylandBackend::endRenderingFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
{ {
setLastDamage(damage); if (damagedRegion.isEmpty()) {
setLastDamage(QRegion());
// If the damaged region of a window is fully occluded, the only
// rendering done, if any, will have been to repair a reused back
// buffer, making it identical to the front buffer.
//
// In this case we won't post the back buffer. Instead we'll just
// set the buffer age to 1, so the repaired regions won't be
// rendered again in the next frame.
if (!renderedRegion.isEmpty())
glFlush(); glFlush();
m_bufferAge = 1;
return;
}
setLastDamage(renderedRegion);
if (!blocksForRetrace()) {
// This also sets lastDamage to empty which prevents the frame from
// being posted again when prepareRenderingFrame() is called.
present();
} else {
// Make sure that the GPU begins processing the command stream
// now and not the next time prepareRenderingFrame() is called.
glFlush();
}
// Save the damaged region to history
if (supportsBufferAge())
addToDamageHistory(damagedRegion);
}
bool EglWaylandBackend::makeCurrent()
{
if (QOpenGLContext *context = QOpenGLContext::currentContext()) {
// Workaround to tell Qt that no QOpenGLContext is current
context->doneCurrent();
}
const bool current = eglMakeCurrent(m_display, m_surface, m_surface, m_context);
return current;
}
void EglWaylandBackend::doneCurrent()
{
eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
} }
Shm *EglWaylandBackend::shm() Shm *EglWaylandBackend::shm()

View File

@ -266,6 +266,8 @@ public:
virtual SceneOpenGL::TexturePrivate *createBackendTexture(SceneOpenGL::Texture *texture); virtual SceneOpenGL::TexturePrivate *createBackendTexture(SceneOpenGL::Texture *texture);
virtual QRegion prepareRenderingFrame(); virtual QRegion prepareRenderingFrame();
virtual void endRenderingFrame(const QRegion &renderedRegion, const QRegion &damagedRegion); virtual void endRenderingFrame(const QRegion &renderedRegion, const QRegion &damagedRegion);
virtual bool makeCurrent() override;
virtual void doneCurrent() override;
Shm *shm(); Shm *shm();
protected: protected:
@ -281,6 +283,7 @@ private:
EGLConfig m_config; EGLConfig m_config;
EGLSurface m_surface; EGLSurface m_surface;
EGLContext m_context; EGLContext m_context;
int m_bufferAge;
QScopedPointer<Wayland::WaylandBackend> m_wayland; QScopedPointer<Wayland::WaylandBackend> m_wayland;
QScopedPointer<Shm> m_shm; QScopedPointer<Shm> m_shm;
friend class EglWaylandTexture; friend class EglWaylandTexture;