Add support for QCOM_tiled_rendering
Bug #7186819

This optional OpenGL extension can be used by tiled renderers to optimize
copies from main memory to tiles memory.

Change-Id: Id4a5d64e61ad17f50e773e8104b9bf584bb65077
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index edb4c10..b149bb9 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -429,13 +429,13 @@
 
 void Caches::startTiling(GLuint x, GLuint y, GLuint width, GLuint height, bool opaque) {
     if (extensions.hasTiledRendering()) {
-
+        glStartTilingQCOM(x, y, width, height, GL_COLOR_BUFFER_BIT0_QCOM);
     }
 }
 
 void Caches::endTiling() {
     if (extensions.hasTiledRendering()) {
-
+        glEndTilingQCOM(GL_COLOR_BUFFER_BIT0_QCOM);
     }
 }
 
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 11eb7a1..9b9ca12 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -175,7 +175,7 @@
     mSaveCount = 1;
 
     mSnapshot->setClip(left, top, right, bottom);
-    mDirtyClip = opaque;
+    mDirtyClip = mOpaqueFrame = opaque;
 
     // If we know that we are going to redraw the entire framebuffer,
     // perform a discard to let the driver know we don't need to preserve
@@ -188,6 +188,9 @@
 
     syncState();
 
+    mTilingSnapshot = mSnapshot;
+    startTiling();
+
     if (!opaque) {
         mCaches.enableScissor();
         mCaches.setScissor(left, mSnapshot->height - bottom, right - left, bottom - top);
@@ -210,7 +213,30 @@
     }
 }
 
+void OpenGLRenderer::startTiling() {
+    startTiling(mTilingSnapshot);
+}
+
+void OpenGLRenderer::startTiling(const sp<Snapshot>& s) {
+    bool opaque = mOpaqueFrame;
+    Rect* clip = mTilingSnapshot->clipRect;
+
+    if (s->flags & Snapshot::kFlagIsFboLayer) {
+        opaque = !s->layer->isBlend();
+        clip = s->clipRect;
+    }
+
+    mCaches.startTiling(clip->left, s->height - clip->bottom,
+            clip->right - clip->left, clip->bottom - clip->top, opaque);
+}
+
+void OpenGLRenderer::endTiling() {
+    mCaches.endTiling();
+}
+
 void OpenGLRenderer::finish() {
+    endTiling();
+
 #if DEBUG_OPENGL
     GLenum status = GL_NO_ERROR;
     while ((status = glGetError()) != GL_NO_ERROR) {
@@ -637,6 +663,7 @@
     mSnapshot->flags |= Snapshot::kFlagDirtyOrtho;
     mSnapshot->orthoMatrix.load(mOrthoMatrix);
 
+    endTiling();
     // Bind texture to FBO
     glBindFramebuffer(GL_FRAMEBUFFER, layer->getFbo());
     layer->bindTexture();
@@ -650,18 +677,7 @@
     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
             layer->getTexture(), 0);
 
-#if DEBUG_LAYERS_AS_REGIONS
-    GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
-    if (status != GL_FRAMEBUFFER_COMPLETE) {
-        ALOGE("Framebuffer incomplete (GL error code 0x%x)", status);
-
-        glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
-
-        Caches::getInstance().resourceCache.decrementRefcount(layer);
-
-        return false;
-    }
-#endif
+    startTiling(mSnapshot);
 
     // Clear the FBO, expand the clear region by 1 to get nice bilinear filtering
     mCaches.enableScissor();
@@ -690,11 +706,14 @@
     const bool fboLayer = current->flags & Snapshot::kFlagIsFboLayer;
 
     if (fboLayer) {
+        endTiling();
+
         // Detach the texture from the FBO
         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
-
         // Unbind current FBO and restore previous one
         glBindFramebuffer(GL_FRAMEBUFFER, previous->fbo);
+
+        startTiling(previous);
     }
 
     Layer* layer = current->layer;
@@ -2621,12 +2640,15 @@
         OpenGLRenderer* renderer = layer->renderer;
         Rect& dirty = layer->dirtyRect;
 
+        endTiling();
+
         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();
 
         resumeAfterLayer();
+        startTiling(mSnapshot);
 
         dirty.setEmpty();
         layer->deferredUpdateScheduled = false;
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 8dcd33f..10ba86e 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -347,6 +347,20 @@
     void syncState();
 
     /**
+     * Tells the GPU what part of the screen is about to be redrawn.
+     * This method needs to be invoked every time getTargetFbo() is
+     * bound again.
+     */
+    void startTiling();
+    void startTiling(const sp<Snapshot>& snapshot);
+
+    /**
+     * Tells the GPU that we are done drawing the frame or that we
+     * are switching to another render target.
+     */
+    void endTiling();
+
+    /**
      * Saves the current state of the renderer as a new snapshot.
      * The new snapshot is saved in mSnapshot and the previous snapshot
      * is linked from mSnapshot->previous.
@@ -735,6 +749,8 @@
     sp<Snapshot> mFirstSnapshot;
     // Current state
     sp<Snapshot> mSnapshot;
+    // State used to define the clipping region
+    sp<Snapshot> mTilingSnapshot;
 
     // Shaders
     SkiaShader* mShader;
@@ -784,6 +800,8 @@
     GLuint mTextureUnit;
     // Track dirty regions, true by default
     bool mTrackDirtyRegions;
+    // Indicate whether we are drawing an opaque frame
+    bool mOpaqueFrame;
 
     friend class DisplayListRenderer;