Optimize GLSL shaders.

Change-Id: I9a5e01bced63d8da0c61330a543a2b805388a59d
This commit is contained in:
Romain Guy
2010-10-11 16:34:59 -07:00
parent 7537f856f9
commit 707b2f78cc
6 changed files with 221 additions and 43 deletions

View File

@@ -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)) {

View File

@@ -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");

View File

@@ -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;

View File

@@ -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.
*/

View File

@@ -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

View File

@@ -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
/**