diff options
-rw-r--r-- | core/java/android/view/HardwareRenderer.java | 3 | ||||
-rw-r--r-- | libs/hwui/DeferredDisplayList.h | 4 | ||||
-rw-r--r-- | libs/hwui/Layer.cpp | 47 | ||||
-rw-r--r-- | libs/hwui/Layer.h | 11 | ||||
-rw-r--r-- | libs/hwui/LayerRenderer.cpp | 8 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.cpp | 121 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.h | 18 |
7 files changed, 181 insertions, 31 deletions
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java index e086f5a3586c..7918823bf583 100644 --- a/core/java/android/view/HardwareRenderer.java +++ b/core/java/android/view/HardwareRenderer.java @@ -428,6 +428,8 @@ public abstract class HardwareRenderer { interface HardwareDrawCallbacks { /** * Invoked before a view is drawn by a hardware renderer. + * This method can be used to apply transformations to the + * canvas but no drawing command should be issued. * * @param canvas The Canvas used to render the view. */ @@ -435,6 +437,7 @@ public abstract class HardwareRenderer { /** * Invoked after a view is drawn by a hardware renderer. + * It is safe to invoke drawing commands from this method. * * @param canvas The Canvas used to render the view. */ diff --git a/libs/hwui/DeferredDisplayList.h b/libs/hwui/DeferredDisplayList.h index cb9da8f59b19..2afc8c16fc19 100644 --- a/libs/hwui/DeferredDisplayList.h +++ b/libs/hwui/DeferredDisplayList.h @@ -52,6 +52,8 @@ public: kOpBatch_Count, // Add other batch ids before this }; + void clear(); + bool isEmpty() { return mBatches.isEmpty(); } /** @@ -78,8 +80,6 @@ private: */ void resetBatchingState(); - void clear(); - void storeStateOpBarrier(OpenGLRenderer& renderer, StateOp* op); void storeRestoreToCountBarrier(int newSaveCount); diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp index 1899002004c4..2998535c9916 100644 --- a/libs/hwui/Layer.cpp +++ b/libs/hwui/Layer.cpp @@ -18,6 +18,8 @@ #include <utils/Log.h> +#include "DisplayList.h" +#include "DeferredDisplayList.h" #include "Layer.h" #include "LayerRenderer.h" #include "OpenGLRenderer.h" @@ -43,15 +45,18 @@ Layer::Layer(const uint32_t layerWidth, const uint32_t layerHeight) { fbo = 0; stencil = NULL; debugDrawUpdate = false; + deferredList = NULL; Caches::getInstance().resourceCache.incrementRefcount(this); } Layer::~Layer() { - if (mesh) delete mesh; - if (meshIndices) delete meshIndices; if (colorFilter) Caches::getInstance().resourceCache.decrementRefcount(colorFilter); removeFbo(); deleteTexture(); + + delete[] mesh; + delete[] meshIndices; + delete deferredList; } uint32_t Layer::computeIdealWidth(uint32_t layerWidth) { @@ -133,5 +138,43 @@ void Layer::setColorFilter(SkiaColorFilter* filter) { } } +void Layer::defer() { + if (!deferredList) { + deferredList = new DeferredDisplayList; + } + DeferStateStruct deferredState(*deferredList, *renderer, + DisplayList::kReplayFlag_ClipChildren); + + const float width = layer.getWidth(); + const float height = layer.getHeight(); + + if (dirtyRect.isEmpty() || (dirtyRect.left <= 0 && dirtyRect.top <= 0 && + dirtyRect.right >= width && dirtyRect.bottom >= height)) { + dirtyRect.set(0, 0, width, height); + } + + renderer->initViewport(width, height); + renderer->setupFrameState(dirtyRect.left, dirtyRect.top, + dirtyRect.right, dirtyRect.bottom, !isBlend()); + + displayList->defer(deferredState, 0); +} + +void Layer::flush() { + if (deferredList && !deferredList->isEmpty()) { + renderer->setViewport(layer.getWidth(), layer.getHeight()); + renderer->prepareDirty(dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom, + !isBlend()); + + deferredList->flush(*renderer, dirtyRect); + + renderer->finish(); + renderer = NULL; + + dirtyRect.setEmpty(); + deferredList->clear(); + } +} + }; // namespace uirenderer }; // namespace android diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h index ccf1da5539aa..0e00191d8654 100644 --- a/libs/hwui/Layer.h +++ b/libs/hwui/Layer.h @@ -42,6 +42,8 @@ namespace uirenderer { // Forward declarations class OpenGLRenderer; class DisplayList; +class DeferredDisplayList; +class DeferStateStruct; /** * A layer has dimensions and is backed by an OpenGL texture or FBO. @@ -271,6 +273,9 @@ struct Layer { return transform; } + void defer(); + void flush(); + /** * Bounds of the layer. */ @@ -379,6 +384,12 @@ private: */ mat4 transform; + /** + * Used to defer display lists when the layer is updated with a + * display list. + */ + DeferredDisplayList* deferredList; + }; // struct Layer }; // namespace uirenderer diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp index 9aa961587ce6..bb0228674581 100644 --- a/libs/hwui/LayerRenderer.cpp +++ b/libs/hwui/LayerRenderer.cpp @@ -129,8 +129,8 @@ Region* LayerRenderer::getRegion() const { void LayerRenderer::generateMesh() { if (mLayer->region.isRect() || mLayer->region.isEmpty()) { if (mLayer->mesh) { - delete mLayer->mesh; - delete mLayer->meshIndices; + delete[] mLayer->mesh; + delete[] mLayer->meshIndices; mLayer->mesh = NULL; mLayer->meshIndices = NULL; @@ -153,8 +153,8 @@ void LayerRenderer::generateMesh() { GLsizei elementCount = count * 6; if (mLayer->mesh && mLayer->meshElementCount < elementCount) { - delete mLayer->mesh; - delete mLayer->meshIndices; + delete[] mLayer->mesh; + delete[] mLayer->meshIndices; mLayer->mesh = NULL; mLayer->meshIndices = NULL; diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 2cf7183360d1..1c36a23fb86c 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -120,6 +120,7 @@ OpenGLRenderer::OpenGLRenderer(): memcpy(mMeshVertices, gMeshVertices, sizeof(gMeshVertices)); mFirstSnapshot = new Snapshot; + mFrameStarted = false; mScissorOptimizationDisabled = false; } @@ -179,14 +180,11 @@ void OpenGLRenderer::initViewport(int width, int height) { mFirstSnapshot->viewport.set(0, 0, width, height); } -status_t OpenGLRenderer::prepare(bool opaque) { - return prepareDirty(0.0f, 0.0f, mWidth, mHeight, opaque); -} - -status_t OpenGLRenderer::prepareDirty(float left, float top, +void OpenGLRenderer::setupFrameState(float left, float top, float right, float bottom, bool opaque) { mCaches.clearGarbage(); + mOpaque = opaque; mSnapshot = new Snapshot(mFirstSnapshot, SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); mSnapshot->fbo = getTargetFbo(); @@ -194,13 +192,17 @@ status_t OpenGLRenderer::prepareDirty(float left, float top, mSnapshot->setClip(left, top, right, bottom); mTilingClip.set(left, top, right, bottom); - mDirtyClip = true; +} - updateLayers(); +status_t OpenGLRenderer::startFrame() { + if (mFrameStarted) return DrawGlInfo::kStatusDone; + mFrameStarted = true; - discardFramebuffer(left, top, right, bottom); + mDirtyClip = true; + + discardFramebuffer(mTilingClip.left, mTilingClip.top, mTilingClip.right, mTilingClip.bottom); - syncState(); + glViewport(0, 0, mWidth, mHeight); // Functors break the tiling extension in pretty spectacular ways // This ensures we don't use tiling when a functor is going to be @@ -211,7 +213,30 @@ status_t OpenGLRenderer::prepareDirty(float left, float top, debugOverdraw(true, true); - return clear(left, top, right, bottom, opaque); + return clear(mTilingClip.left, mTilingClip.top, + mTilingClip.right, mTilingClip.bottom, mOpaque); +} + +status_t OpenGLRenderer::prepare(bool opaque) { + return prepareDirty(0.0f, 0.0f, mWidth, mHeight, opaque); +} + +status_t OpenGLRenderer::prepareDirty(float left, float top, + float right, float bottom, bool opaque) { + setupFrameState(left, top, right, bottom, opaque); + + // Layer renderers will start the frame immediately + // The framebuffer renderer will first defer the display list + // for each layer and wait until the first drawing command + // to start the frame + if (mSnapshot->fbo == 0) { + syncState(); + updateLayers(); + } else { + return startFrame(); + } + + return DrawGlInfo::kStatusDone; } void OpenGLRenderer::discardFramebuffer(float left, float top, float right, float bottom) { @@ -241,8 +266,6 @@ status_t OpenGLRenderer::clear(float left, float top, float right, float bottom, } void OpenGLRenderer::syncState() { - glViewport(0, 0, mWidth, mHeight); - if (mCaches.blend) { glEnable(GL_BLEND); } else { @@ -312,6 +335,8 @@ void OpenGLRenderer::finish() { } #endif } + + mFrameStarted = false; } void OpenGLRenderer::interrupt() { @@ -503,8 +528,8 @@ void OpenGLRenderer::renderOverdraw() { /////////////////////////////////////////////////////////////////////////////// bool OpenGLRenderer::updateLayer(Layer* layer, bool inFrame) { - if (layer->deferredUpdateScheduled && layer->renderer && layer->displayList) { - OpenGLRenderer* renderer = layer->renderer; + if (layer->deferredUpdateScheduled && layer->renderer && + layer->displayList && layer->displayList->isRenderable()) { Rect& dirty = layer->dirtyRect; if (inFrame) { @@ -512,19 +537,29 @@ bool OpenGLRenderer::updateLayer(Layer* layer, bool inFrame) { debugOverdraw(false, false); } - 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 (CC_UNLIKELY(inFrame || mCaches.drawDeferDisabled)) { + OpenGLRenderer* renderer = layer->renderer; + 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(); + } else { + layer->defer(); + } if (inFrame) { resumeAfterLayer(); startTiling(mSnapshot); } - dirty.setEmpty(); + if (CC_UNLIKELY(inFrame || mCaches.drawDeferDisabled)) { + dirty.setEmpty(); + layer->renderer = NULL; + } + layer->deferredUpdateScheduled = false; - layer->renderer = NULL; layer->displayList = NULL; layer->debugDrawUpdate = mCaches.debugLayersUpdates; @@ -535,19 +570,54 @@ bool OpenGLRenderer::updateLayer(Layer* layer, bool inFrame) { } void OpenGLRenderer::updateLayers() { + // If draw deferring is enabled this method will simply defer + // the display list of each individual layer. The layers remain + // in the layer updates list which will be cleared by flushLayers(). int count = mLayerUpdates.size(); if (count > 0) { - startMark("Layer Updates"); + if (CC_UNLIKELY(mCaches.drawDeferDisabled)) { + startMark("Layer Updates"); + } else { + startMark("Defer 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); + if (CC_UNLIKELY(mCaches.drawDeferDisabled)) { + mCaches.resourceCache.decrementRefcount(layer); + } } - mLayerUpdates.clear(); + if (CC_UNLIKELY(mCaches.drawDeferDisabled)) { + mLayerUpdates.clear(); + glBindFramebuffer(GL_FRAMEBUFFER, getTargetFbo()); + } + endMark(); + } +} + +void OpenGLRenderer::flushLayers() { + int count = mLayerUpdates.size(); + if (count > 0) { + startMark("Apply Layer Updates"); + char layerName[12]; + + // Note: it is very important to update the layers in reverse order + for (int i = count - 1; i >= 0; i--) { + sprintf(layerName, "Layer #%d", i); + startMark(layerName); { + Layer* layer = mLayerUpdates.itemAt(i); + layer->flush(); + mCaches.resourceCache.decrementRefcount(layer); + } + endMark(); + } + + mLayerUpdates.clear(); glBindFramebuffer(GL_FRAMEBUFFER, getTargetFbo()); + endMark(); } } @@ -1832,6 +1902,7 @@ status_t OpenGLRenderer::drawDisplayList(DisplayList* displayList, Rect& dirty, // will be performed by the display list itself if (displayList && displayList->isRenderable()) { if (CC_UNLIKELY(mCaches.drawDeferDisabled)) { + startFrame(); ReplayStateStruct replayStruct(*this, dirty, replayFlags); displayList->replay(replayStruct, 0); return replayStruct.mDrawGlStatus; @@ -1840,6 +1911,10 @@ status_t OpenGLRenderer::drawDisplayList(DisplayList* displayList, Rect& dirty, DeferredDisplayList deferredList; DeferStateStruct deferStruct(deferredList, *this, replayFlags); displayList->defer(deferStruct, 0); + + flushLayers(); + startFrame(); + return deferredList.flush(*this, dirty); } diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index 7bb93957bc03..31dc9c8bdf43 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -362,6 +362,18 @@ protected: void initViewport(int width, int height); /** + * Perform the setup specific to a frame. This method does not + * issue any OpenGL commands. + */ + void setupFrameState(float left, float top, float right, float bottom, bool opaque); + + /** + * Indicates the start of rendering. This method will setup the + * initial OpenGL state (viewport, clearing the buffer, etc.) + */ + status_t startFrame(); + + /** * Clears the underlying surface if needed. */ virtual status_t clear(float left, float top, float right, float bottom, bool opaque); @@ -897,6 +909,7 @@ private: bool updateLayer(Layer* layer, bool inFrame); void updateLayers(); + void flushLayers(); /** * Renders the specified region as a series of rectangles. This method @@ -948,6 +961,10 @@ private: sp<Snapshot> mSnapshot; // State used to define the clipping region Rect mTilingClip; + // Is the target render surface opaque + bool mOpaque; + // Is a frame currently being rendered + bool mFrameStarted; // Used to draw textured quads TextureVertex mMeshVertices[4]; @@ -996,6 +1013,7 @@ private: String8 mName; friend class DisplayListRenderer; + friend class Layer; friend class TextSetupFunctor; }; // class OpenGLRenderer |