diff options
author | Romain Guy <romainguy@google.com> | 2012-10-18 15:05:02 -0700 |
---|---|---|
committer | Romain Guy <romainguy@google.com> | 2012-10-18 15:05:02 -0700 |
commit | 7c25aab491707f7324f9941b8cfa9bd2b4b97e76 (patch) | |
tree | 2e670c818c33bf2ead5342dad73b48e000d2e94c /libs | |
parent | b2e2f2470693e78baed20617f989d9a166864ed4 (diff) | |
download | frameworks_base-7c25aab491707f7324f9941b8cfa9bd2b4b97e76.zip frameworks_base-7c25aab491707f7324f9941b8cfa9bd2b4b97e76.tar.gz frameworks_base-7c25aab491707f7324f9941b8cfa9bd2b4b97e76.tar.bz2 |
Defer layer rendering to avoid stalls
Bug #7326824
When a layer is taken out of the cache and initialized it gets cleared
to prepare it for future rendering. This triggers the following sequence
of operations:
glBindFramebuffer(layer.fbo)
attach texture storage to FBO
glClear()
glBindFramebuffer(defaultFbo)
The clear forces a resolve on tilers which stalls the CPU for a little
while, thus producing jank during animations. This change moves the
clear to the next frame when we know we will have to execute a resolve
anyway.
Change-Id: Ic1939c25df20ed65a4c48dc81ee549b2cd8b6ec3
Diffstat (limited to 'libs')
-rw-r--r-- | libs/hwui/DisplayListRenderer.cpp | 2 | ||||
-rw-r--r-- | libs/hwui/DisplayListRenderer.h | 2 | ||||
-rw-r--r-- | libs/hwui/Layer.cpp | 1 | ||||
-rw-r--r-- | libs/hwui/Layer.h | 14 | ||||
-rw-r--r-- | libs/hwui/LayerRenderer.cpp | 23 | ||||
-rw-r--r-- | libs/hwui/LayerRenderer.h | 3 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.cpp | 13 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.h | 13 |
8 files changed, 58 insertions, 13 deletions
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp index 589d5c2..81e68bd 100644 --- a/libs/hwui/DisplayListRenderer.cpp +++ b/libs/hwui/DisplayListRenderer.cpp @@ -1434,7 +1434,7 @@ void DisplayListRenderer::setViewport(int width, int height) { mHeight = height; } -int DisplayListRenderer::prepareDirty(float left, float top, +status_t DisplayListRenderer::prepareDirty(float left, float top, float right, float bottom, bool opaque) { mSnapshot = new Snapshot(mFirstSnapshot, SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h index 2610055..e42def5 100644 --- a/libs/hwui/DisplayListRenderer.h +++ b/libs/hwui/DisplayListRenderer.h @@ -550,7 +550,7 @@ public: virtual bool isDeferred(); virtual void setViewport(int width, int height); - virtual int prepareDirty(float left, float top, float right, float bottom, bool opaque); + virtual status_t prepareDirty(float left, float top, float right, float bottom, bool opaque); virtual void finish(); virtual status_t callDrawGLFunction(Functor *functor, Rect& dirty); diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp index 882e4bb..1cdc063 100644 --- a/libs/hwui/Layer.cpp +++ b/libs/hwui/Layer.cpp @@ -31,6 +31,7 @@ Layer::Layer(const uint32_t layerWidth, const uint32_t layerHeight) { meshIndices = NULL; meshElementCount = 0; cacheable = true; + dirty = false; textureLayer = false; renderTarget = GL_TEXTURE_2D; texture.width = layerWidth; diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h index 448e3da..e1f6a70 100644 --- a/libs/hwui/Layer.h +++ b/libs/hwui/Layer.h @@ -162,6 +162,14 @@ struct Layer { this->cacheable = cacheable; } + inline bool isDirty() { + return dirty; + } + + inline void setDirty(bool dirty) { + this->dirty = dirty; + } + inline bool isTextureLayer() { return textureLayer; } @@ -287,6 +295,12 @@ private: bool textureLayer; /** + * When set to true, this layer is dirty and should be cleared + * before any rendering occurs. + */ + bool dirty; + + /** * Indicates the render target. */ GLenum renderTarget; diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp index f2e7f66..3484d41 100644 --- a/libs/hwui/LayerRenderer.cpp +++ b/libs/hwui/LayerRenderer.cpp @@ -18,6 +18,8 @@ #include <ui/Rect.h> +#include <private/hwui/DrawGlInfo.h> + #include "LayerCache.h" #include "LayerRenderer.h" #include "Matrix.h" @@ -41,7 +43,8 @@ void LayerRenderer::setViewport(int width, int height) { initViewport(width, height); } -int LayerRenderer::prepareDirty(float left, float top, float right, float bottom, bool opaque) { +status_t LayerRenderer::prepareDirty(float left, float top, float right, float bottom, + bool opaque) { LAYER_RENDERER_LOGD("Rendering into layer, fbo = %d", mLayer->getFbo()); glBindFramebuffer(GL_FRAMEBUFFER, mLayer->getFbo()); @@ -63,6 +66,20 @@ int LayerRenderer::prepareDirty(float left, float top, float right, float bottom return OpenGLRenderer::prepareDirty(dirty.left, dirty.top, dirty.right, dirty.bottom, opaque); } +status_t LayerRenderer::clear(float left, float top, float right, float bottom, bool opaque) { + if (mLayer->isDirty()) { + getCaches().disableScissor(); + glClear(GL_COLOR_BUFFER_BIT); + + getCaches().resetScissor(); + mLayer->setDirty(false); + + return DrawGlInfo::kStatusDone; + } + + return OpenGLRenderer::clear(left, top, right, bottom, opaque); +} + void LayerRenderer::finish() { OpenGLRenderer::finish(); @@ -201,6 +218,7 @@ Layer* LayerRenderer::createLayer(uint32_t width, uint32_t height, bool isOpaque layer->setAlpha(255, SkXfermode::kSrcOver_Mode); layer->setBlend(!isOpaque); layer->setColorFilter(NULL); + layer->setDirty(true); layer->region.clear(); GLuint previousFbo; @@ -229,9 +247,6 @@ Layer* LayerRenderer::createLayer(uint32_t width, uint32_t height, bool isOpaque glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, layer->getTexture(), 0); - caches.disableScissor(); - glClear(GL_COLOR_BUFFER_BIT); - glBindFramebuffer(GL_FRAMEBUFFER, previousFbo); return layer; diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h index acedbcc..c44abce 100644 --- a/libs/hwui/LayerRenderer.h +++ b/libs/hwui/LayerRenderer.h @@ -48,7 +48,8 @@ public: virtual ~LayerRenderer(); virtual void setViewport(int width, int height); - virtual int prepareDirty(float left, float top, float right, float bottom, bool opaque); + virtual status_t prepareDirty(float left, float top, float right, float bottom, bool opaque); + virtual status_t clear(float left, float top, float right, float bottom, bool opaque); virtual void finish(); ANDROID_API static Layer* createTextureLayer(bool isOpaque); diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index b6be5b3..914516c 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -165,11 +165,12 @@ void OpenGLRenderer::initViewport(int width, int height) { mFirstSnapshot->viewport.set(0, 0, width, height); } -int OpenGLRenderer::prepare(bool opaque) { +status_t OpenGLRenderer::prepare(bool opaque) { return prepareDirty(0.0f, 0.0f, mWidth, mHeight, opaque); } -int OpenGLRenderer::prepareDirty(float left, float top, float right, float bottom, bool opaque) { +status_t OpenGLRenderer::prepareDirty(float left, float top, float right, float bottom, + bool opaque) { mCaches.clearGarbage(); mSnapshot = new Snapshot(mFirstSnapshot, @@ -203,15 +204,18 @@ int OpenGLRenderer::prepareDirty(float left, float top, float right, float botto debugOverdraw(true, true); + return clear(left, top, right, bottom, opaque); +} + +status_t OpenGLRenderer::clear(float left, float top, float right, float bottom, bool opaque) { if (!opaque) { mCaches.enableScissor(); mCaches.setScissor(left, mSnapshot->height - bottom, right - left, bottom - top); glClear(GL_COLOR_BUFFER_BIT); return DrawGlInfo::kStatusDrew; - } else { - mCaches.resetScissor(); } + mCaches.resetScissor(); return DrawGlInfo::kStatusDone; } @@ -743,6 +747,7 @@ bool OpenGLRenderer::createLayer(float left, float top, float right, float botto bounds.getWidth() / float(layer->getWidth()), 0.0f); layer->setColorFilter(mColorFilter); layer->setBlend(true); + layer->setDirty(false); // Save the layer in the snapshot mSnapshot->flags |= Snapshot::kFlagIsLayer; diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index a40d69a..c5e4c8e 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -94,7 +94,7 @@ public: * and will not be cleared. If false, the target surface * will be cleared */ - ANDROID_API int prepare(bool opaque); + ANDROID_API status_t prepare(bool opaque); /** * Prepares the renderer to draw a frame. This method must be invoked @@ -110,7 +110,7 @@ public: * and will not be cleared. If false, the target surface * will be cleared in the specified dirty rectangle */ - virtual int prepareDirty(float left, float top, float right, float bottom, bool opaque); + virtual status_t prepareDirty(float left, float top, float right, float bottom, bool opaque); /** * Indicates the end of a frame. This method must be invoked whenever @@ -270,6 +270,11 @@ protected: void initViewport(int width, int height); /** + * Clears the underlying surface if needed. + */ + virtual status_t clear(float left, float top, float right, float bottom, bool opaque); + + /** * Call this method after updating a layer during a drawing pass. */ void resumeAfterLayer(); @@ -355,6 +360,10 @@ protected: return false; } + Caches& getCaches() { + return mCaches; + } + private: /** * Ensures the state of the renderer is the same as the state of |