Glop TextureLayer support

Change-Id: I348a926bd4a2f47be9fdbe74058c0aa2f8dc6276
diff --git a/libs/hwui/Glop.h b/libs/hwui/Glop.h
index c9a5679..62da6e08 100644
--- a/libs/hwui/Glop.h
+++ b/libs/hwui/Glop.h
@@ -94,8 +94,10 @@
 
         struct TextureData {
             Texture* texture;
+            GLenum target;
             GLenum filter;
             GLenum clamp;
+            Matrix4* textureTransform;
         } texture;
 
         bool colorEnabled;
diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp
index f50dfc8..3108a8d 100644
--- a/libs/hwui/GlopBuilder.cpp
+++ b/libs/hwui/GlopBuilder.cpp
@@ -274,7 +274,8 @@
     TRIGGER_STAGE(kFillStage);
     REQUIRE_STAGES(kMeshStage);
 
-    mOutGlop->fill.texture = { &texture, PaintUtils::getFilter(paint), GL_CLAMP_TO_EDGE };
+    mOutGlop->fill.texture = { &texture,
+            GL_TEXTURE_2D, PaintUtils::getFilter(paint), GL_CLAMP_TO_EDGE, nullptr };
 
     if (paint) {
         int color = paint->getColor();
@@ -315,7 +316,7 @@
     TRIGGER_STAGE(kFillStage);
     REQUIRE_STAGES(kMeshStage);
 
-    mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM };
+    mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
 
     setFill(paint.getColor(), alphaScale, PaintUtils::getXfermode(paint.getXfermode()),
             paint.getShader(), paint.getColorFilter());
@@ -329,7 +330,7 @@
     REQUIRE_STAGES(kMeshStage);
 
     //specify invalid filter/clamp, since these are always static for PathTextures
-    mOutGlop->fill.texture = { &texture, GL_INVALID_ENUM, GL_INVALID_ENUM };
+    mOutGlop->fill.texture = { &texture, GL_TEXTURE_2D, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
 
     setFill(paint.getColor(), alphaScale, PaintUtils::getXfermode(paint.getXfermode()),
             paint.getShader(), paint.getColorFilter());
@@ -345,7 +346,7 @@
     REQUIRE_STAGES(kMeshStage);
 
     //specify invalid filter/clamp, since these are always static for ShadowTextures
-    mOutGlop->fill.texture = { &texture, GL_INVALID_ENUM, GL_INVALID_ENUM };
+    mOutGlop->fill.texture = { &texture, GL_TEXTURE_2D, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
 
     const int ALPHA_BITMASK = SK_ColorBLACK;
     const int COLOR_BITMASK = ~ALPHA_BITMASK;
@@ -366,7 +367,7 @@
     TRIGGER_STAGE(kFillStage);
     REQUIRE_STAGES(kMeshStage);
 
-    mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM };
+    mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
     setFill(SK_ColorBLACK, 1.0f, SkXfermode::kSrcOver_Mode, nullptr, nullptr);
     return *this;
 }
@@ -375,7 +376,7 @@
     TRIGGER_STAGE(kFillStage);
     REQUIRE_STAGES(kMeshStage);
 
-    mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM };
+    mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
     setFill(SK_ColorBLACK, 1.0f, SkXfermode::kClear_Mode, nullptr, nullptr);
     return *this;
 }
@@ -385,7 +386,8 @@
     TRIGGER_STAGE(kFillStage);
     REQUIRE_STAGES(kMeshStage);
 
-    mOutGlop->fill.texture = { &texture, GL_LINEAR, GL_CLAMP_TO_EDGE };
+    mOutGlop->fill.texture = { &texture,
+            GL_TEXTURE_2D, GL_LINEAR, GL_CLAMP_TO_EDGE, nullptr };
     mOutGlop->fill.color = { alpha, alpha, alpha, alpha };
 
     setFill(SK_ColorWHITE, alpha, mode, nullptr, colorFilter);
@@ -394,6 +396,21 @@
     return *this;
 }
 
