Combine projection matrix, and viewport management

Merge management of ortho projection matrix with the viewport size,
since they should always be changed together.

Change-Id: Iccb8f30828f4fb7848999ac54852e7ed2d6f2eb1
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 2391e80..a4bce3a 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -57,9 +57,6 @@
 }
 
 void DisplayListRenderer::setViewport(int width, int height) {
-    // TODO: DisplayListRenderer shouldn't have a projection matrix, as it should never be used
-    mProjectionMatrix.loadOrtho(0, width, height, 0, -1, 1);
-
     initializeViewport(width, height);
 }
 
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 9606e58..de2fcf4 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -214,7 +214,7 @@
     DeferStateStruct deferredState(*deferredList, *renderer,
             RenderNode::kReplayFlag_ClipChildren);
 
-    renderer->initViewport(width, height);
+    renderer->initializeViewport(width, height);
     renderer->setupFrameState(dirtyRect.left, dirtyRect.top,
             dirtyRect.right, dirtyRect.bottom, !isBlend());
 
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index e0ac2ba..c82197c 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -40,7 +40,7 @@
 }
 
 void LayerRenderer::setViewport(int width, int height) {
-    initViewport(width, height);
+    initializeViewport(width, height);
 }
 
 status_t LayerRenderer::prepareDirty(float left, float top, float right, float bottom,
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 20b038d..4df97e6 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -162,7 +162,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 void OpenGLRenderer::setViewport(int width, int height) {
-    initViewport(width, height);
+    initializeViewport(width, height);
 
     glDisable(GL_DITHER);
     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
@@ -170,12 +170,6 @@
     glEnableVertexAttribArray(Program::kBindingPosition);
 }
 
-void OpenGLRenderer::initViewport(int width, int height) {
-    mProjectionMatrix.loadOrtho(0, width, height, 0, -1, 1);
-
-    initializeViewport(width, height);
-}
-
 void OpenGLRenderer::setupFrameState(float left, float top,
         float right, float bottom, bool opaque) {
     mCaches.clearGarbage();
@@ -244,7 +238,7 @@
 status_t OpenGLRenderer::clear(float left, float top, float right, float bottom, bool opaque) {
     if (!opaque || mCountOverdraw) {
         mCaches.enableScissor();
-        mCaches.setScissor(left, currentSnapshot()->height - bottom, right - left, bottom - top);
+        mCaches.setScissor(left, getViewportHeight() - bottom, right - left, bottom - top);
         glClear(GL_COLOR_BUFFER_BIT);
         return DrawGlInfo::kStatusDrew;
     }
@@ -270,7 +264,7 @@
             clip = &(snapshot->layer->clipRect);
         }
 
-        startTiling(*clip, snapshot->height, opaque);
+        startTiling(*clip, getViewportHeight(), opaque);
     }
 }
 
