summaryrefslogtreecommitdiffstats
path: root/libs/hwui/GradientCache.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/hwui/GradientCache.cpp')
-rw-r--r--libs/hwui/GradientCache.cpp148
1 files changed, 107 insertions, 41 deletions
diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp
index 3678788..2e4e349 100644
--- a/libs/hwui/GradientCache.cpp
+++ b/libs/hwui/GradientCache.cpp
@@ -16,13 +16,9 @@
#define LOG_TAG "OpenGLRenderer"
-#include <GLES2/gl2.h>
-
-#include <SkCanvas.h>
-#include <SkGradientShader.h>
-
#include <utils/threads.h>
+#include "Caches.h"
#include "Debug.h"
#include "GradientCache.h"
#include "Properties.h"
@@ -31,6 +27,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
///////////////////////////////////////////////////////////////////////////////
@@ -45,6 +57,8 @@ GradientCache::GradientCache():
INIT_LOGD(" Using default gradient cache size of %.2fMB", DEFAULT_GRADIENT_CACHE_SIZE);
}
+ glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
+
mCache.setOnEntryRemovedListener(this);
}
@@ -83,7 +97,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 +111,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,36 +127,45 @@ void GradientCache::clear() {
mCache.clear();
}
-Texture* GradientCache::addLinearGradient(GradientCacheEntry& gradient,
- uint32_t* colors, float* positions, int count, SkShader::TileMode tileMode) {
- SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1024, 1);
- bitmap.allocPixels();
- bitmap.eraseColor(0);
+void GradientCache::getGradientInfo(const uint32_t* colors, const int count,
+ GradientInfo& info) {
+ uint32_t width = 256 * (count - 1);
- SkCanvas canvas(bitmap);
+ if (!Caches::getInstance().extensions.hasNPot()) {
+ width = 1 << (31 - __builtin_clz(width));
+ }
+
+ bool hasAlpha = false;
+ 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(), 1.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);
@@ -151,25 +173,69 @@ 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;
+
+ const float alpha = startA * oppAmount + endA * amount;
+ const float a = alpha / 255.0f;
+ *p++ = uint8_t(a * (startR * oppAmount + endR * amount));
+ *p++ = uint8_t(a * (startG * oppAmount + endG * amount));
+ *p++ = uint8_t(a * (startB * oppAmount + endB * amount));
+ *p++ = uint8_t(alpha);
}
- 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);