Merge "Improve gradients" into jb-mr1-dev
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user