@@ -333,7 +327,7 @@
 
 void OpenGLRenderer::resume() {
     const Snapshot* snapshot = currentSnapshot();
-    glViewport(0, 0, snapshot->viewport.getWidth(), snapshot->viewport.getHeight());
+    glViewport(0, 0, getViewportWidth(), getViewportHeight());
     glBindFramebuffer(GL_FRAMEBUFFER, snapshot->fbo);
     debugOverdraw(true, false);
 
@@ -354,9 +348,8 @@
 }
 
 void OpenGLRenderer::resumeAfterLayer() {
-    const Snapshot* snapshot = currentSnapshot();
-    glViewport(0, 0, snapshot->viewport.getWidth(), snapshot->viewport.getHeight());
-    glBindFramebuffer(GL_FRAMEBUFFER, snapshot->fbo);
+    glViewport(0, 0, getViewportWidth(), getViewportHeight());
+    glBindFramebuffer(GL_FRAMEBUFFER, currentSnapshot()->fbo);
     debugOverdraw(true, false);
 
     mCaches.resetScissor();
@@ -381,8 +374,8 @@
     info.clipRight = clip.right;
     info.clipBottom = clip.bottom;
     info.isLayer = hasLayer();
-    info.width = currentSnapshot()->viewport.getWidth();
-    info.height = currentSnapshot()->height;
+    info.width = getViewportWidth();
+    info.height = getViewportHeight();
     currentTransform()->copyTo(&info.transform[0]);
 
     bool dirtyClip = mDirtyClip;
@@ -437,7 +430,7 @@
         const Rect* clip = &mTilingClip;
 
         mCaches.enableScissor();
-        mCaches.setScissor(clip->left, firstSnapshot()->height - clip->bottom,
+        mCaches.setScissor(clip->left, firstSnapshot()->getViewportHeight() - clip->bottom,
                 clip->right - clip->left, clip->bottom - clip->top);
 
         // 1x overdraw
@@ -621,14 +614,12 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 void OpenGLRenderer::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {
-    bool restoreOrtho = removed.flags & Snapshot::kFlagDirtyOrtho;
+    bool restoreViewport = removed.flags & Snapshot::kFlagIsFboLayer;
     bool restoreClip = removed.flags & Snapshot::kFlagClipSet;
     bool restoreLayer = removed.flags & Snapshot::kFlagIsLayer;
 
-    if (restoreOrtho) {
-        const Rect& r = restored.viewport;
-        glViewport(r.left, r.top, r.right, r.bottom);
-        mProjectionMatrix.load(removed.orthoMatrix); // TODO: should ortho be stored in 'restored'?
+    if (restoreViewport) {
+        glViewport(0, 0, getViewportWidth(), getViewportHeight());
     }
 
     if (restoreClip) {
@@ -671,7 +662,7 @@
         // When the layer is not an FBO, we may use glCopyTexImage so we
         // need to make sure the layer does not extend outside the bounds
         // of the framebuffer
-        if (!bounds.intersect(currentSnapshot()->previous->viewport)) {
+        if (!bounds.intersect(Rect(0, 0, getViewportWidth(), getViewportHeight()))) {
             bounds.setEmpty();
         } else if (fboLayer) {
             clip.set(bounds);
@@ -719,7 +710,7 @@
         if (!currentSnapshot()->isIgnored()) {
             mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
             mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
-            mSnapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
+            mSnapshot->initializeViewport(bounds.getWidth(), bounds.getHeight());
         }
     }
 
@@ -831,8 +822,9 @@
                 layer->setEmpty(false);
             }
 
-            glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bounds.left,
-                    mSnapshot->height - bounds.bottom, bounds.getWidth(), bounds.getHeight());
+            glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
+                    bounds.left, getViewportHeight() - bounds.bottom,
+                    bounds.getWidth(), bounds.getHeight());
 
             // Enqueue the buffer coordinates to clear the corresponding region later
             mLayers.push(new Rect(bounds));
@@ -847,14 +839,11 @@
     layer->setFbo(mCaches.fboCache.get());
 
     mSnapshot->region = &mSnapshot->layer->region;
-    mSnapshot->flags |= Snapshot::kFlagFboTarget | Snapshot::kFlagIsFboLayer |
-            Snapshot::kFlagDirtyOrtho;
+    mSnapshot->flags |= Snapshot::kFlagFboTarget | Snapshot::kFlagIsFboLayer;
     mSnapshot->fbo = layer->getFbo();
     mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
     mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
-    mSnapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
-    mSnapshot->height = bounds.getHeight();
-    mSnapshot->orthoMatrix.load(mProjectionMatrix);
+    mSnapshot->initializeViewport(bounds.getWidth(), bounds.getHeight());
 
     endTiling();
     debugOverdraw(false, false);
@@ -884,7 +873,6 @@
     // Change the ortho projection
     glViewport(0, 0, bounds.getWidth(), bounds.getHeight());
 
-    mProjectionMatrix.loadOrtho(0.0f, bounds.getWidth(), bounds.getHeight(), 0.0f, -1.0f, 1.0f);
 
     return true;
 }
@@ -1419,7 +1407,7 @@
     Rect clip(*currentClipRect());
     clip.snapToPixelBoundaries();
 
-    if (mCaches.setScissor(clip.left, currentSnapshot()->height - clip.bottom,
+    if (mCaches.setScissor(clip.left, getViewportHeight() - clip.bottom,
             clip.getWidth(), clip.getHeight())) {
         mDirtyClip = false;
     }
@@ -1694,12 +1682,14 @@
     }
 
     bool dirty = right - left > 0.0f && bottom - top > 0.0f;
-    if (!ignoreTransform) {
-        mCaches.currentProgram->set(mProjectionMatrix, mModelViewMatrix, *currentTransform(), offset);
-        if (dirty && mTrackDirtyRegions) dirtyLayer(left, top, right, bottom, *currentTransform());
-    } else {
-        mCaches.currentProgram->set(mProjectionMatrix, mModelViewMatrix, mat4::identity(), offset);
-        if (dirty && mTrackDirtyRegions) dirtyLayer(left, top, right, bottom);
+    const Matrix4& transformMatrix = ignoreTransform ? Matrix4::identity() : *currentTransform();
+    mCaches.currentProgram->set(mSnapshot->getOrthoMatrix(), mModelViewMatrix, transformMatrix, offset);
+    if (dirty && mTrackDirtyRegions) {
+        if (!ignoreTransform) {
+            dirtyLayer(left, top, right, bottom, *currentTransform());
+        } else {
+            dirtyLayer(left, top, right, bottom);
+        }
     }
 }
 
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 4f7f01e..b58b817 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -254,8 +254,8 @@
         return mSnapshot->clipRegion->isEmpty();
     }
 
-    int getViewportWidth() { return currentSnapshot()->viewport.getWidth(); }
-    int getViewportHeight() { return currentSnapshot()->viewport.getHeight(); }
+    int getViewportWidth() { return currentSnapshot()->getViewportWidth(); }
+    int getViewportHeight() { return currentSnapshot()->getViewportHeight(); }
 
     /**
      * Scales the alpha on the current snapshot. This alpha value will be modulated
@@ -354,12 +354,6 @@
 
 protected:
     /**
-     * Computes the projection matrix, initialize the first snapshot
-     * and stores the dimensions of the render target.
-     */
-    void initViewport(int width, int height);
-
-    /**
      * Perform the setup specific to a frame. This method does not
      * issue any OpenGL commands.
      */
@@ -930,9 +924,6 @@
      */
     Texture* getTexture(const SkBitmap* bitmap);
 
-    // Ortho matrix used for projection in shaders
-    mat4 mProjectionMatrix;
-
     /**
      * Model-view matrix used to position/size objects
      *
diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
index 6bfa203..029b56d 100644
--- a/libs/hwui/Snapshot.cpp
+++ b/libs/hwui/Snapshot.cpp
@@ -34,7 +34,6 @@
         , fbo(0)
         , invisible(false)
         , empty(false)
-        , height(0)
         , alpha(1.0f) {
     transform = &mTransformRoot;
     clipRect = &mClipRectRoot;
@@ -53,9 +52,8 @@
         , fbo(s->fbo)
         , invisible(s->invisible)
         , empty(false)
-        , viewport(s->viewport)
-        , height(s->height)
-        , alpha(s->alpha) {
+        , alpha(s->alpha)
+        , mViewportData(s->mViewportData) {
 
     if (saveFlags & SkCanvas::kMatrix_SaveFlag) {
         mTransformRoot.load(*s->transform);
@@ -215,7 +213,7 @@
 
 void Snapshot::dump() const {
     ALOGD("Snapshot %p, flags %x, prev %p, height %d, ignored %d, hasComplexClip %d",
-            this, flags, previous.get(), height, isIgnored(), clipRegion && !clipRegion->isEmpty());
+            this, flags, previous.get(), getViewportHeight(), isIgnored(), clipRegion && !clipRegion->isEmpty());
     ALOGD("  ClipRect (at %p) %.1f %.1f %.1f %.1f",
             clipRect, clipRect->left, clipRect->top, clipRect->right, clipRect->bottom);
     ALOGD("  Transform (at %p):", transform);
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index 038aea8..e9ab1ff 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -65,17 +65,16 @@
          * Indicates that this snapshot is a special type of layer
          * backed by an FBO. This flag only makes sense when the
          * flag kFlagIsLayer is also set.
+         *
+         * Viewport has been modified to fit the new Fbo, and must be
+         * restored when this snapshot is restored.
          */
         kFlagIsFboLayer = 0x4,
         /**
-         * Indicates that this snapshot has changed the ortho matrix.
-         */
-        kFlagDirtyOrtho = 0x8,
-        /**
          * Indicates that this snapshot or an ancestor snapshot is
          * an FBO layer.
          */
-        kFlagFboTarget = 0x10
+        kFlagFboTarget = 0x8,
     };
 
     /**
@@ -125,6 +124,14 @@
      */
     void resetTransform(float x, float y, float z);
 
+    void initializeViewport(int width, int height) {
+        mViewportData.initialize(width, height);
+    }
+
+    int getViewportWidth() const { return mViewportData.mWidth; }
+    int getViewportHeight() const { return mViewportData.mHeight; }
+    const Matrix4& getOrthoMatrix() const { return mViewportData.mOrthoMatrix; }
+
     /**
      * Indicates whether this snapshot should be ignored. A snapshot
      * is typicalled ignored if its layer is invisible or empty.
@@ -173,21 +180,6 @@
     bool empty;
 
     /**
-     * Current viewport.
-     */
-    Rect viewport;
-
-    /**
-     * Height of the framebuffer the snapshot is rendering into.
-     */
-    int height;
-
-    /**
-     * Contains the previous ortho matrix.
-     */
-    mat4 orthoMatrix;
-
-    /**
      * Local transformation. Holds the current translation, scale and
      * rotation values.
      *
@@ -236,6 +228,27 @@
     void dump() const;
 
 private:
+    struct ViewportData {
+        ViewportData() : mWidth(0), mHeight() {}
+        void initialize(int width, int height) {
+            mWidth = width;
+            mHeight = height;
+            mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1);
+        }
+
+        /*
+         * Width and height of current viewport.
+         *
+         * The viewport is always defined to be (0, 0, width, height).
+         */
+        int mWidth;
+        int mHeight;
+        /**
+         * Contains the current orthographic, projection matrix.
+         */
+        mat4 mOrthoMatrix;
+    };
+
     void ensureClipRegion();
     void copyClipRectFromRegion();
 
