change geometry w/o compositor restart

This possibly fails on some (older?) ati chip/driver combos
-> Waiting for bugreports

REVIEW: 103246
This commit is contained in:
Thomas Lübking 2011-11-26 16:15:46 +01:00
parent 0dbfdf4979
commit d845b60c6c
17 changed files with 196 additions and 35 deletions

View file

@ -532,6 +532,13 @@ bool EffectsHandlerImpl::hasKeyboardGrab() const
return keyboard_grab_effect != NULL;
}
void EffectsHandlerImpl::desktopResized(const QSize &size)
{
scene->screenGeometryChanged(size);
emit screenGeometryChanged(size);
Workspace::self()->addRepaintFull();
}
void EffectsHandlerImpl::slotPropertyNotify(Toplevel* t, long int atom)
{
if (!registered_atoms.contains(atom))
@ -1243,6 +1250,21 @@ bool EffectsHandlerImpl::isEffectLoaded(const QString& name)
return false;
}
void EffectsHandlerImpl::reloadEffect(Effect *effect)
{
QString effectName;
for (QVector< EffectPair >::iterator it = loaded_effects.begin(); it != loaded_effects.end(); ++it) {
if ((*it).second == effect) {
effectName = (*it).first;
break;
}
}
if (!effectName.isNull()) {
unloadEffect(effectName);
loadEffect(effectName);
}
}
void EffectsHandlerImpl::effectsChanged()
{
loaded_effects.clear();

View file

@ -160,7 +160,9 @@ public:
bool borderActivated(ElectricBorder border);
void grabbedKeyboardEvent(QKeyEvent* e);
bool hasKeyboardGrab() const;
void desktopResized(const QSize &size);
virtual void reloadEffect(Effect *effect);
bool loadEffect(const QString& name, bool checkDefault = false);
void toggleEffect(const QString& name);
void unloadEffect(const QString& name);

View file

@ -63,6 +63,7 @@ BlurEffect::BlurEffect()
connect(effects, SIGNAL(windowAdded(EffectWindow*)), this, SLOT(slotWindowAdded(EffectWindow*)));
connect(effects, SIGNAL(windowDeleted(EffectWindow*)), this, SLOT(slotWindowDeleted(EffectWindow*)));
connect(effects, SIGNAL(propertyNotify(EffectWindow*,long)), this, SLOT(slotPropertyNotify(EffectWindow*,long)));
connect(effects, SIGNAL(screenGeometryChanged(QSize)), this, SLOT(slotScreenGeometryChanged()));
}
BlurEffect::~BlurEffect()
@ -76,6 +77,11 @@ BlurEffect::~BlurEffect()
delete target;
}
void BlurEffect::slotScreenGeometryChanged()
{
effects->reloadEffect(this);
}
void BlurEffect::reconfigure(ReconfigureFlags flags)
{
Q_UNUSED(flags)

View file

@ -52,6 +52,7 @@ public Q_SLOTS:
void slotWindowAdded(EffectWindow *w);
void slotWindowDeleted(EffectWindow *w);
void slotPropertyNotify(EffectWindow *w, long atom);
void slotScreenGeometryChanged();
private:
QRect expand(const QRect &rect) const;

View file

@ -76,8 +76,9 @@ void Workspace::desktopResized()
#ifdef KWIN_BUILD_SCREENEDGES
m_screenEdge.update(true);
#endif
if (compositing())
compositeResetTimer.start(0);
if (effects) {
static_cast<EffectsHandlerImpl*>(effects)->desktopResized(geom.size());
}
}
void Workspace::saveOldScreenSizes()

View file

