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/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index 80b1917..62ac2ba 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -41,6 +41,8 @@
         "attribute vec2 texCoords;\n";
 const char* gVS_Header_Attributes_Distance =
         "attribute float vtxDistance;\n";
+const char* gVS_Header_Uniforms_TextureTransform =
+        "uniform mat4 mainTextureTransform;\n";
 const char* gVS_Header_Uniforms =
         "uniform mat4 transform;\n";
 const char* gVS_Header_Uniforms_IsPoint =
@@ -76,6 +78,8 @@
         "\nvoid main(void) {\n";
 const char* gVS_Main_OutTexCoords =
         "    outTexCoords = texCoords;\n";
+const char* gVS_Main_OutTransformedTexCoords =
+        "    outTexCoords = (mainTextureTransform * vec4(texCoords, 0.0, 1.0)).xy;\n";
 const char* gVS_Main_OutGradient[3] = {
         // Linear
         "    linear = vec2((screenSpace * position).x, 0.5);\n",
@@ -103,6 +107,8 @@
 
 const char* gFS_Header_Extension_FramebufferFetch =
         "#extension GL_NV_shader_framebuffer_fetch : enable\n\n";
+const char* gFS_Header_Extension_ExternalTexture =
+        "#extension GL_OES_EGL_image_external : require\n\n";
 const char* gFS_Header =
         "precision mediump float;\n\n";
 const char* gFS_Uniforms_Color =
@@ -116,6 +122,8 @@
         "uniform float pointSize;\n";
 const char* gFS_Uniforms_TextureSampler =
         "uniform sampler2D sampler;\n";
+const char* gFS_Uniforms_ExternalTextureSampler =
+        "uniform samplerExternalOES sampler;\n";
 const char* gFS_Uniforms_GradientSampler[3] = {
         // Linear
         "uniform sampler2D gradientSampler;\n",
@@ -369,7 +377,7 @@
 String8 ProgramCache::generateVertexShader(const ProgramDescription& description) {
     // Add attributes
     String8 shader(gVS_Header_Attributes);
-    if (description.hasTexture) {
+    if (description.hasTexture || description.hasExternalTexture) {
         shader.append(gVS_Header_Attributes_TexCoords);
     }
     if (description.hasWidth) {
@@ -377,6 +385,9 @@
     }
     // Uniforms
     shader.append(gVS_Header_Uniforms);
+    if (description.hasExternalTexture) {
+        shader.append(gVS_Header_Uniforms_TextureTransform);
+    }
     if (description.hasGradient) {
         shader.append(gVS_Header_Uniforms_HasGradient[description.gradientType]);
     }
@@ -387,7 +398,7 @@
         shader.append(gVS_Header_Uniforms_IsPoint);
     }
     // Varyings
-    if (description.hasTexture) {
+    if (description.hasTexture || description.hasExternalTexture) {
         shader.append(gVS_Header_Varyings_HasTexture);
     }
     if (description.hasWidth) {
@@ -407,6 +418,9 @@
         if (description.hasTexture) {
             shader.append(gVS_Main_OutTexCoords);
         }
+        if (description.hasExternalTexture) {
+            shader.append(gVS_Main_OutTransformedTexCoords);
+        }
         if (description.hasWidth) {
             shader.append(gVS_Main_Width);
         }
@@ -440,11 +454,14 @@
     if (blendFramebuffer) {
         shader.append(gFS_Header_Extension_FramebufferFetch);
     }
+    if (description.hasExternalTexture) {
+        shader.append(gFS_Header_Extension_ExternalTexture);
+    }
 
     shader.append(gFS_Header);
 
     // Varyings
-    if (description.hasTexture) {
+    if (description.hasTexture || description.hasExternalTexture) {
         shader.append(gVS_Header_Varyings_HasTexture);
     }
     if (description.hasWidth) {
@@ -461,7 +478,7 @@
 
     // Uniforms
     int modulateOp = MODULATE_OP_NO_MODULATE;
-    const bool singleColor = !description.hasTexture &&
+    const bool singleColor = !description.hasTexture && !description.hasExternalTexture &&
             !description.hasGradient && !description.hasBitmap;
 
     if (description.modulate || singleColor) {
@@ -471,6 +488,9 @@
     if (description.hasTexture) {
         shader.append(gFS_Uniforms_TextureSampler);
     }
+    if (description.hasExternalTexture) {
+        shader.append(gFS_Uniforms_ExternalTextureSampler);
+    }
     if (description.hasWidth) {
         shader.append(gFS_Uniforms_Width);
     }
@@ -487,11 +507,11 @@
         bool fast = false;
 
         const bool noShader = !description.hasGradient && !description.hasBitmap;
-        const bool singleTexture = description.hasTexture &&
+        const bool singleTexture = (description.hasTexture || description.hasExternalTexture) &&
                 !description.hasAlpha8Texture && noShader;
         const bool singleA8Texture = description.hasTexture &&
                 description.hasAlpha8Texture && noShader;
-        const bool singleGradient = !description.hasTexture &&
+        const bool singleGradient = !description.hasTexture && !description.hasExternalTexture &&
                 description.hasGradient && !description.hasBitmap &&
                 description.gradientType == ProgramDescription::kGradientLinear;
 
@@ -554,7 +574,7 @@
     // Begin the shader
     shader.append(gFS_Main); {
         // Stores the result in fragColor directly
-        if (description.hasTexture) {
+        if (description.hasTexture || description.hasExternalTexture) {
             if (description.hasAlpha8Texture) {
                 if (!description.hasGradient && !description.hasBitmap) {
                     shader.append(gFS_Main_FetchA8Texture[modulateOp]);