summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/jni/android/graphics/Shader.cpp46
-rw-r--r--libs/hwui/GradientCache.cpp140
-rw-r--r--libs/hwui/GradientCache.h41
-rw-r--r--libs/hwui/Program.h9
-rw-r--r--libs/hwui/ProgramCache.cpp72
-rw-r--r--libs/hwui/SkiaShader.cpp65
-rw-r--r--libs/hwui/SkiaShader.h9
-rw-r--r--opengl/java/android/opengl/Matrix.java4
-rw-r--r--tests/HwAccelerationTest/AndroidManifest.xml9
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/GradientStopsActivity.java116
10 files changed, 393 insertions, 118 deletions
diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp
index f4cc9e4..6323ab3 100644
--- a/core/jni/android/graphics/Shader.cpp
+++ b/core/jni/android/graphics/Shader.cpp
@@ -150,19 +150,35 @@ static SkiaShader* LinearGradient_postCreate1(JNIEnv* env, jobject o, SkShader*
jfloat* storedBounds = new jfloat[4];
storedBounds[0] = x0; storedBounds[1] = y0;
storedBounds[2] = x1; storedBounds[3] = y1;
- jfloat* storedPositions = new jfloat[count];
- uint32_t* storedColors = new uint32_t[count];
- for (size_t i = 0; i < count; i++) {
- storedColors[i] = static_cast<uint32_t>(colorValues[i]);
- }
+
+ bool missFirst = false;
+ bool missLast = false;
+ size_t stopCount = count;
+ jfloat* storedPositions = NULL;
if (posArray) {
AutoJavaFloatArray autoPos(env, posArray, count);
const float* posValues = autoPos.ptr();
- for (size_t i = 0; i < count; i++) {
- storedPositions[i] = posValues[i];
+
+ missFirst = posValues[0] != 0.0f;
+ missLast = posValues[count - 1] != 1.0f;
+
+ stopCount += missFirst + missLast;
+ storedPositions = new jfloat[stopCount];
+
+ if (missFirst) {
+ storedPositions[0] = 0.0f;
+ }
+
+ for (size_t i = missFirst; i < count + missFirst; i++) {
+ storedPositions[i] = posValues[i - missFirst];
+ }
+
+ if (missLast) {
+ storedPositions[stopCount - 1] = 1.0f;
}
} else {
+ storedPositions = new jfloat[count];
storedPositions[0] = 0.0f;
const jfloat step = 1.0f / (count - 1);
for (size_t i = 1; i < count - 1; i++) {
@@ -171,8 +187,22 @@ static SkiaShader* LinearGradient_postCreate1(JNIEnv* env, jobject o, SkShader*
storedPositions[count - 1] = 1.0f;
}
+ uint32_t* storedColors = new uint32_t[stopCount];
+
+ if (missFirst) {
+ storedColors[0] = static_cast<uint32_t>(colorValues[0]);
+ }
+
+ for (size_t i = missFirst; i < count + missFirst; i++) {
+ storedColors[i] = static_cast<uint32_t>(colorValues[i - missFirst]);
+ }
+
+ if (missLast) {
+ storedColors[stopCount - 1] = static_cast<uint32_t>(colorValues[count - 1]);
+ }
+
SkiaShader* skiaShader = new SkiaLinearGradientShader(storedBounds, storedColors,
- storedPositions, count, shader, static_cast<SkShader::TileMode>(tileMode), NULL,
+ storedPositions, stopCount, shader, static_cast<SkShader::TileMode>(tileMode), NULL,
(shader->getFlags() & SkShader::kOpaqueAlpha_Flag) == 0);
env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT);
diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp
index 7026eea..b1c4dfe 100644
--- a/libs/hwui/GradientCache.cpp
+++ b/libs/hwui/GradientCache.cpp
@@ -16,9 +16,6 @@
#define LOG_TAG "OpenGLRenderer"
-#include <SkCanvas.h>
-#include <SkGradientShader.h>
-
#include <utils/threads.h>
#include "Debug.h"
@@ -29,6 +26,22 @@ namespace android {
namespace uirenderer {
///////////////////////////////////////////////////////////////////////////////
+// Defines
+///////////////////////////////////////////////////////////////////////////////
+
+#define GRADIENT_TEXTURE_HEIGHT 2
+#define GRADIENT_BYTES_PER_PIXEL 4
+
+///////////////////////////////////////////////////////////////////////////////
+// Functions
+///////////////////////////////////////////////////////////////////////////////
+
+template<typename T>
+static inline T min(T a, T b) {
+ return a < b ? a : b;
+}
+
+///////////////////////////////////////////////////////////////////////////////
// Constructors/destructor
///////////////////////////////////////////////////////////////////////////////
@@ -83,7 +96,7 @@ void GradientCache::setMaxSize(uint32_t maxSize) {
void GradientCache::operator()(GradientCacheEntry& shader, Texture*& texture) {
if (texture) {
- const uint32_t size = texture->width * texture->height * 4;
+ const uint32_t size = texture->width * texture->height * GRADIENT_BYTES_PER_PIXEL;
mSize -= size;
}
@@ -97,14 +110,13 @@ void GradientCache::operator()(GradientCacheEntry& shader, Texture*& texture) {
// Caching
///////////////////////////////////////////////////////////////////////////////
-Texture* GradientCache::get(uint32_t* colors, float* positions,
- int count, SkShader::TileMode tileMode) {
+Texture* GradientCache::get(uint32_t* colors, float* positions, int count) {
- GradientCacheEntry gradient(colors, positions, count, tileMode);
+ GradientCacheEntry gradient(colors, positions, count);
Texture* texture = mCache.get(gradient);
if (!texture) {
- texture = addLinearGradient(gradient, colors, positions, count, tileMode);
+ texture = addLinearGradient(gradient, colors, positions, count);
}
return texture;
@@ -114,39 +126,41 @@ void GradientCache::clear() {
mCache.clear();
}
-Texture* GradientCache::addLinearGradient(GradientCacheEntry& gradient,
- uint32_t* colors, float* positions, int count, SkShader::TileMode tileMode) {
- int width = 256 * (count - 1);
- width = width < mMaxTextureSize ? width : mMaxTextureSize;
-
- SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, 4);
- bitmap.allocPixels();
- bitmap.eraseColor(0);
+void GradientCache::getGradientInfo(const uint32_t* colors, const int count,
+ GradientInfo& info) {
+ uint32_t width = 1 << (31 - __builtin_clz(256 * (count - 1)));
+ bool hasAlpha = false;
- SkCanvas canvas(bitmap);
+ for (int i = 0; i < count; i++) {
+ if (((colors[i] >> 24) & 0xff) < 255) {
+ hasAlpha = true;
+ break;
+ }
+ }
- SkPoint points[2];
- points[0].set(0.0f, 0.0f);
- points[1].set(bitmap.width(), 0.0f);
+ info.width = min(width, uint32_t(mMaxTextureSize));
+ info.hasAlpha = hasAlpha;
+}
- SkShader* localShader = SkGradientShader::CreateLinear(points,
- reinterpret_cast<const SkColor*>(colors), positions, count, tileMode);
+Texture* GradientCache::addLinearGradient(GradientCacheEntry& gradient,
+ uint32_t* colors, float* positions, int count) {
- SkPaint p;
- p.setStyle(SkPaint::kStrokeAndFill_Style);
- p.setShader(localShader)->unref();
+ GradientInfo info;
+ getGradientInfo(colors, count, info);
- canvas.drawRectCoords(0.0f, 0.0f, bitmap.width(), 4.0f, p);
+ Texture* texture = new Texture;
+ texture->width = info.width;
+ texture->height = GRADIENT_TEXTURE_HEIGHT;
+ texture->blend = info.hasAlpha;
+ texture->generation = 1;
// Asume the cache is always big enough
- const uint32_t size = bitmap.rowBytes() * bitmap.height();
+ const uint32_t size = texture->width * texture->height * GRADIENT_BYTES_PER_PIXEL;
while (mSize + size > mMaxSize) {
mCache.removeOldest();
}
- Texture* texture = new Texture;
- generateTexture(&bitmap, texture);
+ generateTexture(colors, positions, count, texture);
mSize += size;
mCache.put(gradient, texture);
@@ -154,25 +168,67 @@ Texture* GradientCache::addLinearGradient(GradientCacheEntry& gradient,
return texture;
}
-void GradientCache::generateTexture(SkBitmap* bitmap, Texture* texture) {
- SkAutoLockPixels autoLock(*bitmap);
- if (!bitmap->readyToDraw()) {
- ALOGE("Cannot generate texture from shader");
- return;
+void GradientCache::generateTexture(uint32_t* colors, float* positions,
+ int count, Texture* texture) {
+
+ const uint32_t width = texture->width;
+ const GLsizei rowBytes = width * GRADIENT_BYTES_PER_PIXEL;
+ uint32_t pixels[width * texture->height];
+
+ int currentPos = 1;
+
+ float startA = (colors[0] >> 24) & 0xff;
+ float startR = (colors[0] >> 16) & 0xff;
+ float startG = (colors[0] >> 8) & 0xff;
+ float startB = (colors[0] >> 0) & 0xff;
+
+ float endA = (colors[1] >> 24) & 0xff;
+ float endR = (colors[1] >> 16) & 0xff;
+ float endG = (colors[1] >> 8) & 0xff;
+ float endB = (colors[1] >> 0) & 0xff;
+
+ float start = positions[0];
+ float distance = positions[1] - start;
+
+ uint8_t* p = (uint8_t*) pixels;
+ for (uint32_t x = 0; x < width; x++) {
+ float pos = x / float(width - 1);
+ if (pos > positions[currentPos]) {
+ startA = endA;
+ startR = endR;
+ startG = endG;
+ startB = endB;
+ start = positions[currentPos];
+
+ currentPos++;
+
+ endA = (colors[currentPos] >> 24) & 0xff;
+ endR = (colors[currentPos] >> 16) & 0xff;
+ endG = (colors[currentPos] >> 8) & 0xff;
+ endB = (colors[currentPos] >> 0) & 0xff;
+ distance = positions[currentPos] - start;
+ }
+
+ float amount = (pos - start) / distance;
+ float oppAmount = 1.0f - amount;
+
+ *p++ = uint8_t(startR * oppAmount + endR * amount);
+ *p++ = uint8_t(startG * oppAmount + endG * amount);
+ *p++ = uint8_t(startB * oppAmount + endB * amount);
+ *p++ = uint8_t(startA * oppAmount + endA * amount);
}
- texture->generation = bitmap->getGenerationID();
- texture->width = bitmap->width();
- texture->height = bitmap->height();
+ for (int i = 1; i < GRADIENT_TEXTURE_HEIGHT; i++) {
+ memcpy(pixels + width * i, pixels, rowBytes);
+ }
glGenTextures(1, &texture->id);
glBindTexture(GL_TEXTURE_2D, texture->id);
- glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel());
+ glPixelStorei(GL_UNPACK_ALIGNMENT, GRADIENT_BYTES_PER_PIXEL);
- texture->blend = !bitmap->isOpaque();
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bitmap->rowBytesAsPixels(), texture->height, 0,
- GL_RGBA, GL_UNSIGNED_BYTE, bitmap->getPixels());
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, texture->height, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, pixels);
texture->setFilter(GL_LINEAR);
texture->setWrap(GL_CLAMP_TO_EDGE);
diff --git a/libs/hwui/GradientCache.h b/libs/hwui/GradientCache.h
index 59515a1..3b7c1fa 100644
--- a/libs/hwui/GradientCache.h
+++ b/libs/hwui/GradientCache.h
@@ -36,16 +36,14 @@ struct GradientCacheEntry {
count = 0;
colors = NULL;
positions = NULL;
- tileMode = SkShader::kClamp_TileMode;
}
- GradientCacheEntry(uint32_t* colors, float* positions, int count,
- SkShader::TileMode tileMode) {
- copy(colors, positions, count, tileMode);
+ GradientCacheEntry(uint32_t* colors, float* positions, int count) {
+ copy(colors, positions, count);
}
GradientCacheEntry(const GradientCacheEntry& entry) {
- copy(entry.colors, entry.positions, entry.count, entry.tileMode);
+ copy(entry.colors, entry.positions, entry.count);
}
~GradientCacheEntry() {
@@ -58,7 +56,7 @@ struct GradientCacheEntry {
delete[] colors;
delete[] positions;
- copy(entry.colors, entry.positions, entry.count, entry.tileMode);
+ copy(entry.colors, entry.positions, entry.count);
}
return *this;
@@ -67,13 +65,11 @@ struct GradientCacheEntry {
bool operator<(const GradientCacheEntry& r) const {
const GradientCacheEntry& rhs = (const GradientCacheEntry&) r;
LTE_INT(count) {
- LTE_INT(tileMode) {
- int result = memcmp(colors, rhs.colors, count * sizeof(uint32_t));
- if (result< 0) return true;
- else if (result == 0) {
- result = memcmp(positions, rhs.positions, count * sizeof(float));
- if (result < 0) return true;
- }
+ int result = memcmp(colors, rhs.colors, count * sizeof(uint32_t));
+ if (result< 0) return true;
+ else if (result == 0) {
+ result = memcmp(positions, rhs.positions, count * sizeof(float));
+ if (result < 0) return true;
}
}
return false;
@@ -86,11 +82,10 @@ struct GradientCacheEntry {
private:
- void copy(uint32_t* colors, float* positions, int count, SkShader::TileMode tileMode) {
+ void copy(uint32_t* colors, float* positions, int count) {
this->count = count;
this->colors = new uint32_t[count];
this->positions = new float[count];
- this->tileMode = tileMode;
memcpy(this->colors, colors, count * sizeof(uint32_t));
memcpy(this->positions, positions, count * sizeof(float));
@@ -118,8 +113,8 @@ public:
/**
* Returns the texture associated with the specified shader.
*/
- Texture* get(uint32_t* colors, float* positions,
- int count, SkShader::TileMode tileMode = SkShader::kClamp_TileMode);
+ Texture* get(uint32_t* colors, float* positions, int count);
+
/**
* Clears the cache. This causes all textures to be deleted.
*/
@@ -144,10 +139,16 @@ private:
* returned.
*/
Texture* addLinearGradient(GradientCacheEntry& gradient,
- uint32_t* colors, float* positions, int count,
- SkShader::TileMode tileMode = SkShader::kClamp_TileMode);
+ uint32_t* colors, float* positions, int count);
+
+ void generateTexture(uint32_t* colors, float* positions, int count, Texture* texture);
+
+ struct GradientInfo {
+ uint32_t width;
+ bool hasAlpha;
+ };
- void generateTexture(SkBitmap* bitmap, Texture* texture);
+ void getGradientInfo(const uint32_t* colors, const int count, GradientInfo& info);
GenerationCache<GradientCacheEntry, Texture*> mCache;
diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h
index 491767f..1818f82 100644
--- a/libs/hwui/Program.h
+++ b/libs/hwui/Program.h
@@ -79,6 +79,8 @@ namespace uirenderer {
#define PROGRAM_HAS_GAMMA_CORRECTION 40
+#define PROGRAM_IS_SIMPLE_GRADIENT 41
+
///////////////////////////////////////////////////////////////////////////////
// Types
///////////////////////////////////////////////////////////////////////////////
@@ -96,14 +98,14 @@ typedef uint64_t programid;
*/
struct ProgramDescription {
enum ColorModifier {
- kColorNone,
+ kColorNone = 0,
kColorMatrix,
kColorLighting,
kColorBlend
};
enum Gradient {
- kGradientLinear,
+ kGradientLinear = 0,
kGradientCircular,
kGradientSweep
};
@@ -129,6 +131,7 @@ struct ProgramDescription {
bool hasGradient;
Gradient gradientType;
+ bool isSimpleGradient;
SkXfermode::Mode shadersMode;
@@ -170,6 +173,7 @@ struct ProgramDescription {
hasGradient = false;
gradientType = kGradientLinear;
+ isSimpleGradient = false;
shadersMode = SkXfermode::kClear_Mode;
@@ -255,6 +259,7 @@ struct ProgramDescription {
if (hasExternalTexture) key |= programid(0x1) << PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT;
if (hasTextureTransform) key |= programid(0x1) << PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT;
if (hasGammaCorrection) key |= programid(0x1) << PROGRAM_HAS_GAMMA_CORRECTION;
+ if (isSimpleGradient) key |= programid(0x1) << PROGRAM_IS_SIMPLE_GRADIENT;
return key;
}
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index 70bd1a8..d601f01 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -71,13 +71,16 @@ const char* gVS_Header_Varyings_PointHasBitmap =
"varying highp vec2 outPointBitmapTexCoords;\n";
// TODO: These values are used to sample from textures,
// they may need to be highp
-const char* gVS_Header_Varyings_HasGradient[3] = {
+const char* gVS_Header_Varyings_HasGradient[6] = {
// Linear
"varying highp vec2 linear;\n",
+ "varying highp float linear;\n",
// Circular
"varying highp vec2 circular;\n",
+ "varying highp vec2 circular;\n",
// Sweep
- "varying highp vec2 sweep;\n"
+ "varying highp vec2 sweep;\n",
+ "varying highp vec2 sweep;\n",
};
const char* gVS_Main =
"\nvoid main(void) {\n";
@@ -85,13 +88,16 @@ const char* gVS_Main_OutTexCoords =
" outTexCoords = texCoords;\n";
const char* gVS_Main_OutTransformedTexCoords =
" outTexCoords = (mainTextureTransform * vec4(texCoords, 0.0, 1.0)).xy;\n";
-const char* gVS_Main_OutGradient[3] = {
+const char* gVS_Main_OutGradient[6] = {
// Linear
" linear = vec2((screenSpace * position).x, 0.5);\n",
+ " linear = (screenSpace * position).x;\n",
// Circular
" circular = (screenSpace * position).xy;\n",
+ " circular = (screenSpace * position).xy;\n",
// Sweep
- " sweep = (screenSpace * position).xy;\n"
+ " sweep = (screenSpace * position).xy;\n",
+ " sweep = (screenSpace * position).xy;\n",
};
const char* gVS_Main_OutBitmapTexCoords =
" outBitmapTexCoords = (textureTransform * position).xy * textureDimension;\n";
@@ -131,13 +137,19 @@ const char* gFS_Uniforms_TextureSampler =
"uniform sampler2D sampler;\n";
const char* gFS_Uniforms_ExternalTextureSampler =
"uniform samplerExternalOES sampler;\n";
-const char* gFS_Uniforms_GradientSampler[3] = {
+const char* gFS_Uniforms_GradientSampler[6] = {
// Linear
"uniform sampler2D gradientSampler;\n",
+ "uniform vec4 startColor;\n"
+ "uniform vec4 endColor;\n",
// Circular
"uniform sampler2D gradientSampler;\n",
+ "uniform vec4 startColor;\n"
+ "uniform vec4 endColor;\n",
// Sweep
- "uniform sampler2D gradientSampler;\n"
+ "uniform sampler2D gradientSampler;\n",
+ "uniform vec4 startColor;\n"
+ "uniform vec4 endColor;\n",
};
const char* gFS_Uniforms_BitmapSampler =
"uniform sampler2D bitmapSampler;\n";
@@ -193,14 +205,22 @@ const char* gFS_Fast_SingleModulateA8Texture_ApplyGamma =
"\nvoid main(void) {\n"
" gl_FragColor = color * pow(texture2D(sampler, outTexCoords).a, gamma);\n"
"}\n\n";
-const char* gFS_Fast_SingleGradient =
+const char* gFS_Fast_SingleGradient[2] = {
"\nvoid main(void) {\n"
" gl_FragColor = texture2D(gradientSampler, linear);\n"
- "}\n\n";
-const char* gFS_Fast_SingleModulateGradient =
+ "}\n\n",
+ "\nvoid main(void) {\n"
+ " gl_FragColor = mix(startColor, endColor, clamp(linear, 0.0, 1.0));\n"
+ "}\n\n"
+};
+const char* gFS_Fast_SingleModulateGradient[2] = {
"\nvoid main(void) {\n"
" gl_FragColor = color.a * texture2D(gradientSampler, linear);\n"
- "}\n\n";
+ "}\n\n",
+ "\nvoid main(void) {\n"
+ " gl_FragColor = color.a * mix(startColor, endColor, clamp(linear, 0.0, 1.0));\n"
+ "}\n\n"
+};
// General case
const char* gFS_Main_FetchColor =
@@ -232,15 +252,18 @@ const char* gFS_Main_FetchA8Texture[2] = {
// Modulate
" fragColor = color * texture2D(sampler, outTexCoords).a;\n"
};
-const char* gFS_Main_FetchGradient[3] = {
+const char* gFS_Main_FetchGradient[6] = {
// Linear
" vec4 gradientColor = texture2D(gradientSampler, linear);\n",
+ " vec4 gradientColor = mix(startColor, endColor, clamp(linear, 0.0, 1.0));\n",
// Circular
- " highp float index = length(circular);\n"
- " vec4 gradientColor = texture2D(gradientSampler, vec2(index, 0.5));\n",
+ " vec4 gradientColor = texture2D(gradientSampler, vec2(length(circular), 0.5));\n",
+ " vec4 gradientColor = mix(startColor, endColor, clamp(length(circular), 0.0, 1.0));\n",
// Sweep
" highp float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n"
- " vec4 gradientColor = texture2D(gradientSampler, vec2(index - floor(index), 0.5));\n"
+ " vec4 gradientColor = texture2D(gradientSampler, vec2(index - floor(index), 0.5));\n",
+ " highp float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n"
+ " vec4 gradientColor = mix(startColor, endColor, clamp(index - floor(index), 0.0, 1.0));\n"
};
const char* gFS_Main_FetchBitmap =
" vec4 bitmapColor = texture2D(bitmapSampler, outBitmapTexCoords);\n";
@@ -395,8 +418,11 @@ Program* ProgramCache::generateProgram(const ProgramDescription& description, pr
String8 vertexShader = generateVertexShader(description);
String8 fragmentShader = generateFragmentShader(description);
- Program* program = new Program(description, vertexShader.string(), fragmentShader.string());
- return program;
+ return new Program(description, vertexShader.string(), fragmentShader.string());
+}
+
+static inline size_t gradientIndex(const ProgramDescription& description) {
+ return description.gradientType * 2 + description.isSimpleGradient;
}
String8 ProgramCache::generateVertexShader(const ProgramDescription& description) {
@@ -430,7 +456,7 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description
shader.append(gVS_Header_Varyings_IsAA);
}
if (description.hasGradient) {
- shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]);
+ shader.append(gVS_Header_Varyings_HasGradient[gradientIndex(description)]);
}
if (description.hasBitmap) {
shader.append(description.isPoint ?
@@ -449,7 +475,7 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description
shader.append(gVS_Main_AA);
}
if (description.hasGradient) {
- shader.append(gVS_Main_OutGradient[description.gradientType]);
+ shader.append(gVS_Main_OutGradient[gradientIndex(description)]);
}
if (description.hasBitmap) {
shader.append(description.isPoint ?
@@ -491,7 +517,7 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
shader.append(gVS_Header_Varyings_IsAA);
}
if (description.hasGradient) {
- shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]);
+ shader.append(gVS_Header_Varyings_HasGradient[gradientIndex(description)]);
}
if (description.hasBitmap) {
shader.append(description.isPoint ?
@@ -517,7 +543,7 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
shader.append(gFS_Uniforms_AA);
}
if (description.hasGradient) {
- shader.append(gFS_Uniforms_GradientSampler[description.gradientType]);
+ shader.append(gFS_Uniforms_GradientSampler[gradientIndex(description)]);
}
if (description.hasBitmap && description.isPoint) {
shader.append(gFS_Header_Uniforms_PointHasBitmap);
@@ -567,9 +593,9 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
fast = true;
} else if (singleGradient) {
if (!description.modulate) {
- shader.append(gFS_Fast_SingleGradient);
+ shader.append(gFS_Fast_SingleGradient[description.isSimpleGradient]);
} else {
- shader.append(gFS_Fast_SingleModulateGradient);
+ shader.append(gFS_Fast_SingleModulateGradient[description.isSimpleGradient]);
}
fast = true;
}
@@ -624,7 +650,7 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
shader.append(gFS_Main_AccountForAA);
}
if (description.hasGradient) {
- shader.append(gFS_Main_FetchGradient[description.gradientType]);
+ shader.append(gFS_Main_FetchGradient[gradientIndex(description)]);
}
if (description.hasBitmap) {
if (description.isPoint) {
diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp
index 66993a4..71e1739 100644
--- a/libs/hwui/SkiaShader.cpp
+++ b/libs/hwui/SkiaShader.cpp
@@ -38,6 +38,21 @@ static const GLint gTileModes[] = {
GL_MIRRORED_REPEAT // == SkShader::kMirror_TileMode
};
+/**
+ * This function does not work for n == 0.
+ */
+static inline bool isPowerOfTwo(unsigned int n) {
+ return !(n & (n - 1));
+}
+
+static inline void bindUniformColor(int slot, uint32_t color) {
+ glUniform4f(slot,
+ ((color >> 16) & 0xff) / 255.0f,
+ ((color >> 8) & 0xff) / 255.0f,
+ ((color ) & 0xff) / 255.0f,
+ ((color >> 24) & 0xff) / 255.0f);
+}
+
///////////////////////////////////////////////////////////////////////////////
// Base shader
///////////////////////////////////////////////////////////////////////////////
@@ -188,6 +203,8 @@ SkiaLinearGradientShader::SkiaLinearGradientShader(float* bounds, uint32_t* colo
mUnitMatrix.load(unitMatrix);
updateLocalMatrix(matrix);
+
+ mIsSimple = count == 2 && tileMode == SkShader::kClamp_TileMode;
}
SkiaLinearGradientShader::~SkiaLinearGradientShader() {
@@ -206,6 +223,7 @@ SkiaShader* SkiaLinearGradientShader::copy() {
copy->mPositions = new float[mCount];
memcpy(copy->mPositions, mPositions, sizeof(float) * mCount);
copy->mCount = mCount;
+ copy->mIsSimple = mIsSimple;
return copy;
}
@@ -213,21 +231,27 @@ void SkiaLinearGradientShader::describe(ProgramDescription& description,
const Extensions& extensions) {
description.hasGradient = true;
description.gradientType = ProgramDescription::kGradientLinear;
+ description.isSimpleGradient = mIsSimple;
}
void SkiaLinearGradientShader::setupProgram(Program* program, const mat4& modelView,
const Snapshot& snapshot, GLuint* textureUnit) {
- GLuint textureSlot = (*textureUnit)++;
- Caches::getInstance().activeTexture(textureSlot);
+ if (CC_UNLIKELY(!mIsSimple)) {
+ GLuint textureSlot = (*textureUnit)++;
+ Caches::getInstance().activeTexture(textureSlot);
+
+ Texture* texture = mGradientCache->get(mColors, mPositions, mCount);
- Texture* texture = mGradientCache->get(mColors, mPositions, mCount, mTileX);
+ // Uniforms
+ bindTexture(texture, gTileModes[mTileX], gTileModes[mTileY]);
+ glUniform1i(program->getUniform("gradientSampler"), textureSlot);
+ } else {
+ bindUniformColor(program->getUniform("startColor"), mColors[0]);
+ bindUniformColor(program->getUniform("endColor"), mColors[1]);
+ }
mat4 screenSpace;
computeScreenSpaceMatrix(screenSpace, modelView);
-
- // Uniforms
- bindTexture(texture, gTileModes[mTileX], gTileModes[mTileY]);
- glUniform1i(program->getUniform("gradientSampler"), textureSlot);
glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
}
@@ -269,6 +293,7 @@ SkiaShader* SkiaCircularGradientShader::copy() {
copy->mPositions = new float[mCount];
memcpy(copy->mPositions, mPositions, sizeof(float) * mCount);
copy->mCount = mCount;
+ copy->mIsSimple = mIsSimple;
return copy;
}
@@ -276,6 +301,7 @@ void SkiaCircularGradientShader::describe(ProgramDescription& description,
const Extensions& extensions) {
description.hasGradient = true;
description.gradientType = ProgramDescription::kGradientCircular;
+ description.isSimpleGradient = mIsSimple;
}
///////////////////////////////////////////////////////////////////////////////
@@ -296,6 +322,8 @@ SkiaSweepGradientShader::SkiaSweepGradientShader(float x, float y, uint32_t* col
mUnitMatrix.load(unitMatrix);
updateLocalMatrix(matrix);
+
+ mIsSimple = count == 2;
}
SkiaSweepGradientShader::SkiaSweepGradientShader(Type type, float x, float y, uint32_t* colors,
@@ -303,6 +331,8 @@ SkiaSweepGradientShader::SkiaSweepGradientShader(Type type, float x, float y, ui
SkMatrix* matrix, bool blend):
SkiaShader(type, key, tileMode, tileMode, matrix, blend),
mColors(colors), mPositions(positions), mCount(count) {
+
+ mIsSimple = count == 2 && tileMode == SkShader::kClamp_TileMode;
}
SkiaSweepGradientShader::~SkiaSweepGradientShader() {
@@ -318,6 +348,7 @@ SkiaShader* SkiaSweepGradientShader::copy() {
copy->mPositions = new float[mCount];
memcpy(copy->mPositions, mPositions, sizeof(float) * mCount);
copy->mCount = mCount;
+ copy->mIsSimple = mIsSimple;
return copy;
}
@@ -325,21 +356,27 @@ void SkiaSweepGradientShader::describe(ProgramDescription& description,
const Extensions& extensions) {
description.hasGradient = true;
description.gradientType = ProgramDescription::kGradientSweep;
+ description.isSimpleGradient = mIsSimple;
}
void SkiaSweepGradientShader::setupProgram(Program* program, const mat4& modelView,
const Snapshot& snapshot, GLuint* textureUnit) {
- GLuint textureSlot = (*textureUnit)++;
- Caches::getInstance().activeTexture(textureSlot);
+ if (CC_UNLIKELY(!mIsSimple)) {
+ GLuint textureSlot = (*textureUnit)++;
+ Caches::getInstance().activeTexture(textureSlot);
- Texture* texture = mGradientCache->get(mColors, mPositions, mCount);
+ Texture* texture = mGradientCache->get(mColors, mPositions, mCount);
+
+ // Uniforms
+ bindTexture(texture, gTileModes[mTileX], gTileModes[mTileY]);
+ glUniform1i(program->getUniform("gradientSampler"), textureSlot);
+ } else {
+ bindUniformColor(program->getUniform("startColor"), mColors[0]);
+ bindUniformColor(program->getUniform("endColor"), mColors[1]);
+ }
mat4 screenSpace;
computeScreenSpaceMatrix(screenSpace, modelView);
-
- // Uniforms
- bindTexture(texture, gTileModes[mTileX], gTileModes[mTileY]);
- glUniform1i(program->getUniform("gradientSampler"), textureSlot);
glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
}
diff --git a/libs/hwui/SkiaShader.h b/libs/hwui/SkiaShader.h
index 2de9a93..a710b86 100644
--- a/libs/hwui/SkiaShader.h
+++ b/libs/hwui/SkiaShader.h
@@ -154,13 +154,6 @@ private:
SkiaBitmapShader() {
}
- /**
- * This method does not work for n == 0.
- */
- inline bool isPowerOfTwo(unsigned int n) {
- return !(n & (n - 1));
- }
-
SkBitmap* mBitmap;
Texture* mTexture;
GLenum mWrapS;
@@ -185,6 +178,7 @@ private:
SkiaLinearGradientShader() {
}
+ bool mIsSimple;
float* mBounds;
uint32_t* mColors;
float* mPositions;
@@ -211,6 +205,7 @@ protected:
SkiaSweepGradientShader() {
}
+ bool mIsSimple;
uint32_t* mColors;
float* mPositions;
int mCount;
diff --git a/opengl/java/android/opengl/Matrix.java b/opengl/java/android/opengl/Matrix.java
index 3f07337..72128ac 100644
--- a/opengl/java/android/opengl/Matrix.java
+++ b/opengl/java/android/opengl/Matrix.java
@@ -337,8 +337,8 @@ public class Matrix {
final float y = 2.0f * (near * r_height);
final float A = (right + left) * r_width;
final float B = (top + bottom) * r_height;
- final float C = -(far + near) * r_depth;
- final float D = -2.0f * (far * near * r_depth);
+ final float C = (far + near) * r_depth;
+ final float D = 2.0f * (far * near * r_depth);
m[offset + 0] = x;
m[offset + 5] = y;
m[offset + 8] = A;
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index e7247a3..fad5993 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -33,6 +33,15 @@
<meta-data android:name="android.graphics.renderThread" android:value="true" />
<activity
+ android:name="GradientStopsActivity"
+ android:label="_GradientStops">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ <activity
android:name="PaintDrawFilterActivity"
android:label="_DrawFilter">
<intent-filter>
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/GradientStopsActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/GradientStopsActivity.java
new file mode 100644
index 0000000..ed00ecd
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/GradientStopsActivity.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+package com.android.test.hwui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.LinearGradient;
+import android.graphics.Paint;
+import android.graphics.Shader;
+import android.os.Bundle;
+import android.view.View;
+
+@SuppressWarnings("UnusedDeclaration")
+public class GradientStopsActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(new GradientView(this));
+ }
+
+ private class GradientView extends View {
+ public GradientView(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ int[] colors = new int[] { 0xffff0000, 0xff0000ff };
+ float[] positions = new float[] { 0.3f, 0.6f };
+ LinearGradient gradient = new LinearGradient(0.0f, 0.0f, 256.0f, 0.0f,
+ colors, positions, Shader.TileMode.CLAMP);
+
+ Paint paint = new Paint();
+ paint.setShader(gradient);
+
+ canvas.drawRect(0.0f, 0.0f, 256.0f, 50.0f, paint);
+
+ colors = new int[] { 0xffff0000, 0xff0000ff, 0xff00ff00 };
+ positions = new float[] { 0.3f, 0.6f, 1.0f };
+ gradient = new LinearGradient(0.0f, 0.0f, 256.0f, 0.0f,
+ colors, positions, Shader.TileMode.CLAMP);
+
+ paint.setShader(gradient);
+
+ canvas.translate(0.0f, 75.0f);
+ canvas.drawRect(0.0f, 0.0f, 256.0f, 50.0f, paint);
+
+ colors = new int[] { 0xffff0000, 0xff0000ff, 0xff00ff00 };
+ positions = new float[] { 0.0f, 0.3f, 0.6f };
+ gradient = new LinearGradient(0.0f, 0.0f, 256.0f, 0.0f,
+ colors, positions, Shader.TileMode.CLAMP);
+
+ paint.setShader(gradient);
+
+ canvas.translate(0.0f, 75.0f);
+ canvas.drawRect(0.0f, 0.0f, 256.0f, 50.0f, paint);
+
+ colors = new int[] { 0xff000000, 0xffffffff };
+ gradient = new LinearGradient(0.0f, 0.0f, 256.0f, 0.0f,
+ colors, null, Shader.TileMode.CLAMP);
+
+ paint.setShader(gradient);
+
+ canvas.translate(0.0f, 75.0f);
+ canvas.drawRect(0.0f, 0.0f, 256.0f, 50.0f, paint);
+
+ gradient = new LinearGradient(0.0f, 0.0f, 256.0f, 0.0f,
+ colors, null, Shader.TileMode.REPEAT);
+
+ paint.setShader(gradient);
+
+ canvas.translate(0.0f, 75.0f);
+ canvas.drawRect(0.0f, 0.0f, 768.0f, 50.0f, paint);
+
+ gradient = new LinearGradient(0.0f, 0.0f, 256.0f, 0.0f,
+ colors, null, Shader.TileMode.MIRROR);
+
+ paint.setShader(gradient);
+
+ canvas.translate(0.0f, 75.0f);
+ canvas.drawRect(0.0f, 0.0f, 768.0f, 50.0f, paint);
+
+ gradient = new LinearGradient(0.0f, 0.0f, 256.0f, 0.0f,
+ colors, null, Shader.TileMode.CLAMP);
+
+ paint.setShader(gradient);
+
+ canvas.translate(0.0f, 75.0f);
+ canvas.drawRect(0.0f, 0.0f, 768.0f, 50.0f, paint);
+
+ gradient = new LinearGradient(0.0f, 0.0f, 768.0f, 0.0f,
+ colors, null, Shader.TileMode.CLAMP);
+
+ paint.setShader(gradient);
+
+ canvas.translate(0.0f, 75.0f);
+ canvas.drawRect(0.0f, 0.0f, 768.0f, 50.0f, paint);
+ }
+ }
+}