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:
parent
6152cc4fa5
commit
fe440377bb
2 changed files with 199 additions and 144 deletions
221
scene_opengl.cpp
221
scene_opengl.cpp
|
@ -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 ®ion, 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,12 +1008,9 @@ 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;
|
||||
GLTexture *tex = NULL;
|
||||
switch(type) {
|
||||
case Content:
|
||||
tex = texture;
|
||||
|
@ -1043,23 +1027,49 @@ void SceneOpenGL::Window::prepareStates(TextureType type, double opacity, double
|
|||
case DecorationBottom:
|
||||
tex = bottomTexture;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
prepareStates(type, opacity, brightness, saturation, shader, tex);
|
||||
case Shadow:
|
||||
tex = static_cast<SceneOpenGLShadow*>(m_shadow)->shadowTexture();
|
||||
}
|
||||
return tex;
|
||||
}
|
||||
|
||||
void SceneOpenGL::Window::prepareStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader, GLTexture *texture)
|
||||
|
||||
//***************************************
|
||||
// SceneOpenGL2Window
|
||||
//***************************************
|
||||
SceneOpenGL2Window::SceneOpenGL2Window(Toplevel *c)
|
||||
: SceneOpenGL::Window(c)
|
||||
{
|
||||
if (shader) {
|
||||
prepareShaderRenderStates(type, opacity, brightness, saturation, shader);
|
||||
}
|
||||
|
||||
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 {
|
||||
prepareRenderStates(type, opacity, brightness, saturation, texture);
|
||||
shader = ShaderManager::instance()->pushShader(ShaderManager::SimpleShader);
|
||||
shader->setUniform(GLShader::Offset, QVector2D(x(), y()));
|
||||
}
|
||||
}
|
||||
|
||||
shader->setUniform(GLShader::WindowTransformation, transformation(mask, data));
|
||||
}
|
||||
|
||||
void SceneOpenGL2Window::endRenderWindow(const WindowPaintData &data)
|
||||
{
|
||||
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
|
||||
|
|
|
@ -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 ®ion, 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
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue