Split SceneOpenGL::Window into specific classes for OpenGL 1 and 2

The Window implementation performed many checks whether the rendering
uses the OpenGL 1 or OpenGL 2 code path and there were quite a few
cludges around to make this work.

So instead of many if-else blocks the specific code has now been moved
into a specific sub class and calls to pure virtual method in the base
class are used to trigger this behavior. Although that adds some overhead
in a rather hot code path it should be better than the many chained
method calls used before to handle OpenGL 1 and 2.

It also makes the code a little bit more readable as all the complete
OpenGL 1 implementation is now in one block ifdefed for OpenGL ES.
This commit is contained in:
Martin Gräßlin 2012-09-06 12:25:55 +02:00
parent 6152cc4fa5
commit fe440377bb
2 changed files with 199 additions and 144 deletions

View file

@ -371,7 +371,7 @@ void SceneOpenGL::paintBackground(QRegion region)
void SceneOpenGL::windowAdded(Toplevel* c) void SceneOpenGL::windowAdded(Toplevel* c)
{ {
assert(!windows.contains(c)); assert(!windows.contains(c));
Window *w = new Window(c); Window *w = Window::createWindow(c);
windows[ c ] = w; windows[ c ] = w;
w->setScene(this); w->setScene(this);
connect(c, SIGNAL(opacityChanged(KWin::Toplevel*,qreal)), SLOT(windowOpacityChanged(KWin::Toplevel*))); connect(c, SIGNAL(opacityChanged(KWin::Toplevel*,qreal)), SLOT(windowOpacityChanged(KWin::Toplevel*)));
@ -561,6 +561,17 @@ SceneOpenGL::Window::~Window()
delete bottomTexture; delete bottomTexture;
} }
SceneOpenGL::Window *SceneOpenGL::Window::createWindow(Toplevel *t)
{
if (ShaderManager::instance()->isValid()) {
return new SceneOpenGL2Window(t);
}
#ifndef KWIN_HAVE_OPENGLES
return new SceneOpenGL1Window(t);
#endif
return NULL;
}
// Bind the window pixmap to an OpenGL texture. // Bind the window pixmap to an OpenGL texture.
bool SceneOpenGL::Window::bindTexture() bool SceneOpenGL::Window::bindTexture()
{ {
@ -707,26 +718,7 @@ void SceneOpenGL::Window::performPaint(int mask, QRegion region, WindowPaintData
texture->setFilter(filter == ImageFilterGood ? GL_LINEAR : GL_NEAREST); texture->setFilter(filter == ImageFilterGood ? GL_LINEAR : GL_NEAREST);
bool sceneShader = false; beginRenderWindow(mask, data);
if (!data.shader && ShaderManager::instance()->isValid()) {
// set the shader for uniform initialising in paint decoration
if ((mask & PAINT_WINDOW_TRANSFORMED) || (mask & PAINT_SCREEN_TRANSFORMED)) {
data.shader = ShaderManager::instance()->pushShader(ShaderManager::GenericShader);
} else {
data.shader = ShaderManager::instance()->pushShader(ShaderManager::SimpleShader);
data.shader->setUniform(GLShader::Offset, QVector2D(x(), y()));
}
sceneShader = true;
}
const QMatrix4x4 windowTransformation = transformation(mask, data);
if (data.shader)
data.shader->setUniform(GLShader::WindowTransformation, windowTransformation);
if (!sceneShader)
pushMatrix(windowTransformation);
WindowQuadList decoration = data.quads.select(WindowQuadDecoration); WindowQuadList decoration = data.quads.select(WindowQuadDecoration);
@ -801,9 +793,9 @@ void SceneOpenGL::Window::performPaint(int mask, QRegion region, WindowPaintData
WindowQuadList contentQuads = data.quads.select(WindowQuadContents); WindowQuadList contentQuads = data.quads.select(WindowQuadContents);
if (!contentQuads.empty()) { if (!contentQuads.empty()) {
texture->bind(); texture->bind();
prepareStates(Content, data.opacity(), data.brightness(), data.saturation(), data.shader); prepareStates(Content, data.opacity(), data.brightness(), data.saturation());
renderQuads(mask, region, contentQuads, texture, false, hardwareClipping); renderQuads(mask, region, contentQuads, texture, false, hardwareClipping);
restoreStates(Content, data.opacity(), data.brightness(), data.saturation(), data.shader); restoreStates(Content, data.opacity(), data.brightness(), data.saturation());
texture->unbind(); texture->unbind();
#ifndef KWIN_HAVE_OPENGLES #ifndef KWIN_HAVE_OPENGLES
if (m_scene && m_scene->debug) { if (m_scene && m_scene->debug) {
@ -818,12 +810,7 @@ void SceneOpenGL::Window::performPaint(int mask, QRegion region, WindowPaintData
glDisable(GL_SCISSOR_TEST); glDisable(GL_SCISSOR_TEST);
} }
if (sceneShader) { endRenderWindow(data);
ShaderManager::instance()->popShader();
data.shader = NULL;
} else {
popMatrix();
}
} }
void SceneOpenGL::Window::paintDecoration(const QPixmap* decoration, TextureType decorationType, void SceneOpenGL::Window::paintDecoration(const QPixmap* decoration, TextureType decorationType,
@ -886,10 +873,10 @@ void SceneOpenGL::Window::paintDecoration(const QPixmap* decoration, TextureType
decorationTexture->setWrapMode(GL_CLAMP_TO_EDGE); decorationTexture->setWrapMode(GL_CLAMP_TO_EDGE);
decorationTexture->bind(); decorationTexture->bind();
prepareStates(decorationType, data.opacity() * data.decorationOpacity(), data.brightness(), data.saturation(), data.shader); prepareStates(decorationType, data.opacity() * data.decorationOpacity(), data.brightness(), data.saturation());
makeDecorationArrays(quads, rect, decorationTexture); makeDecorationArrays(quads, rect, decorationTexture);
GLVertexBuffer::streamingBuffer()->render(region, GL_TRIANGLES, hardwareClipping); GLVertexBuffer::streamingBuffer()->render(region, GL_TRIANGLES, hardwareClipping);
restoreStates(decorationType, data.opacity() * data.decorationOpacity(), data.brightness(), data.saturation(), data.shader); restoreStates(decorationType, data.opacity() * data.decorationOpacity(), data.brightness(), data.saturation());
decorationTexture->unbind(); decorationTexture->unbind();
#ifndef KWIN_HAVE_OPENGLES #ifndef KWIN_HAVE_OPENGLES
if (m_scene && m_scene->debug) { if (m_scene && m_scene->debug) {
@ -923,9 +910,9 @@ void SceneOpenGL::Window::paintShadow(const QRegion &region, const WindowPaintDa
texture->setFilter(GL_NEAREST); texture->setFilter(GL_NEAREST);
texture->setWrapMode(GL_CLAMP_TO_EDGE); texture->setWrapMode(GL_CLAMP_TO_EDGE);
texture->bind(); texture->bind();
prepareStates(Shadow, data.opacity(), data.brightness(), data.saturation(), data.shader, texture); prepareStates(Shadow, data.opacity(), data.brightness(), data.saturation());
renderQuads(0, region, quads, texture, true, hardwareClipping); renderQuads(0, region, quads, texture, true, hardwareClipping);
restoreStates(Shadow, data.opacity(), data.brightness(), data.saturation(), data.shader, texture); restoreStates(Shadow, data.opacity(), data.brightness(), data.saturation());
texture->unbind(); texture->unbind();
#ifndef KWIN_HAVE_OPENGLES #ifndef KWIN_HAVE_OPENGLES
if (m_scene && m_scene->debug) { if (m_scene && m_scene->debug) {
@ -1021,45 +1008,68 @@ void SceneOpenGL::Window::renderQuads(int, const QRegion& region, const WindowQu
delete[] texcoords; delete[] texcoords;
} }
void SceneOpenGL::Window::prepareStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader) GLTexture *SceneOpenGL::Window::textureForType(SceneOpenGL::Window::TextureType type)
{ {
if (shader) GLTexture *tex = NULL;
prepareShaderRenderStates(type, opacity, brightness, saturation, shader); switch(type) {
else { case Content:
Texture *tex = NULL; tex = texture;
switch(type) { break;
case Content: case DecorationTop:
tex = texture; tex = topTexture;
break; break;
case DecorationTop: case DecorationLeft:
tex = topTexture; tex = leftTexture;
break; break;
case DecorationLeft: case DecorationRight:
tex = leftTexture; tex = rightTexture;
break; break;
case DecorationRight: case DecorationBottom:
tex = rightTexture; tex = bottomTexture;
break; break;
case DecorationBottom: case Shadow:
tex = bottomTexture; tex = static_cast<SceneOpenGLShadow*>(m_shadow)->shadowTexture();
break; }
default: return tex;
return; }
//***************************************
// SceneOpenGL2Window
//***************************************
SceneOpenGL2Window::SceneOpenGL2Window(Toplevel *c)
: SceneOpenGL::Window(c)
{
}
SceneOpenGL2Window::~SceneOpenGL2Window()
{
}
void SceneOpenGL2Window::beginRenderWindow(int mask, const WindowPaintData &data)
{
GLShader *shader = data.shader;
if (!shader) {
// set the shader for uniform initialising in paint decoration
if ((mask & Scene::PAINT_WINDOW_TRANSFORMED) || (mask & Scene::PAINT_SCREEN_TRANSFORMED)) {
shader = ShaderManager::instance()->pushShader(ShaderManager::GenericShader);
} else {
shader = ShaderManager::instance()->pushShader(ShaderManager::SimpleShader);
shader->setUniform(GLShader::Offset, QVector2D(x(), y()));
} }
prepareStates(type, opacity, brightness, saturation, shader, tex);
} }
shader->setUniform(GLShader::WindowTransformation, transformation(mask, data));
} }
void SceneOpenGL::Window::prepareStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader, GLTexture *texture) void SceneOpenGL2Window::endRenderWindow(const WindowPaintData &data)
{ {
if (shader) { if (!data.shader) {
prepareShaderRenderStates(type, opacity, brightness, saturation, shader); ShaderManager::instance()->popShader();
} else {
prepareRenderStates(type, opacity, brightness, saturation, texture);
} }
} }
void SceneOpenGL::Window::prepareShaderRenderStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader) void SceneOpenGL2Window::prepareStates(TextureType type, qreal opacity, qreal brightness, qreal saturation)
{ {
// setup blending of transparent windows // setup blending of transparent windows
bool opaque = isOpaque() && opacity == 1.0; bool opaque = isOpaque() && opacity == 1.0;
@ -1076,23 +1086,55 @@ void SceneOpenGL::Window::prepareShaderRenderStates(TextureType type, double opa
} }
} }
const float rgb = brightness * opacity; const qreal rgb = brightness * opacity;
const float a = opacity; const qreal a = opacity;
GLShader *shader = ShaderManager::instance()->getBoundShader();
shader->setUniform(GLShader::ModulationConstant, QVector4D(rgb, rgb, rgb, a)); shader->setUniform(GLShader::ModulationConstant, QVector4D(rgb, rgb, rgb, a));
shader->setUniform(GLShader::Saturation, saturation); shader->setUniform(GLShader::Saturation, saturation);
shader->setUniform(GLShader::AlphaToOne, opaque ? 1 : 0); shader->setUniform(GLShader::AlphaToOne, opaque ? 1 : 0);
} }
void SceneOpenGL::Window::prepareRenderStates(TextureType type, double opacity, double brightness, double saturation, GLTexture *tex) void SceneOpenGL2Window::restoreStates(TextureType type, qreal opacity, qreal brightness, qreal saturation)
{ {
#ifdef KWIN_HAVE_OPENGLES Q_UNUSED(brightness);
Q_UNUSED(type) Q_UNUSED(saturation);
Q_UNUSED(opacity) bool opaque = isOpaque() && opacity == 1.0;
Q_UNUSED(brightness) if (type != Content)
Q_UNUSED(saturation) opaque = false;
Q_UNUSED(tex) if (!opaque) {
#else glDisable(GL_BLEND);
}
ShaderManager::instance()->getBoundShader()->setUniform(GLShader::AlphaToOne, 0);
}
//***************************************
// SceneOpenGL1Window
//***************************************
#ifndef KWIN_HAVE_OPENGLES
SceneOpenGL1Window::SceneOpenGL1Window(Toplevel *c)
: SceneOpenGL::Window(c)
{
}
SceneOpenGL1Window::~SceneOpenGL1Window()
{
}
void SceneOpenGL1Window::beginRenderWindow(int mask, const WindowPaintData &data)
{
pushMatrix(transformation(mask, data));
}
void SceneOpenGL1Window::endRenderWindow(const WindowPaintData &data)
{
Q_UNUSED(data)
popMatrix();
}
void SceneOpenGL1Window::prepareStates(TextureType type, qreal opacity, qreal brightness, qreal saturation)
{
GLTexture *tex = textureForType(type);
bool alpha = false; bool alpha = false;
bool opaque = true; bool opaque = true;
if (type == Content) { if (type == Content) {
@ -1217,70 +1259,11 @@ void SceneOpenGL::Window::prepareRenderStates(TextureType type, double opacity,
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_CONSTANT); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_CONSTANT);
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant); glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant);
} }
#endif
} }
void SceneOpenGL::Window::restoreStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader) void SceneOpenGL1Window::restoreStates(TextureType type, qreal opacity, qreal brightness, qreal saturation)
{ {
if (shader) GLTexture *tex = textureForType(type);
restoreShaderRenderStates(type, opacity, brightness, saturation, shader);
else {
Texture *tex = NULL;
switch(type) {
case Content:
tex = texture;
break;
case DecorationTop:
tex = topTexture;
break;
case DecorationLeft:
tex = leftTexture;
break;
case DecorationRight:
tex = rightTexture;
break;
case DecorationBottom:
tex = bottomTexture;
break;
default:
return;
}
restoreStates(type, opacity, brightness, saturation, shader, tex);
}
}
void SceneOpenGL::Window::restoreStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader, GLTexture *texture)
{
if (shader) {
restoreShaderRenderStates(type, opacity, brightness, saturation, shader);
} else {
restoreRenderStates(type, opacity, brightness, saturation, texture);
}
}
void SceneOpenGL::Window::restoreShaderRenderStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader)
{
Q_UNUSED(brightness);
Q_UNUSED(saturation);
Q_UNUSED(shader);
bool opaque = isOpaque() && opacity == 1.0;
if (type != Content)
opaque = false;
if (!opaque) {
glDisable(GL_BLEND);
}
ShaderManager::instance()->getBoundShader()->setUniform(GLShader::AlphaToOne, 0);
}
void SceneOpenGL::Window::restoreRenderStates(TextureType type, double opacity, double brightness, double saturation, GLTexture *tex)
{
Q_UNUSED(type)
#ifdef KWIN_HAVE_OPENGLES
Q_UNUSED(opacity)
Q_UNUSED(brightness)
Q_UNUSED(saturation)
Q_UNUSED(tex)
#else
if (opacity != 1.0 || saturation != 1.0 || brightness != 1.0f) { if (opacity != 1.0 || saturation != 1.0 || brightness != 1.0f) {
if (saturation != 1.0 && tex->saturationSupported()) { if (saturation != 1.0 && tex->saturationSupported()) {
glActiveTexture(GL_TEXTURE3); glActiveTexture(GL_TEXTURE3);
@ -1296,8 +1279,8 @@ void SceneOpenGL::Window::restoreRenderStates(TextureType type, double opacity,
glColor4f(0, 0, 0, 0); glColor4f(0, 0, 0, 0);
glPopAttrib(); // ENABLE_BIT glPopAttrib(); // ENABLE_BIT
#endif
} }
#endif
//**************************************** //****************************************
// SceneOpenGL::EffectFrame // SceneOpenGL::EffectFrame

View file

@ -132,7 +132,6 @@ class SceneOpenGL::Window
: public Scene::Window : public Scene::Window
{ {
public: public:
Window(Toplevel* c);
virtual ~Window(); virtual ~Window();
virtual void performPaint(int mask, QRegion region, WindowPaintData data); virtual void performPaint(int mask, QRegion region, WindowPaintData data);
virtual void pixmapDiscarded(); virtual void pixmapDiscarded();
@ -142,8 +141,16 @@ public:
void setScene(SceneOpenGL *scene) { void setScene(SceneOpenGL *scene) {
m_scene = scene; m_scene = scene;
} }
/**
* @brief Factory method to create a Window taking the OpenGL version into account.
*
* @param t The Toplevel for which a Scene Window should be created
* @return :SceneOpenGL::Window* OpenGL version aware Window
**/
static SceneOpenGL::Window *createWindow(Toplevel *t);
protected: protected:
Window(Toplevel* c);
enum TextureType { enum TextureType {
Content, Content,
DecorationTop, DecorationTop,
@ -158,14 +165,51 @@ protected:
void paintShadow(const QRegion &region, const WindowPaintData &data, bool hardwareClipping); void paintShadow(const QRegion &region, const WindowPaintData &data, bool hardwareClipping);
void makeDecorationArrays(const WindowQuadList& quads, const QRect &rect, Texture *tex) const; void makeDecorationArrays(const WindowQuadList& quads, const QRect &rect, Texture *tex) const;
void renderQuads(int, const QRegion& region, const WindowQuadList& quads, GLTexture* tex, bool normalized, bool hardwareClipping); void renderQuads(int, const QRegion& region, const WindowQuadList& quads, GLTexture* tex, bool normalized, bool hardwareClipping);
void prepareStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader); /**
void prepareStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader, GLTexture *texture); * @brief Called from performPaint once it is determined whether the window will be painted.
void prepareRenderStates(TextureType type, double opacity, double brightness, double saturation, GLTexture *tex); * This method has to be implemented by the concrete sub class to perform operations for setting
void prepareShaderRenderStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader); * up the OpenGL state (e.g. pushing a matrix).
void restoreStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader); *
void restoreStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader, GLTexture *texture); * @param mask The mask which is used to render the Window
void restoreRenderStates(TextureType type, double opacity, double brightness, double saturation, GLTexture *tex); * @param data The WindowPaintData for this frame
void restoreShaderRenderStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader); * @see performPaint
* @see endRenderWindow
**/
virtual void beginRenderWindow(int mask, const WindowPaintData &data) = 0;
/**
* @brief Called from performPaint once the window and decoration has been rendered.
* This method has to be implemented by the concrete sub class to perform operations for resetting
* the OpenGL state after rendering this window (e.g. pop matrix).
*
* @param data The WindowPaintData with which this window got rendered
**/
virtual void endRenderWindow(const WindowPaintData &data) = 0;
/**
* @brief Prepare the OpenGL rendering state before the texture with @p type will be rendered.
*
* @param type The type of the Texture which will be rendered
* @param opacity The opacity value to use for this rendering
* @param brightness The brightness value to use for this rendering
* @param saturation The saturation value to use for this rendering
**/
virtual void prepareStates(TextureType type, qreal opacity, qreal brightness, qreal saturation) = 0;
/**
* @brief Restores the OpenGL rendering state after the texture with @p type has been rendered.
*
* @param type The type of the Texture which has been rendered
* @param opacity The opacity value used for the rendering
* @param brightness The brightness value used for this rendering
* @param saturation The saturation value used for this rendering
**/
virtual void restoreStates(TextureType type, qreal opacity, qreal brightness, qreal saturation) = 0;
/**
* @brief Returns the texture for the given @p type.
*
* @param type The Texture Type for which the texture should be retrieved
* @return :GLTexture* the texture
**/
GLTexture *textureForType(TextureType type);
private: private:
Texture *texture; Texture *texture;
@ -176,6 +220,34 @@ private:
SceneOpenGL *m_scene; SceneOpenGL *m_scene;
}; };
class SceneOpenGL2Window : public SceneOpenGL::Window
{
public:
SceneOpenGL2Window(Toplevel *c);
virtual ~SceneOpenGL2Window();
protected:
virtual void beginRenderWindow(int mask, const WindowPaintData &data);
virtual void endRenderWindow(const WindowPaintData &data);
virtual void prepareStates(TextureType type, qreal opacity, qreal brightness, qreal saturation);
virtual void restoreStates(TextureType type, qreal opacity, qreal brightness, qreal saturation);
};
#ifndef KWIN_HAVE_OPENGLES
class SceneOpenGL1Window : public SceneOpenGL::Window
{
public:
SceneOpenGL1Window(Toplevel *c);
virtual ~SceneOpenGL1Window();
protected:
virtual void beginRenderWindow(int mask, const WindowPaintData &data);
virtual void endRenderWindow(const WindowPaintData &data);
virtual void prepareStates(TextureType type, qreal opacity, qreal brightness, qreal saturation);
virtual void restoreStates(TextureType type, qreal opacity, qreal brightness, qreal saturation);
};
#endif
class SceneOpenGL::EffectFrame class SceneOpenGL::EffectFrame
: public Scene::EffectFrame : public Scene::EffectFrame
{ {