summaryrefslogtreecommitdiffstats
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/hwui/Android.mk1
-rw-r--r--libs/hwui/GradientCache.cpp160
-rw-r--r--libs/hwui/GradientCache.h89
-rw-r--r--libs/hwui/OpenGLRenderer.cpp93
-rw-r--r--libs/hwui/OpenGLRenderer.h19
-rw-r--r--libs/hwui/Program.cpp2
-rw-r--r--libs/hwui/Program.h11
-rw-r--r--libs/hwui/TextureCache.cpp1
-rw-r--r--libs/hwui/shaders/drawLinearGradient.vert6
9 files changed, 367 insertions, 15 deletions
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 809f74d6..1bdb9d3 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -2,6 +2,7 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
+ GradientCache.cpp \
LayerCache.cpp \
Matrix.cpp \
OpenGLRenderer.cpp \
diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp
new file mode 100644
index 0000000..aeda416
--- /dev/null
+++ b/libs/hwui/GradientCache.cpp
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#define LOG_TAG "OpenGLRenderer"
+
+#include <GLES2/gl2.h>
+
+#include <SkCanvas.h>
+#include <SkGradientShader.h>
+
+#include "GradientCache.h"
+
+namespace android {
+namespace uirenderer {
+
+///////////////////////////////////////////////////////////////////////////////
+// Constructors/destructor
+///////////////////////////////////////////////////////////////////////////////
+
+GradientCache::GradientCache(uint32_t maxByteSize):
+ mCache(GenerationCache<SkShader*, Texture*>::kUnlimitedCapacity),
+ mSize(0), mMaxSize(maxByteSize) {
+ mCache.setOnEntryRemovedListener(this);
+}
+
+GradientCache::~GradientCache() {
+ mCache.clear();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Size management
+///////////////////////////////////////////////////////////////////////////////
+
+uint32_t GradientCache::getSize() {
+ return mSize;
+}
+
+uint32_t GradientCache::getMaxSize() {
+ return mMaxSize;
+}
+
+void GradientCache::setMaxSize(uint32_t maxSize) {
+ mMaxSize = maxSize;
+ while (mSize > mMaxSize) {
+ mCache.removeOldest();
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Callbacks
+///////////////////////////////////////////////////////////////////////////////
+
+void GradientCache::operator()(SkShader*& shader, Texture*& texture) {
+ if (shader) {
+ const uint32_t size = texture->width * texture->height * 4;
+ mSize -= size;
+ }
+
+ if (texture) {
+ glDeleteTextures(1, &texture->id);
+ delete texture;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Caching
+///////////////////////////////////////////////////////////////////////////////
+
+Texture* GradientCache::get(SkShader* shader) {
+ Texture* texture = mCache.get(shader);
+ return texture;
+}
+
+void GradientCache::remove(SkShader* shader) {
+ mCache.remove(shader);
+}
+
+void GradientCache::clear() {
+ mCache.clear();
+}
+
+Texture* GradientCache::addLinearGradient(SkShader* shader, float* bounds, 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);
+
+ SkCanvas canvas(bitmap);
+
+ SkPoint points[2];
+ points[0].set(0.0f, 0.0f);
+ points[1].set(bitmap.width(), 0.0f);
+
+ SkShader* localShader = SkGradientShader::CreateLinear(points,
+ reinterpret_cast<const SkColor*>(colors), positions, count, tileMode);
+
+ SkPaint p;
+ p.setStyle(SkPaint::kStrokeAndFill_Style);
+ p.setShader(localShader)->unref();
+
+ canvas.drawRectCoords(0.0f, 0.0f, bitmap.width(), 1.0f, p);
+
+ // Asume the cache is always big enough
+ const uint32_t size = bitmap.rowBytes() * bitmap.height();
+ while (mSize + size > mMaxSize) {
+ mCache.removeOldest();
+ }
+
+ Texture* texture = new Texture;
+ generateTexture(&bitmap, texture);
+
+ mSize += size;
+ mCache.put(shader, texture);
+
+ return texture;
+}
+
+void GradientCache::generateTexture(SkBitmap* bitmap, Texture* texture) {
+ SkAutoLockPixels autoLock(*bitmap);
+ if (!bitmap->readyToDraw()) {
+ LOGE("Cannot generate texture from shader");
+ return;
+ }
+
+ texture->generation = bitmap->getGenerationID();
+ texture->width = bitmap->width();
+ texture->height = bitmap->height();
+
+ glGenTextures(1, &texture->id);
+
+ glBindTexture(GL_TEXTURE_2D, texture->id);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel());
+
+ texture->blend = !bitmap->isOpaque();
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bitmap->rowBytesAsPixels(), texture->height, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, bitmap->getPixels());
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/GradientCache.h b/libs/hwui/GradientCache.h
new file mode 100644
index 0000000..12c8a23
--- /dev/null
+++ b/libs/hwui/GradientCache.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef ANDROID_UI_GRADIENT_CACHE_H
+#define ANDROID_UI_GRADIENT_CACHE_H
+
+#include <SkShader.h>
+
+#include "Texture.h"
+#include "GenerationCache.h"
+
+namespace android {
+namespace uirenderer {
+
+/**
+ * A simple LRU gradient cache. The cache has a maximum size expressed in bytes.
+ * Any texture added to the cache causing the cache to grow beyond the maximum
+ * allowed size will also cause the oldest texture to be kicked out.
+ */
+class GradientCache: public OnEntryRemoved<SkShader*, Texture*> {
+public:
+ GradientCache(uint32_t maxByteSize);
+ ~GradientCache();
+
+ /**
+ * Used as a callback when an entry is removed from the cache.
+ * Do not invoke directly.
+ */
+ void operator()(SkShader*& shader, Texture*& texture);
+
+ /**
+ * Adds a new linear gradient to the cache. The generated texture is
+ * returned.
+ */
+ Texture* addLinearGradient(SkShader* shader, float* bounds, uint32_t* colors,
+ float* positions, int count, SkShader::TileMode tileMode);
+ /**
+ * Returns the texture associated with the specified shader.
+ */
+ Texture* get(SkShader* shader);
+ /**
+ * Removes the texture associated with the specified shader. Returns NULL
+ * if the texture cannot be found. Upon remove the texture is freed.
+ */
+ void remove(SkShader* shader);
+ /**
+ * Clears the cache. This causes all textures to be deleted.
+ */
+ void clear();
+
+ /**
+ * Sets the maximum size of the cache in bytes.
+ */
+ void setMaxSize(uint32_t maxSize);
+ /**
+ * Returns the maximum size of the cache in bytes.
+ */
+ uint32_t getMaxSize();
+ /**
+ * Returns the current size of the cache in bytes.
+ */
+ uint32_t getSize();
+
+private:
+ void generateTexture(SkBitmap* bitmap, Texture* texture);
+
+ GenerationCache<SkShader*, Texture*> mCache;
+
+ uint32_t mSize;
+ uint32_t mMaxSize;
+}; // class GradientCache
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_UI_GRADIENT_CACHE_H
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 731862b..e39385a 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -37,10 +37,12 @@ namespace uirenderer {
// These properties are defined in mega-bytes
#define PROPERTY_TEXTURE_CACHE_SIZE "ro.hwui.texture_cache_size"
#define PROPERTY_LAYER_CACHE_SIZE "ro.hwui.layer_cache_size"
+#define PROPERTY_GRADIENT_CACHE_SIZE "ro.hwui.gradient_cache_size"
-#define DEFAULT_TEXTURE_CACHE_SIZE 20
-#define DEFAULT_LAYER_CACHE_SIZE 10
+#define DEFAULT_TEXTURE_CACHE_SIZE 20.0f
+#define DEFAULT_LAYER_CACHE_SIZE 10.0f
#define DEFAULT_PATCH_CACHE_SIZE 100
+#define DEFAULT_GRADIENT_CACHE_SIZE 0.5f
// Converts a number of mega-bytes into bytes
#define MB(s) s * 1024 * 1024
@@ -104,22 +106,30 @@ OpenGLRenderer::OpenGLRenderer():
mBlend(false), mLastSrcMode(GL_ZERO), mLastDstMode(GL_ZERO),
mTextureCache(MB(DEFAULT_TEXTURE_CACHE_SIZE)),
mLayerCache(MB(DEFAULT_LAYER_CACHE_SIZE)),
+ mGradientCache(MB(DEFAULT_GRADIENT_CACHE_SIZE)),
mPatchCache(DEFAULT_PATCH_CACHE_SIZE) {
LOGD("Create OpenGLRenderer");
char property[PROPERTY_VALUE_MAX];
if (property_get(PROPERTY_TEXTURE_CACHE_SIZE, property, NULL) > 0) {
LOGD(" Setting texture cache size to %sMB", property);
- mTextureCache.setMaxSize(MB(atoi(property)));
+ mTextureCache.setMaxSize(MB(atof(property)));
} else {
- LOGD(" Using default texture cache size of %dMB", DEFAULT_TEXTURE_CACHE_SIZE);
+ LOGD(" Using default texture cache size of %.2fMB", DEFAULT_TEXTURE_CACHE_SIZE);
}
if (property_get(PROPERTY_LAYER_CACHE_SIZE, property, NULL) > 0) {
LOGD(" Setting layer cache size to %sMB", property);
- mLayerCache.setMaxSize(MB(atoi(property)));
+ mLayerCache.setMaxSize(MB(atof(property)));
} else {
- LOGD(" Using default layer cache size of %dMB", DEFAULT_LAYER_CACHE_SIZE);
+ LOGD(" Using default layer cache size of %.2fMB", DEFAULT_LAYER_CACHE_SIZE);
+ }
+
+ if (property_get(PROPERTY_GRADIENT_CACHE_SIZE, property, NULL) > 0) {
+ LOGD(" Setting gradient cache size to %sMB", property);
+ mLayerCache.setMaxSize(MB(atof(property)));
+ } else {
+ LOGD(" Using default gradient cache size of %.2fMB", DEFAULT_GRADIENT_CACHE_SIZE);
}
mDrawColorProgram = new DrawColorProgram;
@@ -143,6 +153,7 @@ OpenGLRenderer::~OpenGLRenderer() {
mTextureCache.clear();
mLayerCache.clear();
+ mGradientCache.clear();
mPatchCache.clear();
}
@@ -538,8 +549,9 @@ void OpenGLRenderer::setupBitmapShader(SkBitmap* bitmap, SkShader::TileMode tile
mShaderMatrix = matrix;
}
-void OpenGLRenderer::setupLinearGradientShader(SkShader* shader, float* bounds,uint32_t* colors,
- float* positions, SkShader::TileMode tileMode, SkMatrix* matrix, bool hasAlpha) {
+void OpenGLRenderer::setupLinearGradientShader(SkShader* shader, float* bounds, uint32_t* colors,
+ float* positions, int count, SkShader::TileMode tileMode, SkMatrix* matrix,
+ bool hasAlpha) {
// TODO: We should use a struct to describe each shader
mShader = OpenGLRenderer::kShaderLinearGradient;
mShaderKey = shader;
@@ -550,6 +562,7 @@ void OpenGLRenderer::setupLinearGradientShader(SkShader* shader, float* bounds,u
mShaderBounds = bounds;
mShaderColors = colors;
mShaderPositions = positions;
+ mShaderCount = count;
}
///////////////////////////////////////////////////////////////////////////////
@@ -566,21 +579,22 @@ void OpenGLRenderer::drawColorRect(float left, float top, float right, float bot
// Render using pre-multiplied alpha
const int alpha = (color >> 24) & 0xFF;
const GLfloat a = alpha / 255.0f;
- const GLfloat r = a * ((color >> 16) & 0xFF) / 255.0f;
- const GLfloat g = a * ((color >> 8) & 0xFF) / 255.0f;
- const GLfloat b = a * ((color ) & 0xFF) / 255.0f;
switch (mShader) {
case OpenGLRenderer::kShaderBitmap:
drawBitmapShader(left, top, right, bottom, a, mode);
return;
case OpenGLRenderer::kShaderLinearGradient:
- // TODO: Generate gradient texture, set appropriate shader
- break;
+ drawLinearGradientShader(left, top, right, bottom, a, mode);
+ return;
default:
break;
}
+ const GLfloat r = a * ((color >> 16) & 0xFF) / 255.0f;
+ const GLfloat g = a * ((color >> 8) & 0xFF) / 255.0f;
+ const GLfloat b = a * ((color ) & 0xFF) / 255.0f;
+
// Pre-multiplication happens when setting the shader color
chooseBlending(alpha < 255 || mShaderBlend, mode);
@@ -605,6 +619,58 @@ void OpenGLRenderer::drawColorRect(float left, float top, float right, float bot
glDrawArrays(GL_TRIANGLE_STRIP, 0, gDrawColorVertexCount);
}
+void OpenGLRenderer::drawLinearGradientShader(float left, float top, float right, float bottom,
+ float alpha, SkXfermode::Mode mode) {
+ Texture* texture = mGradientCache.get(mShaderKey);
+ if (!texture) {
+ texture = mGradientCache.addLinearGradient(mShaderKey, mShaderBounds, mShaderColors,
+ mShaderPositions, mShaderCount, mShaderTileX);
+ }
+
+ mModelView.loadTranslate(left, top, 0.0f);
+ mModelView.scale(right - left, bottom - top, 1.0f);
+
+ useProgram(mDrawLinearGradientProgram);
+ mDrawLinearGradientProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform);
+
+ chooseBlending(mShaderBlend || alpha < 1.0f, mode);
+
+ if (texture->id != mLastTexture) {
+ glBindTexture(GL_TEXTURE_2D, texture->id);
+ mLastTexture = texture->id;
+ }
+ // TODO: Don't set the texture parameters every time
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gTileModes[mShaderTileX]);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gTileModes[mShaderTileX]);
+
+ Rect start(mShaderBounds[0], mShaderBounds[1], mShaderBounds[2], mShaderBounds[3]);
+ if (mShaderMatrix) {
+ mat4 shaderMatrix(*mShaderMatrix);
+ shaderMatrix.mapRect(start);
+ }
+ mSnapshot->transform.mapRect(start);
+
+ const float gradientX = start.right - start.left;
+ const float gradientY = start.bottom - start.top;
+
+ mat4 screenSpace(mSnapshot->transform);
+ screenSpace.multiply(mModelView);
+
+ // Always premultiplied
+ glUniform4f(mDrawLinearGradientProgram->color, alpha, alpha, alpha, alpha);
+ glUniform2f(mDrawLinearGradientProgram->start, start.left, start.top);
+ glUniform2f(mDrawLinearGradientProgram->gradient, gradientX, gradientY);
+ glUniform1f(mDrawLinearGradientProgram->gradientLength,
+ 1.0f / (gradientX * gradientX + gradientY * gradientY));
+ glUniformMatrix4fv(mDrawLinearGradientProgram->screenSpace, 1, GL_FALSE,
+ &screenSpace.data[0]);
+
+ glVertexAttribPointer(mDrawLinearGradientProgram->position, 2, GL_FLOAT, GL_FALSE,
+ gDrawTextureVertexStride, &mDrawTextureVertices[0].position[0]);
+
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, gDrawTextureVertexCount);
+}
+
void OpenGLRenderer::drawBitmapShader(float left, float top, float right, float bottom,
float alpha, SkXfermode::Mode mode) {
const Texture* texture = mTextureCache.get(mShaderBitmap);
@@ -680,6 +746,7 @@ void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float b
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gTileModes[mShaderTileY]);
// Always premultiplied
+ //glUniform4f(mDrawTextureProgram->color, alpha, alpha, alpha, alpha);
glUniform4f(mDrawTextureProgram->color, alpha, alpha, alpha, alpha);
glVertexAttribPointer(mDrawTextureProgram->position, 2, GL_FLOAT, GL_FALSE,
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 5a530eb..dd7999d 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -36,6 +36,7 @@
#include "Snapshot.h"
#include "TextureCache.h"
#include "LayerCache.h"
+#include "GradientCache.h"
#include "PatchCache.h"
#include "Vertex.h"
@@ -104,7 +105,8 @@ public:
void setupBitmapShader(SkBitmap* bitmap, SkShader::TileMode tileX, SkShader::TileMode tileY,
SkMatrix* matrix, bool hasAlpha);
void setupLinearGradientShader(SkShader* shader, float* bounds, uint32_t* colors,
- float* positions, SkShader::TileMode tileMode, SkMatrix* matrix, bool hasAlpha);
+ float* positions, int count, SkShader::TileMode tileMode,
+ SkMatrix* matrix, bool hasAlpha);
private:
/**
@@ -249,6 +251,19 @@ private:
SkXfermode::Mode mode);
/**
+ * Fills the specified rectangle with the currently set linear gradient shader.
+ *
+ * @param left The left coordinate of the rectangle
+ * @param top The top coordinate of the rectangle
+ * @param right The right coordinate of the rectangle
+ * @param bottom The bottom coordinate of the rectangle
+ * @param alpha An additional translucency parameter, between 0.0f and 1.0f
+ * @param mode The blending mode
+ */
+ void drawLinearGradientShader(float left, float top, float right, float bottom, float alpha,
+ SkXfermode::Mode mode);
+
+ /**
* Resets the texture coordinates stored in mDrawTextureVertices. Setting the values
* back to default is achieved by calling:
*
@@ -335,10 +350,12 @@ private:
float* mShaderBounds;
uint32_t* mShaderColors;
float* mShaderPositions;
+ int mShaderCount;
// Various caches
TextureCache mTextureCache;
LayerCache mLayerCache;
+ GradientCache mGradientCache;
PatchCache mPatchCache;
}; // class OpenGLRenderer
diff --git a/libs/hwui/Program.cpp b/libs/hwui/Program.cpp
index 6202ba3..841b6c8 100644
--- a/libs/hwui/Program.cpp
+++ b/libs/hwui/Program.cpp
@@ -190,6 +190,8 @@ DrawLinearGradientProgram::DrawLinearGradientProgram():
gradient = addUniform("gradient");
gradientLength = addUniform("gradientLength");
sampler = addUniform("sampler");
+ start = addUniform("start");
+ screenSpace = addUniform("screenSpace");
}
void DrawLinearGradientProgram::use() {
diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h
index d7970d9..18a8e92 100644
--- a/libs/hwui/Program.h
+++ b/libs/hwui/Program.h
@@ -213,6 +213,17 @@ public:
virtual void remove();
/**
+ * Name of the matrix used to compute the screen space coordinates
+ * of the vertices.
+ */
+ int screenSpace;
+
+ /**
+ * Name of the linear gradient start point.
+ */
+ int start;
+
+ /**
* Name of the linear gradient vector.
*/
int gradient;
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index ff7d7c9..ff9e2af 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -97,6 +97,7 @@ Texture* TextureCache::get(SkBitmap* bitmap) {
} else if (bitmap->getGenerationID() != texture->generation) {
generateTexture(bitmap, texture, true);
}
+ // TODO: Do something to destroy the texture object if it's too big for the cache
return texture;
}
diff --git a/libs/hwui/shaders/drawLinearGradient.vert b/libs/hwui/shaders/drawLinearGradient.vert
index 963dc87..f5c669b 100644
--- a/libs/hwui/shaders/drawLinearGradient.vert
+++ b/libs/hwui/shaders/drawLinearGradient.vert
@@ -4,13 +4,17 @@ attribute vec4 position;
uniform float gradientLength;
uniform vec2 gradient;
+uniform vec2 start;
uniform mat4 transform;
+uniform mat4 screenSpace;
varying float index;
void main(void) {
+ vec4 location = screenSpace * position;
+ index = dot(location.xy - start, gradient) * gradientLength;
+
gl_Position = transform * position;
- index = dot(gl_Position.xy, gradient) * gradientLength;
}
);