Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2f57de16 authored by Automerger Merge Worker's avatar Automerger Merge Worker
Browse files

Merge changes I04f5fe51,I6d5790b2 into rvc-dev am: cb322091

Change-Id: Id5c002759106974cf8057c8957eba6865a387283
parents e1693364 cb322091
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -59,8 +59,6 @@ filegroup {
        "gl/Program.cpp",
        "gl/ProgramCache.cpp",
        "gl/filters/BlurFilter.cpp",
        "gl/filters/KawaseBlurFilter.cpp",
        "gl/filters/GaussianBlurFilter.cpp",
        "gl/filters/GenericProgram.cpp",
    ],
}
+1 −9
Original line number Diff line number Diff line
@@ -50,8 +50,6 @@
#include "Program.h"
#include "ProgramCache.h"
#include "filters/BlurFilter.h"
#include "filters/GaussianBlurFilter.h"
#include "filters/KawaseBlurFilter.h"

extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);

@@ -430,13 +428,7 @@ GLESRenderEngine::GLESRenderEngine(const RenderEngineCreationArgs& args, EGLDisp
    }

    if (args.supportsBackgroundBlur) {
        char isGaussian[PROPERTY_VALUE_MAX];
        property_get("debug.sf.gaussianBlur", isGaussian, "0");
        if (atoi(isGaussian)) {
            mBlurFilter = new GaussianBlurFilter(*this);
        } else {
            mBlurFilter = new KawaseBlurFilter(*this);
        }
        mBlurFilter = new BlurFilter(*this);
        checkErrors("BlurFilter creation");
    }

+0 −2
Original line number Diff line number Diff line
@@ -261,8 +261,6 @@ private:
    friend class ImageManager;
    friend class GLFramebuffer;
    friend class BlurFilter;
    friend class GaussianBlurFilter;
    friend class KawaseBlurFilter;
    friend class GenericProgram;
    std::unique_ptr<FlushTracer> mFlushTracer;
    std::unique_ptr<ImageManager> mImageManager = std::make_unique<ImageManager>(this);
