Introduce a helper class to automatically push/pop Shaders

The ShaderBinder class can be used for the case that a block of code
should be executed with a given Shader being bound. This is useful for
all the cases where there is a if-block for OpenGL2 execution with a
Shader being pushed in the first line to the ShaderManager and popped in
the last line of the block. With the helper this can be simplified to:

ShaderBinder binder(myCustomShader);

or

ShaderBinder binder(ShaderManager::GenericShader);

The ctor of ShaderBinder pushes the given Shader to the stack and once
the helper goes out of scope it will be popped again from the stack.

In addition the helper can take care of OpenGL 1 compositing, that is it
just does nothing. So it can also be used where there is a shared OpenGL1
and OpenGL2 code path where the Shader should only be pushed in OpenGL2.
This basically removes all the checks for the compositing type before
pushing/popping a Shader to the stack.

REVIEW: 106521
icc-effect-5.14.5
Martin Gräßlin 2012-09-21 11:25:08 +02:00
parent f9a2ecbf33
commit c2a4f81927
16 changed files with 129 additions and 97 deletions

View File

@ -213,10 +213,9 @@ void CubeEffect::loadConfig(QString config)
}
// set the cap color on the shader
if (effects->compositingType() == OpenGL2Compositing && m_capShader->isValid()) {
ShaderManager::instance()->pushShader(m_capShader);
if (m_capShader->isValid()) {
ShaderBinder binder(m_capShader);
m_capShader->setUniform("u_capColor", capColor);
ShaderManager::instance()->popShader();
}
}
@ -311,7 +310,7 @@ bool CubeEffect::loadShader()
kError(1212) << "The cylinder shader failed to load!" << endl;
return false;
} else {
shaderManager->pushShader(cylinderShader);
ShaderBinder binder(cylinderShader);
cylinderShader->setUniform("sampler", 0);
QMatrix4x4 projection;
float fovy = 60.0f;
@ -334,7 +333,6 @@ bool CubeEffect::loadShader()
cylinderShader->setUniform(GLShader::WindowTransformation, identity);
QRect rect = effects->clientArea(FullArea, activeScreen, effects->currentDesktop());
cylinderShader->setUniform("width", (float)rect.width() * 0.5f);
shaderManager->popShader();
}
// TODO: use generic shader - currently it is failing in alpha/brightness manipulation
sphereShader = new GLShader(sphereVertexshader, fragmentshader);
@ -342,7 +340,7 @@ bool CubeEffect::loadShader()
kError(1212) << "The sphere shader failed to load!" << endl;
return false;
} else {
shaderManager->pushShader(sphereShader);
ShaderBinder binder(sphereShader);
sphereShader->setUniform("sampler", 0);
QMatrix4x4 projection;
float fovy = 60.0f;
@ -367,7 +365,6 @@ bool CubeEffect::loadShader()
sphereShader->setUniform("width", (float)rect.width() * 0.5f);
sphereShader->setUniform("height", (float)rect.height() * 0.5f);
sphereShader->setUniform("u_offset", QVector2D(0, 0));
shaderManager->popShader();
checkGLError("Loading Sphere Shader");
}
return true;
@ -404,15 +401,10 @@ void CubeEffect::paintScreen(int mask, QRegion region, ScreenPaintData& data)
// wallpaper
if (wallpaper) {
if (effects->compositingType() == OpenGL2Compositing) {
ShaderManager::instance()->pushShader(ShaderManager::SimpleShader);
}
ShaderBinder binder(ShaderManager::SimpleShader);
wallpaper->bind();
wallpaper->render(region, rect);
wallpaper->unbind();
if (effects->compositingType() == OpenGL2Compositing) {
ShaderManager::instance()->popShader();
}
}
glEnable(GL_BLEND);
@ -500,7 +492,7 @@ void CubeEffect::paintScreen(int mask, QRegion region, ScreenPaintData& data)
ShaderManager *shaderManager = ShaderManager::instance();
if (shaderManager->isValid() && m_reflectionShader->isValid()) {
// ensure blending is enabled - no attribute stack
shaderManager->pushShader(m_reflectionShader);
ShaderBinder binder(m_reflectionShader);
QMatrix4x4 windowTransformation;
windowTransformation.translate(rect.x() + rect.width() * 0.5f, 0.0, 0.0);
m_reflectionShader->setUniform("windowTransformation", windowTransformation);
@ -525,8 +517,6 @@ void CubeEffect::paintScreen(int mask, QRegion region, ScreenPaintData& data)
vbo->reset();
vbo->setData(6, 3, verts.data(), texcoords.data());
vbo->render(GL_TRIANGLES);
shaderManager->popShader();
} else {
#ifndef KWIN_HAVE_OPENGLES
glColor4f(0.0, 0.0, 0.0, alpha);

View File

@ -80,10 +80,9 @@ bool ExplosionEffect::loadData()
kError(1212) << "The shader failed to load!" << endl;
return false;
} else {
ShaderManager::instance()->pushShader(mShader);
ShaderBinder binder(mShader);
mShader->setUniform("startOffsetTexture", 4);
mShader->setUniform("endOffsetTexture", 5);
ShaderManager::instance()->popShader();
}
mStartOffsetTex = new GLTexture(starttexture);

