Merge "DO NOT MERGE Inspect SkShader to determine hw shader." into lmp-preview-dev

This commit is contained in:
Chris Craik
2014-05-23 23:21:48 +00:00
committed by Android (Google) Code Review
28 changed files with 648 additions and 1341 deletions

View File

@ -41,10 +41,6 @@ import android.text.TextUtils;
* An implementation of Canvas on top of OpenGL ES 2.0.
*/
class GLES20Canvas extends HardwareCanvas {
// Must match modifiers used in the JNI layer
private static final int MODIFIER_NONE = 0;
private static final int MODIFIER_SHADER = 2;
private final boolean mOpaque;
protected long mRenderer;
@ -650,13 +646,8 @@ class GLES20Canvas extends HardwareCanvas {
@Override
public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,
Paint paint) {
int modifiers = setupModifiers(paint, MODIFIER_SHADER);
try {
nDrawArc(mRenderer, oval.left, oval.top, oval.right, oval.bottom,
startAngle, sweepAngle, useCenter, paint.mNativePaint);
} finally {
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
}
nDrawArc(mRenderer, oval.left, oval.top, oval.right, oval.bottom,
startAngle, sweepAngle, useCenter, paint.mNativePaint);
}
private static native void nDrawArc(long renderer, float left, float top,
@ -672,7 +663,6 @@ class GLES20Canvas extends HardwareCanvas {
public void drawPatch(NinePatch patch, Rect dst, Paint paint) {
Bitmap bitmap = patch.getBitmap();
throwIfCannotDraw(bitmap);
// Shaders are ignored when drawing patches
final long nativePaint = paint == null ? 0 : paint.mNativePaint;
nDrawPatch(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, patch.mNativeChunk,
dst.left, dst.top, dst.right, dst.bottom, nativePaint);
@ -682,7 +672,6 @@ class GLES20Canvas extends HardwareCanvas {
public void drawPatch(NinePatch patch, RectF dst, Paint paint) {
Bitmap bitmap = patch.getBitmap();
throwIfCannotDraw(bitmap);
// Shaders are ignored when drawing patches
final long nativePaint = paint == null ? 0 : paint.mNativePaint;
nDrawPatch(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, patch.mNativeChunk,
dst.left, dst.top, dst.right, dst.bottom, nativePaint);
@ -694,14 +683,8 @@ class GLES20Canvas extends HardwareCanvas {
@Override
public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
throwIfCannotDraw(bitmap);
// Shaders are ignored when drawing bitmaps
int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
try {
final long nativePaint = paint == null ? 0 : paint.mNativePaint;
nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, nativePaint);
} finally {
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
}
final long nativePaint = paint == null ? 0 : paint.mNativePaint;
nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, nativePaint);
}
private static native void nDrawBitmap(long renderer, long bitmap, byte[] buffer,
@ -710,15 +693,9 @@ class GLES20Canvas extends HardwareCanvas {
@Override
public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
throwIfCannotDraw(bitmap);
// Shaders are ignored when drawing bitmaps
int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
try {
final long nativePaint = paint == null ? 0 : paint.mNativePaint;
nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer,
matrix.native_instance, nativePaint);
} finally {
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
}
final long nativePaint = paint == null ? 0 : paint.mNativePaint;
nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer,
matrix.native_instance, nativePaint);
}
private static native void nDrawBitmap(long renderer, long bitmap, byte[] buffer,
@ -727,55 +704,43 @@ class GLES20Canvas extends HardwareCanvas {
@Override
public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
throwIfCannotDraw(bitmap);
// Shaders are ignored when drawing bitmaps
int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
try {
final long nativePaint = paint == null ? 0 : paint.mNativePaint;
final long nativePaint = paint == null ? 0 : paint.mNativePaint;
int left, top, right, bottom;
if (src == null) {
left = top = 0;
right = bitmap.getWidth();
bottom = bitmap.getHeight();
} else {
left = src.left;
right = src.right;
top = src.top;
bottom = src.bottom;
}
nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom,
dst.left, dst.top, dst.right, dst.bottom, nativePaint);
} finally {
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
int left, top, right, bottom;
if (src == null) {
left = top = 0;
right = bitmap.getWidth();
bottom = bitmap.getHeight();
} else {
left = src.left;
right = src.right;
top = src.top;
bottom = src.bottom;
}
nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom,
dst.left, dst.top, dst.right, dst.bottom, nativePaint);
}
@Override
public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {
throwIfCannotDraw(bitmap);
// Shaders are ignored when drawing bitmaps
int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
try {
final long nativePaint = paint == null ? 0 : paint.mNativePaint;
float left, top, right, bottom;
if (src == null) {
left = top = 0;
right = bitmap.getWidth();
bottom = bitmap.getHeight();
} else {
left = src.left;
right = src.right;
top = src.top;
bottom = src.bottom;
}
nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom,
dst.left, dst.top, dst.right, dst.bottom, nativePaint);
} finally {
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
final long nativePaint = paint == null ? 0 : paint.mNativePaint;
float left, top, right, bottom;
if (src == null) {
left = top = 0;
right = bitmap.getWidth();
bottom = bitmap.getHeight();
} else {
left = src.left;
right = src.right;
top = src.top;
bottom = src.bottom;
}
nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom,
dst.left, dst.top, dst.right, dst.bottom, nativePaint);
}
private static native void nDrawBitmap(long renderer, long bitmap, byte[] buffer,
@ -805,7 +770,6 @@ class GLES20Canvas extends HardwareCanvas {
throw new ArrayIndexOutOfBoundsException();
}
// Shaders are ignored when drawing bitmaps
final long nativePaint = paint == null ? 0 : paint.mNativePaint;
nDrawBitmap(mRenderer, colors, offset, stride, x, y,
width, height, hasAlpha, nativePaint);
@ -817,7 +781,6 @@ class GLES20Canvas extends HardwareCanvas {
@Override
public void drawBitmap(int[] colors, int offset, int stride, int x, int y,
int width, int height, boolean hasAlpha, Paint paint) {
// Shaders are ignored when drawing bitmaps
drawBitmap(colors, offset, stride, (float) x, (float) y, width, height, hasAlpha, paint);
}
@ -840,14 +803,9 @@ class GLES20Canvas extends HardwareCanvas {
checkRange(colors.length, colorOffset, count);
}
int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
try {
final long nativePaint = paint == null ? 0 : paint.mNativePaint;
nDrawBitmapMesh(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, meshWidth, meshHeight,
verts, vertOffset, colors, colorOffset, nativePaint);
} finally {
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
}
final long nativePaint = paint == null ? 0 : paint.mNativePaint;
nDrawBitmapMesh(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, meshWidth, meshHeight,
verts, vertOffset, colors, colorOffset, nativePaint);
}
private static native void nDrawBitmapMesh(long renderer, long bitmap, byte[] buffer,
@ -856,12 +814,7 @@ class GLES20Canvas extends HardwareCanvas {
@Override
public void drawCircle(float cx, float cy, float radius, Paint paint) {
int modifiers = setupModifiers(paint, MODIFIER_SHADER);
try {
nDrawCircle(mRenderer, cx, cy, radius, paint.mNativePaint);
} finally {
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
}
nDrawCircle(mRenderer, cx, cy, radius, paint.mNativePaint);
}
private static native void nDrawCircle(long renderer, float cx, float cy,
@ -906,12 +859,7 @@ class GLES20Canvas extends HardwareCanvas {
if ((offset | count) < 0 || offset + count > pts.length) {
throw new IllegalArgumentException("The lines array must contain 4 elements per line.");
}
int modifiers = setupModifiers(paint, MODIFIER_SHADER);
try {
nDrawLines(mRenderer, pts, offset, count, paint.mNativePaint);
} finally {
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
}
nDrawLines(mRenderer, pts, offset, count, paint.mNativePaint);
}
private static native void nDrawLines(long renderer, float[] points,
@ -924,12 +872,7 @@ class GLES20Canvas extends HardwareCanvas {
@Override
public void drawOval(RectF oval, Paint paint) {
int modifiers = setupModifiers(paint, MODIFIER_SHADER);
try {
nDrawOval(mRenderer, oval.left, oval.top, oval.right, oval.bottom, paint.mNativePaint);
} finally {
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
}
nDrawOval(mRenderer, oval.left, oval.top, oval.right, oval.bottom, paint.mNativePaint);
}
private static native void nDrawOval(long renderer, float left, float top,
@ -944,17 +887,12 @@ class GLES20Canvas extends HardwareCanvas {
@Override
public void drawPath(Path path, Paint paint) {
int modifiers = setupModifiers(paint, MODIFIER_SHADER);
try {
if (path.isSimplePath) {
if (path.rects != null) {
nDrawRects(mRenderer, path.rects.mNativeRegion, paint.mNativePaint);
}
} else {
nDrawPath(mRenderer, path.mNativePath, paint.mNativePaint);
if (path.isSimplePath) {
if (path.rects != null) {
nDrawRects(mRenderer, path.rects.mNativeRegion, paint.mNativePaint);
}
} finally {
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
} else {
nDrawPath(mRenderer, path.mNativePath, paint.mNativePaint);
}
}
@ -962,12 +900,7 @@ class GLES20Canvas extends HardwareCanvas {
private static native void nDrawRects(long renderer, long region, long paint);
void drawRects(float[] rects, int count, Paint paint) {
int modifiers = setupModifiers(paint, MODIFIER_SHADER);
try {
nDrawRects(mRenderer, rects, count, paint.mNativePaint);
} finally {
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
}
nDrawRects(mRenderer, rects, count, paint.mNativePaint);
}
private static native void nDrawRects(long renderer, float[] rects, int count, long paint);
@ -1029,12 +962,7 @@ class GLES20Canvas extends HardwareCanvas {
public void drawPoints(float[] pts, int offset, int count, Paint paint) {
if (count < 2) return;
int modifiers = setupModifiers(paint, MODIFIER_SHADER);
try {
nDrawPoints(mRenderer, pts, offset, count, paint.mNativePaint);
} finally {
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
}
nDrawPoints(mRenderer, pts, offset, count, paint.mNativePaint);
}
private static native void nDrawPoints(long renderer, float[] points,
@ -1047,12 +975,7 @@ class GLES20Canvas extends HardwareCanvas {
throw new IndexOutOfBoundsException();
}
int modifiers = setupModifiers(paint);
try {
nDrawPosText(mRenderer, text, index, count, pos, paint.mNativePaint);
} finally {
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
}
nDrawPosText(mRenderer, text, index, count, pos, paint.mNativePaint);
}
private static native void nDrawPosText(long renderer, char[] text, int index, int count,
@ -1065,12 +988,7 @@ class GLES20Canvas extends HardwareCanvas {
throw new ArrayIndexOutOfBoundsException();
}
int modifiers = setupModifiers(paint);
try {
nDrawPosText(mRenderer, text, 0, text.length(), pos, paint.mNativePaint);
} finally {
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
}
nDrawPosText(mRenderer, text, 0, text.length(), pos, paint.mNativePaint);
}
private static native void nDrawPosText(long renderer, String text, int start, int end,
@ -1079,12 +997,7 @@ class GLES20Canvas extends HardwareCanvas {
@Override
public void drawRect(float left, float top, float right, float bottom, Paint paint) {
if (left == right || top == bottom) return;
int modifiers = setupModifiers(paint, MODIFIER_SHADER);
try {
nDrawRect(mRenderer, left, top, right, bottom, paint.mNativePaint);
} finally {
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
}
nDrawRect(mRenderer, left, top, right, bottom, paint.mNativePaint);
}
private static native void nDrawRect(long renderer, float left, float top,
@ -1108,12 +1021,7 @@ class GLES20Canvas extends HardwareCanvas {
@Override
public void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
Paint paint) {
int modifiers = setupModifiers(paint, MODIFIER_SHADER);
try {
nDrawRoundRect(mRenderer, left, top, right, bottom, rx, ry, paint.mNativePaint);
} finally {
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
}
nDrawRoundRect(mRenderer, left, top, right, bottom, rx, ry, paint.mNativePaint);
}
private static native void nDrawRoundRect(long renderer, float left, float top,
@ -1125,13 +1033,8 @@ class GLES20Canvas extends HardwareCanvas {
throw new IndexOutOfBoundsException();
}
int modifiers = setupModifiers(paint);
try {
nDrawText(mRenderer, text, index, count, x, y, paint.mBidiFlags, paint.mNativePaint,
paint.mNativeTypeface);
} finally {
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
}
nDrawText(mRenderer, text, index, count, x, y,
paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
}
private static native void nDrawText(long renderer, char[] text, int index, int count,
@ -1139,24 +1042,18 @@ class GLES20Canvas extends HardwareCanvas {
@Override
public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
int modifiers = setupModifiers(paint);
try {
if (text instanceof String || text instanceof SpannedString ||
text instanceof SpannableString) {
nDrawText(mRenderer, text.toString(), start, end, x, y, paint.mBidiFlags,
paint.mNativePaint, paint.mNativeTypeface);
} else if (text instanceof GraphicsOperations) {
((GraphicsOperations) text).drawText(this, start, end, x, y,
paint);
} else {
char[] buf = TemporaryBuffer.obtain(end - start);
TextUtils.getChars(text, start, end, buf, 0);
nDrawText(mRenderer, buf, 0, end - start, x, y,
paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
TemporaryBuffer.recycle(buf);
}
} finally {
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
if (text instanceof String || text instanceof SpannedString ||
text instanceof SpannableString) {
nDrawText(mRenderer, text.toString(), start, end, x, y, paint.mBidiFlags,
paint.mNativePaint, paint.mNativeTypeface);
} else if (text instanceof GraphicsOperations) {
((GraphicsOperations) text).drawText(this, start, end, x, y, paint);
} else {
char[] buf = TemporaryBuffer.obtain(end - start);
TextUtils.getChars(text, start, end, buf, 0);
nDrawText(mRenderer, buf, 0, end - start, x, y,
paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
TemporaryBuffer.recycle(buf);
}
}
@ -1166,13 +1063,8 @@ class GLES20Canvas extends HardwareCanvas {
throw new IndexOutOfBoundsException();
}
int modifiers = setupModifiers(paint);
try {
nDrawText(mRenderer, text, start, end, x, y, paint.mBidiFlags, paint.mNativePaint,
paint.mNativeTypeface);
} finally {
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
}
nDrawText(mRenderer, text, start, end, x, y,
paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
}
private static native void nDrawText(long renderer, String text, int start, int end,
@ -1180,13 +1072,8 @@ class GLES20Canvas extends HardwareCanvas {
@Override
public void drawText(String text, float x, float y, Paint paint) {
int modifiers = setupModifiers(paint);
try {
nDrawText(mRenderer, text, 0, text.length(), x, y, paint.mBidiFlags,
paint.mNativePaint, paint.mNativeTypeface);
} finally {
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
}
nDrawText(mRenderer, text, 0, text.length(), x, y,
paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
}
@Override
@ -1196,13 +1083,8 @@ class GLES20Canvas extends HardwareCanvas {
throw new ArrayIndexOutOfBoundsException();
}
int modifiers = setupModifiers(paint);
try {
nDrawTextOnPath(mRenderer, text, index, count, path.mNativePath, hOffset, vOffset,
paint.mBidiFlags, paint.mNativePaint);
} finally {
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
}
nDrawTextOnPath(mRenderer, text, index, count, path.mNativePath, hOffset, vOffset,
paint.mBidiFlags, paint.mNativePaint);
}
private static native void nDrawTextOnPath(long renderer, char[] text, int index, int count,
@ -1212,13 +1094,8 @@ class GLES20Canvas extends HardwareCanvas {
public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) {
if (text.length() == 0) return;
int modifiers = setupModifiers(paint);
try {
nDrawTextOnPath(mRenderer, text, 0, text.length(), path.mNativePath, hOffset, vOffset,
paint.mBidiFlags, paint.mNativePaint);
} finally {
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
}
nDrawTextOnPath(mRenderer, text, 0, text.length(), path.mNativePath, hOffset, vOffset,
paint.mBidiFlags, paint.mNativePaint);
}
private static native void nDrawTextOnPath(long renderer, String text, int start, int end,
@ -1234,13 +1111,8 @@ class GLES20Canvas extends HardwareCanvas {
throw new IllegalArgumentException("Unknown direction: " + dir);
}
int modifiers = setupModifiers(paint);
try {
nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y, dir,
paint.mNativePaint, paint.mNativeTypeface);
} finally {
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
}
nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y, dir,
paint.mNativePaint, paint.mNativeTypeface);
}
private static native void nDrawTextRun(long renderer, char[] text, int index, int count,
@ -1253,27 +1125,22 @@ class GLES20Canvas extends HardwareCanvas {
throw new IndexOutOfBoundsException();
}
int modifiers = setupModifiers(paint);
try {
int flags = dir == 0 ? 0 : 1;
if (text instanceof String || text instanceof SpannedString ||
text instanceof SpannableString) {
nDrawTextRun(mRenderer, text.toString(), start, end, contextStart,
contextEnd, x, y, flags, paint.mNativePaint, paint.mNativeTypeface);
} else if (text instanceof GraphicsOperations) {
((GraphicsOperations) text).drawTextRun(this, start, end,
contextStart, contextEnd, x, y, flags, paint);
} else {
int contextLen = contextEnd - contextStart;
int len = end - start;
char[] buf = TemporaryBuffer.obtain(contextLen);
TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
nDrawTextRun(mRenderer, buf, start - contextStart, len, 0, contextLen,
x, y, flags, paint.mNativePaint, paint.mNativeTypeface);
TemporaryBuffer.recycle(buf);
}
} finally {
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
int flags = dir == 0 ? 0 : 1;
if (text instanceof String || text instanceof SpannedString ||
text instanceof SpannableString) {
nDrawTextRun(mRenderer, text.toString(), start, end, contextStart,
contextEnd, x, y, flags, paint.mNativePaint, paint.mNativeTypeface);
} else if (text instanceof GraphicsOperations) {
((GraphicsOperations) text).drawTextRun(this, start, end,
contextStart, contextEnd, x, y, flags, paint);
} else {
int contextLen = contextEnd - contextStart;
int len = end - start;
char[] buf = TemporaryBuffer.obtain(contextLen);
TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
nDrawTextRun(mRenderer, buf, start - contextStart, len, 0, contextLen,
x, y, flags, paint.mNativePaint, paint.mNativeTypeface);
TemporaryBuffer.recycle(buf);
}
}
@ -1286,40 +1153,4 @@ class GLES20Canvas extends HardwareCanvas {
int indexOffset, int indexCount, Paint paint) {
// TODO: Implement
}
private int setupModifiers(Bitmap b, Paint paint) {
if (b.getConfig() != Bitmap.Config.ALPHA_8) {
return MODIFIER_NONE;
} else {
return setupModifiers(paint);
}
}
private int setupModifiers(Paint paint) {
int modifiers = MODIFIER_NONE;
final Shader shader = paint.getShader();
if (shader != null) {
nSetupShader(mRenderer, shader.native_shader);
modifiers |= MODIFIER_SHADER;
}
return modifiers;
}
private int setupModifiers(Paint paint, int flags) {
int modifiers = MODIFIER_NONE;
final Shader shader = paint.getShader();
if (shader != null && (flags & MODIFIER_SHADER) != 0) {
nSetupShader(mRenderer, shader.native_shader);
modifiers |= MODIFIER_SHADER;
}
return modifiers;
}
private static native void nSetupShader(long renderer, long shader);
private static native void nResetModifiers(long renderer, int modifiers);
}

View File

@ -50,26 +50,16 @@ static jint Color_HSVToColor(JNIEnv* env, jobject, jint alpha, jfloatArray hsvAr
///////////////////////////////////////////////////////////////////////////////////////////////
static void Shader_destructor(JNIEnv* env, jobject o, jlong shaderHandle, jlong skiaShaderHandle)
static void Shader_destructor(JNIEnv* env, jobject o, jlong shaderHandle)
{
SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
SkiaShader* skiaShader = reinterpret_cast<SkiaShader*>(skiaShaderHandle);
SkSafeUnref(shader);
// skiaShader == NULL when not !USE_OPENGL_RENDERER, so no need to delete it outside the ifdef
#ifdef USE_OPENGL_RENDERER
if (android::uirenderer::Caches::hasInstance()) {
android::uirenderer::Caches::getInstance().resourceCache.destructor(skiaShader);
} else {
delete skiaShader;
}
#endif
}
static void Shader_setLocalMatrix(JNIEnv* env, jobject o, jlong shaderHandle,
jlong skiaShaderHandle, jlong matrixHandle)
jlong matrixHandle)
{
SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
SkiaShader* skiaShader = reinterpret_cast<SkiaShader*>(skiaShaderHandle);
const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
if (shader) {
if (NULL == matrix) {
@ -78,9 +68,6 @@ static void Shader_setLocalMatrix(JNIEnv* env, jobject o, jlong shaderHandle,
else {
shader->setLocalMatrix(*matrix);
}
#ifdef USE_OPENGL_RENDERER
skiaShader->setMatrix(const_cast<SkMatrix*>(matrix));
#endif
}
}
@ -98,20 +85,6 @@ static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong bitmapHandle
return reinterpret_cast<jlong>(s);
}
static jlong BitmapShader_postConstructor(JNIEnv* env, jobject o, jlong shaderHandle,
jlong bitmapHandle, jint tileModeX, jint tileModeY) {
SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
#ifdef USE_OPENGL_RENDERER
SkiaShader* skiaShader = new SkiaBitmapShader(bitmap, shader,
static_cast<SkShader::TileMode>(tileModeX), static_cast<SkShader::TileMode>(tileModeY),
NULL, !shader->isOpaque());
return reinterpret_cast<jlong>(skiaShader);
#else
return NULL;
#endif
}
///////////////////////////////////////////////////////////////////////////////////////////////
static jlong LinearGradient_create1(JNIEnv* env, jobject o,
@ -141,105 +114,6 @@ static jlong LinearGradient_create1(JNIEnv* env, jobject o,
return reinterpret_cast<jlong>(shader);
}
static jlong LinearGradient_postCreate1(JNIEnv* env, jobject o, jlong shaderHandle,
jfloat x0, jfloat y0, jfloat x1, jfloat y1, jintArray colorArray,
jfloatArray posArray, jint tileMode) {
#ifdef USE_OPENGL_RENDERER
SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
size_t count = env->GetArrayLength(colorArray);
const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
jfloat* storedBounds = new jfloat[4];
storedBounds[0] = x0; storedBounds[1] = y0;
storedBounds[2] = x1; storedBounds[3] = y1;
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();
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++) {
storedPositions[i] = step * i;
}
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, stopCount, shader, static_cast<SkShader::TileMode>(tileMode), NULL,
!shader->isOpaque());
env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT);
return reinterpret_cast<jlong>(skiaShader);
#else
return NULL;
#endif
}
static jlong LinearGradient_postCreate2(JNIEnv* env, jobject o, jlong shaderHandle,
jfloat x0, jfloat y0, jfloat x1, jfloat y1, jint color0, jint color1, jint tileMode) {
#ifdef USE_OPENGL_RENDERER
SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
float* storedBounds = new float[4];
storedBounds[0] = x0; storedBounds[1] = y0;
storedBounds[2] = x1; storedBounds[3] = y1;
float* storedPositions = new float[2];
storedPositions[0] = 0.0f;
storedPositions[1] = 1.0f;
uint32_t* storedColors = new uint32_t[2];
storedColors[0] = static_cast<uint32_t>(color0);
storedColors[1] = static_cast<uint32_t>(color1);
SkiaShader* skiaShader = new SkiaLinearGradientShader(storedBounds, storedColors,
storedPositions, 2, shader, static_cast<SkShader::TileMode>(tileMode), NULL,
!shader->isOpaque());
return reinterpret_cast<jlong>(skiaShader);
#else
return NULL;
#endif
}
static jlong LinearGradient_create2(JNIEnv* env, jobject o,
jfloat x0, jfloat y0, jfloat x1, jfloat y1,
jint color0, jint color1, jint tileMode)
@ -300,67 +174,6 @@ static jlong RadialGradient_create2(JNIEnv* env, jobject, jfloat x, jfloat y, jf
return reinterpret_cast<jlong>(s);
}
static jlong RadialGradient_postCreate1(JNIEnv* env, jobject o, jlong shaderHandle,
jfloat x, jfloat y, jfloat radius, jintArray colorArray, jfloatArray posArray, jint tileMode) {
#ifdef USE_OPENGL_RENDERER
SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
size_t count = env->GetArrayLength(colorArray);
const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
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]);
}
if (posArray) {
AutoJavaFloatArray autoPos(env, posArray, count);
const float* posValues = autoPos.ptr();
for (size_t i = 0; i < count; i++) {
storedPositions[i] = posValues[i];
}
} else {
storedPositions[0] = 0.0f;
const jfloat step = 1.0f / (count - 1);
for (size_t i = 1; i < count - 1; i++) {
storedPositions[i] = step * i;
}
storedPositions[count - 1] = 1.0f;
}
SkiaShader* skiaShader = new SkiaCircularGradientShader(x, y, radius, storedColors,
storedPositions, count, shader, (SkShader::TileMode) tileMode, NULL,
!shader->isOpaque());
env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT);
return reinterpret_cast<jlong>(skiaShader);
#else
return NULL;
#endif
}
static jlong RadialGradient_postCreate2(JNIEnv* env, jobject o, jlong shaderHandle,
jfloat x, jfloat y, jfloat radius, jint color0, jint color1, jint tileMode) {
#ifdef USE_OPENGL_RENDERER
SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
float* storedPositions = new float[2];
storedPositions[0] = 0.0f;
storedPositions[1] = 1.0f;
uint32_t* storedColors = new uint32_t[2];
storedColors[0] = static_cast<uint32_t>(color0);
storedColors[1] = static_cast<uint32_t>(color1);
SkiaShader* skiaShader = new SkiaCircularGradientShader(x, y, radius, storedColors,
storedPositions, 2, shader, (SkShader::TileMode) tileMode, NULL,
!shader->isOpaque());
return reinterpret_cast<jlong>(skiaShader);
#else
return NULL;
#endif
}
///////////////////////////////////////////////////////////////////////////////
static jlong SweepGradient_create1(JNIEnv* env, jobject, jfloat x, jfloat y,
@ -393,65 +206,6 @@ static jlong SweepGradient_create2(JNIEnv* env, jobject, jfloat x, jfloat y,
return reinterpret_cast<jlong>(s);
}
static jlong SweepGradient_postCreate1(JNIEnv* env, jobject o, jlong shaderHandle,
jfloat x, jfloat y, jintArray colorArray, jfloatArray posArray) {
#ifdef USE_OPENGL_RENDERER
SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
size_t count = env->GetArrayLength(colorArray);
const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
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]);
}
if (posArray) {
AutoJavaFloatArray autoPos(env, posArray, count);
const float* posValues = autoPos.ptr();
for (size_t i = 0; i < count; i++) {
storedPositions[i] = posValues[i];
}
} else {
storedPositions[0] = 0.0f;
const jfloat step = 1.0f / (count - 1);
for (size_t i = 1; i < count - 1; i++) {
storedPositions[i] = step * i;
}
storedPositions[count - 1] = 1.0f;
}
SkiaShader* skiaShader = new SkiaSweepGradientShader(x, y, storedColors, storedPositions, count,
shader, NULL, !shader->isOpaque());
env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT);
return reinterpret_cast<jlong>(skiaShader);
#else
return NULL;
#endif
}
static jlong SweepGradient_postCreate2(JNIEnv* env, jobject o, jlong shaderHandle,
jfloat x, jfloat y, jint color0, jint color1) {
#ifdef USE_OPENGL_RENDERER
SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
float* storedPositions = new float[2];
storedPositions[0] = 0.0f;
storedPositions[1] = 1.0f;
uint32_t* storedColors = new uint32_t[2];
storedColors[0] = static_cast<uint32_t>(color0);
storedColors[1] = static_cast<uint32_t>(color1);
SkiaShader* skiaShader = new SkiaSweepGradientShader(x, y, storedColors, storedPositions, 2,
shader, NULL, !shader->isOpaque());
return reinterpret_cast<jlong>(skiaShader);
#else
return NULL;
#endif
}
///////////////////////////////////////////////////////////////////////////////////////////////
static jlong ComposeShader_create1(JNIEnv* env, jobject o,
@ -476,40 +230,6 @@ static jlong ComposeShader_create2(JNIEnv* env, jobject o,
return reinterpret_cast<jlong>(shader);
}
static jlong ComposeShader_postCreate2(JNIEnv* env, jobject o, jlong shaderHandle,
jlong shaderAHandle, jlong shaderBHandle, jint porterDuffModeHandle) {
#ifdef USE_OPENGL_RENDERER
SkShader* shader = reinterpret_cast<SkShader *>(shaderHandle);
SkiaShader* shaderA = reinterpret_cast<SkiaShader *>(shaderAHandle);
SkiaShader* shaderB = reinterpret_cast<SkiaShader *>(shaderBHandle);
SkPorterDuff::Mode porterDuffMode = static_cast<SkPorterDuff::Mode>(porterDuffModeHandle);
SkXfermode::Mode mode = SkPorterDuff::ToXfermodeMode(porterDuffMode);
SkiaShader* skiaShader = new SkiaComposeShader(shaderA, shaderB, mode, shader);
return reinterpret_cast<jlong>(skiaShader);
#else
return NULL;
#endif
}
static jlong ComposeShader_postCreate1(JNIEnv* env, jobject o, jlong shaderHandle,
jlong shaderAHandle, jlong shaderBHandle, jlong modeHandle) {
#ifdef USE_OPENGL_RENDERER
SkShader* shader = reinterpret_cast<SkShader *>(shaderHandle);
SkiaShader* shaderA = reinterpret_cast<SkiaShader *>(shaderAHandle);
SkiaShader* shaderB = reinterpret_cast<SkiaShader *>(shaderBHandle);
SkXfermode* mode = reinterpret_cast<SkXfermode *>(modeHandle);
SkXfermode::Mode skiaMode;
if (!SkXfermode::AsMode(mode, &skiaMode)) {
// TODO: Support other modes
skiaMode = SkXfermode::kSrcOver_Mode;
}
SkiaShader* skiaShader = new SkiaComposeShader(shaderA, shaderB, skiaMode, shader);
return reinterpret_cast<jlong>(skiaShader);
#else
return NULL;
#endif
}
///////////////////////////////////////////////////////////////////////////////////////////////
static JNINativeMethod gColorMethods[] = {
@ -518,41 +238,32 @@ static JNINativeMethod gColorMethods[] = {
};
static JNINativeMethod gShaderMethods[] = {
{ "nativeDestructor", "(JJ)V", (void*)Shader_destructor },
{ "nativeSetLocalMatrix", "(JJJ)V", (void*)Shader_setLocalMatrix }
{ "nativeDestructor", "(J)V", (void*)Shader_destructor },
{ "nativeSetLocalMatrix", "(JJ)V", (void*)Shader_setLocalMatrix }
};
static JNINativeMethod gBitmapShaderMethods[] = {
{ "nativeCreate", "(JII)J", (void*)BitmapShader_constructor },
{ "nativePostCreate", "(JJII)J", (void*)BitmapShader_postConstructor }
};
static JNINativeMethod gLinearGradientMethods[] = {
{ "nativeCreate1", "(FFFF[I[FI)J", (void*)LinearGradient_create1 },
{ "nativeCreate2", "(FFFFIII)J", (void*)LinearGradient_create2 },
{ "nativePostCreate1", "(JFFFF[I[FI)J", (void*)LinearGradient_postCreate1 },
{ "nativePostCreate2", "(JFFFFIII)J", (void*)LinearGradient_postCreate2 }
};
static JNINativeMethod gRadialGradientMethods[] = {
{ "nativeCreate1", "(FFF[I[FI)J", (void*)RadialGradient_create1 },
{ "nativeCreate2", "(FFFIII)J", (void*)RadialGradient_create2 },
{ "nativePostCreate1", "(JFFF[I[FI)J", (void*)RadialGradient_postCreate1 },
{ "nativePostCreate2", "(JFFFIII)J", (void*)RadialGradient_postCreate2 }
};
static JNINativeMethod gSweepGradientMethods[] = {
{ "nativeCreate1", "(FF[I[F)J", (void*)SweepGradient_create1 },
{ "nativeCreate2", "(FFII)J", (void*)SweepGradient_create2 },
{ "nativePostCreate1", "(JFF[I[F)J", (void*)SweepGradient_postCreate1 },
{ "nativePostCreate2", "(JFFII)J", (void*)SweepGradient_postCreate2 }
};
static JNINativeMethod gComposeShaderMethods[] = {
{ "nativeCreate1", "(JJJ)J", (void*)ComposeShader_create1 },
{ "nativeCreate2", "(JJI)J", (void*)ComposeShader_create2 },
{ "nativePostCreate1", "(JJJJ)J", (void*)ComposeShader_postCreate1 },
{ "nativePostCreate2", "(JJJI)J", (void*)ComposeShader_postCreate2 }
};
#include <android_runtime/AndroidRuntime.h>

View File

@ -45,7 +45,6 @@
#include <DisplayListRenderer.h>
#include <LayerRenderer.h>
#include <OpenGLRenderer.h>
#include <SkiaShader.h>
#include <Stencil.h>
#include <Rect.h>
#include <RenderNode.h>
@ -85,8 +84,6 @@ using namespace uirenderer;
#define RENDERER_LOGD(...)
#endif
#define MODIFIER_SHADER 2
// ----------------------------------------------------------------------------
static struct {
@ -615,24 +612,6 @@ static void android_view_GLES20Canvas_drawLines(JNIEnv* env, jobject clazz,
env->ReleaseFloatArrayElements(points, storage, 0);
}
// ----------------------------------------------------------------------------
// Shaders and color filters
// ----------------------------------------------------------------------------
static void android_view_GLES20Canvas_resetModifiers(JNIEnv* env, jobject clazz,
jlong rendererPtr, jint modifiers) {
OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
if (modifiers & MODIFIER_SHADER) renderer->resetShader();
}
static void android_view_GLES20Canvas_setupShader(JNIEnv* env, jobject clazz,
jlong rendererPtr, jlong shaderPtr) {
OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
SkiaShader* shader = reinterpret_cast<SkiaShader*>(shaderPtr);
renderer->setupShader(shader);
}
// ----------------------------------------------------------------------------
// Draw filters
// ----------------------------------------------------------------------------
@ -1091,9 +1070,6 @@ static JNINativeMethod gMethods[] = {
{ "nDrawPath", "(JJJ)V", (void*) android_view_GLES20Canvas_drawPath },
{ "nDrawLines", "(J[FIIJ)V", (void*) android_view_GLES20Canvas_drawLines },
{ "nResetModifiers", "(JI)V", (void*) android_view_GLES20Canvas_resetModifiers },
{ "nSetupShader", "(JJ)V", (void*) android_view_GLES20Canvas_setupShader },
{ "nSetupPaintFilter", "(JII)V", (void*) android_view_GLES20Canvas_setupPaintFilter },
{ "nResetPaintFilter", "(J)V", (void*) android_view_GLES20Canvas_resetPaintFilter },

View File

@ -44,7 +44,6 @@ public class BitmapShader extends Shader {
mTileY = tileY;
final long b = bitmap.ni();
native_instance = nativeCreate(b, tileX.nativeInt, tileY.nativeInt);
native_shader = nativePostCreate(native_instance, b, tileX.nativeInt, tileY.nativeInt);
}
/**
@ -59,6 +58,4 @@ public class BitmapShader extends Shader {
private static native long nativeCreate(long native_bitmap, int shaderTileModeX,
int shaderTileModeY);
private static native long nativePostCreate(long native_shader, long native_bitmap,
int shaderTileModeX, int shaderTileModeY);
}

View File

@ -55,14 +55,6 @@ public class ComposeShader extends Shader {
mXferMode = mode;
native_instance = nativeCreate1(shaderA.native_instance, shaderB.native_instance,
(mode != null) ? mode.native_instance : 0);
if (mode instanceof PorterDuffXfermode) {
PorterDuff.Mode pdMode = ((PorterDuffXfermode) mode).mode;
native_shader = nativePostCreate2(native_instance, shaderA.native_shader,
shaderB.native_shader, pdMode != null ? pdMode.nativeInt : 0);
} else {
native_shader = nativePostCreate1(native_instance, shaderA.native_shader,
shaderB.native_shader, mode != null ? mode.native_instance : 0);
}
}
/** Create a new compose shader, given shaders A, B, and a combining PorterDuff mode.
@ -79,8 +71,6 @@ public class ComposeShader extends Shader {
mPorterDuffMode = mode;
native_instance = nativeCreate2(shaderA.native_instance, shaderB.native_instance,
mode.nativeInt);
native_shader = nativePostCreate2(native_instance, shaderA.native_shader,
shaderB.native_shader, mode.nativeInt);
}
/**
@ -108,8 +98,4 @@ public class ComposeShader extends Shader {
long native_mode);
private static native long nativeCreate2(long native_shaderA, long native_shaderB,
int porterDuffMode);
private static native long nativePostCreate1(long native_shader, long native_skiaShaderA,
long native_skiaShaderB, long native_mode);
private static native long nativePostCreate2(long native_shader, long native_skiaShaderA,
long native_skiaShaderB, int porterDuffMode);
}

View File

@ -66,8 +66,6 @@ public class LinearGradient extends Shader {
mPositions = positions;
mTileMode = tile;
native_instance = nativeCreate1(x0, y0, x1, y1, colors, positions, tile.nativeInt);
native_shader = nativePostCreate1(native_instance, x0, y0, x1, y1, colors, positions,
tile.nativeInt);
}
/** Create a shader that draws a linear gradient along a line.
@ -90,8 +88,6 @@ public class LinearGradient extends Shader {
mColor1 = color1;
mTileMode = tile;
native_instance = nativeCreate2(x0, y0, x1, y1, color0, color1, tile.nativeInt);
native_shader = nativePostCreate2(native_instance, x0, y0, x1, y1, color0, color1,
tile.nativeInt);
}
/**
@ -120,8 +116,4 @@ public class LinearGradient extends Shader {
int colors[], float positions[], int tileMode);
private native long nativeCreate2(float x0, float y0, float x1, float y1,
int color0, int color1, int tileMode);
private native long nativePostCreate1(long native_shader, float x0, float y0, float x1, float y1,
int colors[], float positions[], int tileMode);
private native long nativePostCreate2(long native_shader, float x0, float y0, float x1, float y1,
int color0, int color1, int tileMode);
}

View File

@ -66,8 +66,6 @@ public class RadialGradient extends Shader {
mPositions = positions;
mTileMode = tile;
native_instance = nativeCreate1(x, y, radius, colors, positions, tile.nativeInt);
native_shader = nativePostCreate1(native_instance, x, y, radius, colors, positions,
tile.nativeInt);
}
/** Create a shader that draws a radial gradient given the center and radius.
@ -91,8 +89,6 @@ public class RadialGradient extends Shader {
mColor1 = color1;
mTileMode = tile;
native_instance = nativeCreate2(x, y, radius, color0, color1, tile.nativeInt);
native_shader = nativePostCreate2(native_instance, x, y, radius, color0, color1,
tile.nativeInt);
}
/**
@ -121,10 +117,5 @@ public class RadialGradient extends Shader {
int colors[], float positions[], int tileMode);
private static native long nativeCreate2(float x, float y, float radius,
int color0, int color1, int tileMode);
private static native long nativePostCreate1(long native_shader, float x, float y, float radius,
int colors[], float positions[], int tileMode);
private static native long nativePostCreate2(long native_shader, float x, float y, float radius,
int color0, int color1, int tileMode);
}

View File

@ -29,10 +29,6 @@ public class Shader {
* @hide
*/
public long native_instance;
/**
* @hide
*/
public long native_shader;
private Matrix mLocalMatrix;
@ -78,7 +74,7 @@ public class Shader {
*/
public void setLocalMatrix(Matrix localM) {
mLocalMatrix = localM;
nativeSetLocalMatrix(native_instance, native_shader,
nativeSetLocalMatrix(native_instance,
localM == null ? 0 : localM.native_instance);
}
@ -86,7 +82,7 @@ public class Shader {
try {
super.finalize();
} finally {
nativeDestructor(native_instance, native_shader);
nativeDestructor(native_instance);
}
}
@ -112,7 +108,7 @@ public class Shader {
}
}
private static native void nativeDestructor(long native_shader, long native_skiaShader);
private static native void nativeDestructor(long native_shader);
private static native void nativeSetLocalMatrix(long native_shader,
long native_skiaShader, long matrix_instance);
long matrix_instance);
}

View File

@ -63,7 +63,6 @@ public class SweepGradient extends Shader {
mColors = colors;
mPositions = positions;
native_instance = nativeCreate1(cx, cy, colors, positions);
native_shader = nativePostCreate1(native_instance, cx, cy, colors, positions);
}
/**
@ -81,7 +80,6 @@ public class SweepGradient extends Shader {
mColor0 = color0;
mColor1 = color1;
native_instance = nativeCreate2(cx, cy, color0, color1);
native_shader = nativePostCreate2(native_instance, cx, cy, color0, color1);
}
/**
@ -108,10 +106,5 @@ public class SweepGradient extends Shader {
private static native long nativeCreate1(float x, float y, int colors[], float positions[]);
private static native long nativeCreate2(float x, float y, int color0, int color1);
private static native long nativePostCreate1(long native_shader, float cx, float cy,
int[] colors, float[] positions);
private static native long nativePostCreate2(long native_shader, float cx, float cy,
int color0, int color1);
}

View File

@ -33,6 +33,7 @@
#include "thread/TaskManager.h"
#include "AssetAtlas.h"
#include "Extensions.h"
#include "FontRenderer.h"
#include "GammaFontRenderer.h"
#include "TextureCache.h"

View File

@ -230,6 +230,11 @@ public:
return false;
}
if (op->mPaint && mOps[0].op->mPaint &&
op->mPaint->getShader() != mOps[0].op->mPaint->getShader()) {
return false;
}
/* Draw Modifiers compatibility check
*
* Shadows are ignored, as only text uses them, and in that case they are drawn
@ -244,7 +249,6 @@ public:
*/
const DrawModifiers& lhsMod = lhs->mDrawModifiers;
const DrawModifiers& rhsMod = rhs->mDrawModifiers;
if (lhsMod.mShader != rhsMod.mShader) return false;
// Draw filter testing expects bit fields to be clear if filter not set.
if (lhsMod.mHasDrawFilter != rhsMod.mHasDrawFilter) return false;

View File

@ -58,11 +58,6 @@ void DisplayListData::cleanupResources() {
caches.resourceCache.decrementRefcountLocked(patchResources.itemAt(i));
}
for (size_t i = 0; i < shaders.size(); i++) {
caches.resourceCache.decrementRefcountLocked(shaders.itemAt(i));
caches.resourceCache.destructorLocked(shaders.itemAt(i));
}
for (size_t i = 0; i < sourcePaths.size(); i++) {
caches.resourceCache.decrementRefcountLocked(sourcePaths.itemAt(i));
}
@ -92,7 +87,6 @@ void DisplayListData::cleanupResources() {
bitmapResources.clear();
ownedBitmapResources.clear();
patchResources.clear();
shaders.clear();
sourcePaths.clear();
paints.clear();
regions.clear();

View File

@ -56,7 +56,6 @@ class DisplayListRenderer;
class OpenGLRenderer;
class Rect;
class Layer;
class SkiaShader;
class ClipRectOp;
class SaveLayerOp;
@ -127,7 +126,6 @@ public:
SortedVector<const SkPath*> sourcePaths;
Vector<const SkRegion*> regions;
Vector<const SkMatrix*> matrices;
Vector<SkiaShader*> shaders;
Vector<Layer*> layers;
uint32_t functorCount;
bool hasDrawOps;

View File

@ -208,9 +208,16 @@ protected:
if (!state.mMatrix.isSimple()) return false;
// check state/paint for transparency
if (state.mDrawModifiers.mShader ||
state.mAlpha != 1.0f ||
(mPaint && mPaint->getAlpha() != 0xFF)) return false;
if (mPaint) {
if (mPaint->getShader() && !mPaint->getShader()->isOpaque()) {
return false;
}
if (mPaint->getAlpha() != 0xFF) {
return false;
}
}
if (state.mAlpha != 1.0f) return false;
SkXfermode::Mode mode = OpenGLRenderer::getXfermodeDirect(mPaint);
return (mode == SkXfermode::kSrcOver_Mode ||
@ -592,37 +599,6 @@ private:
const SkRegion* mRegion;
};
class ResetShaderOp : public StateOp {
public:
virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
renderer.resetShader();
}
virtual void output(int level, uint32_t logFlags) const {
OP_LOGS("ResetShader");
}
virtual const char* name() { return "ResetShader"; }
};
class SetupShaderOp : public StateOp {
public:
SetupShaderOp(SkiaShader* shader)
: mShader(shader) {}
virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
renderer.setupShader(mShader);
}
virtual void output(int level, uint32_t logFlags) const {
OP_LOG("SetupShader, shader %p", mShader);
}
virtual const char* name() { return "SetupShader"; }
private:
SkiaShader* mShader;
};
class ResetPaintFilterOp : public StateOp {
public:
virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {

View File

@ -47,7 +47,6 @@ DisplayListRenderer::~DisplayListRenderer() {
///////////////////////////////////////////////////////////////////////////////
DisplayListData* DisplayListRenderer::finishRecording() {
mShaderMap.clear();
mPaintMap.clear();
mRegionMap.clear();
mPathMap.clear();
@ -394,15 +393,6 @@ status_t DisplayListRenderer::drawRects(const float* rects, int count, const SkP
return DrawGlInfo::kStatusDone;
}
void DisplayListRenderer::resetShader() {
addStateOp(new (alloc()) ResetShaderOp());
}
void DisplayListRenderer::setupShader(SkiaShader* shader) {
shader = refShader(shader);
addStateOp(new (alloc()) SetupShaderOp(shader));
}
void DisplayListRenderer::resetPaintFilter() {
addStateOp(new (alloc()) ResetPaintFilterOp());
}

View File

@ -95,9 +95,6 @@ public:
virtual bool clipRegion(const SkRegion* region, SkRegion::Op op);
// Misc - should be implemented with SkPaint inspection
virtual void resetShader();
virtual void setupShader(SkiaShader* shader);
virtual void resetPaintFilter();
virtual void setupPaintFilter(int clearBits, int setBits);
@ -269,21 +266,6 @@ private:
return bitmap;
}
inline SkiaShader* refShader(SkiaShader* shader) {
if (!shader) return NULL;
SkiaShader* shaderCopy = mShaderMap.valueFor(shader);
// TODO: We also need to handle generation ID changes in compose shaders
if (shaderCopy == NULL || shaderCopy->getGenerationId() != shader->getGenerationId()) {
shaderCopy = shader->copy();
// replaceValueFor() performs an add if the entry doesn't exist
mShaderMap.replaceValueFor(shader, shaderCopy);
mDisplayListData->shaders.add(shaderCopy);
mCaches.resourceCache.incrementRefcount(shaderCopy);
}
return shaderCopy;
}
inline const Res_png_9patch* refPatch(const Res_png_9patch* patch) {
mDisplayListData->patchResources.add(patch);
mCaches.resourceCache.incrementRefcount(patch);
@ -293,7 +275,6 @@ private:
DefaultKeyedVector<const SkPaint*, const SkPaint*> mPaintMap;
DefaultKeyedVector<const SkPath*, const SkPath*> mPathMap;
DefaultKeyedVector<const SkRegion*, const SkRegion*> mRegionMap;
DefaultKeyedVector<SkiaShader*, SkiaShader*> mShaderMap;
Caches& mCaches;
DisplayListData* mDisplayListData;

View File

@ -73,7 +73,7 @@ status_t TextSetupFunctor::operator ()(int what, void* data) {
}
}
renderer->setupDrawColorFilter(paint->getColorFilter());
renderer->setupDrawShader();
renderer->setupDrawShader(paint->getShader());
renderer->setupDrawBlending(paint);
renderer->setupDrawProgram();
renderer->setupDrawModelView(kModelViewMode_Translate, false,
@ -85,7 +85,7 @@ status_t TextSetupFunctor::operator ()(int what, void* data) {
renderer->setupDrawTexture(0);
renderer->setupDrawPureColorUniforms();
renderer->setupDrawColorFilterUniforms(paint->getColorFilter());
renderer->setupDrawShaderUniforms(pureTranslate);
renderer->setupDrawShaderUniforms(paint->getShader(), pureTranslate);
renderer->setupDrawTextGammaUniforms();
return NO_ERROR;

View File

@ -21,6 +21,7 @@
#include <sys/types.h>
#include <SkCanvas.h>
#include <SkShader.h>
#include <SkTypeface.h>
#include <utils/Log.h>
@ -37,6 +38,7 @@
#include "PathTessellator.h"
#include "Properties.h"
#include "ShadowTessellator.h"
#include "SkiaShader.h"
#include "utils/GLUtils.h"
#include "Vector.h"
#include "VertexBuffer.h"
@ -1053,6 +1055,45 @@ void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap)
#define DRAW_DOUBLE_STENCIL(DRAW_COMMAND) DRAW_DOUBLE_STENCIL_IF(true, DRAW_COMMAND)
// This class is purely for inspection. It inherits from SkShader, but Skia does not know how to
// use it. The OpenGLRenderer will look at it to find its Layer and whether it is opaque.
class LayerShader : public SkShader {
public:
LayerShader(Layer* layer, const SkMatrix* localMatrix)
: INHERITED(localMatrix)
, mLayer(layer) {
}
virtual bool asACustomShader(void** data) const {
if (data) {
*data = static_cast<void*>(mLayer);
}
return true;
}
virtual bool isOpaque() const {
return !mLayer->isBlend();
}
protected:
virtual void shadeSpan(int x, int y, SkPMColor[], int count) {
LOG_ALWAYS_FATAL("LayerShader should never be drawn with raster backend.");
}
virtual void flatten(SkWriteBuffer&) const {
LOG_ALWAYS_FATAL("LayerShader should never be flattened.");
}
virtual Factory getFactory() const {
LOG_ALWAYS_FATAL("LayerShader should never be created from a stream.");
return NULL;
}
private:
// Unowned.
Layer* mLayer;
typedef SkShader INHERITED;
};
void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) {
if (CC_UNLIKELY(layer->region.isEmpty())) return; // nothing to draw
@ -1066,21 +1107,19 @@ void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) {
paint.setAntiAlias(true);
paint.setColor(SkColorSetARGB(int(getLayerAlpha(layer) * 255), 0, 0, 0));
SkiaShader* oldShader = mDrawModifiers.mShader;
// create LayerShader to map SaveLayer content into subsequent draw
SkMatrix shaderMatrix;
shaderMatrix.setTranslate(rect.left, rect.bottom);
shaderMatrix.preScale(1, -1);
SkiaLayerShader layerShader(layer, &shaderMatrix);
mDrawModifiers.mShader = &layerShader;
LayerShader layerShader(layer, &shaderMatrix);
paint.setShader(&layerShader);
// Since the drawing primitive is defined in local drawing space,
// we don't need to modify the draw matrix
const SkPath* maskPath = layer->getConvexMask();
DRAW_DOUBLE_STENCIL(drawConvexPath(*maskPath, &paint));
mDrawModifiers.mShader = oldShader;
paint.setShader(NULL);
restore();
return;
@ -1627,9 +1666,9 @@ void OpenGLRenderer::setupDrawColor(float r, float g, float b, float a) {
mSetShaderColor = mDescription.setColorModulate(a);
}
void OpenGLRenderer::setupDrawShader() {
if (mDrawModifiers.mShader) {
mDrawModifiers.mShader->describe(mDescription, mExtensions);
void OpenGLRenderer::setupDrawShader(const SkShader* shader) {
if (shader != NULL) {
SkiaShader::describe(&mCaches, mDescription, mExtensions, *shader);
}
}
@ -1655,15 +1694,21 @@ void OpenGLRenderer::accountForClear(SkXfermode::Mode mode) {
}
}
static bool isBlendedColorFilter(const SkColorFilter* filter) {
if (filter == NULL) {
return false;
}
return (filter->getFlags() & SkColorFilter::kAlphaUnchanged_Flag) == 0;
}
void OpenGLRenderer::setupDrawBlending(const Layer* layer, bool swapSrcDst) {
SkXfermode::Mode mode = layer->getMode();
// When the blending mode is kClear_Mode, we need to use a modulate color
// argb=1,0,0,0
accountForClear(mode);
// TODO: check shader blending, once we have shader drawing support for layers.
bool blend = layer->isBlend() || getLayerAlpha(layer) < 1.0f ||
(mColorSet && mColorA < 1.0f) ||
(mDrawModifiers.mShader && mDrawModifiers.mShader->blend()) ||
layer->getColorFilter();
(mColorSet && mColorA < 1.0f) || isBlendedColorFilter(layer->getColorFilter());
chooseBlending(blend, mode, mDescription, swapSrcDst);
}
@ -1673,8 +1718,8 @@ void OpenGLRenderer::setupDrawBlending(const SkPaint* paint, bool blend, bool sw
// argb=1,0,0,0
accountForClear(mode);
blend |= (mColorSet && mColorA < 1.0f) ||
(mDrawModifiers.mShader && mDrawModifiers.mShader->blend()) ||
(paint && paint->getColorFilter());
(getShader(paint) && !getShader(paint)->isOpaque()) ||
isBlendedColorFilter(getColorFilter(paint));
chooseBlending(blend, mode, mDescription, swapSrcDst);
}
@ -1717,8 +1762,8 @@ void OpenGLRenderer::setupDrawModelView(ModelViewMode mode, bool offset,
}
}
void OpenGLRenderer::setupDrawColorUniforms() {
if ((mColorSet && !mDrawModifiers.mShader) || (mDrawModifiers.mShader && mSetShaderColor)) {
void OpenGLRenderer::setupDrawColorUniforms(bool hasShader) {
if ((mColorSet && !hasShader) || (hasShader && mSetShaderColor)) {
mCaches.currentProgram->setColor(mColorR, mColorG, mColorB, mColorA);
}
}
@ -1729,20 +1774,22 @@ void OpenGLRenderer::setupDrawPureColorUniforms() {
}
}
void OpenGLRenderer::setupDrawShaderUniforms(bool ignoreTransform) {
if (mDrawModifiers.mShader) {
if (ignoreTransform) {
// if ignoreTransform=true was passed to setupDrawModelView, undo currentTransform()
// because it was built into modelView / the geometry, and the SkiaShader needs to
// compensate.
mat4 modelViewWithoutTransform;
modelViewWithoutTransform.loadInverse(*currentTransform());
modelViewWithoutTransform.multiply(mModelViewMatrix);
mModelViewMatrix.load(modelViewWithoutTransform);
}
mDrawModifiers.mShader->setupProgram(mCaches.currentProgram,
mModelViewMatrix, *mSnapshot, &mTextureUnit);
void OpenGLRenderer::setupDrawShaderUniforms(const SkShader* shader, bool ignoreTransform) {
if (shader == NULL) {
return;
}
if (ignoreTransform) {
// if ignoreTransform=true was passed to setupDrawModelView, undo currentTransform()
// because it was built into modelView / the geometry, and the description needs to
// compensate.
mat4 modelViewWithoutTransform;
modelViewWithoutTransform.loadInverse(*currentTransform());
modelViewWithoutTransform.multiply(mModelViewMatrix);
mModelViewMatrix.load(modelViewWithoutTransform);
}
SkiaShader::setupProgram(&mCaches, mModelViewMatrix, &mTextureUnit, mExtensions, *shader);
}
void OpenGLRenderer::setupDrawColorFilterUniforms(const SkColorFilter* filter) {
@ -2201,7 +2248,7 @@ status_t OpenGLRenderer::drawBitmap(const SkBitmap* bitmap,
// Apply a scale transform on the canvas only when a shader is in use
// Skia handles the ratio between the dst and src rects as a scale factor
// when a shader is set
bool useScaleTransform = mDrawModifiers.mShader && scaled;
bool useScaleTransform = getShader(paint) && scaled;
bool ignoreTransform = false;
if (CC_LIKELY(currentTransform()->isPureTranslate() && !useScaleTransform)) {
@ -2359,13 +2406,13 @@ status_t OpenGLRenderer::drawVertexBuffer(VertexBufferMode mode,
if (isAA) setupDrawAA();
setupDrawColor(color, ((color >> 24) & 0xFF) * mSnapshot->alpha);
setupDrawColorFilter(getColorFilter(paint));
setupDrawShader();
setupDrawShader(getShader(paint));
setupDrawBlending(paint, isAA);
setupDrawProgram();
setupDrawModelView(kModelViewMode_Translate, useOffset, 0, 0, 0, 0);
setupDrawColorUniforms();
setupDrawColorUniforms(getShader(paint));
setupDrawColorFilterUniforms(getColorFilter(paint));
setupDrawShaderUniforms();
setupDrawShaderUniforms(getShader(paint));
const void* vertices = vertexBuffer.getBuffer();
bool force = mCaches.unbindMeshBuffer();
@ -2670,7 +2717,7 @@ void OpenGLRenderer::drawTextShadow(const SkPaint* paint, const char* text,
const float sy = y - shadow->top + textShadow.dy;
const int shadowAlpha = ((textShadow.color >> 24) & 0xFF) * mSnapshot->alpha;
if (mDrawModifiers.mShader) {
if (getShader(paint)) {
textShadow.color = SK_ColorWHITE;
}
@ -2678,7 +2725,7 @@ void OpenGLRenderer::drawTextShadow(const SkPaint* paint, const char* text,
setupDrawWithTexture(true);
setupDrawAlpha8Color(textShadow.color, shadowAlpha < 255 ? shadowAlpha : alpha);
setupDrawColorFilter(getColorFilter(paint));
setupDrawShader();
setupDrawShader(getShader(paint));
setupDrawBlending(paint, true);
setupDrawProgram();
setupDrawModelView(kModelViewMode_TranslateAndScale, false,
@ -2686,7 +2733,7 @@ void OpenGLRenderer::drawTextShadow(const SkPaint* paint, const char* text,
setupDrawTexture(shadow->id);
setupDrawPureColorUniforms();
setupDrawColorFilterUniforms(getColorFilter(paint));
setupDrawShaderUniforms();
setupDrawShaderUniforms(getShader(paint));
setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset);
glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
@ -3007,21 +3054,6 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y) {
return DrawGlInfo::kStatusDrew;
}
///////////////////////////////////////////////////////////////////////////////
// Shaders
///////////////////////////////////////////////////////////////////////////////
void OpenGLRenderer::resetShader() {
mDrawModifiers.mShader = NULL;
}
void OpenGLRenderer::setupShader(SkiaShader* shader) {
mDrawModifiers.mShader = shader;
if (mDrawModifiers.mShader) {
mDrawModifiers.mShader->setCaches(mCaches);
}
}
///////////////////////////////////////////////////////////////////////////////
// Draw filters
///////////////////////////////////////////////////////////////////////////////
@ -3080,7 +3112,7 @@ void OpenGLRenderer::drawPathTexture(const PathTexture* texture,
setupDrawWithTexture(true);
setupDrawAlpha8Color(paint->getColor(), alpha);
setupDrawColorFilter(getColorFilter(paint));
setupDrawShader();
setupDrawShader(getShader(paint));
setupDrawBlending(paint, true);
setupDrawProgram();
setupDrawModelView(kModelViewMode_TranslateAndScale, false,
@ -3088,7 +3120,7 @@ void OpenGLRenderer::drawPathTexture(const PathTexture* texture,
setupDrawTexture(texture->id);
setupDrawPureColorUniforms();
setupDrawColorFilterUniforms(getColorFilter(paint));
setupDrawShaderUniforms();
setupDrawShaderUniforms(getShader(paint));
setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset);
glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
@ -3254,7 +3286,7 @@ status_t OpenGLRenderer::drawColorRects(const float* rects, int count, const SkP
int color = paint->getColor();
// If a shader is set, preserve only the alpha
if (mDrawModifiers.mShader) {
if (getShader(paint)) {
color |= 0x00ffffff;
}
@ -3290,15 +3322,15 @@ status_t OpenGLRenderer::drawColorRects(const float* rects, int count, const SkP
setupDraw();
setupDrawNoTexture();
setupDrawColor(color, ((color >> 24) & 0xFF) * currentSnapshot()->alpha);
setupDrawShader();
setupDrawShader(getShader(paint));
setupDrawColorFilter(getColorFilter(paint));
setupDrawBlending(paint);
setupDrawProgram();
setupDrawDirtyRegionsDisabled();
setupDrawModelView(kModelViewMode_Translate, false,
0.0f, 0.0f, 0.0f, 0.0f, ignoreTransform);
setupDrawColorUniforms();
setupDrawShaderUniforms();
setupDrawColorUniforms(getShader(paint));
setupDrawShaderUniforms(getShader(paint));
setupDrawColorFilterUniforms(getColorFilter(paint));
if (dirty && hasLayer()) {
@ -3314,21 +3346,21 @@ void OpenGLRenderer::drawColorRect(float left, float top, float right, float bot
const SkPaint* paint, bool ignoreTransform) {
int color = paint->getColor();
// If a shader is set, preserve only the alpha
if (mDrawModifiers.mShader) {
if (getShader(paint)) {
color |= 0x00ffffff;
}
setupDraw();
setupDrawNoTexture();
setupDrawColor(color, ((color >> 24) & 0xFF) * currentSnapshot()->alpha);
setupDrawShader();
setupDrawShader(getShader(paint));
setupDrawColorFilter(getColorFilter(paint));
setupDrawBlending(paint);
setupDrawProgram();
setupDrawModelView(kModelViewMode_TranslateAndScale, false,
left, top, right, bottom, ignoreTransform);
setupDrawColorUniforms();
setupDrawShaderUniforms(ignoreTransform);
setupDrawColorUniforms(getShader(paint));
setupDrawShaderUniforms(getShader(paint), ignoreTransform);
setupDrawColorFilterUniforms(getColorFilter(paint));
setupDrawSimpleMesh();
@ -3441,7 +3473,7 @@ void OpenGLRenderer::drawAlpha8TextureMesh(float left, float top, float right, f
setupDrawAlpha8Color(color, alpha);
}
setupDrawColorFilter(getColorFilter(paint));
setupDrawShader();
setupDrawShader(getShader(paint));
setupDrawBlending(paint, true);
setupDrawProgram();
if (!dirty) setupDrawDirtyRegionsDisabled();
@ -3449,7 +3481,7 @@ void OpenGLRenderer::drawAlpha8TextureMesh(float left, float top, float right, f
setupDrawTexture(texture);
setupDrawPureColorUniforms();
setupDrawColorFilterUniforms(getColorFilter(paint));
setupDrawShaderUniforms(ignoreTransform);
setupDrawShaderUniforms(getShader(paint), ignoreTransform);
setupDrawMesh(vertices, texCoords);
glDrawArrays(drawMode, 0, elementsCount);

View File

@ -26,7 +26,6 @@
#include <SkMatrix.h>
#include <SkPaint.h>
#include <SkRegion.h>
#include <SkShader.h>
#include <SkXfermode.h>
#include <utils/Blur.h>
@ -45,13 +44,15 @@
#include "Program.h"
#include "Rect.h"
#include "Renderer.h"
#include "StatefulBaseRenderer.h"
#include "Snapshot.h"
#include "StatefulBaseRenderer.h"
#include "UvMapper.h"
#include "Vertex.h"
#include "Caches.h"
#include "CanvasProperty.h"
class SkShader;
namespace android {
namespace uirenderer {
@ -59,7 +60,6 @@ class DeferredDisplayState;
class RenderNode;
class TextSetupFunctor;
class VertexBuffer;
class SkiaShader;
struct DrawModifiers {
DrawModifiers() {
@ -70,7 +70,6 @@ struct DrawModifiers {
memset(this, 0, sizeof(DrawModifiers));
}
SkiaShader* mShader;
float mOverrideLayerAlpha;
// Draw filters
@ -217,9 +216,6 @@ public:
status_t drawShadow(const mat4& casterTransformXY, const mat4& casterTransformZ,
float casterAlpha, bool casterUnclipped, const SkPath* casterPerimeter);
virtual void resetShader();
virtual void setupShader(SkiaShader* shader);
virtual void resetPaintFilter();
virtual void setupPaintFilter(int clearBits, int setBits);
@ -466,6 +462,14 @@ protected:
return paint ? paint->getColorFilter() : NULL;
}
/**
* Safely retrieves the Shader from the given Paint. If the paint is
* null then null is returned.
*/
static inline const SkShader* getShader(const SkPaint* paint) {
return paint ? paint->getShader() : NULL;
}
/**
* Set to true to suppress error checks at the end of a frame.
*/
@ -838,7 +842,7 @@ private:
void setupDrawColor(float r, float g, float b, float a);
void setupDrawAlpha8Color(int color, int alpha);
void setupDrawTextGamma(const SkPaint* paint);
void setupDrawShader();
void setupDrawShader(const SkShader* shader);
void setupDrawColorFilter(const SkColorFilter* filter);
void setupDrawBlending(const Layer* layer, bool swapSrcDst = false);
void setupDrawBlending(const SkPaint* paint, bool blend = true, bool swapSrcDst = false);
@ -862,9 +866,17 @@ private:
*/
void setupDrawModelView(ModelViewMode mode, bool offset,
float left, float top, float right, float bottom, bool ignoreTransform = false);
void setupDrawColorUniforms();
void setupDrawColorUniforms(bool hasShader);
void setupDrawPureColorUniforms();
void setupDrawShaderUniforms(bool ignoreTransform = false);
/**
* Setup uniforms for the current shader.
*
* @param shader SkShader on the current paint.
*
* @param ignoreTransform Set to true to ignore the transform in shader.
*/
void setupDrawShaderUniforms(const SkShader* shader, bool ignoreTransform = false);
void setupDrawColorFilterUniforms(const SkColorFilter* paint);
void setupDrawSimpleMesh();
void setupDrawTexture(GLuint texture);

View File

@ -35,7 +35,6 @@ class RenderNode;
class Layer;
class Matrix4;
class SkiaColorFilter;
class SkiaShader;
class Patch;
enum DrawOpMode {
@ -183,9 +182,6 @@ public:
virtual bool clipRegion(const SkRegion* region, SkRegion::Op op) = 0;
// Misc - should be implemented with SkPaint inspection
virtual void resetShader() = 0;
virtual void setupShader(SkiaShader* shader) = 0;
virtual void resetPaintFilter() = 0;
virtual void setupPaintFilter(int clearBits, int setBits) = 0;

View File

@ -71,11 +71,6 @@ void ResourceCache::incrementRefcount(const SkPath* pathResource) {
incrementRefcount((void*) pathResource, kPath);
}
void ResourceCache::incrementRefcount(SkiaShader* shaderResource) {
SkSafeRef(shaderResource->getSkShader());
incrementRefcount((void*) shaderResource, kShader);
}
void ResourceCache::incrementRefcount(const Res_png_9patch* patchResource) {
incrementRefcount((void*) patchResource, kNinePatch);
}
@ -104,11 +99,6 @@ void ResourceCache::incrementRefcountLocked(const SkPath* pathResource) {
incrementRefcountLocked((void*) pathResource, kPath);
}
void ResourceCache::incrementRefcountLocked(SkiaShader* shaderResource) {
SkSafeRef(shaderResource->getSkShader());
incrementRefcountLocked((void*) shaderResource, kShader);
}
void ResourceCache::incrementRefcountLocked(const Res_png_9patch* patchResource) {
incrementRefcountLocked((void*) patchResource, kNinePatch);
}
@ -132,11 +122,6 @@ void ResourceCache::decrementRefcount(const SkPath* pathResource) {
decrementRefcount((void*) pathResource);
}
void ResourceCache::decrementRefcount(SkiaShader* shaderResource) {
SkSafeUnref(shaderResource->getSkShader());
decrementRefcount((void*) shaderResource);
}
void ResourceCache::decrementRefcount(const Res_png_9patch* patchResource) {
decrementRefcount((void*) patchResource);
}
@ -168,11 +153,6 @@ void ResourceCache::decrementRefcountLocked(const SkPath* pathResource) {
decrementRefcountLocked((void*) pathResource);
}
void ResourceCache::decrementRefcountLocked(SkiaShader* shaderResource) {
SkSafeUnref(shaderResource->getSkShader());
decrementRefcountLocked((void*) shaderResource);
}
void ResourceCache::decrementRefcountLocked(const Res_png_9patch* patchResource) {
decrementRefcountLocked((void*) patchResource);
}
@ -227,25 +207,6 @@ void ResourceCache::destructorLocked(const SkBitmap* resource) {
}
}
void ResourceCache::destructor(SkiaShader* resource) {
Mutex::Autolock _l(mLock);
destructorLocked(resource);
}
void ResourceCache::destructorLocked(SkiaShader* resource) {
ssize_t index = mCache->indexOfKey(resource);
ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
if (ref == NULL) {
// If we're not tracking this resource, just delete it
delete resource;
return;
}
ref->destroyed = true;
if (ref->refCount == 0) {
deleteResourceReferenceLocked(resource, ref);
}
}
void ResourceCache::destructor(Res_png_9patch* resource) {
Mutex::Autolock _l(mLock);
destructorLocked(resource);
@ -333,11 +294,6 @@ void ResourceCache::deleteResourceReferenceLocked(const void* resource, Resource
}
}
break;
case kShader: {
SkiaShader* shader = (SkiaShader*) resource;
delete shader;
}
break;
case kNinePatch: {
if (Caches::hasInstance()) {
Caches::getInstance().patchCache.removeDeferred((Res_png_9patch*) resource);

View File

@ -20,7 +20,6 @@
#include <cutils/compiler.h>
#include <SkBitmap.h>
#include <SkiaShader.h>
#include <utils/KeyedVector.h>
@ -36,7 +35,6 @@ namespace uirenderer {
*/
enum ResourceType {
kBitmap,
kShader,
kNinePatch,
kPath,
kLayer
@ -70,36 +68,30 @@ public:
void incrementRefcount(const SkPath* resource);
void incrementRefcount(const SkBitmap* resource);
void incrementRefcount(SkiaShader* resource);
void incrementRefcount(const Res_png_9patch* resource);
void incrementRefcount(Layer* resource);
void incrementRefcountLocked(const SkPath* resource);
void incrementRefcountLocked(const SkBitmap* resource);
void incrementRefcountLocked(SkiaShader* resource);
void incrementRefcountLocked(const Res_png_9patch* resource);
void incrementRefcountLocked(Layer* resource);
void decrementRefcount(const SkBitmap* resource);
void decrementRefcount(const SkPath* resource);
void decrementRefcount(SkiaShader* resource);
void decrementRefcount(const Res_png_9patch* resource);
void decrementRefcount(Layer* resource);
void decrementRefcountLocked(const SkBitmap* resource);
void decrementRefcountLocked(const SkPath* resource);
void decrementRefcountLocked(SkiaShader* resource);
void decrementRefcountLocked(const Res_png_9patch* resource);
void decrementRefcountLocked(Layer* resource);
void destructor(SkPath* resource);
void destructor(const SkBitmap* resource);
void destructor(SkiaShader* resource);
void destructor(Res_png_9patch* resource);
void destructorLocked(SkPath* resource);
void destructorLocked(const SkBitmap* resource);
void destructorLocked(SkiaShader* resource);
void destructorLocked(Res_png_9patch* resource);
bool recycle(SkBitmap* resource);

View File

@ -21,9 +21,10 @@
#include <SkMatrix.h>
#include "Caches.h"
#include "Layer.h"
#include "Matrix.h"
#include "SkiaShader.h"
#include "Texture.h"
#include "Matrix.h"
namespace android {
namespace uirenderer {
@ -54,89 +55,142 @@ static inline void bindUniformColor(int slot, uint32_t color) {
a);
}
///////////////////////////////////////////////////////////////////////////////
// Base shader
///////////////////////////////////////////////////////////////////////////////
void SkiaShader::copyFrom(const SkiaShader& shader) {
mType = shader.mType;
mKey = shader.mKey;
mTileX = shader.mTileX;
mTileY = shader.mTileY;
mBlend = shader.mBlend;
mUnitMatrix = shader.mUnitMatrix;
mShaderMatrix = shader.mShaderMatrix;
mGenerationId = shader.mGenerationId;
}
SkiaShader::SkiaShader(): mCaches(NULL) {
}
SkiaShader::SkiaShader(Type type, SkShader* key, SkShader::TileMode tileX,
SkShader::TileMode tileY, const SkMatrix* matrix, bool blend):
mType(type), mKey(key), mTileX(tileX), mTileY(tileY), mBlend(blend),
mCaches(NULL) {
setMatrix(matrix);
mGenerationId = 0;
}
SkiaShader::~SkiaShader() {
}
void SkiaShader::describe(ProgramDescription& description, const Extensions& extensions) {
}
void SkiaShader::setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot,
GLuint* textureUnit) {
}
void SkiaShader::bindTexture(Texture* texture, GLenum wrapS, GLenum wrapT) {
mCaches->bindTexture(texture->id);
static inline void bindTexture(Caches* caches, Texture* texture, GLenum wrapS, GLenum wrapT) {
caches->bindTexture(texture->id);
texture->setWrapST(wrapS, wrapT);
}
void SkiaShader::computeScreenSpaceMatrix(mat4& screenSpace, const mat4& modelView) {
screenSpace.loadMultiply(mUnitMatrix, mShaderMatrix);
screenSpace.multiply(modelView);
/**
* Compute the matrix to transform to screen space.
* @param screenSpace Output param for the computed matrix.
* @param unitMatrix The unit matrix for gradient shaders, as returned by SkShader::asAGradient,
* or identity.
* @param localMatrix Local matrix, as returned by SkShader::getLocalMatrix().
* @param modelViewMatrix Model view matrix, as supplied by the OpenGLRenderer.
*/
static void computeScreenSpaceMatrix(mat4& screenSpace, const SkMatrix& unitMatrix,
const SkMatrix& localMatrix, const mat4& modelViewMatrix) {
mat4 shaderMatrix;
// uses implicit construction
shaderMatrix.loadInverse(localMatrix);
// again, uses implicit construction
screenSpace.loadMultiply(unitMatrix, shaderMatrix);
screenSpace.multiply(modelViewMatrix);
}
// Returns true if one is a bitmap and the other is a gradient
static bool bitmapAndGradient(SkiaShaderType type1, SkiaShaderType type2) {
return (type1 == kBitmap_SkiaShaderType && type2 == kGradient_SkiaShaderType)
|| (type2 == kBitmap_SkiaShaderType && type1 == kGradient_SkiaShaderType);
}
SkiaShaderType SkiaShader::getType(const SkShader& shader) {
// First check for a gradient shader.
switch (shader.asAGradient(NULL)) {
case SkShader::kNone_GradientType:
// Not a gradient shader. Fall through to check for other types.
break;
case SkShader::kLinear_GradientType:
case SkShader::kRadial_GradientType:
case SkShader::kSweep_GradientType:
return kGradient_SkiaShaderType;
default:
// This is a Skia gradient that has no SkiaShader equivalent. Return None to skip.
return kNone_SkiaShaderType;
}
// The shader is not a gradient. Check for a bitmap shader.
if (shader.asABitmap(NULL, NULL, NULL) == SkShader::kDefault_BitmapType) {
return kBitmap_SkiaShaderType;
}
// Check for a ComposeShader.
SkShader::ComposeRec rec;
if (shader.asACompose(&rec)) {
const SkiaShaderType shaderAType = getType(*rec.fShaderA);
const SkiaShaderType shaderBType = getType(*rec.fShaderB);
// Compose is only supported if one is a bitmap and the other is a
// gradient. Otherwise, return None to skip.
if (!bitmapAndGradient(shaderAType, shaderBType)) {
return kNone_SkiaShaderType;
}
return kCompose_SkiaShaderType;
}
if (shader.asACustomShader(NULL)) {
return kLayer_SkiaShaderType;
}
return kNone_SkiaShaderType;
}
typedef void (*describeProc)(Caches* caches, ProgramDescription& description,
const Extensions& extensions, const SkShader& shader);
describeProc gDescribeProc[] = {
InvalidSkiaShader::describe,
SkiaBitmapShader::describe,
SkiaGradientShader::describe,
SkiaComposeShader::describe,
SkiaLayerShader::describe,
};
typedef void (*setupProgramProc)(Caches* caches, const mat4& modelViewMatrix,
GLuint* textureUnit, const Extensions& extensions, const SkShader& shader);
setupProgramProc gSetupProgramProc[] = {
InvalidSkiaShader::setupProgram,
SkiaBitmapShader::setupProgram,
SkiaGradientShader::setupProgram,
SkiaComposeShader::setupProgram,
SkiaLayerShader::setupProgram,
};
void SkiaShader::describe(Caches* caches, ProgramDescription& description,
const Extensions& extensions, const SkShader& shader) {
gDescribeProc[getType(shader)](caches, description, extensions, shader);
}
void SkiaShader::setupProgram(Caches* caches, const mat4& modelViewMatrix,
GLuint* textureUnit, const Extensions& extensions, const SkShader& shader) {
gSetupProgramProc[getType(shader)](caches, modelViewMatrix, textureUnit, extensions, shader);
}
///////////////////////////////////////////////////////////////////////////////
// Layer shader
///////////////////////////////////////////////////////////////////////////////
SkiaLayerShader::SkiaLayerShader(Layer* layer, const SkMatrix* matrix):
SkiaShader(kBitmap, NULL, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode,
matrix, layer->isBlend()), mLayer(layer) {
updateLocalMatrix(matrix);
}
SkiaShader* SkiaLayerShader::copy() {
SkiaLayerShader* copy = new SkiaLayerShader();
copy->copyFrom(*this);
copy->mLayer = mLayer;
return copy;
}
void SkiaLayerShader::describe(ProgramDescription& description, const Extensions& extensions) {
void SkiaLayerShader::describe(Caches*, ProgramDescription& description,
const Extensions&, const SkShader& shader) {
description.hasBitmap = true;
}
void SkiaLayerShader::setupProgram(Program* program, const mat4& modelView,
const Snapshot& snapshot, GLuint* textureUnit) {
GLuint textureSlot = (*textureUnit)++;
Caches::getInstance().activeTexture(textureSlot);
void SkiaLayerShader::setupProgram(Caches* caches, const mat4& modelViewMatrix,
GLuint* textureUnit, const Extensions&, const SkShader& shader) {
Layer* layer;
if (!shader.asACustomShader(reinterpret_cast<void**>(&layer))) {
LOG_ALWAYS_FATAL("SkiaLayerShader::setupProgram called on the wrong type of shader!");
}
const float width = mLayer->getWidth();
const float height = mLayer->getHeight();
GLuint textureSlot = (*textureUnit)++;
caches->activeTexture(textureSlot);
const float width = layer->getWidth();
const float height = layer->getHeight();
mat4 textureTransform;
computeScreenSpaceMatrix(textureTransform, modelView);
computeScreenSpaceMatrix(textureTransform, SkMatrix::I(), shader.getLocalMatrix(),
modelViewMatrix);
// Uniforms
mLayer->bindTexture();
mLayer->setWrap(GL_CLAMP_TO_EDGE);
mLayer->setFilter(GL_LINEAR);
layer->bindTexture();
layer->setWrap(GL_CLAMP_TO_EDGE);
layer->setFilter(GL_LINEAR);
Program* program = caches->currentProgram;
glUniform1i(program->getUniform("bitmapSampler"), textureSlot);
glUniformMatrix4fv(program->getUniform("textureTransform"), 1,
GL_FALSE, &textureTransform.data[0]);
@ -147,67 +201,99 @@ void SkiaLayerShader::setupProgram(Program* program, const mat4& modelView,
// Bitmap shader
///////////////////////////////////////////////////////////////////////////////
SkiaBitmapShader::SkiaBitmapShader(SkBitmap* bitmap, SkShader* key, SkShader::TileMode tileX,
SkShader::TileMode tileY, SkMatrix* matrix, bool blend):
SkiaShader(kBitmap, key, tileX, tileY, matrix, blend), mBitmap(bitmap), mTexture(NULL) {
updateLocalMatrix(matrix);
}
struct BitmapShaderInfo {
float width;
float height;
GLenum wrapS;
GLenum wrapT;
Texture* texture;
};
SkiaShader* SkiaBitmapShader::copy() {
SkiaBitmapShader* copy = new SkiaBitmapShader();
copy->copyFrom(*this);
copy->mBitmap = mBitmap;
return copy;
}
void SkiaBitmapShader::describe(ProgramDescription& description, const Extensions& extensions) {
Texture* texture = mCaches->textureCache.get(mBitmap);
if (!texture) return;
mTexture = texture;
static bool bitmapShaderHelper(Caches* caches, ProgramDescription* description,
BitmapShaderInfo* shaderInfo,
const Extensions& extensions,
const SkBitmap& bitmap, SkShader::TileMode tileModes[2]) {
Texture* texture = caches->textureCache.get(&bitmap);
if (!texture) return false;
const float width = texture->width;
const float height = texture->height;
GLenum wrapS, wrapT;
description.hasBitmap = true;
if (description) {
description->hasBitmap = true;
}
// The driver does not support non-power of two mirrored/repeated
// textures, so do it ourselves
if (!extensions.hasNPot() && (!isPowerOfTwo(width) || !isPowerOfTwo(height)) &&
(mTileX != SkShader::kClamp_TileMode || mTileY != SkShader::kClamp_TileMode)) {
description.isBitmapNpot = true;
description.bitmapWrapS = gTileModes[mTileX];
description.bitmapWrapT = gTileModes[mTileY];
mWrapS = GL_CLAMP_TO_EDGE;
mWrapT = GL_CLAMP_TO_EDGE;
(tileModes[0] != SkShader::kClamp_TileMode ||
tileModes[1] != SkShader::kClamp_TileMode)) {
if (description) {
description->isBitmapNpot = true;
description->bitmapWrapS = gTileModes[tileModes[0]];
description->bitmapWrapT = gTileModes[tileModes[1]];
}
wrapS = GL_CLAMP_TO_EDGE;
wrapT = GL_CLAMP_TO_EDGE;
} else {
mWrapS = gTileModes[mTileX];
mWrapT = gTileModes[mTileY];
wrapS = gTileModes[tileModes[0]];
wrapT = gTileModes[tileModes[1]];
}
if (shaderInfo) {
shaderInfo->width = width;
shaderInfo->height = height;
shaderInfo->wrapS = wrapS;
shaderInfo->wrapT = wrapT;
shaderInfo->texture = texture;
}
return true;
}
void SkiaBitmapShader::setupProgram(Program* program, const mat4& modelView,
const Snapshot&, GLuint* textureUnit) {
void SkiaBitmapShader::describe(Caches* caches, ProgramDescription& description,
const Extensions& extensions, const SkShader& shader) {
SkBitmap bitmap;
SkShader::TileMode xy[2];
if (shader.asABitmap(&bitmap, NULL, xy) != SkShader::kDefault_BitmapType) {
LOG_ALWAYS_FATAL("SkiaBitmapShader::describe called with a different kind of shader!");
}
bitmapShaderHelper(caches, &description, NULL, extensions, bitmap, xy);
}
void SkiaBitmapShader::setupProgram(Caches* caches, const mat4& modelViewMatrix,
GLuint* textureUnit, const Extensions& extensions, const SkShader& shader) {
SkBitmap bitmap;
SkShader::TileMode xy[2];
if (shader.asABitmap(&bitmap, NULL, xy) != SkShader::kDefault_BitmapType) {
LOG_ALWAYS_FATAL("SkiaBitmapShader::setupProgram called with a different kind of shader!");
}
GLuint textureSlot = (*textureUnit)++;
Caches::getInstance().activeTexture(textureSlot);
Texture* texture = mTexture;
mTexture = NULL;
if (!texture) return;
BitmapShaderInfo shaderInfo;
if (!bitmapShaderHelper(caches, NULL, &shaderInfo, extensions, bitmap, xy)) {
return;
}
Program* program = caches->currentProgram;
Texture* texture = shaderInfo.texture;
const AutoTexture autoCleanup(texture);
const float width = texture->width;
const float height = texture->height;
mat4 textureTransform;
computeScreenSpaceMatrix(textureTransform, modelView);
computeScreenSpaceMatrix(textureTransform, SkMatrix::I(), shader.getLocalMatrix(),
modelViewMatrix);
// Uniforms
bindTexture(texture, mWrapS, mWrapT);
bindTexture(caches, texture, shaderInfo.wrapS, shaderInfo.wrapT);
texture->setFilter(GL_LINEAR);
glUniform1i(program->getUniform("bitmapSampler"), textureSlot);
glUniformMatrix4fv(program->getUniform("textureTransform"), 1,
GL_FALSE, &textureTransform.data[0]);
glUniform2f(program->getUniform("textureDimension"), 1.0f / width, 1.0f / height);
glUniform2f(program->getUniform("textureDimension"), 1.0f / shaderInfo.width,
1.0f / shaderInfo.height);
}
///////////////////////////////////////////////////////////////////////////////
@ -225,74 +311,6 @@ static void toUnitMatrix(const SkPoint pts[2], SkMatrix* matrix) {
matrix->postScale(inv, inv);
}
SkiaLinearGradientShader::SkiaLinearGradientShader(float* bounds, uint32_t* colors,
float* positions, int count, SkShader* key, SkShader::TileMode tileMode,
SkMatrix* matrix, bool blend):
SkiaShader(kLinearGradient, key, tileMode, tileMode, matrix, blend),
mBounds(bounds), mColors(colors), mPositions(positions), mCount(count) {
SkPoint points[2];
points[0].set(bounds[0], bounds[1]);
points[1].set(bounds[2], bounds[3]);
SkMatrix unitMatrix;
toUnitMatrix(points, &unitMatrix);
mUnitMatrix.load(unitMatrix);
updateLocalMatrix(matrix);
mIsSimple = count == 2 && tileMode == SkShader::kClamp_TileMode;
}
SkiaLinearGradientShader::~SkiaLinearGradientShader() {
delete[] mBounds;
delete[] mColors;
delete[] mPositions;
}
SkiaShader* SkiaLinearGradientShader::copy() {
SkiaLinearGradientShader* copy = new SkiaLinearGradientShader();
copy->copyFrom(*this);
copy->mBounds = new float[4];
memcpy(copy->mBounds, mBounds, sizeof(float) * 4);
copy->mColors = new uint32_t[mCount];
memcpy(copy->mColors, mColors, sizeof(uint32_t) * mCount);
copy->mPositions = new float[mCount];
memcpy(copy->mPositions, mPositions, sizeof(float) * mCount);
copy->mCount = mCount;
copy->mIsSimple = mIsSimple;
return copy;
}
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&, GLuint* textureUnit) {
if (CC_UNLIKELY(!mIsSimple)) {
GLuint textureSlot = (*textureUnit)++;
Caches::getInstance().activeTexture(textureSlot);
Texture* texture = mCaches->gradientCache.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]);
}
Caches::getInstance().dither.setupProgram(program, textureUnit);
mat4 screenSpace;
computeScreenSpaceMatrix(screenSpace, modelView);
glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
}
///////////////////////////////////////////////////////////////////////////////
// Circular gradient shader
///////////////////////////////////////////////////////////////////////////////
@ -304,37 +322,6 @@ static void toCircularUnitMatrix(const float x, const float y, const float radiu
matrix->postScale(inv, inv);
}
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, colors, positions, count, key,
tileMode, matrix, blend) {
SkMatrix unitMatrix;
toCircularUnitMatrix(x, y, radius, &unitMatrix);
mUnitMatrix.load(unitMatrix);
updateLocalMatrix(matrix);
}
SkiaShader* SkiaCircularGradientShader::copy() {
SkiaCircularGradientShader* copy = new SkiaCircularGradientShader();
copy->copyFrom(*this);
copy->mColors = new uint32_t[mCount];
memcpy(copy->mColors, mColors, sizeof(uint32_t) * mCount);
copy->mPositions = new float[mCount];
memcpy(copy->mPositions, mPositions, sizeof(float) * mCount);
copy->mCount = mCount;
copy->mIsSimple = mIsSimple;
return copy;
}
void SkiaCircularGradientShader::describe(ProgramDescription& description,
const Extensions& extensions) {
description.hasGradient = true;
description.gradientType = ProgramDescription::kGradientCircular;
description.isSimpleGradient = mIsSimple;
}
///////////////////////////////////////////////////////////////////////////////
// Sweep gradient shader
///////////////////////////////////////////////////////////////////////////////
@ -343,74 +330,103 @@ static void toSweepUnitMatrix(const float x, const float y, SkMatrix* matrix) {
matrix->setTranslate(-x, -y);
}
SkiaSweepGradientShader::SkiaSweepGradientShader(float x, float y, uint32_t* colors,
float* positions, int count, SkShader* key, SkMatrix* matrix, bool blend):
SkiaShader(kSweepGradient, key, SkShader::kClamp_TileMode,
SkShader::kClamp_TileMode, matrix, blend),
mColors(colors), mPositions(positions), mCount(count) {
SkMatrix unitMatrix;
toSweepUnitMatrix(x, y, &unitMatrix);
mUnitMatrix.load(unitMatrix);
///////////////////////////////////////////////////////////////////////////////
// Common gradient code
///////////////////////////////////////////////////////////////////////////////
updateLocalMatrix(matrix);
mIsSimple = count == 2;
static bool isSimpleGradient(const SkShader::GradientInfo& gradInfo) {
return gradInfo.fColorCount == 2 && gradInfo.fTileMode == SkShader::kClamp_TileMode;
}
SkiaSweepGradientShader::SkiaSweepGradientShader(Type type, uint32_t* colors,
float* positions, int count, SkShader* key, SkShader::TileMode tileMode,
SkMatrix* matrix, bool blend):
SkiaShader(type, key, tileMode, tileMode, matrix, blend),
mColors(colors), mPositions(positions), mCount(count) {
// protected method, that doesn't setup mUnitMatrix - should be handled by subclass
void SkiaGradientShader::describe(Caches*, ProgramDescription& description,
const Extensions& extensions, const SkShader& shader) {
SkShader::GradientInfo gradInfo;
gradInfo.fColorCount = 0;
gradInfo.fColors = NULL;
gradInfo.fColorOffsets = NULL;
mIsSimple = count == 2 && tileMode == SkShader::kClamp_TileMode;
}
SkiaSweepGradientShader::~SkiaSweepGradientShader() {
delete[] mColors;
delete[] mPositions;
}
SkiaShader* SkiaSweepGradientShader::copy() {
SkiaSweepGradientShader* copy = new SkiaSweepGradientShader();
copy->copyFrom(*this);
copy->mColors = new uint32_t[mCount];
memcpy(copy->mColors, mColors, sizeof(uint32_t) * mCount);
copy->mPositions = new float[mCount];
memcpy(copy->mPositions, mPositions, sizeof(float) * mCount);
copy->mCount = mCount;
copy->mIsSimple = mIsSimple;
return copy;
}
void SkiaSweepGradientShader::describe(ProgramDescription& description,
const Extensions& extensions) {
switch (shader.asAGradient(&gradInfo)) {
case SkShader::kLinear_GradientType:
description.gradientType = ProgramDescription::kGradientLinear;
break;
case SkShader::kRadial_GradientType:
description.gradientType = ProgramDescription::kGradientCircular;
break;
case SkShader::kSweep_GradientType:
description.gradientType = ProgramDescription::kGradientSweep;
break;
default:
// Do nothing. This shader is unsupported.
return;
}
description.hasGradient = true;
description.gradientType = ProgramDescription::kGradientSweep;
description.isSimpleGradient = mIsSimple;
description.isSimpleGradient = isSimpleGradient(gradInfo);
}
void SkiaSweepGradientShader::setupProgram(Program* program, const mat4& modelView,
const Snapshot& snapshot, GLuint* textureUnit) {
if (CC_UNLIKELY(!mIsSimple)) {
GLuint textureSlot = (*textureUnit)++;
Caches::getInstance().activeTexture(textureSlot);
void SkiaGradientShader::setupProgram(Caches* caches, const mat4& modelViewMatrix,
GLuint* textureUnit, const Extensions&, const SkShader& shader) {
// SkShader::GradientInfo.fColorCount is an in/out parameter. As input, it tells asAGradient
// how much space has been allocated for fColors and fColorOffsets. 10 was chosen
// arbitrarily, but should be >= 2.
// As output, it tells the number of actual colors/offsets in the gradient.
const int COLOR_COUNT = 10;
SkAutoSTMalloc<COLOR_COUNT, SkColor> colorStorage(COLOR_COUNT);
SkAutoSTMalloc<COLOR_COUNT, SkScalar> positionStorage(COLOR_COUNT);
Texture* texture = mCaches->gradientCache.get(mColors, mPositions, mCount);
SkShader::GradientInfo gradInfo;
gradInfo.fColorCount = COLOR_COUNT;
gradInfo.fColors = colorStorage.get();
gradInfo.fColorOffsets = positionStorage.get();
SkShader::GradientType gradType = shader.asAGradient(&gradInfo);
Program* program = caches->currentProgram;
if (CC_UNLIKELY(!isSimpleGradient(gradInfo))) {
if (gradInfo.fColorCount > COLOR_COUNT) {
// There was not enough room in our arrays for all the colors and offsets. Try again,
// now that we know the true number of colors.
gradInfo.fColors = colorStorage.reset(gradInfo.fColorCount);
gradInfo.fColorOffsets = positionStorage.reset(gradInfo.fColorCount);
shader.asAGradient(&gradInfo);
}
GLuint textureSlot = (*textureUnit)++;
caches->activeTexture(textureSlot);
#ifndef SK_SCALAR_IS_FLOAT
#error Need to convert gradInfo.fColorOffsets to float!
#endif
Texture* texture = caches->gradientCache.get(gradInfo.fColors, gradInfo.fColorOffsets,
gradInfo.fColorCount);
// Uniforms
bindTexture(texture, gTileModes[mTileX], gTileModes[mTileY]);
bindTexture(caches, texture, gTileModes[gradInfo.fTileMode], gTileModes[gradInfo.fTileMode]);
glUniform1i(program->getUniform("gradientSampler"), textureSlot);
} else {
bindUniformColor(program->getUniform("startColor"), mColors[0]);
bindUniformColor(program->getUniform("endColor"), mColors[1]);
bindUniformColor(program->getUniform("startColor"), gradInfo.fColors[0]);
bindUniformColor(program->getUniform("endColor"), gradInfo.fColors[1]);
}
mCaches->dither.setupProgram(program, textureUnit);
caches->dither.setupProgram(program, textureUnit);
SkMatrix unitMatrix;
switch (gradType) {
case SkShader::kLinear_GradientType:
toUnitMatrix(gradInfo.fPoint, &unitMatrix);
break;
case SkShader::kRadial_GradientType:
toCircularUnitMatrix(gradInfo.fPoint[0].fX, gradInfo.fPoint[0].fY,
gradInfo.fRadius[0], &unitMatrix);
break;
case SkShader::kSweep_GradientType:
toSweepUnitMatrix(gradInfo.fPoint[0].fX, gradInfo.fPoint[0].fY, &unitMatrix);
break;
default:
LOG_ALWAYS_FATAL("Invalid SkShader gradient type %d", gradType);
}
mat4 screenSpace;
computeScreenSpaceMatrix(screenSpace, modelView);
computeScreenSpaceMatrix(screenSpace, unitMatrix, shader.getLocalMatrix(), modelViewMatrix);
glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
}
@ -418,49 +434,39 @@ void SkiaSweepGradientShader::setupProgram(Program* program, const mat4& modelVi
// Compose shader
///////////////////////////////////////////////////////////////////////////////
SkiaComposeShader::SkiaComposeShader(SkiaShader* first, SkiaShader* second,
SkXfermode::Mode mode, SkShader* key):
SkiaShader(kCompose, key, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode,
NULL, first->blend() || second->blend()),
mFirst(first), mSecond(second), mMode(mode), mCleanup(false) {
}
SkiaComposeShader::~SkiaComposeShader() {
if (mCleanup) {
delete mFirst;
delete mSecond;
void SkiaComposeShader::describe(Caches* caches, ProgramDescription& description,
const Extensions& extensions, const SkShader& shader) {
SkShader::ComposeRec rec;
if (!shader.asACompose(&rec)) {
LOG_ALWAYS_FATAL("SkiaComposeShader::describe called on the wrong shader type!");
}
}
SkiaShader* SkiaComposeShader::copy() {
SkiaComposeShader* copy = new SkiaComposeShader();
copy->copyFrom(*this);
copy->mFirst = mFirst->copy();
copy->mSecond = mSecond->copy();
copy->mMode = mMode;
copy->cleanup();
return copy;
}
void SkiaComposeShader::describe(ProgramDescription& description, const Extensions& extensions) {
mFirst->describe(description, extensions);
mSecond->describe(description, extensions);
if (mFirst->type() == kBitmap) {
SkiaShader::describe(caches, description, extensions, *rec.fShaderA);
SkiaShader::describe(caches, description, extensions, *rec.fShaderB);
if (SkiaShader::getType(*rec.fShaderA) == kBitmap_SkiaShaderType) {
description.isBitmapFirst = true;
}
description.shadersMode = mMode;
if (!SkXfermode::AsMode(rec.fMode, &description.shadersMode)) {
// TODO: Support other modes.
description.shadersMode = SkXfermode::kSrcOver_Mode;
}
}
void SkiaComposeShader::setupProgram(Program* program, const mat4& modelView,
const Snapshot& snapshot, GLuint* textureUnit) {
void SkiaComposeShader::setupProgram(Caches* caches, const mat4& modelViewMatrix,
GLuint* textureUnit, const Extensions& extensions, const SkShader& shader) {
SkShader::ComposeRec rec;
if (!shader.asACompose(&rec)) {
LOG_ALWAYS_FATAL("SkiaComposeShader::setupProgram called on the wrong shader type!");
}
// Apply this compose shader's local transform and pass it down to
// the child shaders. They will in turn apply their local transform
// to this matrix.
mat4 transform;
computeScreenSpaceMatrix(transform, modelView);
computeScreenSpaceMatrix(transform, SkMatrix::I(), shader.getLocalMatrix(),
modelViewMatrix);
mFirst->setupProgram(program, transform, snapshot, textureUnit);
mSecond->setupProgram(program, transform, snapshot, textureUnit);
SkiaShader::setupProgram(caches, transform, textureUnit, extensions, *rec.fShaderA);
SkiaShader::setupProgram(caches, transform, textureUnit, extensions, *rec.fShaderB);
}
}; // namespace uirenderer

View File

@ -28,249 +28,90 @@
#include "ProgramCache.h"
#include "TextureCache.h"
#include "GradientCache.h"
#include "Snapshot.h"
namespace android {
namespace uirenderer {
class Caches;
///////////////////////////////////////////////////////////////////////////////
// Base shader
///////////////////////////////////////////////////////////////////////////////
class Layer;
/**
* Represents a Skia shader. A shader will modify the GL context and active
* program to recreate the original effect.
* Type of Skia shader in use.
*/
enum SkiaShaderType {
kNone_SkiaShaderType,
kBitmap_SkiaShaderType,
kGradient_SkiaShaderType,
kCompose_SkiaShaderType,
kLayer_SkiaShaderType
};
class SkiaShader {
public:
/**
* Type of Skia shader in use.
*/
enum Type {
kNone,
kBitmap,
kLinearGradient,
kCircularGradient,
kSweepGradient,
kCompose
};
static SkiaShaderType getType(const SkShader& shader);
static void describe(Caches* caches, ProgramDescription& description,
const Extensions& extensions, const SkShader& shader);
static void setupProgram(Caches* caches, const mat4& modelViewMatrix,
GLuint* textureUnit, const Extensions& extensions, const SkShader& shader);
};
ANDROID_API SkiaShader(Type type, SkShader* key, SkShader::TileMode tileX,
SkShader::TileMode tileY, const SkMatrix* matrix, bool blend);
virtual ~SkiaShader();
virtual SkiaShader* copy() = 0;
void copyFrom(const SkiaShader& shader);
virtual void describe(ProgramDescription& description, const Extensions& extensions);
virtual void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot,
GLuint* textureUnit);
inline SkShader* getSkShader() {
return mKey;
class InvalidSkiaShader {
public:
static void describe(Caches* caches, ProgramDescription& description,
const Extensions& extensions, const SkShader& shader) {
// This shader is unsupported. Skip it.
}
static void setupProgram(Caches* caches, const mat4& modelViewMatrix,
GLuint* textureUnit, const Extensions& extensions, const SkShader& shader) {
// This shader is unsupported. Skip it.
}
inline bool blend() const {
return mBlend;
}
Type type() const {
return mType;
}
virtual void setCaches(Caches& caches) {
mCaches = &caches;
}
uint32_t getGenerationId() {
return mGenerationId;
}
void setMatrix(const SkMatrix* matrix) {
updateLocalMatrix(matrix);
mGenerationId++;
}
void updateLocalMatrix(const SkMatrix* matrix) {
if (matrix) {
mat4 localMatrix(*matrix);
mShaderMatrix.loadInverse(localMatrix);
} else {
mShaderMatrix.loadIdentity();
}
}
void computeScreenSpaceMatrix(mat4& screenSpace, const mat4& modelView);
protected:
SkiaShader();
/**
* The appropriate texture unit must have been activated prior to invoking
* this method.
*/
inline void bindTexture(Texture* texture, GLenum wrapS, GLenum wrapT);
Type mType;
SkShader* mKey;
SkShader::TileMode mTileX;
SkShader::TileMode mTileY;
bool mBlend;
Caches* mCaches;
mat4 mUnitMatrix;
mat4 mShaderMatrix;
private:
uint32_t mGenerationId;
}; // struct SkiaShader
///////////////////////////////////////////////////////////////////////////////
// Implementations
///////////////////////////////////////////////////////////////////////////////
};
/**
* A shader that draws a layer.
*/
struct SkiaLayerShader: public SkiaShader {
SkiaLayerShader(Layer* layer, const SkMatrix* matrix);
SkiaShader* copy();
void describe(ProgramDescription& description, const Extensions& extensions);
void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot,
GLuint* textureUnit);
private:
SkiaLayerShader() {
}
Layer* mLayer;
}; // struct SkiaLayerShader
class SkiaLayerShader {
public:
static void describe(Caches* caches, ProgramDescription& description,
const Extensions& extensions, const SkShader& shader);
static void setupProgram(Caches* caches, const mat4& modelViewMatrix,
GLuint* textureUnit, const Extensions& extensions, const SkShader& shader);
}; // class SkiaLayerShader
/**
* A shader that draws a bitmap.
*/
struct SkiaBitmapShader: public SkiaShader {
ANDROID_API SkiaBitmapShader(SkBitmap* bitmap, SkShader* key, SkShader::TileMode tileX,
SkShader::TileMode tileY, SkMatrix* matrix, bool blend);
SkiaShader* copy();
class SkiaBitmapShader {
public:
static void describe(Caches* caches, ProgramDescription& description,
const Extensions& extensions, const SkShader& shader);
static void setupProgram(Caches* caches, const mat4& modelViewMatrix,
GLuint* textureUnit, const Extensions& extensions, const SkShader& shader);
void describe(ProgramDescription& description, const Extensions& extensions);
void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot,
GLuint* textureUnit);
private:
SkiaBitmapShader() : mBitmap(NULL), mTexture(NULL) {
}
SkBitmap* mBitmap;
Texture* mTexture;
GLenum mWrapS;
GLenum mWrapT;
}; // struct SkiaBitmapShader
}; // class SkiaBitmapShader
/**
* A shader that draws a linear gradient.
* A shader that draws one of three types of gradient, depending on shader param.
*/
struct SkiaLinearGradientShader: public SkiaShader {
ANDROID_API SkiaLinearGradientShader(float* bounds, uint32_t* colors, float* positions,
int count, SkShader* key, SkShader::TileMode tileMode, SkMatrix* matrix, bool blend);
~SkiaLinearGradientShader();
SkiaShader* copy();
void describe(ProgramDescription& description, const Extensions& extensions);
void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot,
GLuint* textureUnit);
private:
SkiaLinearGradientShader() {
}
bool mIsSimple;
float* mBounds;
uint32_t* mColors;
float* mPositions;
int mCount;
}; // struct SkiaLinearGradientShader
/**
* A shader that draws a sweep gradient.
*/
struct SkiaSweepGradientShader: public SkiaShader {
ANDROID_API SkiaSweepGradientShader(float x, float y, uint32_t* colors, float* positions,
int count, SkShader* key, SkMatrix* matrix, bool blend);
~SkiaSweepGradientShader();
SkiaShader* copy();
virtual void describe(ProgramDescription& description, const Extensions& extensions);
void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot,
GLuint* textureUnit);
protected:
SkiaSweepGradientShader(Type type, uint32_t* colors, float* positions,
int count, SkShader* key, SkShader::TileMode tileMode, SkMatrix* matrix, bool blend);
SkiaSweepGradientShader() {
}
bool mIsSimple;
uint32_t* mColors;
float* mPositions;
int mCount;
}; // struct SkiaSweepGradientShader
/**
* A shader that draws a circular gradient.
*/
struct SkiaCircularGradientShader: public SkiaSweepGradientShader {
ANDROID_API SkiaCircularGradientShader(float x, float y, float radius, uint32_t* colors,
float* positions, int count, SkShader* key,SkShader::TileMode tileMode,
SkMatrix* matrix, bool blend);
SkiaShader* copy();
void describe(ProgramDescription& description, const Extensions& extensions);
private:
SkiaCircularGradientShader() {
}
}; // struct SkiaCircularGradientShader
class SkiaGradientShader {
public:
static void describe(Caches* caches, ProgramDescription& description,
const Extensions& extensions, const SkShader& shader);
static void setupProgram(Caches* caches, const mat4& modelViewMatrix,
GLuint* textureUnit, const Extensions& extensions, const SkShader& shader);
};
/**
* A shader that draws two shaders, composited with an xfermode.
*/
struct SkiaComposeShader: public SkiaShader {
ANDROID_API SkiaComposeShader(SkiaShader* first, SkiaShader* second, SkXfermode::Mode mode,
SkShader* key);
~SkiaComposeShader();
SkiaShader* copy();
void setCaches(Caches& caches) {
SkiaShader::setCaches(caches);
mFirst->setCaches(caches);
mSecond->setCaches(caches);
}
void describe(ProgramDescription& description, const Extensions& extensions);
void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot,
GLuint* textureUnit);
private:
SkiaComposeShader(): mCleanup(false) {
}
void cleanup() {
mCleanup = true;
}
SkiaShader* mFirst;
SkiaShader* mSecond;
SkXfermode::Mode mMode;
bool mCleanup;
}; // struct SkiaComposeShader
class SkiaComposeShader {
public:
static void describe(Caches* caches, ProgramDescription& description,
const Extensions& extensions, const SkShader& shader);
static void setupProgram(Caches* caches, const mat4& modelViewMatrix,
GLuint* textureUnit, const Extensions& extensions, const SkShader& shader);
}; // class SkiaComposeShader
}; // namespace uirenderer
}; // namespace android

View File

@ -34,7 +34,7 @@ namespace uirenderer {
///////////////////////////////////////////////////////////////////////////////
TextureCache::TextureCache():
mCache(LruCache<const SkBitmap*, Texture*>::kUnlimitedCapacity),
mCache(LruCache<const SkPixelRef*, Texture*>::kUnlimitedCapacity),
mSize(0), mMaxSize(MB(DEFAULT_TEXTURE_CACHE_SIZE)),
mFlushRate(DEFAULT_TEXTURE_CACHE_FLUSH_RATE) {
char property[PROPERTY_VALUE_MAX];
@ -58,7 +58,7 @@ TextureCache::TextureCache():
}
TextureCache::TextureCache(uint32_t maxByteSize):
mCache(LruCache<const SkBitmap*, Texture*>::kUnlimitedCapacity),
mCache(LruCache<const SkPixelRef*, Texture*>::kUnlimitedCapacity),
mSize(0), mMaxSize(maxByteSize) {
init();
}
@ -103,7 +103,7 @@ void TextureCache::setFlushRate(float flushRate) {
// Callbacks
///////////////////////////////////////////////////////////////////////////////
void TextureCache::operator()(const SkBitmap*&, Texture*& texture) {
void TextureCache::operator()(const SkPixelRef*&, Texture*& texture) {
// This will be called already locked
if (texture) {
mSize -= texture->bitmapSize;
@ -122,7 +122,7 @@ void TextureCache::operator()(const SkBitmap*&, Texture*& texture) {
///////////////////////////////////////////////////////////////////////////////
void TextureCache::resetMarkInUse() {
LruCache<const SkBitmap*, Texture*>::Iterator iter(mCache);
LruCache<const SkPixelRef*, Texture*>::Iterator iter(mCache);
while (iter.next()) {
iter.value()->isInUse = false;
}
@ -140,7 +140,7 @@ bool TextureCache::canMakeTextureFromBitmap(const SkBitmap* bitmap) {
// Returns a prepared Texture* that either is already in the cache or can fit
// in the cache (and is thus added to the cache)
Texture* TextureCache::getCachedTexture(const SkBitmap* bitmap) {
Texture* texture = mCache.get(bitmap);
Texture* texture = mCache.get(bitmap->pixelRef());
if (!texture) {
if (!canMakeTextureFromBitmap(bitmap)) {
@ -170,7 +170,7 @@ Texture* TextureCache::getCachedTexture(const SkBitmap* bitmap) {
if (mDebugEnabled) {
ALOGD("Texture created, size = %d", size);
}
mCache.put(bitmap, texture);
mCache.put(bitmap->pixelRef(), texture);
}
} else if (!texture->isInUse && bitmap->getGenerationID() != texture->generation) {
// Texture was in the cache but is dirty, re-upload
@ -218,7 +218,7 @@ Texture* TextureCache::getTransient(const SkBitmap* bitmap) {
}
void TextureCache::remove(const SkBitmap* bitmap) {
mCache.remove(bitmap);
mCache.remove(bitmap->pixelRef());
}
void TextureCache::removeDeferred(const SkBitmap* bitmap) {
@ -231,7 +231,7 @@ void TextureCache::clearGarbage() {
size_t count = mGarbage.size();
for (size_t i = 0; i < count; i++) {
const SkBitmap* bitmap = mGarbage.itemAt(i);
mCache.remove(bitmap);
mCache.remove(bitmap->pixelRef());
delete bitmap;
}
mGarbage.clear();

View File

@ -49,7 +49,7 @@ namespace uirenderer {
* 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 TextureCache: public OnEntryRemoved<const SkBitmap*, Texture*> {
class TextureCache: public OnEntryRemoved<const SkPixelRef*, Texture*> {
public:
TextureCache();
TextureCache(uint32_t maxByteSize);
@ -59,7 +59,7 @@ public:
* Used as a callback when an entry is removed from the cache.
* Do not invoke directly.
*/
void operator()(const SkBitmap*& bitmap, Texture*& texture);
void operator()(const SkPixelRef*& pixelRef, Texture*& texture);
/**
* Resets all Textures to not be marked as in use
@ -147,7 +147,7 @@ private:
void init();
LruCache<const SkBitmap*, Texture*> mCache;
LruCache<const SkPixelRef*, Texture*> mCache;
uint32_t mSize;
uint32_t mMaxSize;

View File

@ -302,6 +302,36 @@ public abstract class DisplayModifier {
paint.setShader(ResourceModifiers.instance().mVertGradient);
}
});
put("radGradient", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
paint.setShader(ResourceModifiers.instance().mRadGradient);
}
});
put("sweepGradient", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
paint.setShader(ResourceModifiers.instance().mSweepGradient);
}
});
put("composeShader", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
paint.setShader(ResourceModifiers.instance().mComposeShader);
}
});
put("bad composeShader", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
paint.setShader(ResourceModifiers.instance().mBadComposeShader);
}
});
put("bad composeShader 2", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
paint.setShader(ResourceModifiers.instance().mAnotherBadComposeShader);
}
});
}
});

View File

@ -23,7 +23,11 @@ import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapShader;
import android.graphics.Color;
import android.graphics.ComposeShader;
import android.graphics.LinearGradient;
import android.graphics.PorterDuff;
import android.graphics.RadialGradient;
import android.graphics.SweepGradient;
import android.graphics.Matrix;
import android.graphics.Shader;
@ -38,6 +42,11 @@ public class ResourceModifiers {
public final LinearGradient mHorGradient;
public final LinearGradient mDiagGradient;
public final LinearGradient mVertGradient;
public final RadialGradient mRadGradient;
public final SweepGradient mSweepGradient;
public final ComposeShader mComposeShader;
public final ComposeShader mBadComposeShader;
public final ComposeShader mAnotherBadComposeShader;
public final Bitmap mBitmap;
private final Matrix mMtx1;
private final Matrix mMtx2;
@ -90,6 +99,12 @@ public class ResourceModifiers {
mVertGradient = new LinearGradient(0.0f, 0.0f, 0.0f, mDrawHeight / 2.0f,
Color.YELLOW, Color.MAGENTA, Shader.TileMode.MIRROR);
mSweepGradient = new SweepGradient(mDrawWidth / 2.0f, mDrawHeight / 2.0f,
Color.YELLOW, Color.MAGENTA);
mComposeShader = new ComposeShader(mRepeatShader, mHorGradient,
PorterDuff.Mode.MULTIPLY);
final float width = mBitmap.getWidth() / 8.0f;
final float height = mBitmap.getHeight() / 8.0f;
@ -106,6 +121,16 @@ public class ResourceModifiers {
0xff00ff00, 0xff0000ff, 0xffff0000, 0xff00ff00,
0x00ff0000, 0x0000ff00, 0x000000ff, 0x00ff0000,
};
// Use a repeating gradient with many colors to test the non simple case.
mRadGradient = new RadialGradient(mDrawWidth / 4.0f, mDrawHeight / 4.0f, 4.0f,
mBitmapColors, null, Shader.TileMode.REPEAT);
mBadComposeShader = new ComposeShader(mRadGradient, mComposeShader,
PorterDuff.Mode.MULTIPLY);
mAnotherBadComposeShader = new ComposeShader(mRadGradient, mVertGradient,
PorterDuff.Mode.MULTIPLY);
}
}