Track texture memory globally

Also mostly consolidates texture creation

Change-Id: Ifea01303afda531dcec99b8fe2a0f64cf2f24420
diff --git a/libs/hwui/renderstate/OffscreenBufferPool.cpp b/libs/hwui/renderstate/OffscreenBufferPool.cpp
index 227b640..98c94df 100644
--- a/libs/hwui/renderstate/OffscreenBufferPool.cpp
+++ b/libs/hwui/renderstate/OffscreenBufferPool.cpp
@@ -34,29 +34,22 @@
 
 OffscreenBuffer::OffscreenBuffer(RenderState& renderState, Caches& caches,
         uint32_t viewportWidth, uint32_t viewportHeight)
-        : renderState(renderState)
+        : GpuMemoryTracker(GpuObjectType::OffscreenBuffer)
+        , renderState(renderState)
         , viewportWidth(viewportWidth)
         , viewportHeight(viewportHeight)
         , texture(caches) {
-    texture.width = computeIdealDimension(viewportWidth);
-    texture.height = computeIdealDimension(viewportHeight);
+    uint32_t width = computeIdealDimension(viewportWidth);
+    uint32_t height = computeIdealDimension(viewportHeight);
+    texture.resize(width, height, GL_RGBA);
     texture.blend = true;
-
-    caches.textureState().activateTexture(0);
-    glGenTextures(1, &texture.id);
-    caches.textureState().bindTexture(GL_TEXTURE_2D, texture.id);
-
-    texture.setWrap(GL_CLAMP_TO_EDGE, false, false, GL_TEXTURE_2D);
+    texture.setWrap(GL_CLAMP_TO_EDGE);
     // not setting filter on texture, since it's set when drawing, based on transform
-
-    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture.width, texture.height, 0,
-            GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
 }
 
 Rect OffscreenBuffer::getTextureCoordinates() {
-    const float texX = 1.0f / float(texture.width);
-    const float texY = 1.0f / float(texture.height);
+    const float texX = 1.0f / static_cast<float>(texture.width());
+    const float texY = 1.0f / static_cast<float>(texture.height());
     return Rect(0, viewportHeight * texY, viewportWidth * texX, 0);
 }
 
@@ -69,8 +62,8 @@
     size_t count;
     const android::Rect* rects = safeRegion.getArray(&count);
 
-    const float texX = 1.0f / float(texture.width);
-    const float texY = 1.0f / float(texture.height);
+    const float texX = 1.0f / float(texture.width());
+    const float texY = 1.0f / float(texture.height());
 
     FatVector<TextureVertex, 64> meshVector(count * 4); // uses heap if more than 64 vertices needed
     TextureVertex* mesh = &meshVector[0];
