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);
|
QObject::timerEvent(te);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int s_pendingFlushes = 0;
|
|
||||||
|
|
||||||
void Compositor::performCompositing()
|
void Compositor::performCompositing()
|
||||||
{
|
{
|
||||||
if (!isOverlayWindowVisible())
|
if (!isOverlayWindowVisible())
|
||||||
|
@ -543,15 +541,7 @@ void Compositor::performCompositing()
|
||||||
win->getDamageRegionReply();
|
win->getDamageRegionReply();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pending = !repaints_region.isEmpty() || windowRepaintsPending();
|
if (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;
|
|
||||||
m_scene->idle();
|
m_scene->idle();
|
||||||
// Note: It would seem here we should undo suspended unredirect, but when scenes need
|
// 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
|
// 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()
|
void EglOnXBackend::present()
|
||||||
{
|
{
|
||||||
if (lastMask() & Scene::PAINT_SCREEN_REGION && surfaceHasSubPost && eglPostSubBufferNV) {
|
const bool swap = (options->glPreferBufferSwap() && options->glPreferBufferSwap() != Options::ExtendDamage) ||
|
||||||
const QRect damageRect = lastDamage().boundingRect();
|
!(lastMask() & Scene::PAINT_SCREEN_REGION && surfaceHasSubPost && eglPostSubBufferNV);
|
||||||
|
if (swap) {
|
||||||
eglPostSubBufferNV(dpy, surface, damageRect.left(), displayHeight() - damageRect.bottom() - 1, damageRect.width(), damageRect.height());
|
|
||||||
} else {
|
|
||||||
eglSwapBuffers(dpy, surface);
|
eglSwapBuffers(dpy, surface);
|
||||||
|
} else {
|
||||||
|
const QRect damageRect = lastDamage().boundingRect();
|
||||||
|
eglPostSubBufferNV(dpy, surface, damageRect.left(), displayHeight() - damageRect.bottom() - 1, damageRect.width(), damageRect.height());
|
||||||
}
|
}
|
||||||
|
|
||||||
eglWaitGL();
|
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
|
// However mesa/dri will return a range error (6) because deactivating the
|
||||||
// swapinterval (as of today) seems completely unsupported
|
// swapinterval (as of today) seems completely unsupported
|
||||||
setHasWaitSync(true);
|
setHasWaitSync(true);
|
||||||
setSwapInterval(0);
|
setSwapInterval(1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
qWarning() << "NO VSYNC! glXWaitVideoSync(1,0,&uint) isn't 0 but" << glXWaitVideoSync(1, 0, &sync);
|
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()
|
void GlxBackend::present()
|
||||||
{
|
{
|
||||||
|
QRegion displayRegion(0, 0, displayWidth(), displayHeight());
|
||||||
|
const bool fullRepaint = (lastDamage() == displayRegion);
|
||||||
|
|
||||||
if (isDoubleBuffer()) {
|
if (isDoubleBuffer()) {
|
||||||
if (lastMask() & Scene::PAINT_SCREEN_REGION) {
|
|
||||||
waitSync();
|
if (fullRepaint) {
|
||||||
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 (haveSwapInterval) {
|
if (haveSwapInterval) {
|
||||||
setSwapInterval(options->isGlVSync() ? 1 : 0);
|
|
||||||
glXSwapBuffers(display(), glxbuffer);
|
glXSwapBuffers(display(), glxbuffer);
|
||||||
setSwapInterval(0);
|
startRenderTimer();
|
||||||
startRenderTimer(); // this is important so we don't assume to be loosing frames in the compositor timing calculation
|
|
||||||
} else {
|
} else {
|
||||||
waitSync();
|
waitSync(); // calls startRenderTimer();
|
||||||
glXSwapBuffers(display(), glxbuffer);
|
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();
|
glXWaitGL();
|
||||||
} else {
|
} else {
|
||||||
glXWaitGL();
|
glXWaitGL();
|
||||||
if (lastMask() & Scene::PAINT_SCREEN_REGION)
|
if (!fullRepaint)
|
||||||
foreach (const QRect & r, lastDamage().rects())
|
foreach (const QRect & r, lastDamage().rects())
|
||||||
XCopyArea(display(), buffer, rootWindow(), gcroot, r.x(), r.y(), r.width(), r.height(), r.x(), r.y());
|
XCopyArea(display(), buffer, rootWindow(), gcroot, r.x(), r.y(), r.width(), r.height(), r.x(), r.y());
|
||||||
else
|
else
|
||||||
XCopyArea(display(), buffer, rootWindow(), gcroot, 0, 0, displayWidth(), displayHeight(), 0, 0);
|
XCopyArea(display(), buffer, rootWindow(), gcroot, 0, 0, displayWidth(), displayHeight(), 0, 0);
|
||||||
}
|
}
|
||||||
|
setLastDamage(QRegion());
|
||||||
XFlush(display());
|
XFlush(display());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
29
options.cpp
29
options.cpp
|
@ -161,6 +161,7 @@ Options::Options(QObject *parent)
|
||||||
, m_glStrictBinding(Options::defaultGlStrictBinding())
|
, m_glStrictBinding(Options::defaultGlStrictBinding())
|
||||||
, m_glStrictBindingFollowsDriver(Options::defaultGlStrictBindingFollowsDriver())
|
, m_glStrictBindingFollowsDriver(Options::defaultGlStrictBindingFollowsDriver())
|
||||||
, m_glLegacy(Options::defaultGlLegacy())
|
, m_glLegacy(Options::defaultGlLegacy())
|
||||||
|
, m_glPreferBufferSwap(Options::defaultGlPreferBufferSwap())
|
||||||
, OpTitlebarDblClick(Options::defaultOperationTitlebarDblClick())
|
, OpTitlebarDblClick(Options::defaultOperationTitlebarDblClick())
|
||||||
, CmdActiveTitlebar1(Options::defaultCommandActiveTitlebar1())
|
, CmdActiveTitlebar1(Options::defaultCommandActiveTitlebar1())
|
||||||
, CmdActiveTitlebar2(Options::defaultCommandActiveTitlebar2())
|
, CmdActiveTitlebar2(Options::defaultCommandActiveTitlebar2())
|
||||||
|
@ -768,6 +769,24 @@ void Options::setGlLegacy(bool glLegacy)
|
||||||
emit glLegacyChanged();
|
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()
|
void Options::reparseConfiguration()
|
||||||
{
|
{
|
||||||
KGlobal::config()->reparseConfiguration();
|
KGlobal::config()->reparseConfiguration();
|
||||||
|
@ -957,6 +976,16 @@ void Options::reloadCompositingSettings(bool force)
|
||||||
}
|
}
|
||||||
setGlLegacy(config.readEntry("GLLegacy", Options::defaultGlLegacy()));
|
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()));
|
setColorCorrected(config.readEntry("GLColorCorrection", Options::defaultColorCorrected()));
|
||||||
|
|
||||||
m_xrenderSmoothScale = config.readEntry("XRenderSmoothScale", false);
|
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_OBJECT
|
||||||
Q_ENUMS(FocusPolicy)
|
Q_ENUMS(FocusPolicy)
|
||||||
|
Q_ENUMS(GlSwapStrategy)
|
||||||
Q_ENUMS(MouseCommand)
|
Q_ENUMS(MouseCommand)
|
||||||
Q_ENUMS(MouseWheelCommand)
|
Q_ENUMS(MouseWheelCommand)
|
||||||
|
|
||||||
|
@ -187,6 +188,7 @@ class Options : public QObject, public KDecorationOptions
|
||||||
* Whether legacy OpenGL should be used or OpenGL (ES) 2
|
* Whether legacy OpenGL should be used or OpenGL (ES) 2
|
||||||
**/
|
**/
|
||||||
Q_PROPERTY(bool glLegacy READ isGlLegacy WRITE setGlLegacy NOTIFY glLegacyChanged)
|
Q_PROPERTY(bool glLegacy READ isGlLegacy WRITE setGlLegacy NOTIFY glLegacyChanged)
|
||||||
|
Q_PROPERTY(char glPreferBufferSwap READ glPreferBufferSwap WRITE setGlPreferBufferSwap NOTIFY glPreferBufferSwapChanged)
|
||||||
public:
|
public:
|
||||||
|
|
||||||
explicit Options(QObject *parent = NULL);
|
explicit Options(QObject *parent = NULL);
|
||||||
|
@ -549,6 +551,11 @@ public:
|
||||||
return m_glLegacy;
|
return m_glLegacy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum GlSwapStrategy { NoSwapEncourage = 0, CopyFrontBuffer = 'c', PaintFullScreen = 'p', ExtendDamage = 'e', AutoSwapStrategy = 'a' };
|
||||||
|
GlSwapStrategy glPreferBufferSwap() const {
|
||||||
|
return m_glPreferBufferSwap;
|
||||||
|
}
|
||||||
|
|
||||||
// setters
|
// setters
|
||||||
void setFocusPolicy(FocusPolicy focusPolicy);
|
void setFocusPolicy(FocusPolicy focusPolicy);
|
||||||
void setNextFocusPrefersMouse(bool nextFocusPrefersMouse);
|
void setNextFocusPrefersMouse(bool nextFocusPrefersMouse);
|
||||||
|
@ -610,6 +617,7 @@ public:
|
||||||
void setGlStrictBinding(bool glStrictBinding);
|
void setGlStrictBinding(bool glStrictBinding);
|
||||||
void setGlStrictBindingFollowsDriver(bool glStrictBindingFollowsDriver);
|
void setGlStrictBindingFollowsDriver(bool glStrictBindingFollowsDriver);
|
||||||
void setGlLegacy(bool glLegacy);
|
void setGlLegacy(bool glLegacy);
|
||||||
|
void setGlPreferBufferSwap(char glPreferBufferSwap);
|
||||||
|
|
||||||
// default values
|
// default values
|
||||||
static WindowOperation defaultOperationTitlebarDblClick() {
|
static WindowOperation defaultOperationTitlebarDblClick() {
|
||||||
|
@ -717,6 +725,9 @@ public:
|
||||||
static bool defaultGlLegacy() {
|
static bool defaultGlLegacy() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
static GlSwapStrategy defaultGlPreferBufferSwap() {
|
||||||
|
return AutoSwapStrategy;
|
||||||
|
}
|
||||||
static int defaultAnimationSpeed() {
|
static int defaultAnimationSpeed() {
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
@ -797,6 +808,7 @@ Q_SIGNALS:
|
||||||
void glStrictBindingChanged();
|
void glStrictBindingChanged();
|
||||||
void glStrictBindingFollowsDriverChanged();
|
void glStrictBindingFollowsDriverChanged();
|
||||||
void glLegacyChanged();
|
void glLegacyChanged();
|
||||||
|
void glPreferBufferSwapChanged();
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
void setColorCorrected(bool colorCorrected = false);
|
void setColorCorrected(bool colorCorrected = false);
|
||||||
|
@ -847,6 +859,7 @@ private:
|
||||||
bool m_glStrictBinding;
|
bool m_glStrictBinding;
|
||||||
bool m_glStrictBindingFollowsDriver;
|
bool m_glStrictBindingFollowsDriver;
|
||||||
bool m_glLegacy;
|
bool m_glLegacy;
|
||||||
|
GlSwapStrategy m_glPreferBufferSwap;
|
||||||
|
|
||||||
WindowOperation OpTitlebarDblClick;
|
WindowOperation OpTitlebarDblClick;
|
||||||
|
|
||||||
|
|
45
scene.cpp
45
scene.cpp
|
@ -103,8 +103,9 @@ Scene::~Scene()
|
||||||
// returns mask and possibly modified region
|
// returns mask and possibly modified region
|
||||||
void Scene::paintScreen(int* mask, QRegion* region)
|
void Scene::paintScreen(int* mask, QRegion* region)
|
||||||
{
|
{
|
||||||
*mask = (*region == QRegion(0, 0, displayWidth(), displayHeight()))
|
const QRegion displayRegion(0, 0, displayWidth(), displayHeight());
|
||||||
? 0 : PAINT_SCREEN_REGION;
|
*mask = (*region == displayRegion) ? 0 : PAINT_SCREEN_REGION;
|
||||||
|
|
||||||
updateTimeDiff();
|
updateTimeDiff();
|
||||||
// preparation step
|
// preparation step
|
||||||
static_cast<EffectsHandlerImpl*>(effects)->startPaint();
|
static_cast<EffectsHandlerImpl*>(effects)->startPaint();
|
||||||
|
@ -124,10 +125,10 @@ void Scene::paintScreen(int* mask, QRegion* region)
|
||||||
*region = infiniteRegion();
|
*region = infiniteRegion();
|
||||||
} else if (*mask & PAINT_SCREEN_REGION) {
|
} else if (*mask & PAINT_SCREEN_REGION) {
|
||||||
// make sure not to go outside visible screen
|
// make sure not to go outside visible screen
|
||||||
*region &= QRegion(0, 0, displayWidth(), displayHeight());
|
*region &= displayRegion;
|
||||||
} else {
|
} else {
|
||||||
// whole screen, not transformed, force region to be full
|
// whole screen, not transformed, force region to be full
|
||||||
*region = QRegion(0, 0, displayWidth(), displayHeight());
|
*region = displayRegion;
|
||||||
}
|
}
|
||||||
painted_region = *region;
|
painted_region = *region;
|
||||||
if (*mask & PAINT_SCREEN_BACKGROUND_FIRST) {
|
if (*mask & PAINT_SCREEN_BACKGROUND_FIRST) {
|
||||||
|
@ -141,7 +142,7 @@ void Scene::paintScreen(int* mask, QRegion* region)
|
||||||
effects->postPaintScreen();
|
effects->postPaintScreen();
|
||||||
*region |= painted_region;
|
*region |= painted_region;
|
||||||
// make sure not to go outside of the screen area
|
// make sure not to go outside of the screen area
|
||||||
*region &= QRegion(0, 0, displayWidth(), displayHeight());
|
*region &= displayRegion;
|
||||||
// make sure all clipping is restored
|
// make sure all clipping is restored
|
||||||
Q_ASSERT(!PaintClipper::clip());
|
Q_ASSERT(!PaintClipper::clip());
|
||||||
}
|
}
|
||||||
|
@ -236,6 +237,7 @@ void Scene::paintSimpleScreen(int orig_mask, QRegion region)
|
||||||
QList< QPair< Window*, Phase2Data > > phase2data;
|
QList< QPair< Window*, Phase2Data > > phase2data;
|
||||||
|
|
||||||
QRegion dirtyArea = region;
|
QRegion dirtyArea = region;
|
||||||
|
bool opaqueFullscreen(false);
|
||||||
for (int i = 0; // do prePaintWindow bottom to top
|
for (int i = 0; // do prePaintWindow bottom to top
|
||||||
i < stacking_order.count();
|
i < stacking_order.count();
|
||||||
++i) {
|
++i) {
|
||||||
|
@ -254,10 +256,12 @@ void Scene::paintSimpleScreen(int orig_mask, QRegion region)
|
||||||
topw->resetRepaints();
|
topw->resetRepaints();
|
||||||
|
|
||||||
// Clip out the decoration for opaque windows; the decoration is drawn in the second pass
|
// 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()) {
|
if (w->isOpaque()) {
|
||||||
Client *c = NULL;
|
Client *c = NULL;
|
||||||
if (topw->isClient()) {
|
if (topw->isClient()) {
|
||||||
c = static_cast<Client*>(topw);
|
c = static_cast<Client*>(topw);
|
||||||
|
opaqueFullscreen = c->isFullScreen();
|
||||||
}
|
}
|
||||||
// the window is fully opaque
|
// the window is fully opaque
|
||||||
if (c && c->decorationHasAlpha()) {
|
if (c && c->decorationHasAlpha()) {
|
||||||
|
@ -297,13 +301,24 @@ void Scene::paintSimpleScreen(int orig_mask, QRegion region)
|
||||||
w->suspendUnredirect(data.mask & PAINT_WINDOW_TRANSLUCENT);
|
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;
|
QRegion allclips, upperTranslucentDamage;
|
||||||
|
// This is the occlusion culling pass
|
||||||
for (int i = phase2data.count() - 1; i >= 0; --i) {
|
for (int i = phase2data.count() - 1; i >= 0; --i) {
|
||||||
QPair< Window*, Phase2Data > *entry = &phase2data[i];
|
QPair< Window*, Phase2Data > *entry = &phase2data[i];
|
||||||
Phase2Data *data = &entry->second;
|
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
|
// subtract the parts which will possibly been drawn as part of
|
||||||
// a higher opaque window
|
// 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
|
// clip away the opaque regions for all windows below this one
|
||||||
allclips |= data->clip;
|
allclips |= data->clip;
|
||||||
// extend the translucent damage for windows below this by remaining (translucent) regions
|
// extend the translucent damage for windows below this by remaining (translucent) regions
|
||||||
upperTranslucentDamage |= data->region - data->clip;
|
if (!fullRepaint)
|
||||||
} else {
|
upperTranslucentDamage |= data->region - data->clip;
|
||||||
|
} else if (!fullRepaint) {
|
||||||
upperTranslucentDamage |= data->region;
|
upperTranslucentDamage |= data->region;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -338,7 +354,10 @@ void Scene::paintSimpleScreen(int orig_mask, QRegion region)
|
||||||
|
|
||||||
paintWindow(data->window, data->mask, data->region, data->quads);
|
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)
|
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);
|
w->sceneWindow()->performPaint(mask, region, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Scene::extendPaintRegion(QRegion ®ion, bool opaqueFullscreen)
|
||||||
|
{
|
||||||
|
Q_UNUSED(region);
|
||||||
|
Q_UNUSED(opaqueFullscreen);
|
||||||
|
}
|
||||||
|
|
||||||
bool Scene::waitSyncAvailable() const
|
bool Scene::waitSyncAvailable() const
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|
3
scene.h
3
scene.h
|
@ -125,6 +125,9 @@ protected:
|
||||||
virtual void paintWindow(Window* w, int mask, QRegion region, WindowQuadList quads);
|
virtual void paintWindow(Window* w, int mask, QRegion region, WindowQuadList quads);
|
||||||
// called after all effects had their drawWindow() called
|
// called after all effects had their drawWindow() called
|
||||||
virtual void finalDrawWindow(EffectWindowImpl* w, int mask, QRegion region, WindowPaintData& data);
|
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
|
// compute time since the last repaint
|
||||||
void updateTimeDiff();
|
void updateTimeDiff();
|
||||||
// saved data for 2nd pass of optimized screen painting
|
// saved data for 2nd pass of optimized screen painting
|
||||||
|
|
|
@ -98,7 +98,8 @@ void OpenGLBackend::setFailed(const QString &reason)
|
||||||
|
|
||||||
void OpenGLBackend::idle()
|
void OpenGLBackend::idle()
|
||||||
{
|
{
|
||||||
present();
|
if (hasPendingFlush())
|
||||||
|
present();
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************************************
|
/************************************************
|
||||||
|
@ -269,7 +270,52 @@ int SceneOpenGL::paint(QRegion damage, ToplevelList toplevels)
|
||||||
#ifdef CHECK_GL_ERROR
|
#ifdef CHECK_GL_ERROR
|
||||||
checkGLError("Paint1");
|
checkGLError("Paint1");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
const QRegion displayRegion(0, 0, displayWidth(), displayHeight());
|
||||||
paintScreen(&mask, &damage); // call generic implementation
|
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
|
#ifdef CHECK_GL_ERROR
|
||||||
checkGLError("Paint2");
|
checkGLError("Paint2");
|
||||||
#endif
|
#endif
|
||||||
|
@ -328,6 +374,35 @@ void SceneOpenGL::paintBackground(QRegion region)
|
||||||
doPaintBackground(verts);
|
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)
|
void SceneOpenGL::windowAdded(Toplevel* c)
|
||||||
{
|
{
|
||||||
assert(!windows.contains(c));
|
assert(!windows.contains(c));
|
||||||
|
|
|
@ -68,6 +68,7 @@ public:
|
||||||
protected:
|
protected:
|
||||||
SceneOpenGL(Workspace* ws, OpenGLBackend *backend);
|
SceneOpenGL(Workspace* ws, OpenGLBackend *backend);
|
||||||
virtual void paintBackground(QRegion region);
|
virtual void paintBackground(QRegion region);
|
||||||
|
virtual void extendPaintRegion(QRegion ®ion, bool opaqueFullscreen);
|
||||||
QMatrix4x4 transformation(int mask, const ScreenPaintData &data) const;
|
QMatrix4x4 transformation(int mask, const ScreenPaintData &data) const;
|
||||||
|
|
||||||
virtual void doPaintBackground(const QVector<float> &vertices) = 0;
|
virtual void doPaintBackground(const QVector<float> &vertices) = 0;
|
||||||
|
|
Loading…
Reference in a new issue