am 413ab3a5: Merge "Improve gradients" into jb-mr1-dev

* commit '413ab3a5a2065295080ae063a72a9a7e30f2d484':
  Improve gradients
This commit is contained in:
Romain Guy
2012-07-31 18:58:18 -07:00
committed by Android Git Automerger
10 changed files with 395 additions and 120 deletions

View File

@@ -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);

View File

@@ -16,9 +16,6 @@
#define LOG_TAG "OpenGLRenderer"
#include <SkCanvas.h>
#include <SkGradientShader.h>
#include <utils/threads.h>
#include "Debug.h"
@@ -28,6 +25,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();
}
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;
for (int i = 0; i < count; i++) {
if (((colors[i] >> 24) & 0xff) < 255) {
hasAlpha = true;
break;
}
}
info.width = min(width, uint32_t(mMaxTextureSize));
info.hasAlpha = hasAlpha;
}
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;
uint32_t* colors, float* positions, int count) {
SkBitmap bitmap;
bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, 4);
bitmap.allocPixels();
bitmap.eraseColor(0);
GradientInfo info;
getGradientInfo(colors, count, info);
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(), 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);

View File

@@ -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(SkBitmap* bitmap, Texture* texture);
void generateTexture(uint32_t* colors, float* positions, int count, Texture* texture);
struct GradientInfo {
uint32_t width;
bool hasAlpha;
};
void getGradientInfo(const uint32_t* colors, const int count, GradientInfo& info);
GenerationCache<GradientCacheEntry, Texture*> mCache;

View File

@@ -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;
}

View File

@@ -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) {

View File

@@ -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, mTileX);
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]);
}
@@ -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]);
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -32,6 +32,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">

View File

@@ -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);
}
}
}