Merge "Bitmap CTS additions for wrapHardwareBuffer."
diff --git a/tests/tests/graphics/jni/android_graphics_cts_BitmapTest.cpp b/tests/tests/graphics/jni/android_graphics_cts_BitmapTest.cpp
index 2e3bf06..b08f384 100644
--- a/tests/tests/graphics/jni/android_graphics_cts_BitmapTest.cpp
+++ b/tests/tests/graphics/jni/android_graphics_cts_BitmapTest.cpp
@@ -19,6 +19,8 @@
#include <jni.h>
#include <android/bitmap.h>
+#include <android/hardware_buffer.h>
+#include <android/hardware_buffer_jni.h>
#include "NativeTestHelpers.h"
@@ -41,11 +43,37 @@
ASSERT_EQ(err, ANDROID_BITMAP_RESULT_JNI_EXCEPTION);
}
+static void fillRgbaHardwareBuffer(JNIEnv* env, jclass, jobject hwBuffer) {
+ AHardwareBuffer* hardware_buffer = AHardwareBuffer_fromHardwareBuffer(env, hwBuffer);
+ AHardwareBuffer_Desc description;
+ AHardwareBuffer_describe(hardware_buffer, &description);
+ ASSERT_EQ(AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, description.format);
+
+ uint8_t* rgbaBytes;
+ AHardwareBuffer_lock(hardware_buffer,
+ AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY,
+ -1,
+ nullptr,
+ reinterpret_cast<void**>(&rgbaBytes));
+ int c = 0;
+ for (int y = 0; y < description.width; ++y) {
+ for (int x = 0; x < description.height; ++x) {
+ rgbaBytes[c++] = static_cast<uint8_t>(x % 255);
+ rgbaBytes[c++] = static_cast<uint8_t>(y % 255);
+ rgbaBytes[c++] = 42;
+ rgbaBytes[c++] = 255;
+ }
+ }
+ AHardwareBuffer_unlock(hardware_buffer, nullptr);
+}
+
static JNINativeMethod gMethods[] = {
{ "nValidateBitmapInfo", "(Landroid/graphics/Bitmap;IIZ)V",
(void*) validateBitmapInfo },
{ "nValidateNdkAccessAfterRecycle", "(Landroid/graphics/Bitmap;)V",
(void*) validateNdkAccessAfterRecycle },
+ { "nFillRgbaHwBuffer", "(Landroid/hardware/HardwareBuffer;)V",
+ (void*) fillRgbaHardwareBuffer },
};
int register_android_graphics_cts_BitmapTest(JNIEnv* env) {
diff --git a/tests/tests/graphics/src/android/graphics/cts/BitmapTest.java b/tests/tests/graphics/src/android/graphics/cts/BitmapTest.java
index 5289726..69bb828 100644
--- a/tests/tests/graphics/src/android/graphics/cts/BitmapTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/BitmapTest.java
@@ -34,6 +34,7 @@
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Picture;
+import android.hardware.HardwareBuffer;
import android.os.Debug;
import android.os.Parcel;
import android.os.StrictMode;
@@ -522,6 +523,31 @@
}
@Test
+ public void testWrapHardwareBufferSucceeds() {
+ try (HardwareBuffer hwBuffer = createTestBuffer(128, 128, false)) {
+ Bitmap bitmap = Bitmap.wrapHardwareBuffer(hwBuffer, ColorSpace.get(Named.SRGB));
+ assertNotNull(bitmap);
+ bitmap.recycle();
+ }
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testWrapHardwareBufferWithInvalidUsageFails() {
+ try (HardwareBuffer hwBuffer = HardwareBuffer.create(512, 512, HardwareBuffer.RGBA_8888, 1,
+ HardwareBuffer.USAGE_CPU_WRITE_RARELY)) {
+ Bitmap bitmap = Bitmap.wrapHardwareBuffer(hwBuffer, ColorSpace.get(Named.SRGB));
+ }
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testWrapHardwareBufferWithRgbBufferButNonRgbColorSpaceFails() {
+ try (HardwareBuffer hwBuffer = HardwareBuffer.create(512, 512, HardwareBuffer.RGBA_8888, 1,
+ HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE)) {
+ Bitmap bitmap = Bitmap.wrapHardwareBuffer(hwBuffer, ColorSpace.get(Named.CIE_LAB));
+ }
+ }
+
+ @Test
public void testGenerationId() {
Bitmap bitmap = Bitmap.createBitmap(10, 10, Config.ARGB_8888);
int genId = bitmap.getGenerationId();
@@ -1380,6 +1406,30 @@
assertFalse(bitmap1.sameAs(bitmap4));
}
+ @Test
+ public void testSameAs_wrappedHardwareBuffer() {
+ try (HardwareBuffer hwBufferA = createTestBuffer(512, 512, true);
+ HardwareBuffer hwBufferB = createTestBuffer(512, 512, true);
+ HardwareBuffer hwBufferC = createTestBuffer(512, 512, true);) {
+ // Fill buffer C with generated data
+ nFillRgbaHwBuffer(hwBufferC);
+
+ // Create the test bitmaps
+ Bitmap bitmap1 = Bitmap.wrapHardwareBuffer(hwBufferA, ColorSpace.get(Named.SRGB));
+ Bitmap bitmap2 = Bitmap.wrapHardwareBuffer(hwBufferA, ColorSpace.get(Named.SRGB));
+ Bitmap bitmap3 = BitmapFactory.decodeResource(mRes, R.drawable.robot);
+ Bitmap bitmap4 = Bitmap.wrapHardwareBuffer(hwBufferB, ColorSpace.get(Named.SRGB));
+ Bitmap bitmap5 = Bitmap.wrapHardwareBuffer(hwBufferC, ColorSpace.get(Named.SRGB));
+
+ // Run the compare-a-thon
+ assertTrue(bitmap1.sameAs(bitmap2)); // SAME UNDERLYING BUFFER
+ assertTrue(bitmap2.sameAs(bitmap1)); // SAME UNDERLYING BUFFER
+ assertFalse(bitmap1.sameAs(bitmap3)); // HW vs. NON-HW
+ assertTrue(bitmap1.sameAs(bitmap4)); // DIFFERENT BUFFERS, SAME CONTENT
+ assertFalse(bitmap1.sameAs(bitmap5)); // DIFFERENT BUFFERS, DIFFERENT CONTENT
+ }
+ }
+
@Test(expected=IllegalStateException.class)
public void testHardwareGetPixel() {
Bitmap bitmap = BitmapFactory.decodeResource(mRes, R.drawable.robot, HARDWARE_OPTIONS);
@@ -1620,6 +1670,41 @@
@Test
@LargeTest
+ public void testWrappedHardwareBufferBitmapNotLeaking() {
+ Debug.MemoryInfo meminfoStart = new Debug.MemoryInfo();
+ Debug.MemoryInfo meminfoEnd = new Debug.MemoryInfo();
+ BitmapFactory.Options opts = new BitmapFactory.Options();
+ opts.inPreferredConfig = Config.HARDWARE;
+ opts.inScaled = false;
+
+ final ColorSpace colorSpace = ColorSpace.get(Named.SRGB);
+ try (HardwareBuffer hwBuffer = createTestBuffer(128, 128, false)) {
+ for (int i = 0; i < 2000; i++) {
+ if (i == 2) {
+ // Not really the "start" but by having done a couple
+ // we've fully initialized any state that may be required,
+ // so memory usage should be stable now
+ runGcAndFinalizersSync();
+ Debug.getMemoryInfo(meminfoStart);
+ }
+ if (i % 100 == 5) {
+ assertNotLeaking(i, meminfoStart, meminfoEnd);
+ }
+ Bitmap bitmap = Bitmap.wrapHardwareBuffer(hwBuffer, colorSpace);
+ assertNotNull(bitmap);
+ // Make sure nothing messed with the bitmap
+ assertEquals(128, bitmap.getWidth());
+ assertEquals(128, bitmap.getHeight());
+ assertEquals(Config.HARDWARE, bitmap.getConfig());
+ bitmap.recycle();
+ }
+ }
+
+ assertNotLeaking(2000, meminfoStart, meminfoEnd);
+ }
+
+ @Test
+ @LargeTest
public void testDrawingHardwareBitmapNotLeaking() {
Debug.MemoryInfo meminfoStart = new Debug.MemoryInfo();
Debug.MemoryInfo meminfoEnd = new Debug.MemoryInfo();
@@ -1656,6 +1741,64 @@
assertNotLeaking(2000, meminfoStart, meminfoEnd);
}
+ @Test
+ public void testWrapHardwareBufferHoldsReference() {
+ RenderTarget renderTarget = RenderTarget.create();
+ renderTarget.setDefaultSize(128, 128);
+ final Surface surface = renderTarget.getSurface();
+ Bitmap bitmap = null;
+
+ // Create hardware-buffer and wrap it in a Bitmap
+ try (HardwareBuffer hwBuffer = createTestBuffer(128, 128, false)) {
+ // Fill buffer with colors (x, y, 42, 255)
+ nFillRgbaHwBuffer(hwBuffer);
+ bitmap = Bitmap.wrapHardwareBuffer(hwBuffer, ColorSpace.get(Named.SRGB));
+ }
+
+ // Buffer is closed at this point. Ensure bitmap still works by drawing it
+ assertEquals(128, bitmap.getWidth());
+ assertEquals(128, bitmap.getHeight());
+ assertEquals(Config.HARDWARE, bitmap.getConfig());
+
+ // Copy bitmap to target bitmap we can read from
+ Bitmap dstBitmap = bitmap.copy(Config.ARGB_8888, false);
+ bitmap.recycle();
+
+ // Ensure that the bitmap has valid contents
+ int pixel = dstBitmap.getPixel(0, 0);
+ assertEquals(255 << 24 | 42, pixel);
+ dstBitmap.recycle();
+ }
+
+ @Test
+ public void testWrapHardwareBufferPreservesColors() {
+ try (HardwareBuffer hwBuffer = createTestBuffer(128, 128, true)) {
+ // Fill buffer with colors (x, y, 42, 255)
+ nFillRgbaHwBuffer(hwBuffer);
+
+ // Create HW bitmap from this buffer
+ Bitmap srcBitmap = Bitmap.wrapHardwareBuffer(hwBuffer, ColorSpace.get(Named.SRGB));
+ assertNotNull(srcBitmap);
+
+ // Copy it to target non-HW bitmap
+ Bitmap dstBitmap = srcBitmap.copy(Config.ARGB_8888, false);
+ srcBitmap.recycle();
+
+ // Ensure all colors are as expected (matches the nFillRgbaHwBuffer call used above).
+ for (int y = 0; y < 128; ++y) {
+ for (int x = 0; x < 128; ++x) {
+ int pixel = dstBitmap.getPixel(x, y);
+ short a = 255;
+ short r = (short) (x % 255);
+ short g = (short) (y % 255);
+ short b = 42;
+ assertEquals(a << 24 | r << 16 | g << 8 | b, pixel);
+ }
+ }
+ dstBitmap.recycle();
+ }
+ }
+
private void strictModeTest(Runnable runnable) {
StrictMode.ThreadPolicy originalPolicy = StrictMode.getThreadPolicy();
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
@@ -1674,6 +1817,19 @@
boolean is565);
private static native void nValidateNdkAccessAfterRecycle(Bitmap bitmap);
+ private static native void nFillRgbaHwBuffer(HardwareBuffer hwBuffer);
+
+ private static HardwareBuffer createTestBuffer(int width, int height, boolean cpuAccess) {
+ long usage = HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE;
+ if (cpuAccess) {
+ usage |= HardwareBuffer.USAGE_CPU_WRITE_RARELY;
+ }
+ // We can assume that RGBA_8888 format is supported for every platform.
+ HardwareBuffer hwBuffer = HardwareBuffer.create(width, height, HardwareBuffer.RGBA_8888,
+ 1, usage);
+ return hwBuffer;
+ }
+
private static int scaleFromDensity(int size, int sdensity, int tdensity) {
if (sdensity == Bitmap.DENSITY_NONE || sdensity == tdensity) {
return size;