@ -795,6 +795,16 @@ public:
virtual EffectFrame* effectFrame(EffectFrameStyle style, bool staticSize = true,
const QPoint& position = QPoint(-1, -1), Qt::Alignment alignment = Qt::AlignCenter) const = 0;
/**
* Allows an effect to trigger a reload of itself.
* This can be used by an effect which needs to be reloaded when screen geometry changes.
* It is possible that the effect cannot be loaded again as it's supported method does no longer
* hold.
* @param effect The effect to reload
* @since 4.8
**/
virtual void reloadEffect(Effect *effect) = 0;
/**
* Sends message over DCOP to reload given effect.
* @param effectname effect's name without "kwin4_effect_" prefix.
@ -1033,6 +1043,15 @@ Q_SIGNALS:
**/
void hideOutline();
/**
* Signal emitted after the screen geometry changed (e.g. add of a monitor).
* Effects using displayWidth()/displayHeight() to cache information should
* react on this signal and update the caches.
* @param size The new screen size
* @since 4.8
**/
void screenGeometryChanged(const QSize &size);
protected:
QVector< EffectPair > loaded_effects;
QHash< QString, KLibrary* > effect_libraries;

View file

@ -689,6 +689,20 @@ GLShader *ShaderManager::pushShader(ShaderType type, bool reset)
return shader;
}
void ShaderManager::resetAllShaders()
{
if (!m_inited || !m_valid) {
return;
}
pushShader(SimpleShader, true);
pushShader(GenericShader, true);
pushShader(ColorShader, true);
popShader();
popShader();
popShader();
}
void ShaderManager::pushShader(GLShader *shader)
{
// only bind shader if it is not already bound

View file

@ -321,6 +321,13 @@ public:
**/
void popShader();
/**
* Resets all shaders to the default uniform values.
* Only built in shaders are changed.
* @since 4.8
**/
void resetAllShaders();
/**
* Creates a GLShader with a built-in vertex shader and a custom fragment shader.
* @param vertex The generic vertex shader

View file

@ -120,6 +120,13 @@ void OverlayWindow::setShape(const QRegion& reg)
m_shape = reg;
}
void OverlayWindow::resize(const QSize &size)
{
assert(m_window != None);
XResizeWindow(display(), m_window, size.width(), size.height());
setShape(QRegion(0, 0, size.width(), size.height()));
}
bool OverlayWindow::isVisible() const
{
return m_visible;

View file

@ -37,6 +37,7 @@ public:
void show();
void hide(); // hides and resets overlay window
void setShape(const QRegion& reg);
void resize(const QSize &size);
/// Destroys XComposite overlay window
void destroy();
Window window() const;

View file

@ -426,6 +426,11 @@ OverlayWindow* Scene::overlayWindow()
return m_overlayWindow;
}
void Scene::screenGeometryChanged(const QSize &size)
{
m_overlayWindow->resize(size);
}
//****************************************
// Scene::Window
//****************************************

View file

@ -60,6 +60,13 @@ public:
virtual void windowAdded(Toplevel*) = 0;
// a window has been destroyed
virtual void windowDeleted(Deleted*) = 0;
/**
* Method invoked when the screen geometry is changed.
* Reimplementing classes should also invoke the parent method
* as it takes care of resizing the overlay window.
* @param size The new screen geometry size
**/
virtual void screenGeometryChanged(const QSize &size);
// Flags controlling how painting is done.
enum {
// Window (or at least part of it) will be painted opaque.

View file

@ -53,6 +53,7 @@ public:
virtual void paint(QRegion damage, ToplevelList windows);
virtual void windowAdded(Toplevel*);
virtual void windowDeleted(Deleted*);
virtual void screenGeometryChanged(const QSize &size);
protected:
virtual void paintGenericScreen(int mask, ScreenPaintData data);
@ -70,6 +71,9 @@ private:
bool initBufferConfigs();
bool initDrawableConfigs();
void waitSync();
#ifndef KWIN_HAVE_OPENGLES
void setupModelViewProjectionMatrix();
#endif
void flushBuffer(int mask, QRegion damage);
GC gcroot;
class FBConfigInfo
@ -86,6 +90,7 @@ private:
#ifndef KWIN_HAVE_OPENGLES
Drawable buffer;
GLXFBConfig fbcbuffer;
bool m_resetModelViewProjectionMatrix;
#endif
static bool db;
#ifndef KWIN_HAVE_OPENGLES

View file

@ -218,6 +218,13 @@ void SceneOpenGL::flushBuffer(int mask, QRegion damage)
XFlush(display());
}
void SceneOpenGL::screenGeometryChanged(const QSize &size)
{
glViewport(0,0, size.width(), size.height());
Scene::screenGeometryChanged(size);
ShaderManager::instance()->resetAllShaders();
}
//****************************************
// SceneOpenGL::Texture
//****************************************

View file

@ -38,6 +38,7 @@ GLXDrawable SceneOpenGL::last_pixmap = None;
SceneOpenGL::SceneOpenGL(Workspace* ws)
: Scene(ws)
, init_ok(false)
, m_resetModelViewProjectionMatrix(true)
{
initGLX();
// check for FBConfig support
@ -100,23 +101,7 @@ SceneOpenGL::SceneOpenGL(Workspace* ws)
}
// OpenGL scene setup
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
float fovy = 60.0f;
float aspect = 1.0f;
float zNear = 0.1f;
float zFar = 100.0f;
float ymax = zNear * tan(fovy * M_PI / 360.0f);
float ymin = -ymax;
float xmin = ymin * aspect;
float xmax = ymax * aspect;
// swap top and bottom to have OpenGL coordinate system match X system
glFrustum(xmin, xmax, ymin, ymax, zNear, zFar);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
float scaleFactor = 1.1 * tan(fovy * M_PI / 360.0f) / ymax;
glTranslatef(xmin * scaleFactor, ymax * scaleFactor, -1.1);
glScalef((xmax - xmin)*scaleFactor / displayWidth(), -(ymax - ymin)*scaleFactor / displayHeight(), 0.001);
setupModelViewProjectionMatrix();
if (checkGLError("Init")) {
kError(1212) << "OpenGL compositing setup failed";
return; // error
@ -152,6 +137,28 @@ SceneOpenGL::~SceneOpenGL()
checkGLError("Cleanup");
}
void SceneOpenGL::setupModelViewProjectionMatrix()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
float fovy = 60.0f;
float aspect = 1.0f;
float zNear = 0.1f;
float zFar = 100.0f;
float ymax = zNear * tan(fovy * M_PI / 360.0f);
float ymin = -ymax;
float xmin = ymin * aspect;
float xmax = ymax * aspect;
// swap top and bottom to have OpenGL coordinate system match X system
glFrustum(xmin, xmax, ymin, ymax, zNear, zFar);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
float scaleFactor = 1.1 * tan(fovy * M_PI / 360.0f) / ymax;
glTranslatef(xmin * scaleFactor, ymax * scaleFactor, -1.1);
glScalef((xmax - xmin)*scaleFactor / displayWidth(), -(ymax - ymin)*scaleFactor / displayHeight(), 0.001);
m_resetModelViewProjectionMatrix = false;
}
bool SceneOpenGL::initTfp()
{
if (glXBindTexImageEXT == NULL || glXReleaseTexImageEXT == NULL)
@ -451,6 +458,10 @@ void SceneOpenGL::paint(QRegion damage, ToplevelList toplevels)
grabXServer();
glXWaitX();
if (m_resetModelViewProjectionMatrix) {
// reset model view projection matrix if required
setupModelViewProjectionMatrix();
}
glPushMatrix();
int mask = 0;
#ifdef CHECK_GL_ERROR
@ -558,6 +569,33 @@ void SceneOpenGL::flushBuffer(int mask, QRegion damage)
}
}
void SceneOpenGL::screenGeometryChanged(const QSize &size)
{
Scene::screenGeometryChanged(size);
glViewport(0,0, size.width(), size.height());
if (m_overlayWindow->window() == None) {
glXMakeCurrent(display(), None, NULL);
glXDestroyPixmap(display(), glxbuffer);
XFreePixmap(display(), buffer);
XVisualInfo* visual = glXGetVisualFromFBConfig(display(), fbcbuffer);
buffer = XCreatePixmap(display(), rootWindow(), size.width(), size.height(), visual->depth);
XFree(visual);
glxbuffer = glXCreatePixmap(display(), fbcbuffer, buffer, NULL);
glXMakeCurrent(display(), glxbuffer, ctxbuffer);
// TODO: there seems some bug, some clients become black until an eg. un/remap - could be a general pixmap buffer issue, though
}
else {
glXMakeCurrent(display(), None, NULL); // deactivate context ////
XMoveResizeWindow(display(), buffer, 0,0, size.width(), size.height());
m_overlayWindow->setup(buffer);
XSync(display(), false); // ensure X11 stuff has applied ////
glXMakeCurrent(display(), glxbuffer, ctxbuffer); // reactivate context ////
glViewport(0,0, size.width(), size.height()); // adjust viewport last - should btw. be superflous on the Pixmap buffer - iirc glXCreatePixmap sets the context anyway. ////
}
ShaderManager::instance()->resetAllShaders();
m_resetModelViewProjectionMatrix = true;
}
//****************************************
// SceneOpenGL::Texture
//****************************************

