kwin: Refactor SceneOpenGL::Window
Reimplement performPaint() in SceneOpenGL1Window and SceneOpenGL2Window. The roles between begin/endRenderWindow() and performPaint() are now reversed; performPaint() contains the specialized code while begin/ endRenderWindow() contains the shared code. This reduces the state churn in the OpenGL2 backend from the repeated calls to prepare/restoreStates().
This commit is contained in:
parent
631769d18f
commit
40d6bd66d4
2 changed files with 177 additions and 76 deletions
204
scene_opengl.cpp
204
scene_opengl.cpp
|
@ -1053,11 +1053,10 @@ QMatrix4x4 SceneOpenGL::Window::transformation(int mask, const WindowPaintData &
|
||||||
return matrix;
|
return matrix;
|
||||||
}
|
}
|
||||||
|
|
||||||
// paint the window
|
bool SceneOpenGL::Window::beginRenderWindow(int mask, const QRegion ®ion, WindowPaintData &data)
|
||||||
void SceneOpenGL::Window::performPaint(int mask, QRegion region, WindowPaintData data)
|
|
||||||
{
|
{
|
||||||
if (region.isEmpty())
|
if (region.isEmpty())
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
m_hardwareClipping = region != infiniteRegion() && (mask & PAINT_WINDOW_TRANSFORMED) && !(mask & PAINT_SCREEN_TRANSFORMED);
|
m_hardwareClipping = region != infiniteRegion() && (mask & PAINT_WINDOW_TRANSFORMED) && !(mask & PAINT_SCREEN_TRANSFORMED);
|
||||||
if (region != infiniteRegion() && !m_hardwareClipping) {
|
if (region != infiniteRegion() && !m_hardwareClipping) {
|
||||||
|
@ -1084,7 +1083,7 @@ void SceneOpenGL::Window::performPaint(int mask, QRegion region, WindowPaintData
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bindTexture()) {
|
if (!bindTexture()) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_hardwareClipping) {
|
if (m_hardwareClipping) {
|
||||||
|
@ -1100,8 +1099,6 @@ void SceneOpenGL::Window::performPaint(int mask, QRegion region, WindowPaintData
|
||||||
|
|
||||||
m_texture->setFilter(filter == ImageFilterGood ? GL_LINEAR : GL_NEAREST);
|
m_texture->setFilter(filter == ImageFilterGood ? GL_LINEAR : GL_NEAREST);
|
||||||
|
|
||||||
beginRenderWindow(mask, data);
|
|
||||||
|
|
||||||
const GLVertexAttrib attribs[] = {
|
const GLVertexAttrib attribs[] = {
|
||||||
{ VA_Position, 2, GL_FLOAT, offsetof(GLVertex2D, position) },
|
{ VA_Position, 2, GL_FLOAT, offsetof(GLVertex2D, position) },
|
||||||
{ VA_TexCoord, 2, GL_FLOAT, offsetof(GLVertex2D, texcoord) },
|
{ VA_TexCoord, 2, GL_FLOAT, offsetof(GLVertex2D, texcoord) },
|
||||||
|
@ -1111,39 +1108,14 @@ void SceneOpenGL::Window::performPaint(int mask, QRegion region, WindowPaintData
|
||||||
vbo->reset();
|
vbo->reset();
|
||||||
vbo->setAttribLayout(attribs, 2, sizeof(GLVertex2D));
|
vbo->setAttribLayout(attribs, 2, sizeof(GLVertex2D));
|
||||||
|
|
||||||
// shadow
|
return true;
|
||||||
if (m_shadow) {
|
|
||||||
paintShadow(region, data);
|
|
||||||
}
|
|
||||||
// decorations
|
|
||||||
if (toplevel->isClient()) {
|
|
||||||
paintDecorations<Client>(data, region);
|
|
||||||
} else if (toplevel->isDeleted()) {
|
|
||||||
paintDecorations<Deleted>(data, region);
|
|
||||||
}
|
|
||||||
|
|
||||||
// paint the content
|
|
||||||
WindowQuadList contentQuads = data.quads.select(WindowQuadContents);
|
|
||||||
if (!contentQuads.empty()) {
|
|
||||||
m_texture->bind();
|
|
||||||
prepareStates(Content, data.opacity(), data.brightness(), data.saturation(), data.screen());
|
|
||||||
renderQuads(mask, region, contentQuads, m_texture, false);
|
|
||||||
restoreStates(Content, data.opacity(), data.brightness(), data.saturation());
|
|
||||||
m_texture->unbind();
|
|
||||||
#ifndef KWIN_HAVE_OPENGLES
|
|
||||||
if (m_scene && m_scene->debug()) {
|
|
||||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
|
||||||
renderQuads(mask, region, contentQuads, m_texture, false);
|
|
||||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SceneOpenGL::Window::endRenderWindow()
|
||||||
|
{
|
||||||
if (m_hardwareClipping) {
|
if (m_hardwareClipping) {
|
||||||
glDisable(GL_SCISSOR_TEST);
|
glDisable(GL_SCISSOR_TEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
endRenderWindow(data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1357,11 +1329,31 @@ SceneOpenGL2Window::~SceneOpenGL2Window()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneOpenGL2Window::beginRenderWindow(int mask, const WindowPaintData &data)
|
QVector4D SceneOpenGL2Window::modulate(float opacity, float brightness) const
|
||||||
{
|
{
|
||||||
|
const float a = opacity;
|
||||||
|
const float rgb = opacity * brightness;
|
||||||
|
|
||||||
|
return QVector4D(rgb, rgb, rgb, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneOpenGL2Window::setBlendEnabled(bool enabled)
|
||||||
|
{
|
||||||
|
if (enabled && !m_blendingEnabled)
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
else if (!enabled && m_blendingEnabled)
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
|
||||||
|
m_blendingEnabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneOpenGL2Window::performPaint(int mask, QRegion region, WindowPaintData data)
|
||||||
|
{
|
||||||
|
if (!beginRenderWindow(mask, region, data))
|
||||||
|
return;
|
||||||
|
|
||||||
GLShader *shader = data.shader;
|
GLShader *shader = data.shader;
|
||||||
if (!shader) {
|
if (!shader) {
|
||||||
// set the shader for uniform initialising in paint decoration
|
|
||||||
if ((mask & Scene::PAINT_WINDOW_TRANSFORMED) || (mask & Scene::PAINT_SCREEN_TRANSFORMED)) {
|
if ((mask & Scene::PAINT_WINDOW_TRANSFORMED) || (mask & Scene::PAINT_SCREEN_TRANSFORMED)) {
|
||||||
shader = ShaderManager::instance()->pushShader(ShaderManager::GenericShader);
|
shader = ShaderManager::instance()->pushShader(ShaderManager::GenericShader);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1370,16 +1362,113 @@ void SceneOpenGL2Window::beginRenderWindow(int mask, const WindowPaintData &data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static_cast<SceneOpenGL2*>(m_scene)->colorCorrection()->setupForOutput(data.screen());
|
||||||
|
|
||||||
shader->setUniform(GLShader::WindowTransformation, transformation(mask, data));
|
shader->setUniform(GLShader::WindowTransformation, transformation(mask, data));
|
||||||
|
shader->setUniform(GLShader::Saturation, data.saturation());
|
||||||
|
|
||||||
|
const GLenum filter = (mask & (Effect::PAINT_WINDOW_TRANSFORMED | Effect::PAINT_SCREEN_TRANSFORMED))
|
||||||
|
&& options->glSmoothScale() != 0 ? GL_LINEAR : GL_NEAREST;
|
||||||
|
|
||||||
|
WindowQuadList contentQuads;
|
||||||
|
WindowQuadList shadowQuads;
|
||||||
|
WindowQuadList decoQuads[2];
|
||||||
|
|
||||||
|
// Split the quads into separate lists for each type
|
||||||
|
foreach (const WindowQuad &quad, data.quads) {
|
||||||
|
switch (quad.type()) {
|
||||||
|
case WindowQuadDecorationLeftRight:
|
||||||
|
decoQuads[0].append(quad);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case WindowQuadDecorationTopBottom:
|
||||||
|
decoQuads[1].append(quad);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case WindowQuadContents:
|
||||||
|
contentQuads.append(quad);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case WindowQuadShadowTopLeft:
|
||||||
|
case WindowQuadShadowTop:
|
||||||
|
case WindowQuadShadowTopRight:
|
||||||
|
case WindowQuadShadowLeft:
|
||||||
|
case WindowQuadShadowRight:
|
||||||
|
case WindowQuadShadowBottomLeft:
|
||||||
|
case WindowQuadShadowBottom:
|
||||||
|
case WindowQuadShadowBottomRight:
|
||||||
|
shadowQuads.append(quad);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneOpenGL2Window::endRenderWindow(const WindowPaintData &data)
|
// Make sure the blend function is set up correctly in case we will be doing blending
|
||||||
{
|
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
if (!data.shader) {
|
|
||||||
ShaderManager::instance()->popShader();
|
|
||||||
|
// Shadow
|
||||||
|
// -----------
|
||||||
|
if (m_shadow && !shadowQuads.isEmpty()) {
|
||||||
|
if (GLTexture *texture = static_cast<SceneOpenGLShadow*>(m_shadow)->shadowTexture()) {
|
||||||
|
setBlendEnabled(true);
|
||||||
|
|
||||||
|
shader->setUniform(GLShader::ModulationConstant,
|
||||||
|
modulate(data.opacity() * data.decorationOpacity(), data.brightness()));
|
||||||
|
|
||||||
|
texture->setFilter(filter);
|
||||||
|
texture->setWrapMode(GL_CLAMP_TO_EDGE);
|
||||||
|
texture->bind();
|
||||||
|
|
||||||
|
renderQuads(0, region, shadowQuads, texture, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Decorations
|
||||||
|
// -----------
|
||||||
|
GLTexture *textures[2];
|
||||||
|
|
||||||
|
if (!(decoQuads[0].isEmpty() && decoQuads[1].isEmpty()) && getDecorationTextures(textures)) {
|
||||||
|
setBlendEnabled(true);
|
||||||
|
|
||||||
|
shader->setUniform(GLShader::ModulationConstant,
|
||||||
|
modulate(data.opacity() * data.decorationOpacity(), data.brightness()));
|
||||||
|
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
if (!textures[i] || decoQuads[i].isEmpty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
textures[i]->setFilter(filter);
|
||||||
|
textures[i]->setWrapMode(GL_CLAMP_TO_EDGE);
|
||||||
|
textures[i]->bind();
|
||||||
|
|
||||||
|
renderQuads(0, region, decoQuads[i], textures[i], false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Content
|
||||||
|
// ---------
|
||||||
|
if (!contentQuads.isEmpty()) {
|
||||||
|
setBlendEnabled(!isOpaque() || data.opacity() < 1.0);
|
||||||
|
|
||||||
|
shader->setUniform(GLShader::ModulationConstant, modulate(data.opacity(), data.brightness()));
|
||||||
|
|
||||||
|
m_texture->bind();
|
||||||
|
renderQuads(mask, region, contentQuads, m_texture, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
setBlendEnabled(false);
|
||||||
|
|
||||||
|
if (!data.shader)
|
||||||
|
ShaderManager::instance()->popShader();
|
||||||
|
|
||||||
|
endRenderWindow();
|
||||||
|
}
|
||||||
|
|
||||||
void SceneOpenGL2Window::prepareStates(TextureType type, qreal opacity, qreal brightness, qreal saturation, int screen)
|
void SceneOpenGL2Window::prepareStates(TextureType type, qreal opacity, qreal brightness, qreal saturation, int screen)
|
||||||
{
|
{
|
||||||
// setup blending of transparent windows
|
// setup blending of transparent windows
|
||||||
|
@ -1444,15 +1533,42 @@ SceneOpenGL1Window::~SceneOpenGL1Window()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneOpenGL1Window::beginRenderWindow(int mask, const WindowPaintData &data)
|
// paint the window
|
||||||
|
void SceneOpenGL1Window::performPaint(int mask, QRegion region, WindowPaintData data)
|
||||||
{
|
{
|
||||||
|
if (!beginRenderWindow(mask, region, data))
|
||||||
|
return;
|
||||||
|
|
||||||
pushMatrix(transformation(mask, data));
|
pushMatrix(transformation(mask, data));
|
||||||
|
|
||||||
|
// shadow
|
||||||
|
if (m_shadow) {
|
||||||
|
paintShadow(region, data);
|
||||||
|
}
|
||||||
|
// decorations
|
||||||
|
paintDecorations(data, region);
|
||||||
|
|
||||||
|
// paint the content
|
||||||
|
WindowQuadList contentQuads = data.quads.select(WindowQuadContents);
|
||||||
|
if (!contentQuads.empty()) {
|
||||||
|
m_texture->bind();
|
||||||
|
prepareStates(Content, data.opacity(), data.brightness(), data.saturation(), data.screen());
|
||||||
|
renderQuads(mask, region, contentQuads, m_texture, false);
|
||||||
|
restoreStates(Content, data.opacity(), data.brightness(), data.saturation());
|
||||||
|
m_texture->unbind();
|
||||||
|
|
||||||
|
#ifndef KWIN_HAVE_OPENGLES
|
||||||
|
if (m_scene && m_scene->debug()) {
|
||||||
|
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||||
|
renderQuads(mask, region, contentQuads, m_texture, false);
|
||||||
|
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneOpenGL1Window::endRenderWindow(const WindowPaintData &data)
|
|
||||||
{
|
|
||||||
Q_UNUSED(data)
|
|
||||||
popMatrix();
|
popMatrix();
|
||||||
|
|
||||||
|
endRenderWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneOpenGL1Window::prepareStates(TextureType type, qreal opacity, qreal brightness, qreal saturation, int screen)
|
void SceneOpenGL1Window::prepareStates(TextureType type, qreal opacity, qreal brightness, qreal saturation, int screen)
|
||||||
|
|
|
@ -33,6 +33,7 @@ namespace KWin
|
||||||
class ColorCorrection;
|
class ColorCorrection;
|
||||||
class LanczosFilter;
|
class LanczosFilter;
|
||||||
class OpenGLBackend;
|
class OpenGLBackend;
|
||||||
|
class OpenGLPaintRedirector;
|
||||||
|
|
||||||
class SceneOpenGL
|
class SceneOpenGL
|
||||||
: public Scene
|
: public Scene
|
||||||
|
@ -214,7 +215,9 @@ class SceneOpenGL::Window
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~Window();
|
virtual ~Window();
|
||||||
virtual void performPaint(int mask, QRegion region, WindowPaintData data);
|
bool beginRenderWindow(int mask, const QRegion ®ion, WindowPaintData &data);
|
||||||
|
virtual void performPaint(int mask, QRegion region, WindowPaintData data) = 0;
|
||||||
|
void endRenderWindow();
|
||||||
virtual void pixmapDiscarded();
|
virtual void pixmapDiscarded();
|
||||||
bool bindTexture();
|
bool bindTexture();
|
||||||
void discardTexture();
|
void discardTexture();
|
||||||
|
@ -233,28 +236,10 @@ protected:
|
||||||
};
|
};
|
||||||
|
|
||||||
QMatrix4x4 transformation(int mask, const WindowPaintData &data) const;
|
QMatrix4x4 transformation(int mask, const WindowPaintData &data) const;
|
||||||
|
bool getDecorationTextures(GLTexture **textures) const;
|
||||||
void paintDecoration(GLTexture *texture, TextureType type, const QRegion ®ion, const WindowPaintData &data, const WindowQuadList &quads);
|
void paintDecoration(GLTexture *texture, TextureType type, const QRegion ®ion, const WindowPaintData &data, const WindowQuadList &quads);
|
||||||
void paintShadow(const QRegion ®ion, const WindowPaintData &data);
|
void paintShadow(const QRegion ®ion, const WindowPaintData &data);
|
||||||
void renderQuads(int, const QRegion& region, const WindowQuadList& quads, GLTexture* tex, bool normalized);
|
void renderQuads(int, const QRegion& region, const WindowQuadList& quads, GLTexture* tex, bool normalized);
|
||||||
/**
|
|
||||||
* @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.
|
* @brief Prepare the OpenGL rendering state before the texture with @p type will be rendered.
|
||||||
*
|
*
|
||||||
|
@ -284,15 +269,15 @@ protected:
|
||||||
**/
|
**/
|
||||||
GLTexture *textureForType(TextureType type);
|
GLTexture *textureForType(TextureType type);
|
||||||
|
|
||||||
|
void paintDecorations(const WindowPaintData &data, const QRegion ®ion);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
SceneOpenGL *m_scene;
|
SceneOpenGL *m_scene;
|
||||||
bool m_hardwareClipping;
|
bool m_hardwareClipping;
|
||||||
|
Texture *m_texture;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
OpenGLPaintRedirector *paintRedirector() const;
|
OpenGLPaintRedirector *paintRedirector() const;
|
||||||
bool getDecorationTextures(GLTexture **textures) const;
|
|
||||||
void paintDecorations(const WindowPaintData &data, const QRegion ®ion);
|
|
||||||
Texture *m_texture;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class SceneOpenGL2Window : public SceneOpenGL::Window
|
class SceneOpenGL2Window : public SceneOpenGL::Window
|
||||||
|
@ -302,8 +287,9 @@ public:
|
||||||
virtual ~SceneOpenGL2Window();
|
virtual ~SceneOpenGL2Window();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void beginRenderWindow(int mask, const WindowPaintData &data);
|
QVector4D modulate(float opacity, float brightness) const;
|
||||||
virtual void endRenderWindow(const WindowPaintData &data);
|
void setBlendEnabled(bool enabled);
|
||||||
|
virtual void performPaint(int mask, QRegion region, WindowPaintData data);
|
||||||
virtual void prepareStates(TextureType type, qreal opacity, qreal brightness, qreal saturation, int screen);
|
virtual void prepareStates(TextureType type, qreal opacity, qreal brightness, qreal saturation, int screen);
|
||||||
virtual void restoreStates(TextureType type, qreal opacity, qreal brightness, qreal saturation);
|
virtual void restoreStates(TextureType type, qreal opacity, qreal brightness, qreal saturation);
|
||||||
|
|
||||||
|
@ -322,8 +308,7 @@ public:
|
||||||
virtual ~SceneOpenGL1Window();
|
virtual ~SceneOpenGL1Window();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void beginRenderWindow(int mask, const WindowPaintData &data);
|
virtual void performPaint(int mask, QRegion region, WindowPaintData data);
|
||||||
virtual void endRenderWindow(const WindowPaintData &data);
|
|
||||||
virtual void prepareStates(TextureType type, qreal opacity, qreal brightness, qreal saturation, int screen);
|
virtual void prepareStates(TextureType type, qreal opacity, qreal brightness, qreal saturation, int screen);
|
||||||
virtual void restoreStates(TextureType type, qreal opacity, qreal brightness, qreal saturation);
|
virtual void restoreStates(TextureType type, qreal opacity, qreal brightness, qreal saturation);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue