diff options
Diffstat (limited to 'graphics/java/android')
31 files changed, 2367 insertions, 138 deletions
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java index c726d0e..688fd7a 100644 --- a/graphics/java/android/graphics/Bitmap.java +++ b/graphics/java/android/graphics/Bitmap.java @@ -27,7 +27,6 @@ import java.nio.IntBuffer; import java.nio.ShortBuffer; public final class Bitmap implements Parcelable { - /** * Indicates that the bitmap was created for an unknown pixel density. * @@ -64,7 +63,7 @@ public final class Bitmap implements Parcelable { private boolean mRecycled; // Package-scoped for fast access. - /*package*/ int mDensity = sDefaultDensity = getDefaultDensity(); + int mDensity = getDefaultDensity(); private static volatile Matrix sScaleMatrix; @@ -78,15 +77,15 @@ public final class Bitmap implements Parcelable { public static void setDefaultDensity(int density) { sDefaultDensity = density; } - - /*package*/ static int getDefaultDensity() { + + static int getDefaultDensity() { if (sDefaultDensity >= 0) { return sDefaultDensity; } sDefaultDensity = DisplayMetrics.DENSITY_DEVICE; return sDefaultDensity; } - + /** * @noinspection UnusedDeclaration */ @@ -95,7 +94,7 @@ public final class Bitmap implements Parcelable { This can be called from JNI code. */ - /*package*/ Bitmap(int nativeBitmap, byte[] buffer, boolean isMutable, byte[] ninePatchChunk, + Bitmap(int nativeBitmap, byte[] buffer, boolean isMutable, byte[] ninePatchChunk, int density) { this(nativeBitmap, buffer, isMutable, ninePatchChunk, null, density); } @@ -108,7 +107,7 @@ public final class Bitmap implements Parcelable { This can be called from JNI code. */ - /*package*/ Bitmap(int nativeBitmap, byte[] buffer, boolean isMutable, byte[] ninePatchChunk, + Bitmap(int nativeBitmap, byte[] buffer, boolean isMutable, byte[] ninePatchChunk, int[] layoutBounds, int density) { if (nativeBitmap == 0) { throw new RuntimeException("internal error: native bitmap is 0"); @@ -202,9 +201,14 @@ public final class Bitmap implements Parcelable { */ public void recycle() { if (!mRecycled) { - mBuffer = null; - nativeRecycle(mNativeBitmap); - mNinePatchChunk = null; + if (nativeRecycle(mNativeBitmap)) { + // return value indicates whether native pixel object was actually recycled. + // false indicates that it is still in use at the native level and these + // objects should not be collected now. They will be collected later when the + // Bitmap itself is collected. + mBuffer = null; + mNinePatchChunk = null; + } mRecycled = true; } } @@ -347,11 +351,15 @@ public final class Bitmap implements Parcelable { } /** - * Copy the bitmap's pixels into the specified buffer (allocated by the + * <p>Copy the bitmap's pixels into the specified buffer (allocated by the * caller). An exception is thrown if the buffer is not large enough to * hold all of the pixels (taking into account the number of bytes per * pixel) or if the Buffer subclass is not one of the support types - * (ByteBuffer, ShortBuffer, IntBuffer). + * (ByteBuffer, ShortBuffer, IntBuffer).</p> + * <p>The content of the bitmap is copied into the buffer as-is. This means + * that if this bitmap stores its pixels pre-multiplied + * (see {@link #isPremultiplied()}, the values in the buffer will also be + * pre-multiplied.</p> */ public void copyPixelsToBuffer(Buffer dst) { int elements = dst.remaining(); @@ -382,10 +390,10 @@ public final class Bitmap implements Parcelable { } /** - * Copy the pixels from the buffer, beginning at the current position, + * <p>Copy the pixels from the buffer, beginning at the current position, * overwriting the bitmap's pixels. The data in the buffer is not changed * in any way (unlike setPixels(), which converts from unpremultipled 32bit - * to whatever the bitmap's native format is. + * to whatever the bitmap's native format is.</p> */ public void copyPixelsFromBuffer(Buffer src) { checkRecycled("copyPixelsFromBuffer called on recycled bitmap"); @@ -402,7 +410,7 @@ public final class Bitmap implements Parcelable { throw new RuntimeException("unsupported Buffer subclass"); } - long bufferBytes = (long)elements << shift; + long bufferBytes = (long) elements << shift; long bitmapBytes = getByteCount(); if (bufferBytes < bitmapBytes) { @@ -410,6 +418,11 @@ public final class Bitmap implements Parcelable { } nativeCopyPixelsFromBuffer(mNativeBitmap, src); + + // now update the buffer's position + int position = src.position(); + position += bitmapBytes >> shift; + src.position(position); } /** @@ -622,6 +635,22 @@ public final class Bitmap implements Parcelable { /** * Returns a mutable bitmap with the specified width and height. Its + * initial density is determined from the given {@link DisplayMetrics}. + * + * @param display Display metrics for the display this bitmap will be + * drawn on. + * @param width The width of the bitmap + * @param height The height of the bitmap + * @param config The bitmap config to create. + * @throws IllegalArgumentException if the width or height are <= 0 + */ + public static Bitmap createBitmap(DisplayMetrics display, int width, + int height, Config config) { + return createBitmap(display, width, height, config, true); + } + + /** + * Returns a mutable bitmap with the specified width and height. Its * initial density is as per {@link #getDensity}. * * @param width The width of the bitmap @@ -634,10 +663,33 @@ public final class Bitmap implements Parcelable { * @throws IllegalArgumentException if the width or height are <= 0 */ private static Bitmap createBitmap(int width, int height, Config config, boolean hasAlpha) { + return createBitmap(null, width, height, config, hasAlpha); + } + + /** + * Returns a mutable bitmap with the specified width and height. Its + * initial density is determined from the given {@link DisplayMetrics}. + * + * @param display Display metrics for the display this bitmap will be + * drawn on. + * @param width The width of the bitmap + * @param height The height of the bitmap + * @param config The bitmap config to create. + * @param hasAlpha If the bitmap is ARGB_8888 this flag can be used to mark the + * bitmap as opaque. Doing so will clear the bitmap in black + * instead of transparent. + * + * @throws IllegalArgumentException if the width or height are <= 0 + */ + private static Bitmap createBitmap(DisplayMetrics display, int width, int height, + Config config, boolean hasAlpha) { if (width <= 0 || height <= 0) { throw new IllegalArgumentException("width and height must be > 0"); } Bitmap bm = nativeCreate(null, 0, width, width, height, config.nativeInt, true); + if (display != null) { + bm.mDensity = display.densityDpi; + } if (config == Config.ARGB_8888 && !hasAlpha) { nativeErase(bm.mNativeBitmap, 0xff000000); nativeSetHasAlpha(bm.mNativeBitmap, hasAlpha); @@ -670,6 +722,31 @@ public final class Bitmap implements Parcelable { */ public static Bitmap createBitmap(int colors[], int offset, int stride, int width, int height, Config config) { + return createBitmap(null, colors, offset, stride, width, height, config); + } + + /** + * Returns a immutable bitmap with the specified width and height, with each + * pixel value set to the corresponding value in the colors array. Its + * initial density is determined from the given {@link DisplayMetrics}. + * + * @param display Display metrics for the display this bitmap will be + * drawn on. + * @param colors Array of {@link Color} used to initialize the pixels. + * @param offset Number of values to skip before the first color in the + * array of colors. + * @param stride Number of colors in the array between rows (must be >= + * width or <= -width). + * @param width The width of the bitmap + * @param height The height of the bitmap + * @param config The bitmap config to create. If the config does not + * support per-pixel alpha (e.g. RGB_565), then the alpha + * bytes in the colors[] will be ignored (assumed to be FF) + * @throws IllegalArgumentException if the width or height are <= 0, or if + * the color array's length is less than the number of pixels. + */ + public static Bitmap createBitmap(DisplayMetrics display, int colors[], + int offset, int stride, int width, int height, Config config) { checkWidthHeight(width, height); if (Math.abs(stride) < width) { @@ -684,8 +761,12 @@ public final class Bitmap implements Parcelable { if (width <= 0 || height <= 0) { throw new IllegalArgumentException("width and height must be > 0"); } - return nativeCreate(colors, offset, stride, width, height, + Bitmap bm = nativeCreate(colors, offset, stride, width, height, config.nativeInt, false); + if (display != null) { + bm.mDensity = display.densityDpi; + } + return bm; } /** @@ -704,7 +785,29 @@ public final class Bitmap implements Parcelable { * the color array's length is less than the number of pixels. */ public static Bitmap createBitmap(int colors[], int width, int height, Config config) { - return createBitmap(colors, 0, width, width, height, config); + return createBitmap(null, colors, 0, width, width, height, config); + } + + /** + * Returns a immutable bitmap with the specified width and height, with each + * pixel value set to the corresponding value in the colors array. Its + * initial density is determined from the given {@link DisplayMetrics}. + * + * @param display Display metrics for the display this bitmap will be + * drawn on. + * @param colors Array of {@link Color} used to initialize the pixels. + * This array must be at least as large as width * height. + * @param width The width of the bitmap + * @param height The height of the bitmap + * @param config The bitmap config to create. If the config does not + * support per-pixel alpha (e.g. RGB_565), then the alpha + * bytes in the colors[] will be ignored (assumed to be FF) + * @throws IllegalArgumentException if the width or height are <= 0, or if + * the color array's length is less than the number of pixels. + */ + public static Bitmap createBitmap(DisplayMetrics display, int colors[], + int width, int height, Config config) { + return createBitmap(display, colors, 0, width, width, height, config); } /** @@ -780,6 +883,27 @@ public final class Bitmap implements Parcelable { return mIsMutable; } + /** + * <p>Indicates whether pixels stored in this bitmaps are stored pre-multiplied. + * When a pixel is pre-multiplied, the RGB components have been multiplied by + * the alpha component. For instance, if the original color is a 50% + * translucent red <code>(128, 255, 0, 0)</code>, the pre-multiplied form is + * <code>(128, 128, 0, 0)</code>.</p> + * + * <p>This method always returns false if {@link #getConfig()} is + * {@link Bitmap.Config#RGB_565}.</p> + * + * <p>This method only returns true if {@link #hasAlpha()} returns true. + * A bitmap with no alpha channel can be used both as a pre-multiplied and + * as a non pre-multiplied bitmap.</p> + * + * @return true if the underlying pixels have been pre-multiplied, false + * otherwise + */ + public final boolean isPremultiplied() { + return getConfig() != Config.RGB_565 && hasAlpha(); + } + /** Returns the bitmap's width */ public final int getWidth() { return mWidth == -1 ? mWidth = nativeWidth(mNativeBitmap) : mWidth; @@ -848,7 +972,7 @@ public final class Bitmap implements Parcelable { * @hide */ static public int scaleFromDensity(int size, int sdensity, int tdensity) { - if (sdensity == DENSITY_NONE || sdensity == tdensity) { + if (sdensity == DENSITY_NONE || tdensity == DENSITY_NONE || sdensity == tdensity) { return size; } @@ -911,6 +1035,51 @@ public final class Bitmap implements Parcelable { } /** + * Indicates whether the renderer responsible for drawing this + * bitmap should attempt to use mipmaps when this bitmap is drawn + * scaled down. + * + * If you know that you are going to draw this bitmap at less than + * 50% of its original size, you may be able to obtain a higher + * quality + * + * This property is only a suggestion that can be ignored by the + * renderer. It is not guaranteed to have any effect. + * + * @return true if the renderer should attempt to use mipmaps, + * false otherwise + * + * @see #setHasMipMap(boolean) + */ + public final boolean hasMipMap() { + return nativeHasMipMap(mNativeBitmap); + } + + /** + * Set a hint for the renderer responsible for drawing this bitmap + * indicating that it should attempt to use mipmaps when this bitmap + * is drawn scaled down. + * + * If you know that you are going to draw this bitmap at less than + * 50% of its original size, you may be able to obtain a higher + * quality by turning this property on. + * + * Note that if the renderer respects this hint it might have to + * allocate extra memory to hold the mipmap levels for this bitmap. + * + * This property is only a suggestion that can be ignored by the + * renderer. It is not guaranteed to have any effect. + * + * @param hasMipMap indicates whether the renderer should attempt + * to use mipmaps + * + * @see #hasMipMap() + */ + public final void setHasMipMap(boolean hasMipMap) { + nativeSetHasMipMap(mNativeBitmap, hasMipMap); + } + + /** * Fills the bitmap's pixels with the specified {@link Color}. * * @throws IllegalStateException if the bitmap is not mutable. @@ -926,7 +1095,7 @@ public final class Bitmap implements Parcelable { /** * Returns the {@link Color} at the specified location. Throws an exception * if x or y are out of bounds (negative or >= to the width or height - * respectively). + * respectively). The returned color is a non-premultiplied ARGB value. * * @param x The x coordinate (0...width-1) of the pixel to return * @param y The y coordinate (0...height-1) of the pixel to return @@ -944,6 +1113,7 @@ public final class Bitmap implements Parcelable { * a packed int representing a {@link Color}. The stride parameter allows * the caller to allow for gaps in the returned pixels array between * rows. For normal packed results, just pass width for the stride value. + * The returned colors are non-premultiplied ARGB values. * * @param pixels The array to receive the bitmap's colors * @param offset The first index to write into pixels[] @@ -955,6 +1125,7 @@ public final class Bitmap implements Parcelable { * the bitmap * @param width The number of pixels to read from each row * @param height The number of rows to read + * * @throws IllegalArgumentException if x, y, width, height exceed the * bounds of the bitmap, or if abs(stride) < width. * @throws ArrayIndexOutOfBoundsException if the pixels array is too small @@ -974,6 +1145,7 @@ public final class Bitmap implements Parcelable { /** * Shared code to check for illegal arguments passed to getPixel() * or setPixel() + * * @param x x coordinate of the pixel * @param y y coordinate of the pixel */ @@ -1029,12 +1201,14 @@ public final class Bitmap implements Parcelable { } /** - * Write the specified {@link Color} into the bitmap (assuming it is - * mutable) at the x,y coordinate. + * <p>Write the specified {@link Color} into the bitmap (assuming it is + * mutable) at the x,y coordinate. The color must be a + * non-premultiplied ARGB value.</p> * * @param x The x coordinate of the pixel to replace (0...width-1) * @param y The y coordinate of the pixel to replace (0...height-1) - * @param color The {@link Color} to write into the bitmap + * @param color The ARGB color to write into the bitmap + * * @throws IllegalStateException if the bitmap is not mutable * @throws IllegalArgumentException if x, y are outside of the bitmap's * bounds. @@ -1049,8 +1223,9 @@ public final class Bitmap implements Parcelable { } /** - * Replace pixels in the bitmap with the colors in the array. Each element - * in the array is a packed int prepresenting a {@link Color} + * <p>Replace pixels in the bitmap with the colors in the array. Each element + * in the array is a packed int prepresenting a non-premultiplied ARGB + * {@link Color}.</p> * * @param pixels The colors to write to the bitmap * @param offset The index of the first color to read from pixels[] @@ -1063,6 +1238,7 @@ public final class Bitmap implements Parcelable { * the bitmap. * @param width The number of colors to copy from pixels[] per row * @param height The number of rows to write to the bitmap + * * @throws IllegalStateException if the bitmap is not mutable * @throws IllegalArgumentException if x, y, width, height are outside of * the bitmap's bounds. @@ -1070,7 +1246,7 @@ public final class Bitmap implements Parcelable { * to receive the specified number of pixels. */ public void setPixels(int[] pixels, int offset, int stride, - int x, int y, int width, int height) { + int x, int y, int width, int height) { checkRecycled("Can't call setPixels() on a recycled bitmap"); if (!isMutable()) { throw new IllegalStateException(); @@ -1220,7 +1396,7 @@ public final class Bitmap implements Parcelable { private static native Bitmap nativeCopy(int srcBitmap, int nativeConfig, boolean isMutable); private static native void nativeDestructor(int nativeBitmap); - private static native void nativeRecycle(int nativeBitmap); + private static native boolean nativeRecycle(int nativeBitmap); private static native boolean nativeCompress(int nativeBitmap, int format, int quality, OutputStream stream, @@ -1230,7 +1406,6 @@ public final class Bitmap implements Parcelable { private static native int nativeHeight(int nativeBitmap); private static native int nativeRowBytes(int nativeBitmap); private static native int nativeConfig(int nativeBitmap); - private static native boolean nativeHasAlpha(int nativeBitmap); private static native int nativeGetPixel(int nativeBitmap, int x, int y); private static native void nativeGetPixels(int nativeBitmap, int[] pixels, @@ -1259,7 +1434,10 @@ public final class Bitmap implements Parcelable { int[] offsetXY); private static native void nativePrepareToDraw(int nativeBitmap); + private static native boolean nativeHasAlpha(int nativeBitmap); private static native void nativeSetHasAlpha(int nBitmap, boolean hasAlpha); + private static native boolean nativeHasMipMap(int nativeBitmap); + private static native void nativeSetHasMipMap(int nBitmap, boolean hasMipMap); private static native boolean nativeSameAs(int nb0, int nb1); /* package */ final int ni() { diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java index 5094df18..381e65b 100644 --- a/graphics/java/android/graphics/BitmapFactory.java +++ b/graphics/java/android/graphics/BitmapFactory.java @@ -19,6 +19,7 @@ package android.graphics; import android.content.res.AssetManager; import android.content.res.Resources; import android.util.DisplayMetrics; +import android.util.Log; import android.util.TypedValue; import java.io.BufferedInputStream; @@ -303,6 +304,7 @@ public class BitmapFactory { /* do nothing. If the exception happened on open, bm will be null. */ + Log.e("BitmapFactory", "Unable to decode stream: " + e); } finally { if (stream != null) { try { diff --git a/graphics/java/android/graphics/BitmapRegionDecoder.java b/graphics/java/android/graphics/BitmapRegionDecoder.java index c1d3407..b38d107 100644 --- a/graphics/java/android/graphics/BitmapRegionDecoder.java +++ b/graphics/java/android/graphics/BitmapRegionDecoder.java @@ -36,6 +36,9 @@ import java.io.InputStream; public final class BitmapRegionDecoder { private int mNativeBitmapRegionDecoder; private boolean mRecycled; + // ensures that the native decoder object exists and that only one decode can + // occur at a time. + private final Object mNativeLock = new Object(); /** * Create a BitmapRegionDecoder from the specified byte array. @@ -179,24 +182,30 @@ public final class BitmapRegionDecoder { * decoded. */ public Bitmap decodeRegion(Rect rect, BitmapFactory.Options options) { - checkRecycled("decodeRegion called on recycled region decoder"); - if (rect.right <= 0 || rect.bottom <= 0 || rect.left >= getWidth() - || rect.top >= getHeight()) - throw new IllegalArgumentException("rectangle is outside the image"); - return nativeDecodeRegion(mNativeBitmapRegionDecoder, rect.left, rect.top, - rect.right - rect.left, rect.bottom - rect.top, options); + synchronized (mNativeLock) { + checkRecycled("decodeRegion called on recycled region decoder"); + if (rect.right <= 0 || rect.bottom <= 0 || rect.left >= getWidth() + || rect.top >= getHeight()) + throw new IllegalArgumentException("rectangle is outside the image"); + return nativeDecodeRegion(mNativeBitmapRegionDecoder, rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, options); + } } /** Returns the original image's width */ public int getWidth() { - checkRecycled("getWidth called on recycled region decoder"); - return nativeGetWidth(mNativeBitmapRegionDecoder); + synchronized (mNativeLock) { + checkRecycled("getWidth called on recycled region decoder"); + return nativeGetWidth(mNativeBitmapRegionDecoder); + } } /** Returns the original image's height */ public int getHeight() { - checkRecycled("getHeight called on recycled region decoder"); - return nativeGetHeight(mNativeBitmapRegionDecoder); + synchronized (mNativeLock) { + checkRecycled("getHeight called on recycled region decoder"); + return nativeGetHeight(mNativeBitmapRegionDecoder); + } } /** @@ -210,9 +219,11 @@ public final class BitmapRegionDecoder { * memory when there are no more references to this region decoder. */ public void recycle() { - if (!mRecycled) { - nativeClean(mNativeBitmapRegionDecoder); - mRecycled = true; + synchronized (mNativeLock) { + if (!mRecycled) { + nativeClean(mNativeBitmapRegionDecoder); + mRecycled = true; + } } } diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index f9b8a5f..4170cfe 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -371,12 +371,30 @@ public class Paint { public void reset() { native_reset(mNativePaint); setFlags(DEFAULT_PAINT_FLAGS); + // TODO: Turning off hinting has undesirable side effects, we need to // revisit hinting once we add support for subpixel positioning // setHinting(DisplayMetrics.DENSITY_DEVICE >= DisplayMetrics.DENSITY_TV // ? HINTING_OFF : HINTING_ON); + + mColorFilter = null; + mMaskFilter = null; + mPathEffect = null; + mRasterizer = null; + mShader = null; + mTypeface = null; + mXfermode = null; + mHasCompatScaling = false; - mCompatScaling = mInvCompatScaling = 1; + mCompatScaling = 1; + mInvCompatScaling = 1; + + hasShadow = false; + shadowDx = 0; + shadowDy = 0; + shadowRadius = 0; + shadowColor = 0; + mBidiFlags = BIDI_DEFAULT_LTR; setTextLocale(Locale.getDefault()); } @@ -1055,7 +1073,6 @@ public class Paint { * Get the text Locale. * * @return the paint's Locale used for drawing text, never null. - * @hide */ public Locale getTextLocale() { return mLocale; @@ -1086,7 +1103,6 @@ public class Paint { * job in certain ambiguous cases * * @param locale the paint's locale value for drawing text, must not be null. - * @hide */ public void setTextLocale(Locale locale) { if (locale == null) { diff --git a/graphics/java/android/graphics/Rect.java b/graphics/java/android/graphics/Rect.java index 6c204ab..8b5609f 100644 --- a/graphics/java/android/graphics/Rect.java +++ b/graphics/java/android/graphics/Rect.java @@ -69,10 +69,14 @@ public final class Rect implements Parcelable { * rectangle. */ public Rect(Rect r) { - left = r.left; - top = r.top; - right = r.right; - bottom = r.bottom; + if (r == null) { + left = top = right = bottom = 0; + } else { + left = r.left; + top = r.top; + right = r.right; + bottom = r.bottom; + } } @Override diff --git a/graphics/java/android/graphics/RectF.java b/graphics/java/android/graphics/RectF.java index 108b7f9..53178b0 100644 --- a/graphics/java/android/graphics/RectF.java +++ b/graphics/java/android/graphics/RectF.java @@ -66,17 +66,25 @@ public class RectF implements Parcelable { * rectangle. */ public RectF(RectF r) { - left = r.left; - top = r.top; - right = r.right; - bottom = r.bottom; + if (r == null) { + left = top = right = bottom = 0.0f; + } else { + left = r.left; + top = r.top; + right = r.right; + bottom = r.bottom; + } } public RectF(Rect r) { - left = r.left; - top = r.top; - right = r.right; - bottom = r.bottom; + if (r == null) { + left = top = right = bottom = 0.0f; + } else { + left = r.left; + top = r.top; + right = r.right; + bottom = r.bottom; + } } @Override diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java index 87421b1..e82ccd4 100644 --- a/graphics/java/android/graphics/drawable/BitmapDrawable.java +++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java @@ -385,7 +385,7 @@ public class BitmapDrawable extends Drawable { Shader shader = state.mPaint.getShader(); if (shader == null) { if (mApplyGravity) { - final int layoutDirection = getResolvedLayoutDirectionSelf(); + final int layoutDirection = getLayoutDirection(); Gravity.apply(state.mGravity, mBitmapWidth, mBitmapHeight, getBounds(), mDstRect, layoutDirection); mApplyGravity = false; diff --git a/graphics/java/android/graphics/drawable/ClipDrawable.java b/graphics/java/android/graphics/drawable/ClipDrawable.java index c41dd07..b7429d4 100644 --- a/graphics/java/android/graphics/drawable/ClipDrawable.java +++ b/graphics/java/android/graphics/drawable/ClipDrawable.java @@ -209,7 +209,7 @@ public class ClipDrawable extends Drawable implements Drawable.Callback { if ((mClipState.mOrientation & VERTICAL) != 0) { h -= (h - ih) * (10000 - level) / 10000; } - final int layoutDirection = getResolvedLayoutDirectionSelf(); + final int layoutDirection = getLayoutDirection(); Gravity.apply(mClipState.mGravity, w, h, bounds, r, layoutDirection); if (w > 0 && h > 0) { @@ -239,7 +239,12 @@ public class ClipDrawable extends Drawable implements Drawable.Callback { return null; } - + /** @hide */ + @Override + public void setLayoutDirection(int layoutDirection) { + mClipState.mDrawable.setLayoutDirection(layoutDirection); + super.setLayoutDirection(layoutDirection); + } final static class ClipState extends ConstantState { Drawable mDrawable; diff --git a/graphics/java/android/graphics/drawable/ColorDrawable.java b/graphics/java/android/graphics/drawable/ColorDrawable.java index 88c9155..d11e554 100644 --- a/graphics/java/android/graphics/drawable/ColorDrawable.java +++ b/graphics/java/android/graphics/drawable/ColorDrawable.java @@ -20,6 +20,7 @@ import android.graphics.*; import android.content.res.Resources; import android.content.res.TypedArray; import android.util.AttributeSet; +import android.view.ViewDebug; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -34,8 +35,10 @@ import java.io.IOException; * @attr ref android.R.styleable#ColorDrawable_color */ public class ColorDrawable extends Drawable { + @ViewDebug.ExportedProperty(deepExport = true, prefix = "state_") private ColorState mState; private final Paint mPaint = new Paint(); + private boolean mMutated; /** * Creates a new black ColorDrawable. @@ -63,6 +66,21 @@ public class ColorDrawable extends Drawable { return super.getChangingConfigurations() | mState.mChangingConfigurations; } + /** + * A mutable BitmapDrawable still shares its Bitmap with any other Drawable + * that comes from the same resource. + * + * @return This drawable. + */ + @Override + public Drawable mutate() { + if (!mMutated && super.mutate() == this) { + mState = new ColorState(mState); + mMutated = true; + } + return this; + } + @Override public void draw(Canvas canvas) { if ((mState.mUseColor >>> 24) != 0) { @@ -158,6 +176,7 @@ public class ColorDrawable extends Drawable { final static class ColorState extends ConstantState { int mBaseColor; // base color, independent of setAlpha() + @ViewDebug.ExportedProperty int mUseColor; // basecolor modulated by setAlpha() int mChangingConfigurations; @@ -165,6 +184,7 @@ public class ColorDrawable extends Drawable { if (state != null) { mBaseColor = state.mBaseColor; mUseColor = state.mUseColor; + mChangingConfigurations = state.mChangingConfigurations; } } diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java index 785582c..f9392e4 100644 --- a/graphics/java/android/graphics/drawable/Drawable.java +++ b/graphics/java/android/graphics/drawable/Drawable.java @@ -37,7 +37,6 @@ import android.util.DisplayMetrics; import android.util.StateSet; import android.util.TypedValue; import android.util.Xml; -import android.view.View; import java.io.IOException; import java.io.InputStream; @@ -124,6 +123,8 @@ public abstract class Drawable { private WeakReference<Callback> mCallback = null; private boolean mVisible = true; + private int mLayoutDirection; + /** * Draw in its bounds (set via setBounds) respecting optional effects such * as alpha (set via setAlpha) and color filter (set via setColorFilter). @@ -296,19 +297,6 @@ public abstract class Drawable { } /** - * Implement this interface if you want to create an drawable that is RTL aware - * @hide - */ - public static interface Callback2 extends Callback { - /** - * A Drawable can call this to get the resolved layout direction of the <var>who</var>. - * - * @param who The drawable being queried. - */ - public int getResolvedLayoutDirection(Drawable who); - } - - /** * Bind a {@link Callback} object to this Drawable. Required for clients * that want to support animated drawables. * @@ -385,15 +373,30 @@ public abstract class Drawable { } /** - * Get the resolved layout direction of this Drawable. + * Returns the resolved layout direction for this Drawable. + * + * @return One of {@link android.view.View#LAYOUT_DIRECTION_LTR}, + * {@link android.view.View#LAYOUT_DIRECTION_RTL} + * * @hide */ - public int getResolvedLayoutDirectionSelf() { - final Callback callback = getCallback(); - if (callback == null || !(callback instanceof Callback2)) { - return View.LAYOUT_DIRECTION_LTR; + public int getLayoutDirection() { + return mLayoutDirection; + } + + /** + * Set the layout direction for this drawable. Should be a resolved direction as the + * Drawable as no capacity to do the resolution on his own. + * + * @param layoutDirection One of {@link android.view.View#LAYOUT_DIRECTION_LTR}, + * {@link android.view.View#LAYOUT_DIRECTION_RTL} + * + * @hide + */ + public void setLayoutDirection(int layoutDirection) { + if (getLayoutDirection() != layoutDirection) { + mLayoutDirection = layoutDirection; } - return ((Callback2) callback).getResolvedLayoutDirection(this); } /** @@ -777,7 +780,8 @@ public abstract class Drawable { // to the compatibility density only to have them scaled back up when // drawn to the screen. if (opts == null) opts = new BitmapFactory.Options(); - opts.inScreenDensity = DisplayMetrics.DENSITY_DEVICE; + opts.inScreenDensity = res != null + ? res.getDisplayMetrics().noncompatDensityDpi : DisplayMetrics.DENSITY_DEVICE; Bitmap bm = BitmapFactory.decodeResourceStream(res, value, is, pad, opts); if (bm != null) { byte[] np = bm.getNinePatchChunk(); diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java index 15b2c0b..41b272d 100644 --- a/graphics/java/android/graphics/drawable/DrawableContainer.java +++ b/graphics/java/android/graphics/drawable/DrawableContainer.java @@ -105,7 +105,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { mAlpha = alpha; if (mCurrDrawable != null) { if (mEnterAnimationEnd == 0) { - mCurrDrawable.setAlpha(alpha); + mCurrDrawable.mutate().setAlpha(alpha); } else { animate(false); } @@ -118,7 +118,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { if (mDrawableContainerState.mDither != dither) { mDrawableContainerState.mDither = dither; if (mCurrDrawable != null) { - mCurrDrawable.setDither(mDrawableContainerState.mDither); + mCurrDrawable.mutate().setDither(mDrawableContainerState.mDither); } } } @@ -128,7 +128,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { if (mColorFilter != cf) { mColorFilter = cf; if (mCurrDrawable != null) { - mCurrDrawable.setColorFilter(cf); + mCurrDrawable.mutate().setColorFilter(cf); } } } @@ -176,7 +176,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { } if (mCurrDrawable != null) { mCurrDrawable.jumpToCurrentState(); - mCurrDrawable.setAlpha(mAlpha); + mCurrDrawable.mutate().setAlpha(mAlpha); } if (mExitAnimationEnd != 0) { mExitAnimationEnd = 0; @@ -312,6 +312,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { mCurrDrawable = d; mCurIndex = idx; if (d != null) { + d.mutate(); if (mDrawableContainerState.mEnterFadeDuration > 0) { mEnterAnimationEnd = now + mDrawableContainerState.mEnterFadeDuration; } else { @@ -355,13 +356,13 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { if (mCurrDrawable != null) { if (mEnterAnimationEnd != 0) { if (mEnterAnimationEnd <= now) { - mCurrDrawable.setAlpha(mAlpha); + mCurrDrawable.mutate().setAlpha(mAlpha); mEnterAnimationEnd = 0; } else { int animAlpha = (int)((mEnterAnimationEnd-now)*255) / mDrawableContainerState.mEnterFadeDuration; if (DEBUG) android.util.Log.i(TAG, toString() + " cur alpha " + animAlpha); - mCurrDrawable.setAlpha(((255-animAlpha)*mAlpha)/255); + mCurrDrawable.mutate().setAlpha(((255-animAlpha)*mAlpha)/255); animating = true; } } @@ -378,7 +379,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { int animAlpha = (int)((mExitAnimationEnd-now)*255) / mDrawableContainerState.mExitFadeDuration; if (DEBUG) android.util.Log.i(TAG, toString() + " last alpha " + animAlpha); - mLastDrawable.setAlpha((animAlpha*mAlpha)/255); + mLastDrawable.mutate().setAlpha((animAlpha*mAlpha)/255); animating = true; } } @@ -443,7 +444,6 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { int mConstantMinimumWidth; int mConstantMinimumHeight; - boolean mHaveOpacity = false; int mOpacity; boolean mHaveStateful = false; @@ -492,7 +492,6 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { mConstantWidth = orig.mConstantWidth; mConstantHeight = orig.mConstantHeight; - mHaveOpacity = orig.mHaveOpacity; mOpacity = orig.mOpacity; mHaveStateful = orig.mHaveStateful; mStateful = orig.mStateful; @@ -527,7 +526,6 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { mDrawables[pos] = dr; mNumChildren++; mChildrenChangingConfigurations |= dr.getChangingConfigurations(); - mHaveOpacity = false; mHaveStateful = false; mConstantPadding = null; @@ -655,10 +653,6 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { } public final int getOpacity() { - if (mHaveOpacity) { - return mOpacity; - } - final int N = getChildCount(); final Drawable[] drawables = mDrawables; int op = N > 0 ? drawables[0].getOpacity() : PixelFormat.TRANSPARENT; @@ -666,7 +660,6 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { op = Drawable.resolveOpacity(op, drawables[i].getOpacity()); } mOpacity = op; - mHaveOpacity = true; return op; } diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java index 5b50beb..0623a9e 100644 --- a/graphics/java/android/graphics/drawable/GradientDrawable.java +++ b/graphics/java/android/graphics/drawable/GradientDrawable.java @@ -435,7 +435,8 @@ public class GradientDrawable extends Drawable { final int currFillAlpha = modulateAlpha(prevFillAlpha); final int currStrokeAlpha = modulateAlpha(prevStrokeAlpha); - final boolean haveStroke = currStrokeAlpha > 0 && mStrokePaint.getStrokeWidth() > 0; + final boolean haveStroke = currStrokeAlpha > 0 && mStrokePaint != null && + mStrokePaint.getStrokeWidth() > 0; final boolean haveFill = currFillAlpha > 0; final GradientState st = mGradientState; /* we need a layer iff we're drawing both a fill and stroke, and the @@ -477,6 +478,9 @@ public class GradientDrawable extends Drawable { mFillPaint.setAlpha(currFillAlpha); mFillPaint.setDither(mDither); mFillPaint.setColorFilter(mColorFilter); + if (mColorFilter != null && !mGradientState.mHasSolidColor) { + mFillPaint.setColor(0xff000000); + } if (haveStroke) { mStrokePaint.setAlpha(currStrokeAlpha); mStrokePaint.setDither(mDither); @@ -512,7 +516,10 @@ public class GradientDrawable extends Drawable { canvas.drawRoundRect(mRect, rad, rad, mStrokePaint); } } else { - canvas.drawRect(mRect, mFillPaint); + if (mFillPaint.getColor() != 0 || mColorFilter != null || + mFillPaint.getShader() != null) { + canvas.drawRect(mRect, mFillPaint); + } if (haveStroke) { canvas.drawRect(mRect, mStrokePaint); } @@ -603,9 +610,9 @@ public class GradientDrawable extends Drawable { /** * <p>Changes this drawbale to use a single color instead of a gradient.</p> - * <p><strong>Note</strong>: changing orientation will affect all instances + * <p><strong>Note</strong>: changing color will affect all instances * of a drawable loaded from a resource. It is recommended to invoke - * {@link #mutate()} before changing the orientation.</p> + * {@link #mutate()} before changing the color.</p> * * @param argb The color used to fill the shape * @@ -649,7 +656,7 @@ public class GradientDrawable extends Drawable { @Override public int getOpacity() { - return PixelFormat.TRANSLUCENT; + return mGradientState.mOpaque ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT; } @Override @@ -735,6 +742,9 @@ public class GradientDrawable extends Drawable { mFillPaint.setShader(new LinearGradient(x0, y0, x1, y1, colors, st.mPositions, Shader.TileMode.CLAMP)); + if (!mGradientState.mHasSolidColor) { + mFillPaint.setColor(0xff000000); + } } else if (st.mGradient == RADIAL_GRADIENT) { x0 = r.left + (r.right - r.left) * st.mCenterX; y0 = r.top + (r.bottom - r.top) * st.mCenterY; @@ -744,6 +754,9 @@ public class GradientDrawable extends Drawable { mFillPaint.setShader(new RadialGradient(x0, y0, level * st.mGradientRadius, colors, null, Shader.TileMode.CLAMP)); + if (!mGradientState.mHasSolidColor) { + mFillPaint.setColor(0xff000000); + } } else if (st.mGradient == SWEEP_GRADIENT) { x0 = r.left + (r.right - r.left) * st.mCenterX; y0 = r.top + (r.bottom - r.top) * st.mCenterY; @@ -774,6 +787,9 @@ public class GradientDrawable extends Drawable { } mFillPaint.setShader(new SweepGradient(x0, y0, tempColors, tempPositions)); + if (!mGradientState.mHasSolidColor) { + mFillPaint.setColor(0xff000000); + } } } } @@ -1011,7 +1027,10 @@ public class GradientDrawable extends Drawable { } else { Log.w("drawable", "Bad element under <shape>: " + name); } + } + + mGradientState.computeOpacity(); } private static float getFloatOrFraction(TypedArray a, int index, float defaultValue) { @@ -1079,10 +1098,11 @@ public class GradientDrawable extends Drawable { private float mGradientRadius = 0.5f; private boolean mUseLevel; private boolean mUseLevelForShape; + private boolean mOpaque; GradientState(Orientation orientation, int[] colors) { mOrientation = orientation; - mColors = colors; + setColors(colors); } public GradientState(GradientState state) { @@ -1120,6 +1140,7 @@ public class GradientDrawable extends Drawable { mGradientRadius = state.mGradientRadius; mUseLevel = state.mUseLevel; mUseLevelForShape = state.mUseLevelForShape; + mOpaque = state.mOpaque; } @Override @@ -1139,6 +1160,7 @@ public class GradientDrawable extends Drawable { public void setShape(int shape) { mShape = shape; + computeOpacity(); } public void setGradientType(int gradient) { @@ -1153,24 +1175,65 @@ public class GradientDrawable extends Drawable { public void setColors(int[] colors) { mHasSolidColor = false; mColors = colors; + computeOpacity(); } public void setSolidColor(int argb) { mHasSolidColor = true; mSolidColor = argb; mColors = null; + computeOpacity(); + } + + private void computeOpacity() { + if (mShape != RECTANGLE) { + mOpaque = false; + return; + } + + if (mRadius > 0 || mRadiusArray != null) { + mOpaque = false; + return; + } + + if (mStrokeWidth > 0 && !isOpaque(mStrokeColor)) { + mOpaque = false; + return; + } + + if (mHasSolidColor) { + mOpaque = isOpaque(mSolidColor); + return; + } + + if (mColors != null) { + for (int i = 0; i < mColors.length; i++) { + if (!isOpaque(mColors[i])) { + mOpaque = false; + return; + } + } + } + + mOpaque = true; + } + + private static boolean isOpaque(int color) { + return ((color >> 24) & 0xff) == 0xff; } public void setStroke(int width, int color) { mStrokeWidth = width; mStrokeColor = color; + computeOpacity(); } - + public void setStroke(int width, int color, float dashWidth, float dashGap) { mStrokeWidth = width; mStrokeColor = color; mStrokeDashWidth = dashWidth; mStrokeDashGap = dashGap; + computeOpacity(); } public void setCornerRadius(float radius) { @@ -1180,14 +1243,14 @@ public class GradientDrawable extends Drawable { mRadius = radius; mRadiusArray = null; } - + public void setCornerRadii(float[] radii) { mRadiusArray = radii; if (radii == null) { mRadius = 0; } } - + public void setSize(int width, int height) { mWidth = width; mHeight = height; @@ -1202,11 +1265,17 @@ public class GradientDrawable extends Drawable { mGradientState = state; initializeWithState(state); mRectIsDirty = true; + mMutated = false; } private void initializeWithState(GradientState state) { if (state.mHasSolidColor) { mFillPaint.setColor(state.mSolidColor); + } else if (state.mColors == null) { + // If we don't have a solid color and we don't have a gradient, + // the app is stroking the shape, set the color to the default + // value of state.mSolidColor + mFillPaint.setColor(0); } mPadding = state.mPadding; if (state.mStrokeWidth >= 0) { diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java index 383fe71..0351b71 100644 --- a/graphics/java/android/graphics/drawable/LayerDrawable.java +++ b/graphics/java/android/graphics/drawable/LayerDrawable.java @@ -590,6 +590,19 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { return this; } + /** @hide */ + @Override + public void setLayoutDirection(int layoutDirection) { + if (getLayoutDirection() != layoutDirection) { + final ChildDrawable[] array = mLayerState.mChildren; + final int N = mLayerState.mNum; + for (int i = 0; i < N; i++) { + array[i].mDrawable.setLayoutDirection(layoutDirection); + } + } + super.setLayoutDirection(layoutDirection); + } + static class ChildDrawable { public Drawable mDrawable; public int mInsetL, mInsetT, mInsetR, mInsetB; diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java index b68b267..2ee6233 100644 --- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java +++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java @@ -181,7 +181,7 @@ public class NinePatchDrawable extends Drawable { } } - private Insets scaleFromDensity(Insets insets, int sdensity, int tdensity) { + private static Insets scaleFromDensity(Insets insets, int sdensity, int tdensity) { int left = Bitmap.scaleFromDensity(insets.left, sdensity, tdensity); int top = Bitmap.scaleFromDensity(insets.top, sdensity, tdensity); int right = Bitmap.scaleFromDensity(insets.right, sdensity, tdensity); @@ -296,7 +296,7 @@ public class NinePatchDrawable extends Drawable { if (dither) { options.inDither = false; } - options.inScreenDensity = DisplayMetrics.DENSITY_DEVICE; + options.inScreenDensity = r.getDisplayMetrics().noncompatDensityDpi; final Rect padding = new Rect(); final Rect layoutInsets = new Rect(); diff --git a/graphics/java/android/graphics/drawable/ScaleDrawable.java b/graphics/java/android/graphics/drawable/ScaleDrawable.java index ccad250..bd2b2f0 100644 --- a/graphics/java/android/graphics/drawable/ScaleDrawable.java +++ b/graphics/java/android/graphics/drawable/ScaleDrawable.java @@ -221,7 +221,7 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback { final int ih = min ? mScaleState.mDrawable.getIntrinsicHeight() : 0; h -= (int) ((h - ih) * (10000 - level) * mScaleState.mScaleHeight / 10000); } - final int layoutDirection = getResolvedLayoutDirectionSelf(); + final int layoutDirection = getLayoutDirection(); Gravity.apply(mScaleState.mGravity, w, h, bounds, r, layoutDirection); if (w > 0 && h > 0) { diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java index a3622a2..2ec1293 100644 --- a/graphics/java/android/graphics/drawable/ShapeDrawable.java +++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java @@ -373,8 +373,16 @@ public class ShapeDrawable extends Drawable { @Override public Drawable mutate() { if (!mMutated && super.mutate() == this) { - mShapeState.mPaint = new Paint(mShapeState.mPaint); - mShapeState.mPadding = new Rect(mShapeState.mPadding); + if (mShapeState.mPaint != null) { + mShapeState.mPaint = new Paint(mShapeState.mPaint); + } else { + mShapeState.mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + } + if (mShapeState.mPadding != null) { + mShapeState.mPadding = new Rect(mShapeState.mPadding); + } else { + mShapeState.mPadding = new Rect(); + } try { mShapeState.mShape = mShapeState.mShape.clone(); } catch (CloneNotSupportedException e) { diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java index 384ca81..f8f3ac9 100644 --- a/graphics/java/android/graphics/drawable/StateListDrawable.java +++ b/graphics/java/android/graphics/drawable/StateListDrawable.java @@ -261,6 +261,16 @@ public class StateListDrawable extends DrawableContainer { return this; } + /** @hide */ + @Override + public void setLayoutDirection(int layoutDirection) { + final int numStates = getStateCount(); + for (int i = 0; i < numStates; i++) { + getStateDrawable(i).setLayoutDirection(layoutDirection); + } + super.setLayoutDirection(layoutDirection); + } + static final class StateListState extends DrawableContainerState { int[][] mStateSets; diff --git a/graphics/java/android/renderscript/Matrix2f.java b/graphics/java/android/renderscript/Matrix2f.java index acc5bd8..39abd4f 100644 --- a/graphics/java/android/renderscript/Matrix2f.java +++ b/graphics/java/android/renderscript/Matrix2f.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * Copyright (C) 2009-2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -59,23 +59,23 @@ public class Matrix2f { /** * Returns the value for a given row and column * - * @param i row of the value to return - * @param j column of the value to return + * @param x column of the value to return + * @param y row of the value to return * - * @return value in the ith row and jth column + * @return value in the yth row and xth column */ - public float get(int i, int j) { - return mMat[i*2 + j]; + public float get(int x, int y) { + return mMat[x*2 + y]; } /** * Sets the value for a given row and column * - * @param i row of the value to set - * @param j column of the value to set + * @param x column of the value to set + * @param y row of the value to set */ - public void set(int i, int j, float v) { - mMat[i*2 + j] = v; + public void set(int x, int y, float v) { + mMat[x*2 + y] = v; } /** diff --git a/graphics/java/android/renderscript/Matrix3f.java b/graphics/java/android/renderscript/Matrix3f.java index 253506d..66f2c81 100644 --- a/graphics/java/android/renderscript/Matrix3f.java +++ b/graphics/java/android/renderscript/Matrix3f.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * Copyright (C) 2009-2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -59,23 +59,23 @@ public class Matrix3f { /** * Returns the value for a given row and column * - * @param i row of the value to return - * @param j column of the value to return + * @param x column of the value to return + * @param y row of the value to return * - * @return value in the ith row and jth column + * @return value in the yth row and xth column */ - public float get(int i, int j) { - return mMat[i*3 + j]; + public float get(int x, int y) { + return mMat[x*3 + y]; } /** * Sets the value for a given row and column * - * @param i row of the value to set - * @param j column of the value to set + * @param x column of the value to set + * @param y row of the value to set */ - public void set(int i, int j, float v) { - mMat[i*3 + j] = v; + public void set(int x, int y, float v) { + mMat[x*3 + y] = v; } /** diff --git a/graphics/java/android/renderscript/Matrix4f.java b/graphics/java/android/renderscript/Matrix4f.java index adc1806..4600424 100644 --- a/graphics/java/android/renderscript/Matrix4f.java +++ b/graphics/java/android/renderscript/Matrix4f.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * Copyright (C) 2009-2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -59,23 +59,23 @@ public class Matrix4f { /** * Returns the value for a given row and column * - * @param i row of the value to return - * @param j column of the value to return + * @param x column of the value to return + * @param y row of the value to return * - * @return value in the ith row and jth column + * @return value in the yth row and xth column */ - public float get(int i, int j) { - return mMat[i*4 + j]; + public float get(int x, int y) { + return mMat[x*4 + y]; } /** * Sets the value for a given row and column * - * @param i row of the value to set - * @param j column of the value to set + * @param x column of the value to set + * @param y row of the value to set */ - public void set(int i, int j, float v) { - mMat[i*4 + j] = v; + public void set(int x, int y, float v) { + mMat[x*4 + y] = v; } /** @@ -113,6 +113,34 @@ public class Matrix4f { } /** + * Sets the values of the matrix to those of the parameter + * + * @param src matrix to load the values from + * @hide + */ + public void load(Matrix3f src) { + mMat[0] = src.mMat[0]; + mMat[1] = src.mMat[1]; + mMat[2] = src.mMat[2]; + mMat[3] = 0; + + mMat[4] = src.mMat[3]; + mMat[5] = src.mMat[4]; + mMat[6] = src.mMat[5]; + mMat[7] = 0; + + mMat[8] = src.mMat[6]; + mMat[9] = src.mMat[7]; + mMat[10] = src.mMat[8]; + mMat[11] = 0; + + mMat[12] = 0; + mMat[13] = 0; + mMat[14] = 0; + mMat[15] = 1; + } + + /** * Sets current values to be a rotation matrix of certain angle * about a given axis * diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java index 2032f67..76edb0a 100644 --- a/graphics/java/android/renderscript/RenderScript.java +++ b/graphics/java/android/renderscript/RenderScript.java @@ -561,6 +561,48 @@ public class RenderScript { return rsnScriptCCreate(mContext, resName, cacheDir, script, length); } + native int rsnScriptIntrinsicCreate(int con, int id, int eid); + synchronized int nScriptIntrinsicCreate(int id, int eid) { + validate(); + return rsnScriptIntrinsicCreate(mContext, id, eid); + } + + native int rsnScriptKernelIDCreate(int con, int sid, int slot, int sig); + synchronized int nScriptKernelIDCreate(int sid, int slot, int sig) { + validate(); + return rsnScriptKernelIDCreate(mContext, sid, slot, sig); + } + + native int rsnScriptFieldIDCreate(int con, int sid, int slot); + synchronized int nScriptFieldIDCreate(int sid, int slot) { + validate(); + return rsnScriptFieldIDCreate(mContext, sid, slot); + } + + native int rsnScriptGroupCreate(int con, int[] kernels, int[] src, int[] dstk, int[] dstf, int[] types); + synchronized int nScriptGroupCreate(int[] kernels, int[] src, int[] dstk, int[] dstf, int[] types) { + validate(); + return rsnScriptGroupCreate(mContext, kernels, src, dstk, dstf, types); + } + + native void rsnScriptGroupSetInput(int con, int group, int kernel, int alloc); + synchronized void nScriptGroupSetInput(int group, int kernel, int alloc) { + validate(); + rsnScriptGroupSetInput(mContext, group, kernel, alloc); + } + + native void rsnScriptGroupSetOutput(int con, int group, int kernel, int alloc); + synchronized void nScriptGroupSetOutput(int group, int kernel, int alloc) { + validate(); + rsnScriptGroupSetOutput(mContext, group, kernel, alloc); + } + + native void rsnScriptGroupExecute(int con, int group); + synchronized void nScriptGroupExecute(int group) { + validate(); + rsnScriptGroupExecute(mContext, group); + } + native int rsnSamplerCreate(int con, int magFilter, int minFilter, int wrapS, int wrapT, int wrapR, float aniso); synchronized int nSamplerCreate(int magFilter, int minFilter, diff --git a/graphics/java/android/renderscript/Script.java b/graphics/java/android/renderscript/Script.java index bbf5e7e..3fe3261 100644 --- a/graphics/java/android/renderscript/Script.java +++ b/graphics/java/android/renderscript/Script.java @@ -16,10 +16,105 @@ package android.renderscript; +import android.util.SparseArray; + /** * **/ public class Script extends BaseObj { + + /** + * KernelID is an identifier for a Script + root function pair. It is used + * as an identifier for ScriptGroup creation. + * + * This class should not be directly created. Instead use the method in the + * reflected or intrinsic code "getKernelID_funcname()". + * + */ + public static final class KernelID extends BaseObj { + Script mScript; + int mSlot; + int mSig; + KernelID(int id, RenderScript rs, Script s, int slot, int sig) { + super(id, rs); + mScript = s; + mSlot = slot; + mSig = sig; + } + } + + private final SparseArray<KernelID> mKIDs = new SparseArray<KernelID>(); + /** + * Only to be used by generated reflected classes. + * + * + * @param slot + * @param sig + * @param ein + * @param eout + * + * @return KernelID + */ + protected KernelID createKernelID(int slot, int sig, Element ein, Element eout) { + KernelID k = mKIDs.get(slot); + if (k != null) { + return k; + } + + int id = mRS.nScriptKernelIDCreate(getID(mRS), slot, sig); + if (id == 0) { + throw new RSDriverException("Failed to create KernelID"); + } + + k = new KernelID(id, mRS, this, slot, sig); + mKIDs.put(slot, k); + return k; + } + + /** + * FieldID is an identifier for a Script + exported field pair. It is used + * as an identifier for ScriptGroup creation. + * + * This class should not be directly created. Instead use the method in the + * reflected or intrinsic code "getFieldID_funcname()". + * + */ + public static final class FieldID extends BaseObj { + Script mScript; + int mSlot; + FieldID(int id, RenderScript rs, Script s, int slot) { + super(id, rs); + mScript = s; + mSlot = slot; + } + } + + private final SparseArray<FieldID> mFIDs = new SparseArray(); + /** + * Only to be used by generated reflected classes. + * + * @param slot + * @param e + * + * @return FieldID + */ + protected FieldID createFieldID(int slot, Element e) { + FieldID f = mFIDs.get(slot); + if (f != null) { + return f; + } + + int id = mRS.nScriptFieldIDCreate(getID(mRS), slot); + if (id == 0) { + throw new RSDriverException("Failed to create FieldID"); + } + + f = new FieldID(id, mRS, this, slot); + mFIDs.put(slot, f); + return f; + } + + /** * Only intended for use by generated reflected code. * diff --git a/graphics/java/android/renderscript/ScriptGroup.java b/graphics/java/android/renderscript/ScriptGroup.java new file mode 100644 index 0000000..7afdb39 --- /dev/null +++ b/graphics/java/android/renderscript/ScriptGroup.java @@ -0,0 +1,464 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.renderscript; + +import java.lang.reflect.Method; +import java.util.ArrayList; + +/** + * ScriptGroup creates a groups of scripts which are executed + * together based upon upon one execution call as if they were + * all part of a single script. The scripts may be connected + * internally or to an external allocation. For the internal + * connections the intermediate results are not observable after + * the execution of the script. + * <p> + * The external connections are grouped into inputs and outputs. + * All outputs are produced by a script kernel and placed into a + * user supplied allocation. Inputs are similar but supply the + * input of a kernal. Inputs bounds to a script are set directly + * upon the script. + * <p> + * A ScriptGroup must contain at least one kernel. A ScriptGroup + * must contain only a single directed acyclic graph (DAG) of + * script kernels and connections. Attempting to create a + * ScriptGroup with multiple DAGs or attempting to create + * a cycle within a ScriptGroup will throw an exception. + * + **/ +public final class ScriptGroup extends BaseObj { + IO mOutputs[]; + IO mInputs[]; + + static class IO { + Script.KernelID mKID; + Allocation mAllocation; + + IO(Script.KernelID s) { + mKID = s; + } + } + + static class ConnectLine { + ConnectLine(Type t, Script.KernelID from, Script.KernelID to) { + mFrom = from; + mToK = to; + mAllocationType = t; + } + + ConnectLine(Type t, Script.KernelID from, Script.FieldID to) { + mFrom = from; + mToF = to; + mAllocationType = t; + } + + Script.FieldID mToF; + Script.KernelID mToK; + Script.KernelID mFrom; + Type mAllocationType; + } + + static class Node { + Script mScript; + ArrayList<Script.KernelID> mKernels = new ArrayList<Script.KernelID>(); + ArrayList<ConnectLine> mInputs = new ArrayList<ConnectLine>(); + ArrayList<ConnectLine> mOutputs = new ArrayList<ConnectLine>(); + int dagNumber; + + Node mNext; + + Node(Script s) { + mScript = s; + } + } + + + ScriptGroup(int id, RenderScript rs) { + super(id, rs); + } + + /** + * Sets an input of the ScriptGroup. This specifies an + * Allocation to be used for the kernels which require a kernel + * input and that input is provided external to the group. + * + * @param s The ID of the kernel where the allocation should be + * connected. + * @param a The allocation to connect. + */ + public void setInput(Script.KernelID s, Allocation a) { + for (int ct=0; ct < mInputs.length; ct++) { + if (mInputs[ct].mKID == s) { + mInputs[ct].mAllocation = a; + mRS.nScriptGroupSetInput(getID(mRS), s.getID(mRS), mRS.safeID(a)); + return; + } + } + throw new RSIllegalArgumentException("Script not found"); + } + + /** + * Sets an output of the ScriptGroup. This specifies an + * Allocation to be used for the kernels which require a kernel + * output and that output is provided external to the group. + * + * @param s The ID of the kernel where the allocation should be + * connected. + * @param a The allocation to connect. + */ + public void setOutput(Script.KernelID s, Allocation a) { + for (int ct=0; ct < mOutputs.length; ct++) { + if (mOutputs[ct].mKID == s) { + mOutputs[ct].mAllocation = a; + mRS.nScriptGroupSetOutput(getID(mRS), s.getID(mRS), mRS.safeID(a)); + return; + } + } + throw new RSIllegalArgumentException("Script not found"); + } + + /** + * Execute the ScriptGroup. This will run all the kernels in + * the script. The state of the connecting lines will not be + * observable after this operation. + */ + public void execute() { + mRS.nScriptGroupExecute(getID(mRS)); + } + + + /** + * Create a ScriptGroup. There are two steps to creating a + * ScriptGoup. + * <p> + * First all the Kernels to be used by the group should be + * added. Once this is done the kernels should be connected. + * Kernels cannot be added once a connection has been made. + * <p> + * Second, add connections. There are two forms of connections. + * Kernel to Kernel and Kernel to Field. Kernel to Kernel is + * higher performance and should be used where possible. The + * line of connections cannot form a loop. If a loop is detected + * an exception is thrown. + * <p> + * Once all the connections are made a call to create will + * return the ScriptGroup object. + * + */ + public static final class Builder { + private RenderScript mRS; + private ArrayList<Node> mNodes = new ArrayList<Node>(); + private ArrayList<ConnectLine> mLines = new ArrayList<ConnectLine>(); + private int mKernelCount; + + /** + * Create a builder for generating a ScriptGroup. + * + * + * @param rs The Renderscript context. + */ + public Builder(RenderScript rs) { + mRS = rs; + } + + // do a DFS from original node, looking for original node + // any cycle that could be created must contain original node + private void validateCycle(Node target, Node original) { + for (int ct = 0; ct < target.mOutputs.size(); ct++) { + final ConnectLine cl = target.mOutputs.get(ct); + if (cl.mToK != null) { + Node tn = findNode(cl.mToK.mScript); + if (tn.equals(original)) { + throw new RSInvalidStateException("Loops in group not allowed."); + } + validateCycle(tn, original); + } + if (cl.mToF != null) { + Node tn = findNode(cl.mToF.mScript); + if (tn.equals(original)) { + throw new RSInvalidStateException("Loops in group not allowed."); + } + validateCycle(tn, original); + } + } + } + + private void mergeDAGs(int valueUsed, int valueKilled) { + for (int ct=0; ct < mNodes.size(); ct++) { + if (mNodes.get(ct).dagNumber == valueKilled) + mNodes.get(ct).dagNumber = valueUsed; + } + } + + private void validateDAGRecurse(Node n, int dagNumber) { + // combine DAGs if this node has been seen already + if (n.dagNumber != 0 && n.dagNumber != dagNumber) { + mergeDAGs(n.dagNumber, dagNumber); + return; + } + + n.dagNumber = dagNumber; + for (int ct=0; ct < n.mOutputs.size(); ct++) { + final ConnectLine cl = n.mOutputs.get(ct); + if (cl.mToK != null) { + Node tn = findNode(cl.mToK.mScript); + validateDAGRecurse(tn, dagNumber); + } + if (cl.mToF != null) { + Node tn = findNode(cl.mToF.mScript); + validateDAGRecurse(tn, dagNumber); + } + } + } + + private void validateDAG() { + for (int ct=0; ct < mNodes.size(); ct++) { + Node n = mNodes.get(ct); + if (n.mInputs.size() == 0) { + if (n.mOutputs.size() == 0 && mNodes.size() > 1) { + throw new RSInvalidStateException("Groups cannot contain unconnected scripts"); + } + validateDAGRecurse(n, ct+1); + } + } + int dagNumber = mNodes.get(0).dagNumber; + for (int ct=0; ct < mNodes.size(); ct++) { + if (mNodes.get(ct).dagNumber != dagNumber) { + throw new RSInvalidStateException("Multiple DAGs in group not allowed."); + } + } + } + + private Node findNode(Script s) { + for (int ct=0; ct < mNodes.size(); ct++) { + if (s == mNodes.get(ct).mScript) { + return mNodes.get(ct); + } + } + return null; + } + + private Node findNode(Script.KernelID k) { + for (int ct=0; ct < mNodes.size(); ct++) { + Node n = mNodes.get(ct); + for (int ct2=0; ct2 < n.mKernels.size(); ct2++) { + if (k == n.mKernels.get(ct2)) { + return n; + } + } + } + return null; + } + + /** + * Adds a Kernel to the group. + * + * + * @param k The kernel to add. + * + * @return Builder Returns this. + */ + public Builder addKernel(Script.KernelID k) { + if (mLines.size() != 0) { + throw new RSInvalidStateException( + "Kernels may not be added once connections exist."); + } + + //android.util.Log.v("RSR", "addKernel 1 k=" + k); + if (findNode(k) != null) { + return this; + } + //android.util.Log.v("RSR", "addKernel 2 "); + mKernelCount++; + Node n = findNode(k.mScript); + if (n == null) { + //android.util.Log.v("RSR", "addKernel 3 "); + n = new Node(k.mScript); + mNodes.add(n); + } + n.mKernels.add(k); + return this; + } + + /** + * Adds a connection to the group. + * + * + * @param t The type of the connection. This is used to + * determine the kernel launch sizes on the source side + * of this connection. + * @param from The source for the connection. + * @param to The destination of the connection. + * + * @return Builder Returns this + */ + public Builder addConnection(Type t, Script.KernelID from, Script.FieldID to) { + //android.util.Log.v("RSR", "addConnection " + t +", " + from + ", " + to); + + Node nf = findNode(from); + if (nf == null) { + throw new RSInvalidStateException("From script not found."); + } + + Node nt = findNode(to.mScript); + if (nt == null) { + throw new RSInvalidStateException("To script not found."); + } + + ConnectLine cl = new ConnectLine(t, from, to); + mLines.add(new ConnectLine(t, from, to)); + + nf.mOutputs.add(cl); + nt.mInputs.add(cl); + + validateCycle(nf, nf); + return this; + } + + /** + * Adds a connection to the group. + * + * + * @param t The type of the connection. This is used to + * determine the kernel launch sizes for both sides of + * this connection. + * @param from The source for the connection. + * @param to The destination of the connection. + * + * @return Builder Returns this + */ + public Builder addConnection(Type t, Script.KernelID from, Script.KernelID to) { + //android.util.Log.v("RSR", "addConnection " + t +", " + from + ", " + to); + + Node nf = findNode(from); + if (nf == null) { + throw new RSInvalidStateException("From script not found."); + } + + Node nt = findNode(to); + if (nt == null) { + throw new RSInvalidStateException("To script not found."); + } + + ConnectLine cl = new ConnectLine(t, from, to); + mLines.add(new ConnectLine(t, from, to)); + + nf.mOutputs.add(cl); + nt.mInputs.add(cl); + + validateCycle(nf, nf); + return this; + } + + + + /** + * Creates the Script group. + * + * + * @return ScriptGroup The new ScriptGroup + */ + public ScriptGroup create() { + + if (mNodes.size() == 0) { + throw new RSInvalidStateException("Empty script groups are not allowed"); + } + + // reset DAG numbers in case we're building a second group + for (int ct=0; ct < mNodes.size(); ct++) { + mNodes.get(ct).dagNumber = 0; + } + validateDAG(); + + ArrayList<IO> inputs = new ArrayList<IO>(); + ArrayList<IO> outputs = new ArrayList<IO>(); + + int[] kernels = new int[mKernelCount]; + int idx = 0; + for (int ct=0; ct < mNodes.size(); ct++) { + Node n = mNodes.get(ct); + for (int ct2=0; ct2 < n.mKernels.size(); ct2++) { + final Script.KernelID kid = n.mKernels.get(ct2); + kernels[idx++] = kid.getID(mRS); + + boolean hasInput = false; + boolean hasOutput = false; + for (int ct3=0; ct3 < n.mInputs.size(); ct3++) { + if (n.mInputs.get(ct3).mToK == kid) { + hasInput = true; + } + } + for (int ct3=0; ct3 < n.mOutputs.size(); ct3++) { + if (n.mOutputs.get(ct3).mFrom == kid) { + hasOutput = true; + } + } + if (!hasInput) { + inputs.add(new IO(kid)); + } + if (!hasOutput) { + outputs.add(new IO(kid)); + } + + } + } + if (idx != mKernelCount) { + throw new RSRuntimeException("Count mismatch, should not happen."); + } + + int[] src = new int[mLines.size()]; + int[] dstk = new int[mLines.size()]; + int[] dstf = new int[mLines.size()]; + int[] types = new int[mLines.size()]; + + for (int ct=0; ct < mLines.size(); ct++) { + ConnectLine cl = mLines.get(ct); + src[ct] = cl.mFrom.getID(mRS); + if (cl.mToK != null) { + dstk[ct] = cl.mToK.getID(mRS); + } + if (cl.mToF != null) { + dstf[ct] = cl.mToF.getID(mRS); + } + types[ct] = cl.mAllocationType.getID(mRS); + } + + int id = mRS.nScriptGroupCreate(kernels, src, dstk, dstf, types); + if (id == 0) { + throw new RSRuntimeException("Object creation error, should not happen."); + } + + ScriptGroup sg = new ScriptGroup(id, mRS); + sg.mOutputs = new IO[outputs.size()]; + for (int ct=0; ct < outputs.size(); ct++) { + sg.mOutputs[ct] = outputs.get(ct); + } + + sg.mInputs = new IO[inputs.size()]; + for (int ct=0; ct < inputs.size(); ct++) { + sg.mInputs[ct] = inputs.get(ct); + } + + return sg; + } + + } + + +} + + diff --git a/graphics/java/android/renderscript/ScriptIntrinsic.java b/graphics/java/android/renderscript/ScriptIntrinsic.java new file mode 100644 index 0000000..f54943a --- /dev/null +++ b/graphics/java/android/renderscript/ScriptIntrinsic.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.renderscript; + +import android.content.Context; +import android.content.res.Resources; +import android.util.Log; + + +/** + * Base class for all Intrinsic scripts. An intrinsic a script + * which implements a pre-defined function. Intrinsics are + * provided to provide effecient implemtations of common + * operations. + * + * Not intended for direct use. + **/ +public abstract class ScriptIntrinsic extends Script { + ScriptIntrinsic(int id, RenderScript rs) { + super(id, rs); + } +} diff --git a/graphics/java/android/renderscript/ScriptIntrinsicBlend.java b/graphics/java/android/renderscript/ScriptIntrinsicBlend.java new file mode 100644 index 0000000..65c69c0 --- /dev/null +++ b/graphics/java/android/renderscript/ScriptIntrinsicBlend.java @@ -0,0 +1,465 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.renderscript; + + +/** + * Intrinsic kernels for blending two buffers. Each blend function is a separate + * kernel to make it easy to change between blend modes. + **/ +public class ScriptIntrinsicBlend extends ScriptIntrinsic { + ScriptIntrinsicBlend(int id, RenderScript rs) { + super(id, rs); + } + + /** + * Supported elements types are uchar4 + * + * + * @param rs + * @param e + * + * @return ScriptIntrinsicBlend + */ + public static ScriptIntrinsicBlend create(RenderScript rs, Element e) { + // 7 comes from RS_SCRIPT_INTRINSIC_ID_BLEND in rsDefines.h + int id = rs.nScriptIntrinsicCreate(7, e.getID(rs)); + return new ScriptIntrinsicBlend(id, rs); + + } + + private void blend(int id, Allocation ain, Allocation aout) { + if (!ain.getElement().isCompatible(Element.U8_4(mRS))) { + throw new RSIllegalArgumentException("Input is not of expected format."); + } + if (!aout.getElement().isCompatible(Element.U8_4(mRS))) { + throw new RSIllegalArgumentException("Output is not of expected format."); + } + forEach(id, ain, aout, null); + } + + /** + * dst = {0, 0, 0, 0} + * + * @param ain The source buffer + * @param aout The destination buffer + */ + public void forEachClear(Allocation ain, Allocation aout) { + blend(0, ain, aout); + } + + /** + * Get a KernelID for the Clear kernel. + * + * @return Script.KernelID The KernelID object. + */ + public Script.KernelID getKernelIDClear() { + return createKernelID(0, 3, null, null); + } + + + /** + * dst = src + * + * @param ain The source buffer + * @param aout The destination buffer + */ + public void forEachSrc(Allocation ain, Allocation aout) { + blend(1, ain, aout); + } + + /** + * Get a KernelID for the Src kernel. + * + * @return Script.KernelID The KernelID object. + */ + public Script.KernelID getKernelIDSrc() { + return createKernelID(1, 3, null, null); + } + + /** + * dst = dst + * This is a NOP + * + * @param ain The source buffer + * @param aout The destination buffer + */ + public void forEachDst(Allocation ain, Allocation aout) { + // NOP + } + + /** + * Get a KernelID for the Dst kernel. + * + * @return Script.KernelID The KernelID object. + */ + public Script.KernelID getKernelIDDst() { + return createKernelID(2, 3, null, null); + } + + /** + * dst = src + dst * (1.0 - src.a) + * + * @param ain The source buffer + * @param aout The destination buffer + */ + public void forEachSrcOver(Allocation ain, Allocation aout) { + blend(3, ain, aout); + } + + /** + * Get a KernelID for the SrcOver kernel. + * + * @return Script.KernelID The KernelID object. + */ + public Script.KernelID getKernelIDSrcOver() { + return createKernelID(3, 3, null, null); + } + + /** + * dst = dst + src * (1.0 - dst.a) + * + * @param ain The source buffer + * @param aout The destination buffer + */ + public void forEachDstOver(Allocation ain, Allocation aout) { + blend(4, ain, aout); + } + + /** + * Get a KernelID for the DstOver kernel. + * + * @return Script.KernelID The KernelID object. + */ + public Script.KernelID getKernelIDDstOver() { + return createKernelID(4, 3, null, null); + } + + /** + * dst = src * dst.a + * + * @param ain The source buffer + * @param aout The destination buffer + */ + public void forEachSrcIn(Allocation ain, Allocation aout) { + blend(5, ain, aout); + } + + /** + * Get a KernelID for the SrcIn kernel. + * + * @return Script.KernelID The KernelID object. + */ + public Script.KernelID getKernelIDSrcIn() { + return createKernelID(5, 3, null, null); + } + + /** + * dst = dst * src.a + * + * @param ain The source buffer + * @param aout The destination buffer + */ + public void forEachDstIn(Allocation ain, Allocation aout) { + blend(6, ain, aout); + } + + /** + * Get a KernelID for the DstIn kernel. + * + * @return Script.KernelID The KernelID object. + */ + public Script.KernelID getKernelIDDstIn() { + return createKernelID(6, 3, null, null); + } + + /** + * dst = src * (1.0 - dst.a) + * + * @param ain The source buffer + * @param aout The destination buffer + */ + public void forEachSrcOut(Allocation ain, Allocation aout) { + blend(7, ain, aout); + } + + /** + * Get a KernelID for the SrcOut kernel. + * + * @return Script.KernelID The KernelID object. + */ + public Script.KernelID getKernelIDSrcOut() { + return createKernelID(7, 3, null, null); + } + + /** + * dst = dst * (1.0 - src.a) + * + * @param ain The source buffer + * @param aout The destination buffer + */ + public void forEachDstOut(Allocation ain, Allocation aout) { + blend(8, ain, aout); + } + + /** + * Get a KernelID for the DstOut kernel. + * + * @return Script.KernelID The KernelID object. + */ + public Script.KernelID getKernelIDDstOut() { + return createKernelID(8, 3, null, null); + } + + /** + * dst.rgb = src.rgb * dst.a + (1.0 - src.a) * dst.rgb + * dst.a = dst.a + * + * @param ain The source buffer + * @param aout The destination buffer + */ + public void forEachSrcAtop(Allocation ain, Allocation aout) { + blend(9, ain, aout); + } + + /** + * Get a KernelID for the SrcAtop kernel. + * + * @return Script.KernelID The KernelID object. + */ + public Script.KernelID getKernelIDSrcAtop() { + return createKernelID(9, 3, null, null); + } + + /** + * dst = dst.rgb * src.a + (1.0 - dst.a) * src.rgb + * dst.a = src.a + * + * @param ain The source buffer + * @param aout The destination buffer + */ + public void forEachDstAtop(Allocation ain, Allocation aout) { + blend(10, ain, aout); + } + + /** + * Get a KernelID for the DstAtop kernel. + * + * @return Script.KernelID The KernelID object. + */ + public Script.KernelID getKernelIDDstAtop() { + return createKernelID(10, 3, null, null); + } + + /** + * dst = {src.r ^ dst.r, src.g ^ dst.g, src.b ^ dst.b, src.a ^ dst.a} + * + * @param ain The source buffer + * @param aout The destination buffer + */ + public void forEachXor(Allocation ain, Allocation aout) { + blend(11, ain, aout); + } + + /** + * Get a KernelID for the Xor kernel. + * + * @return Script.KernelID The KernelID object. + */ + public Script.KernelID getKernelIDXor() { + return createKernelID(11, 3, null, null); + } + + //////// +/* + public void forEachNormal(Allocation ain, Allocation aout) { + blend(12, ain, aout); + } + + public void forEachAverage(Allocation ain, Allocation aout) { + blend(13, ain, aout); + } +*/ + /** + * dst = src * dst + * + * @param ain The source buffer + * @param aout The destination buffer + */ + public void forEachMultiply(Allocation ain, Allocation aout) { + blend(14, ain, aout); + } + + /** + * Get a KernelID for the Multiply kernel. + * + * @return Script.KernelID The KernelID object. + */ + public Script.KernelID getKernelIDMultiply() { + return createKernelID(14, 3, null, null); + } + +/* + public void forEachScreen(Allocation ain, Allocation aout) { + blend(15, ain, aout); + } + + public void forEachDarken(Allocation ain, Allocation aout) { + blend(16, ain, aout); + } + + public void forEachLighten(Allocation ain, Allocation aout) { + blend(17, ain, aout); + } + + public void forEachOverlay(Allocation ain, Allocation aout) { + blend(18, ain, aout); + } + + public void forEachHardlight(Allocation ain, Allocation aout) { + blend(19, ain, aout); + } + + public void forEachSoftlight(Allocation ain, Allocation aout) { + blend(20, ain, aout); + } + + public void forEachDifference(Allocation ain, Allocation aout) { + blend(21, ain, aout); + } + + public void forEachNegation(Allocation ain, Allocation aout) { + blend(22, ain, aout); + } + + public void forEachExclusion(Allocation ain, Allocation aout) { + blend(23, ain, aout); + } + + public void forEachColorDodge(Allocation ain, Allocation aout) { + blend(24, ain, aout); + } + + public void forEachInverseColorDodge(Allocation ain, Allocation aout) { + blend(25, ain, aout); + } + + public void forEachSoftDodge(Allocation ain, Allocation aout) { + blend(26, ain, aout); + } + + public void forEachColorBurn(Allocation ain, Allocation aout) { + blend(27, ain, aout); + } + + public void forEachInverseColorBurn(Allocation ain, Allocation aout) { + blend(28, ain, aout); + } + + public void forEachSoftBurn(Allocation ain, Allocation aout) { + blend(29, ain, aout); + } + + public void forEachReflect(Allocation ain, Allocation aout) { + blend(30, ain, aout); + } + + public void forEachGlow(Allocation ain, Allocation aout) { + blend(31, ain, aout); + } + + public void forEachFreeze(Allocation ain, Allocation aout) { + blend(32, ain, aout); + } + + public void forEachHeat(Allocation ain, Allocation aout) { + blend(33, ain, aout); + } +*/ + /** + * dst = min(src + dst, 1.0) + * + * @param ain The source buffer + * @param aout The destination buffer + */ + public void forEachAdd(Allocation ain, Allocation aout) { + blend(34, ain, aout); + } + + /** + * Get a KernelID for the Add kernel. + * + * @return Script.KernelID The KernelID object. + */ + public Script.KernelID getKernelIDAdd() { + return createKernelID(34, 3, null, null); + } + + /** + * dst = max(dst - src, 0.0) + * + * @param ain The source buffer + * @param aout The destination buffer + */ + public void forEachSubtract(Allocation ain, Allocation aout) { + blend(35, ain, aout); + } + + /** + * Get a KernelID for the Subtract kernel. + * + * @return Script.KernelID The KernelID object. + */ + public Script.KernelID getKernelIDSubtract() { + return createKernelID(35, 3, null, null); + } + +/* + public void forEachStamp(Allocation ain, Allocation aout) { + blend(36, ain, aout); + } + + public void forEachRed(Allocation ain, Allocation aout) { + blend(37, ain, aout); + } + + public void forEachGreen(Allocation ain, Allocation aout) { + blend(38, ain, aout); + } + + public void forEachBlue(Allocation ain, Allocation aout) { + blend(39, ain, aout); + } + + public void forEachHue(Allocation ain, Allocation aout) { + blend(40, ain, aout); + } + + public void forEachSaturation(Allocation ain, Allocation aout) { + blend(41, ain, aout); + } + + public void forEachColor(Allocation ain, Allocation aout) { + blend(42, ain, aout); + } + + public void forEachLuminosity(Allocation ain, Allocation aout) { + blend(43, ain, aout); + } +*/ +} + diff --git a/graphics/java/android/renderscript/ScriptIntrinsicBlur.java b/graphics/java/android/renderscript/ScriptIntrinsicBlur.java new file mode 100644 index 0000000..11164e3 --- /dev/null +++ b/graphics/java/android/renderscript/ScriptIntrinsicBlur.java @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.renderscript; + +import android.content.Context; +import android.content.res.Resources; +import android.util.Log; + +/** + * Intrinsic Gausian blur filter. Applies a gaussian blur of the + * specified radius to all elements of an allocation. + * + * + **/ +public final class ScriptIntrinsicBlur extends ScriptIntrinsic { + private final float[] mValues = new float[9]; + private Allocation mInput; + + private ScriptIntrinsicBlur(int id, RenderScript rs) { + super(id, rs); + } + + /** + * Create an intrinsic for applying a blur to an allocation. The + * default radius is 5.0. + * + * Supported elements types are {@link Element#U8_4} + * + * @param rs The Renderscript context + * @param e Element type for inputs and outputs + * + * @return ScriptIntrinsicBlur + */ + public static ScriptIntrinsicBlur create(RenderScript rs, Element e) { + if (e != Element.U8_4(rs)) { + throw new RSIllegalArgumentException("Unsuported element type."); + } + int id = rs.nScriptIntrinsicCreate(5, e.getID(rs)); + ScriptIntrinsicBlur sib = new ScriptIntrinsicBlur(id, rs); + sib.setRadius(5.f); + return sib; + } + + /** + * Set the input of the blur. + * Must match the element type supplied during create. + * + * @param ain The input allocation + */ + public void setInput(Allocation ain) { + mInput = ain; + setVar(1, ain); + } + + /** + * Set the radius of the Blur. + * + * Supported range 0 < radius <= 25 + * + * @param radius The radius of the blur + */ + public void setRadius(float radius) { + if (radius <= 0 || radius > 25) { + throw new RSIllegalArgumentException("Radius out of range (0 < r <= 25)."); + } + setVar(0, radius); + } + + /** + * Apply the filter to the input and save to the specified + * allocation. + * + * @param aout Output allocation. Must match creation element + * type. + */ + public void forEach(Allocation aout) { + forEach(0, null, aout, null); + } + + /** + * Get a KernelID for this intrinsic kernel. + * + * @return Script.KernelID The KernelID object. + */ + public Script.KernelID getKernelID() { + return createKernelID(0, 2, null, null); + } + + /** + * Get a FieldID for the input field of this intrinsic. + * + * @return Script.FieldID The FieldID object. + */ + public Script.FieldID getFieldID_Input() { + return createFieldID(1, null); + } +} + diff --git a/graphics/java/android/renderscript/ScriptIntrinsicColorMatrix.java b/graphics/java/android/renderscript/ScriptIntrinsicColorMatrix.java new file mode 100644 index 0000000..cb458ba --- /dev/null +++ b/graphics/java/android/renderscript/ScriptIntrinsicColorMatrix.java @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.renderscript; + +import android.content.Context; +import android.content.res.Resources; +import android.util.Log; + +/** + * Intrinsic for applying a color matrix to allocations. + * + * This has the same effect as loading each element and + * converting it to a {@link Element#F32_4}, multiplying the + * result by the 4x4 color matrix as performed by + * rsMatrixMultiply() and writing it to the output after + * conversion back to {@link Element#U8_4}. + **/ +public final class ScriptIntrinsicColorMatrix extends ScriptIntrinsic { + private final Matrix4f mMatrix = new Matrix4f(); + private Allocation mInput; + + private ScriptIntrinsicColorMatrix(int id, RenderScript rs) { + super(id, rs); + } + + /** + * Create an intrinsic for applying a color matrix to an + * allocation. + * + * Supported elements types are {@link Element#U8_4} + * + * @param rs The Renderscript context + * @param e Element type for intputs and outputs + * + * @return ScriptIntrinsicColorMatrix + */ + public static ScriptIntrinsicColorMatrix create(RenderScript rs, Element e) { + if (e != Element.U8_4(rs)) { + throw new RSIllegalArgumentException("Unsuported element type."); + } + int id = rs.nScriptIntrinsicCreate(2, e.getID(rs)); + return new ScriptIntrinsicColorMatrix(id, rs); + + } + + private void setMatrix() { + FieldPacker fp = new FieldPacker(16*4); + fp.addMatrix(mMatrix); + setVar(0, fp); + } + + /** + * Set the color matrix which will be applied to each cell of + * the image. + * + * @param m The 4x4 matrix to set. + */ + public void setColorMatrix(Matrix4f m) { + mMatrix.load(m); + setMatrix(); + } + + /** + * Set the color matrix which will be applied to each cell of the image. + * This will set the alpha channel to be a copy. + * + * @param m The 3x3 matrix to set. + */ + public void setColorMatrix(Matrix3f m) { + mMatrix.load(m); + setMatrix(); + } + + /** + * Set a color matrix to convert from RGB to luminance. The alpha channel + * will be a copy. + * + */ + public void setGreyscale() { + mMatrix.loadIdentity(); + mMatrix.set(0, 0, 0.299f); + mMatrix.set(1, 0, 0.587f); + mMatrix.set(2, 0, 0.114f); + mMatrix.set(0, 1, 0.299f); + mMatrix.set(1, 1, 0.587f); + mMatrix.set(2, 1, 0.114f); + mMatrix.set(0, 2, 0.299f); + mMatrix.set(1, 2, 0.587f); + mMatrix.set(2, 2, 0.114f); + setMatrix(); + } + + /** + * Set the matrix to convert from YUV to RGB with a direct copy of the 4th + * channel. + * + */ + public void setYUVtoRGB() { + mMatrix.loadIdentity(); + mMatrix.set(0, 0, 1.f); + mMatrix.set(1, 0, 0.f); + mMatrix.set(2, 0, 1.13983f); + mMatrix.set(0, 1, 1.f); + mMatrix.set(1, 1, -0.39465f); + mMatrix.set(2, 1, -0.5806f); + mMatrix.set(0, 2, 1.f); + mMatrix.set(1, 2, 2.03211f); + mMatrix.set(2, 2, 0.f); + setMatrix(); + } + + /** + * Set the matrix to convert from RGB to YUV with a direct copy of the 4th + * channel. + * + */ + public void setRGBtoYUV() { + mMatrix.loadIdentity(); + mMatrix.set(0, 0, 0.299f); + mMatrix.set(1, 0, 0.587f); + mMatrix.set(2, 0, 0.114f); + mMatrix.set(0, 1, -0.14713f); + mMatrix.set(1, 1, -0.28886f); + mMatrix.set(2, 1, 0.436f); + mMatrix.set(0, 2, 0.615f); + mMatrix.set(1, 2, -0.51499f); + mMatrix.set(2, 2, -0.10001f); + setMatrix(); + } + + + /** + * Invoke the kernel and apply the matrix to each cell of ain and copy to + * aout. + * + * @param ain Input allocation + * @param aout Output allocation + */ + public void forEach(Allocation ain, Allocation aout) { + forEach(0, ain, aout, null); + } + + /** + * Get a KernelID for this intrinsic kernel. + * + * @return Script.KernelID The KernelID object. + */ + public Script.KernelID getKernelID() { + return createKernelID(0, 3, null, null); + } + +} + diff --git a/graphics/java/android/renderscript/ScriptIntrinsicConvolve3x3.java b/graphics/java/android/renderscript/ScriptIntrinsicConvolve3x3.java new file mode 100644 index 0000000..91efa02 --- /dev/null +++ b/graphics/java/android/renderscript/ScriptIntrinsicConvolve3x3.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.renderscript; + +import android.content.Context; +import android.content.res.Resources; +import android.util.Log; + +/** + * Intrinsic for applying a 3x3 convolve to an allocation. + * + **/ +public final class ScriptIntrinsicConvolve3x3 extends ScriptIntrinsic { + private final float[] mValues = new float[9]; + private Allocation mInput; + + private ScriptIntrinsicConvolve3x3(int id, RenderScript rs) { + super(id, rs); + } + + /** + * Supported elements types are {@link Element#U8_4} + * + * The default coefficients are. + * + * <code> + * <p> [ 0, 0, 0 ] + * <p> [ 0, 1, 0 ] + * <p> [ 0, 0, 0 ] + * </code> + * + * @param rs The Renderscript context + * @param e Element type for intputs and outputs + * + * @return ScriptIntrinsicConvolve3x3 + */ + public static ScriptIntrinsicConvolve3x3 create(RenderScript rs, Element e) { + float f[] = { 0, 0, 0, 0, 1, 0, 0, 0, 0}; + if (e != Element.U8_4(rs)) { + throw new RSIllegalArgumentException("Unsuported element type."); + } + int id = rs.nScriptIntrinsicCreate(1, e.getID(rs)); + ScriptIntrinsicConvolve3x3 si = new ScriptIntrinsicConvolve3x3(id, rs); + si.setCoefficients(f); + return si; + + } + + /** + * Set the input of the blur. + * Must match the element type supplied during create. + * + * @param ain The input allocation. + */ + public void setInput(Allocation ain) { + mInput = ain; + setVar(1, ain); + } + + /** + * Set the coefficients for the convolve. + * + * The convolve layout is + * <code> + * <p> [ 0, 1, 2 ] + * <p> [ 3, 4, 5 ] + * <p> [ 6, 7, 8 ] + * </code> + * + * @param v The array of coefficients to set + */ + public void setCoefficients(float v[]) { + FieldPacker fp = new FieldPacker(9*4); + for (int ct=0; ct < mValues.length; ct++) { + mValues[ct] = v[ct]; + fp.addF32(mValues[ct]); + } + setVar(0, fp); + } + + /** + * Apply the filter to the input and save to the specified + * allocation. + * + * @param aout Output allocation. Must match creation element + * type. + */ + public void forEach(Allocation aout) { + forEach(0, null, aout, null); + } + + /** + * Get a KernelID for this intrinsic kernel. + * + * @return Script.KernelID The KernelID object. + */ + public Script.KernelID getKernelID() { + return createKernelID(0, 2, null, null); + } + + /** + * Get a FieldID for the input field of this intrinsic. + * + * @return Script.FieldID The FieldID object. + */ + public Script.FieldID getFieldID_Input() { + return createFieldID(1, null); + } + +} + diff --git a/graphics/java/android/renderscript/ScriptIntrinsicConvolve5x5.java b/graphics/java/android/renderscript/ScriptIntrinsicConvolve5x5.java new file mode 100644 index 0000000..1f52e3f --- /dev/null +++ b/graphics/java/android/renderscript/ScriptIntrinsicConvolve5x5.java @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.renderscript; + +import android.util.Log; + +/** + * Intrinsic for applying a 5x5 convolve to an allocation. + * + **/ +public final class ScriptIntrinsicConvolve5x5 extends ScriptIntrinsic { + private final float[] mValues = new float[25]; + private Allocation mInput; + + private ScriptIntrinsicConvolve5x5(int id, RenderScript rs) { + super(id, rs); + } + + /** + * Supported elements types are {@link Element#U8_4} + * + * The default coefficients are. + * <code> + * <p> [ 0, 0, 0, 0, 0 ] + * <p> [ 0, 0, 0, 0, 0 ] + * <p> [ 0, 0, 1, 0, 0 ] + * <p> [ 0, 0, 0, 0, 0 ] + * <p> [ 0, 0, 0, 0, 0 ] + * </code> + * + * @param rs The Renderscript context + * @param e Element type for intputs and outputs + * + * @return ScriptIntrinsicConvolve5x5 + */ + public static ScriptIntrinsicConvolve5x5 create(RenderScript rs, Element e) { + int id = rs.nScriptIntrinsicCreate(4, e.getID(rs)); + return new ScriptIntrinsicConvolve5x5(id, rs); + + } + + /** + * Set the input of the blur. + * Must match the element type supplied during create. + * + * @param ain The input allocation. + */ + public void setInput(Allocation ain) { + mInput = ain; + setVar(1, ain); + } + + /** + * Set the coefficients for the convolve. + * + * The convolve layout is + * <code> + * <p> [ 0, 1, 2, 3, 4 ] + * <p> [ 5, 6, 7, 8, 9 ] + * <p> [ 10, 11, 12, 13, 14 ] + * <p> [ 15, 16, 17, 18, 19 ] + * <p> [ 20, 21, 22, 23, 24 ] + * </code> + * + * @param v The array of coefficients to set + */ + public void setCoefficients(float v[]) { + FieldPacker fp = new FieldPacker(25*4); + for (int ct=0; ct < mValues.length; ct++) { + mValues[ct] = v[ct]; + fp.addF32(mValues[ct]); + } + setVar(0, fp); + } + + /** + * Apply the filter to the input and save to the specified + * allocation. + * + * @param aout Output allocation. Must match creation element + * type. + */ + public void forEach(Allocation aout) { + forEach(0, null, aout, null); + } + + /** + * Get a KernelID for this intrinsic kernel. + * + * @return Script.KernelID The KernelID object. + */ + public Script.KernelID getKernelID() { + return createKernelID(0, 2, null, null); + } + + /** + * Get a FieldID for the input field of this intrinsic. + * + * @return Script.FieldID The FieldID object. + */ + public Script.FieldID getFieldID_Input() { + return createFieldID(1, null); + } +} + diff --git a/graphics/java/android/renderscript/ScriptIntrinsicLUT.java b/graphics/java/android/renderscript/ScriptIntrinsicLUT.java new file mode 100644 index 0000000..41bdd25 --- /dev/null +++ b/graphics/java/android/renderscript/ScriptIntrinsicLUT.java @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.renderscript; + +import android.content.Context; +import android.content.res.Resources; +import android.util.Log; + +/** + * Intrinsic for applying a per-channel lookup table. Each + * channel of the input has an independant lookup table. The + * tables are 256 entries in size and can cover the full value + * range of {@link Element#U8_4}. + **/ +public final class ScriptIntrinsicLUT extends ScriptIntrinsic { + private final Matrix4f mMatrix = new Matrix4f(); + private Allocation mTables; + private final byte mCache[] = new byte[1024]; + private boolean mDirty = true; + + private ScriptIntrinsicLUT(int id, RenderScript rs) { + super(id, rs); + mTables = Allocation.createSized(rs, Element.U8(rs), 1024); + for (int ct=0; ct < 256; ct++) { + mCache[ct] = (byte)ct; + mCache[ct + 256] = (byte)ct; + mCache[ct + 512] = (byte)ct; + mCache[ct + 768] = (byte)ct; + } + setVar(0, mTables); + } + + /** + * Supported elements types are {@link Element#U8_4} + * + * The defaults tables are identity. + * + * @param rs The Renderscript context + * @param e Element type for intputs and outputs + * + * @return ScriptIntrinsicLUT + */ + public static ScriptIntrinsicLUT create(RenderScript rs, Element e) { + int id = rs.nScriptIntrinsicCreate(3, e.getID(rs)); + return new ScriptIntrinsicLUT(id, rs); + + } + + + private void validate(int index, int value) { + if (index < 0 || index > 255) { + throw new RSIllegalArgumentException("Index out of range (0-255)."); + } + if (value < 0 || value > 255) { + throw new RSIllegalArgumentException("Value out of range (0-255)."); + } + } + + /** + * Set an entry in the red channel lookup table + * + * @param index Must be 0-255 + * @param value Must be 0-255 + */ + public void setRed(int index, int value) { + validate(index, value); + mCache[index] = (byte)value; + mDirty = true; + } + + /** + * Set an entry in the green channel lookup table + * + * @param index Must be 0-255 + * @param value Must be 0-255 + */ + public void setGreen(int index, int value) { + validate(index, value); + mCache[index+256] = (byte)value; + mDirty = true; + } + + /** + * Set an entry in the blue channel lookup table + * + * @param index Must be 0-255 + * @param value Must be 0-255 + */ + public void setBlue(int index, int value) { + validate(index, value); + mCache[index+512] = (byte)value; + mDirty = true; + } + + /** + * Set an entry in the alpha channel lookup table + * + * @param index Must be 0-255 + * @param value Must be 0-255 + */ + public void setAlpha(int index, int value) { + validate(index, value); + mCache[index+768] = (byte)value; + mDirty = true; + } + + + /** + * Invoke the kernel and apply the lookup to each cell of ain + * and copy to aout. + * + * @param ain Input allocation + * @param aout Output allocation + */ + public void forEach(Allocation ain, Allocation aout) { + if (mDirty) { + mDirty = false; + mTables.copyFromUnchecked(mCache); + } + forEach(0, ain, aout, null); + } + + /** + * Get a KernelID for this intrinsic kernel. + * + * @return Script.KernelID The KernelID object. + */ + public Script.KernelID getKernelID() { + return createKernelID(0, 3, null, null); + } +} + diff --git a/graphics/java/android/renderscript/ScriptIntrinsicYuvToRGB.java b/graphics/java/android/renderscript/ScriptIntrinsicYuvToRGB.java new file mode 100644 index 0000000..dc8a5aa --- /dev/null +++ b/graphics/java/android/renderscript/ScriptIntrinsicYuvToRGB.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.renderscript; + + +/** + * Intrinsic for converting an Android YUV buffer to RGB. + * + * The input allocation is supplied in NV21 format as a U8 + * element type. The output is RGBA, the alpha channel will be + * set to 255. + */ +public final class ScriptIntrinsicYuvToRGB extends ScriptIntrinsic { + private Allocation mInput; + + ScriptIntrinsicYuvToRGB(int id, RenderScript rs) { + super(id, rs); + } + + /** + * Create an intrinsic for converting YUV to RGB. + * + * Supported elements types are {@link Element#U8_4} + * + * @param rs The Renderscript context + * @param e Element type for output + * + * @return ScriptIntrinsicYuvToRGB + */ + public static ScriptIntrinsicYuvToRGB create(RenderScript rs, Element e) { + // 6 comes from RS_SCRIPT_INTRINSIC_YUV_TO_RGB in rsDefines.h + int id = rs.nScriptIntrinsicCreate(6, e.getID(rs)); + ScriptIntrinsicYuvToRGB si = new ScriptIntrinsicYuvToRGB(id, rs); + return si; + } + + + /** + * Set the input yuv allocation, must be {@link Element#U8}. + * + * @param ain The input allocation. + */ + public void setInput(Allocation ain) { + mInput = ain; + setVar(0, ain); + } + + /** + * Convert the image to RGB. + * + * @param aout Output allocation. Must match creation element + * type. + */ + public void forEach(Allocation aout) { + forEach(0, null, aout, null); + } + + /** + * Get a KernelID for this intrinsic kernel. + * + * @return Script.KernelID The KernelID object. + */ + public Script.KernelID getKernelID() { + return createKernelID(0, 2, null, null); + } + + /** + * Get a FieldID for the input field of this intrinsic. + * + * @return Script.FieldID The FieldID object. + */ + public Script.FieldID getFieldID_Input() { + return createFieldID(0, null); + } +} |