+GlopBuilder& GlopBuilder::setFillTextureLayer(Layer& layer, float alpha) {
+    TRIGGER_STAGE(kFillStage);
+    REQUIRE_STAGES(kMeshStage);
+
+    mOutGlop->fill.texture = { &(layer.getTexture()),
+            layer.getRenderTarget(), GL_LINEAR, GL_CLAMP_TO_EDGE, &layer.getTexTransform() };
+    mOutGlop->fill.color = { alpha, alpha, alpha, alpha };
+
+    setFill(SK_ColorWHITE, alpha, layer.getMode(), nullptr, layer.getColorFilter());
+
+    mDescription.modulate = mOutGlop->fill.color.a < 1.0f;
+    mDescription.hasTextureTransform = true;
+    return *this;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // Transform
 ////////////////////////////////////////////////////////////////////////////////
@@ -492,20 +509,27 @@
 
 void verify(const ProgramDescription& description, const Glop& glop) {
     bool hasTexture = glop.fill.texture.texture != nullptr;
-    LOG_ALWAYS_FATAL_IF(description.hasTexture != hasTexture);
+    LOG_ALWAYS_FATAL_IF(description.hasTexture && description.hasExternalTexture);
+    LOG_ALWAYS_FATAL_IF((description.hasTexture || description.hasExternalTexture )!= hasTexture);
     LOG_ALWAYS_FATAL_IF((glop.mesh.vertices.flags & VertexAttribFlags::kTextureCoord) != hasTexture);
 
     if ((glop.mesh.vertices.flags & VertexAttribFlags::kAlpha) && glop.mesh.vertices.bufferObject) {
         LOG_ALWAYS_FATAL("VBO and alpha attributes are not currently compatible");
     }
+
+    if (description.hasTextureTransform != (glop.fill.texture.textureTransform != nullptr)) {
+        LOG_ALWAYS_FATAL("Texture transform incorrectly specified");
+    }
 }
 
 void GlopBuilder::build() {
     REQUIRE_STAGES(kAllStages);
-
-    mDescription.hasTexture = static_cast<int>(mOutGlop->mesh.vertices.flags & VertexAttribFlags::kTextureCoord);
-    mDescription.hasColors = static_cast<int>(mOutGlop->mesh.vertices.flags & VertexAttribFlags::kColor);
-    mDescription.hasVertexAlpha = static_cast<int>(mOutGlop->mesh.vertices.flags & VertexAttribFlags::kAlpha);
+    if (mOutGlop->mesh.vertices.flags & VertexAttribFlags::kTextureCoord) {
+        mDescription.hasTexture = mOutGlop->fill.texture.target == GL_TEXTURE_2D;
+        mDescription.hasExternalTexture = mOutGlop->fill.texture.target == GL_TEXTURE_EXTERNAL_OES;
+    }
+    mDescription.hasColors = mOutGlop->mesh.vertices.flags & VertexAttribFlags::kColor;
+    mDescription.hasVertexAlpha = mOutGlop->mesh.vertices.flags & VertexAttribFlags::kAlpha;
 
     // serialize shader info into ShaderData
     GLuint textureUnit = mOutGlop->fill.texture.texture ? 1 : 0;
diff --git a/libs/hwui/GlopBuilder.h b/libs/hwui/GlopBuilder.h
index c24b122..4b871d5 100644
--- a/libs/hwui/GlopBuilder.h
+++ b/libs/hwui/GlopBuilder.h
@@ -57,11 +57,19 @@
     GlopBuilder& setFillClear();
     GlopBuilder& setFillLayer(Texture& texture, const SkColorFilter* colorFilter,
             float alpha, SkXfermode::Mode mode);
+    GlopBuilder& setFillTextureLayer(Layer& layer, float alpha);
 
     GlopBuilder& setTransform(const Matrix4& ortho, const Matrix4& transform, bool fudgingOffset);
 
     GlopBuilder& setModelViewMapUnitToRect(const Rect destination);
     GlopBuilder& setModelViewMapUnitToRectSnap(const Rect destination);
+    GlopBuilder& setModelViewMapUnitToRectOptionalSnap(bool snap, const Rect destination) {
+        if (snap) {
+            return setModelViewMapUnitToRectSnap(destination);
+        } else {
+            return setModelViewMapUnitToRect(destination);
+        }
+    }
     GlopBuilder& setModelViewOffsetRect(float offsetX, float offsetY, const Rect source);
     GlopBuilder& setModelViewOffsetRectSnap(float offsetX, float offsetY, const Rect source);
 
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index f598664..30ffcea 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -356,8 +356,9 @@
 
 bool LayerRenderer::copyLayer(RenderState& renderState, Layer* layer, SkBitmap* bitmap) {
     Caches& caches = Caches::getInstance();
-    if (layer && bitmap->width() <= caches.maxTextureSize &&
-            bitmap->height() <= caches.maxTextureSize) {
+    if (layer
+            && bitmap->width() <= caches.maxTextureSize
+            && bitmap->height() <= caches.maxTextureSize) {
 
         GLuint fbo = caches.fboCache.get();
         if (!fbo) {
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 3913ee5..83715ba 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -846,8 +846,21 @@
 }
 
 void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) {
-    float alpha = getLayerAlpha(layer);
+    if (USE_GLOPS) {
+        bool snap = !layer->getForceFilter()
+                && layer->getWidth() == (uint32_t) rect.getWidth()
+                && layer->getHeight() == (uint32_t) rect.getHeight();
+        Glop glop;
+        GlopBuilder aBuilder(mRenderState, mCaches, &glop);
+        aBuilder.setMeshTexturedUvQuad(nullptr, Rect(0, 1, 1, 0)) // TODO: simplify with VBO
+                .setFillTextureLayer(*layer, getLayerAlpha(layer))
+                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
+                .setModelViewMapUnitToRectOptionalSnap(snap, rect)
+                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+                .build();
+    }
 
+    float alpha = getLayerAlpha(layer);
     setupDraw();
     if (layer->getRenderTarget() == GL_TEXTURE_2D) {
         setupDrawWithTexture();
@@ -866,10 +879,10 @@
     } else {
         setupDrawExternalTexture(layer->getTextureId());
     }
-    if (currentTransform()->isPureTranslate() &&
-            !layer->getForceFilter() &&
-            layer->getWidth() == (uint32_t) rect.getWidth() &&
-            layer->getHeight() == (uint32_t) rect.getHeight()) {
+    if (currentTransform()->isPureTranslate()
+            && !layer->getForceFilter()
+            && layer->getWidth() == (uint32_t) rect.getWidth()
+            && layer->getHeight() == (uint32_t) rect.getHeight()) {
         const float x = (int) floorf(rect.left + currentTransform()->getTranslateX() + 0.5f);
         const float y = (int) floorf(rect.top + currentTransform()->getTranslateY() + 0.5f);
 
diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp
index 7992077..ca3a4c2 100644
--- a/libs/hwui/renderstate/RenderState.cpp
+++ b/libs/hwui/renderstate/RenderState.cpp
@@ -260,19 +260,25 @@
     meshState().bindIndicesBufferInternal(indices.bufferObject);
 
     if (vertices.flags & VertexAttribFlags::kTextureCoord) {
-        // fill.texture always takes slot 0, shader samplers increment from there
+        const Glop::Fill::TextureData& texture = fill.texture;
+        // texture always takes slot 0, shader samplers increment from there
         mCaches->textureState().activateTexture(0);
 
-        if (fill.texture.clamp != GL_INVALID_ENUM) {
-            fill.texture.texture->setWrap(fill.texture.clamp, true);
+        if (texture.clamp != GL_INVALID_ENUM) {
+            texture.texture->setWrap(texture.clamp, true);
         }
-        if (fill.texture.filter != GL_INVALID_ENUM) {
-            fill.texture.texture->setFilter(fill.texture.filter, true);
+        if (texture.filter != GL_INVALID_ENUM) {
+            texture.texture->setFilter(texture.filter, true);
         }
 
-        mCaches->textureState().bindTexture(fill.texture.texture->id);
+        mCaches->textureState().bindTexture(texture.target, texture.texture->id);
         meshState().enableTexCoordsVertexArray();
         meshState().bindTexCoordsVertexPointer(force, vertices.texCoord, vertices.stride);
+
+        if (texture.textureTransform) {
+            glUniformMatrix4fv(fill.program->getUniform("mainTextureTransform"), 1,
+                    GL_FALSE, &texture.textureTransform->data[0]);
+        }
     } else {
         meshState().disableTexCoordsVertexArray();
     }