diff options
-rw-r--r-- | core/jni/android/graphics/Shader.cpp | 46 | ||||
-rw-r--r-- | libs/hwui/GradientCache.cpp | 140 | ||||
-rw-r--r-- | libs/hwui/GradientCache.h | 41 | ||||
-rw-r--r-- | libs/hwui/Program.h | 9 | ||||
-rw-r--r-- | libs/hwui/ProgramCache.cpp | 72 | ||||
-rw-r--r-- | libs/hwui/SkiaShader.cpp | 65 | ||||
-rw-r--r-- | libs/hwui/SkiaShader.h | 9 | ||||
-rw-r--r-- | opengl/java/android/opengl/Matrix.java | 4 | ||||
-rw-r--r-- | tests/HwAccelerationTest/AndroidManifest.xml | 9 | ||||
-rw-r--r-- | tests/HwAccelerationTest/src/com/android/test/hwui/GradientStopsActivity.java | 116 |
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); + } + } +} |