Minimize state changes when updating layers
Change-Id: I407fcc80bd3178f9f09a3b379ceb7f7ce0749e08
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 1de0f9d..edb4c10 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -378,6 +378,9 @@
if (scissorEnabled && (x != mScissorX || y != mScissorY ||
width != mScissorWidth || height != mScissorHeight)) {
+ if (x < 0) x = 0;
+ if (y < 0) y = 0;
+
glScissor(x, y, width, height);
mScissorX = x;
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index b57d806..5d59a4c 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -37,6 +37,10 @@
LayerRenderer::~LayerRenderer() {
}
+void LayerRenderer::setViewport(int width, int height) {
+ initViewport(width, height);
+}
+
int LayerRenderer::prepareDirty(float left, float top, float right, float bottom, bool opaque) {
LAYER_RENDERER_LOGD("Rendering into layer, fbo = %d", mLayer->getFbo());
diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h
index 531aa5b..8d42f7f 100644
--- a/libs/hwui/LayerRenderer.h
+++ b/libs/hwui/LayerRenderer.h
@@ -47,6 +47,7 @@
ANDROID_API LayerRenderer(Layer* layer);
virtual ~LayerRenderer();
+ virtual void setViewport(int width, int height);
virtual int prepareDirty(float left, float top, float right, float bottom, bool opaque);
virtual void finish();
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 4aefcba..11eb7a1 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -144,6 +144,15 @@
}
void OpenGLRenderer::setViewport(int width, int height) {
+ initViewport(width, height);
+
+ glDisable(GL_DITHER);
+ glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+
+ glEnableVertexAttribArray(Program::kBindingPosition);
+}
+
+void OpenGLRenderer::initViewport(int width, int height) {
mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1);
mWidth = width;
@@ -151,11 +160,6 @@
mFirstSnapshot->height = height;
mFirstSnapshot->viewport.set(0, 0, width, height);
-
- glDisable(GL_DITHER);
- glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
-
- glEnableVertexAttribArray(Program::kBindingPosition);
}
int OpenGLRenderer::prepare(bool opaque) {
@@ -251,8 +255,9 @@
void OpenGLRenderer::resume() {
sp<Snapshot> snapshot = (mSnapshot != NULL) ? mSnapshot : mFirstSnapshot;
-
glViewport(0, 0, snapshot->viewport.getWidth(), snapshot->viewport.getHeight());
+ glBindFramebuffer(GL_FRAMEBUFFER, snapshot->fbo);
+
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
mCaches.scissorEnabled = glIsEnabled(GL_SCISSOR_TEST);
@@ -261,7 +266,6 @@
dirtyClip();
mCaches.activeTexture(0);
- glBindFramebuffer(GL_FRAMEBUFFER, snapshot->fbo);
mCaches.blend = true;
glEnable(GL_BLEND);
@@ -269,6 +273,15 @@
glBlendEquation(GL_FUNC_ADD);
}
+void OpenGLRenderer::resumeAfterLayer() {
+ sp<Snapshot> snapshot = (mSnapshot != NULL) ? mSnapshot : mFirstSnapshot;
+ glViewport(0, 0, snapshot->viewport.getWidth(), snapshot->viewport.getHeight());
+ glBindFramebuffer(GL_FRAMEBUFFER, snapshot->fbo);
+
+ mCaches.resetScissor();
+ dirtyClip();
+}
+
void OpenGLRenderer::detachFunctor(Functor* functor) {
mFunctors.remove(functor);
}
@@ -1081,6 +1094,22 @@
return !clipRect.intersects(r);
}
+bool OpenGLRenderer::quickRejectNoScissor(float left, float top, float right, float bottom,
+ Rect& transformed, Rect& clip) {
+ if (mSnapshot->isIgnored()) {
+ return true;
+ }
+
+ transformed.set(left, top, right, bottom);
+ mSnapshot->transform->mapRect(transformed);
+ transformed.snapToPixelBoundaries();
+
+ clip.set(*mSnapshot->clipRect);
+ clip.snapToPixelBoundaries();
+
+ return !clip.intersects(transformed);
+}
+
bool OpenGLRenderer::quickReject(float left, float top, float right, float bottom) {
if (mSnapshot->isIgnored()) {
return true;
@@ -2574,22 +2603,30 @@
}
status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* paint) {
- if (!layer || quickReject(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight())) {
+ if (!layer) {
+ return DrawGlInfo::kStatusDone;
+ }
+
+ Rect transformed;
+ Rect clip;
+ const bool rejected = quickRejectNoScissor(x, y,
+ x + layer->layer.getWidth(), y + layer->layer.getHeight(), transformed, clip);
+
+ if (rejected) {
return DrawGlInfo::kStatusDone;
}
bool debugLayerUpdate = false;
-
if (layer->deferredUpdateScheduled && layer->renderer && layer->displayList) {
OpenGLRenderer* renderer = layer->renderer;
Rect& dirty = layer->dirtyRect;
- interrupt();
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();
- resume();
+
+ resumeAfterLayer();
dirty.setEmpty();
layer->deferredUpdateScheduled = false;
@@ -2599,6 +2636,7 @@
debugLayerUpdate = mCaches.debugLayersUpdates;
}
+ mCaches.setScissorEnabled(!clip.contains(transformed));
mCaches.activeTexture(0);
if (CC_LIKELY(!layer->region.isEmpty())) {
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 7f9405f..8dcd33f 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -255,6 +255,17 @@
protected:
/**
+ * Computes the projection matrix, initialize the first snapshot
+ * and stores the dimensions of the render target.
+ */
+ void initViewport(int width, int height);
+
+ /**
+ * Call this method after updating a layer during a drawing pass.
+ */
+ void resumeAfterLayer();
+
+ /**
* Compose the layer defined in the current snapshot with the layer
* defined by the previous snapshot.
*
@@ -360,6 +371,13 @@
void setScissorFromClip();
/**
+ * Performs a quick reject but does not affect the scissor. Returns
+ * the transformed rect to test and the current clip.
+ */
+ bool quickRejectNoScissor(float left, float top, float right, float bottom,
+ Rect& transformed, Rect& clip);
+
+ /**
* Creates a new layer stored in the specified snapshot.
*
* @param snapshot The snapshot associated with the new layer