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.
icc-effect-5.14.5
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)
{
assert(!windows.contains(c));
Window *w = new Window(c);
Window *w = Window::createWindow(c);
windows[ c ] = w;
w->setScene(this);
connect(c, SIGNAL(opacityChanged(KWin::Toplevel*,qreal)), SLOT(windowOpacityChanged(KWin::Toplevel*)));
@ -561,6 +561,17 @@ SceneOpenGL::Window::~Window()
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.
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);
bool sceneShader = false;
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);
beginRenderWindow(mask, data);
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);
if (!contentQuads.empty()) {
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);
restoreStates(Content, data.opacity(), data.brightness(), data.saturation(), data.shader);
restoreStates(Content, data.opacity(), data.brightness(), data.saturation());
texture->unbind();
#ifndef KWIN_HAVE_OPENGLES
if (m_scene && m_scene->debug) {
@ -818,12 +810,7 @@ void SceneOpenGL::Window::performPaint(int mask, QRegion region, WindowPaintData
glDisable(GL_SCISSOR_TEST);
}
if (sceneShader) {
ShaderManager::instance()->popShader();
data.shader = NULL;
} else {
popMatrix();
}
endRenderWindow(data);
}
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->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);
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();
#ifndef KWIN_HAVE_OPENGLES
if (m_scene && m_scene->debug) {
@ -923,9 +910,9 @@ void SceneOpenGL::Window::paintShadow(const QRegion &region, const WindowPaintDa
texture->setFilter(GL_NEAREST);
texture->setWrapMode(GL_CLAMP_TO_EDGE);
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);
restoreStates(Shadow, data.opacity(), data.brightness(), data.saturation(), data.shader, texture);
restoreStates(Shadow, data.opacity(), data.brightness(), data.saturation());
texture->unbind();
#ifndef KWIN_HAVE_OPENGLES
if (m_scene && m_scene->debug) {
@ -1021,45 +1008,68 @@ void SceneOpenGL::Window::renderQuads(int, const QRegion& region, const WindowQu
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)
prepareShaderRenderStates(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;
GLTexture *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;
case Shadow:
tex = static_cast<SceneOpenGLShadow*>(m_shadow)->shadowTexture();
}
return tex;
}
//***************************************
// 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) {
prepareShaderRenderStates(type, opacity, brightness, saturation, shader);
} else {
prepareRenderStates(type, opacity, brightness, saturation, texture);
if (!data.shader) {
ShaderManager::instance()->popShader();
}
}
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
bool opaque = isOpaque() && opacity == 1.0;
@ -1076,23 +1086,55 @@ void SceneOpenGL::Window::prepareShaderRenderStates(TextureType type, double opa
}
}
const float rgb = brightness * opacity;
const float a = opacity;
const qreal rgb = brightness * opacity;
const qreal a = opacity;
GLShader *shader = ShaderManager::instance()->getBoundShader();
shader->setUniform(GLShader::ModulationConstant, QVector4D(rgb, rgb, rgb, a));
shader->setUniform(GLShader::Saturation, saturation);
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(type)
Q_UNUSED(opacity)
Q_UNUSED(brightness)
Q_UNUSED(saturation)
Q_UNUSED(tex)
#else
Q_UNUSED(brightness);
Q_UNUSED(saturation);
bool opaque = isOpaque() && opacity == 1.0;
if (type != Content)
opaque = false;
if (!opaque) {
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 opaque = true;
if (type == Content) {
@ -1217,70 +1259,11 @@ void SceneOpenGL::Window::prepareRenderStates(TextureType type, double opacity,
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_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)
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
GLTexture *tex = textureForType(type);
if (opacity != 1.0 || saturation != 1.0 || brightness != 1.0f) {
if (saturation != 1.0 && tex->saturationSupported()) {
glActiveTexture(GL_TEXTURE3);
@ -1296,8 +1279,8 @@ void SceneOpenGL::Window::restoreRenderStates(TextureType type, double opacity,
glColor4f(0, 0, 0, 0);
glPopAttrib(); // ENABLE_BIT
#endif
}
#endif
//****************************************
// SceneOpenGL::EffectFrame

View File

@ -132,7 +132,6 @@ class SceneOpenGL::Window
: public Scene::Window
{
public:
Window(Toplevel* c);
virtual ~Window();
virtual void performPaint(int mask, QRegion region, WindowPaintData data);
virtual void pixmapDiscarded();
@ -142,8 +141,16 @@ public:
void setScene(SceneOpenGL *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:
Window(Toplevel* c);
enum TextureType {
Content,
DecorationTop,
@ -158,14 +165,51 @@ protected:
void paintShadow(const QRegion &region, const WindowPaintData &data, bool hardwareClipping);
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 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);
void prepareRenderStates(TextureType type, double opacity, double brightness, double saturation, GLTexture *tex);
void prepareShaderRenderStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader);
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);
void restoreRenderStates(TextureType type, double opacity, double brightness, double saturation, GLTexture *tex);
void restoreShaderRenderStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader);
/**
* @brief Called from performPaint once it is determined whether the window will be painted.
* This method has to be implemented by the concrete sub class to perform operations for setting
* up the OpenGL state (e.g. pushing a matrix).
*
* @param mask The mask which is used to render the Window
* @param data The WindowPaintData for this frame
* @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:
Texture *texture;
@ -176,6 +220,34 @@ private:
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
: public Scene::EffectFrame
{