support a permanent glSwapBuffer
either by - forcing fullrepaints unconditionally - turning a repaint to a full one beyond a threshhold - completing the the backbuffer from the frontbuffer after the paint BUG: 307965 FIXED-IN: 4.10 REVIEW: 107198
This commit is contained in:
parent
499e34736b
commit
9aef5b85a0
9 changed files with 224 additions and 84 deletions
|
@ -501,8 +501,6 @@ void Compositor::timerEvent(QTimerEvent *te)
|
|||
QObject::timerEvent(te);
|
||||
}
|
||||
|
||||
static int s_pendingFlushes = 0;
|
||||
|
||||
void Compositor::performCompositing()
|
||||
{
|
||||
if (!isOverlayWindowVisible())
|
||||
|
@ -543,15 +541,7 @@ void Compositor::performCompositing()
|
|||
win->getDamageRegionReply();
|
||||
}
|
||||
|
||||
bool pending = !repaints_region.isEmpty() || windowRepaintsPending();
|
||||
if (pending)
|
||||
s_pendingFlushes = 3;
|
||||
else if (m_scene->hasPendingFlush())
|
||||
--s_pendingFlushes;
|
||||
else
|
||||
s_pendingFlushes = 0;
|
||||
if (s_pendingFlushes < 1) {
|
||||
s_pendingFlushes = 0;
|
||||
if (repaints_region.isEmpty() && !windowRepaintsPending()) {
|
||||
m_scene->idle();
|
||||
// Note: It would seem here we should undo suspended unredirect, but when scenes need
|
||||
// it for some reason, e.g. transformations or translucency, the next pass that does not
|
||||
|
|
|
@ -194,12 +194,13 @@ bool EglOnXBackend::initBufferConfigs()
|
|||
|
||||
void EglOnXBackend::present()
|
||||
{
|
||||
if (lastMask() & Scene::PAINT_SCREEN_REGION && surfaceHasSubPost && eglPostSubBufferNV) {
|
||||
const QRect damageRect = lastDamage().boundingRect();
|
||||
|
||||
eglPostSubBufferNV(dpy, surface, damageRect.left(), displayHeight() - damageRect.bottom() - 1, damageRect.width(), damageRect.height());
|
||||
} else {
|
||||
const bool swap = (options->glPreferBufferSwap() && options->glPreferBufferSwap() != Options::ExtendDamage) ||
|
||||
!(lastMask() & Scene::PAINT_SCREEN_REGION && surfaceHasSubPost && eglPostSubBufferNV);
|
||||
if (swap) {
|
||||
eglSwapBuffers(dpy, surface);
|
||||
} else {
|
||||
const QRect damageRect = lastDamage().boundingRect();
|
||||
eglPostSubBufferNV(dpy, surface, damageRect.left(), displayHeight() - damageRect.bottom() - 1, damageRect.width(), damageRect.height());
|
||||
}
|
||||
|
||||
eglWaitGL();
|
||||
|
|
117
glxbackend.cpp
117
glxbackend.cpp
|
@ -115,7 +115,7 @@ void GlxBackend::init()
|
|||
// However mesa/dri will return a range error (6) because deactivating the
|
||||
// swapinterval (as of today) seems completely unsupported
|
||||
setHasWaitSync(true);
|
||||
setSwapInterval(0);
|
||||
setSwapInterval(1);
|
||||
}
|
||||
else
|
||||
qWarning() << "NO VSYNC! glXWaitVideoSync(1,0,&uint) isn't 0 but" << glXWaitVideoSync(1, 0, &sync);
|
||||
|
@ -473,77 +473,80 @@ void GlxBackend::waitSync()
|
|||
|
||||
void GlxBackend::present()
|
||||
{
|
||||
QRegion displayRegion(0, 0, displayWidth(), displayHeight());
|
||||
const bool fullRepaint = (lastDamage() == displayRegion);
|
||||
|
||||
if (isDoubleBuffer()) {
|
||||
if (lastMask() & Scene::PAINT_SCREEN_REGION) {
|
||||
waitSync();
|
||||
if (glXCopySubBuffer) {
|
||||
foreach (const QRect & r, lastDamage().rects()) {
|
||||
// convert to OpenGL coordinates
|
||||
int y = displayHeight() - r.y() - r.height();
|
||||
glXCopySubBuffer(display(), glxbuffer, r.x(), y, r.width(), r.height());
|
||||
}
|
||||
} else {
|
||||
// if a shader is bound or the texture unit is enabled, copy pixels results in a black screen
|
||||
// therefore unbind the shader and restore after copying the pixels
|
||||
GLint shader = 0;
|
||||
if (ShaderManager::instance()->isShaderBound()) {
|
||||
glGetIntegerv(GL_CURRENT_PROGRAM, &shader);
|
||||
glUseProgram(0);
|
||||
}
|
||||
bool reenableTexUnit = false;
|
||||
if (glIsEnabled(GL_TEXTURE_2D)) {
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
reenableTexUnit = true;
|
||||
}
|
||||
// no idea why glScissor() is used, but Compiz has it and it doesn't seem to hurt
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glDrawBuffer(GL_FRONT);
|
||||
int xpos = 0;
|
||||
int ypos = 0;
|
||||
foreach (const QRect & r, lastDamage().rects()) {
|
||||
// convert to OpenGL coordinates
|
||||
int y = displayHeight() - r.y() - r.height();
|
||||
// Move raster position relatively using glBitmap() rather
|
||||
// than using glRasterPos2f() - the latter causes drawing
|
||||
// artefacts at the bottom screen edge with some gfx cards
|
||||
// glRasterPos2f( r.x(), r.y() + r.height());
|
||||
glBitmap(0, 0, 0, 0, r.x() - xpos, y - ypos, NULL);
|
||||
xpos = r.x();
|
||||
ypos = y;
|
||||
glScissor(r.x(), y, r.width(), r.height());
|
||||
glCopyPixels(r.x(), y, r.width(), r.height(), GL_COLOR);
|
||||
}
|
||||
glBitmap(0, 0, 0, 0, -xpos, -ypos, NULL); // move position back to 0,0
|
||||
glDrawBuffer(GL_BACK);
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
if (reenableTexUnit) {
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
}
|
||||
// rebind previously bound shader
|
||||
if (ShaderManager::instance()->isShaderBound()) {
|
||||
glUseProgram(shader);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
if (fullRepaint) {
|
||||
if (haveSwapInterval) {
|
||||
setSwapInterval(options->isGlVSync() ? 1 : 0);
|
||||
glXSwapBuffers(display(), glxbuffer);
|
||||
setSwapInterval(0);
|
||||
startRenderTimer(); // this is important so we don't assume to be loosing frames in the compositor timing calculation
|
||||
startRenderTimer();
|
||||
} else {
|
||||
waitSync();
|
||||
waitSync(); // calls startRenderTimer();
|
||||
glXSwapBuffers(display(), glxbuffer);
|
||||
}
|
||||
} else if (glXCopySubBuffer) {
|
||||
waitSync();
|
||||
foreach (const QRect & r, lastDamage().rects()) {
|
||||
// convert to OpenGL coordinates
|
||||
int y = displayHeight() - r.y() - r.height();
|
||||
glXCopySubBuffer(display(), glxbuffer, r.x(), y, r.width(), r.height());
|
||||
}
|
||||
} else { // Copy Pixels
|
||||
// if a shader is bound or the texture unit is enabled, copy pixels results in a black screen
|
||||
// therefore unbind the shader and restore after copying the pixels
|
||||
GLint shader = 0;
|
||||
if (ShaderManager::instance()->isShaderBound()) {
|
||||
glGetIntegerv(GL_CURRENT_PROGRAM, &shader);
|
||||
glUseProgram(0);
|
||||
}
|
||||
bool reenableTexUnit = false;
|
||||
if (glIsEnabled(GL_TEXTURE_2D)) {
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
reenableTexUnit = true;
|
||||
}
|
||||
// no idea why glScissor() is used, but Compiz has it and it doesn't seem to hurt
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glDrawBuffer(GL_FRONT);
|
||||
waitSync();
|
||||
int xpos = 0;
|
||||
int ypos = 0;
|
||||
foreach (const QRect & r, lastDamage().rects()) {
|
||||
// convert to OpenGL coordinates
|
||||
int y = displayHeight() - r.y() - r.height();
|
||||
// Move raster position relatively using glBitmap() rather
|
||||
// than using glRasterPos2f() - the latter causes drawing
|
||||
// artefacts at the bottom screen edge with some gfx cards
|
||||
// glRasterPos2f( r.x(), r.y() + r.height());
|
||||
glBitmap(0, 0, 0, 0, r.x() - xpos, y - ypos, NULL);
|
||||
xpos = r.x();
|
||||
ypos = y;
|
||||
glScissor(r.x(), y, r.width(), r.height());
|
||||
glCopyPixels(r.x(), y, r.width(), r.height(), GL_COLOR);
|
||||
}
|
||||
glBitmap(0, 0, 0, 0, -xpos, -ypos, NULL); // move position back to 0,0
|
||||
glDrawBuffer(GL_BACK);
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
if (reenableTexUnit) {
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
}
|
||||
// rebind previously bound shader
|
||||
if (ShaderManager::instance()->isShaderBound()) {
|
||||
glUseProgram(shader);
|
||||
}
|
||||
}
|
||||
|
||||
glXWaitGL();
|
||||
} else {
|
||||
glXWaitGL();
|
||||
if (lastMask() & Scene::PAINT_SCREEN_REGION)
|
||||
if (!fullRepaint)
|
||||
foreach (const QRect & r, lastDamage().rects())
|
||||
XCopyArea(display(), buffer, rootWindow(), gcroot, r.x(), r.y(), r.width(), r.height(), r.x(), r.y());
|
||||
else
|
||||
XCopyArea(display(), buffer, rootWindow(), gcroot, 0, 0, displayWidth(), displayHeight(), 0, 0);
|
||||
}
|
||||
setLastDamage(QRegion());
|
||||
XFlush(display());
|
||||
}
|
||||
|
||||
|
|
29
options.cpp
29
options.cpp
|
@ -161,6 +161,7 @@ Options::Options(QObject *parent)
|
|||
, m_glStrictBinding(Options::defaultGlStrictBinding())
|
||||
, m_glStrictBindingFollowsDriver(Options::defaultGlStrictBindingFollowsDriver())
|
||||
, m_glLegacy(Options::defaultGlLegacy())
|
||||
, m_glPreferBufferSwap(Options::defaultGlPreferBufferSwap())
|
||||
, OpTitlebarDblClick(Options::defaultOperationTitlebarDblClick())
|
||||
, CmdActiveTitlebar1(Options::defaultCommandActiveTitlebar1())
|
||||
, CmdActiveTitlebar2(Options::defaultCommandActiveTitlebar2())
|
||||
|
@ -768,6 +769,24 @@ void Options::setGlLegacy(bool glLegacy)
|
|||
emit glLegacyChanged();
|
||||
}
|
||||
|
||||
void Options::setGlPreferBufferSwap(char glPreferBufferSwap)
|
||||
{
|
||||
if (glPreferBufferSwap == 'a') {
|
||||
// buffer cpying is very fast with the nvidia blob
|
||||
// but due to restrictions in DRI2 *incredibly* slow for all MESA drivers
|
||||
// see http://www.x.org/releases/X11R7.7/doc/dri2proto/dri2proto.txt, item 2.5
|
||||
if (GLPlatform::instance()->driver() == Driver_NVidia)
|
||||
glPreferBufferSwap = CopyFrontBuffer;
|
||||
else
|
||||
glPreferBufferSwap = ExtendDamage;
|
||||
}
|
||||
if (m_glPreferBufferSwap == (GlSwapStrategy)glPreferBufferSwap) {
|
||||
return;
|
||||
}
|
||||
m_glPreferBufferSwap = (GlSwapStrategy)glPreferBufferSwap;
|
||||
emit glPreferBufferSwapChanged();
|
||||
}
|
||||
|
||||
void Options::reparseConfiguration()
|
||||
{
|
||||
KGlobal::config()->reparseConfiguration();
|
||||
|
@ -957,6 +976,16 @@ void Options::reloadCompositingSettings(bool force)
|
|||
}
|
||||
setGlLegacy(config.readEntry("GLLegacy", Options::defaultGlLegacy()));
|
||||
|
||||
char c = 0;
|
||||
if (isGlVSync()) { // buffer swap enforcement makes little sense without
|
||||
const QString s = config.readEntry("GLPreferBufferSwap", QString(Options::defaultGlPreferBufferSwap()));
|
||||
if (!s.isEmpty())
|
||||
c = s.at(0).toAscii();
|
||||
if (c != 'a' && c != 'c' && c != 'p' && c != 'e')
|
||||
c = 0;
|
||||
}
|
||||
setGlPreferBufferSwap(c);
|
||||
|
||||
setColorCorrected(config.readEntry("GLColorCorrection", Options::defaultColorCorrected()));
|
||||
|
||||
m_xrenderSmoothScale = config.readEntry("XRenderSmoothScale", false);
|
||||
|
|
13
options.h
13
options.h
|
@ -42,6 +42,7 @@ class Options : public QObject, public KDecorationOptions
|
|||
{
|
||||
Q_OBJECT
|
||||
Q_ENUMS(FocusPolicy)
|
||||
Q_ENUMS(GlSwapStrategy)
|
||||
Q_ENUMS(MouseCommand)
|
||||
Q_ENUMS(MouseWheelCommand)
|
||||
|
||||
|
@ -187,6 +188,7 @@ class Options : public QObject, public KDecorationOptions
|
|||
* Whether legacy OpenGL should be used or OpenGL (ES) 2
|
||||
**/
|
||||
Q_PROPERTY(bool glLegacy READ isGlLegacy WRITE setGlLegacy NOTIFY glLegacyChanged)
|
||||
Q_PROPERTY(char glPreferBufferSwap READ glPreferBufferSwap WRITE setGlPreferBufferSwap NOTIFY glPreferBufferSwapChanged)
|
||||
public:
|
||||
|
||||
explicit Options(QObject *parent = NULL);
|
||||
|
@ -549,6 +551,11 @@ public:
|
|||
return m_glLegacy;
|
||||
}
|
||||
|
||||
enum GlSwapStrategy { NoSwapEncourage = 0, CopyFrontBuffer = 'c', PaintFullScreen = 'p', ExtendDamage = 'e', AutoSwapStrategy = 'a' };
|
||||
GlSwapStrategy glPreferBufferSwap() const {
|
||||
return m_glPreferBufferSwap;
|
||||
}
|
||||
|
||||
// setters
|
||||
void setFocusPolicy(FocusPolicy focusPolicy);
|
||||
void setNextFocusPrefersMouse(bool nextFocusPrefersMouse);
|
||||
|
@ -610,6 +617,7 @@ public:
|
|||
void setGlStrictBinding(bool glStrictBinding);
|
||||
void setGlStrictBindingFollowsDriver(bool glStrictBindingFollowsDriver);
|
||||
void setGlLegacy(bool glLegacy);
|
||||
void setGlPreferBufferSwap(char glPreferBufferSwap);
|
||||
|
||||
// default values
|
||||
static WindowOperation defaultOperationTitlebarDblClick() {
|
||||
|
@ -717,6 +725,9 @@ public:
|
|||
static bool defaultGlLegacy() {
|
||||
return false;
|
||||
}
|
||||
static GlSwapStrategy defaultGlPreferBufferSwap() {
|
||||
return AutoSwapStrategy;
|
||||
}
|
||||
static int defaultAnimationSpeed() {
|
||||
return 3;
|
||||
}
|
||||
|
@ -797,6 +808,7 @@ Q_SIGNALS:
|
|||
void glStrictBindingChanged();
|
||||
void glStrictBindingFollowsDriverChanged();
|
||||
void glLegacyChanged();
|
||||
void glPreferBufferSwapChanged();
|
||||
|
||||
public Q_SLOTS:
|
||||
void setColorCorrected(bool colorCorrected = false);
|
||||
|
@ -847,6 +859,7 @@ private:
|
|||
bool m_glStrictBinding;
|
||||
bool m_glStrictBindingFollowsDriver;
|
||||
bool m_glLegacy;
|
||||
GlSwapStrategy m_glPreferBufferSwap;
|
||||
|
||||
WindowOperation OpTitlebarDblClick;
|
||||
|
||||
|
|
45
scene.cpp
45
scene.cpp
|
@ -103,8 +103,9 @@ Scene::~Scene()
|
|||
// returns mask and possibly modified region
|
||||
void Scene::paintScreen(int* mask, QRegion* region)
|
||||
{
|
||||
*mask = (*region == QRegion(0, 0, displayWidth(), displayHeight()))
|
||||
? 0 : PAINT_SCREEN_REGION;
|
||||
const QRegion displayRegion(0, 0, displayWidth(), displayHeight());
|
||||
*mask = (*region == displayRegion) ? 0 : PAINT_SCREEN_REGION;
|
||||
|
||||
updateTimeDiff();
|
||||
// preparation step
|
||||
static_cast<EffectsHandlerImpl*>(effects)->startPaint();
|
||||
|
@ -124,10 +125,10 @@ void Scene::paintScreen(int* mask, QRegion* region)
|
|||
*region = infiniteRegion();
|
||||
} else if (*mask & PAINT_SCREEN_REGION) {
|
||||
// make sure not to go outside visible screen
|
||||
*region &= QRegion(0, 0, displayWidth(), displayHeight());
|
||||
*region &= displayRegion;
|
||||
} else {
|
||||
// whole screen, not transformed, force region to be full
|
||||
*region = QRegion(0, 0, displayWidth(), displayHeight());
|
||||
*region = displayRegion;
|
||||
}
|
||||
painted_region = *region;
|
||||
if (*mask & PAINT_SCREEN_BACKGROUND_FIRST) {
|
||||
|
@ -141,7 +142,7 @@ void Scene::paintScreen(int* mask, QRegion* region)
|
|||
effects->postPaintScreen();
|
||||
*region |= painted_region;
|
||||
// make sure not to go outside of the screen area
|
||||
*region &= QRegion(0, 0, displayWidth(), displayHeight());
|
||||
*region &= displayRegion;
|
||||
// make sure all clipping is restored
|
||||
Q_ASSERT(!PaintClipper::clip());
|
||||
}
|
||||
|
@ -236,6 +237,7 @@ void Scene::paintSimpleScreen(int orig_mask, QRegion region)
|
|||
QList< QPair< Window*, Phase2Data > > phase2data;
|
||||
|
||||
QRegion dirtyArea = region;
|
||||
bool opaqueFullscreen(false);
|
||||
for (int i = 0; // do prePaintWindow bottom to top
|
||||
i < stacking_order.count();
|
||||
++i) {
|
||||
|
@ -254,10 +256,12 @@ void Scene::paintSimpleScreen(int orig_mask, QRegion region)
|
|||
topw->resetRepaints();
|
||||
|
||||
// Clip out the decoration for opaque windows; the decoration is drawn in the second pass
|
||||
opaqueFullscreen = false; // TODO: do we care about unmanged windows here (maybe input windows?)
|
||||
if (w->isOpaque()) {
|
||||
Client *c = NULL;
|
||||
if (topw->isClient()) {
|
||||
c = static_cast<Client*>(topw);
|
||||
opaqueFullscreen = c->isFullScreen();
|
||||
}
|
||||
// the window is fully opaque
|
||||
if (c && c->decorationHasAlpha()) {
|
||||
|
@ -297,13 +301,24 @@ void Scene::paintSimpleScreen(int orig_mask, QRegion region)
|
|||
w->suspendUnredirect(data.mask & PAINT_WINDOW_TRANSLUCENT);
|
||||
}
|
||||
|
||||
// This is the occlusion culling pass
|
||||
const QRegion displayRegion(0, 0, displayWidth(), displayHeight());
|
||||
|
||||
bool fullRepaint(dirtyArea == displayRegion); // spare some expensive region operations
|
||||
if (!fullRepaint) {
|
||||
extendPaintRegion(dirtyArea, opaqueFullscreen);
|
||||
fullRepaint = (dirtyArea == displayRegion);
|
||||
}
|
||||
|
||||
QRegion allclips, upperTranslucentDamage;
|
||||
// This is the occlusion culling pass
|
||||
for (int i = phase2data.count() - 1; i >= 0; --i) {
|
||||
QPair< Window*, Phase2Data > *entry = &phase2data[i];
|
||||
Phase2Data *data = &entry->second;
|
||||
|
||||
data->region |= upperTranslucentDamage;
|
||||
if (fullRepaint)
|
||||
data->region = displayRegion;
|
||||
else
|
||||
data->region |= upperTranslucentDamage;
|
||||
|
||||
// subtract the parts which will possibly been drawn as part of
|
||||
// a higher opaque window
|
||||
|
@ -315,8 +330,9 @@ void Scene::paintSimpleScreen(int orig_mask, QRegion region)
|
|||
// clip away the opaque regions for all windows below this one
|
||||
allclips |= data->clip;
|
||||
// extend the translucent damage for windows below this by remaining (translucent) regions
|
||||
upperTranslucentDamage |= data->region - data->clip;
|
||||
} else {
|
||||
if (!fullRepaint)
|
||||
upperTranslucentDamage |= data->region - data->clip;
|
||||
} else if (!fullRepaint) {
|
||||
upperTranslucentDamage |= data->region;
|
||||
}
|
||||
}
|
||||
|
@ -338,7 +354,10 @@ void Scene::paintSimpleScreen(int orig_mask, QRegion region)
|
|||
|
||||
paintWindow(data->window, data->mask, data->region, data->quads);
|
||||
}
|
||||
painted_region |= paintedArea;
|
||||
if (fullRepaint)
|
||||
painted_region = displayRegion;
|
||||
else
|
||||
painted_region |= paintedArea;
|
||||
}
|
||||
|
||||
void Scene::paintWindow(Window* w, int mask, QRegion region, WindowQuadList quads)
|
||||
|
@ -452,6 +471,12 @@ void Scene::finalDrawWindow(EffectWindowImpl* w, int mask, QRegion region, Windo
|
|||
w->sceneWindow()->performPaint(mask, region, data);
|
||||
}
|
||||
|
||||
void Scene::extendPaintRegion(QRegion ®ion, bool opaqueFullscreen)
|
||||
{
|
||||
Q_UNUSED(region);
|
||||
Q_UNUSED(opaqueFullscreen);
|
||||
}
|
||||
|
||||
bool Scene::waitSyncAvailable() const
|
||||
{
|
||||
return false;
|
||||
|
|
3
scene.h
3
scene.h
|
@ -125,6 +125,9 @@ protected:
|
|||
virtual void paintWindow(Window* w, int mask, QRegion region, WindowQuadList quads);
|
||||
// called after all effects had their drawWindow() called
|
||||
virtual void finalDrawWindow(EffectWindowImpl* w, int mask, QRegion region, WindowPaintData& data);
|
||||
// let the scene decide whether it's better to paint more of the screen, eg. in order to allow a buffer swap
|
||||
// the default is NOOP
|
||||
virtual void extendPaintRegion(QRegion ®ion, bool opaqueFullscreen);
|
||||
// compute time since the last repaint
|
||||
void updateTimeDiff();
|
||||
// saved data for 2nd pass of optimized screen painting
|
||||
|
|
|
@ -98,7 +98,8 @@ void OpenGLBackend::setFailed(const QString &reason)
|
|||
|
||||
void OpenGLBackend::idle()
|
||||
{
|
||||
present();
|
||||
if (hasPendingFlush())
|
||||
present();
|
||||
}
|
||||
|
||||
/************************************************
|
||||
|
@ -269,7 +270,52 @@ int SceneOpenGL::paint(QRegion damage, ToplevelList toplevels)
|
|||
#ifdef CHECK_GL_ERROR
|
||||
checkGLError("Paint1");
|
||||
#endif
|
||||
|
||||
const QRegion displayRegion(0, 0, displayWidth(), displayHeight());
|
||||
paintScreen(&mask, &damage); // call generic implementation
|
||||
#ifndef KWIN_HAVE_OPENGLES
|
||||
// copy dirty parts from front to backbuffer
|
||||
if (options->glPreferBufferSwap() == Options::CopyFrontBuffer && damage != displayRegion) {
|
||||
GLint shader = 0;
|
||||
if (ShaderManager::instance()->isShaderBound()) {
|
||||
glGetIntegerv(GL_CURRENT_PROGRAM, &shader);
|
||||
glUseProgram(0);
|
||||
}
|
||||
bool reenableTexUnit = false;
|
||||
if (glIsEnabled(GL_TEXTURE_2D)) {
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
reenableTexUnit = true;
|
||||
}
|
||||
// no idea why glScissor() is used, but Compiz has it and it doesn't seem to hurt
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glReadBuffer(GL_FRONT);
|
||||
|
||||
int xpos = 0;
|
||||
int ypos = 0;
|
||||
const QRegion dirty = displayRegion - damage;
|
||||
foreach (const QRect &r, dirty.rects()) {
|
||||
// convert to OpenGL coordinates
|
||||
int y = displayHeight() - r.y() - r.height();
|
||||
glBitmap(0, 0, 0, 0, r.x() - xpos, y - ypos, NULL); // not glRasterPos2f, see glxbackend.cpp
|
||||
xpos = r.x();
|
||||
ypos = y;
|
||||
glScissor(r.x(), y, r.width(), r.height());
|
||||
glCopyPixels(r.x(), y, r.width(), r.height(), GL_COLOR);
|
||||
}
|
||||
|
||||
glBitmap(0, 0, 0, 0, -xpos, -ypos, NULL); // move position back to 0,0
|
||||
glReadBuffer(GL_BACK);
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
if (reenableTexUnit) {
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
}
|
||||
// rebind previously bound shader
|
||||
if (ShaderManager::instance()->isShaderBound()) {
|
||||
glUseProgram(shader);
|
||||
}
|
||||
damage = displayRegion;
|
||||
}
|
||||
#endif
|
||||
#ifdef CHECK_GL_ERROR
|
||||
checkGLError("Paint2");
|
||||
#endif
|
||||
|
@ -328,6 +374,35 @@ void SceneOpenGL::paintBackground(QRegion region)
|
|||
doPaintBackground(verts);
|
||||
}
|
||||
|
||||
void SceneOpenGL::extendPaintRegion(QRegion ®ion, bool opaqueFullscreen)
|
||||
{
|
||||
#ifndef KWIN_HAVE_OPENGLES
|
||||
if (options->glPreferBufferSwap() == Options::ExtendDamage) { // only Extend "large" repaints
|
||||
const QRegion displayRegion(0, 0, displayWidth(), displayHeight());
|
||||
uint damagedPixels = 0;
|
||||
const uint fullRepaintLimit = (opaqueFullscreen?0.49f:0.748f)*displayWidth()*displayHeight();
|
||||
// 16:9 is 75% of 4:3 and 2.55:1 is 49.01% of 5:4
|
||||
// (5:4 is the most square format and 2.55:1 is Cinemascope55 - the widest ever shot
|
||||
// movie aspect - two times ;-) It's a Fox format, though, so maybe we want to restrict
|
||||
// to 2.20:1 - Panavision - which has actually been used for interesting movies ...)
|
||||
// would be 57% of 5/4
|
||||
foreach (const QRect &r, region.rects()) {
|
||||
// damagedPixels += r.width() * r.height(); // combined window damage test
|
||||
damagedPixels = r.width() * r.height(); // experimental single window damage testing
|
||||
if (damagedPixels > fullRepaintLimit) {
|
||||
region = displayRegion;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (options->glPreferBufferSwap() == Options::PaintFullScreen) { // forced full rePaint
|
||||
region = QRegion(0, 0, displayWidth(), displayHeight());
|
||||
}
|
||||
#else
|
||||
Q_UNUSED(region);
|
||||
Q_UNUSED(opaqueFullscreen);
|
||||
#endif
|
||||
}
|
||||
|
||||
void SceneOpenGL::windowAdded(Toplevel* c)
|
||||
{
|
||||
assert(!windows.contains(c));
|
||||
|
|
|
@ -68,6 +68,7 @@ public:
|
|||
protected:
|
||||
SceneOpenGL(Workspace* ws, OpenGLBackend *backend);
|
||||
virtual void paintBackground(QRegion region);
|
||||
virtual void extendPaintRegion(QRegion ®ion, bool opaqueFullscreen);
|
||||
QMatrix4x4 transformation(int mask, const ScreenPaintData &data) const;
|
||||
|
||||
virtual void doPaintBackground(const QVector<float> &vertices) = 0;
|
||||
|
|
Loading…
Reference in a new issue