diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java index 7c4897ad141dd..b5e103ff243ba 100644 --- a/core/java/android/widget/ListView.java +++ b/core/java/android/widget/ListView.java @@ -26,7 +26,6 @@ import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.Rect; -import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.util.SparseBooleanArray; @@ -2980,7 +2979,6 @@ public class ListView extends AbsListView { if (!mStackFromBottom) { int bottom; - final int scrollY = mScrollY; for (int i = 0; i < count; i++) { if ((headerDividers || first + i >= headerCount) && (footerDividers || first + i < footerLimit)) { diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 5b226b4eb3b4c..4878063d689c6 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -985,6 +985,7 @@ void OpenGLRenderer::setupTextureAlpha8(GLuint texture, uint32_t width, uint32_t ProgramDescription description; description.hasTexture = true; description.hasAlpha8Texture = true; + const bool setColor = description.setAlpha8Color(r, g, b, a); if (applyFilters) { if (mShader) { @@ -1021,7 +1022,9 @@ void OpenGLRenderer::setupTextureAlpha8(GLuint texture, uint32_t width, uint32_t mModelView.loadIdentity(); } mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform); - glUniform4f(mCaches.currentProgram->color, r, g, b, a); + if (setColor) { + mCaches.currentProgram->setColor(r, g, b, a); + } textureUnit++; if (applyFilters) { @@ -1126,6 +1129,8 @@ void OpenGLRenderer::setupColorRect(float left, float top, float right, float bo // Describe the required shaders ProgramDescription description; + const bool setColor = description.setColor(r, g, b, a); + if (mShader) { mShader->describe(description, mExtensions); } @@ -1152,7 +1157,7 @@ void OpenGLRenderer::setupColorRect(float left, float top, float right, float bo mat4 identity; mCaches.currentProgram->set(mOrthoMatrix, mModelView, identity); } - glUniform4f(mCaches.currentProgram->color, r, g, b, a); + mCaches.currentProgram->setColor(r, g, b, a); // Setup attributes and uniforms required by the shaders if (mShader) { @@ -1189,6 +1194,7 @@ void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float b ProgramDescription description; description.hasTexture = true; + const bool setColor = description.setColor(alpha, alpha, alpha, alpha); if (mColorFilter) { mColorFilter->describe(description, mExtensions); } @@ -1211,7 +1217,9 @@ void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float b glUniform1i(mCaches.currentProgram->getUniform("sampler"), 0); // Always premultiplied - glUniform4f(mCaches.currentProgram->color, alpha, alpha, alpha, alpha); + if (setColor) { + mCaches.currentProgram->setColor(alpha, alpha, alpha, alpha); + } // Mesh int texCoordsSlot = mCaches.currentProgram->getAttrib("texCoords"); diff --git a/libs/hwui/Program.cpp b/libs/hwui/Program.cpp index 2e1b9a073e3d4..25674c65f926c 100644 --- a/libs/hwui/Program.cpp +++ b/libs/hwui/Program.cpp @@ -58,7 +58,6 @@ Program::Program(const char* vertex, const char* fragment) { mUse = false; position = addAttrib("position"); - color = addUniform("color"); transform = addUniform("transform"); } @@ -124,6 +123,10 @@ void Program::set(const mat4& projectionMatrix, const mat4& modelViewMatrix, glUniformMatrix4fv(transform, 1, GL_FALSE, &t.data[0]); } +void Program::setColor(const float r, const float g, const float b, const float a) { + glUniform4f(getUniform("color"), r, g, b, a); +} + void Program::use() { glUseProgram(id); mUse = true; diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h index 6531c74865913..026097c7cbe24 100644 --- a/libs/hwui/Program.h +++ b/libs/hwui/Program.h @@ -76,16 +76,16 @@ public: void set(const mat4& projectionMatrix, const mat4& modelViewMatrix, const mat4& transformMatrix); + /** + * Sets the color associated with this shader. + */ + void setColor(const float r, const float g, const float b, const float a); + /** * Name of the position attribute. */ int position; - /** - * Name of the color uniform. - */ - int color; - /** * Name of the transform uniform. */ diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp index 63e92a51df566..1282b7102788c 100644 --- a/libs/hwui/ProgramCache.cpp +++ b/libs/hwui/ProgramCache.cpp @@ -23,6 +23,14 @@ namespace android { namespace uirenderer { +/////////////////////////////////////////////////////////////////////////////// +// Defines +/////////////////////////////////////////////////////////////////////////////// + +#define MODULATE_OP_NO_MODULATE 0 +#define MODULATE_OP_MODULATE 1 +#define MODULATE_OP_MODULATE_A8 2 + /////////////////////////////////////////////////////////////////////////////// // Vertex shaders snippets /////////////////////////////////////////////////////////////////////////////// @@ -69,8 +77,7 @@ const char* gVS_Main_OutGradient[3] = { " sweep = (screenSpace * position).xy;\n" }; const char* gVS_Main_OutBitmapTexCoords = - " vec4 bitmapCoords = textureTransform * position;\n" - " outBitmapTexCoords = bitmapCoords.xy * textureDimension;\n"; + " outBitmapTexCoords = (textureTransform * position).xy * textureDimension;\n"; const char* gVS_Main_Position = " gl_Position = transform * position;\n"; const char* gVS_Footer = @@ -113,12 +120,52 @@ const char* gFS_Uniforms_ColorOp[4] = { const char* gFS_Main = "\nvoid main(void) {\n" " lowp vec4 fragColor;\n"; + +// Fast cases +const char* gFS_Fast_SingleColor = + "\nvoid main(void) {\n" + " gl_FragColor = color;\n" + "}\n\n"; +const char* gFS_Fast_SingleTexture = + "\nvoid main(void) {\n" + " gl_FragColor = texture2D(sampler, outTexCoords);\n" + "}\n\n"; +const char* gFS_Fast_SingleModulateTexture = + "\nvoid main(void) {\n" + " gl_FragColor = color.a * texture2D(sampler, outTexCoords);\n" + "}\n\n"; +const char* gFS_Fast_SingleA8Texture = + "\nvoid main(void) {\n" + " gl_FragColor = vec4(0.0, 0.0, 0.0, texture2D(sampler, outTexCoords).a);\n" + "}\n\n"; +const char* gFS_Fast_SingleModulateA8Texture = + "\nvoid main(void) {\n" + " gl_FragColor = color * texture2D(sampler, outTexCoords).a;\n" + "}\n\n"; +const char* gFS_Fast_SingleGradient = + "\nvoid main(void) {\n" + " gl_FragColor = texture2D(gradientSampler, linear);\n" + "}\n\n"; +const char* gFS_Fast_SingleModulateGradient = + "\nvoid main(void) {\n" + " gl_FragColor = color.a * texture2D(gradientSampler, linear);\n" + "}\n\n"; + +// General case 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_FetchTexture[2] = { + // Don't modulate + " fragColor = texture2D(sampler, outTexCoords);\n", + // Modulate + " fragColor = color * texture2D(sampler, outTexCoords);\n" +}; +const char* gFS_Main_FetchA8Texture[2] = { + // Don't modulate + " fragColor = vec4(0.0, 0.0, 0.0, texture2D(sampler, outTexCoords).a);\n", + // Modulate + " fragColor = color * texture2D(sampler, outTexCoords).a;\n" +}; const char* gFS_Main_FetchGradient[3] = { // Linear " vec4 gradientColor = texture2D(gradientSampler, linear);\n", @@ -137,12 +184,30 @@ const char* gFS_Main_BlendShadersBG = " fragColor = blendShaders(gradientColor, bitmapColor)"; const char* gFS_Main_BlendShadersGB = " fragColor = blendShaders(bitmapColor, gradientColor)"; -const char* gFS_Main_BlendShaders_Modulate = - " * fragColor.a;\n"; -const char* gFS_Main_GradientShader_Modulate = - " fragColor = gradientColor * fragColor.a;\n"; -const char* gFS_Main_BitmapShader_Modulate = - " fragColor = bitmapColor * fragColor.a;\n"; +const char* gFS_Main_BlendShaders_Modulate[3] = { + // Don't modulate + ";\n", + // Modulate + " * fragColor.a;\n", + // Modulate with alpha 8 texture + " * texture2D(sampler, outTexCoords).a;\n" +}; +const char* gFS_Main_GradientShader_Modulate[3] = { + // Don't modulate + " fragColor = gradientColor;\n", + // Modulate + " fragColor = gradientColor * fragColor.a;\n", + // Modulate with alpha 8 texture + " fragColor = gradientColor * texture2D(sampler, outTexCoords).a;\n" + }; +const char* gFS_Main_BitmapShader_Modulate[3] = { + // Don't modulate + " fragColor = bitmapColor;\n", + // Modulate + " fragColor = bitmapColor * fragColor.a;\n", + // Modulate with alpha 8 texture + " fragColor = bitmapColor * texture2D(sampler, outTexCoords).a;\n" + }; const char* gFS_Main_FragColor = " gl_FragColor = fragColor;\n"; const char* gFS_Main_FragColor_Blend = @@ -317,7 +382,7 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti // Set the default precision String8 shader; - bool blendFramebuffer = description.framebufferMode >= SkXfermode::kPlus_Mode; + const bool blendFramebuffer = description.framebufferMode >= SkXfermode::kPlus_Mode; if (blendFramebuffer) { shader.append(gFS_Header_Extension_FramebufferFetch); } @@ -335,15 +400,72 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti shader.append(gVS_Header_Varyings_HasBitmap); } - // Uniforms - shader.append(gFS_Uniforms_Color); + int modulateOp = MODULATE_OP_NO_MODULATE; + const bool singleColor = !description.hasTexture && + !description.hasGradient && !description.hasBitmap; + + if (description.modulate || singleColor) { + shader.append(gFS_Uniforms_Color); + if (!singleColor) modulateOp = MODULATE_OP_MODULATE; + } if (description.hasTexture) { shader.append(gFS_Uniforms_TextureSampler); } if (description.hasGradient) { shader.append(gFS_Uniforms_GradientSampler[description.gradientType]); } + + // Optimization for common cases + if (!blendFramebuffer) { + bool fast = false; + + const bool noShader = !description.hasGradient && !description.hasBitmap; + const bool singleTexture = description.hasTexture && + !description.hasAlpha8Texture && noShader; + const bool singleA8Texture = description.hasTexture && + description.hasAlpha8Texture && noShader; + const bool singleGradient = !description.hasTexture && + description.hasGradient && !description.hasBitmap && + description.gradientType == ProgramDescription::kGradientLinear; + + if (singleColor) { + shader.append(gFS_Fast_SingleColor); + fast = true; + } else if (singleTexture) { + if (!description.modulate) { + shader.append(gFS_Fast_SingleTexture); + } else { + shader.append(gFS_Fast_SingleModulateTexture); + } + fast = true; + } else if (singleA8Texture) { + if (!description.modulate) { + shader.append(gFS_Fast_SingleA8Texture); + } else { + shader.append(gFS_Fast_SingleModulateA8Texture); + } + fast = true; + } else if (singleGradient) { + if (!description.modulate) { + shader.append(gFS_Fast_SingleGradient); + } else { + shader.append(gFS_Fast_SingleModulateGradient); + } + fast = true; + } + + if (fast) { + if (DEBUG_PROGRAM_CACHE) { + PROGRAM_LOGD("*** Fast case:\n"); + PROGRAM_LOGD("*** Generated fragment shader:\n\n"); + printLongString(shader); + } + + return shader; + } + } + if (description.hasBitmap) { shader.append(gFS_Uniforms_BitmapSampler); } @@ -368,12 +490,16 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti // Stores the result in fragColor directly if (description.hasTexture) { if (description.hasAlpha8Texture) { - shader.append(gFS_Main_FetchA8Texture); + if (!description.hasGradient && !description.hasBitmap) { + shader.append(gFS_Main_FetchA8Texture[modulateOp]); + } } else { - shader.append(gFS_Main_FetchTexture); + shader.append(gFS_Main_FetchTexture[modulateOp]); } } else { - shader.append(gFS_Main_FetchColor); + if ((!description.hasGradient && !description.hasBitmap) || description.modulate) { + shader.append(gFS_Main_FetchColor); + } } if (description.hasGradient) { shader.append(gFS_Main_FetchGradient[description.gradientType]); @@ -387,17 +513,20 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti } // Case when we have two shaders set if (description.hasGradient && description.hasBitmap) { + int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp; if (description.isBitmapFirst) { shader.append(gFS_Main_BlendShadersBG); } else { shader.append(gFS_Main_BlendShadersGB); } - shader.append(gFS_Main_BlendShaders_Modulate); + shader.append(gFS_Main_BlendShaders_Modulate[op]); } else { if (description.hasGradient) { - shader.append(gFS_Main_GradientShader_Modulate); + int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp; + shader.append(gFS_Main_GradientShader_Modulate[op]); } else if (description.hasBitmap) { - shader.append(gFS_Main_BitmapShader_Modulate); + int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp; + shader.append(gFS_Main_BitmapShader_Modulate[op]); } } // Apply the color op if needed diff --git a/libs/hwui/ProgramCache.h b/libs/hwui/ProgramCache.h index 4fa80111d358b..964d842ecc49d 100644 --- a/libs/hwui/ProgramCache.h +++ b/libs/hwui/ProgramCache.h @@ -44,6 +44,11 @@ namespace uirenderer { #define PROGRAM_LOGD(...) #endif +// TODO: This should be set in properties +#define PANEL_BIT_DEPTH 18 +#define COLOR_COMPONENT_THRESHOLD (1.0f - (0.5f / PANEL_BIT_DEPTH)) +#define COLOR_COMPONENT_INV_THRESHOLD (0.5f / PANEL_BIT_DEPTH) + #define PROGRAM_KEY_TEXTURE 0x1 #define PROGRAM_KEY_A8_TEXTURE 0x2 #define PROGRAM_KEY_BITMAP 0x4 @@ -68,6 +73,7 @@ namespace uirenderer { #define PROGRAM_BITMAP_WRAPT_SHIFT 11 #define PROGRAM_GRADIENT_TYPE_SHIFT 33 +#define PROGRAM_MODULATE 35 /////////////////////////////////////////////////////////////////////////////// // Types @@ -99,7 +105,7 @@ struct ProgramDescription { }; ProgramDescription(): - hasTexture(false), hasAlpha8Texture(false), + hasTexture(false), hasAlpha8Texture(false), modulate(false), hasBitmap(false), isBitmapNpot(false), hasGradient(false), gradientType(kGradientLinear), shadersMode(SkXfermode::kClear_Mode), isBitmapFirst(false), @@ -112,6 +118,9 @@ struct ProgramDescription { bool hasTexture; bool hasAlpha8Texture; + // Modulate, this should only be set when setColor() return true + bool modulate; + // Shaders bool hasBitmap; bool isBitmapNpot; @@ -134,18 +143,31 @@ struct ProgramDescription { SkXfermode::Mode framebufferMode; bool swapSrcDst; - inline uint32_t getEnumForWrap(GLenum wrap) const { - switch (wrap) { - case GL_CLAMP_TO_EDGE: - return 0; - case GL_REPEAT: - return 1; - case GL_MIRRORED_REPEAT: - return 2; - } - return 0; + /** + * Indicates, for a given color, whether color modulation is required in + * the fragment shader. When this method returns true, the program should + * be provided with a modulation color. + */ + bool setColor(const float r, const float g, const float b, const float a) { + modulate = a < COLOR_COMPONENT_THRESHOLD || r < COLOR_COMPONENT_THRESHOLD || + g < COLOR_COMPONENT_THRESHOLD || b < COLOR_COMPONENT_THRESHOLD; + return modulate; } + /** + * Indicates, for a given color, whether color modulation is required in + * the fragment shader. When this method returns true, the program should + * be provided with a modulation color. + */ + bool setAlpha8Color(const float r, const float g, const float b, const float a) { + modulate = a < COLOR_COMPONENT_THRESHOLD || r > COLOR_COMPONENT_INV_THRESHOLD || + g > COLOR_COMPONENT_INV_THRESHOLD || b > COLOR_COMPONENT_INV_THRESHOLD; + return modulate; + } + + /** + * Computes the unique key identifying this program. + */ programid key() const { programid key = 0; if (hasTexture) key |= PROGRAM_KEY_TEXTURE; @@ -180,14 +202,32 @@ struct ProgramDescription { } key |= (framebufferMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_FRAMEBUFFER_SHIFT; if (swapSrcDst) key |= PROGRAM_KEY_SWAP_SRC_DST; + if (modulate) key |= programid(0x1) << PROGRAM_MODULATE; return key; } + /** + * Logs the specified message followed by the key identifying this program. + */ void log(const char* message) const { programid k = key(); PROGRAM_LOGD("%s (key = 0x%.8x%.8x)", message, uint32_t(k >> 32), uint32_t(k & 0xffffffff)); } + +private: + inline uint32_t getEnumForWrap(GLenum wrap) const { + switch (wrap) { + case GL_CLAMP_TO_EDGE: + return 0; + case GL_REPEAT: + return 1; + case GL_MIRRORED_REPEAT: + return 2; + } + return 0; + } + }; // struct ProgramDescription /**