OSDN Git Service

Minimize state changes when updating layers
authorRomain Guy <romainguy@google.com>
Tue, 18 Sep 2012 22:40:58 +0000 (15:40 -0700)
committerRomain Guy <romainguy@google.com>
Tue, 18 Sep 2012 22:41:16 +0000 (15:41 -0700)
Change-Id: I407fcc80bd3178f9f09a3b379ceb7f7ce0749e08

libs/hwui/Caches.cpp
libs/hwui/LayerRenderer.cpp
libs/hwui/LayerRenderer.h
libs/hwui/OpenGLRenderer.cpp
libs/hwui/OpenGLRenderer.h

index 1de0f9d..edb4c10 100644 (file)
@@ -378,6 +378,9 @@ bool Caches::setScissor(GLint x, GLint y, GLint width, GLint height) {
     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;
index b57d806..5d59a4c 100644 (file)
@@ -37,6 +37,10 @@ LayerRenderer::LayerRenderer(Layer* layer): mLayer(layer) {
 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());
 
index 531aa5b..8d42f7f 100644 (file)
@@ -47,6 +47,7 @@ public:
     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();
 
index 4aefcba..11eb7a1 100644 (file)
@@ -144,6 +144,15 @@ bool OpenGLRenderer::isDeferred() {
 }
 
 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 @@ void OpenGLRenderer::setViewport(int width, int height) {
 
     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::interrupt() {
 
 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 @@ void OpenGLRenderer::resume() {
     dirtyClip();
 
     mCaches.activeTexture(0);
-    glBindFramebuffer(GL_FRAMEBUFFER, snapshot->fbo);
 
     mCaches.blend = true;
     glEnable(GL_BLEND);
@@ -269,6 +273,15 @@ void OpenGLRenderer::resume() {
     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 @@ bool OpenGLRenderer::quickRejectNoScissor(float left, float top, float right, fl
     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::drawPath(SkPath* path, SkPaint* paint) {
 }
 
 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;
     }
 
-    bool debugLayerUpdate = false;
+    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 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* pain
         debugLayerUpdate = mCaches.debugLayersUpdates;
     }
 
+    mCaches.setScissorEnabled(!clip.contains(transformed));
     mCaches.activeTexture(0);
 
     if (CC_LIKELY(!layer->region.isEmpty())) {
index 7f9405f..8dcd33f 100644 (file)
@@ -255,6 +255,17 @@ public:
 
 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 @@ private:
     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