[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
This commit is contained in:
parent
afbc5222e1
commit
f1a9dc4d25
2 changed files with 80 additions and 11 deletions
|
@ -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()) {
|
||||||
glFlush();
|
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();
|
||||||
|
|
||||||
|
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()
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue