Optimize GLSL shaders.
Change-Id: I9a5e01bced63d8da0c61330a543a2b805388a59d
This commit is contained in:
@@ -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)) {
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user