From 11cb642756093a4af901b1525375b1eb2b5c3e2b Mon Sep 17 00:00:00 2001 From: Romain Guy Date: Fri, 21 Sep 2012 00:39:43 -0700 Subject: Update layers in a single batch at the beginning of a frame Bug #7186819 Change-Id: Ice5926dfedfb3be3a3064e65008dafa2852407da --- libs/hwui/LayerRenderer.cpp | 4 ++ libs/hwui/LayerRenderer.h | 10 ++-- libs/hwui/OpenGLRenderer.cpp | 136 ++++++++++++++++++++++++++++++------------- libs/hwui/OpenGLRenderer.h | 15 +++++ 4 files changed, 121 insertions(+), 44 deletions(-) (limited to 'libs') diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp index 5d59a4c..bb004c0 100644 --- a/libs/hwui/LayerRenderer.cpp +++ b/libs/hwui/LayerRenderer.cpp @@ -78,6 +78,10 @@ GLint LayerRenderer::getTargetFbo() { return mLayer->getFbo(); } +bool LayerRenderer::suppressErrorChecks() { + return true; +} + /////////////////////////////////////////////////////////////////////////////// // Dirty region tracking /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h index 8d42f7f..392f863 100644 --- a/libs/hwui/LayerRenderer.h +++ b/libs/hwui/LayerRenderer.h @@ -51,10 +51,6 @@ public: virtual int prepareDirty(float left, float top, float right, float bottom, bool opaque); virtual void finish(); - virtual bool hasLayer(); - virtual Region* getRegion(); - virtual GLint getTargetFbo(); - ANDROID_API static Layer* createTextureLayer(bool isOpaque); ANDROID_API static Layer* createLayer(uint32_t width, uint32_t height, bool isOpaque = false); ANDROID_API static bool resizeLayer(Layer* layer, uint32_t width, uint32_t height); @@ -64,6 +60,12 @@ public: ANDROID_API static void destroyLayerDeferred(Layer* layer); ANDROID_API static bool copyLayer(Layer* layer, SkBitmap* bitmap); +protected: + virtual bool hasLayer(); + virtual Region* getRegion(); + virtual GLint getTargetFbo(); + virtual bool suppressErrorChecks(); + private: void generateMesh(); diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index da0900a..c475f20 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -177,6 +177,8 @@ int OpenGLRenderer::prepareDirty(float left, float top, float right, float botto mSnapshot->setClip(left, top, right, bottom); mDirtyClip = opaque; + updateLayers(); + // If we know that we are going to redraw the entire framebuffer, // perform a discard to let the driver know we don't need to preserve // the back buffer for this frame. @@ -230,33 +232,36 @@ void OpenGLRenderer::endTiling() { void OpenGLRenderer::finish() { endTiling(); + if (!suppressErrorChecks()) { #if DEBUG_OPENGL - GLenum status = GL_NO_ERROR; - while ((status = glGetError()) != GL_NO_ERROR) { - ALOGD("GL error from OpenGLRenderer: 0x%x", status); - switch (status) { - case GL_INVALID_ENUM: - ALOGE(" GL_INVALID_ENUM"); - break; - case GL_INVALID_VALUE: - ALOGE(" GL_INVALID_VALUE"); - break; - case GL_INVALID_OPERATION: - ALOGE(" GL_INVALID_OPERATION"); - break; - case GL_OUT_OF_MEMORY: - ALOGE(" Out of memory!"); - break; + GLenum status = GL_NO_ERROR; + while ((status = glGetError()) != GL_NO_ERROR) { + ALOGD("GL error from OpenGLRenderer: 0x%x", status); + switch (status) { + case GL_INVALID_ENUM: + ALOGE(" GL_INVALID_ENUM"); + break; + case GL_INVALID_VALUE: + ALOGE(" GL_INVALID_VALUE"); + break; + case GL_INVALID_OPERATION: + ALOGE(" GL_INVALID_OPERATION"); + break; + case GL_OUT_OF_MEMORY: + ALOGE(" Out of memory!"); + break; + } } - } #endif + #if DEBUG_MEMORY_USAGE - mCaches.dumpMemoryUsage(); -#else - if (mCaches.getDebugLevel() & kDebugMemory) { mCaches.dumpMemoryUsage(); - } +#else + if (mCaches.getDebugLevel() & kDebugMemory) { + mCaches.dumpMemoryUsage(); + } #endif + } } void OpenGLRenderer::interrupt() { @@ -393,6 +398,75 @@ status_t OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) { } /////////////////////////////////////////////////////////////////////////////// +// Layers +/////////////////////////////////////////////////////////////////////////////// + +bool OpenGLRenderer::updateLayer(Layer* layer, bool inFrame) { + if (layer->deferredUpdateScheduled && layer->renderer && layer->displayList) { + OpenGLRenderer* renderer = layer->renderer; + Rect& dirty = layer->dirtyRect; + + if (inFrame) endTiling(); + + renderer->setViewport(layer->layer.getWidth(), layer->layer.getHeight()); + renderer->prepareDirty(dirty.left, dirty.top, dirty.right, dirty.bottom, !layer->isBlend()); + renderer->drawDisplayList(layer->displayList, dirty, DisplayList::kReplayFlag_ClipChildren); + renderer->finish(); + + if (inFrame) { + resumeAfterLayer(); + startTiling(mSnapshot); + } + + dirty.setEmpty(); + layer->deferredUpdateScheduled = false; + layer->renderer = NULL; + layer->displayList = NULL; + + return true; + } + + return false; +} + +void OpenGLRenderer::updateLayers() { + int count = mLayerUpdates.size(); + if (count > 0) { + startMark("Layer Updates"); + + // Note: it is very important to update the layers in reverse order + for (int i = count - 1; i >= 0; i--) { + Layer* layer = mLayerUpdates.itemAt(i); + updateLayer(layer, false); + mCaches.resourceCache.decrementRefcount(layer); + } + mLayerUpdates.clear(); + + glBindFramebuffer(GL_FRAMEBUFFER, getTargetFbo()); + endMark(); + } +} + +void OpenGLRenderer::pushLayerUpdate(Layer* layer) { + if (layer) { + mLayerUpdates.push_back(layer); + mCaches.resourceCache.incrementRefcount(layer); + } +} + +void OpenGLRenderer::clearLayerUpdates() { + size_t count = mLayerUpdates.size(); + if (count > 0) { + mCaches.resourceCache.lock(); + for (size_t i = 0; i < count; i++) { + mCaches.resourceCache.decrementRefcountLocked(mLayerUpdates.itemAt(i)); + } + mCaches.resourceCache.unlock(); + mLayerUpdates.clear(); + } +} + +/////////////////////////////////////////////////////////////////////////////// // State management /////////////////////////////////////////////////////////////////////////////// @@ -2629,25 +2703,7 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* pain } bool debugLayerUpdate = false; - if (layer->deferredUpdateScheduled && layer->renderer && layer->displayList) { - OpenGLRenderer* renderer = layer->renderer; - Rect& dirty = layer->dirtyRect; - - endTiling(); - - renderer->setViewport(layer->layer.getWidth(), layer->layer.getHeight()); - renderer->prepareDirty(dirty.left, dirty.top, dirty.right, dirty.bottom, !layer->isBlend()); - renderer->drawDisplayList(layer->displayList, dirty, DisplayList::kReplayFlag_ClipChildren); - renderer->finish(); - - resumeAfterLayer(); - startTiling(mSnapshot); - - dirty.setEmpty(); - layer->deferredUpdateScheduled = false; - layer->renderer = NULL; - layer->displayList = NULL; - + if (updateLayer(layer, true)) { debugLayerUpdate = mCaches.debugLayersUpdates; } diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index 4bbdde1..3e34336 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -132,6 +132,9 @@ public: ANDROID_API void attachFunctor(Functor* functor); virtual status_t callDrawGLFunction(Functor* functor, Rect& dirty); + ANDROID_API void pushLayerUpdate(Layer* layer); + ANDROID_API void clearLayerUpdates(); + ANDROID_API int getSaveCount() const; virtual int save(int flags); virtual void restore(); @@ -339,6 +342,13 @@ protected: return resultMode; } + /** + * Set to true to suppress error checks at the end of a frame. + */ + virtual bool suppressErrorChecks() { + return false; + } + private: /** * Ensures the state of the renderer is the same as the state of @@ -720,6 +730,9 @@ private: void finishDrawTexture(); void accountForClear(SkXfermode::Mode mode); + bool updateLayer(Layer* layer, bool inFrame); + void updateLayers(); + /** * Renders the specified region as a series of rectangles. This method * is used for debugging only. @@ -780,6 +793,8 @@ private: Vector mLayers; // List of functors to invoke after a frame is drawn SortedVector mFunctors; + // List of layers to update at the beginning of a frame + Vector mLayerUpdates; // Indentity matrix const mat4 mIdentity; -- cgit v1.1