View File

@ -219,7 +219,6 @@ void FlipSwitchEffect::paintScreen(int mask, QRegion region, ScreenPaintData& da
// TODO: move to kwinglutils
QMatrix4x4 origProjection;
QMatrix4x4 origModelview;
ShaderManager *shaderManager = ShaderManager::instance();
if (effects->numScreens() > 1) {
// unfortunatelly we have to change the projection matrix in dual screen mode
QRect fullRect = effects->clientArea(FullArea, effects->activeScreen(), effects->currentDesktop());
@ -265,13 +264,13 @@ void FlipSwitchEffect::paintScreen(int mask, QRegion region, ScreenPaintData& da
projection.frustum(xmin * xminFactor, xmax * xmaxFactor, ymin * yminFactor, ymax * ymaxFactor, zNear, zFar);
QMatrix4x4 modelview;
modelview.translate(xTranslate, yTranslate, 0.0);
if (shaderManager->isShaderBound()) {
GLShader *shader = shaderManager->pushShader(ShaderManager::GenericShader);
if (effects->compositingType() == OpenGL2Compositing) {
ShaderBinder binder(ShaderManager::GenericShader);
GLShader *shader = binder.shader();
origProjection = shader->getUniformMatrix4x4("projection");
origModelview = shader->getUniformMatrix4x4("modelview");
shader->setUniform("projection", projection);
shader->setUniform("modelview", origModelview * modelview);
shaderManager->popShader();
} else {
#ifndef KWIN_HAVE_OPENGLES
glMatrixMode(GL_PROJECTION);
@ -377,11 +376,11 @@ void FlipSwitchEffect::paintScreen(int mask, QRegion region, ScreenPaintData& da
}
if (effects->numScreens() > 1) {
if (shaderManager->isShaderBound()) {
GLShader *shader = shaderManager->pushShader(ShaderManager::GenericShader);
if (effects->compositingType() == OpenGL2Compositing) {
ShaderBinder binder(ShaderManager::GenericShader);
GLShader *shader = binder.shader();
shader->setUniform("projection", origProjection);
shader->setUniform("modelview", origModelview);
shaderManager->popShader();
} else {
#ifndef KWIN_HAVE_OPENGLES
popMatrix();

View File

@ -124,11 +124,10 @@ void InvertEffect::paintEffectFrame(KWin::EffectFrame* frame, QRegion region, do
{
if (m_valid && m_allWindows) {
frame->setShader(m_shader);
ShaderManager::instance()->pushShader(m_shader);
ShaderBinder binder(m_shader);
m_shader->setUniform("screenTransformation", QMatrix4x4());
m_shader->setUniform("windowTransformation", QMatrix4x4());
effects->paintEffectFrame(frame, region, opacity, frameOpacity);
ShaderManager::instance()->popShader();
} else {
effects->paintEffectFrame(frame, region, opacity, frameOpacity);
}

View File

@ -307,7 +307,7 @@ void LogoutEffect::renderVignetting()
QMatrix4x4 projection = ShaderManager::instance()->pushShader(KWin::ShaderManager::SimpleShader)->getUniformMatrix4x4("projection");
ShaderManager::instance()->popShader();
ShaderManager::instance()->pushShader(m_vignettingShader);
ShaderBinder binder(m_vignettingShader);
m_vignettingShader->setUniform(KWin::GLShader::ProjectionMatrix, projection);
m_vignettingShader->setUniform("u_progress", (float)progress * 0.9f);
glEnable(GL_BLEND);
@ -335,7 +335,6 @@ void LogoutEffect::renderVignetting()
}
glDisable(GL_SCISSOR_TEST);
glDisable(GL_BLEND);
ShaderManager::instance()->popShader();
}
void LogoutEffect::renderVignettingLegacy()
@ -384,7 +383,7 @@ void LogoutEffect::renderBlurTexture()
return;
}
// Unmodified base image
ShaderManager::instance()->pushShader(m_blurShader);
ShaderBinder binder(m_blurShader);
m_blurShader->setUniform(GLShader::Offset, QVector2D(0, 0));
m_blurShader->setUniform(GLShader::ModulationConstant, QVector4D(1.0, 1.0, 1.0, 1.0));
m_blurShader->setUniform(GLShader::Saturation, 1.0);
@ -396,7 +395,6 @@ void LogoutEffect::renderBlurTexture()
blurTexture->render(infiniteRegion(), QRect(0, 0, displayWidth(), displayHeight()));
blurTexture->unbind();
glDisable(GL_BLEND);
ShaderManager::instance()->popShader();
checkGLError("Render blur texture");
}

View File

@ -119,9 +119,8 @@ bool LookingGlassEffect::loadData()
const QString fragmentshader = KGlobal::dirs()->findResource("data", "kwin/lookingglass.frag");
m_shader = ShaderManager::instance()->loadFragmentShader(ShaderManager::SimpleShader, fragmentshader);
if (m_shader->isValid()) {
ShaderManager::instance()->pushShader(m_shader);
ShaderBinder binder(m_shader);
m_shader->setUniform("u_textureSize", QVector2D(displayWidth(), displayHeight()));
ShaderManager::instance()->popShader();
} else {
kError(1212) << "The shader failed to load!" << endl;
return false;
@ -242,12 +241,11 @@ void LookingGlassEffect::postPaintScreen()
m_texture->bind();
// Use the shader
ShaderManager::instance()->pushShader(m_shader);
ShaderBinder binder(m_shader);
m_shader->setUniform("u_zoom", (float)zoom);
m_shader->setUniform("u_radius", (float)radius);
m_shader->setUniform("u_cursor", QVector2D(cursorPos().x(), cursorPos().y()));
m_vbo->render(GL_TRIANGLES);
ShaderManager::instance()->popShader();
m_texture->unbind();
}
}

View File

@ -168,13 +168,9 @@ void MagnifierEffect::paintScreen(int mask, QRegion region, ScreenPaintData& dat
verts << area.right() + FRAME_WIDTH << area.bottom() + FRAME_WIDTH;
verts << area.right() + FRAME_WIDTH << area.bottom() + 1;
vbo->setData(verts.size() / 2, 2, verts.constData(), NULL);
if (effects->compositingType() == OpenGL2Compositing) {
ShaderManager::instance()->pushShader(ShaderManager::ColorShader);
}
ShaderBinder binder(ShaderManager::ColorShader);
vbo->render(GL_TRIANGLES);
if (effects->compositingType() == OpenGL2Compositing) {
ShaderManager::instance()->popShader();
}
}
if (effects->compositingType() == XRenderCompositing) {
#ifdef KWIN_HAVE_XRENDER_COMPOSITING

View File

@ -116,9 +116,7 @@ void MouseMarkEffect::paintScreen(int mask, QRegion region, ScreenPaintData& dat
vbo->reset();
vbo->setUseColor(true);
vbo->setColor(color);
if (effects->compositingType() == OpenGL2Compositing) {
ShaderManager::instance()->pushShader(ShaderManager::ColorShader);
}
ShaderBinder binder(ShaderManager::ColorShader);
QVector<float> verts;
foreach (const Mark & mark, marks) {
verts.clear();
@ -138,9 +136,6 @@ void MouseMarkEffect::paintScreen(int mask, QRegion region, ScreenPaintData& dat
vbo->setData(verts.size() / 2, 2, verts.data(), NULL);
vbo->render(GL_LINE_STRIP);
}
if (effects->compositingType() == OpenGL2Compositing) {
ShaderManager::instance()->popShader();
}
glLineWidth(1.0);
#ifndef KWIN_HAVE_OPENGLES
glDisable(GL_LINE_SMOOTH);

View File

@ -86,9 +86,7 @@ void ResizeEffect::paintWindow(EffectWindow* w, int mask, QRegion region, Window
GLVertexBuffer *vbo = GLVertexBuffer::streamingBuffer();
vbo->reset();
vbo->setUseColor(true);
if (effects->compositingType() == OpenGL2Compositing) {
ShaderManager::instance()->pushShader(ShaderManager::ColorShader);
}
ShaderBinder binder(ShaderManager::ColorShader);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
color.setAlphaF(alpha);
@ -105,9 +103,6 @@ void ResizeEffect::paintWindow(EffectWindow* w, int mask, QRegion region, Window
}
vbo->setData(verts.count() / 2, 2, verts.data(), NULL);
vbo->render(GL_TRIANGLES);
if (effects->compositingType() == OpenGL2Compositing) {
ShaderManager::instance()->popShader();
}
glDisable(GL_BLEND);
}

View File

@ -176,9 +176,7 @@ void ShowFpsEffect::paintGL(int fps)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// TODO painting first the background white and then the contents
// means that the contents also blend with the background, I guess
if (effects->compositingType() == OpenGL2Compositing) {
ShaderManager::instance()->pushShader(ShaderManager::ColorShader);
}
ShaderBinder binder(ShaderManager::ColorShader);
GLVertexBuffer *vbo = GLVertexBuffer::streamingBuffer();
vbo->reset();
QColor color(255, 255, 255);
@ -228,9 +226,6 @@ void ShowFpsEffect::paintGL(int fps)
// Paint amount of rendered pixels graph
paintDrawSizeGraph(x, y);
if (effects->compositingType() == OpenGL2Compositing) {
ShaderManager::instance()->popShader();
}
// Paint FPS numerical value
paintFPSText(fps);
@ -449,14 +444,11 @@ void ShowFpsEffect::paintFPSText(int fps)
delete fpsText;
fpsText = new GLTexture(im);
fpsText->bind();
ShaderBinder binder(ShaderManager::SimpleShader);
if (effects->compositingType() == OpenGL2Compositing) {
GLShader *shader = ShaderManager::instance()->pushShader(ShaderManager::SimpleShader);
shader->setUniform("offset", QVector2D(0, 0));
binder.shader()->setUniform("offset", QVector2D(0, 0));
}
fpsText->render(QRegion(fpsTextRect), fpsTextRect);
if (effects->compositingType() == OpenGL2Compositing) {
ShaderManager::instance()->popShader();
}
fpsText->unbind();
effects->addRepaint(fpsTextRect);
}

View File

@ -76,9 +76,7 @@ void ShowPaintEffect::paintGL()
GLVertexBuffer *vbo = GLVertexBuffer::streamingBuffer();
vbo->reset();
vbo->setUseColor(true);
if (effects->compositingType() == OpenGL2Compositing) {
ShaderManager::instance()->pushShader(ShaderManager::ColorShader);
}
ShaderBinder binder(ShaderManager::ColorShader);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
QColor color = colors[ color_index ];
@ -96,9 +94,6 @@ void ShowPaintEffect::paintGL()
}
vbo->setData(verts.count() / 2, 2, verts.data(), NULL);
vbo->render(GL_TRIANGLES);
if (effects->compositingType() == OpenGL2Compositing) {
ShaderManager::instance()->popShader();
}
glDisable(GL_BLEND);
}

View File

@ -81,9 +81,7 @@ void SnapHelperEffect::postPaintScreen()
GLVertexBuffer *vbo = GLVertexBuffer::streamingBuffer();
vbo->reset();
vbo->setUseColor(true);
if (effects->compositingType() == OpenGL2Compositing) {
ShaderManager::instance()->pushShader(ShaderManager::ColorShader);
}
ShaderBinder binder(ShaderManager::ColorShader);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@ -122,9 +120,6 @@ void SnapHelperEffect::postPaintScreen()
}
vbo->setData(verts.count() / 2, 2, verts.data(), NULL);
vbo->render(GL_LINES);
if (effects->compositingType() == OpenGL2Compositing) {
ShaderManager::instance()->popShader();
}
glDisable(GL_BLEND);
glLineWidth(1.0);

View File

@ -125,11 +125,10 @@ void TrackMouseEffect::paintScreen(int mask, QRegion region, ScreenPaintData& da
return;
if ( effects->isOpenGLCompositing() && m_texture[0] && m_texture[1]) {
GLShader *shader(0);
ShaderBinder binder(ShaderManager::GenericShader);
GLShader *shader(binder.shader());
QMatrix4x4 modelview;
if (effects->compositingType() == OpenGL2Compositing) {
ShaderManager::instance()->pushShader(ShaderManager::GenericShader);
shader = ShaderManager::instance()->getBoundShader();
if (shader) {
modelview = shader->getUniformMatrix4x4("modelview");
}
glEnable(GL_BLEND);
@ -154,9 +153,8 @@ void TrackMouseEffect::paintScreen(int mask, QRegion region, ScreenPaintData& da
popMatrix();
}
glDisable(GL_BLEND);
if (effects->compositingType() == OpenGL2Compositing) {
if (shader) {
shader->setUniform(GLShader::ModelViewMatrix, modelview);
ShaderManager::instance()->popShader();
}
}
#ifdef KWIN_HAVE_XRENDER_COMPOSITING

View File

@ -210,7 +210,8 @@ void LanczosFilter::performPaint(EffectWindowImpl* w, int mask, QRegion region,
const qreal rgb = data.brightness() * data.opacity();
const qreal a = data.opacity();
GLShader *shader = ShaderManager::instance()->pushShader(ShaderManager::SimpleShader);
ShaderBinder binder(ShaderManager::SimpleShader);
GLShader *shader = binder.shader();
shader->setUniform(GLShader::Offset, QVector2D(0, 0));
shader->setUniform(GLShader::ModulationConstant, QVector4D(rgb, rgb, rgb, a));
shader->setUniform(GLShader::Saturation, data.saturation());
@ -218,7 +219,6 @@ void LanczosFilter::performPaint(EffectWindowImpl* w, int mask, QRegion region,
cachedTexture->render(region, textureRect, hardwareClipping);
ShaderManager::instance()->popShader();
glDisable(GL_BLEND);
} else {
prepareRenderStates(cachedTexture, data.opacity(), data.brightness(), data.saturation());
@ -347,7 +347,8 @@ void LanczosFilter::performPaint(EffectWindowImpl* w, int mask, QRegion region,
const qreal rgb = data.brightness() * data.opacity();
const qreal a = data.opacity();
GLShader *shader = ShaderManager::instance()->pushShader(ShaderManager::SimpleShader);
ShaderBinder binder(ShaderManager::SimpleShader);
GLShader *shader = binder.shader();
shader->setUniform(GLShader::Offset, QVector2D(0, 0));
shader->setUniform(GLShader::ModulationConstant, QVector4D(rgb, rgb, rgb, a));
shader->setUniform(GLShader::Saturation, data.saturation());
@ -355,7 +356,6 @@ void LanczosFilter::performPaint(EffectWindowImpl* w, int mask, QRegion region,
cache->render(region, textureRect, hardwareClipping);
ShaderManager::instance()->popShader();
glDisable(GL_BLEND);
} else {
prepareRenderStates(cache, data.opacity(), data.brightness(), data.saturation());
@ -621,11 +621,10 @@ bool LanczosShader::init()
!(gl->isRadeon() && gl->chipClass() < R600)) {
m_shader = ShaderManager::instance()->loadFragmentShader(ShaderManager::SimpleShader, ":/resources/lanczos-fragment.glsl");
if (m_shader->isValid()) {
ShaderManager::instance()->pushShader(m_shader);
ShaderBinder binder(m_shader);
m_uTexUnit = m_shader->uniformLocation("texUnit");
m_uKernel = m_shader->uniformLocation("kernel");
m_uOffsets = m_shader->uniformLocation("offsets");
ShaderManager::instance()->popShader();
return true;
} else {
kDebug(1212) << "Shader is not valid";

View File

@ -394,6 +394,95 @@ private:
static ShaderManager *s_shaderManager;
};
/**
* An helper class to push a Shader on to ShaderManager's stack and ensuring that the Shader
* gets popped again from the stack automatically once the object goes out of life.
*
* How to use:
* @code
* {
* GLShader *myCustomShaderIWantToPush;
* ShaderBinder binder(myCustomShaderIWantToPush);
* // do stuff with the shader being pushed on the stack
* }
* // here the Shader is automatically popped as helper does no longer exist.
* @endcode
*
* This class takes care for the case that the Compositor uses OpenGL 1 and the ShaderManager is
* not valid. In that case the helper does not do anything. So this helper can be used to simplify
* the code to remove checks for OpenGL 1/2.
* @since 4.10
**/
class KWIN_EXPORT ShaderBinder
{
public:
/**
* @brief Pushes the Shader of the given @p type to the ShaderManager's stack.
*
* @param type The built-in Shader type
* @param reset Whether all uniforms should be reset to their default values. Defaults to false.
* @see ShaderManager::pushShader
**/
ShaderBinder(ShaderManager::ShaderType type, bool reset = false);
/**
* @brief Pushes the given @p shader to the ShaderManager's stack.
*
* @param shader The Shader to push on the stack
* @see ShaderManager::pushShader
**/
ShaderBinder(GLShader *shader);
~ShaderBinder();
/**
* @return The Shader pushed to the Stack. On OpenGL 1 this returns a @c null pointer.
**/
GLShader *shader();
private:
GLShader *m_shader;
};
inline
ShaderBinder::ShaderBinder(ShaderManager::ShaderType type, bool reset)
: m_shader(NULL)
{
#ifndef KWIN_HAVE_OPENGLES
if (!ShaderManager::instance()->isValid()) {
return;
}
#endif
m_shader = ShaderManager::instance()->pushShader(type, reset);
}
inline
ShaderBinder::ShaderBinder(GLShader *shader)
: m_shader(shader)
{
#ifndef KWIN_HAVE_OPENGLES
if (!ShaderManager::instance()->isValid()) {
return;
}
#endif
ShaderManager::instance()->pushShader(shader);
}
inline
ShaderBinder::~ShaderBinder()
{
#ifndef KWIN_HAVE_OPENGLES
if (!ShaderManager::instance()->isValid()) {
return;
}
#endif
ShaderManager::instance()->popShader();
}
inline
GLShader* ShaderBinder::shader()
{
return m_shader;
}
/**
* @short Render target object
*

View File

@ -447,14 +447,11 @@ SceneOpenGL2::~SceneOpenGL2()
void SceneOpenGL2::paintGenericScreen(int mask, ScreenPaintData data)
{
ShaderManager *shaderManager = ShaderManager::instance();
ShaderBinder binder(ShaderManager::GenericShader);
GLShader *shader = shaderManager->pushShader(ShaderManager::GenericShader);
shader->setUniform(GLShader::ScreenTransformation, transformation(mask, data));
binder.shader()->setUniform(GLShader::ScreenTransformation, transformation(mask, data));
Scene::paintGenericScreen(mask, data);
shaderManager->popShader();
}
void SceneOpenGL2::doPaintBackground(const QVector< float >& vertices)
@ -464,12 +461,10 @@ void SceneOpenGL2::doPaintBackground(const QVector< float >& vertices)
vbo->setUseColor(true);
vbo->setData(vertices.count() / 2, 2, vertices.data(), NULL);
GLShader *shader = ShaderManager::instance()->pushShader(ShaderManager::ColorShader);
shader->setUniform(GLShader::Offset, QVector2D(0, 0));
ShaderBinder binder(ShaderManager::ColorShader);
binder.shader()->setUniform(GLShader::Offset, QVector2D(0, 0));
vbo->render(GL_TRIANGLES);
ShaderManager::instance()->popShader();
}
SceneOpenGL::Window *SceneOpenGL2::createWindow(Toplevel *t)