+107 −9
Original line number Diff line number Diff line
@@ -31,13 +31,24 @@ namespace renderengine {
namespace gl {

BlurFilter::BlurFilter(GLESRenderEngine& engine)
      : mEngine(engine), mCompositionFbo(engine), mBlurredFbo(engine), mMixProgram(engine) {
      : mEngine(engine),
        mCompositionFbo(engine),
        mPingFbo(engine),
        mPongFbo(engine),
        mMixProgram(engine),
        mBlurProgram(engine) {
    mMixProgram.compile(getVertexShader(), getMixFragShader());
    mMPosLoc = mMixProgram.getAttributeLocation("aPosition");
    mMUvLoc = mMixProgram.getAttributeLocation("aUV");
    mMTextureLoc = mMixProgram.getUniformLocation("uTexture");
    mMCompositionTextureLoc = mMixProgram.getUniformLocation("uCompositionTexture");
    mMMixLoc = mMixProgram.getUniformLocation("uMix");

    mBlurProgram.compile(getVertexShader(), getFragmentShader());
    mBPosLoc = mBlurProgram.getAttributeLocation("aPosition");
    mBUvLoc = mBlurProgram.getAttributeLocation("aUV");
    mBTextureLoc = mBlurProgram.getUniformLocation("uTexture");
    mBOffsetLoc = mBlurProgram.getUniformLocation("uOffset");
}

status_t BlurFilter::setAsDrawTarget(const DisplaySettings& display, uint32_t radius) {
@@ -51,14 +62,14 @@ status_t BlurFilter::setAsDrawTarget(const DisplaySettings& display, uint32_t ra

        const uint32_t fboWidth = floorf(mDisplayWidth * kFboScale);
        const uint32_t fboHeight = floorf(mDisplayHeight * kFboScale);
        mBlurredFbo.allocateBuffers(fboWidth, fboHeight);
        allocateTextures();
        mPingFbo.allocateBuffers(fboWidth, fboHeight);
        mPongFbo.allocateBuffers(fboWidth, fboHeight);
        mTexturesAllocated = true;
    }

    if (mBlurredFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) {
    if (mPingFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) {
        ALOGE("Invalid blur buffer");
        return mBlurredFbo.getStatus();
        return mPingFbo.getStatus();
    }
    if (mCompositionFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) {
        ALOGE("Invalid composition buffer");
@@ -96,6 +107,61 @@ void BlurFilter::drawMesh(GLuint uv, GLuint position) {
    mEngine.checkErrors("Drawing blur mesh");
}

status_t BlurFilter::prepare() {
    ATRACE_NAME("BlurFilter::prepare");

    if (mPongFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) {
        ALOGE("Invalid FBO");
        return mPongFbo.getStatus();
    }
    if (!mBlurProgram.isValid()) {
        ALOGE("Invalid shader");
        return GL_INVALID_OPERATION;
    }

    blit(mCompositionFbo, mPingFbo);

    // Kawase is an approximation of Gaussian, but it behaves differently from it.
    // A radius transformation is required for approximating them, and also to introduce
    // non-integer steps, necessary to smoothly interpolate large radii.
    auto radius = mRadius / 6.0f;

    // Calculate how many passes we'll do, based on the radius.
    // Too many passes will make the operation expensive.
    auto passes = min(kMaxPasses, (uint32_t)ceil(radius));

    // We'll ping pong between our textures, to accumulate the result of various offsets.
    mBlurProgram.useProgram();
    GLFramebuffer* read = &mPingFbo;
    GLFramebuffer* draw = &mPongFbo;
    float stepX = radius / (float)mCompositionFbo.getBufferWidth() / (float)passes;
    float stepY = radius / (float)mCompositionFbo.getBufferHeight() / (float)passes;
    glActiveTexture(GL_TEXTURE0);
    glUniform1i(mBTextureLoc, 0);
    for (auto i = 0; i < passes; i++) {
        ATRACE_NAME("BlurFilter::renderPass");
        draw->bind();

        glViewport(0, 0, draw->getBufferWidth(), draw->getBufferHeight());
        glBindTexture(GL_TEXTURE_2D, read->getTextureName());
        glUniform2f(mBOffsetLoc, stepX * i, stepY * i);
        mEngine.checkErrors("Setting uniforms");

        drawMesh(mBUvLoc, mBPosLoc);

        // Swap buffers for next iteration
        auto tmp = draw;
        draw = read;
        read = tmp;
    }
    mLastDrawTarget = read;

    // Cleanup
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    return NO_ERROR;
}

status_t BlurFilter::render(bool multiPass) {
    ATRACE_NAME("BlurFilter::render");

@@ -107,9 +173,10 @@ status_t BlurFilter::render(bool multiPass) {
    // be writing onto it. Let's disable the crossfade, otherwise we'd need 1 extra frame buffer,
    // as large as the screen size.
    if (mix >= 1 || multiPass) {
        mBlurredFbo.bindAsReadBuffer();
        glBlitFramebuffer(0, 0, mBlurredFbo.getBufferWidth(), mBlurredFbo.getBufferHeight(), 0, 0,
                          mDisplayWidth, mDisplayHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR);
        mLastDrawTarget->bindAsReadBuffer();
        glBlitFramebuffer(0, 0, mLastDrawTarget->getBufferWidth(),
                          mLastDrawTarget->getBufferHeight(), 0, 0, mDisplayWidth, mDisplayHeight,
                          GL_COLOR_BUFFER_BIT, GL_LINEAR);
        glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
        return NO_ERROR;
    }
@@ -117,7 +184,7 @@ status_t BlurFilter::render(bool multiPass) {
    mMixProgram.useProgram();
    glUniform1f(mMMixLoc, mix);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, mBlurredFbo.getTextureName());
    glBindTexture(GL_TEXTURE_2D, mLastDrawTarget->getTextureName());
    glUniform1i(mMTextureLoc, 0);
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, mCompositionFbo.getTextureName());
@@ -145,6 +212,28 @@ string BlurFilter::getVertexShader() const {
    )SHADER";
}

string BlurFilter::getFragmentShader() const {
    return R"SHADER(#version 310 es
        precision mediump float;

        uniform sampler2D uTexture;
        uniform vec2 uOffset;

        highp in vec2 vUV;
        out vec4 fragColor;

        void main() {
            fragColor  = texture(uTexture, vUV, 0.0);
            fragColor += texture(uTexture, vUV + vec2( uOffset.x,  uOffset.y), 0.0);
            fragColor += texture(uTexture, vUV + vec2( uOffset.x, -uOffset.y), 0.0);
            fragColor += texture(uTexture, vUV + vec2(-uOffset.x,  uOffset.y), 0.0);
            fragColor += texture(uTexture, vUV + vec2(-uOffset.x, -uOffset.y), 0.0);

            fragColor = vec4(fragColor.rgb * 0.2, 1.0);
        }
    )SHADER";
}

string BlurFilter::getMixFragShader() const {
    string shader = R"SHADER(#version 310 es
        precision mediump float;
@@ -165,6 +254,15 @@ string BlurFilter::getMixFragShader() const {
    return shader;
}

void BlurFilter::blit(GLFramebuffer& read, GLFramebuffer& draw) const {
    read.bindAsReadBuffer();
    draw.bindAsDrawBuffer();
    glBlitFramebuffer(0, 0, read.getBufferWidth(), read.getBufferHeight(), 0, 0,
                      draw.getBufferWidth(), draw.getBufferHeight(), GL_COLOR_BUFFER_BIT,
                      GL_LINEAR);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

} // namespace gl
} // namespace renderengine
} // namespace android
+23 −9
Original line number Diff line number Diff line
@@ -27,10 +27,17 @@ namespace android {
namespace renderengine {
namespace gl {

/**
 * This is an implementation of a Kawase blur, as described in here:
 * https://community.arm.com/cfs-file/__key/communityserver-blogs-components-weblogfiles/
 * 00-00-00-20-66/siggraph2015_2D00_mmg_2D00_marius_2D00_notes.pdf
 */
class BlurFilter {
public:
    // Downsample FBO to improve performance
    static constexpr float kFboScale = 0.25f;
    // Maximum number of render passes
    static constexpr uint32_t kMaxPasses = 6;
    // To avoid downscaling artifacts, we interpolate the blurred fbo with the full composited
    // image, up to this radius.
    static constexpr float kMaxCrossFadeRadius = 30.0f;
@@ -40,28 +47,29 @@ public:

    // Set up render targets, redirecting output to offscreen texture.
    status_t setAsDrawTarget(const DisplaySettings&, uint32_t radius);
    // Allocate any textures needed for the filter.
    virtual void allocateTextures() = 0;
    // Execute blur passes, rendering to offscreen texture.
    virtual status_t prepare() = 0;
    status_t prepare();
    // Render blur to the bound framebuffer (screen).
    status_t render(bool multiPass);

protected:
private:
    uint32_t mRadius;
    void drawMesh(GLuint uv, GLuint position);
    void blit(GLFramebuffer& read, GLFramebuffer& draw) const;
    string getVertexShader() const;
    string getFragmentShader() const;
    string getMixFragShader() const;

    GLESRenderEngine& mEngine;
    // Frame buffer holding the composited background.
    GLFramebuffer mCompositionFbo;
    // Frame buffer holding the blur result.
    GLFramebuffer mBlurredFbo;
    // Frame buffers holding the blur passes.
    GLFramebuffer mPingFbo;
    GLFramebuffer mPongFbo;
    uint32_t mDisplayWidth;
    uint32_t mDisplayHeight;

private:
    string getMixFragShader() const;
    // Buffer holding the final blur pass.
    GLFramebuffer* mLastDrawTarget;
    bool mTexturesAllocated = false;

    GenericProgram mMixProgram;
@@ -70,6 +78,12 @@ private:
    GLuint mMMixLoc;
    GLuint mMTextureLoc;
    GLuint mMCompositionTextureLoc;

    GenericProgram mBlurProgram;
    GLuint mBPosLoc;
    GLuint mBUvLoc;
    GLuint mBTextureLoc;
    GLuint mBOffsetLoc;
};

} // namespace gl
Loading