Add support for circular gradients to the GL renderer.
This change also adds full support for local transformation matrices on
sweep and radial gradients.
Change-Id: Id8773bc0766575190e3f3d51984fc5e57b266c3f
diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp
index 264ad3d..c698b5a 100644
--- a/libs/hwui/Matrix.cpp
+++ b/libs/hwui/Matrix.cpp
@@ -144,6 +144,12 @@
return data[kTranslateY];
}
+void Matrix4::multiply(float v) {
+ for (int i = 0; i < 16; i++) {
+ data[i] *= v;
+ }
+}
+
void Matrix4::loadTranslate(float x, float y, float z) {
loadIdentity();
data[kTranslateX] = x;
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index c247a67..0608efe 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -83,6 +83,8 @@
load(u);
}
+ void multiply(float v);
+
void translate(float x, float y, float z) {
Matrix4 u;
u.loadTranslate(x, y, z);
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index bcc1edf..3e9412c 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -40,9 +40,12 @@
"uniform vec2 gradientStart;\n"
"uniform mat4 screenSpace;\n",
// Circular
- "",
+ "uniform vec2 gradientStart;\n"
+ "uniform mat4 gradientMatrix;\n"
+ "uniform mat4 screenSpace;\n",
// Sweep
"uniform vec2 gradientStart;\n"
+ "uniform mat4 gradientMatrix;\n"
"uniform mat4 screenSpace;\n"
};
const char* gVS_Header_Uniforms_HasBitmap =
@@ -56,7 +59,7 @@
// Linear
"varying float index;\n",
// Circular
- "",
+ "varying vec2 circular;\n",
// Sweep
"varying vec2 sweep;\n"
};
@@ -69,10 +72,11 @@
" vec4 location = screenSpace * position;\n"
" index = dot(location.xy - gradientStart, gradient) * gradientLength;\n",
// Circular
- "",
+ " vec4 location = screenSpace * position;\n"
+ " circular = (gradientMatrix * vec4(location.xy - gradientStart, 0.0, 0.0)).xy;\n",
// Sweep
" vec4 location = screenSpace * position;\n"
- " sweep = location.xy - gradientStart;\n"
+ " sweep = (gradientMatrix * vec4(location.xy - gradientStart, 0.0, 0.0)).xy;\n"
};
const char* gVS_Main_OutBitmapTexCoords =
" vec4 bitmapCoords = textureTransform * position;\n"
@@ -98,6 +102,7 @@
// Linear
"uniform sampler2D gradientSampler;\n",
// Circular
+ "uniform float gradientRadius;\n"
"uniform sampler2D gradientSampler;\n",
// Sweep
"uniform sampler2D gradientSampler;\n"
@@ -129,7 +134,8 @@
// Linear
" vec4 gradientColor = texture2D(gradientSampler, vec2(index, 0.5));\n",
// Circular
- "",
+ " float index = length(circular) * gradientRadius;\n"
+ " vec4 gradientColor = texture2D(gradientSampler, vec2(index, 0.5));\n",
// Sweep
" float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n"
" vec4 gradientColor = texture2D(gradientSampler, vec2(index - floor(index), 0.5));\n"
diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp
index c5d9767..9e1f6c2 100644
--- a/libs/hwui/SkiaShader.cpp
+++ b/libs/hwui/SkiaShader.cpp
@@ -209,6 +209,30 @@
}
///////////////////////////////////////////////////////////////////////////////
+// Circular gradient shader
+///////////////////////////////////////////////////////////////////////////////
+
+SkiaCircularGradientShader::SkiaCircularGradientShader(float x, float y, float radius,
+ uint32_t* colors, float* positions, int count, SkShader* key, SkShader::TileMode tileMode,
+ SkMatrix* matrix, bool blend):
+ SkiaSweepGradientShader(kCircularGradient, x, y, colors, positions, count, key,
+ tileMode, matrix, blend),
+ mRadius(radius) {
+}
+
+void SkiaCircularGradientShader::describe(ProgramDescription& description,
+ const Extensions& extensions) {
+ description.hasGradient = true;
+ description.gradientType = ProgramDescription::kGradientCircular;
+}
+
+void SkiaCircularGradientShader::setupProgram(Program* program, const mat4& modelView,
+ const Snapshot& snapshot, GLuint* textureUnit) {
+ SkiaSweepGradientShader::setupProgram(program, modelView, snapshot, textureUnit);
+ glUniform1f(program->getUniform("gradientRadius"), 1.0f / mRadius);
+}
+
+///////////////////////////////////////////////////////////////////////////////
// Sweep gradient shader
///////////////////////////////////////////////////////////////////////////////
@@ -219,6 +243,13 @@
mX(x), mY(y), mColors(colors), mPositions(positions), mCount(count) {
}
+SkiaSweepGradientShader::SkiaSweepGradientShader(Type type, float x, float y, uint32_t* colors,
+ float* positions, int count, SkShader* key, SkShader::TileMode tileMode,
+ SkMatrix* matrix, bool blend):
+ SkiaShader(type, key, tileMode, tileMode, matrix, blend),
+ mX(x), mY(y), mColors(colors), mPositions(positions), mCount(count) {
+}
+
SkiaSweepGradientShader::~SkiaSweepGradientShader() {
delete[] mColors;
delete[] mPositions;
@@ -243,10 +274,15 @@
float left = mX;
float top = mY;
+ mat4 shaderMatrix;
if (mMatrix) {
- mat4 shaderMatrix(*mMatrix);
+ shaderMatrix.load(*mMatrix);
shaderMatrix.mapPoint(left, top);
}
+
+ mat4 copy(shaderMatrix);
+ shaderMatrix.loadInverse(copy);
+
snapshot.transform->mapPoint(left, top);
mat4 screenSpace(*snapshot.transform);
@@ -255,6 +291,7 @@
// Uniforms
bindTexture(texture->id, gTileModes[mTileX], gTileModes[mTileY], textureSlot);
glUniform1i(program->getUniform("gradientSampler"), textureSlot);
+ glUniformMatrix4fv(program->getUniform("gradientMatrix"), 1, GL_FALSE, &shaderMatrix.data[0]);
glUniform2f(program->getUniform("gradientStart"), left, top);
glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
}
diff --git a/libs/hwui/SkiaShader.h b/libs/hwui/SkiaShader.h
index b67bfee..0023c46 100644
--- a/libs/hwui/SkiaShader.h
+++ b/libs/hwui/SkiaShader.h
@@ -152,12 +152,15 @@
SkShader* key, SkMatrix* matrix, bool blend);
~SkiaSweepGradientShader();
- void describe(ProgramDescription& description, const Extensions& extensions);
- void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot,
+ virtual void describe(ProgramDescription& description, const Extensions& extensions);
+ virtual void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot,
GLuint* textureUnit);
void updateTransforms(Program* program, const mat4& modelView, const Snapshot& snapshot);
-private:
+protected:
+ SkiaSweepGradientShader(Type type, float x, float y, uint32_t* colors, float* positions,
+ int count, SkShader* key, SkShader::TileMode tileMode, SkMatrix* matrix, bool blend);
+
float mX, mY;
uint32_t* mColors;
float* mPositions;
@@ -165,6 +168,21 @@
}; // struct SkiaSweepGradientShader
/**
+ * A shader that draws a circular gradient.
+ */
+struct SkiaCircularGradientShader: public SkiaSweepGradientShader {
+ SkiaCircularGradientShader(float x, float y, float radius, uint32_t* colors, float* positions,
+ int count, SkShader* key,SkShader::TileMode tileMode, SkMatrix* matrix, bool blend);
+
+ void describe(ProgramDescription& description, const Extensions& extensions);
+ void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot,
+ GLuint* textureUnit);
+
+private:
+ float mRadius;
+}; // struct SkiaCircularGradientShader
+
+/**
* A shader that draws two shaders, composited with an xfermode.
*/
struct SkiaComposeShader: public SkiaShader {