Merge branch 'KDE/4.11' into master
Conflicts: CMakeLists.txt doc/kcontrol/screensaver/index.docbook kcontrol/krdb/krdb.cpp kscreensaver/kblank_screensaver/kblank.desktop kscreensaver/krandom_screensaver/krandom.desktop kscreensaver/libkscreensaver/main.cpp ksplash/ksplashqml/SplashApp.cpp kstyles/oxygen/config/main.cpp kstyles/oxygen/demo/main.cpp kstyles/oxygen/oxygenstylehelper.cpp kwin/clients/oxygen/config/oxygenexceptiondialog.cpp kwin/clients/oxygen/config/ui/oxygenconfigurationui.ui kwin/clients/oxygen/config/ui/oxygenexceptiondialog.ui kwin/clients/oxygen/demo/main.cpp kwin/clients/oxygen/oxygenconfigdata.kcfg kwin/egl_wayland_backend.cpp kwin/eglonxbackend.h kwin/glxbackend.cpp kwin/glxbackend.h kwin/kcmkwin/kwinoptions/kwinactions.desktop kwin/scene_opengl.cpp kwin/scene_opengl.h plasma/desktop/applets/pager/pager.cpp plasma/desktop/shell/activitymanager/activitymanager.cpp plasma/desktop/shell/activitymanager/activitymanager.h plasma/desktop/shell/controllerwindow.cpp plasma/desktop/shell/data/plasma-desktop.desktop plasma/generic/dataengines/geolocation/geolocation.cpp plasma/generic/dataengines/nowplaying/plasma-dataengine-nowplaying.desktop plasma/generic/wallpapers/color/plasma-wallpaper-color.desktop plasma/generic/wallpapers/image/image.cpp plasma/generic/wallpapers/image/image.h
This commit is contained in:
commit
afbc5222e1
12 changed files with 281 additions and 45 deletions
|
@ -172,7 +172,7 @@ Comment[zh_TW]=下一代桌面的樣式
|
|||
X-KDE-Library=kwin3_oxygen
|
||||
|
||||
X-KDE-PluginInfo-Author=Nuno Pinheiro, Casper Boemann, Riccardo Iaconelli, Huynh Huu Long, Thomas Luebking, Hugo Pereira Da Costa, Matthew Woehlke
|
||||
X-KDE-PluginInfo-Email=nuno@oxygen-icons.org, cbr@boemann.dk, riccardo@kde.org, long.upcase@googlemail.com, thomas.luebking@web.de, hugo@oxygen-icons.org, mw_triad@users.sourceforge.net
|
||||
X-KDE-PluginInfo-Email=nuno@oxygen-icons.org, cbr@boemann.dk, riccardo@kde.org, long.upcase@googlemail.com, thomas.luebking@web.de, hugo.pereira@free.fr, mw_triad@users.sourceforge.net
|
||||
X-KDE-PluginInfo-Name=Oxygen
|
||||
X-KDE-PluginInfo-Category=
|
||||
X-KDE-PluginInfo-Depends=
|
||||
|
|
|
@ -264,8 +264,8 @@ public:
|
|||
virtual ~EglWaylandBackend();
|
||||
virtual void screenGeometryChanged(const QSize &size);
|
||||
virtual SceneOpenGL::TexturePrivate *createBackendTexture(SceneOpenGL::Texture *texture);
|
||||
virtual void prepareRenderingFrame();
|
||||
virtual void endRenderingFrame(const QRegion &damage);
|
||||
virtual QRegion prepareRenderingFrame();
|
||||
virtual void endRenderingFrame(const QRegion &renderedRegion, const QRegion &damagedRegion);
|
||||
Shm *shm();
|
||||
|
||||
protected:
|
||||
|
|
|
@ -37,6 +37,7 @@ EglOnXBackend::EglOnXBackend()
|
|||
: OpenGLBackend()
|
||||
, ctx(EGL_NO_CONTEXT)
|
||||
, surfaceHasSubPost(0)
|
||||
, m_bufferAge(0)
|
||||
{
|
||||
init();
|
||||
// Egl is always direct rendering
|
||||
|
@ -99,6 +100,16 @@ void EglOnXBackend::init()
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
setSupportsBufferAge(false);
|
||||
|
||||
if (hasGLExtension("EGL_EXT_buffer_age")) {
|
||||
const QByteArray useBufferAge = qgetenv("KWIN_USE_BUFFER_AGE");
|
||||
|
||||
if (useBufferAge != "0")
|
||||
setSupportsBufferAge(true);
|
||||
}
|
||||
|
||||
setSyncsToVBlank(false);
|
||||
setBlocksForRetrace(false);
|
||||
gs_tripleBufferNeedsDetection = false;
|
||||
|
@ -268,6 +279,13 @@ void EglOnXBackend::present()
|
|||
if (lastDamage().isEmpty())
|
||||
return;
|
||||
|
||||
if (supportsBufferAge()) {
|
||||
eglSwapBuffers(dpy, surface);
|
||||
eglQuerySurface(dpy, surface, EGL_BUFFER_AGE_EXT, &m_bufferAge);
|
||||
setLastDamage(QRegion());
|
||||
return;
|
||||
}
|
||||
|
||||
const QRegion displayRegion(0, 0, displayWidth(), displayHeight());
|
||||
const bool fullRepaint = (lastDamage() == displayRegion);
|
||||
|
||||
|
@ -312,8 +330,11 @@ void EglOnXBackend::present()
|
|||
void EglOnXBackend::screenGeometryChanged(const QSize &size)
|
||||
{
|
||||
Q_UNUSED(size)
|
||||
// no backend specific code needed
|
||||
|
||||
// TODO: base implementation in OpenGLBackend
|
||||
|
||||
// The back buffer contents are now undefined
|
||||
m_bufferAge = 0;
|
||||
}
|
||||
|
||||
SceneOpenGL::TexturePrivate *EglOnXBackend::createBackendTexture(SceneOpenGL::Texture *texture)
|
||||
|
@ -321,8 +342,10 @@ SceneOpenGL::TexturePrivate *EglOnXBackend::createBackendTexture(SceneOpenGL::Te
|
|||
return new EglTexture(texture, this);
|
||||
}
|
||||
|
||||
void EglOnXBackend::prepareRenderingFrame()
|
||||
QRegion EglOnXBackend::prepareRenderingFrame()
|
||||
{
|
||||
QRegion repaint;
|
||||
|
||||
if (gs_tripleBufferNeedsDetection) {
|
||||
// the composite timer floors the repaint frequency. This can pollute our triple buffering
|
||||
// detection because the glXSwapBuffers call for the new frame has to wait until the pending
|
||||
|
@ -331,21 +354,55 @@ void EglOnXBackend::prepareRenderingFrame()
|
|||
// fllush the buffer queue
|
||||
usleep(1000);
|
||||
}
|
||||
|
||||
present();
|
||||
|
||||
if (supportsBufferAge())
|
||||
repaint = accumulatedDamageHistory(m_bufferAge);
|
||||
|
||||
startRenderTimer();
|
||||
eglWaitNative(EGL_CORE_NATIVE_ENGINE);
|
||||
|
||||
return repaint;
|
||||
}
|
||||
|
||||
void EglOnXBackend::endRenderingFrame(const QRegion &damage)
|
||||
void EglOnXBackend::endRenderingFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
|
||||
{
|
||||
setLastDamage(damage);
|
||||
glFlush();
|
||||
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();
|
||||
|
||||
m_bufferAge = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
setLastDamage(renderedRegion);
|
||||
|
||||
if (!blocksForRetrace()) {
|
||||
present(); // this sets lastDamage emtpy and prevents execution from prepareRenderingFrame()
|
||||
// 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();
|
||||
}
|
||||
|
||||
if (overlayWindow()->window()) // show the window only after the first pass,
|
||||
overlayWindow()->show(); // since that pass may take long
|
||||
|
||||
// Save the damaged region to history
|
||||
if (supportsBufferAge())
|
||||
addToDamageHistory(damagedRegion);
|
||||
}
|
||||
|
||||
bool EglOnXBackend::makeCurrent()
|
||||
|
|
|
@ -34,8 +34,8 @@ public:
|
|||
virtual ~EglOnXBackend();
|
||||
virtual void screenGeometryChanged(const QSize &size);
|
||||
virtual SceneOpenGL::TexturePrivate *createBackendTexture(SceneOpenGL::Texture *texture);
|
||||
virtual void prepareRenderingFrame();
|
||||
virtual void endRenderingFrame(const QRegion &damage);
|
||||
virtual QRegion prepareRenderingFrame();
|
||||
virtual void endRenderingFrame(const QRegion &damage, const QRegion &damagedRegion);
|
||||
virtual bool makeCurrent() override;
|
||||
virtual void doneCurrent() override;
|
||||
|
||||
|
@ -51,6 +51,7 @@ private:
|
|||
EGLSurface surface;
|
||||
EGLContext ctx;
|
||||
int surfaceHasSubPost;
|
||||
int m_bufferAge;
|
||||
friend class EglTexture;
|
||||
};
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@ GlxBackend::GlxBackend()
|
|||
, fbconfig(NULL)
|
||||
, glxWindow(None)
|
||||
, ctx(nullptr)
|
||||
, m_bufferAge(0)
|
||||
, haveSwapInterval(false)
|
||||
{
|
||||
init();
|
||||
|
@ -104,8 +105,19 @@ void GlxBackend::init()
|
|||
options->setGlPreferBufferSwap('e'); // for unknown drivers - should not happen
|
||||
glPlatform->printResults();
|
||||
initGL(GlxPlatformInterface);
|
||||
|
||||
// Check whether certain features are supported
|
||||
haveSwapInterval = glXSwapIntervalMESA || glXSwapIntervalEXT || glXSwapIntervalSGI;
|
||||
|
||||
setSupportsBufferAge(false);
|
||||
|
||||
if (hasGLExtension("GLX_EXT_buffer_age")) {
|
||||
const QByteArray useBufferAge = qgetenv("KWIN_USE_BUFFER_AGE");
|
||||
|
||||
if (useBufferAge != "0")
|
||||
setSupportsBufferAge(true);
|
||||
}
|
||||
|
||||
setSyncsToVBlank(false);
|
||||
setBlocksForRetrace(false);
|
||||
haveWaitSync = false;
|
||||
|
@ -426,6 +438,13 @@ void GlxBackend::present()
|
|||
if (lastDamage().isEmpty())
|
||||
return;
|
||||
|
||||
if (supportsBufferAge()) {
|
||||
glXSwapBuffers(display(), glxWindow);
|
||||
glXQueryDrawable(display(), glxWindow, GLX_BACK_BUFFER_AGE_EXT, (GLuint *) &m_bufferAge);
|
||||
setLastDamage(QRegion());
|
||||
return;
|
||||
}
|
||||
|
||||
const QRegion displayRegion(0, 0, displayWidth(), displayHeight());
|
||||
const bool fullRepaint = (lastDamage() == displayRegion);
|
||||
|
||||
|
@ -486,6 +505,9 @@ void GlxBackend::screenGeometryChanged(const QSize &size)
|
|||
|
||||
makeCurrent();
|
||||
glViewport(0, 0, size.width(), size.height());
|
||||
|
||||
// The back buffer contents are now undefined
|
||||
m_bufferAge = 0;
|
||||
}
|
||||
|
||||
SceneOpenGL::TexturePrivate *GlxBackend::createBackendTexture(SceneOpenGL::Texture *texture)
|
||||
|
@ -493,8 +515,10 @@ SceneOpenGL::TexturePrivate *GlxBackend::createBackendTexture(SceneOpenGL::Textu
|
|||
return new GlxTexture(texture, this);
|
||||
}
|
||||
|
||||
void GlxBackend::prepareRenderingFrame()
|
||||
QRegion GlxBackend::prepareRenderingFrame()
|
||||
{
|
||||
QRegion repaint;
|
||||
|
||||
if (gs_tripleBufferNeedsDetection) {
|
||||
// the composite timer floors the repaint frequency. This can pollute our triple buffering
|
||||
// detection because the glXSwapBuffers call for the new frame has to wait until the pending
|
||||
|
@ -503,21 +527,55 @@ void GlxBackend::prepareRenderingFrame()
|
|||
// fllush the buffer queue
|
||||
usleep(1000);
|
||||
}
|
||||
|
||||
present();
|
||||
|
||||
if (supportsBufferAge())
|
||||
repaint = accumulatedDamageHistory(m_bufferAge);
|
||||
|
||||
startRenderTimer();
|
||||
glXWaitX();
|
||||
|
||||
return repaint;
|
||||
}
|
||||
|
||||
void GlxBackend::endRenderingFrame(const QRegion &damage)
|
||||
void GlxBackend::endRenderingFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
|
||||
{
|
||||
setLastDamage(damage);
|
||||
glFlush();
|
||||
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();
|
||||
|
||||
m_bufferAge = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
setLastDamage(renderedRegion);
|
||||
|
||||
if (!blocksForRetrace()) {
|
||||
present(); // this sets lastDamage emtpy and prevents execution from prepareRenderingFrame()
|
||||
// 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();
|
||||
}
|
||||
|
||||
if (overlayWindow()->window()) // show the window only after the first pass,
|
||||
overlayWindow()->show(); // since that pass may take long
|
||||
|
||||
// Save the damaged region to history
|
||||
if (supportsBufferAge())
|
||||
addToDamageHistory(damagedRegion);
|
||||
}
|
||||
|
||||
bool GlxBackend::makeCurrent()
|
||||
|
|
|
@ -44,8 +44,8 @@ public:
|
|||
virtual ~GlxBackend();
|
||||
virtual void screenGeometryChanged(const QSize &size);
|
||||
virtual SceneOpenGL::TexturePrivate *createBackendTexture(SceneOpenGL::Texture *texture);
|
||||
virtual void prepareRenderingFrame();
|
||||
virtual void endRenderingFrame(const QRegion &damage);
|
||||
virtual QRegion prepareRenderingFrame();
|
||||
virtual void endRenderingFrame(const QRegion &damage, const QRegion &damagedRegion);
|
||||
virtual bool makeCurrent() override;
|
||||
virtual void doneCurrent() override;
|
||||
|
||||
|
@ -66,6 +66,7 @@ private:
|
|||
GLXFBConfig fbconfig;
|
||||
GLXWindow glxWindow;
|
||||
GLXContext ctx;
|
||||
int m_bufferAge;
|
||||
bool haveSwapInterval, haveWaitSync;
|
||||
friend class GlxTexture;
|
||||
};
|
||||
|
|
|
@ -75,6 +75,9 @@ void KWINGLUTILS_EXPORT glResolveFunctions(OpenGLPlatformInterface platformInter
|
|||
#define GL_READ_FRAMEBUFFER 0x8CA8
|
||||
#endif
|
||||
|
||||
#ifndef GLX_BACK_BUFFER_AGE_EXT
|
||||
#define GLX_BACK_BUFFER_AGE_EXT 0x20F4
|
||||
#endif
|
||||
|
||||
#include <fixx11h.h>
|
||||
|
||||
|
@ -501,6 +504,10 @@ extern KWINGLUTILS_EXPORT glCopyBufferSubData_func glCopyBufferSubData;
|
|||
#define EGL_POST_SUB_BUFFER_SUPPORTED_NV 0x30BE
|
||||
#endif
|
||||
|
||||
#ifndef EGL_BUFFER_AGE_EXT
|
||||
#define EGL_BUFFER_AGE_EXT 0x313D
|
||||
#endif
|
||||
|
||||
#ifndef GL_UNPACK_ROW_LENGTH
|
||||
#define GL_UNPACK_ROW_LENGTH 0x0CF2
|
||||
#endif
|
||||
|
|
66
scene.cpp
66
scene.cpp
|
@ -101,48 +101,62 @@ Scene::~Scene()
|
|||
}
|
||||
|
||||
// returns mask and possibly modified region
|
||||
void Scene::paintScreen(int* mask, QRegion* region)
|
||||
void Scene::paintScreen(int* mask, const QRegion &damage, const QRegion &repaint,
|
||||
QRegion *updateRegion, QRegion *validRegion)
|
||||
{
|
||||
const QRegion displayRegion(0, 0, displayWidth(), displayHeight());
|
||||
*mask = (*region == displayRegion) ? 0 : PAINT_SCREEN_REGION;
|
||||
*mask = (damage == displayRegion) ? 0 : PAINT_SCREEN_REGION;
|
||||
|
||||
updateTimeDiff();
|
||||
// preparation step
|
||||
static_cast<EffectsHandlerImpl*>(effects)->startPaint();
|
||||
|
||||
QRegion region = damage;
|
||||
|
||||
ScreenPrePaintData pdata;
|
||||
pdata.mask = *mask;
|
||||
pdata.paint = *region;
|
||||
pdata.paint = region;
|
||||
|
||||
effects->prePaintScreen(pdata, time_diff);
|
||||
*mask = pdata.mask;
|
||||
*region = pdata.paint;
|
||||
region = pdata.paint;
|
||||
|
||||
if (*mask & (PAINT_SCREEN_TRANSFORMED | PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS)) {
|
||||
// Region painting is not possible with transformations,
|
||||
// because screen damage doesn't match transformed positions.
|
||||
*mask &= ~PAINT_SCREEN_REGION;
|
||||
*region = infiniteRegion();
|
||||
region = infiniteRegion();
|
||||
} else if (*mask & PAINT_SCREEN_REGION) {
|
||||
// make sure not to go outside visible screen
|
||||
*region &= displayRegion;
|
||||
region &= displayRegion;
|
||||
} else {
|
||||
// whole screen, not transformed, force region to be full
|
||||
*region = displayRegion;
|
||||
region = displayRegion;
|
||||
}
|
||||
painted_region = *region;
|
||||
|
||||
painted_region = region;
|
||||
repaint_region = repaint;
|
||||
|
||||
if (*mask & PAINT_SCREEN_BACKGROUND_FIRST) {
|
||||
paintBackground(*region);
|
||||
paintBackground(region);
|
||||
}
|
||||
|
||||
ScreenPaintData data;
|
||||
effects->paintScreen(*mask, *region, data);
|
||||
foreach (Window * w, stacking_order) {
|
||||
effects->paintScreen(*mask, region, data);
|
||||
|
||||
foreach (Window *w, stacking_order) {
|
||||
effects->postPaintWindow(effectWindow(w));
|
||||
}
|
||||
|
||||
effects->postPaintScreen();
|
||||
*region |= painted_region;
|
||||
|
||||
// make sure not to go outside of the screen area
|
||||
*region &= displayRegion;
|
||||
*updateRegion = damaged_region;
|
||||
*validRegion = (region | painted_region) & displayRegion;
|
||||
|
||||
repaint_region = QRegion();
|
||||
damaged_region = QRegion();
|
||||
|
||||
// make sure all clipping is restored
|
||||
Q_ASSERT(!PaintClipper::clip());
|
||||
}
|
||||
|
@ -222,6 +236,8 @@ void Scene::paintGenericScreen(int orig_mask, ScreenPaintData)
|
|||
foreach (const Phase2Data & d, phase2) {
|
||||
paintWindow(d.window, d.mask, d.region, d.quads);
|
||||
}
|
||||
|
||||
damaged_region = QRegion(0, 0, displayWidth(), displayHeight());
|
||||
}
|
||||
|
||||
// The optimized case without any transformations at all.
|
||||
|
@ -298,8 +314,13 @@ void Scene::paintSimpleScreen(int orig_mask, QRegion region)
|
|||
w->suspendUnredirect(data.mask & PAINT_WINDOW_TRANSLUCENT);
|
||||
}
|
||||
|
||||
const QRegion displayRegion(0, 0, displayWidth(), displayHeight());
|
||||
// Save the part of the repaint region that's exclusively rendered to
|
||||
// bring a reused back buffer up to date. Then union the dirty region
|
||||
// with the repaint region.
|
||||
const QRegion repaintClip = repaint_region - dirtyArea;
|
||||
dirtyArea |= repaint_region;
|
||||
|
||||
const QRegion displayRegion(0, 0, displayWidth(), displayHeight());
|
||||
bool fullRepaint(dirtyArea == displayRegion); // spare some expensive region operations
|
||||
if (!fullRepaint) {
|
||||
extendPaintRegion(dirtyArea, opaqueFullscreen);
|
||||
|
@ -307,6 +328,8 @@ void Scene::paintSimpleScreen(int orig_mask, QRegion region)
|
|||
}
|
||||
|
||||
QRegion allclips, upperTranslucentDamage;
|
||||
upperTranslucentDamage = repaint_region;
|
||||
|
||||
// This is the occlusion culling pass
|
||||
for (int i = phase2data.count() - 1; i >= 0; --i) {
|
||||
QPair< Window*, Phase2Data > *entry = &phase2data[i];
|
||||
|
@ -351,10 +374,21 @@ void Scene::paintSimpleScreen(int orig_mask, QRegion region)
|
|||
|
||||
paintWindow(data->window, data->mask, data->region, data->quads);
|
||||
}
|
||||
if (fullRepaint)
|
||||
|
||||
if (fullRepaint) {
|
||||
painted_region = displayRegion;
|
||||
else
|
||||
damaged_region = displayRegion;
|
||||
} else {
|
||||
painted_region |= paintedArea;
|
||||
|
||||
// Clip the repainted region from the damaged region.
|
||||
// It's important that we don't add the union of the damaged region
|
||||
// and the repainted region to the damage history. Otherwise the
|
||||
// repaint region will grow with every frame until it eventually
|
||||
// covers the whole back buffer, at which point we're always doing
|
||||
// full repaints.
|
||||
damaged_region = paintedArea - repaintClip;
|
||||
}
|
||||
}
|
||||
|
||||
static Scene::Window *s_recursionCheck = NULL;
|
||||
|
|
7
scene.h
7
scene.h
|
@ -117,7 +117,8 @@ public Q_SLOTS:
|
|||
virtual void windowClosed(KWin::Toplevel* c, KWin::Deleted* deleted) = 0;
|
||||
protected:
|
||||
// shared implementation, starts painting the screen
|
||||
void paintScreen(int* mask, QRegion* region);
|
||||
void paintScreen(int *mask, const QRegion &damage, const QRegion &repaint,
|
||||
QRegion *updateRegion, QRegion *validRegion);
|
||||
friend class EffectsHandlerImpl;
|
||||
// called after all effects had their paintScreen() called
|
||||
void finalPaintScreen(int mask, QRegion region, ScreenPaintData& data);
|
||||
|
@ -162,6 +163,10 @@ protected:
|
|||
// up all the way from paintSimpleScreen() up to paintScreen(), so save them here rather
|
||||
// than propagate them up in arguments.
|
||||
QRegion painted_region;
|
||||
// Additional damage that needs to be repaired to bring a reused back buffer up to date
|
||||
QRegion repaint_region;
|
||||
// The dirty region before it was unioned with repaint_region
|
||||
QRegion damaged_region;
|
||||
// time since last repaint
|
||||
int time_diff;
|
||||
QElapsedTimer last_time;
|
||||
|
|
|
@ -83,6 +83,7 @@ OpenGLBackend::OpenGLBackend()
|
|||
, m_syncsToVBlank(false)
|
||||
, m_blocksForRetrace(false)
|
||||
, m_directRendering(false)
|
||||
, m_haveBufferAge(false)
|
||||
, m_failed(false)
|
||||
{
|
||||
}
|
||||
|
@ -109,6 +110,29 @@ void OpenGLBackend::idle()
|
|||
}
|
||||
}
|
||||
|
||||
void OpenGLBackend::addToDamageHistory(const QRegion ®ion)
|
||||
{
|
||||
if (m_damageHistory.count() > 10)
|
||||
m_damageHistory.removeLast();
|
||||
|
||||
m_damageHistory.prepend(region);
|
||||
}
|
||||
|
||||
QRegion OpenGLBackend::accumulatedDamageHistory(int bufferAge) const
|
||||
{
|
||||
QRegion region;
|
||||
|
||||
// Note: An age of zero means the buffer contents are undefined
|
||||
if (bufferAge > 0 && bufferAge <= m_damageHistory.count()) {
|
||||
for (int i = 0; i < bufferAge - 1; i++)
|
||||
region |= m_damageHistory[i];
|
||||
} else {
|
||||
region = QRegion(0, 0, displayWidth(), displayHeight());
|
||||
}
|
||||
|
||||
return region;
|
||||
}
|
||||
|
||||
/************************************************
|
||||
* SceneOpenGL
|
||||
***********************************************/
|
||||
|
@ -343,7 +367,7 @@ qint64 SceneOpenGL::paint(QRegion damage, ToplevelList toplevels)
|
|||
}
|
||||
|
||||
m_backend->makeCurrent();
|
||||
m_backend->prepareRenderingFrame();
|
||||
QRegion repaint = m_backend->prepareRenderingFrame();
|
||||
|
||||
const GLenum status = glGetGraphicsResetStatus();
|
||||
if (status != GL_NO_ERROR) {
|
||||
|
@ -356,22 +380,33 @@ qint64 SceneOpenGL::paint(QRegion damage, ToplevelList toplevels)
|
|||
checkGLError("Paint1");
|
||||
#endif
|
||||
|
||||
paintScreen(&mask, &damage); // call generic implementation
|
||||
// After this call, updateRegion will contain the damaged region in the
|
||||
// back buffer. This is the region that needs to be posted to repair
|
||||
// the front buffer. It doesn't include the additional damage returned
|
||||
// by prepareRenderingFrame(). validRegion is the region that has been
|
||||
// repainted, and may be larger than updateRegion.
|
||||
QRegion updateRegion, validRegion;
|
||||
paintScreen(&mask, damage, repaint, &updateRegion, &validRegion); // call generic implementation
|
||||
|
||||
#ifndef KWIN_HAVE_OPENGLES
|
||||
const QRegion displayRegion(0, 0, displayWidth(), displayHeight());
|
||||
|
||||
// copy dirty parts from front to backbuffer
|
||||
if (options->glPreferBufferSwap() == Options::CopyFrontBuffer && damage != displayRegion) {
|
||||
if (!m_backend->supportsBufferAge() &&
|
||||
options->glPreferBufferSwap() == Options::CopyFrontBuffer &&
|
||||
validRegion != displayRegion) {
|
||||
glReadBuffer(GL_FRONT);
|
||||
copyPixels(displayRegion - damage);
|
||||
copyPixels(displayRegion - validRegion);
|
||||
glReadBuffer(GL_BACK);
|
||||
damage = displayRegion;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CHECK_GL_ERROR
|
||||
checkGLError("Paint2");
|
||||
#endif
|
||||
|
||||
m_backend->endRenderingFrame(damage);
|
||||
m_backend->endRenderingFrame(validRegion, updateRegion);
|
||||
|
||||
// do cleanup
|
||||
stacking_order.clear();
|
||||
|
@ -427,6 +462,9 @@ void SceneOpenGL::paintBackground(QRegion region)
|
|||
|
||||
void SceneOpenGL::extendPaintRegion(QRegion ®ion, bool opaqueFullscreen)
|
||||
{
|
||||
if (m_backend->supportsBufferAge())
|
||||
return;
|
||||
|
||||
if (options->glPreferBufferSwap() == Options::ExtendDamage) { // only Extend "large" repaints
|
||||
const QRegion displayRegion(0, 0, displayWidth(), displayHeight());
|
||||
uint damagedPixels = 0;
|
||||
|
|
|
@ -463,23 +463,29 @@ public:
|
|||
}
|
||||
virtual void screenGeometryChanged(const QSize &size) = 0;
|
||||
virtual SceneOpenGL::TexturePrivate *createBackendTexture(SceneOpenGL::Texture *texture) = 0;
|
||||
|
||||
/**
|
||||
* @brief Backend specific code to prepare the rendering of a frame including flushing the
|
||||
* previously rendered frame to the screen if the backend works this way.
|
||||
*
|
||||
* @return A region that if not empty will be repainted in addition to the damaged region
|
||||
**/
|
||||
virtual void prepareRenderingFrame() = 0;
|
||||
virtual QRegion prepareRenderingFrame() = 0;
|
||||
|
||||
/**
|
||||
* @brief Backend specific code to handle the end of rendering a frame.
|
||||
*
|
||||
* @param damage The actual updated region in this frame
|
||||
* @param renderedRegion The possibly larger region that has been rendered
|
||||
* @param damagedRegion The damaged region that should be posted
|
||||
**/
|
||||
virtual void endRenderingFrame(const QRegion &damage) = 0;
|
||||
virtual void endRenderingFrame(const QRegion &damage, const QRegion &damagedRegion) = 0;
|
||||
virtual bool makeCurrent() = 0;
|
||||
virtual void doneCurrent() = 0;
|
||||
/**
|
||||
* @brief Compositor is going into idle mode, flushes any pending paints.
|
||||
**/
|
||||
void idle();
|
||||
|
||||
/**
|
||||
* @return bool Whether the scene needs to flush a frame.
|
||||
**/
|
||||
|
@ -540,6 +546,21 @@ public:
|
|||
bool isDirectRendering() const {
|
||||
return m_directRendering;
|
||||
}
|
||||
|
||||
bool supportsBufferAge() const {
|
||||
return m_haveBufferAge;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the damage that has accumulated since a buffer of the given age was presented.
|
||||
*/
|
||||
QRegion accumulatedDamageHistory(int bufferAge) const;
|
||||
|
||||
/**
|
||||
* Saves the given region to damage history.
|
||||
*/
|
||||
void addToDamageHistory(const QRegion ®ion);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Backend specific flushing of frame to screen.
|
||||
|
@ -586,6 +607,11 @@ protected:
|
|||
void setIsDirectRendering(bool direct) {
|
||||
m_directRendering = direct;
|
||||
}
|
||||
|
||||
void setSupportsBufferAge(bool value) {
|
||||
m_haveBufferAge = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return const QRegion& Damage of previously rendered frame
|
||||
**/
|
||||
|
@ -623,6 +649,10 @@ private:
|
|||
* @brief Whether direct rendering is used, defaults to @c false.
|
||||
**/
|
||||
bool m_directRendering;
|
||||
/**
|
||||
* @brief Whether the backend supports GLX_EXT_buffer_age / EGL_EXT_buffer_age.
|
||||
*/
|
||||
bool m_haveBufferAge;
|
||||
/**
|
||||
* @brief Whether the initialization failed, of course default to @c false.
|
||||
**/
|
||||
|
@ -631,6 +661,10 @@ private:
|
|||
* @brief Damaged region of previously rendered frame.
|
||||
**/
|
||||
QRegion m_lastDamage;
|
||||
/**
|
||||
* @brief The damage history for the past 10 frames.
|
||||
*/
|
||||
QList<QRegion> m_damageHistory;
|
||||
/**
|
||||
* @brief Timer to measure how long a frame renders.
|
||||
**/
|
||||
|
|
|
@ -191,12 +191,13 @@ qint64 SceneXrender::paint(QRegion damage, ToplevelList toplevels)
|
|||
}
|
||||
|
||||
int mask = 0;
|
||||
paintScreen(&mask, &damage);
|
||||
QRegion updateRegion, validRegion;
|
||||
paintScreen(&mask, damage, QRegion(), &updateRegion, &validRegion);
|
||||
|
||||
if (m_overlayWindow->window()) // show the window only after the first pass, since
|
||||
m_overlayWindow->show(); // that pass may take long
|
||||
|
||||
present(mask, damage);
|
||||
present(mask, updateRegion);
|
||||
// do cleanup
|
||||
stacking_order.clear();
|
||||
|
||||
|
|
Loading…
Reference in a new issue