Loading core/jni/android_nio_utils.cpp +18 −40 Original line number Original line Diff line number Diff line Loading @@ -18,51 +18,29 @@ #include "core_jni_helpers.h" #include "core_jni_helpers.h" namespace { namespace android { void* getPointer(JNIEnv *_env, jobject buffer, jarray *array, void** elements) { AutoBufferPointer::AutoBufferPointer(JNIEnv* env, jobject nioBuffer, jboolean commit) assert(array); : fEnv(env), fCommit(commit) { jint position; jlong pointer = jniGetNioBufferPointer(fEnv, nioBuffer); jint limit; jint elementSizeShift; jlong pointer = jniGetNioBufferFields(_env, buffer, &position, &limit, &elementSizeShift); if (pointer != 0L) { if (pointer != 0L) { *array = nullptr; // Buffer is backed by a direct buffer. *elements = nullptr; fArray = nullptr; pointer += position << elementSizeShift; fElements = nullptr; return reinterpret_cast<void*>(pointer); fPointer = reinterpret_cast<void*>(pointer); } else { // Buffer is backed by a managed array. jint byteOffset = jniGetNioBufferBaseArrayOffset(fEnv, nioBuffer); fArray = jniGetNioBufferBaseArray(fEnv, nioBuffer); fElements = fEnv->GetPrimitiveArrayCritical(fArray, /* isCopy= */ nullptr); fPointer = reinterpret_cast<void*>(reinterpret_cast<char*>(fElements) + byteOffset); } } jint offset = jniGetNioBufferBaseArrayOffset(_env, buffer); *array = jniGetNioBufferBaseArray(_env, buffer); *elements = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0); return reinterpret_cast<void*>(reinterpret_cast<char*>(*elements) + offset); } } void releasePointer(JNIEnv *_env, jarray array, void *elements, jboolean commit) { AutoBufferPointer::~AutoBufferPointer() { _env->ReleasePrimitiveArrayCritical(array, elements, commit ? 0 : JNI_ABORT); } } // namespace void* android::nio_getPointer(JNIEnv *_env, jobject buffer, jarray *array) { void* elements; return getPointer(_env, buffer, array, &elements); } void android::nio_releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit) { releasePointer(_env, array, data, commit); } /////////////////////////////////////////////////////////////////////////////// android::AutoBufferPointer::AutoBufferPointer(JNIEnv* env, jobject nioBuffer, jboolean commit) { fEnv = env; fCommit = commit; fPointer = getPointer(env, nioBuffer, &fArray, &fElements); } android::AutoBufferPointer::~AutoBufferPointer() { if (nullptr != fArray) { if (nullptr != fArray) { releasePointer(fEnv, fArray, fElements, fCommit); fEnv->ReleasePrimitiveArrayCritical(fArray, fElements, fCommit ? 0 : JNI_ABORT); } } } } } // namespace android core/jni/android_nio_utils.h +42 −35 Original line number Original line Diff line number Diff line Loading @@ -22,51 +22,58 @@ namespace android { namespace android { /** /** * Given an nio.Buffer, return a pointer to it, beginning at its current * Class providing scoped access to the memory backing a java.nio.Buffer instance. * position. The returned pointer is only valid for the current JNI stack-frame. * For performance, it does not create any global references, so the getPointer * (and releasePointer if array is returned non-null) must be done in the * same JNI stack-frame. * * * @param env The current JNI env * Instances of this class should only be allocated on the stack as heap allocation is not * @param buffer The nio.Buffer object * supported. * @param array REQUIRED. Output. If on return it is set to non-null, then * * nio_releasePointer must be called with the array * Instances of this class do not create any global references for performance reasons. * and the returned pointer when the caller is through with it. * If on return it is set to null, do not call * nio_releasePointer. * @return The pointer to the memory in the buffer object */ */ void* nio_getPointer(JNIEnv *env, jobject buffer, jarray *array); class AutoBufferPointer final { public: /** /** Constructor for an AutoBufferPointer instance. * Call this if android_nio_getPointer returned non-null in its array parameter. * Pass that array and the returned pointer when you are done accessing the * pointer. If called (i.e. array is non-null), it must be called in the same * JNI stack-frame as getPointer * * * @param env The current JNI env * @param env The current JNI env * @param buffer The array returned from android_nio_getPointer (!= null) * @param nioBuffer Instance of a java.nio.Buffer whose memory will be accessed. * @param pointer The pointer returned by android_nio_getPointer * @param commit JNI_TRUE if the underlying memory will be updated and should be * @param commit JNI_FALSE if the pointer was just read, and JNI_TRUE if * copied back to the managed heap. JNI_FALSE if the data will * the pointer was written to. * not be modified or the modifications may be discarded. * * The commit parameter is only applicable if the buffer is backed by a managed heap * array and the runtime had to provide a copy of the data rather than the original data. */ */ void nio_releasePointer(JNIEnv *env, jarray array, void *pointer, jboolean commit); class AutoBufferPointer { public: AutoBufferPointer(JNIEnv* env, jobject nioBuffer, jboolean commit); AutoBufferPointer(JNIEnv* env, jobject nioBuffer, jboolean commit); /** Destructor for an AutoBufferPointer instance. * * Releases critical managed heap array pointer if acquired. */ ~AutoBufferPointer(); ~AutoBufferPointer(); /** * Returns a pointer to the current position of the buffer provided to the constructor. This * pointer is only valid whilst the AutoBufferPointer instance remains in scope. */ void* pointer() const { return fPointer; } void* pointer() const { return fPointer; } private: private: JNIEnv* fEnv; JNIEnv* const fEnv; void* fPointer; // pointer to current buffer position. void* fPointer; // Pointer to current buffer position when constructed. void* fElements; // pointer to array element 0 (may be directly in fArray or a copy). void* fElements; // Pointer to array element 0 (null if buffer is direct, may be jarray fArray; // pointer to array on managed heap. // within fArray or point to a copy of the array). jboolean fCommit; // commit data to source if required (when fElements is a copy of fArray). jarray fArray; // Pointer to array on managed heap. const jboolean fCommit; // Flag to commit data to source (when fElements is a copy of fArray). // Unsupported constructors and operators. AutoBufferPointer() = delete; AutoBufferPointer(AutoBufferPointer&) = delete; AutoBufferPointer& operator=(AutoBufferPointer&) = delete; static void* operator new(std::size_t); static void* operator new[](std::size_t); static void* operator new(std::size_t, void*); static void* operator new[](std::size_t, void*); static void operator delete(void*, std::size_t); static void operator delete[](void*, std::size_t); }; }; } /* namespace android */ } /* namespace android */ Loading core/tests/coretests/src/android/graphics/BitmapTest.java +165 −6 Original line number Original line Diff line number Diff line Loading @@ -23,6 +23,8 @@ import androidx.test.filters.SmallTest; import junit.framework.TestCase; import junit.framework.TestCase; import java.nio.ByteBuffer; import java.nio.ByteBuffer; import java.nio.IntBuffer; import java.nio.ShortBuffer; public class BitmapTest extends TestCase { public class BitmapTest extends TestCase { Loading Loading @@ -266,10 +268,11 @@ public class BitmapTest extends TestCase { } } @SmallTest @SmallTest public void testCopyWithDirectBuffer() { public void testCopyWithDirectByteBuffer() { // Initialize Bitmap // Initialize Bitmap final int width = 2; final int width = 2; final int height = 2; final int height = 2; final int bytesPerPixel = 2; Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2); bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2); Loading @@ -277,7 +280,8 @@ public class BitmapTest extends TestCase { // of bitmap. // of bitmap. final int pad = 1; final int pad = 1; final byte padValue = 0x5a; final byte padValue = 0x5a; final int bufferSize = pad + width * height * 2 + pad; final int bytesPerElement = 1; final int bufferSize = pad + width * height * bytesPerPixel / bytesPerElement + pad; ByteBuffer directBuffer = ByteBuffer.allocateDirect(bufferSize); ByteBuffer directBuffer = ByteBuffer.allocateDirect(bufferSize); // Write padding // Write padding Loading @@ -287,7 +291,8 @@ public class BitmapTest extends TestCase { // Copy bitmap // Copy bitmap directBuffer.position(pad); directBuffer.position(pad); bm1.copyPixelsToBuffer(directBuffer); bm1.copyPixelsToBuffer(directBuffer); assertEquals(directBuffer.position(), pad + width * height * 2); assertEquals(directBuffer.position(), pad + width * height * bytesPerPixel / bytesPerElement); // Check padding // Check padding assertEquals(directBuffer.get(0), padValue); assertEquals(directBuffer.get(0), padValue); Loading @@ -301,10 +306,89 @@ public class BitmapTest extends TestCase { } } @SmallTest @SmallTest public void testCopyWithHeapBuffer() { public void testCopyWithDirectShortBuffer() { // Initialize Bitmap // Initialize Bitmap final int width = 2; final int width = 2; final int height = 2; final int height = 2; final int bytesPerPixel = 2; Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2); // Copy bytes to heap buffer, buffer is padded by fixed amount (pad bytes) either side // of bitmap. final int pad = 1; final short padValue = 0x55aa; final int bytesPerElement = 2; final int bufferSize = pad + width * height * bytesPerPixel / bytesPerElement + pad; ShortBuffer directBuffer = ByteBuffer.allocateDirect(bufferSize * bytesPerElement).asShortBuffer(); // Write padding directBuffer.put(0, padValue); directBuffer.put(directBuffer.limit() - 1, padValue); // Copy bitmap directBuffer.position(pad); bm1.copyPixelsToBuffer(directBuffer); assertEquals(directBuffer.position(), pad + width * height * bytesPerPixel / bytesPerElement); // Check padding assertEquals(directBuffer.get(0), padValue); assertEquals(directBuffer.get(directBuffer.limit() - 1), padValue); // Create bitmap from heap buffer and check match. directBuffer.position(pad); Bitmap bm2 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); bm2.copyPixelsFromBuffer(directBuffer); assertTrue(bm2.sameAs(bm1)); } @SmallTest public void testCopyWithDirectIntBuffer() { // Initialize Bitmap final int width = 2; final int height = 2; final int bytesPerPixel = 2; Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2); // Copy bytes to heap buffer, buffer is padded by fixed amount (pad bytes) either side // of bitmap. final int pad = 1; final int padValue = 0x55aa5a5a; final int bytesPerElement = 4; final int bufferSize = pad + width * height * bytesPerPixel / bytesPerElement + pad; IntBuffer directBuffer = ByteBuffer.allocateDirect(bufferSize * bytesPerElement).asIntBuffer(); // Write padding directBuffer.put(0, padValue); directBuffer.put(directBuffer.limit() - 1, padValue); // Copy bitmap directBuffer.position(pad); bm1.copyPixelsToBuffer(directBuffer); assertEquals(directBuffer.position(), pad + width * height * bytesPerPixel / bytesPerElement); // Check padding assertEquals(directBuffer.get(0), padValue); assertEquals(directBuffer.get(directBuffer.limit() - 1), padValue); // Create bitmap from heap buffer and check match. directBuffer.position(pad); Bitmap bm2 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); bm2.copyPixelsFromBuffer(directBuffer); assertTrue(bm2.sameAs(bm1)); } @SmallTest public void testCopyWithHeapByteBuffer() { // Initialize Bitmap final int width = 2; final int height = 2; final int bytesPerPixel = 2; Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2); bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2); Loading @@ -312,7 +396,8 @@ public class BitmapTest extends TestCase { // of bitmap. // of bitmap. final int pad = 1; final int pad = 1; final byte padValue = 0x5a; final byte padValue = 0x5a; final int bufferSize = pad + width * height * 2 + pad; final int bytesPerElement = 1; final int bufferSize = pad + width * height * bytesPerPixel / bytesPerElement + pad; ByteBuffer heapBuffer = ByteBuffer.allocate(bufferSize); ByteBuffer heapBuffer = ByteBuffer.allocate(bufferSize); // Write padding // Write padding Loading @@ -322,7 +407,81 @@ public class BitmapTest extends TestCase { // Copy bitmap // Copy bitmap heapBuffer.position(pad); heapBuffer.position(pad); bm1.copyPixelsToBuffer(heapBuffer); bm1.copyPixelsToBuffer(heapBuffer); assertEquals(heapBuffer.position(), pad + width * height * 2); assertEquals(heapBuffer.position(), pad + width * height * bytesPerPixel / bytesPerElement); // Check padding assertEquals(heapBuffer.get(0), padValue); assertEquals(heapBuffer.get(heapBuffer.limit() - 1), padValue); // Create bitmap from heap buffer and check match. heapBuffer.position(pad); Bitmap bm2 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); bm2.copyPixelsFromBuffer(heapBuffer); assertTrue(bm2.sameAs(bm1)); } @SmallTest public void testCopyWithHeapShortBuffer() { // Initialize Bitmap final int width = 2; final int height = 2; final int bytesPerPixel = 2; Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2); // Copy bytes to heap buffer, buffer is padded by fixed amount (pad bytes) either side // of bitmap. final int pad = 1; final short padValue = 0x55aa; final int bytesPerElement = 2; final int bufferSize = pad + width * height * bytesPerPixel / bytesPerElement + pad; ShortBuffer heapBuffer = ShortBuffer.allocate(bufferSize); // Write padding heapBuffer.put(0, padValue); heapBuffer.put(heapBuffer.limit() - 1, padValue); // Copy bitmap heapBuffer.position(pad); bm1.copyPixelsToBuffer(heapBuffer); assertEquals(heapBuffer.position(), pad + width * height * bytesPerPixel / bytesPerElement); // Check padding assertEquals(heapBuffer.get(0), padValue); assertEquals(heapBuffer.get(heapBuffer.limit() - 1), padValue); // Create bitmap from heap buffer and check match. heapBuffer.position(pad); Bitmap bm2 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); bm2.copyPixelsFromBuffer(heapBuffer); assertTrue(bm2.sameAs(bm1)); } @SmallTest public void testCopyWithHeapIntBuffer() { // Initialize Bitmap final int width = 2; final int height = 2; final int bytesPerPixel = 2; Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2); // Copy bytes to heap buffer, buffer is padded by fixed amount (pad bytes) either side // of bitmap. final int pad = 1; final int padValue = 0x55aa5a5a; final int bytesPerElement = 4; final int bufferSize = pad + width * height * bytesPerPixel / bytesPerElement + pad; IntBuffer heapBuffer = IntBuffer.allocate(bufferSize); // Write padding heapBuffer.put(0, padValue); heapBuffer.put(heapBuffer.limit() - 1, padValue); // Copy bitmap heapBuffer.position(pad); bm1.copyPixelsToBuffer(heapBuffer); assertEquals(heapBuffer.position(), pad + width * height * bytesPerPixel / bytesPerElement); // Check padding // Check padding assertEquals(heapBuffer.get(0), padValue); assertEquals(heapBuffer.get(0), padValue); Loading Loading
core/jni/android_nio_utils.cpp +18 −40 Original line number Original line Diff line number Diff line Loading @@ -18,51 +18,29 @@ #include "core_jni_helpers.h" #include "core_jni_helpers.h" namespace { namespace android { void* getPointer(JNIEnv *_env, jobject buffer, jarray *array, void** elements) { AutoBufferPointer::AutoBufferPointer(JNIEnv* env, jobject nioBuffer, jboolean commit) assert(array); : fEnv(env), fCommit(commit) { jint position; jlong pointer = jniGetNioBufferPointer(fEnv, nioBuffer); jint limit; jint elementSizeShift; jlong pointer = jniGetNioBufferFields(_env, buffer, &position, &limit, &elementSizeShift); if (pointer != 0L) { if (pointer != 0L) { *array = nullptr; // Buffer is backed by a direct buffer. *elements = nullptr; fArray = nullptr; pointer += position << elementSizeShift; fElements = nullptr; return reinterpret_cast<void*>(pointer); fPointer = reinterpret_cast<void*>(pointer); } else { // Buffer is backed by a managed array. jint byteOffset = jniGetNioBufferBaseArrayOffset(fEnv, nioBuffer); fArray = jniGetNioBufferBaseArray(fEnv, nioBuffer); fElements = fEnv->GetPrimitiveArrayCritical(fArray, /* isCopy= */ nullptr); fPointer = reinterpret_cast<void*>(reinterpret_cast<char*>(fElements) + byteOffset); } } jint offset = jniGetNioBufferBaseArrayOffset(_env, buffer); *array = jniGetNioBufferBaseArray(_env, buffer); *elements = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0); return reinterpret_cast<void*>(reinterpret_cast<char*>(*elements) + offset); } } void releasePointer(JNIEnv *_env, jarray array, void *elements, jboolean commit) { AutoBufferPointer::~AutoBufferPointer() { _env->ReleasePrimitiveArrayCritical(array, elements, commit ? 0 : JNI_ABORT); } } // namespace void* android::nio_getPointer(JNIEnv *_env, jobject buffer, jarray *array) { void* elements; return getPointer(_env, buffer, array, &elements); } void android::nio_releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit) { releasePointer(_env, array, data, commit); } /////////////////////////////////////////////////////////////////////////////// android::AutoBufferPointer::AutoBufferPointer(JNIEnv* env, jobject nioBuffer, jboolean commit) { fEnv = env; fCommit = commit; fPointer = getPointer(env, nioBuffer, &fArray, &fElements); } android::AutoBufferPointer::~AutoBufferPointer() { if (nullptr != fArray) { if (nullptr != fArray) { releasePointer(fEnv, fArray, fElements, fCommit); fEnv->ReleasePrimitiveArrayCritical(fArray, fElements, fCommit ? 0 : JNI_ABORT); } } } } } // namespace android
core/jni/android_nio_utils.h +42 −35 Original line number Original line Diff line number Diff line Loading @@ -22,51 +22,58 @@ namespace android { namespace android { /** /** * Given an nio.Buffer, return a pointer to it, beginning at its current * Class providing scoped access to the memory backing a java.nio.Buffer instance. * position. The returned pointer is only valid for the current JNI stack-frame. * For performance, it does not create any global references, so the getPointer * (and releasePointer if array is returned non-null) must be done in the * same JNI stack-frame. * * * @param env The current JNI env * Instances of this class should only be allocated on the stack as heap allocation is not * @param buffer The nio.Buffer object * supported. * @param array REQUIRED. Output. If on return it is set to non-null, then * * nio_releasePointer must be called with the array * Instances of this class do not create any global references for performance reasons. * and the returned pointer when the caller is through with it. * If on return it is set to null, do not call * nio_releasePointer. * @return The pointer to the memory in the buffer object */ */ void* nio_getPointer(JNIEnv *env, jobject buffer, jarray *array); class AutoBufferPointer final { public: /** /** Constructor for an AutoBufferPointer instance. * Call this if android_nio_getPointer returned non-null in its array parameter. * Pass that array and the returned pointer when you are done accessing the * pointer. If called (i.e. array is non-null), it must be called in the same * JNI stack-frame as getPointer * * * @param env The current JNI env * @param env The current JNI env * @param buffer The array returned from android_nio_getPointer (!= null) * @param nioBuffer Instance of a java.nio.Buffer whose memory will be accessed. * @param pointer The pointer returned by android_nio_getPointer * @param commit JNI_TRUE if the underlying memory will be updated and should be * @param commit JNI_FALSE if the pointer was just read, and JNI_TRUE if * copied back to the managed heap. JNI_FALSE if the data will * the pointer was written to. * not be modified or the modifications may be discarded. * * The commit parameter is only applicable if the buffer is backed by a managed heap * array and the runtime had to provide a copy of the data rather than the original data. */ */ void nio_releasePointer(JNIEnv *env, jarray array, void *pointer, jboolean commit); class AutoBufferPointer { public: AutoBufferPointer(JNIEnv* env, jobject nioBuffer, jboolean commit); AutoBufferPointer(JNIEnv* env, jobject nioBuffer, jboolean commit); /** Destructor for an AutoBufferPointer instance. * * Releases critical managed heap array pointer if acquired. */ ~AutoBufferPointer(); ~AutoBufferPointer(); /** * Returns a pointer to the current position of the buffer provided to the constructor. This * pointer is only valid whilst the AutoBufferPointer instance remains in scope. */ void* pointer() const { return fPointer; } void* pointer() const { return fPointer; } private: private: JNIEnv* fEnv; JNIEnv* const fEnv; void* fPointer; // pointer to current buffer position. void* fPointer; // Pointer to current buffer position when constructed. void* fElements; // pointer to array element 0 (may be directly in fArray or a copy). void* fElements; // Pointer to array element 0 (null if buffer is direct, may be jarray fArray; // pointer to array on managed heap. // within fArray or point to a copy of the array). jboolean fCommit; // commit data to source if required (when fElements is a copy of fArray). jarray fArray; // Pointer to array on managed heap. const jboolean fCommit; // Flag to commit data to source (when fElements is a copy of fArray). // Unsupported constructors and operators. AutoBufferPointer() = delete; AutoBufferPointer(AutoBufferPointer&) = delete; AutoBufferPointer& operator=(AutoBufferPointer&) = delete; static void* operator new(std::size_t); static void* operator new[](std::size_t); static void* operator new(std::size_t, void*); static void* operator new[](std::size_t, void*); static void operator delete(void*, std::size_t); static void operator delete[](void*, std::size_t); }; }; } /* namespace android */ } /* namespace android */ Loading
core/tests/coretests/src/android/graphics/BitmapTest.java +165 −6 Original line number Original line Diff line number Diff line Loading @@ -23,6 +23,8 @@ import androidx.test.filters.SmallTest; import junit.framework.TestCase; import junit.framework.TestCase; import java.nio.ByteBuffer; import java.nio.ByteBuffer; import java.nio.IntBuffer; import java.nio.ShortBuffer; public class BitmapTest extends TestCase { public class BitmapTest extends TestCase { Loading Loading @@ -266,10 +268,11 @@ public class BitmapTest extends TestCase { } } @SmallTest @SmallTest public void testCopyWithDirectBuffer() { public void testCopyWithDirectByteBuffer() { // Initialize Bitmap // Initialize Bitmap final int width = 2; final int width = 2; final int height = 2; final int height = 2; final int bytesPerPixel = 2; Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2); bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2); Loading @@ -277,7 +280,8 @@ public class BitmapTest extends TestCase { // of bitmap. // of bitmap. final int pad = 1; final int pad = 1; final byte padValue = 0x5a; final byte padValue = 0x5a; final int bufferSize = pad + width * height * 2 + pad; final int bytesPerElement = 1; final int bufferSize = pad + width * height * bytesPerPixel / bytesPerElement + pad; ByteBuffer directBuffer = ByteBuffer.allocateDirect(bufferSize); ByteBuffer directBuffer = ByteBuffer.allocateDirect(bufferSize); // Write padding // Write padding Loading @@ -287,7 +291,8 @@ public class BitmapTest extends TestCase { // Copy bitmap // Copy bitmap directBuffer.position(pad); directBuffer.position(pad); bm1.copyPixelsToBuffer(directBuffer); bm1.copyPixelsToBuffer(directBuffer); assertEquals(directBuffer.position(), pad + width * height * 2); assertEquals(directBuffer.position(), pad + width * height * bytesPerPixel / bytesPerElement); // Check padding // Check padding assertEquals(directBuffer.get(0), padValue); assertEquals(directBuffer.get(0), padValue); Loading @@ -301,10 +306,89 @@ public class BitmapTest extends TestCase { } } @SmallTest @SmallTest public void testCopyWithHeapBuffer() { public void testCopyWithDirectShortBuffer() { // Initialize Bitmap // Initialize Bitmap final int width = 2; final int width = 2; final int height = 2; final int height = 2; final int bytesPerPixel = 2; Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2); // Copy bytes to heap buffer, buffer is padded by fixed amount (pad bytes) either side // of bitmap. final int pad = 1; final short padValue = 0x55aa; final int bytesPerElement = 2; final int bufferSize = pad + width * height * bytesPerPixel / bytesPerElement + pad; ShortBuffer directBuffer = ByteBuffer.allocateDirect(bufferSize * bytesPerElement).asShortBuffer(); // Write padding directBuffer.put(0, padValue); directBuffer.put(directBuffer.limit() - 1, padValue); // Copy bitmap directBuffer.position(pad); bm1.copyPixelsToBuffer(directBuffer); assertEquals(directBuffer.position(), pad + width * height * bytesPerPixel / bytesPerElement); // Check padding assertEquals(directBuffer.get(0), padValue); assertEquals(directBuffer.get(directBuffer.limit() - 1), padValue); // Create bitmap from heap buffer and check match. directBuffer.position(pad); Bitmap bm2 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); bm2.copyPixelsFromBuffer(directBuffer); assertTrue(bm2.sameAs(bm1)); } @SmallTest public void testCopyWithDirectIntBuffer() { // Initialize Bitmap final int width = 2; final int height = 2; final int bytesPerPixel = 2; Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2); // Copy bytes to heap buffer, buffer is padded by fixed amount (pad bytes) either side // of bitmap. final int pad = 1; final int padValue = 0x55aa5a5a; final int bytesPerElement = 4; final int bufferSize = pad + width * height * bytesPerPixel / bytesPerElement + pad; IntBuffer directBuffer = ByteBuffer.allocateDirect(bufferSize * bytesPerElement).asIntBuffer(); // Write padding directBuffer.put(0, padValue); directBuffer.put(directBuffer.limit() - 1, padValue); // Copy bitmap directBuffer.position(pad); bm1.copyPixelsToBuffer(directBuffer); assertEquals(directBuffer.position(), pad + width * height * bytesPerPixel / bytesPerElement); // Check padding assertEquals(directBuffer.get(0), padValue); assertEquals(directBuffer.get(directBuffer.limit() - 1), padValue); // Create bitmap from heap buffer and check match. directBuffer.position(pad); Bitmap bm2 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); bm2.copyPixelsFromBuffer(directBuffer); assertTrue(bm2.sameAs(bm1)); } @SmallTest public void testCopyWithHeapByteBuffer() { // Initialize Bitmap final int width = 2; final int height = 2; final int bytesPerPixel = 2; Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2); bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2); Loading @@ -312,7 +396,8 @@ public class BitmapTest extends TestCase { // of bitmap. // of bitmap. final int pad = 1; final int pad = 1; final byte padValue = 0x5a; final byte padValue = 0x5a; final int bufferSize = pad + width * height * 2 + pad; final int bytesPerElement = 1; final int bufferSize = pad + width * height * bytesPerPixel / bytesPerElement + pad; ByteBuffer heapBuffer = ByteBuffer.allocate(bufferSize); ByteBuffer heapBuffer = ByteBuffer.allocate(bufferSize); // Write padding // Write padding Loading @@ -322,7 +407,81 @@ public class BitmapTest extends TestCase { // Copy bitmap // Copy bitmap heapBuffer.position(pad); heapBuffer.position(pad); bm1.copyPixelsToBuffer(heapBuffer); bm1.copyPixelsToBuffer(heapBuffer); assertEquals(heapBuffer.position(), pad + width * height * 2); assertEquals(heapBuffer.position(), pad + width * height * bytesPerPixel / bytesPerElement); // Check padding assertEquals(heapBuffer.get(0), padValue); assertEquals(heapBuffer.get(heapBuffer.limit() - 1), padValue); // Create bitmap from heap buffer and check match. heapBuffer.position(pad); Bitmap bm2 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); bm2.copyPixelsFromBuffer(heapBuffer); assertTrue(bm2.sameAs(bm1)); } @SmallTest public void testCopyWithHeapShortBuffer() { // Initialize Bitmap final int width = 2; final int height = 2; final int bytesPerPixel = 2; Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2); // Copy bytes to heap buffer, buffer is padded by fixed amount (pad bytes) either side // of bitmap. final int pad = 1; final short padValue = 0x55aa; final int bytesPerElement = 2; final int bufferSize = pad + width * height * bytesPerPixel / bytesPerElement + pad; ShortBuffer heapBuffer = ShortBuffer.allocate(bufferSize); // Write padding heapBuffer.put(0, padValue); heapBuffer.put(heapBuffer.limit() - 1, padValue); // Copy bitmap heapBuffer.position(pad); bm1.copyPixelsToBuffer(heapBuffer); assertEquals(heapBuffer.position(), pad + width * height * bytesPerPixel / bytesPerElement); // Check padding assertEquals(heapBuffer.get(0), padValue); assertEquals(heapBuffer.get(heapBuffer.limit() - 1), padValue); // Create bitmap from heap buffer and check match. heapBuffer.position(pad); Bitmap bm2 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); bm2.copyPixelsFromBuffer(heapBuffer); assertTrue(bm2.sameAs(bm1)); } @SmallTest public void testCopyWithHeapIntBuffer() { // Initialize Bitmap final int width = 2; final int height = 2; final int bytesPerPixel = 2; Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2); // Copy bytes to heap buffer, buffer is padded by fixed amount (pad bytes) either side // of bitmap. final int pad = 1; final int padValue = 0x55aa5a5a; final int bytesPerElement = 4; final int bufferSize = pad + width * height * bytesPerPixel / bytesPerElement + pad; IntBuffer heapBuffer = IntBuffer.allocate(bufferSize); // Write padding heapBuffer.put(0, padValue); heapBuffer.put(heapBuffer.limit() - 1, padValue); // Copy bitmap heapBuffer.position(pad); bm1.copyPixelsToBuffer(heapBuffer); assertEquals(heapBuffer.position(), pad + width * height * bytesPerPixel / bytesPerElement); // Check padding // Check padding assertEquals(heapBuffer.get(0), padValue); assertEquals(heapBuffer.get(0), padValue); Loading