diff options
Diffstat (limited to 'rs/java/android/renderscript/Allocation.java')
-rw-r--r-- | rs/java/android/renderscript/Allocation.java | 260 |
1 files changed, 239 insertions, 21 deletions
diff --git a/rs/java/android/renderscript/Allocation.java b/rs/java/android/renderscript/Allocation.java index 0a5059390449..c0ea1324602b 100644 --- a/rs/java/android/renderscript/Allocation.java +++ b/rs/java/android/renderscript/Allocation.java @@ -16,14 +16,16 @@ package android.renderscript; +import java.nio.ByteBuffer; import java.util.HashMap; + import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; -import android.view.Surface; -import android.util.Log; import android.graphics.Canvas; import android.os.Trace; +import android.util.Log; +import android.view.Surface; /** * <p> This class provides the primary method through which data is passed to @@ -53,12 +55,17 @@ import android.os.Trace; **/ public class Allocation extends BaseObj { + private static final int MAX_NUMBER_IO_INPUT_ALLOC = 16; + Type mType; + boolean mOwningType = false; Bitmap mBitmap; int mUsage; Allocation mAdaptedAllocation; int mSize; + MipmapControl mMipmapControl; + long mTimeStamp = -1; boolean mReadAllowed = true; boolean mWriteAllowed = true; boolean mAutoPadding = false; @@ -78,6 +85,8 @@ public class Allocation extends BaseObj { OnBufferAvailableListener mBufferNotifier; private Surface mGetSurfaceSurface = null; + private ByteBuffer mByteBuffer = null; + private long mByteBufferStride = -1; private Element.DataType validateObjectIsPrimitiveArray(Object d, boolean checkType) { final Class c = d.getClass(); @@ -107,7 +116,7 @@ public class Allocation extends BaseObj { if (cmp == Short.TYPE) { if (checkType) { - validateIsInt16(); + validateIsInt16OrFloat16(); return mType.mElement.mType; } return Element.DataType.SIGNED_16; @@ -134,7 +143,10 @@ public class Allocation extends BaseObj { } return Element.DataType.FLOAT_64; } - return null; + + throw new RSIllegalArgumentException("Parameter of type " + cmp.getSimpleName() + + "[] is not compatible with data type " + mType.mElement.mType.name() + + " of allocation"); } @@ -274,8 +286,24 @@ public class Allocation extends BaseObj { } /** - * Enable/Disable AutoPadding for Vec3 elements. - * By default: Diabled. + * @hide + * Get the Mipmap control flag of the Allocation. + * + * @return the Mipmap control flag of the Allocation + * + */ + public MipmapControl getMipmap() { + return mMipmapControl; + } + + /** + * Enable/Disable AutoPadding for Vec3 Elements. + * + * <p> Vec3 Elements, such as {@link Element#U8_3} are treated as Vec4 Elements + * with the fourth vector element used as padding. Enabling the AutoPadding feature + * will automatically add/remove the padding when you copy to/from an Allocation + * with a Vec3 Element. + * <p> By default: Disabled. * * @param useAutoPadding True: enable AutoPadding; False: disable AutoPadding * @@ -353,6 +381,13 @@ public class Allocation extends BaseObj { Log.e(RenderScript.LOG_TAG, "Couldn't invoke registerNativeAllocation:" + e); throw new RSRuntimeException("Couldn't invoke registerNativeAllocation:" + e); } + guard.open("destroy"); + } + + Allocation(long id, RenderScript rs, Type t, boolean owningType, int usage, MipmapControl mips) { + this(id, rs, t, usage); + mOwningType = owningType; + mMipmapControl = mips; } protected void finalize() throws Throwable { @@ -378,9 +413,10 @@ public class Allocation extends BaseObj { "32 bit integer source does not match allocation type " + mType.mElement.mType); } - private void validateIsInt16() { + private void validateIsInt16OrFloat16() { if ((mType.mElement.mType == Element.DataType.SIGNED_16) || - (mType.mElement.mType == Element.DataType.UNSIGNED_16)) { + (mType.mElement.mType == Element.DataType.UNSIGNED_16) || + (mType.mElement.mType == Element.DataType.FLOAT_16)) { return; } throw new RSIllegalArgumentException( @@ -517,7 +553,7 @@ public class Allocation extends BaseObj { "Can only receive if IO_INPUT usage specified."); } mRS.validate(); - mRS.nAllocationIoReceive(getID(mRS)); + mTimeStamp = mRS.nAllocationIoReceive(getID(mRS)); } finally { Trace.traceEnd(RenderScript.TRACE_TAG); } @@ -727,7 +763,7 @@ public class Allocation extends BaseObj { * @param d the source data array */ public void copyFrom(short[] d) { - validateIsInt16(); + validateIsInt16OrFloat16(); copyFromUnchecked(d, Element.DataType.SIGNED_16, d.length); } @@ -1036,7 +1072,7 @@ public class Allocation extends BaseObj { * @param d the source data array */ public void copy1DRangeFrom(int off, int count, short[] d) { - validateIsInt16(); + validateIsInt16OrFloat16(); copy1DRangeFromUnchecked(off, count, d, Element.DataType.SIGNED_16, d.length); } @@ -1180,7 +1216,7 @@ public class Allocation extends BaseObj { * @param data to be placed into the Allocation */ public void copy2DRangeFrom(int xoff, int yoff, int w, int h, short[] data) { - validateIsInt16(); + validateIsInt16OrFloat16(); copy2DRangeFromUnchecked(xoff, yoff, w, h, data, Element.DataType.SIGNED_16, data.length); } @@ -1449,7 +1485,7 @@ public class Allocation extends BaseObj { * @param d The array to be set from the Allocation. */ public void copyTo(short[] d) { - validateIsInt16(); + validateIsInt16OrFloat16(); copyTo(d, Element.DataType.SIGNED_16, d.length); } @@ -1505,7 +1541,7 @@ public class Allocation extends BaseObj { } final byte[] data = fp.getData(); - int data_length = fp.getPos(); + int data_length = data.length; int eSize = mType.mElement.mElements[component_number].getBytesSize(); eSize *= mType.mElement.mArraySizes[component_number]; @@ -1544,6 +1580,9 @@ public class Allocation extends BaseObj { mRS.finish(); // Necessary because resize is fifoed and update is async. long typeID = mRS.nAllocationGetType(getID(mRS)); + // Sets zero the mID so that the finalizer of the old mType value won't + // destroy the native object that is being reused. + mType.setID(0); mType = new Type(typeID, mRS); mType.updateFromNative(); updateCacheInfo(mType); @@ -1669,7 +1708,7 @@ public class Allocation extends BaseObj { * @param d the source data array */ public void copy1DRangeTo(int off, int count, short[] d) { - validateIsInt16(); + validateIsInt16OrFloat16(); copy1DRangeToUnchecked(off, count, d, Element.DataType.SIGNED_16, d.length); } @@ -1770,7 +1809,7 @@ public class Allocation extends BaseObj { * @param data Dest Array to be copied into */ public void copy2DRangeTo(int xoff, int yoff, int w, int h, short[] data) { - validateIsInt16(); + validateIsInt16OrFloat16(); copy2DRangeToUnchecked(xoff, yoff, w, h, data, Element.DataType.SIGNED_16, data.length); } @@ -1882,11 +1921,12 @@ public class Allocation extends BaseObj { if (type.getID(rs) == 0) { throw new RSInvalidStateException("Bad Type"); } + // TODO: What if there is an exception after this? The native allocation would leak. long id = rs.nAllocationCreateTyped(type.getID(rs), mips.mID, usage, 0); if (id == 0) { throw new RSRuntimeException("Allocation creation failed."); } - return new Allocation(id, rs, type, usage); + return new Allocation(id, rs, type, false, usage, mips); } finally { Trace.traceEnd(RenderScript.TRACE_TAG); } @@ -1944,7 +1984,7 @@ public class Allocation extends BaseObj { if (id == 0) { throw new RSRuntimeException("Allocation creation failed."); } - return new Allocation(id, rs, t, usage); + return new Allocation(id, rs, t, true, usage, MipmapControl.MIPMAP_NONE); } finally { Trace.traceEnd(RenderScript.TRACE_TAG); } @@ -2033,7 +2073,7 @@ public class Allocation extends BaseObj { } // keep a reference to the Bitmap around to prevent GC - Allocation alloc = new Allocation(id, rs, t, usage); + Allocation alloc = new Allocation(id, rs, t, true, usage, mips); alloc.setBitmap(b); return alloc; } @@ -2043,13 +2083,185 @@ public class Allocation extends BaseObj { if (id == 0) { throw new RSRuntimeException("Load failed."); } - return new Allocation(id, rs, t, usage); + return new Allocation(id, rs, t, true, usage, mips); + } finally { + Trace.traceEnd(RenderScript.TRACE_TAG); + } + } + + /** + * Gets or creates a ByteBuffer that contains the raw data of the current Allocation. + * If the Allocation is created with USAGE_IO_INPUT, the returned ByteBuffer + * would contain the up-to-date data as READ ONLY. + * For a 2D or 3D Allocation, the raw data maybe padded so that each row of + * the Allocation has certain alignment. The size of each row including padding, + * called stride, can be queried using the {@link #getStride()} method. + * + * Note: Operating on the ByteBuffer of a destroyed Allocation will triger errors. + * + * @return ByteBuffer The ByteBuffer associated with raw data pointer of the Allocation. + */ + public ByteBuffer getByteBuffer() { + // Create a new ByteBuffer if it is not initialized or using IO_INPUT. + if (mType.hasFaces()) { + throw new RSInvalidStateException("Cubemap is not supported for getByteBuffer()."); + } + if (mType.getYuv() == android.graphics.ImageFormat.NV21 || + mType.getYuv() == android.graphics.ImageFormat.YV12 || + mType.getYuv() == android.graphics.ImageFormat.YUV_420_888 ) { + throw new RSInvalidStateException("YUV format is not supported for getByteBuffer()."); + } + if (mByteBuffer == null || (mUsage & USAGE_IO_INPUT) != 0) { + int xBytesSize = mType.getX() * mType.getElement().getBytesSize(); + long[] stride = new long[1]; + mByteBuffer = mRS.nAllocationGetByteBuffer(getID(mRS), stride, xBytesSize, mType.getY(), mType.getZ()); + mByteBufferStride = stride[0]; + } + if ((mUsage & USAGE_IO_INPUT) != 0) { + return mByteBuffer.asReadOnlyBuffer(); + } + return mByteBuffer; + } + + /** + * Creates a new Allocation Array with the given {@link + * android.renderscript.Type}, and usage flags. + * Note: If the input allocation is of usage: USAGE_IO_INPUT, + * the created Allocation will be sharing the same BufferQueue. + * + * @param rs RenderScript context + * @param t RenderScript type describing data layout + * @param usage bit field specifying how the Allocation is + * utilized + * @param numAlloc Number of Allocations in the array. + * @return Allocation[] + */ + public static Allocation[] createAllocations(RenderScript rs, Type t, int usage, int numAlloc) { + try { + Trace.traceBegin(RenderScript.TRACE_TAG, "createAllocations"); + rs.validate(); + if (t.getID(rs) == 0) { + throw new RSInvalidStateException("Bad Type"); + } + + Allocation[] mAllocationArray = new Allocation[numAlloc]; + mAllocationArray[0] = createTyped(rs, t, usage); + if ((usage & USAGE_IO_INPUT) != 0) { + if (numAlloc > MAX_NUMBER_IO_INPUT_ALLOC) { + throw new RSIllegalArgumentException("Exceeds the max number of Allocations allowed: " + + MAX_NUMBER_IO_INPUT_ALLOC); + } + mAllocationArray[0].setupBufferQueue(numAlloc);; + } + + for (int i=1; i<numAlloc; i++) { + mAllocationArray[i] = createFromAllocation(rs, mAllocationArray[0]); + } + return mAllocationArray; + } finally { + Trace.traceEnd(RenderScript.TRACE_TAG); + } + } + + /** + * Creates a new Allocation with the given {@link + * android.renderscript.Allocation}. The same data layout of + * the input Allocation will be applied. + * If the input allocation is of usage: USAGE_IO_INPUT, the created + * Allocation will be sharing the same BufferQueue. + * + * @param rs Context to which the allocation will belong. + * @param alloc RenderScript Allocation describing data layout. + * @return Allocation sharing the same data structure. + */ + static Allocation createFromAllocation(RenderScript rs, Allocation alloc) { + try { + Trace.traceBegin(RenderScript.TRACE_TAG, "createFromAllcation"); + rs.validate(); + if (alloc.getID(rs) == 0) { + throw new RSInvalidStateException("Bad input Allocation"); + } + + Type type = alloc.getType(); + int usage = alloc.getUsage(); + MipmapControl mips = alloc.getMipmap(); + long id = rs.nAllocationCreateTyped(type.getID(rs), mips.mID, usage, 0); + if (id == 0) { + throw new RSRuntimeException("Allocation creation failed."); + } + Allocation outAlloc = new Allocation(id, rs, type, false, usage, mips); + if ((usage & USAGE_IO_INPUT) != 0) { + outAlloc.shareBufferQueue(alloc); + } + return outAlloc; } finally { Trace.traceEnd(RenderScript.TRACE_TAG); } } /** + * Initialize BufferQueue with specified max number of buffers. + */ + void setupBufferQueue(int numAlloc) { + mRS.validate(); + if ((mUsage & USAGE_IO_INPUT) == 0) { + throw new RSInvalidStateException("Allocation is not USAGE_IO_INPUT."); + } + mRS.nAllocationSetupBufferQueue(getID(mRS), numAlloc); + } + + /** + * Share the BufferQueue with another {@link #USAGE_IO_INPUT} Allocation. + * + * @param alloc Allocation to associate with allocation + */ + void shareBufferQueue(Allocation alloc) { + mRS.validate(); + if ((mUsage & USAGE_IO_INPUT) == 0) { + throw new RSInvalidStateException("Allocation is not USAGE_IO_INPUT."); + } + mGetSurfaceSurface = alloc.getSurface(); + mRS.nAllocationShareBufferQueue(getID(mRS), alloc.getID(mRS)); + } + + /** + * Gets the stride of the Allocation. + * For a 2D or 3D Allocation, the raw data maybe padded so that each row of + * the Allocation has certain alignment. The size of each row including such + * padding is called stride. + * + * @return the stride. For 1D Allocation, the stride will be the number of + * bytes of this Allocation. For 2D and 3D Allocations, the stride + * will be the stride in X dimension measuring in bytes. + */ + public long getStride() { + if (mByteBufferStride == -1) { + getByteBuffer(); + } + return mByteBufferStride; + } + + /** + * Get the timestamp for the most recent buffer held by this Allocation. + * The timestamp is guaranteed to be unique and monotonically increasing. + * Default value: -1. The timestamp will be updated after each {@link + * #ioReceive ioReceive()} call. + * + * It can be used to identify the images by comparing the unique timestamps + * when used with {@link android.hardware.camera2} APIs. + * Example steps: + * 1. Save {@link android.hardware.camera2.TotalCaptureResult} when the + * capture is completed. + * 2. Get the timestamp after {@link #ioReceive ioReceive()} call. + * 3. Comparing totalCaptureResult.get(CaptureResult.SENSOR_TIMESTAMP) with + * alloc.getTimeStamp(). + * @return long Timestamp associated with the buffer held by the Allocation. + */ + public long getTimeStamp() { + return mTimeStamp; + } + + /** * Returns the handle to a raw buffer that is being managed by the screen * compositor. This operation is only valid for Allocations with {@link * #USAGE_IO_INPUT}. @@ -2153,7 +2365,7 @@ public class Allocation extends BaseObj { if(id == 0) { throw new RSRuntimeException("Load failed for bitmap " + b + " element " + e); } - return new Allocation(id, rs, t, usage); + return new Allocation(id, rs, t, true, usage, mips); } /** @@ -2398,6 +2610,12 @@ public class Allocation extends BaseObj { if((mUsage & USAGE_IO_OUTPUT) != 0) { setSurface(null); } + + if (mType != null && mOwningType) { + mType.destroy(); + } + super.destroy(); } + } |