Add support for background blurs

Bug: 141640413
Fixes: 146384234
Test: adb shell setprop debug.sf.disableBlurs 1
Test: adb shell setprop debug.sf.gaussianBlur 0
Test: adb shell setprop ro.surface_flinger.supports_background_blur 1
Test: ./SurfaceFlinger_test --gtest_filter=Layer*Tests/Layer*Test.SetBackgroundBlur*
Test: ./librenderengine_test --gtest_filter=*BlurBackground*"
Test: atest SurfaceFlinger_test:SurfaceInterceptorTest#InterceptBackgroundBlurRadiusUpdateWorks
Change-Id: I5194c910fe7062f33e70943867012539e6c6626a
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 0748dfb..09659fe 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -49,6 +49,9 @@
 #include "GLShadowVertexGenerator.h"
 #include "Program.h"
 #include "ProgramCache.h"
+#include "filters/BlurFilter.h"
+#include "filters/GaussianBlurFilter.h"
+#include "filters/LensBlurFilter.h"
 
 extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
 
@@ -422,6 +425,18 @@
         mTraceGpuCompletion = true;
         mFlushTracer = std::make_unique<FlushTracer>(this);
     }
+
+    if (args.supportsBackgroundBlur) {
+        char isGaussian[PROPERTY_VALUE_MAX];
+        property_get("debug.sf.gaussianBlur", isGaussian, "1");
+        if (atoi(isGaussian)) {
+            mBlurFilter = new GaussianBlurFilter(*this);
+        } else {
+            mBlurFilter = new LensBlurFilter(*this);
+        }
+        checkErrors("BlurFilter creation");
+    }
+
     mImageManager = std::make_unique<ImageManager>(this);
     mDrawingBuffer = createFramebuffer();
 }
@@ -871,11 +886,19 @@
 }
 
 void GLESRenderEngine::checkErrors() const {
+    checkErrors(nullptr);
+}
+
+void GLESRenderEngine::checkErrors(const char* tag) const {
     do {
         // there could be more than one error flag
         GLenum error = glGetError();
         if (error == GL_NO_ERROR) break;
-        ALOGE("GL error 0x%04x", int(error));
+        if (tag == nullptr) {
+            ALOGE("GL error 0x%04x", int(error));
+        } else {
+            ALOGE("GL error: %s -> 0x%04x", tag, int(error));
+        }
     } while (true);
 }
 
@@ -957,13 +980,36 @@
         return BAD_VALUE;
     }
 
-    BindNativeBufferAsFramebuffer fbo(*this, buffer, useFramebufferCache);
+    std::unique_ptr<BindNativeBufferAsFramebuffer> fbo;
+    // Let's find the topmost layer requesting background blur (if any.)
+    // Blurs in multiple layers are not supported, given the cost of the shader.
+    const LayerSettings* blurLayer = nullptr;
+    if (CC_LIKELY(mBlurFilter != nullptr)) {
+        for (auto const& layer : layers) {
+            if (layer.backgroundBlurRadius > 0) {
+                blurLayer = &layer;
+            }
+        }
+    }
 
-    if (fbo.getStatus() != NO_ERROR) {
-        ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).",
-              buffer->handle);
-        checkErrors();
-        return fbo.getStatus();
+    if (blurLayer == nullptr) {
+        fbo = std::make_unique<BindNativeBufferAsFramebuffer>(*this, buffer, useFramebufferCache);
+        if (fbo->getStatus() != NO_ERROR) {
+            ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).",
+                  buffer->handle);
+            checkErrors();
+            return fbo->getStatus();
+        }
+        setViewportAndProjection(display.physicalDisplay, display.clip);
+    } else {
+        setViewportAndProjection(display.physicalDisplay, display.clip);
+        auto status = mBlurFilter->setAsDrawTarget(display);
+        if (status != NO_ERROR) {
+            ALOGE("Failed to prepare blur filter! Aborting GPU composition for buffer (%p).",
+                  buffer->handle);
+            checkErrors();
+            return status;
+        }
     }
 
     // clear the entire buffer, sometimes when we reuse buffers we'd persist
@@ -973,8 +1019,6 @@
     // opaque layers.
     clearWithColor(0.0, 0.0, 0.0, 0.0);
 
-    setViewportAndProjection(display.physicalDisplay, display.clip);
-
     setOutputDataSpace(display.outputDataspace);
     setDisplayMaxLuminance(display.maxLuminance);
 
@@ -991,7 +1035,36 @@
                         .setTexCoords(2 /* size */)
                         .setCropCoords(2 /* size */)
                         .build();
-    for (auto layer : layers) {
+    for (auto const& layer : layers) {
+        if (blurLayer == &layer) {
+            auto status = mBlurFilter->prepare(layer.backgroundBlurRadius);
+            if (status != NO_ERROR) {
+                ALOGE("Failed to render blur effect! Aborting GPU composition for buffer (%p).",
+                      buffer->handle);
+                checkErrors("Can't render first blur pass");
+                return status;
+            }
+
+            fbo = std::make_unique<BindNativeBufferAsFramebuffer>(*this, buffer,
+                                                                  useFramebufferCache);
+            status = fbo->getStatus();
+            if (status != NO_ERROR) {
+                ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).",
+                      buffer->handle);
+                checkErrors("Can't bind native framebuffer");
+                return status;
+            }
+            setViewportAndProjection(display.physicalDisplay, display.clip);
+
+            status = mBlurFilter->render();
+            if (status != NO_ERROR) {
+                ALOGE("Failed to render blur effect! Aborting GPU composition for buffer (%p).",
+                      buffer->handle);
+                checkErrors("Can't render blur filter");
+                return status;
+            }
+        }
+
         mState.maxMasteringLuminance = layer.source.buffer.maxMasteringLuminance;
         mState.maxContentLuminance = layer.source.buffer.maxContentLuminance;
         mState.projectionMatrix = projectionMatrix * layer.geometry.positionTransform;