summaryrefslogtreecommitdiffstats
path: root/libs
diff options
context:
space:
mode:
authorRomain Guy <romainguy@google.com>2010-07-27 17:39:27 -0700
committerRomain Guy <romainguy@google.com>2010-07-27 19:52:29 -0700
commitac670c0433d19397d4e36ced2110475b6f54fe26 (patch)
tree10722cd4e465fc053f9536cc312c1125a694108a /libs
parentbb2b2a996b2c0bea7e434136e20340f4f1b398ab (diff)
downloadframeworks_base-ac670c0433d19397d4e36ced2110475b6f54fe26.zip
frameworks_base-ac670c0433d19397d4e36ced2110475b6f54fe26.tar.gz
frameworks_base-ac670c0433d19397d4e36ced2110475b6f54fe26.tar.bz2
Generate shaders to cover all possible cases.
With this change, all the vertex and fragment shaders used by the GL renderer are now generated based on a program description supplied by the caller. This allows the renderer to generate a large number of shaders without having to write all the possible combinations by hand. The generated shaders are stored in a program cache. Change-Id: If54d286e77ae021c724d42090da476df12a18ebb
Diffstat (limited to 'libs')
-rw-r--r--libs/hwui/Android.mk1
-rw-r--r--libs/hwui/OpenGLRenderer.cpp57
-rw-r--r--libs/hwui/OpenGLRenderer.h6
-rw-r--r--libs/hwui/Program.cpp11
-rw-r--r--libs/hwui/Program.h28
-rw-r--r--libs/hwui/ProgramCache.cpp332
-rw-r--r--libs/hwui/ProgramCache.h155
-rw-r--r--libs/hwui/Vertex.h8
-rw-r--r--libs/hwui/shaders/drawColor.vert11
-rw-r--r--libs/hwui/shaders/drawLinearGradient.vert2
10 files changed, 543 insertions, 68 deletions
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 172952a..a9714c7 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -10,6 +10,7 @@ LOCAL_SRC_FILES:= \
Patch.cpp \
PatchCache.cpp \
Program.cpp \
+ ProgramCache.cpp \
TextureCache.cpp
LOCAL_C_INCLUDES += \
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 2e44e122..0ed6276 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -45,32 +45,22 @@ namespace uirenderer {
#define MB(s) s * 1024 * 1024
// Generates simple and textured vertices
-#define SV(x, y) { { x, y } }
#define FV(x, y, u, v) { { x, y }, { u, v } }
///////////////////////////////////////////////////////////////////////////////
// Globals
///////////////////////////////////////////////////////////////////////////////
-static const SimpleVertex gDrawColorVertices[] = {
- SV(0.0f, 0.0f),
- SV(1.0f, 0.0f),
- SV(0.0f, 1.0f),
- SV(1.0f, 1.0f)
-};
-static const GLsizei gDrawColorVertexStride = sizeof(SimpleVertex);
-static const GLsizei gDrawColorVertexCount = 4;
-
// This array is never used directly but used as a memcpy source in the
// OpenGLRenderer constructor
-static const TextureVertex gDrawTextureVertices[] = {
+static const TextureVertex gMeshVertices[] = {
FV(0.0f, 0.0f, 0.0f, 0.0f),
FV(1.0f, 0.0f, 1.0f, 0.0f),
FV(0.0f, 1.0f, 0.0f, 1.0f),
FV(1.0f, 1.0f, 1.0f, 1.0f)
};
-static const GLsizei gDrawTextureVertexStride = sizeof(TextureVertex);
-static const GLsizei gDrawTextureVertexCount = 4;
+static const GLsizei gMeshStride = sizeof(TextureVertex);
+static const GLsizei gMeshCount = 4;
// In this array, the index of each Blender equals the value of the first
// entry. For instance, gBlends[1] == gBlends[SkXfermode::kSrc_Mode]
@@ -143,7 +133,18 @@ OpenGLRenderer::OpenGLRenderer():
mLastTexture = 0;
- memcpy(mDrawTextureVertices, gDrawTextureVertices, sizeof(gDrawTextureVertices));
+ memcpy(mMeshVertices, gMeshVertices, sizeof(gMeshVertices));
+
+ ProgramDescription d;
+ mProgramCache.get(d);
+ d.hasTexture = true;
+ mProgramCache.get(d);
+ d.hasAlpha8Texture = true;
+ d.hasGradient = true;
+ d.hasBitmap = true;
+ d.shadersMode = SkXfermode::kDstOut_Mode;
+ d.colorOp = ProgramDescription::kColorMatrix;
+ mProgramCache.get(d);
}
OpenGLRenderer::~OpenGLRenderer() {
@@ -650,9 +651,13 @@ void OpenGLRenderer::drawColorRect(float left, float top, float right, float bot
mModelView.scale(right - left, bottom - top, 1.0f);
if (!useProgram(mDrawColorProgram)) {
- const GLvoid* p = &gDrawColorVertices[0].position[0];
+ const GLvoid* vertices = &mMeshVertices[0].position[0];
+ const GLvoid* texCoords = &mMeshVertices[0].texture[0];
+
glVertexAttribPointer(mDrawColorProgram->position, 2, GL_FLOAT, GL_FALSE,
- gDrawColorVertexStride, p);
+ gMeshStride, vertices);
+ glVertexAttribPointer(mDrawColorProgram->texCoords, 2, GL_FLOAT, GL_FALSE,
+ gMeshStride, texCoords);
}
if (!ignoreTransform) {
@@ -664,7 +669,7 @@ void OpenGLRenderer::drawColorRect(float left, float top, float right, float bot
glUniform4f(mDrawColorProgram->color, r, g, b, a);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, gDrawColorVertexCount);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
}
void OpenGLRenderer::drawLinearGradientShader(float left, float top, float right, float bottom,
@@ -717,9 +722,9 @@ void OpenGLRenderer::drawLinearGradientShader(float left, float top, float right
&screenSpace.data[0]);
glVertexAttribPointer(mDrawLinearGradientProgram->position, 2, GL_FLOAT, GL_FALSE,
- gDrawTextureVertexStride, &mDrawTextureVertices[0].position[0]);
+ gMeshStride, &mMeshVertices[0].position[0]);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, gDrawTextureVertexCount);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
}
void OpenGLRenderer::drawBitmapShader(float left, float top, float right, float bottom,
@@ -757,7 +762,7 @@ void OpenGLRenderer::drawBitmapShader(float left, float top, float right, float
resetDrawTextureTexCoords(u1, v1, u2, v2);
drawTextureMesh(left, top, right, bottom, texture->id, alpha, mode, texture->blend,
- &mDrawTextureVertices[0].position[0], &mDrawTextureVertices[0].texture[0], NULL);
+ &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0], NULL);
resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
}
@@ -769,13 +774,13 @@ void OpenGLRenderer::drawTextureRect(float left, float top, float right, float b
getAlphaAndMode(paint, &alpha, &mode);
drawTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f, mode, texture->blend,
- &mDrawTextureVertices[0].position[0], &mDrawTextureVertices[0].texture[0], NULL);
+ &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0], NULL);
}
void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
GLuint texture, float alpha, SkXfermode::Mode mode, bool blend) {
drawTextureMesh(left, top, right, bottom, texture, alpha, mode, blend,
- &mDrawTextureVertices[0].position[0], &mDrawTextureVertices[0].texture[0], NULL);
+ &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0], NULL);
}
void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float bottom,
@@ -794,12 +799,12 @@ void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float b
glUniform4f(mDrawTextureProgram->color, alpha, alpha, alpha, alpha);
glVertexAttribPointer(mDrawTextureProgram->position, 2, GL_FLOAT, GL_FALSE,
- gDrawTextureVertexStride, vertices);
+ gMeshStride, vertices);
glVertexAttribPointer(mDrawTextureProgram->texCoords, 2, GL_FLOAT, GL_FALSE,
- gDrawTextureVertexStride, texCoords);
+ gMeshStride, texCoords);
if (!indices) {
- glDrawArrays(GL_TRIANGLE_STRIP, 0, gDrawTextureVertexCount);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
} else {
glDrawElements(GL_TRIANGLES, elementsCount, GL_UNSIGNED_SHORT, indices);
}
@@ -842,7 +847,7 @@ bool OpenGLRenderer::useProgram(const sp<Program>& program) {
}
void OpenGLRenderer::resetDrawTextureTexCoords(float u1, float v1, float u2, float v2) {
- TextureVertex* v = &mDrawTextureVertices[0];
+ TextureVertex* v = &mMeshVertices[0];
TextureVertex::setUV(v++, u1, v1);
TextureVertex::setUV(v++, u2, v1);
TextureVertex::setUV(v++, u1, v2);
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 248c9c3..975be05 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -41,6 +41,7 @@
#include "PatchCache.h"
#include "Vertex.h"
#include "FontRenderer.h"
+#include "ProgramCache.h"
namespace android {
namespace uirenderer {
@@ -268,7 +269,7 @@ private:
SkXfermode::Mode mode);
/**
- * Resets the texture coordinates stored in mDrawTextureVertices. Setting the values
+ * Resets the texture coordinates stored in mMeshVertices. Setting the values
* back to default is achieved by calling:
*
* resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
@@ -337,7 +338,7 @@ private:
sp<DrawLinearGradientProgram> mDrawLinearGradientProgram;
// Used to draw textured quads
- TextureVertex mDrawTextureVertices[4];
+ TextureVertex mMeshVertices[4];
// Current texture state
GLuint mLastTexture;
@@ -372,6 +373,7 @@ private:
TextureCache mTextureCache;
LayerCache mLayerCache;
GradientCache mGradientCache;
+ ProgramCache mProgramCache;
PatchCache mPatchCache;
}; // class OpenGLRenderer
diff --git a/libs/hwui/Program.cpp b/libs/hwui/Program.cpp
index 6e60808..86fc154 100644
--- a/libs/hwui/Program.cpp
+++ b/libs/hwui/Program.cpp
@@ -27,7 +27,6 @@ namespace uirenderer {
#define SHADER_SOURCE(name, source) const char* name = #source
-#include "shaders/drawColor.vert"
#include "shaders/drawColor.frag"
#include "shaders/drawTexture.vert"
@@ -127,7 +126,7 @@ GLuint Program::buildShader(const char* source, GLenum type) {
///////////////////////////////////////////////////////////////////////////////
DrawColorProgram::DrawColorProgram():
- Program(gDrawColorVertexShader, gDrawColorFragmentShader) {
+ Program(gDrawTextureVertexShader, gDrawColorFragmentShader) {
getAttribsAndUniforms();
}
@@ -138,6 +137,7 @@ DrawColorProgram::DrawColorProgram(const char* vertex, const char* fragment):
void DrawColorProgram::getAttribsAndUniforms() {
position = addAttrib("position");
+ texCoords = addAttrib("texCoords");
color = addUniform("color");
transform = addUniform("transform");
}
@@ -154,11 +154,13 @@ void DrawColorProgram::set(const mat4& projectionMatrix, const mat4& modelViewMa
void DrawColorProgram::use() {
Program::use();
glEnableVertexAttribArray(position);
+ glEnableVertexAttribArray(texCoords);
}
void DrawColorProgram::remove() {
Program::remove();
glDisableVertexAttribArray(position);
+ glDisableVertexAttribArray(texCoords);
}
///////////////////////////////////////////////////////////////////////////////
@@ -167,26 +169,21 @@ void DrawColorProgram::remove() {
DrawTextureProgram::DrawTextureProgram():
DrawColorProgram(gDrawTextureVertexShader, gDrawTextureFragmentShader) {
- texCoords = addAttrib("texCoords");
sampler = addUniform("sampler");
}
DrawTextureProgram::DrawTextureProgram(const char* vertex, const char* fragment):
DrawColorProgram(vertex, fragment) {
- texCoords = addAttrib("texCoords");
sampler = addUniform("sampler");
}
void DrawTextureProgram::use() {
DrawColorProgram::use();
- glActiveTexture(GL_TEXTURE0);
glUniform1i(sampler, 0);
- glEnableVertexAttribArray(texCoords);
}
void DrawTextureProgram::remove() {
DrawColorProgram::remove();
- glDisableVertexAttribArray(texCoords);
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h
index 824aa05..2cdd905 100644
--- a/libs/hwui/Program.h
+++ b/libs/hwui/Program.h
@@ -53,6 +53,16 @@ public:
virtual void remove();
/**
+ * Returns the OpenGL name of the specified attribute.
+ */
+ int getAttrib(const char* name);
+
+ /**
+ * Returns the OpenGL name of the specified uniform.
+ */
+ int getUniform(const char* name);
+
+ /**
* Indicates whether this program is currently in use with
* the GL context.
*/
@@ -67,10 +77,6 @@ protected:
* @return The OpenGL name of the attribute.
*/
int addAttrib(const char* name);
- /**
- * Returns the OpenGL name of the specified attribute.
- */
- int getAttrib(const char* name);
/**
* Adds a uniform with the specified name.
@@ -78,10 +84,6 @@ protected:
* @return The OpenGL name of the uniform.
*/
int addUniform(const char* name);
- /**
- * Returns the OpenGL name of the specified uniform.
- */
- int getUniform(const char* name);
private:
/**
@@ -145,6 +147,11 @@ public:
int position;
/**
+ * Name of the texture coordinates attribute.
+ */
+ int texCoords;
+
+ /**
* Name of the color uniform.
*/
int color;
@@ -184,11 +191,6 @@ public:
* Name of the texture sampler uniform.
*/
int sampler;
-
- /**
- * Name of the texture coordinates attribute.
- */
- int texCoords;
};
class DrawTextProgram: public DrawTextureProgram {
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
new file mode 100644
index 0000000..5a89eb6
--- /dev/null
+++ b/libs/hwui/ProgramCache.cpp
@@ -0,0 +1,332 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "OpenGLRenderer"
+
+#include <utils/String8.h>
+
+#include "ProgramCache.h"
+
+namespace android {
+namespace uirenderer {
+
+///////////////////////////////////////////////////////////////////////////////
+// Vertex shaders snippets
+///////////////////////////////////////////////////////////////////////////////
+
+// TODO: Implement BitmapShader, implement repeat/mirror for npot
+
+const char* gVS_Header_Attributes =
+ "attribute vec4 position;\n";
+const char* gVS_Header_Attributes_TexCoords =
+ "attribute vec2 texCoords;\n";
+const char* gVS_Header_Uniforms =
+ "uniform mat4 transform;\n";
+const char* gVS_Header_Uniforms_HasGradient =
+ "uniform float gradientLength;\n"
+ "uniform vec2 gradient;\n"
+ "uniform vec2 gradientStart;\n"
+ "uniform mat4 screenSpace;\n";
+const char* gVS_Header_Varyings_HasTexture =
+ "varying vec2 outTexCoords;\n";
+const char* gVS_Header_Varyings_HasBitmap =
+ "varying vec2 outBitmapTexCoords;\n";
+const char* gVS_Header_Varyings_HasGradient =
+ "varying float index;\n";
+const char* gVS_Main =
+ "\nvoid main(void) {\n";
+const char* gVS_Main_OutTexCoords =
+ " outTexCoords = texCoords;\n";
+const char* gVS_Main_OutGradientIndex =
+ " vec4 location = screenSpace * position;\n"
+ " index = dot(location.xy - gradientStart, gradient) * gradientLength;\n";
+const char* gVS_Main_Position =
+ " gl_Position = transform * position;\n";
+const char* gVS_Footer =
+ "}\n\n";
+
+///////////////////////////////////////////////////////////////////////////////
+// Fragment shaders snippets
+///////////////////////////////////////////////////////////////////////////////
+
+const char* gFS_Header =
+ "precision mediump float;\n\n";
+const char* gFS_Uniforms_Color =
+ "uniform vec4 color;\n";
+const char* gFS_Uniforms_TextureSampler =
+ "uniform sampler2D sampler;\n";
+const char* gFS_Uniforms_GradientSampler =
+ "uniform sampler2D gradientSampler;\n";
+const char* gFS_Uniforms_BitmapSampler =
+ "uniform sampler2D bitmapSampler;\n";
+const char* gFS_Uniforms_ColorOp[4] = {
+ // None
+ "",
+ // Matrix
+ "uniform mat4 colorMatrix;\n"
+ "uniform vec4 colorMatrixVector;\n",
+ // Lighting
+ "uniform float lightingMul;\n"
+ "uniform float lightingAdd;\n",
+ // PorterDuff
+ "uniform vec4 colorBLend;\n"
+};
+const char* gFS_Main =
+ "\nvoid main(void) {\n"
+ " vec4 fragColor;\n";
+const char* gFS_Main_FetchColor =
+ " fragColor = color;\n";
+const char* gFS_Main_FetchTexture =
+ " fragColor = color * texture2D(sampler, outTexCoords);\n";
+const char* gFS_Main_FetchA8Texture =
+ " fragColor = color * texture2D(sampler, outTexCoords).a;\n";
+const char* gFS_Main_FetchGradient =
+ " vec4 gradientColor = texture2D(gradientSampler, vec2(index, 0.5));\n";
+const char* gFS_Main_FetchBitmap =
+ " vec4 bitmapColor = texture2D(bitmapSampler, outBitmapTexCoords);\n";
+const char* gFS_Main_BlendShadersBG =
+ " fragColor = blendShaders(bitmapColor, gradientColor)";
+const char* gFS_Main_BlendShadersGB =
+ " fragColor = blendShaders(gradientColor, bitmapColor)";
+const char* gFS_Main_BlendShaders_Modulate =
+ " * fragColor.a;\n";
+const char* gFS_Main_FragColor =
+ " gl_FragColor = fragColor;\n";
+const char* gFS_Main_ApplyColorOp[4] = {
+ // None
+ "",
+ // Matrix
+ " fragColor *= colorMatrix;\n"
+ " fragColor += colorMatrixVector;\n",
+ // Lighting
+ " fragColor *= lightingMul;\n"
+ " fragColor += lightingAdd;\n",
+ // PorterDuff
+ " fragColor = blendColors(colorBlend, fragColor);\n"
+};
+const char* gFS_Footer =
+ "}\n\n";
+
+///////////////////////////////////////////////////////////////////////////////
+// PorterDuff snippets
+///////////////////////////////////////////////////////////////////////////////
+
+const char* gPorterDuff[12] = {
+ // Clear
+ "return vec4(0.0, 0.0, 0.0, 0.0);\n",
+ // Src
+ "return src;\n",
+ // Dst
+ "return dst;\n",
+ // SrcOver
+ "return vec4(src.rgb + (1.0 - src.a) * dst.rgb, src.a + dst.a - src.a * dst.a);\n",
+ // DstOver
+ "return vec4(dst.rgb + (1.0 - dst.a) * src.rgb, src.a + dst.a - src.a * dst.a);\n",
+ // SrcIn
+ "return vec4(src.rgb * dst.a, src.a * dst.a);\n",
+ // DstIn
+ "return vec4(dst.rgb * src.a, src.a * dst.a);\n",
+ // SrcOut
+ "return vec4(src.rgb * (1.0 - dst.a), src.a * (1.0 - dst.a));\n",
+ // DstOut
+ "return vec4(dst.rgb * (1.0 - src.a), dst.a * (1.0 - src.a));\n",
+ // SrcAtop
+ "return vec4(src.rgb * dst.a + (1.0 - src.a) * dst.rgb, dst.a);\n",
+ // DstAtop
+ "return vec4(dst.rgb * src.a + (1.0 - dst.a) * src.rgb, src.a);\n",
+ // Xor
+ "return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb, "
+ "src.a + dst.a - 2.0 * src.a * dst.a);\n",
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Constructors/destructors
+///////////////////////////////////////////////////////////////////////////////
+
+ProgramCache::ProgramCache() {
+}
+
+ProgramCache::~ProgramCache() {
+ clear();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Cache management
+///////////////////////////////////////////////////////////////////////////////
+
+void ProgramCache::clear() {
+ size_t count = mCache.size();
+ for (size_t i = 0; i < count; i++) {
+ delete mCache.valueAt(i);
+ }
+ mCache.clear();
+}
+
+Program* ProgramCache::get(const ProgramDescription& description) {
+ programid key = description.key();
+ ssize_t index = mCache.indexOfKey(key);
+ Program* program = NULL;
+ if (index < 0) {
+ PROGRAM_LOGD("Could not find program with key 0x%x", key);
+ program = generateProgram(description, key);
+ mCache.add(key, program);
+ } else {
+ program = mCache.valueAt(index);
+ }
+ return program;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Program generation
+///////////////////////////////////////////////////////////////////////////////
+
+Program* ProgramCache::generateProgram(const ProgramDescription& description, programid key) {
+ String8 vertexShader = generateVertexShader(description);
+ String8 fragmentShader = generateFragmentShader(description);
+
+ Program* program = new Program(vertexShader.string(), fragmentShader.string());
+ return program;
+}
+
+String8 ProgramCache::generateVertexShader(const ProgramDescription& description) {
+ // Add attributes
+ String8 shader(gVS_Header_Attributes);
+ if (description.hasTexture || description.hasBitmap) {
+ shader.append(gVS_Header_Attributes_TexCoords);
+ }
+ // Uniforms
+ shader.append(gVS_Header_Uniforms);
+ if (description.hasGradient) {
+ shader.append(gVS_Header_Uniforms_HasGradient);
+ }
+ // Varyings
+ if (description.hasTexture) {
+ shader.append(gVS_Header_Varyings_HasTexture);
+ }
+ if (description.hasGradient) {
+ shader.append(gVS_Header_Varyings_HasGradient);
+ }
+ if (description.hasBitmap) {
+ shader.append(gVS_Header_Varyings_HasBitmap);
+ }
+
+ // Begin the shader
+ shader.append(gVS_Main); {
+ if (description.hasTexture) {
+ shader.append(gVS_Main_OutTexCoords);
+ }
+ if (description.hasGradient) {
+ shader.append(gVS_Main_OutGradientIndex);
+ }
+ // Output transformed position
+ shader.append(gVS_Main_Position);
+ }
+ // End the shader
+ shader.append(gVS_Footer);
+
+ PROGRAM_LOGD("*** Generated vertex shader:\n\n%s", shader.string());
+
+ return shader;
+}
+
+String8 ProgramCache::generateFragmentShader(const ProgramDescription& description) {
+ // Set the default precision
+ String8 shader(gFS_Header);
+
+ // Varyings
+ if (description.hasTexture) {
+ shader.append(gVS_Header_Varyings_HasTexture);
+ }
+ if (description.hasGradient) {
+ shader.append(gVS_Header_Varyings_HasGradient);
+ }
+ if (description.hasBitmap) {
+ shader.append(gVS_Header_Varyings_HasBitmap);
+ }
+
+
+ // Uniforms
+ shader.append(gFS_Uniforms_Color);
+ if (description.hasTexture) {
+ shader.append(gFS_Uniforms_TextureSampler);
+ }
+ if (description.hasGradient) {
+ shader.append(gFS_Uniforms_GradientSampler);
+ }
+ if (description.hasBitmap) {
+ shader.append(gFS_Uniforms_BitmapSampler);
+ }
+ shader.append(gFS_Uniforms_ColorOp[description.colorOp]);
+
+ // Generate required functions
+ if (description.hasGradient && description.hasBitmap) {
+ generatePorterDuffBlend(shader, "blendShaders", description.shadersMode);
+ }
+ if (description.colorOp == ProgramDescription::kColorBlend) {
+ generatePorterDuffBlend(shader, "blendColors", description.colorMode);
+ }
+
+ // Begin the shader
+ shader.append(gFS_Main); {
+ // Stores the result in fragColor directly
+ if (description.hasTexture) {
+ if (description.hasAlpha8Texture) {
+ shader.append(gFS_Main_FetchA8Texture);
+ } else {
+ shader.append(gFS_Main_FetchTexture);
+ }
+ } else {
+ shader.append(gFS_Main_FetchColor);
+ }
+ if (description.hasGradient) {
+ shader.append(gFS_Main_FetchGradient);
+ }
+ if (description.hasBitmap) {
+ shader.append(gFS_Main_FetchBitmap);
+ }
+ // Case when we have two shaders set
+ if (description.hasGradient && description.hasBitmap) {
+ if (description.isBitmapFirst) {
+ shader.append(gFS_Main_BlendShadersBG);
+ } else {
+ shader.append(gFS_Main_BlendShadersGB);
+ }
+ shader.append(gFS_Main_BlendShaders_Modulate);
+ }
+ // Apply the color op if needed
+ shader.append(gFS_Main_ApplyColorOp[description.colorOp]);
+ // Output the fragment
+ shader.append(gFS_Main_FragColor);
+ }
+ // End the shader
+ shader.append(gFS_Footer);
+
+ PROGRAM_LOGD("*** Generated fragment shader:\n\n%s", shader.string());
+ return shader;
+}
+
+void ProgramCache::generatePorterDuffBlend(String8& shader, const char* name,
+ SkXfermode::Mode mode) {
+ shader.append("\nvec4 ");
+ shader.append(name);
+ shader.append("(vec4 src, vec4 dst) {\n");
+ shader.append(" ");
+ shader.append(gPorterDuff[mode]);
+ shader.append("}\n");
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/ProgramCache.h b/libs/hwui/ProgramCache.h
new file mode 100644
index 0000000..7f2f5fa
--- /dev/null
+++ b/libs/hwui/ProgramCache.h
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_UI_PROGRAM_CACHE_H
+#define ANDROID_UI_PROGRAM_CACHE_H
+
+#include <utils/KeyedVector.h>
+#include <utils/Log.h>
+
+#include <SkXfermode.h>
+
+#include "Program.h"
+
+namespace android {
+namespace uirenderer {
+
+///////////////////////////////////////////////////////////////////////////////
+// Defines
+///////////////////////////////////////////////////////////////////////////////
+
+// Debug
+#define DEBUG_PROGRAM_CACHE 0
+
+// Debug
+#if DEBUG_PROGRAM_CACHE
+ #define PROGRAM_LOGD(...) LOGD(__VA_ARGS__)
+#else
+ #define PROGRAM_LOGD(...)
+#endif
+
+#define PROGRAM_KEY_TEXTURE 0x1
+#define PROGRAM_KEY_A8_TEXTURE 0x2
+#define PROGRAM_KEY_BITMAP 0x4
+#define PROGRAM_KEY_GRADIENT 0x8
+#define PROGRAM_KEY_BITMAP_FIRST 0x10
+#define PROGRAM_KEY_COLOR_MATRIX 0x20
+#define PROGRAM_KEY_COLOR_LIGHTING 0x40
+#define PROGRAM_KEY_COLOR_BLEND 0x80
+
+// Support only the 12 Porter-Duff modes for now
+#define PROGRAM_MAX_XFERMODE 0xC
+#define PROGRAM_XFERMODE_SHADER_SHIFT 24
+#define PROGRAM_XFERMODE_COLOR_OP_SHIFT 20
+
+///////////////////////////////////////////////////////////////////////////////
+// Types
+///////////////////////////////////////////////////////////////////////////////
+
+typedef uint32_t programid;
+
+///////////////////////////////////////////////////////////////////////////////
+// Cache
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Describe the features required for a given program. The features
+ * determine the generation of both the vertex and fragment shaders.
+ * A ProgramDescription must be used in conjunction with a ProgramCache.
+ */
+struct ProgramDescription {
+ enum ColorModifier {
+ kColorNone,
+ kColorMatrix,
+ kColorLighting,
+ kColorBlend
+ };
+
+ ProgramDescription():
+ hasTexture(false), hasAlpha8Texture(false),
+ hasBitmap(false), hasGradient(false), shadersMode(SkXfermode::kClear_Mode),
+ colorOp(kColorNone), colorMode(SkXfermode::kClear_Mode) {
+ }
+
+ // Texturing
+ bool hasTexture;
+ bool hasAlpha8Texture;
+
+ // Shaders
+ bool hasBitmap;
+ bool hasGradient;
+ SkXfermode::Mode shadersMode;
+ bool isBitmapFirst;
+
+ // Color operations
+ int colorOp;
+ SkXfermode::Mode colorMode;
+
+ programid key() const {
+ programid key = 0;
+ if (hasTexture) key |= PROGRAM_KEY_TEXTURE;
+ if (hasAlpha8Texture) key |= PROGRAM_KEY_A8_TEXTURE;
+ if (hasBitmap) key |= PROGRAM_KEY_BITMAP;
+ if (hasGradient) key |= PROGRAM_KEY_GRADIENT;
+ if (isBitmapFirst) key |= PROGRAM_KEY_BITMAP_FIRST;
+ if (hasBitmap && hasGradient) {
+ key |= (shadersMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_SHADER_SHIFT;
+ }
+ switch (colorOp) {
+ case kColorMatrix:
+ key |= PROGRAM_KEY_COLOR_MATRIX;
+ break;
+ case kColorLighting:
+ key |= PROGRAM_KEY_COLOR_LIGHTING;
+ break;
+ case kColorBlend:
+ key |= PROGRAM_KEY_COLOR_BLEND;
+ key |= (colorMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_COLOR_OP_SHIFT;
+ break;
+ case kColorNone:
+ break;
+ }
+ return key;
+ }
+}; // struct ProgramDescription
+
+/**
+ * Generates and caches program. Programs are generated based on
+ * ProgramDescriptions.
+ */
+class ProgramCache {
+public:
+ ProgramCache();
+ ~ProgramCache();
+
+ Program* get(const ProgramDescription& description);
+
+ void clear();
+
+private:
+ Program* generateProgram(const ProgramDescription& description, programid key);
+ String8 generateVertexShader(const ProgramDescription& description);
+ String8 generateFragmentShader(const ProgramDescription& description);
+ void generatePorterDuffBlend(String8& shader, const char* name, SkXfermode::Mode mode);
+
+ KeyedVector<programid, Program*> mCache;
+
+}; // class ProgramCache
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_UI_PROGRAM_CACHE_H
diff --git a/libs/hwui/Vertex.h b/libs/hwui/Vertex.h
index ffd0633..1f54086 100644
--- a/libs/hwui/Vertex.h
+++ b/libs/hwui/Vertex.h
@@ -21,14 +21,6 @@ namespace android {
namespace uirenderer {
/**
- * Simple structure to describe a vertex with a position.
- * This is used to draw filled rectangles without a texture.
- */
-struct SimpleVertex {
- float position[2];
-}; // struct SimpleVertex
-
-/**
* Simple structure to describe a vertex with a position and a texture.
*/
struct TextureVertex {
diff --git a/libs/hwui/shaders/drawColor.vert b/libs/hwui/shaders/drawColor.vert
deleted file mode 100644
index 20e2636..0000000
--- a/libs/hwui/shaders/drawColor.vert
+++ /dev/null
@@ -1,11 +0,0 @@
-SHADER_SOURCE(gDrawColorVertexShader,
-
-attribute vec4 position;
-
-uniform mat4 transform;
-
-void main(void) {
- gl_Position = transform * position;
-}
-
-);
diff --git a/libs/hwui/shaders/drawLinearGradient.vert b/libs/hwui/shaders/drawLinearGradient.vert
index f5c669b..d2f857d 100644
--- a/libs/hwui/shaders/drawLinearGradient.vert
+++ b/libs/hwui/shaders/drawLinearGradient.vert
@@ -2,10 +2,10 @@ SHADER_SOURCE(gDrawLinearGradientVertexShader,
attribute vec4 position;
+uniform mat4 transform;
uniform float gradientLength;
uniform vec2 gradient;
uniform vec2 start;
-uniform mat4 transform;
uniform mat4 screenSpace;
varying float index;