diff --git a/src/effects/blur/blur.cpp b/src/effects/blur/blur.cpp index ea987514c5..0ef5087f8c 100644 --- a/src/effects/blur/blur.cpp +++ b/src/effects/blur/blur.cpp @@ -623,7 +623,7 @@ void BlurEffect::generateNoiseTexture() uint8_t *noiseImageLine = (uint8_t *) noiseImage.scanLine(y); for (int x = 0; x < noiseImage.width(); x++) { - noiseImageLine[x] = qrand() % m_noiseStrength + (128 - m_noiseStrength / 2); + noiseImageLine[x] = qrand() % m_noiseStrength; } } @@ -715,34 +715,58 @@ void BlurEffect::doBlur(const QRegion& shape, const QRect& screen, const float o glDisable(GL_BLEND); } + if (m_noiseStrength > 0) { + // Apply an additive noise onto the blurred image. + // The noise is useful to mask banding artifacts, which often happens due to the smooth color transitions in the + // blurred image. + // The noise is applied in perceptual space (i.e. after glDisable(GL_FRAMEBUFFER_SRGB)). This practice is also + // seen in other application of noise synthesis (films, image codecs), and makes the noise less visible overall + // (reduces graininess). + glEnable(GL_BLEND); + if (opacity < 1.0) { + // We need to modulate the opacity of the noise as well; otherwise a thin layer would appear when applying + // effects like fade out. + // glBlendColor should have been set above. + glBlendFunc(GL_CONSTANT_ALPHA, GL_ONE); + } else { + // Add the shader's output directly to the pixels in framebuffer. + glBlendFunc(GL_ONE, GL_ONE); + } + applyNoise(vbo, blurRectCount * (m_downSampleIterations + 1), shape.rectCount() * 6, screenProjection, windowRect.topLeft()); + glDisable(GL_BLEND); + } + vbo->unbindArrays(); } void BlurEffect::upscaleRenderToScreen(GLVertexBuffer *vbo, int vboStart, int blurRectCount, QMatrix4x4 screenProjection, QPoint windowPosition) { - glActiveTexture(GL_TEXTURE0); m_renderTextures[1].bind(); - if (m_noiseStrength > 0) { - m_shader->bind(BlurShader::NoiseSampleType); - m_shader->setTargetTextureSize(m_renderTextures[0].size() * GLRenderTarget::virtualScreenScale()); - m_shader->setNoiseTextureSize(m_noiseTexture->size() * GLRenderTarget::virtualScreenScale()); - m_shader->setTexturePosition(windowPosition * GLRenderTarget::virtualScreenScale()); - - glActiveTexture(GL_TEXTURE1); - m_noiseTexture->bind(); - } else { - m_shader->bind(BlurShader::UpSampleType); - m_shader->setTargetTextureSize(m_renderTextures[0].size() * GLRenderTarget::virtualScreenScale()); - } + m_shader->bind(BlurShader::UpSampleType); + m_shader->setTargetTextureSize(m_renderTextures[0].size() * GLRenderTarget::virtualScreenScale()); m_shader->setOffset(m_offset); m_shader->setModelViewProjectionMatrix(screenProjection); //Render to the screen vbo->draw(GL_TRIANGLES, vboStart, blurRectCount); + m_shader->unbind(); +} - glActiveTexture(GL_TEXTURE0); +void BlurEffect::applyNoise(GLVertexBuffer *vbo, int vboStart, int blurRectCount, QMatrix4x4 screenProjection, QPoint windowPosition) +{ + m_shader->bind(BlurShader::NoiseSampleType); + m_shader->setTargetTextureSize(m_renderTextures[0].size() * GLRenderTarget::virtualScreenScale()); + m_shader->setNoiseTextureSize(m_noiseTexture->size() * GLRenderTarget::virtualScreenScale()); + m_shader->setTexturePosition(windowPosition * GLRenderTarget::virtualScreenScale()); + + m_noiseTexture->bind(); + + m_shader->setOffset(m_offset); + m_shader->setModelViewProjectionMatrix(screenProjection); + + vbo->draw(GL_TRIANGLES, vboStart, blurRectCount); m_shader->unbind(); } diff --git a/src/effects/blur/blur.h b/src/effects/blur/blur.h index f6aab46dcb..afbacc5a5e 100644 --- a/src/effects/blur/blur.h +++ b/src/effects/blur/blur.h @@ -76,6 +76,7 @@ private: void generateNoiseTexture(); void upscaleRenderToScreen(GLVertexBuffer *vbo, int vboStart, int blurRectCount, QMatrix4x4 screenProjection, QPoint windowPosition); + void applyNoise(GLVertexBuffer *vbo, int vboStart, int blurRectCount, QMatrix4x4 screenProjection, QPoint windowPosition); void downSampleTexture(GLVertexBuffer *vbo, int blurRectCount); void upSampleTexture(GLVertexBuffer *vbo, int blurRectCount); void copyScreenSampleTexture(GLVertexBuffer *vbo, int blurRectCount, QRegion blurShape, QMatrix4x4 screenProjection); diff --git a/src/effects/blur/blurshader.cpp b/src/effects/blur/blurshader.cpp index 457290954e..8923e2e8eb 100644 --- a/src/effects/blur/blurshader.cpp +++ b/src/effects/blur/blurshader.cpp @@ -133,31 +133,19 @@ BlurShader::BlurShader(QObject *parent) streamFragCopy.flush(); - // Fragment shader - Noise texture + // Fragment shader - Noise tiling QTextStream streamFragNoise(&fragmentNoiseSource); streamFragNoise << glHeaderString << glUniformString; - streamFragNoise << "uniform sampler2D noiseTexUnit;\n"; streamFragNoise << "uniform vec2 noiseTextureSize;\n"; streamFragNoise << "uniform vec2 texStartPos;\n"; - // Upsampling + Noise streamFragNoise << "void main(void)\n"; streamFragNoise << "{\n"; - streamFragNoise << " vec2 uv = vec2(gl_FragCoord.xy / renderTextureSize);\n"; streamFragNoise << " vec2 uvNoise = vec2((texStartPos.xy + gl_FragCoord.xy) / noiseTextureSize);\n"; streamFragNoise << " \n"; - streamFragNoise << " vec4 sum = " << texture2D << "(texUnit, uv + vec2(-halfpixel.x * 2.0, 0.0) * offset);\n"; - streamFragNoise << " sum += " << texture2D << "(texUnit, uv + vec2(-halfpixel.x, halfpixel.y) * offset) * 2.0;\n"; - streamFragNoise << " sum += " << texture2D << "(texUnit, uv + vec2(0.0, halfpixel.y * 2.0) * offset);\n"; - streamFragNoise << " sum += " << texture2D << "(texUnit, uv + vec2(halfpixel.x, halfpixel.y) * offset) * 2.0;\n"; - streamFragNoise << " sum += " << texture2D << "(texUnit, uv + vec2(halfpixel.x * 2.0, 0.0) * offset);\n"; - streamFragNoise << " sum += " << texture2D << "(texUnit, uv + vec2(halfpixel.x, -halfpixel.y) * offset) * 2.0;\n"; - streamFragNoise << " sum += " << texture2D << "(texUnit, uv + vec2(0.0, -halfpixel.y * 2.0) * offset);\n"; - streamFragNoise << " sum += " << texture2D << "(texUnit, uv + vec2(-halfpixel.x, -halfpixel.y) * offset) * 2.0;\n"; - streamFragNoise << " \n"; - streamFragNoise << " " << fragColor << " = sum / 12.0 - (vec4(0.5, 0.5, 0.5, 0) - vec4(" << texture2D << "(noiseTexUnit, uvNoise).rrr, 0));\n"; + streamFragNoise << " " << fragColor << " = vec4(" << texture2D << "(texUnit, uvNoise).rrr, 0);\n"; streamFragNoise << "}\n"; streamFragNoise.flush(); @@ -168,9 +156,9 @@ BlurShader::BlurShader(QObject *parent) m_shaderNoisesample.reset(ShaderManager::instance()->loadShaderFromCode(vertexSource, fragmentNoiseSource)); m_valid = m_shaderDownsample->isValid() && - m_shaderUpsample->isValid() && - m_shaderCopysample->isValid() && - m_shaderNoisesample->isValid(); + m_shaderUpsample->isValid() && + m_shaderCopysample->isValid() && + m_shaderNoisesample->isValid(); if (m_valid) { m_mvpMatrixLocationDownsample = m_shaderDownsample->uniformLocation("modelViewProjectionMatrix"); @@ -227,9 +215,6 @@ BlurShader::BlurShader(QObject *parent) m_shaderNoisesample->setUniform(m_texStartPosLocationNoisesample, QVector2D(1.0, 1.0)); m_shaderNoisesample->setUniform(m_halfpixelLocationNoisesample, QVector2D(1.0, 1.0)); - glUniform1i(m_shaderNoisesample->uniformLocation("texUnit"), 0); - glUniform1i(m_shaderNoisesample->uniformLocation("noiseTexUnit"), 1); - ShaderManager::instance()->popShader(); } }