diff options
author | Romain Guy <romainguy@google.com> | 2010-07-27 17:39:27 -0700 |
---|---|---|
committer | Romain Guy <romainguy@google.com> | 2010-07-27 19:52:29 -0700 |
commit | ac670c0433d19397d4e36ced2110475b6f54fe26 (patch) | |
tree | 10722cd4e465fc053f9536cc312c1125a694108a /libs | |
parent | bb2b2a996b2c0bea7e434136e20340f4f1b398ab (diff) | |
download | frameworks_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.mk | 1 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.cpp | 57 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.h | 6 | ||||
-rw-r--r-- | libs/hwui/Program.cpp | 11 | ||||
-rw-r--r-- | libs/hwui/Program.h | 28 | ||||
-rw-r--r-- | libs/hwui/ProgramCache.cpp | 332 | ||||
-rw-r--r-- | libs/hwui/ProgramCache.h | 155 | ||||
-rw-r--r-- | libs/hwui/Vertex.h | 8 | ||||
-rw-r--r-- | libs/hwui/shaders/drawColor.vert | 11 | ||||
-rw-r--r-- | libs/hwui/shaders/drawLinearGradient.vert | 2 |
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; |