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

Commit f82ed8f8 authored by Lucas Dupin's avatar Lucas Dupin
Browse files

Blur shader performance optimizations

- removed mipmap in favor of fbo approach
- bell curve computation outside of shade
- type casting optimizations
- pre-computation of shader variables
- increased UV precision to remove scaling artifacts
- move final copy operation to a blit

Test: visual
Test: systrace
Test: SurfaceFlinger_test
Fixes: 148292484
Change-Id: I2ad38cde837b090cadbadbb79b941dc0524948a4
parent 75df83e9
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -1003,7 +1003,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display,
        setViewportAndProjection(display.physicalDisplay, display.clip);
    } else {
        setViewportAndProjection(display.physicalDisplay, display.clip);
        auto status = mBlurFilter->setAsDrawTarget(display);
        auto status = mBlurFilter->setAsDrawTarget(display, blurLayer->backgroundBlurRadius);
        if (status != NO_ERROR) {
            ALOGE("Failed to prepare blur filter! Aborting GPU composition for buffer (%p).",
                  buffer->handle);
@@ -1037,7 +1037,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display,
                        .build();
    for (auto const layer : layers) {
        if (blurLayer == layer) {
            auto status = mBlurFilter->prepare(layer->backgroundBlurRadius);
            auto status = mBlurFilter->prepare();
            if (status != NO_ERROR) {
                ALOGE("Failed to render blur effect! Aborting GPU composition for buffer (%p).",
                      buffer->handle);
+8 −0
Original line number Diff line number Diff line
@@ -122,6 +122,14 @@ void GLFramebuffer::bind() const {
    glBindFramebuffer(GL_FRAMEBUFFER, mFramebufferName);
}

void GLFramebuffer::bindAsReadBuffer() const {
    glBindFramebuffer(GL_READ_FRAMEBUFFER, mFramebufferName);
}

void GLFramebuffer::bindAsDrawBuffer() const {
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mFramebufferName);
}

void GLFramebuffer::unbind() const {
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
+2 −0
Original line number Diff line number Diff line
@@ -48,6 +48,8 @@ public:
    int32_t getBufferWidth() const { return mBufferWidth; }
    GLenum getStatus() const { return mStatus; }
    void bind() const;
    void bindAsReadBuffer() const;
    void bindAsDrawBuffer() const;
    void unbind() const;

private:
+38 −25
Original line number Diff line number Diff line
@@ -31,29 +31,24 @@ namespace renderengine {
namespace gl {

BlurFilter::BlurFilter(GLESRenderEngine& engine)
      : mEngine(engine), mCompositionFbo(engine), mBlurredFbo(engine), mSimpleProgram(engine) {
    mSimpleProgram.compile(getVertexShader(), getSimpleFragShader());
    mSPosLoc = mSimpleProgram.getAttributeLocation("aPosition");
    mSUvLoc = mSimpleProgram.getAttributeLocation("aUV");
    mSTextureLoc = mSimpleProgram.getUniformLocation("uTexture");
      : mEngine(engine), mCompositionFbo(engine), mBlurredFbo(engine), mMixProgram(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");
}

status_t BlurFilter::setAsDrawTarget(const DisplaySettings& display) {
status_t BlurFilter::setAsDrawTarget(const DisplaySettings& display, uint32_t radius) {
    ATRACE_NAME("BlurFilter::setAsDrawTarget");
    mRadius = radius;

    if (!mTexturesAllocated) {
        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);
@@ -94,27 +89,41 @@ void BlurFilter::drawMesh(GLuint uv, GLuint position) {
status_t BlurFilter::render() {
    ATRACE_NAME("BlurFilter::render");

    // Now let's scale our blur up
    mSimpleProgram.useProgram();
    // Now let's scale our blur up. It will be interpolated with the larger composited
    // texture for the first frames, to hide downscaling artifacts.
    GLfloat mix = fmin(1.0, mRadius / kMaxCrossFadeRadius);
    if (mix >= 1) {
        mBlurredFbo.bindAsReadBuffer();
        glBlitFramebuffer(0, 0, mBlurredFbo.getBufferWidth(), mBlurredFbo.getBufferHeight(), 0, 0,
                          mDisplayWidth, mDisplayHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR);
        glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
        return NO_ERROR;
    }

    mMixProgram.useProgram();
    glUniform1f(mMMixLoc, mix);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, mBlurredFbo.getTextureName());
    glUniform1i(mSTextureLoc, 0);
    glUniform1i(mMTextureLoc, 0);
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, mCompositionFbo.getTextureName());
    glUniform1i(mMCompositionTextureLoc, 1);
    mEngine.checkErrors("Setting final pass uniforms");

    drawMesh(mSUvLoc, mSPosLoc);
    drawMesh(mMUvLoc, mMPosLoc);

    glUseProgram(0);
    glActiveTexture(GL_TEXTURE0);
    return NO_ERROR;
}

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

        in vec2 aPosition;
        in mediump vec2 aUV;
        out mediump vec2 vUV;
        in highp vec2 aUV;
        out highp vec2 vUV;

        void main() {
            vUV = aUV;
@@ -123,18 +132,22 @@ string BlurFilter::getVertexShader() const {
    )SHADER";
}

string BlurFilter::getSimpleFragShader() const {
string BlurFilter::getMixFragShader() const {
    string shader = R"SHADER(
        #version 310 es
        precision lowp float;
        precision mediump float;

        in mediump vec2 vUV;
        in highp vec2 vUV;
        out vec4 fragColor;

        uniform sampler2D uCompositionTexture;
        uniform sampler2D uTexture;
        uniform float uMix;

        void main() {
            fragColor = texture(uTexture, vUV);
            vec4 blurred = texture(uTexture, vUV);
            vec4 composition = texture(uCompositionTexture, vUV);
            fragColor = mix(composition, blurred, uMix);
        }
    )SHADER";
    return shader;
+13 −7
Original line number Diff line number Diff line
@@ -31,22 +31,25 @@ class BlurFilter {
public:
    // Downsample FBO to improve performance
    static constexpr float kFboScale = 0.25f;
    // To avoid downscaling artifacts, we interpolate the blurred fbo with the full composited
    // image, up to this radius.
    static constexpr float kMaxCrossFadeRadius = 15.0f;

    explicit BlurFilter(GLESRenderEngine& engine);
    virtual ~BlurFilter(){};

    // Set up render targets, redirecting output to offscreen texture.
    status_t setAsDrawTarget(const DisplaySettings&);
    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(uint32_t radius) = 0;
    virtual status_t prepare() = 0;
    // Render blur to the bound framebuffer (screen).
    status_t render();

protected:
    uint32_t mRadius;
    void drawMesh(GLuint uv, GLuint position);
    string getSimpleFragShader() const;
    string getVertexShader() const;

    GLESRenderEngine& mEngine;
@@ -58,12 +61,15 @@ protected:
    uint32_t mDisplayHeight;

private:
    string getMixFragShader() const;
    bool mTexturesAllocated = false;

    GenericProgram mSimpleProgram;
    GLuint mSPosLoc;
    GLuint mSUvLoc;
    GLuint mSTextureLoc;
    GenericProgram mMixProgram;
    GLuint mMPosLoc;
    GLuint mMUvLoc;
    GLuint mMMixLoc;
    GLuint mMTextureLoc;
    GLuint mMCompositionTextureLoc;
};

} // namespace gl
Loading