New widget: TextureView
Bug #4343984

TextureView can be used to render media content (video, OpenGL,
RenderScript) inside a View.

The key difference with SurfaceView is that TextureView does
not create a new Surface. This gives the ability to seamlessly
transform, animate, fade, etc. a TextureView, which was hard
if not impossible to do with a SurfaceView.
A TextureView also interacts perfectly with ScrollView,
ListView, etc. It allows application to embed media content
in a much more flexible way than before.

For instance, to render the camera preview at 50% opacity,
all you need to do is the following:

mTextureView.setAlpha(0.5f);
Camera c = Camera.open();
c.setPreviewTexture(mTextureView.getSurfaceTexture());
c.startPreview();

TextureView uses a SurfaceTexture to get the job done. More
APIs are required to make it easy to create OpenGL contexts
for a TextureView. It can currently be done with a bit of
JNI code.

Change-Id: Iaa7953097ab5beb8437bcbbfa03b2df5b7f80cd7
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index e926d99..4dde342 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -633,15 +633,43 @@
     }
 }
 
+void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) {
+    float alpha = layer->alpha / 255.0f;
+
+    setupDraw();
+    setupDrawWithExternalTexture();
+    setupDrawColor(alpha, alpha, alpha, alpha);
+    setupDrawColorFilter();
+    setupDrawBlending(layer->blend, layer->mode);
+    setupDrawProgram();
+    setupDrawModelView(rect.left, rect.top, rect.right, rect.bottom);
+    setupDrawPureColorUniforms();
+    setupDrawColorFilterUniforms();
+    setupDrawExternalTexture(layer->texture);
+    setupDrawTextureTransform(layer->texTransform);
+    setupDrawMesh(&mMeshVertices[0].position[0], &mMeshVertices[0].texture[0]);
+
+    glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
+
+    finishDrawTexture();
+}
+
 void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) {
-    const Rect& texCoords = layer->texCoords;
-    resetDrawTextureTexCoords(texCoords.left, texCoords.top, texCoords.right, texCoords.bottom);
+    if (!layer->isTextureLayer) {
+        const Rect& texCoords = layer->texCoords;
+        resetDrawTextureTexCoords(texCoords.left, texCoords.top,
+                texCoords.right, texCoords.bottom);
 
-    drawTextureMesh(rect.left, rect.top, rect.right, rect.bottom, layer->texture,
-            layer->alpha / 255.0f, layer->mode, layer->blend, &mMeshVertices[0].position[0],
-            &mMeshVertices[0].texture[0], GL_TRIANGLE_STRIP, gMeshCount, swap, swap);
+        drawTextureMesh(rect.left, rect.top, rect.right, rect.bottom, layer->texture,
+                layer->alpha / 255.0f, layer->mode, layer->blend, &mMeshVertices[0].position[0],
+                &mMeshVertices[0].texture[0], GL_TRIANGLE_STRIP, gMeshCount, swap, swap);
 
-    resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
+        resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
+    } else {
+        resetDrawTextureTexCoords(0.0f, 1.0f, 1.0f, 0.0f);
+        drawTextureLayer(layer, rect);
+        resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
+    }
 }
 
 void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) {
@@ -882,6 +910,10 @@
     mDescription.hasAlpha8Texture = isAlpha8;
 }
 
+void OpenGLRenderer::setupDrawWithExternalTexture() {
+    mDescription.hasExternalTexture = true;
+}
+
 void OpenGLRenderer::setupDrawAALine() {
     mDescription.hasWidth = true;
 }
@@ -1055,6 +1087,19 @@
     glEnableVertexAttribArray(mTexCoordsSlot);
 }
 
+void OpenGLRenderer::setupDrawExternalTexture(GLuint texture) {
+    bindExternalTexture(texture);
+    glUniform1i(mCaches.currentProgram->getUniform("sampler"), mTextureUnit++);
+
+    mTexCoordsSlot = mCaches.currentProgram->getAttrib("texCoords");
+    glEnableVertexAttribArray(mTexCoordsSlot);
+}
+
+void OpenGLRenderer::setupDrawTextureTransform(mat4& transform) {
+    glUniformMatrix4fv(mCaches.currentProgram->getUniform("mainTextureTransform"), 1,
+            GL_FALSE, &transform.data[0]);
+}
+
 void OpenGLRenderer::setupDrawMesh(GLvoid* vertices, GLvoid* texCoords, GLuint vbo) {
     if (!vertices) {
         mCaches.bindMeshBuffer(vbo == 0 ? mCaches.meshBuffer : vbo);