Blur shader polish
Overall performance optimizations, including float precision tweaks,
and mipmapping for better antialiasing.
Test: visual
Test: systrace
Test: SurfaceFlinger_test
Bug: 141640413
Change-Id: Ic4e6ac9ccea236c561416f000a2287f2867c71a3
diff --git a/libs/renderengine/gl/filters/BlurFilter.cpp b/libs/renderengine/gl/filters/BlurFilter.cpp
index a554687..a18a999 100644
--- a/libs/renderengine/gl/filters/BlurFilter.cpp
+++ b/libs/renderengine/gl/filters/BlurFilter.cpp
@@ -42,9 +42,20 @@
ATRACE_NAME("BlurFilter::setAsDrawTarget");
if (!mTexturesAllocated) {
- const uint32_t fboWidth = floorf(display.physicalDisplay.width() * kFboScale);
- const uint32_t fboHeight = floorf(display.physicalDisplay.height() * kFboScale);
- mCompositionFbo.allocateBuffers(fboWidth, fboHeight);
+ mDisplayWidth = display.physicalDisplay.width();
+ mDisplayHeight = display.physicalDisplay.height();
+ mCompositionFbo.allocateBuffers(mDisplayWidth, mDisplayHeight);
+
+ // Let's use mimap filtering on the offscreen composition texture,
+ // this will drastically improve overall shader quality.
+ glBindTexture(GL_TEXTURE_2D, mCompositionFbo.getTextureName());
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 3);
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ const uint32_t fboWidth = floorf(mDisplayWidth * kFboScale);
+ const uint32_t fboHeight = floorf(mDisplayHeight * kFboScale);
mBlurredFbo.allocateBuffers(fboWidth, fboHeight);
allocateTextures();
mTexturesAllocated = true;
diff --git a/libs/renderengine/gl/filters/BlurFilter.h b/libs/renderengine/gl/filters/BlurFilter.h
index 2b5ea58..e265b51 100644
--- a/libs/renderengine/gl/filters/BlurFilter.h
+++ b/libs/renderengine/gl/filters/BlurFilter.h
@@ -30,7 +30,7 @@
class BlurFilter {
public:
// Downsample FBO to improve performance
- static constexpr float kFboScale = 0.35f;
+ static constexpr float kFboScale = 0.25f;
explicit BlurFilter(GLESRenderEngine& engine);
virtual ~BlurFilter(){};
@@ -54,6 +54,8 @@
GLFramebuffer mCompositionFbo;
// Frame buffer holding the blur result.
GLFramebuffer mBlurredFbo;
+ uint32_t mDisplayWidth;
+ uint32_t mDisplayHeight;
private:
bool mTexturesAllocated = false;
diff --git a/libs/renderengine/gl/filters/GaussianBlurFilter.cpp b/libs/renderengine/gl/filters/GaussianBlurFilter.cpp
index b1ad72c..f5ba02a 100644
--- a/libs/renderengine/gl/filters/GaussianBlurFilter.cpp
+++ b/libs/renderengine/gl/filters/GaussianBlurFilter.cpp
@@ -77,12 +77,14 @@
// set uniforms
auto width = mVerticalPassFbo.getBufferWidth();
auto height = mVerticalPassFbo.getBufferHeight();
+ auto radiusF = fmax(1.0f, radius * kFboScale);
glViewport(0, 0, width, height);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, mCompositionFbo.getTextureName());
+ glGenerateMipmap(GL_TEXTURE_2D);
glUniform1i(mVTextureLoc, 0);
glUniform2f(mVSizeLoc, width, height);
- glUniform1f(mVRadiusLoc, radius * kFboScale);
+ glUniform1f(mVRadiusLoc, radiusF);
mEngine.checkErrors("Setting vertical-diagonal pass uniforms");
drawMesh(mVUvLoc, mVPosLoc);
@@ -96,7 +98,7 @@
glBindTexture(GL_TEXTURE_2D, mVerticalPassFbo.getTextureName());
glUniform1i(mHTextureLoc, 0);
glUniform2f(mHSizeLoc, width, height);
- glUniform1f(mHRadiusLoc, radius * kFboScale);
+ glUniform1f(mHRadiusLoc, radiusF);
mEngine.checkErrors("Setting vertical pass uniforms");
drawMesh(mHUvLoc, mHPosLoc);
@@ -122,8 +124,7 @@
uniform vec2 uSize;
uniform float uRadius;
- in mediump vec2 vUV;
-
+ mediump in vec2 vUV;
out vec4 fragColor;
#define PI 3.14159265359
@@ -131,7 +132,7 @@
#define MU 0.0
#define A 1.0 / (THETA * sqrt(2.0 * PI))
#define K 1.0 / (2.0 * THETA * THETA)
- #define MAX_SAMPLES 12
+ #define MAX_SAMPLES 10
float gaussianBellCurve(float x) {
float tmp = (x - MU);
@@ -139,14 +140,14 @@
}
vec3 gaussianBlur(sampler2D texture, mediump vec2 uv, float size,
- vec2 direction, float radius) {
+ mediump vec2 direction, float radius) {
float totalWeight = 0.0;
vec3 blurred = vec3(0.);
- int samples = min(int(floor(radius / 2.0)), MAX_SAMPLES);
+ int samples = min(int(ceil(radius / 2.0)), MAX_SAMPLES);
float inc = radius / (size * 2.0);
for (int i = -samples; i <= samples; i++) {
- float normalized = (float(i) / float(samples));
+ float normalized = float(i) / float(samples);
float weight = gaussianBellCurve(normalized);
float radInc = inc * normalized;
blurred += weight * (texture(texture, uv + radInc * direction)).rgb;;
@@ -162,7 +163,7 @@
#else
vec3 color = gaussianBlur(uTexture, vUV, uSize.y, vec2(0.0, 1.0), uRadius);
#endif
- fragColor = vec4(color.r, color.g, color.b, texture(uTexture, vUV).a);
+ fragColor = vec4(color, 1.0);
}
)SHADER";
diff --git a/libs/renderengine/gl/filters/LensBlurFilter.cpp b/libs/renderengine/gl/filters/LensBlurFilter.cpp
index 386bd91..799deac 100644
--- a/libs/renderengine/gl/filters/LensBlurFilter.cpp
+++ b/libs/renderengine/gl/filters/LensBlurFilter.cpp
@@ -86,12 +86,14 @@
// set uniforms
auto width = mVerticalDiagonalPassFbo.getBufferWidth();
auto height = mVerticalDiagonalPassFbo.getBufferHeight();
+ auto radiusF = fmax(1.0f, radius * kFboScale);
glViewport(0, 0, width, height);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, mCompositionFbo.getTextureName());
+ glGenerateMipmap(GL_TEXTURE_2D);
glUniform1i(mVDTexture0Loc, 0);
- glUniform2f(mVDSizeLoc, width, height);
- glUniform1f(mVDRadiusLoc, radius * kFboScale);
+ glUniform2f(mVDSizeLoc, mDisplayWidth, mDisplayHeight);
+ glUniform1f(mVDRadiusLoc, radiusF);
glUniform1i(mVDNumSamplesLoc, kNumSamples);
mEngine.checkErrors("Setting vertical-diagonal pass uniforms");
@@ -108,8 +110,8 @@
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, mVerticalDiagonalPassFbo.getSecondaryTextureName());
glUniform1i(mCTexture1Loc, 1);
- glUniform2f(mCSizeLoc, width, height);
- glUniform1f(mCRadiusLoc, radius * kFboScale);
+ glUniform2f(mCSizeLoc, mDisplayWidth, mDisplayHeight);
+ glUniform1f(mCRadiusLoc, radiusF);
glUniform1i(mCNumSamplesLoc, kNumSamples);
mEngine.checkErrors("Setting vertical pass uniforms");
@@ -134,7 +136,6 @@
shader += R"SHADER(
precision lowp float;
- #define BOKEH_ANGLE 0.0
#define PI 3.14159265359
uniform sampler2D uTexture0;
@@ -142,7 +143,7 @@
uniform float uRadius;
uniform int uNumSamples;
- in mediump vec2 vUV;
+ mediump in vec2 vUV;
#if DIRECTION == 0
layout(location = 0) out vec4 fragColor0;
@@ -152,61 +153,55 @@
out vec4 fragColor;
#endif
- vec4 blur(const sampler2D tex, in vec2 uv, const vec2 direction, float radius,
- in int samples, float intensity) {
- vec4 finalColor = vec4(vec3(0.0), 1.0);
- float blurAmount = 0.0;
+ const vec2 verticalMult = vec2(cos(PI / 2.0), sin(PI / 2.0));
+ const vec2 diagonalMult = vec2(cos(-PI / 6.0), sin(-PI / 6.0));
+ const vec2 diagonal2Mult = vec2(cos(-5.0 * PI / 6.0), sin(-5.0 * PI / 6.0));
+
+ vec3 blur(const sampler2D tex, vec2 uv, const vec2 direction, float radius,
+ int samples, float intensity) {
+ vec3 finalColor = vec3(0.0);
uv += direction * 0.5;
for (int i = 0; i < samples; i++){
float delta = radius * float(i) / float(samples);
- vec4 color = texture(tex, uv + direction * delta);
+ vec3 color = texture(tex, uv + direction * delta).rgb;
color.rgb *= intensity;
- color *= color.a;
- blurAmount += color.a;
finalColor += color;
}
- return finalColor / blurAmount;
+ return finalColor / float(samples);
}
- vec4 blur(const sampler2D tex, in vec2 uv, const vec2 direction, float radius,
- in int samples) {
+ vec3 blur(const sampler2D tex, vec2 uv, const vec2 direction, float radius,
+ int samples) {
return blur(tex, uv, direction, radius, samples, 1.0);
}
vec4[2] verticalDiagonalLensBlur (vec2 uv, sampler2D texture, vec2 resolution,
float radius, int samples) {
- float coc = texture(texture, uv).a;
-
// Vertical Blur
- vec2 blurDirV = (coc / resolution.xy) * vec2(cos(BOKEH_ANGLE + PI / 2.0),
- sin(BOKEH_ANGLE + PI / 2.0));
- vec3 colorV = blur(texture, uv, blurDirV, radius, samples).rgb * coc;
+ vec2 blurDirV = 1.0 / resolution.xy * verticalMult;
+ vec3 colorV = blur(texture, uv, blurDirV, radius, samples);
// Diagonal Blur
- vec2 blurDirD = (coc / resolution.xy) * vec2(cos(BOKEH_ANGLE - PI / 6.0),
- sin(BOKEH_ANGLE - PI / 6.0));
- vec3 colorD = blur(texture, uv, blurDirD, radius, samples).rgb * coc;
+ vec2 blurDirD = 1.0 / resolution.xy * diagonalMult;
+ vec3 colorD = blur(texture, uv, blurDirD, radius, samples);
vec4 composed[2];
- composed[0] = vec4(colorV, coc);
+ composed[0] = vec4(colorV, 1.0);
// added * 0.5, to remap
- composed[1] = vec4((colorD + colorV) * 0.5, coc);
+ composed[1] = vec4((colorD + colorV) * 0.5, 1.0);
return composed;
}
vec4 rhombiLensBlur (vec2 uv, sampler2D texture0, sampler2D texture1, vec2 resolution,
float radius, int samples) {
- float coc1 = texture(texture0, uv).a;
- float coc2 = texture(texture1, uv).a;
+ vec2 blurDirection1 = 1.0 / resolution.xy * diagonalMult;
+ vec3 color1 = blur(texture0, uv, blurDirection1, radius, samples);
- vec2 blurDirection1 = coc1 / resolution.xy * vec2(cos(BOKEH_ANGLE - PI / 6.0), sin(BOKEH_ANGLE - PI / 6.0));
- vec3 color1 = blur(texture0, uv, blurDirection1, radius, samples).rgb * coc1;
-
- vec2 blurDirection2 = coc2 / resolution.xy * vec2(cos(BOKEH_ANGLE - 5.0 * PI / 6.0), sin(BOKEH_ANGLE - 5.0 * PI / 6.0));
- vec3 color2 = blur(texture1, uv, blurDirection2, radius, samples, 2.0).rgb * coc2;
+ vec2 blurDirection2 = 1.0 / resolution.xy * diagonal2Mult;
+ vec3 color2 = blur(texture1, uv, blurDirection2, radius, samples, 2.0);
return vec4((color1 + color2) * 0.33, 1.0);
}