minigbm: move gralloctest to this repo

The autotest eclass has issues when compiling for multilib, and plus
we can keep the test with the source code.

BUG=b:63610343
TEST=emerge-eve arc-cros-gralloc
CQ-DEPEND=CL:699675, CL:699734

Change-Id: I9ec3185f7e18f4717ef560e599e635f03b0a999d
Reviewed-on: https://chromium-review.googlesource.com/699676
Commit-Ready: Gurchetan Singh <gurchetansingh@chromium.org>
Tested-by: Gurchetan Singh <gurchetansingh@chromium.org>
Reviewed-by: Stéphane Marchesin <marcheu@chromium.org>
diff --git a/cros_gralloc/gralloc0/tests/Makefile b/cros_gralloc/gralloc0/tests/Makefile
new file mode 100644
index 0000000..b81f8ec
--- /dev/null
+++ b/cros_gralloc/gralloc0/tests/Makefile
@@ -0,0 +1,30 @@
+# Copyright 2016 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+GRALLOCTEST = gralloctest
+SOURCES += gralloctest.c
+
+CCFLAGS += -g -O2 -Wall -fPIE
+LIBS    += -lhardware -lsync -lcutils -pie
+
+OBJS =  $(foreach source, $(SOURCES), $(addsuffix .o, $(basename $(source))))
+
+OBJECTS = $(addprefix $(TARGET_DIR), $(notdir $(OBJS)))
+BINARY = $(addprefix $(TARGET_DIR), $(GRALLOCTEST))
+
+.PHONY: all clean
+
+all: $(BINARY)
+
+$(BINARY): $(OBJECTS)
+
+clean:
+	$(RM) $(BINARY)
+	$(RM) $(OBJECTS)
+
+$(BINARY):
+	$(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ $(LIBS)
+
+$(TARGET_DIR)%.o: %.c
+	$(CC) $(CFLAGS) -c $^ -o $@ -MMD
diff --git a/cros_gralloc/gralloc0/tests/gralloctest.c b/cros_gralloc/gralloc0/tests/gralloctest.c
new file mode 100644
index 0000000..9fc3b88
--- /dev/null
+++ b/cros_gralloc/gralloc0/tests/gralloctest.c
@@ -0,0 +1,703 @@
+/*
+ * Copyright 2016 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/*
+ * Please run clang-format on this file after making changes:
+ *
+ * clang-format -style=file -i gralloctest.c
+ *
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <cutils/native_handle.h>
+#include <hardware/gralloc.h>
+#include <sync/sync.h>
+#include <system/graphics.h>
+
+#define ALIGN(A, B) (((A) + (B)-1) / (B) * (B))
+#define ARRAY_SIZE(A) (sizeof(A) / sizeof(*(A)))
+
+#define CHECK(cond)                                                                                \
+	do {                                                                                       \
+		if (!(cond)) {                                                                     \
+			fprintf(stderr, "[  FAILED  ] check in %s() %s:%d\n", __func__, __FILE__,  \
+				__LINE__);                                                         \
+			return 0;                                                                  \
+		}                                                                                  \
+	} while (0)
+
+#define CHECK_NO_MSG(cond)                                                                         \
+	do {                                                                                       \
+		if (!(cond)) {                                                                     \
+			return 0;                                                                  \
+		}                                                                                  \
+	} while (0)
+
+/* Private API enumeration -- see <gralloc_drm.h> */
+enum { GRALLOC_DRM_GET_STRIDE,
+       GRALLOC_DRM_GET_FORMAT,
+       GRALLOC_DRM_GET_DIMENSIONS,
+       GRALLOC_DRM_GET_BACKING_STORE,
+};
+
+struct gralloctest_context {
+	struct gralloc_module_t *module;
+	struct alloc_device_t *device;
+	int api;
+};
+
+struct gralloc_testcase {
+	const char *name;
+	int (*run_test)(struct gralloctest_context *ctx);
+	int required_api;
+};
+
+struct combinations {
+	int32_t format;
+	int32_t usage;
+};
+
+// clang-format off
+static struct combinations combos[] = {
+	{ HAL_PIXEL_FORMAT_RGBA_8888,
+	  GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
+	  GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_COMPOSER |
+	  GRALLOC_USAGE_HW_FB | GRALLOC_USAGE_CURSOR },
+	{ HAL_PIXEL_FORMAT_RGBA_8888,
+	  GRALLOC_USAGE_HW_FB | GRALLOC_USAGE_HW_RENDER |
+	  GRALLOC_USAGE_HW_COMPOSER },
+	{ HAL_PIXEL_FORMAT_RGBX_8888,
+	  GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN },
+	{ HAL_PIXEL_FORMAT_YCbCr_420_888,
+	  GRALLOC_USAGE_EXTERNAL_DISP | GRALLOC_USAGE_HW_COMPOSER |
+	  GRALLOC_USAGE_HW_TEXTURE },
+	{ HAL_PIXEL_FORMAT_YCbCr_420_888,
+	  GRALLOC_USAGE_RENDERSCRIPT | GRALLOC_USAGE_SW_READ_OFTEN |
+	  GRALLOC_USAGE_SW_WRITE_OFTEN },
+	{ HAL_PIXEL_FORMAT_YV12,
+	  GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_HW_COMPOSER |
+	  GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP },
+	{ HAL_PIXEL_FORMAT_RGB_565,
+	  GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN },
+	{ HAL_PIXEL_FORMAT_BGRA_8888,
+	  GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN },
+	{ HAL_PIXEL_FORMAT_BLOB,
+	  GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN },
+};
+// clang-format on
+
+struct grallocinfo {
+	buffer_handle_t handle;     /* handle to the buffer */
+	int w;			    /* width  of buffer */
+	int h;			    /* height of buffer */
+	int format;		    /* format of the buffer */
+	int usage;		    /* bitfield indicating usage */
+	int fence_fd;		    /* fence file descriptor */
+	void *vaddr;		    /* buffer virtual memory address */
+	int stride;		    /* stride in pixels */
+	struct android_ycbcr ycbcr; /* sw access for yuv buffers */
+};
+
+/* This function is meant to initialize the test to commonly used defaults. */
+void grallocinfo_init(struct grallocinfo *info, int w, int h, int format, int usage)
+{
+	info->w = w;
+	info->h = h;
+	info->format = format;
+	info->usage = usage;
+	info->fence_fd = -1;
+	info->vaddr = NULL;
+	info->ycbcr.y = NULL;
+	info->ycbcr.cb = NULL;
+	info->ycbcr.cr = NULL;
+	info->stride = 0;
+}
+
+static native_handle_t *duplicate_buffer_handle(buffer_handle_t handle)
+{
+	native_handle_t *hnd = native_handle_create(handle->numFds, handle->numInts);
+
+	if (hnd == NULL)
+		return NULL;
+
+	const int *old_data = handle->data;
+	int *new_data = hnd->data;
+
+	int i;
+	for (i = 0; i < handle->numFds; i++) {
+		*new_data = dup(*old_data);
+		old_data++;
+		new_data++;
+	}
+
+	memcpy(new_data, old_data, sizeof(int) * handle->numInts);
+
+	return hnd;
+}
+
+/****************************************************************
+ * Wrappers around gralloc_module_t and alloc_device_t functions.
+ * GraphicBufferMapper/GraphicBufferAllocator could replace this
+ * in theory.
+ ***************************************************************/
+
+static int allocate(struct alloc_device_t *device, struct grallocinfo *info)
+{
+	int ret;
+
+	ret = device->alloc(device, info->w, info->h, info->format, info->usage, &info->handle,
+			    &info->stride);
+
+	CHECK_NO_MSG(ret == 0);
+	CHECK_NO_MSG(info->handle->version > 0);
+	CHECK_NO_MSG(info->handle->numInts >= 0);
+	CHECK_NO_MSG(info->handle->numFds >= 0);
+	CHECK_NO_MSG(info->stride >= 0);
+
+	return 1;
+}
+
+static int deallocate(struct alloc_device_t *device, struct grallocinfo *info)
+{
+	int ret;
+	ret = device->free(device, info->handle);
+	CHECK(ret == 0);
+	return 1;
+}
+
+static int register_buffer(struct gralloc_module_t *module, struct grallocinfo *info)
+{
+	int ret;
+	ret = module->registerBuffer(module, info->handle);
+	return (ret == 0);
+}
+
+static int unregister_buffer(struct gralloc_module_t *module, struct grallocinfo *info)
+{
+	int ret;
+	ret = module->unregisterBuffer(module, info->handle);
+	return (ret == 0);
+}
+
+static int lock(struct gralloc_module_t *module, struct grallocinfo *info)
+{
+	int ret;
+
+	ret = module->lock(module, info->handle, info->usage, 0, 0, (info->w) / 2, (info->h) / 2,
+			   &info->vaddr);
+
+	return (ret == 0);
+}
+
+static int unlock(struct gralloc_module_t *module, struct grallocinfo *info)
+{
+	int ret;
+	ret = module->unlock(module, info->handle);
+	return (ret == 0);
+}
+
+static int lock_ycbcr(struct gralloc_module_t *module, struct grallocinfo *info)
+{
+	int ret;
+
+	ret = module->lock_ycbcr(module, info->handle, info->usage, 0, 0, (info->w) / 2,
+				 (info->h) / 2, &info->ycbcr);
+
+	return (ret == 0);
+}
+
+static int lock_async(struct gralloc_module_t *module, struct grallocinfo *info)
+{
+	int ret;
+
+	ret = module->lockAsync(module, info->handle, info->usage, 0, 0, (info->w) / 2,
+				(info->h) / 2, &info->vaddr, info->fence_fd);
+
+	return (ret == 0);
+}
+
+static int unlock_async(struct gralloc_module_t *module, struct grallocinfo *info)
+{
+	int ret;
+
+	ret = module->unlockAsync(module, info->handle, &info->fence_fd);
+
+	return (ret == 0);
+}
+
+static int lock_async_ycbcr(struct gralloc_module_t *module, struct grallocinfo *info)
+{
+	int ret;
+
+	ret = module->lockAsync_ycbcr(module, info->handle, info->usage, 0, 0, (info->w) / 2,
+				      (info->h) / 2, &info->ycbcr, info->fence_fd);
+
+	return (ret == 0);
+}
+
+/**************************************************************
+ * END WRAPPERS                                               *
+ **************************************************************/
+
+/* This function tests initialization of gralloc module and allocator. */
+static struct gralloctest_context *test_init_gralloc()
+{
+	int err;
+	hw_module_t const *hw_module;
+	struct gralloctest_context *ctx = calloc(1, sizeof(*ctx));
+
+	err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &hw_module);
+	if (err)
+		return NULL;
+
+	gralloc_open(hw_module, &ctx->device);
+	ctx->module = (gralloc_module_t *)hw_module;
+	if (!ctx->module || !ctx->device)
+		return NULL;
+
+	switch (ctx->module->common.module_api_version) {
+	case GRALLOC_MODULE_API_VERSION_0_3:
+		ctx->api = 3;
+		break;
+	case GRALLOC_MODULE_API_VERSION_0_2:
+		ctx->api = 2;
+		break;
+	default:
+		ctx->api = 1;
+	}
+
+	return ctx;
+}
+
+static int test_close_gralloc(struct gralloctest_context *ctx)
+{
+	CHECK(gralloc_close(ctx->device) == 0);
+	return 1;
+}
+
+/* This function tests allocation with varying buffer dimensions. */
+static int test_alloc_varying_sizes(struct gralloctest_context *ctx)
+{
+	struct grallocinfo info;
+	int i;
+
+	grallocinfo_init(&info, 0, 0, HAL_PIXEL_FORMAT_BGRA_8888, GRALLOC_USAGE_SW_READ_OFTEN);
+
+	for (i = 1; i < 1920; i++) {
+		info.w = i;
+		info.h = i;
+		CHECK(allocate(ctx->device, &info));
+		CHECK(deallocate(ctx->device, &info));
+	}
+
+	info.w = 1;
+	for (i = 1; i < 1920; i++) {
+		info.h = i;
+		CHECK(allocate(ctx->device, &info));
+		CHECK(deallocate(ctx->device, &info));
+	}
+
+	info.h = 1;
+	for (i = 1; i < 1920; i++) {
+		info.w = i;
+		CHECK(allocate(ctx->device, &info));
+		CHECK(deallocate(ctx->device, &info));
+	}
+
+	return 1;
+}
+
+/*
+ * This function tests that we find at least one working format for each
+ * combos which we consider important.
+ */
+static int test_alloc_combinations(struct gralloctest_context *ctx)
+{
+	int i;
+
+	struct grallocinfo info;
+	grallocinfo_init(&info, 512, 512, 0, 0);
+
+	for (i = 0; i < ARRAY_SIZE(combos); i++) {
+		info.format = combos[i].format;
+		info.usage = combos[i].usage;
+		CHECK(allocate(ctx->device, &info));
+		CHECK(deallocate(ctx->device, &info));
+	}
+
+	return 1;
+}
+
+/*
+ * This function tests the advertised API version.
+ * Version_0_2 added (*lock_ycbcr)() method.
+ * Version_0_3 added fence passing to/from lock/unlock.
+ */
+static int test_api(struct gralloctest_context *ctx)
+{
+
+	CHECK(ctx->module->registerBuffer);
+	CHECK(ctx->module->unregisterBuffer);
+	CHECK(ctx->module->lock);
+	CHECK(ctx->module->unlock);
+
+	switch (ctx->module->common.module_api_version) {
+	case GRALLOC_MODULE_API_VERSION_0_3:
+		CHECK(ctx->module->lock_ycbcr);
+		CHECK(ctx->module->lockAsync);
+		CHECK(ctx->module->unlockAsync);
+		CHECK(ctx->module->lockAsync_ycbcr);
+		break;
+	case GRALLOC_MODULE_API_VERSION_0_2:
+		CHECK(ctx->module->lock_ycbcr);
+		CHECK(ctx->module->lockAsync == NULL);
+		CHECK(ctx->module->unlockAsync == NULL);
+		CHECK(ctx->module->lockAsync_ycbcr == NULL);
+		break;
+	case GRALLOC_MODULE_API_VERSION_0_1:
+		CHECK(ctx->module->lockAsync == NULL);
+		CHECK(ctx->module->unlockAsync == NULL);
+		CHECK(ctx->module->lockAsync_ycbcr == NULL);
+		CHECK(ctx->module->lock_ycbcr == NULL);
+		break;
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+/*
+ * This function registers, unregisters, locks and unlocks the buffer in
+ * various orders.
+ */
+static int test_gralloc_order(struct gralloctest_context *ctx)
+{
+	struct grallocinfo info, duplicate;
+
+	grallocinfo_init(&info, 512, 512, HAL_PIXEL_FORMAT_BGRA_8888, GRALLOC_USAGE_SW_READ_OFTEN);
+
+	grallocinfo_init(&duplicate, 512, 512, HAL_PIXEL_FORMAT_BGRA_8888,
+			 GRALLOC_USAGE_SW_READ_OFTEN);
+
+	CHECK(allocate(ctx->device, &info));
+
+	/*
+	 * Duplicate the buffer handle to simulate an additional reference
+	 * in same process.
+	 */
+	native_handle_t *native_handle = duplicate_buffer_handle(info.handle);
+	duplicate.handle = native_handle;
+
+	CHECK(unregister_buffer(ctx->module, &duplicate) == 0);
+	CHECK(register_buffer(ctx->module, &duplicate));
+
+	CHECK(unlock(ctx->module, &duplicate) == 0);
+
+	CHECK(lock(ctx->module, &duplicate));
+	CHECK(duplicate.vaddr);
+	CHECK(unlock(ctx->module, &duplicate));
+
+	CHECK(unregister_buffer(ctx->module, &duplicate));
+
+	CHECK(register_buffer(ctx->module, &duplicate));
+	CHECK(unregister_buffer(ctx->module, &duplicate));
+	CHECK(unregister_buffer(ctx->module, &duplicate) == 0);
+
+	CHECK(register_buffer(ctx->module, &duplicate));
+	CHECK(deallocate(ctx->device, &info));
+
+	CHECK(lock(ctx->module, &duplicate));
+	CHECK(lock(ctx->module, &duplicate));
+	CHECK(unlock(ctx->module, &duplicate));
+	CHECK(unlock(ctx->module, &duplicate));
+	CHECK(unlock(ctx->module, &duplicate) == 0);
+	CHECK(unregister_buffer(ctx->module, &duplicate));
+
+	CHECK(native_handle_close(duplicate.handle) == 0);
+	CHECK(native_handle_delete(native_handle) == 0);
+
+	return 1;
+}
+
+/* This function tests CPU reads and writes. */
+static int test_mapping(struct gralloctest_context *ctx)
+{
+	struct grallocinfo info;
+	uint32_t *ptr = NULL;
+	uint32_t magic_number = 0x000ABBA;
+
+	grallocinfo_init(&info, 512, 512, HAL_PIXEL_FORMAT_BGRA_8888,
+			 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
+
+	CHECK(allocate(ctx->device, &info));
+	CHECK(lock(ctx->module, &info));
+
+	ptr = (uint32_t *)info.vaddr;
+	CHECK(ptr);
+	ptr[(info.w) / 2] = magic_number;
+
+	CHECK(unlock(ctx->module, &info));
+	info.vaddr = NULL;
+	ptr = NULL;
+
+	CHECK(lock(ctx->module, &info));
+	ptr = (uint32_t *)info.vaddr;
+	CHECK(ptr);
+	CHECK(ptr[info.w / 2] == magic_number);
+
+	CHECK(unlock(ctx->module, &info));
+	CHECK(deallocate(ctx->device, &info));
+
+	return 1;
+}
+
+/* This function tests the private API we use in ARC++ -- not part of official
+ * gralloc. */
+static int test_perform(struct gralloctest_context *ctx)
+{
+	int32_t format;
+	uint64_t id1, id2;
+	uint32_t stride, width, height;
+	struct grallocinfo info, duplicate;
+	struct gralloc_module_t *mod = ctx->module;
+
+	grallocinfo_init(&info, 650, 408, HAL_PIXEL_FORMAT_BGRA_8888, GRALLOC_USAGE_SW_READ_OFTEN);
+
+	CHECK(allocate(ctx->device, &info));
+
+	CHECK(mod->perform(mod, GRALLOC_DRM_GET_STRIDE, info.handle, &stride) == 0);
+	CHECK(stride == info.stride);
+
+	CHECK(mod->perform(mod, GRALLOC_DRM_GET_FORMAT, info.handle, &format) == 0);
+	CHECK(format == info.format);
+
+	CHECK(mod->perform(mod, GRALLOC_DRM_GET_DIMENSIONS, info.handle, &width, &height) == 0);
+	CHECK(width == info.w);
+	CHECK(height == info.h);
+
+	native_handle_t *native_handle = duplicate_buffer_handle(info.handle);
+	duplicate.handle = native_handle;
+
+	CHECK(mod->perform(mod, GRALLOC_DRM_GET_BACKING_STORE, duplicate.handle, &id2));
+	CHECK(register_buffer(mod, &duplicate));
+
+	CHECK(mod->perform(mod, GRALLOC_DRM_GET_BACKING_STORE, info.handle, &id1) == 0);
+	CHECK(mod->perform(mod, GRALLOC_DRM_GET_BACKING_STORE, duplicate.handle, &id2) == 0);
+	CHECK(id1 == id2);
+
+	CHECK(unregister_buffer(mod, &duplicate));
+	CHECK(deallocate(ctx->device, &info));
+
+	return 1;
+}
+
+/* This function tests that only YUV buffers work with *lock_ycbcr. */
+static int test_ycbcr(struct gralloctest_context *ctx)
+
+{
+	struct grallocinfo info;
+	grallocinfo_init(&info, 512, 512, HAL_PIXEL_FORMAT_YCbCr_420_888,
+			 GRALLOC_USAGE_SW_READ_OFTEN);
+
+	CHECK(allocate(ctx->device, &info));
+
+	CHECK(lock(ctx->module, &info) == 0);
+	CHECK(lock_ycbcr(ctx->module, &info));
+	CHECK(info.ycbcr.y);
+	CHECK(info.ycbcr.cb);
+	CHECK(info.ycbcr.cr);
+	CHECK(unlock(ctx->module, &info));
+
+	CHECK(deallocate(ctx->device, &info));
+
+	info.format = HAL_PIXEL_FORMAT_BGRA_8888;
+	CHECK(allocate(ctx->device, &info));
+
+	CHECK(lock_ycbcr(ctx->module, &info) == 0);
+	CHECK(lock(ctx->module, &info));
+	CHECK(unlock(ctx->module, &info));
+
+	CHECK(deallocate(ctx->device, &info));
+
+	return 1;
+}
+
+/*
+ * This function tests a method ARC++ uses to query YUV buffer
+ * info -- not part of official gralloc API.  This is used in
+ * Mali, Mesa, the ArcCodec and  wayland_service.
+ */
+static int test_yuv_info(struct gralloctest_context *ctx)
+{
+	struct grallocinfo info;
+	uintptr_t y_size, c_stride, c_size, cr_offset, cb_offset;
+	uint32_t width, height;
+	width = height = 512;
+
+	/* <system/graphics.h> defines YV12 as having:
+	 * - an even width
+	 * - an even height
+	 * - a horizontal stride multiple of 16 pixels
+	 * - a vertical stride equal to the height
+	 *
+	 *   y_size = stride * height.
+	 *   c_stride = ALIGN(stride/2, 16).
+	 *   c_size = c_stride * height/2.
+	 *   size = y_size + c_size * 2.
+	 *   cr_offset = y_size.
+	 *   cb_offset = y_size + c_size.
+	 */
+
+	grallocinfo_init(&info, width, height, HAL_PIXEL_FORMAT_YV12, GRALLOC_USAGE_SW_READ_OFTEN);
+
+	CHECK(allocate(ctx->device, &info));
+
+	y_size = info.stride * height;
+	c_stride = ALIGN(info.stride / 2, 16);
+	c_size = c_stride * height / 2;
+	cr_offset = y_size;
+	cb_offset = y_size + c_size;
+
+	info.usage = 0;
+
+	/*
+	 * Check if the (*lock_ycbcr) with usage of zero returns the
+	 * offsets and strides of the YV12 buffer. This is unofficial
+	 * behavior we are testing here.
+	 */
+	CHECK(lock_ycbcr(ctx->module, &info));
+
+	CHECK(info.stride == info.ycbcr.ystride);
+	CHECK(c_stride == info.ycbcr.cstride);
+	CHECK(cr_offset == (uintptr_t)info.ycbcr.cr);
+	CHECK(cb_offset == (uintptr_t)info.ycbcr.cb);
+
+	CHECK(unlock(ctx->module, &info));
+
+	CHECK(deallocate(ctx->device, &info));
+
+	return 1;
+}
+
+/* This function tests asynchronous locking and unlocking of buffers. */
+static int test_async(struct gralloctest_context *ctx)
+
+{
+	struct grallocinfo rgba_info, ycbcr_info;
+	grallocinfo_init(&rgba_info, 512, 512, HAL_PIXEL_FORMAT_BGRA_8888,
+			 GRALLOC_USAGE_SW_READ_OFTEN);
+	grallocinfo_init(&ycbcr_info, 512, 512, HAL_PIXEL_FORMAT_YCbCr_420_888,
+			 GRALLOC_USAGE_SW_READ_OFTEN);
+
+	CHECK(allocate(ctx->device, &rgba_info));
+	CHECK(allocate(ctx->device, &ycbcr_info));
+
+	CHECK(lock_async(ctx->module, &rgba_info));
+	CHECK(lock_async_ycbcr(ctx->module, &ycbcr_info));
+
+	CHECK(rgba_info.vaddr);
+	CHECK(ycbcr_info.ycbcr.y);
+	CHECK(ycbcr_info.ycbcr.cb);
+	CHECK(ycbcr_info.ycbcr.cr);
+
+	/*
+	 * Wait on the fence returned from unlock_async and check it doesn't
+	 * return an error.
+	 */
+	CHECK(unlock_async(ctx->module, &rgba_info));
+	CHECK(unlock_async(ctx->module, &ycbcr_info));
+
+	if (rgba_info.fence_fd >= 0) {
+		CHECK(sync_wait(rgba_info.fence_fd, 10000) >= 0);
+		CHECK(close(rgba_info.fence_fd) == 0);
+	}
+
+	if (ycbcr_info.fence_fd >= 0) {
+		CHECK(sync_wait(ycbcr_info.fence_fd, 10000) >= 0);
+		CHECK(close(ycbcr_info.fence_fd) == 0);
+	}
+
+	CHECK(deallocate(ctx->device, &rgba_info));
+	CHECK(deallocate(ctx->device, &ycbcr_info));
+
+	return 1;
+}
+
+static const struct gralloc_testcase tests[] = {
+	{ "alloc_varying_sizes", test_alloc_varying_sizes, 1 },
+	{ "alloc_combinations", test_alloc_combinations, 1 },
+	{ "api", test_api, 1 },
+	{ "gralloc_order", test_gralloc_order, 1 },
+	{ "mapping", test_mapping, 1 },
+	{ "perform", test_perform, 1 },
+	{ "ycbcr", test_ycbcr, 2 },
+	{ "yuv_info", test_yuv_info, 2 },
+	{ "async", test_async, 3 },
+};
+
+static void print_help(const char *argv0)
+{
+	uint32_t i;
+	printf("usage: %s <test_name>\n\n", argv0);
+	printf("A valid name test is one the following:\n");
+	for (i = 0; i < ARRAY_SIZE(tests); i++)
+		printf("%s\n", tests[i].name);
+}
+
+int main(int argc, char *argv[])
+{
+	int ret = 0;
+	uint32_t num_run = 0;
+
+	setbuf(stdout, NULL);
+	if (argc == 2) {
+		uint32_t i;
+		char *name = argv[1];
+
+		struct gralloctest_context *ctx = test_init_gralloc();
+		if (!ctx) {
+			fprintf(stderr, "[  FAILED  ] to initialize gralloc.\n");
+			return 1;
+		}
+
+		for (i = 0; i < ARRAY_SIZE(tests); i++) {
+			if (strcmp(tests[i].name, name) && strcmp("all", name))
+				continue;
+
+			int success = 1;
+			if (ctx->api >= tests[i].required_api)
+				success = tests[i].run_test(ctx);
+
+			printf("[ RUN      ] gralloctest.%s\n", tests[i].name);
+			if (!success) {
+				fprintf(stderr, "[  FAILED  ] gralloctest.%s\n", tests[i].name);
+				ret |= 1;
+			} else {
+				printf("[  PASSED  ] gralloctest.%s\n", tests[i].name);
+			}
+
+			num_run++;
+		}
+
+		if (!test_close_gralloc(ctx)) {
+			fprintf(stderr, "[  FAILED  ] to close gralloc.\n");
+			return 1;
+		}
+
+		if (!num_run)
+			goto print_usage;
+
+		return ret;
+	}
+
+print_usage:
+	print_help(argv[0]);
+	return 0;
+}