View file

@ -99,8 +99,32 @@ SceneXrender::SceneXrender(Workspace* ws)
kError(1212) << "No XFixes v3+ extension available";
return;
}
initXRender(true);
}
SceneXrender::~SceneXrender()
{
if (!init_ok) {
// TODO this probably needs to clean up whatever has been created until the failure
m_overlayWindow->destroy();
return;
}
XRenderFreePicture(display(), front);
XRenderFreePicture(display(), buffer);
buffer = None;
m_overlayWindow->destroy();
foreach (Window * w, windows)
delete w;
}
void SceneXrender::initXRender(bool createOverlay)
{
init_ok = false;
if (front != None)
XRenderFreePicture(display(), front);
KXErrorHandler xerr;
if (m_overlayWindow->create()) {
bool haveOverlay = createOverlay ? m_overlayWindow->create() : (m_overlayWindow->window() != None);
if (haveOverlay) {
m_overlayWindow->setup(None);
XWindowAttributes attrs;
XGetWindowAttributes(display(), m_overlayWindow->window(), &attrs);
@ -129,21 +153,6 @@ SceneXrender::SceneXrender(Workspace* ws)
init_ok = true;
}
SceneXrender::~SceneXrender()
{
if (!init_ok) {
// TODO this probably needs to clean up whatever has been created until the failure
m_overlayWindow->destroy();
return;
}
XRenderFreePicture(display(), front);
XRenderFreePicture(display(), buffer);
buffer = None;
m_overlayWindow->destroy();
foreach (Window * w, windows)
delete w;
}
bool SceneXrender::initFailed() const
{
return !init_ok;
@ -153,6 +162,8 @@ bool SceneXrender::initFailed() const
// so it is done manually using this buffer,
void SceneXrender::createBuffer()
{
if (buffer != None)
XRenderFreePicture(display(), buffer);
Pixmap pixmap = XCreatePixmap(display(), rootWindow(), displayWidth(), displayHeight(), DefaultDepth(display(), DefaultScreen(display())));
buffer = XRenderCreatePicture(display(), pixmap, format, 0, 0);
XFreePixmap(display(), pixmap); // The picture owns the pixmap now
@ -774,6 +785,12 @@ XRenderComposite(display(), PictOpOver, _PART_->x11PictureHandle(), decorationAl
}
}
void SceneXrender::screenGeometryChanged(const QSize &size)
{
Scene::screenGeometryChanged(size);
initXRender(false);
}
//****************************************
// SceneXrender::EffectFrame
//****************************************

View file

@ -49,6 +49,7 @@ public:
virtual void paint(QRegion damage, ToplevelList windows);
virtual void windowAdded(Toplevel*);
virtual void windowDeleted(Deleted*);
virtual void screenGeometryChanged(const QSize &size);
Picture bufferPicture();
protected:
virtual void paintBackground(QRegion region);
@ -61,6 +62,7 @@ private:
void paintTransformedScreen(int mask);
void createBuffer();
void flushBuffer(int mask, QRegion damage);
void initXRender(bool createOverlay);
XRenderPictFormat* format;
Picture front;
static Picture buffer;