@@ -246,6 +259,7 @@
     Rect mLocalClip; // don't use directly, call getLocalClip() which initializes this
 
     SkRegion mClipRegionRoot;
+    ViewportData mViewportData;
 
 }; // class Snapshot
 
diff --git a/libs/hwui/StatefulBaseRenderer.cpp b/libs/hwui/StatefulBaseRenderer.cpp
index 05f6cf8..aa83e20 100644
--- a/libs/hwui/StatefulBaseRenderer.cpp
+++ b/libs/hwui/StatefulBaseRenderer.cpp
@@ -38,9 +38,7 @@
 void StatefulBaseRenderer::initializeViewport(int width, int height) {
     mWidth = width;
     mHeight = height;
-
-    mFirstSnapshot->height = height;
-    mFirstSnapshot->viewport.set(0, 0, width, height);
+    mFirstSnapshot->initializeViewport(width, height);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/StatefulBaseRenderer.h b/libs/hwui/StatefulBaseRenderer.h
index 64354ac..9fbf2ca 100644
--- a/libs/hwui/StatefulBaseRenderer.h
+++ b/libs/hwui/StatefulBaseRenderer.h
@@ -46,6 +46,11 @@
     virtual status_t prepare(bool opaque) {
         return prepareDirty(0.0f, 0.0f, mWidth, mHeight, opaque);
     }
+
+    /**
+     * Initialize the first snapshot, computing the projection matrix,
+     * and stores the dimensions of the render target.
+     */
     void initializeViewport(int width, int height);
     void initializeSaveStack(float clipLeft, float clipTop, float clipRight, float clipBottom);