@@ -157,8 +150,8 @@
 OffscreenBuffer* OffscreenBufferPool::resize(OffscreenBuffer* layer,
         const uint32_t width, const uint32_t height) {
     RenderState& renderState = layer->renderState;
-    if (layer->texture.width == OffscreenBuffer::computeIdealDimension(width)
-            && layer->texture.height == OffscreenBuffer::computeIdealDimension(height)) {
+    if (layer->texture.width() == OffscreenBuffer::computeIdealDimension(width)
+            && layer->texture.height() == OffscreenBuffer::computeIdealDimension(height)) {
         // resize in place
         layer->viewportWidth = width;
         layer->viewportHeight = height;
diff --git a/libs/hwui/renderstate/OffscreenBufferPool.h b/libs/hwui/renderstate/OffscreenBufferPool.h
index 2d8d529..94155ef 100644
--- a/libs/hwui/renderstate/OffscreenBufferPool.h
+++ b/libs/hwui/renderstate/OffscreenBufferPool.h
@@ -17,10 +17,10 @@
 #ifndef ANDROID_HWUI_OFFSCREEN_BUFFER_POOL_H
 #define ANDROID_HWUI_OFFSCREEN_BUFFER_POOL_H
 
+#include <GpuMemoryTracker.h>
 #include "Caches.h"
 #include "Texture.h"
 #include "utils/Macros.h"
-
 #include <ui/Region.h>
 
 #include <set>
@@ -40,7 +40,7 @@
  * viewport bounds, since textures are always allocated with width / height as a multiple of 64, for
  * the purpose of improving reuse.
  */
-class OffscreenBuffer {
+class OffscreenBuffer : GpuMemoryTracker {
 public:
     OffscreenBuffer(RenderState& renderState, Caches& caches,
             uint32_t viewportWidth, uint32_t viewportHeight);
@@ -58,7 +58,7 @@
 
     static uint32_t computeIdealDimension(uint32_t dimension);
 
-    uint32_t getSizeInBytes() { return texture.width * texture.height * 4; }
+    uint32_t getSizeInBytes() { return texture.objectSize(); }
 
     RenderState& renderState;
 
@@ -124,8 +124,8 @@
 
         Entry(OffscreenBuffer* layer)
                 : layer(layer)
-                , width(layer->texture.width)
-                , height(layer->texture.height) {
+                , width(layer->texture.width())
+                , height(layer->texture.height()) {
         }
 
         static int compare(const Entry& lhs, const Entry& rhs);
diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp
index 4fa8200..4a1e8fc 100644
--- a/libs/hwui/renderstate/RenderState.cpp
+++ b/libs/hwui/renderstate/RenderState.cpp
@@ -13,12 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#include <GpuMemoryTracker.h>
 #include "renderstate/RenderState.h"
 
 #include "renderthread/CanvasContext.h"
 #include "renderthread/EglManager.h"
 #include "utils/GLUtils.h"
-
 #include <algorithm>
 
 namespace android {
@@ -40,6 +40,8 @@
 void RenderState::onGLContextCreated() {
     LOG_ALWAYS_FATAL_IF(mBlend || mMeshState || mScissor || mStencil,
             "State object lifecycle not managed correctly");
+    GpuMemoryTracker::onGLContextCreated();
+
     mBlend = new Blend();
     mMeshState = new MeshState();
     mScissor = new Scissor();
@@ -106,6 +108,8 @@
     mScissor = nullptr;
     delete mStencil;
     mStencil = nullptr;
+
+    GpuMemoryTracker::onGLContextDestroyed();
 }
 
 void RenderState::flush(Caches::FlushMode mode) {
@@ -310,7 +314,7 @@
             texture.texture->setFilter(texture.filter, true, false, texture.target);
         }
 
-        mCaches->textureState().bindTexture(texture.target, texture.texture->id);
+        mCaches->textureState().bindTexture(texture.target, texture.texture->id());
         meshState().enableTexCoordsVertexArray();
         meshState().bindTexCoordsVertexPointer(force, vertices.texCoord, vertices.stride);
 
diff --git a/libs/hwui/renderstate/TextureState.cpp b/libs/hwui/renderstate/TextureState.cpp
index 1f50f71..26ebdee 100644
--- a/libs/hwui/renderstate/TextureState.cpp
+++ b/libs/hwui/renderstate/TextureState.cpp
@@ -34,134 +34,6 @@
     GL_TEXTURE3
 };
 
-static void uploadToTexture(bool resize, GLenum format, GLenum type, GLsizei stride, GLsizei bpp,
-        GLsizei width, GLsizei height, const GLvoid * data) {
-
-    glPixelStorei(GL_UNPACK_ALIGNMENT, bpp);
-    const bool useStride = stride != width
-            && Caches::getInstance().extensions().hasUnpackRowLength();
-    if ((stride == width) || useStride) {
-        if (useStride) {
-            glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
-        }
-
-        if (resize) {
-            glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, data);
-        } else {
-            glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, data);
-        }
-
-        if (useStride) {
-            glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
-        }
-    } else {
-        //  With OpenGL ES 2.0 we need to copy the bitmap in a temporary buffer
-        //  if the stride doesn't match the width
-
-        GLvoid * temp = (GLvoid *) malloc(width * height * bpp);
-        if (!temp) return;
-
-        uint8_t * pDst = (uint8_t *)temp;
-        uint8_t * pSrc = (uint8_t *)data;
-        for (GLsizei i = 0; i < height; i++) {
-            memcpy(pDst, pSrc, width * bpp);
-            pDst += width * bpp;
-            pSrc += stride * bpp;
-        }
-
-        if (resize) {
-            glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, temp);
-        } else {
-            glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, temp);
-        }
-
-        free(temp);
-    }
-}
-
-static void uploadSkBitmapToTexture(const SkBitmap& bitmap,
-        bool resize, GLenum format, GLenum type) {
-    uploadToTexture(resize, format, type, bitmap.rowBytesAsPixels(), bitmap.bytesPerPixel(),
-            bitmap.width(), bitmap.height(), bitmap.getPixels());
-}
-
-void TextureState::generateTexture(const SkBitmap* bitmap, Texture* texture, bool regenerate) {
-    SkAutoLockPixels alp(*bitmap);
-
-    if (!bitmap->readyToDraw()) {
-        ALOGE("Cannot generate texture from bitmap");
-        return;
-    }
-
-    ATRACE_FORMAT("Upload %ux%u Texture", bitmap->width(), bitmap->height());
-
-    // We could also enable mipmapping if both bitmap dimensions are powers
-    // of 2 but we'd have to deal with size changes. Let's keep this simple
-    const bool canMipMap = Caches::getInstance().extensions().hasNPot();
-
-    // If the texture had mipmap enabled but not anymore,
-    // force a glTexImage2D to discard the mipmap levels
-    const bool resize = !regenerate || bitmap->width() != int(texture->width) ||
-            bitmap->height() != int(texture->height) ||
-            (regenerate && canMipMap && texture->mipMap && !bitmap->hasHardwareMipMap());
-
-    if (!regenerate) {
-        glGenTextures(1, &texture->id);
-    }
-
-    texture->generation = bitmap->getGenerationID();
-    texture->width = bitmap->width();
-    texture->height = bitmap->height();
-
-    bindTexture(texture->id);
-
-    switch (bitmap->colorType()) {
-    case kAlpha_8_SkColorType:
-        uploadSkBitmapToTexture(*bitmap, resize, GL_ALPHA, GL_UNSIGNED_BYTE);
-        texture->blend = true;
-        break;
-    case kRGB_565_SkColorType:
-        uploadSkBitmapToTexture(*bitmap, resize, GL_RGB, GL_UNSIGNED_SHORT_5_6_5);
-        texture->blend = false;
-        break;
-    case kN32_SkColorType:
-        uploadSkBitmapToTexture(*bitmap, resize, GL_RGBA, GL_UNSIGNED_BYTE);
-        // Do this after calling getPixels() to make sure Skia's deferred
-        // decoding happened
-        texture->blend = !bitmap->isOpaque();
-        break;
-    case kARGB_4444_SkColorType:
-    case kIndex_8_SkColorType: {
-        SkBitmap rgbaBitmap;
-        rgbaBitmap.allocPixels(SkImageInfo::MakeN32(texture->width, texture->height,
-                bitmap->alphaType()));
-        rgbaBitmap.eraseColor(0);
-
-        SkCanvas canvas(rgbaBitmap);
-        canvas.drawBitmap(*bitmap, 0.0f, 0.0f, nullptr);
-
-        uploadSkBitmapToTexture(rgbaBitmap, resize, GL_RGBA, GL_UNSIGNED_BYTE);
-        texture->blend = !bitmap->isOpaque();
-        break;
-    }
-    default:
-        ALOGW("Unsupported bitmap colorType: %d", bitmap->colorType());
-        break;
-    }
-
-    if (canMipMap) {
-        texture->mipMap = bitmap->hasHardwareMipMap();
-        if (texture->mipMap) {
-            glGenerateMipmap(GL_TEXTURE_2D);
-        }
-    }
-
-    if (!regenerate) {
-        texture->setFilter(GL_NEAREST);
-        texture->setWrap(GL_CLAMP_TO_EDGE);
-    }
-}
-
 TextureState::TextureState()
         : mTextureUnit(0) {
     glActiveTexture(kTextureUnits[0]);
diff --git a/libs/hwui/renderstate/TextureState.h b/libs/hwui/renderstate/TextureState.h
index 3a2b85a..ec94d7e 100644
--- a/libs/hwui/renderstate/TextureState.h
+++ b/libs/hwui/renderstate/TextureState.h
@@ -76,13 +76,6 @@
      */
     void unbindTexture(GLuint texture);
 
-    /**
-     * Generates the texture from a bitmap into the specified texture structure.
-     *
-     * @param regenerate If true, the bitmap data is reuploaded into the texture, but
-     *        no new texture is generated.
-     */
-    void generateTexture(const SkBitmap* bitmap, Texture* texture, bool regenerate);
 private:
     // total number of texture units available for use
     static const int kTextureUnitsCount = 4;