Loading libs/renderengine/Android.bp +0 −2 Original line number Diff line number Diff line Loading @@ -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", ], } Loading libs/renderengine/gl/GLESRenderEngine.cpp +1 −9 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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"); } Loading libs/renderengine/gl/GLESRenderEngine.h +0 −2 Original line number Diff line number Diff line Loading @@ -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); Loading libs/renderengine/gl/filters/BlurFilter.cpp +107 −9 Original line number Diff line number Diff line Loading @@ -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) { Loading @@ -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"); Loading Loading @@ -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"); Loading @@ -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; } Loading @@ -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()); Loading Loading @@ -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; Loading @@ -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 libs/renderengine/gl/filters/BlurFilter.h +23 −9 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -70,6 +78,12 @@ private: GLuint mMMixLoc; GLuint mMTextureLoc; GLuint mMCompositionTextureLoc; GenericProgram mBlurProgram; GLuint mBPosLoc; GLuint mBUvLoc; GLuint mBTextureLoc; GLuint mBOffsetLoc; }; } // namespace gl Loading Loading
libs/renderengine/Android.bp +0 −2 Original line number Diff line number Diff line Loading @@ -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", ], } Loading
libs/renderengine/gl/GLESRenderEngine.cpp +1 −9 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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"); } Loading
libs/renderengine/gl/GLESRenderEngine.h +0 −2 Original line number Diff line number Diff line Loading @@ -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); Loading
libs/renderengine/gl/filters/BlurFilter.cpp +107 −9 Original line number Diff line number Diff line Loading @@ -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) { Loading @@ -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"); Loading Loading @@ -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"); Loading @@ -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; } Loading @@ -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()); Loading Loading @@ -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; Loading @@ -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
libs/renderengine/gl/filters/BlurFilter.h +23 −9 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -70,6 +78,12 @@ private: GLuint mMMixLoc; GLuint mMTextureLoc; GLuint mMCompositionTextureLoc; GenericProgram mBlurProgram; GLuint mBPosLoc; GLuint mBUvLoc; GLuint mBTextureLoc; GLuint mBOffsetLoc; }; } // namespace gl Loading