C++程序  |  706行  |  18.78 KB

/*
 * 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 <string.h>
#include <unistd.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;
}