summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/view/HardwareRenderer.java3
-rw-r--r--libs/hwui/DeferredDisplayList.h4
-rw-r--r--libs/hwui/Layer.cpp47
-rw-r--r--libs/hwui/Layer.h11
-rw-r--r--libs/hwui/LayerRenderer.cpp8
-rw-r--r--libs/hwui/OpenGLRenderer.cpp121
-rw-r--r--libs/hwui/OpenGLRenderer.h18
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