diff options
-rw-r--r-- | core/java/android/view/GLES20Canvas.java | 15 | ||||
-rw-r--r-- | core/java/android/view/GLES20RenderLayer.java | 2 | ||||
-rw-r--r-- | core/java/android/view/GLES20TextureLayer.java | 2 | ||||
-rw-r--r-- | core/java/android/view/HardwareCanvas.java | 16 | ||||
-rw-r--r-- | core/java/android/view/HardwareLayer.java | 2 | ||||
-rw-r--r-- | core/java/android/view/HardwareRenderer.java | 16 | ||||
-rw-r--r-- | core/java/android/view/View.java | 5 | ||||
-rw-r--r-- | core/java/android/view/ViewRootImpl.java | 6 | ||||
-rw-r--r-- | core/jni/android_view_GLES20Canvas.cpp | 12 | ||||
-rw-r--r-- | libs/hwui/LayerRenderer.cpp | 4 | ||||
-rw-r--r-- | libs/hwui/LayerRenderer.h | 10 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.cpp | 136 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.h | 15 |
13 files changed, 191 insertions, 50 deletions
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java index 032ff7b..c703aaf 100644 --- a/core/java/android/view/GLES20Canvas.java +++ b/core/java/android/view/GLES20Canvas.java @@ -147,7 +147,17 @@ class GLES20Canvas extends HardwareCanvas { /////////////////////////////////////////////////////////////////////////// // Hardware layers /////////////////////////////////////////////////////////////////////////// - + + @Override + void pushLayerUpdate(HardwareLayer layer) { + nPushLayerUpdate(mRenderer, ((GLES20RenderLayer) layer).mLayer); + } + + @Override + void clearLayerUpdates() { + nClearLayerUpdates(mRenderer); + } + static native int nCreateTextureLayer(boolean opaque, int[] layerInfo); static native int nCreateLayer(int width, int height, boolean isOpaque, int[] layerInfo); static native boolean nResizeLayer(int layerId, int width, int height, int[] layerInfo); @@ -163,6 +173,9 @@ class GLES20Canvas extends HardwareCanvas { int left, int top, int right, int bottom); static native boolean nCopyLayer(int layerId, int bitmap); + private static native void nClearLayerUpdates(int renderer); + private static native void nPushLayerUpdate(int renderer, int layer); + /////////////////////////////////////////////////////////////////////////// // Canvas management /////////////////////////////////////////////////////////////////////////// diff --git a/core/java/android/view/GLES20RenderLayer.java b/core/java/android/view/GLES20RenderLayer.java index fcfc8e1..44d4719 100644 --- a/core/java/android/view/GLES20RenderLayer.java +++ b/core/java/android/view/GLES20RenderLayer.java @@ -110,7 +110,7 @@ class GLES20RenderLayer extends GLES20Layer { } @Override - void redraw(DisplayList displayList, Rect dirtyRect) { + void redrawLater(DisplayList displayList, Rect dirtyRect) { GLES20Canvas.nUpdateRenderLayer(mLayer, mCanvas.getRenderer(), ((GLES20DisplayList) displayList).getNativeDisplayList(), dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom); diff --git a/core/java/android/view/GLES20TextureLayer.java b/core/java/android/view/GLES20TextureLayer.java index b0ee2aa..797c734 100644 --- a/core/java/android/view/GLES20TextureLayer.java +++ b/core/java/android/view/GLES20TextureLayer.java @@ -98,6 +98,6 @@ class GLES20TextureLayer extends GLES20Layer { } @Override - void redraw(DisplayList displayList, Rect dirtyRect) { + void redrawLater(DisplayList displayList, Rect dirtyRect) { } } diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java index 777552a..eeae3ed 100644 --- a/core/java/android/view/HardwareCanvas.java +++ b/core/java/android/view/HardwareCanvas.java @@ -132,4 +132,20 @@ public abstract class HardwareCanvas extends Canvas { * @see #detachFunctor(int) */ abstract void attachFunctor(int functor); + + /** + * Indicates that the specified layer must be updated as soon as possible. + * + * @param layer The layer to update + * + * @see #clearLayerUpdates() + */ + abstract void pushLayerUpdate(HardwareLayer layer); + + /** + * Removes all enqueued layer updates. + * + * @see #pushLayerUpdate(HardwareLayer) + */ + abstract void clearLayerUpdates(); } diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java index d798e73..d6868ca 100644 --- a/core/java/android/view/HardwareLayer.java +++ b/core/java/android/view/HardwareLayer.java @@ -203,5 +203,5 @@ abstract class HardwareLayer { * execute in this layer * @param dirtyRect The dirty region of the layer that needs to be redrawn */ - abstract void redraw(DisplayList displayList, Rect dirtyRect); + abstract void redrawLater(DisplayList displayList, Rect dirtyRect); } diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java index ef5dc56..e0e8de3 100644 --- a/core/java/android/view/HardwareRenderer.java +++ b/core/java/android/view/HardwareRenderer.java @@ -370,6 +370,14 @@ public abstract class HardwareRenderer { private static native void nDisableVsync(); /** + * Indicates that the specified hardware layer needs to be updated + * as soon as possible. + * + * @param layer The hardware layer that needs an update + */ + abstract void pushLayerUpdate(HardwareLayer layer); + + /** * Interface used to receive callbacks whenever a view is drawn by * a hardware renderer instance. */ @@ -1154,8 +1162,9 @@ public abstract class HardwareRenderer { getDisplayListStartTime = System.nanoTime(); } - DisplayList displayList; + canvas.clearLayerUpdates(); + DisplayList displayList; Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList"); try { displayList = view.getDisplayList(); @@ -1452,6 +1461,11 @@ public abstract class HardwareRenderer { } @Override + void pushLayerUpdate(HardwareLayer layer) { + mGlCanvas.pushLayerUpdate(layer); + } + + @Override public DisplayList createDisplayList(String name) { return new GLES20DisplayList(name); } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 13de538..31bbc6a 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -12286,9 +12286,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (!mHardwareLayer.isValid()) { return null; } + mHardwareLayer.setLayerPaint(mLayerPaint); + mHardwareLayer.redrawLater(getHardwareLayerDisplayList(mHardwareLayer), mLocalDirtyRect); + ViewRootImpl viewRoot = getViewRootImpl(); + if (viewRoot != null) viewRoot.pushHardwareLayerUpdate(mHardwareLayer); - mHardwareLayer.redraw(getHardwareLayerDisplayList(mHardwareLayer), mLocalDirtyRect); mLocalDirtyRect.setEmpty(); } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 27fd374..6bb8697 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -653,6 +653,12 @@ public final class ViewRootImpl implements ViewParent, } } + void pushHardwareLayerUpdate(HardwareLayer layer) { + if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) { + mAttachInfo.mHardwareRenderer.pushLayerUpdate(layer); + } + } + public boolean attachFunctor(int functor) { //noinspection SimplifiableIfStatement if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) { diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp index 2ff886e..b91eb28 100644 --- a/core/jni/android_view_GLES20Canvas.cpp +++ b/core/jni/android_view_GLES20Canvas.cpp @@ -843,6 +843,16 @@ static jboolean android_view_GLES20Canvas_copyLayer(JNIEnv* env, jobject clazz, return LayerRenderer::copyLayer(layer, bitmap); } +static void android_view_GLES20Canvas_pushLayerUpdate(JNIEnv* env, jobject clazz, + OpenGLRenderer* renderer, Layer* layer) { + renderer->pushLayerUpdate(layer); +} + +static void android_view_GLES20Canvas_clearLayerUpdates(JNIEnv* env, jobject clazz, + OpenGLRenderer* renderer) { + renderer->clearLayerUpdates(); +} + #endif // USE_OPENGL_RENDERER // ---------------------------------------------------------------------------- @@ -1006,6 +1016,8 @@ static JNINativeMethod gMethods[] = { { "nDestroyLayerDeferred", "(I)V", (void*) android_view_GLES20Canvas_destroyLayerDeferred }, { "nDrawLayer", "(IIFFI)V", (void*) android_view_GLES20Canvas_drawLayer }, { "nCopyLayer", "(II)Z", (void*) android_view_GLES20Canvas_copyLayer }, + { "nClearLayerUpdates", "(I)V", (void*) android_view_GLES20Canvas_clearLayerUpdates }, + { "nPushLayerUpdate", "(II)V", (void*) android_view_GLES20Canvas_pushLayerUpdate }, { "nSetTextureLayerTransform", "(II)V", (void*) android_view_GLES20Canvas_setTextureLayerTransform }, 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<Rect*> mLayers; // List of functors to invoke after a frame is drawn SortedVector<Functor*> mFunctors; + // List of layers to update at the beginning of a frame + Vector<Layer*> mLayerUpdates; // Indentity matrix const mat4 mIdentity; |