1053 lines
25 KiB
C
1053 lines
25 KiB
C
/*
|
|
* Copyright 2014 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.
|
|
*/
|
|
|
|
#define _GNU_SOURCE
|
|
#include <assert.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <linux/dma-buf.h>
|
|
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#include <xf86drm.h>
|
|
#include <xf86drmMode.h>
|
|
|
|
#include <gbm.h>
|
|
|
|
#define CHECK(cond) do {\
|
|
if (!(cond)) {\
|
|
printf("CHECK failed in %s() %s:%d\n", __func__, __FILE__, __LINE__);\
|
|
return 0;\
|
|
}\
|
|
} while(0)
|
|
|
|
#define HANDLE_EINTR(x) \
|
|
({ \
|
|
int eintr_wrapper_counter = 0; \
|
|
int eintr_wrapper_result; \
|
|
do { \
|
|
eintr_wrapper_result = (x); \
|
|
} while (eintr_wrapper_result == -1 && errno == EINTR && \
|
|
eintr_wrapper_counter++ < 100); \
|
|
eintr_wrapper_result; \
|
|
})
|
|
|
|
#define ARRAY_SIZE(A) (sizeof(A)/sizeof(*(A)))
|
|
|
|
#define ENODRM -1
|
|
|
|
static int fd;
|
|
static struct gbm_device *gbm;
|
|
|
|
static const uint32_t format_list[] = {
|
|
GBM_FORMAT_C8,
|
|
GBM_FORMAT_RGB332,
|
|
GBM_FORMAT_BGR233,
|
|
GBM_FORMAT_XRGB4444,
|
|
GBM_FORMAT_XBGR4444,
|
|
GBM_FORMAT_RGBX4444,
|
|
GBM_FORMAT_BGRX4444,
|
|
GBM_FORMAT_ARGB4444,
|
|
GBM_FORMAT_ABGR4444,
|
|
GBM_FORMAT_RGBA4444,
|
|
GBM_FORMAT_BGRA4444,
|
|
GBM_FORMAT_XRGB1555,
|
|
GBM_FORMAT_XBGR1555,
|
|
GBM_FORMAT_RGBX5551,
|
|
GBM_FORMAT_BGRX5551,
|
|
GBM_FORMAT_ARGB1555,
|
|
GBM_FORMAT_ABGR1555,
|
|
GBM_FORMAT_RGBA5551,
|
|
GBM_FORMAT_BGRA5551,
|
|
GBM_FORMAT_RGB565,
|
|
GBM_FORMAT_BGR565,
|
|
GBM_FORMAT_RGB888,
|
|
GBM_FORMAT_BGR888,
|
|
GBM_FORMAT_XRGB8888,
|
|
GBM_FORMAT_XBGR8888,
|
|
GBM_FORMAT_RGBX8888,
|
|
GBM_FORMAT_BGRX8888,
|
|
GBM_FORMAT_ARGB8888,
|
|
GBM_FORMAT_ABGR8888,
|
|
GBM_FORMAT_RGBA8888,
|
|
GBM_FORMAT_BGRA8888,
|
|
GBM_FORMAT_XRGB2101010,
|
|
GBM_FORMAT_XBGR2101010,
|
|
GBM_FORMAT_RGBX1010102,
|
|
GBM_FORMAT_BGRX1010102,
|
|
GBM_FORMAT_ARGB2101010,
|
|
GBM_FORMAT_ABGR2101010,
|
|
GBM_FORMAT_RGBA1010102,
|
|
GBM_FORMAT_BGRA1010102,
|
|
GBM_FORMAT_YUYV,
|
|
GBM_FORMAT_YVYU,
|
|
GBM_FORMAT_UYVY,
|
|
GBM_FORMAT_VYUY,
|
|
GBM_FORMAT_AYUV,
|
|
GBM_FORMAT_NV12,
|
|
GBM_FORMAT_YVU420,
|
|
};
|
|
|
|
struct plane_info {
|
|
uint32_t bits_per_pixel;
|
|
uint32_t subsample_rate;
|
|
uint32_t data_mask;
|
|
};
|
|
|
|
#define MAX_PLANES 3
|
|
struct format_info {
|
|
uint32_t pixel_format;
|
|
int num_planes;
|
|
struct plane_info planes[MAX_PLANES];
|
|
};
|
|
|
|
/* Bits per pixel for each. */
|
|
static const struct format_info format_info_list[] = {
|
|
{GBM_FORMAT_C8, 1, {{8, 1, 0xFF}}},
|
|
{GBM_FORMAT_RGB332, 1, {{8, 1, 0xFF}}},
|
|
{GBM_FORMAT_BGR233, 1, {{8, 1, 0xFF}}},
|
|
{GBM_FORMAT_XRGB4444, 1, {{16, 1, 0x0FFF}}},
|
|
{GBM_FORMAT_XBGR4444, 1, {{16, 1, 0x0FFF}}},
|
|
{GBM_FORMAT_RGBX4444, 1, {{16, 1, 0xFFF0}}},
|
|
{GBM_FORMAT_BGRX4444, 1, {{16, 1, 0xFFF0}}},
|
|
{GBM_FORMAT_ARGB4444, 1, {{16, 1, 0xFFFF}}},
|
|
{GBM_FORMAT_ABGR4444, 1, {{16, 1, 0xFFFF}}},
|
|
{GBM_FORMAT_RGBA4444, 1, {{16, 1, 0xFFFF}}},
|
|
{GBM_FORMAT_BGRA4444, 1, {{16, 1, 0xFFFF}}},
|
|
{GBM_FORMAT_XRGB1555, 1, {{16, 1, 0x7FFF}}},
|
|
{GBM_FORMAT_XBGR1555, 1, {{16, 1, 0x7FFF}}},
|
|
{GBM_FORMAT_RGBX5551, 1, {{16, 1, 0xFFFE}}},
|
|
{GBM_FORMAT_BGRX5551, 1, {{16, 1, 0xFFFE}}},
|
|
{GBM_FORMAT_ARGB1555, 1, {{16, 1, 0xFFFF}}},
|
|
{GBM_FORMAT_ABGR1555, 1, {{16, 1, 0xFFFF}}},
|
|
{GBM_FORMAT_RGBA5551, 1, {{16, 1, 0xFFFF}}},
|
|
{GBM_FORMAT_BGRA5551, 1, {{16, 1, 0xFFFF}}},
|
|
{GBM_FORMAT_RGB565, 1, {{16, 1, 0xFFFF}}},
|
|
{GBM_FORMAT_BGR565, 1, {{16, 1, 0xFFFF}}},
|
|
{GBM_FORMAT_RGB888, 1, {{24, 1, 0xFFFFFF}}},
|
|
{GBM_FORMAT_BGR888, 1, {{24, 1, 0xFFFFFF}}},
|
|
{GBM_FORMAT_XRGB8888, 1, {{32, 1, 0x00FFFFFF}}},
|
|
{GBM_FORMAT_XBGR8888, 1, {{32, 1, 0x00FFFFFF}}},
|
|
{GBM_FORMAT_RGBX8888, 1, {{32, 1, 0xFFFFFF00}}},
|
|
{GBM_FORMAT_BGRX8888, 1, {{32, 1, 0xFFFFFF00}}},
|
|
{GBM_FORMAT_ARGB8888, 1, {{32, 1, 0xFFFFFFFF}}},
|
|
{GBM_FORMAT_ABGR8888, 1, {{32, 1, 0xFFFFFFFF}}},
|
|
{GBM_FORMAT_RGBA8888, 1, {{32, 1, 0xFFFFFFFF}}},
|
|
{GBM_FORMAT_BGRA8888, 1, {{32, 1, 0xFFFFFFFF}}},
|
|
{GBM_FORMAT_XRGB2101010, 1, {{32, 1, 0x3FFFFFFF}}},
|
|
{GBM_FORMAT_XBGR2101010, 1, {{32, 1, 0x3FFFFFFF}}},
|
|
{GBM_FORMAT_RGBX1010102, 1, {{32, 1, 0xFFFFFFFC}}},
|
|
{GBM_FORMAT_BGRX1010102, 1, {{32, 1, 0xFFFFFFFC}}},
|
|
{GBM_FORMAT_ARGB2101010, 1, {{32, 1, 0xFFFFFFFF}}},
|
|
{GBM_FORMAT_ABGR2101010, 1, {{32, 1, 0xFFFFFFFF}}},
|
|
{GBM_FORMAT_RGBA1010102, 1, {{32, 1, 0xFFFFFFFF}}},
|
|
{GBM_FORMAT_BGRA1010102, 1, {{32, 1, 0xFFFFFFFF}}},
|
|
{GBM_FORMAT_YUYV, 1, {{16, 1, 0xFFFF}}},
|
|
{GBM_FORMAT_YVYU, 1, {{16, 1, 0xFFFF}}},
|
|
{GBM_FORMAT_UYVY, 1, {{16, 1, 0xFFFF}}},
|
|
{GBM_FORMAT_VYUY, 1, {{16, 1, 0xFFFF}}},
|
|
{GBM_FORMAT_AYUV, 1, {{32, 1, 0xFFFFFFFF}}},
|
|
{GBM_FORMAT_NV12, 2, {{8, 1, 0xFF}, {16, 2, 0xFFFF}}},
|
|
{GBM_FORMAT_YVU420, 3, {{8, 1, 0xFF}, {8, 2, 0xFF}, {8,2, 0xFF}}},
|
|
};
|
|
|
|
static const uint32_t usage_list[] = {
|
|
GBM_BO_USE_SCANOUT,
|
|
GBM_BO_USE_CURSOR_64X64,
|
|
GBM_BO_USE_RENDERING,
|
|
GBM_BO_USE_LINEAR,
|
|
GBM_BO_USE_SW_READ_OFTEN,
|
|
GBM_BO_USE_SW_READ_RARELY,
|
|
GBM_BO_USE_SW_WRITE_OFTEN,
|
|
GBM_BO_USE_SW_WRITE_RARELY,
|
|
};
|
|
|
|
static const uint32_t buffer_list[] = {
|
|
GBM_BO_USE_SCANOUT | GBM_BO_USE_SW_READ_RARELY | GBM_BO_USE_SW_WRITE_RARELY,
|
|
GBM_BO_USE_RENDERING | GBM_BO_USE_SW_READ_RARELY | GBM_BO_USE_SW_WRITE_RARELY,
|
|
GBM_BO_USE_SW_READ_RARELY | GBM_BO_USE_SW_WRITE_RARELY,
|
|
GBM_BO_USE_SW_READ_RARELY | GBM_BO_USE_SW_WRITE_RARELY | GBM_BO_USE_TEXTURING,
|
|
GBM_BO_USE_SW_READ_RARELY | GBM_BO_USE_SW_WRITE_RARELY | GBM_BO_USE_TEXTURING,
|
|
|
|
GBM_BO_USE_RENDERING | GBM_BO_USE_SW_READ_RARELY | GBM_BO_USE_SW_WRITE_RARELY |
|
|
GBM_BO_USE_TEXTURING,
|
|
|
|
GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT | GBM_BO_USE_SW_READ_RARELY |
|
|
GBM_BO_USE_SW_WRITE_RARELY,
|
|
|
|
GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT | GBM_BO_USE_SW_READ_RARELY |
|
|
GBM_BO_USE_SW_WRITE_RARELY | GBM_BO_USE_TEXTURING,
|
|
};
|
|
|
|
static int check_bo(struct gbm_bo *bo)
|
|
{
|
|
uint32_t format;
|
|
size_t num_planes, plane;
|
|
int fd;
|
|
int i;
|
|
|
|
CHECK(bo);
|
|
CHECK(gbm_bo_get_width(bo) >= 0);
|
|
CHECK(gbm_bo_get_height(bo) >= 0);
|
|
CHECK(gbm_bo_get_stride(bo) >= gbm_bo_get_width(bo));
|
|
|
|
format = gbm_bo_get_format(bo);
|
|
for (i = 0; i < ARRAY_SIZE(format_list); i++)
|
|
if (format_list[i] == format)
|
|
break;
|
|
CHECK(i < ARRAY_SIZE(format_list));
|
|
|
|
num_planes = gbm_bo_get_plane_count(bo);
|
|
if (format == GBM_FORMAT_NV12)
|
|
CHECK(num_planes == 2);
|
|
else if (format == GBM_FORMAT_YVU420)
|
|
CHECK(num_planes == 3);
|
|
else
|
|
CHECK(num_planes == 1);
|
|
|
|
CHECK(gbm_bo_get_handle_for_plane(bo, 0).u32 == gbm_bo_get_handle(bo).u32);
|
|
|
|
CHECK(gbm_bo_get_offset(bo, 0) == 0);
|
|
CHECK(gbm_bo_get_plane_size(bo, 0) >=
|
|
gbm_bo_get_width(bo) * gbm_bo_get_height(bo));
|
|
CHECK(gbm_bo_get_stride_for_plane(bo, 0) == gbm_bo_get_stride(bo));
|
|
|
|
for (plane = 0; plane < num_planes; plane++) {
|
|
CHECK(gbm_bo_get_handle_for_plane(bo, plane).u32);
|
|
|
|
fd = gbm_bo_get_plane_fd(bo, plane);
|
|
CHECK(fd > 0);
|
|
close(fd);
|
|
|
|
gbm_bo_get_offset(bo, plane);
|
|
CHECK(gbm_bo_get_plane_size(bo, plane));
|
|
CHECK(gbm_bo_get_stride_for_plane(bo, plane));
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static drmModeConnector *find_first_connected_connector(int fd,
|
|
drmModeRes *resources)
|
|
{
|
|
int i;
|
|
for (i = 0; i < resources->count_connectors; i++) {
|
|
drmModeConnector *connector;
|
|
|
|
connector = drmModeGetConnector(fd, resources->connectors[i]);
|
|
if (connector) {
|
|
if ((connector->count_modes > 0) &&
|
|
(connector->connection == DRM_MODE_CONNECTED))
|
|
return connector;
|
|
|
|
drmModeFreeConnector(connector);
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static int drm_open()
|
|
{
|
|
int fd;
|
|
unsigned i;
|
|
|
|
/* Find the first drm device with a connected display. */
|
|
for (i = 0; i < DRM_MAX_MINOR; i++) {
|
|
char* dev_name;
|
|
drmModeRes *res = NULL;
|
|
int ret;
|
|
|
|
ret = asprintf(&dev_name, DRM_DEV_NAME, DRM_DIR_NAME, i);
|
|
if (ret < 0)
|
|
continue;
|
|
|
|
fd = open(dev_name, O_RDWR, 0);
|
|
free(dev_name);
|
|
if (fd < 0)
|
|
continue;
|
|
|
|
res = drmModeGetResources(fd);
|
|
if (!res) {
|
|
drmClose(fd);
|
|
continue;
|
|
}
|
|
|
|
if (res->count_crtcs > 0 && res->count_connectors > 0) {
|
|
if (find_first_connected_connector(fd, res)) {
|
|
drmModeFreeResources(res);
|
|
return fd;
|
|
}
|
|
}
|
|
|
|
drmClose(fd);
|
|
drmModeFreeResources(res);
|
|
}
|
|
|
|
/*
|
|
* If no drm device has a connected display, fall back to the first
|
|
* drm device.
|
|
*/
|
|
for (i = 0; i < DRM_MAX_MINOR; i++) {
|
|
char* dev_name;
|
|
int ret;
|
|
|
|
ret = asprintf(&dev_name, DRM_DEV_NAME, DRM_DIR_NAME, i);
|
|
if (ret < 0)
|
|
continue;
|
|
|
|
fd = open(dev_name, O_RDWR, 0);
|
|
free(dev_name);
|
|
if (fd < 0)
|
|
continue;
|
|
|
|
return fd;
|
|
}
|
|
|
|
return ENODRM;
|
|
}
|
|
|
|
static int drm_open_vgem()
|
|
{
|
|
const char g_sys_card_path_format[] =
|
|
"/sys/bus/platform/devices/vgem/drm/card%d";
|
|
const char g_dev_card_path_format[] =
|
|
"/dev/dri/card%d";
|
|
char *name;
|
|
int i, fd;
|
|
|
|
for (i = 0; i < 16; i++) {
|
|
struct stat _stat;
|
|
int ret;
|
|
ret = asprintf(&name, g_sys_card_path_format, i);
|
|
assert(ret != -1);
|
|
|
|
if (stat(name, &_stat) == -1) {
|
|
free(name);
|
|
continue;
|
|
}
|
|
|
|
free(name);
|
|
ret = asprintf(&name, g_dev_card_path_format, i);
|
|
assert(ret != -1);
|
|
|
|
fd = open(name, O_RDWR);
|
|
free(name);
|
|
if (fd == -1) {
|
|
return -1;
|
|
}
|
|
return fd;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static int create_vgem_bo(int fd, size_t size, uint32_t * handle)
|
|
{
|
|
struct drm_mode_create_dumb create;
|
|
int ret;
|
|
|
|
memset(&create, 0, sizeof(create));
|
|
create.height = size;
|
|
create.width = 1;
|
|
create.bpp = 8;
|
|
|
|
ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create);
|
|
if (ret)
|
|
return ret;
|
|
|
|
assert(create.size >= size);
|
|
|
|
*handle = create.handle;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Tests initialization.
|
|
*/
|
|
static int test_init()
|
|
{
|
|
fd = drm_open();
|
|
|
|
CHECK(fd >= 0);
|
|
|
|
gbm = gbm_create_device(fd);
|
|
|
|
CHECK(gbm_device_get_fd(gbm) == fd);
|
|
|
|
const char* backend_name = gbm_device_get_backend_name(gbm);
|
|
|
|
CHECK(backend_name);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Tests reinitialization.
|
|
*/
|
|
static int test_reinit()
|
|
{
|
|
gbm_device_destroy(gbm);
|
|
close(fd);
|
|
|
|
fd = drm_open();
|
|
CHECK(fd >= 0);
|
|
|
|
gbm = gbm_create_device(fd);
|
|
|
|
CHECK(gbm_device_get_fd(gbm) == fd);
|
|
|
|
struct gbm_bo *bo;
|
|
bo = gbm_bo_create(gbm, 1024, 1024, GBM_FORMAT_XRGB8888, GBM_BO_USE_RENDERING);
|
|
CHECK(check_bo(bo));
|
|
gbm_bo_destroy(bo);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Tests repeated alloc/free.
|
|
*/
|
|
static int test_alloc_free()
|
|
{
|
|
int i;
|
|
for(i = 0; i < 1000; i++) {
|
|
struct gbm_bo *bo;
|
|
bo = gbm_bo_create(gbm, 1024, 1024, GBM_FORMAT_XRGB8888, GBM_BO_USE_RENDERING);
|
|
CHECK(check_bo(bo));
|
|
gbm_bo_destroy(bo);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Tests that we can allocate different buffer dimensions.
|
|
*/
|
|
static int test_alloc_free_sizes()
|
|
{
|
|
int i;
|
|
for(i = 1; i < 1920; i++) {
|
|
struct gbm_bo *bo;
|
|
bo = gbm_bo_create(gbm, i, i, GBM_FORMAT_XRGB8888, GBM_BO_USE_RENDERING);
|
|
CHECK(check_bo(bo));
|
|
gbm_bo_destroy(bo);
|
|
}
|
|
|
|
for(i = 1; i < 1920; i++) {
|
|
struct gbm_bo *bo;
|
|
bo = gbm_bo_create(gbm, i, 1, GBM_FORMAT_XRGB8888, GBM_BO_USE_RENDERING);
|
|
CHECK(check_bo(bo));
|
|
gbm_bo_destroy(bo);
|
|
}
|
|
|
|
for(i = 1; i < 1920; i++) {
|
|
struct gbm_bo *bo;
|
|
bo = gbm_bo_create(gbm, 1, i, GBM_FORMAT_XRGB8888, GBM_BO_USE_RENDERING);
|
|
CHECK(check_bo(bo));
|
|
gbm_bo_destroy(bo);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Tests that we can allocate different buffer formats.
|
|
*/
|
|
static int test_alloc_free_formats()
|
|
{
|
|
int i;
|
|
|
|
for(i = 0; i < ARRAY_SIZE(format_list); i++) {
|
|
uint32_t format = format_list[i];
|
|
if (gbm_device_is_format_supported(gbm, format, GBM_BO_USE_RENDERING)) {
|
|
struct gbm_bo *bo;
|
|
bo = gbm_bo_create(gbm, 1024, 1024, format, GBM_BO_USE_RENDERING);
|
|
CHECK(check_bo(bo));
|
|
gbm_bo_destroy(bo);
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Tests that we find at least one working format for each usage.
|
|
*/
|
|
static int test_alloc_free_usage()
|
|
{
|
|
int i, j;
|
|
|
|
for(i = 0; i < ARRAY_SIZE(usage_list); i++) {
|
|
uint32_t usage = usage_list[i];
|
|
int found = 0;
|
|
for(j = 0; j < ARRAY_SIZE(format_list); j++) {
|
|
uint32_t format = format_list[j];
|
|
if (gbm_device_is_format_supported(gbm, format, usage)) {
|
|
struct gbm_bo *bo;
|
|
if (usage == GBM_BO_USE_CURSOR_64X64)
|
|
bo = gbm_bo_create(gbm, 64, 64, format, usage);
|
|
else
|
|
bo = gbm_bo_create(gbm, 1024, 1024, format, usage);
|
|
CHECK(check_bo(bo));
|
|
found = 1;
|
|
gbm_bo_destroy(bo);
|
|
}
|
|
}
|
|
CHECK(found);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Tests user data.
|
|
*/
|
|
static int been_there1;
|
|
static int been_there2;
|
|
|
|
void destroy_data1(struct gbm_bo *bo, void *data)
|
|
{
|
|
been_there1 = 1;
|
|
}
|
|
|
|
void destroy_data2(struct gbm_bo *bo, void *data)
|
|
{
|
|
been_there2 = 1;
|
|
}
|
|
|
|
static int test_user_data()
|
|
{
|
|
struct gbm_bo *bo1, *bo2;
|
|
char *data1, *data2;
|
|
|
|
been_there1 = 0;
|
|
been_there2 = 0;
|
|
|
|
bo1 = gbm_bo_create(gbm, 1024, 1024, GBM_FORMAT_XRGB8888, GBM_BO_USE_RENDERING);
|
|
bo2 = gbm_bo_create(gbm, 1024, 1024, GBM_FORMAT_XRGB8888, GBM_BO_USE_RENDERING);
|
|
data1 = (char*)malloc(1);
|
|
data2 = (char*)malloc(1);
|
|
CHECK(data1);
|
|
CHECK(data2);
|
|
|
|
gbm_bo_set_user_data(bo1, data1, destroy_data1);
|
|
gbm_bo_set_user_data(bo2, data2, destroy_data2);
|
|
|
|
CHECK((char*)gbm_bo_get_user_data(bo1) == data1);
|
|
CHECK((char*)gbm_bo_get_user_data(bo2) == data2);
|
|
|
|
gbm_bo_destroy(bo1);
|
|
CHECK(been_there1 == 1);
|
|
|
|
gbm_bo_set_user_data(bo2, NULL, NULL);
|
|
gbm_bo_destroy(bo2);
|
|
CHECK(been_there2 == 0);
|
|
|
|
free(data1);
|
|
free(data2);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Tests destruction.
|
|
*/
|
|
static int test_destroy()
|
|
{
|
|
gbm_device_destroy(gbm);
|
|
close(fd);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Tests prime export.
|
|
*/
|
|
static int test_export()
|
|
{
|
|
struct gbm_bo *bo;
|
|
int prime_fd;
|
|
|
|
bo = gbm_bo_create(gbm, 1024, 1024, GBM_FORMAT_XRGB8888, GBM_BO_USE_RENDERING);
|
|
CHECK(check_bo(bo));
|
|
|
|
prime_fd = gbm_bo_get_fd(bo);
|
|
CHECK(prime_fd > 0);
|
|
close(prime_fd);
|
|
|
|
gbm_bo_destroy(bo);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Tests prime import using VGEM sharing buffer.
|
|
*/
|
|
static int test_import_vgem()
|
|
{
|
|
struct gbm_import_fd_data fd_data;
|
|
int vgem_fd = drm_open_vgem();
|
|
struct drm_prime_handle prime_handle;
|
|
struct gbm_bo *bo;
|
|
const int width = 123;
|
|
const int height = 456;
|
|
const int bytes_per_pixel = 4;
|
|
const int size = width * height * bytes_per_pixel;
|
|
|
|
if (vgem_fd <= 0)
|
|
return 1;
|
|
|
|
CHECK(create_vgem_bo(vgem_fd, size, &prime_handle.handle) == 0);
|
|
prime_handle.flags = DRM_CLOEXEC;
|
|
CHECK(drmIoctl(vgem_fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &prime_handle) == 0);
|
|
|
|
fd_data.fd = prime_handle.fd;
|
|
fd_data.width = width;
|
|
fd_data.height = height;
|
|
fd_data.stride = width * bytes_per_pixel;
|
|
fd_data.format = GBM_FORMAT_XRGB8888;
|
|
|
|
bo = gbm_bo_import(gbm, GBM_BO_IMPORT_FD, &fd_data, GBM_BO_USE_RENDERING);
|
|
CHECK(check_bo(bo));
|
|
gbm_bo_destroy(bo);
|
|
close(prime_handle.fd);
|
|
|
|
close(vgem_fd);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Tests prime import using dma-buf API.
|
|
*/
|
|
static int test_import_dmabuf()
|
|
{
|
|
struct gbm_import_fd_data fd_data;
|
|
struct gbm_bo *bo1, *bo2;
|
|
const int width = 123;
|
|
const int height = 456;
|
|
int prime_fd;
|
|
|
|
bo1 = gbm_bo_create(gbm, width, height, GBM_FORMAT_XRGB8888, GBM_BO_USE_RENDERING);
|
|
CHECK(check_bo(bo1));
|
|
|
|
prime_fd = gbm_bo_get_fd(bo1);
|
|
CHECK(prime_fd >= 0);
|
|
|
|
fd_data.fd = prime_fd;
|
|
fd_data.width = width;
|
|
fd_data.height = height;
|
|
fd_data.stride = gbm_bo_get_stride(bo1);
|
|
fd_data.format = GBM_FORMAT_XRGB8888;
|
|
|
|
gbm_bo_destroy(bo1);
|
|
|
|
bo2 = gbm_bo_import(gbm, GBM_BO_IMPORT_FD, &fd_data, GBM_BO_USE_RENDERING);
|
|
CHECK(check_bo(bo2));
|
|
CHECK(fd_data.width == gbm_bo_get_width(bo2));
|
|
CHECK(fd_data.height == gbm_bo_get_height(bo2));
|
|
CHECK(fd_data.stride == gbm_bo_get_stride(bo2));
|
|
|
|
gbm_bo_destroy(bo2);
|
|
close(prime_fd);
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
/*
|
|
* Tests GBM_BO_IMPORT_FD_MODIFIER entry point.
|
|
*/
|
|
static int test_import_modifier()
|
|
{
|
|
struct gbm_import_fd_modifier_data fd_data;
|
|
struct gbm_bo *bo1, *bo2;
|
|
const int width = 567;
|
|
const int height = 891;
|
|
size_t num_planes, p;
|
|
int i;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(format_list); i++) {
|
|
uint32_t format = format_list[i];
|
|
if (gbm_device_is_format_supported(gbm, format, GBM_BO_USE_RENDERING)) {
|
|
bo1 = gbm_bo_create(gbm, width, height, format, GBM_BO_USE_RENDERING);
|
|
CHECK(check_bo(bo1));
|
|
|
|
num_planes = gbm_bo_get_plane_count(bo1);
|
|
fd_data.num_fds = num_planes;
|
|
|
|
for (p = 0; p < num_planes; p++) {
|
|
fd_data.fds[p] = gbm_bo_get_plane_fd(bo1, p);
|
|
CHECK(fd_data.fds[p] >= 0);
|
|
|
|
fd_data.strides[p] = gbm_bo_get_stride_for_plane(bo1, p);
|
|
fd_data.offsets[p] = gbm_bo_get_offset(bo1, p);
|
|
}
|
|
|
|
fd_data.modifier = gbm_bo_get_modifier(bo1);
|
|
fd_data.width = width;
|
|
fd_data.height = height;
|
|
fd_data.format = format;
|
|
|
|
gbm_bo_destroy(bo1);
|
|
|
|
bo2 = gbm_bo_import(gbm, GBM_BO_IMPORT_FD_MODIFIER, &fd_data,
|
|
GBM_BO_USE_RENDERING);
|
|
|
|
CHECK(check_bo(bo2));
|
|
CHECK(fd_data.width == gbm_bo_get_width(bo2));
|
|
CHECK(fd_data.height == gbm_bo_get_height(bo2));
|
|
CHECK(fd_data.modifier == gbm_bo_get_modifier(bo2));
|
|
|
|
for (p = 0; p < num_planes; p++) {
|
|
CHECK(fd_data.strides[p] == gbm_bo_get_stride_for_plane(bo2, p));
|
|
CHECK(fd_data.offsets[p] == gbm_bo_get_offset(bo2, p));
|
|
}
|
|
|
|
gbm_bo_destroy(bo2);
|
|
|
|
for (p = 0; p < num_planes; p++)
|
|
close(fd_data.fds[p]);
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int test_gem_map()
|
|
{
|
|
uint32_t *pixel, pixel_size;
|
|
struct gbm_bo *bo;
|
|
void *map_data, *addr;
|
|
|
|
uint32_t stride = 0;
|
|
const int width = 666;
|
|
const int height = 777;
|
|
|
|
addr = map_data = NULL;
|
|
|
|
bo = gbm_bo_create(gbm, width, height, GBM_FORMAT_ARGB8888,
|
|
GBM_BO_USE_SW_READ_RARELY | GBM_BO_USE_SW_WRITE_RARELY);
|
|
CHECK(check_bo(bo));
|
|
|
|
addr = gbm_bo_map2(bo, 0, 0, width, height, GBM_BO_TRANSFER_READ_WRITE, &stride,
|
|
&map_data, 0);
|
|
|
|
CHECK(addr != MAP_FAILED);
|
|
CHECK(map_data);
|
|
CHECK(stride > 0);
|
|
|
|
pixel = (uint32_t *)addr;
|
|
pixel_size = sizeof(*pixel);
|
|
|
|
pixel[(height / 2) * (stride / pixel_size) + width / 2] = 0xABBAABBA;
|
|
gbm_bo_unmap(bo, map_data);
|
|
|
|
/* Re-map and verify written previously data. */
|
|
stride = 0;
|
|
addr = map_data = NULL;
|
|
|
|
addr = gbm_bo_map2(bo, 0, 0, width, height, GBM_BO_TRANSFER_READ_WRITE, &stride,
|
|
&map_data, 0);
|
|
|
|
CHECK(addr != MAP_FAILED);
|
|
CHECK(map_data);
|
|
CHECK(stride > 0);
|
|
|
|
pixel = (uint32_t *)addr;
|
|
CHECK(pixel[(height / 2) * (stride / pixel_size) + width / 2] == 0xABBAABBA);
|
|
|
|
gbm_bo_unmap(bo, map_data);
|
|
gbm_bo_destroy(bo);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int test_dmabuf_map()
|
|
{
|
|
uint32_t *pixel;
|
|
struct gbm_bo *bo;
|
|
void *addr, *map_data;
|
|
const int width = 666;
|
|
const int height = 777;
|
|
int x, y, ret, prime_fd;
|
|
struct dma_buf_sync sync_end = { 0 };
|
|
struct dma_buf_sync sync_start = { 0 };
|
|
uint32_t pixel_size, stride, stride_pixels, length;
|
|
|
|
bo = gbm_bo_create(gbm, width, height, GBM_FORMAT_ARGB8888, GBM_BO_USE_LINEAR);
|
|
CHECK(check_bo(bo));
|
|
|
|
prime_fd = gbm_bo_get_fd(bo);
|
|
CHECK(prime_fd > 0);
|
|
|
|
stride = gbm_bo_get_stride(bo);
|
|
length = gbm_bo_get_plane_size(bo, 0);
|
|
CHECK(stride > 0);
|
|
CHECK(length > 0);
|
|
|
|
addr = mmap(NULL, length, (PROT_READ | PROT_WRITE), MAP_SHARED, prime_fd, 0);
|
|
CHECK(addr != MAP_FAILED);
|
|
|
|
pixel = (uint32_t *)addr;
|
|
pixel_size = sizeof(*pixel);
|
|
stride_pixels = stride / pixel_size;
|
|
|
|
sync_start.flags = DMA_BUF_SYNC_START | DMA_BUF_SYNC_WRITE;
|
|
ret = HANDLE_EINTR(ioctl(prime_fd, DMA_BUF_IOCTL_SYNC, &sync_start));
|
|
CHECK(ret == 0);
|
|
|
|
for (y = 0; y < height; ++y)
|
|
for (x = 0; x < width; ++x)
|
|
pixel[y * stride_pixels + x] = ((y << 16) | x);
|
|
|
|
sync_end.flags = DMA_BUF_SYNC_END | DMA_BUF_SYNC_WRITE;
|
|
ret = HANDLE_EINTR(ioctl(prime_fd, DMA_BUF_IOCTL_SYNC, &sync_end));
|
|
CHECK(ret == 0);
|
|
|
|
ret = munmap(addr, length);
|
|
CHECK(ret == 0);
|
|
|
|
ret = close(prime_fd);
|
|
CHECK(ret == 0);
|
|
|
|
prime_fd = gbm_bo_get_fd(bo);
|
|
CHECK(prime_fd > 0);
|
|
|
|
addr = mmap(NULL, length, (PROT_READ | PROT_WRITE), MAP_SHARED, prime_fd, 0);
|
|
CHECK(addr != MAP_FAILED);
|
|
|
|
pixel = (uint32_t *)addr;
|
|
|
|
memset(&sync_start, 0, sizeof(sync_start));
|
|
memset(&sync_end, 0, sizeof(sync_end));
|
|
|
|
sync_start.flags = DMA_BUF_SYNC_START | DMA_BUF_SYNC_READ;
|
|
ret = HANDLE_EINTR(ioctl(prime_fd, DMA_BUF_IOCTL_SYNC, &sync_start));
|
|
CHECK(ret == 0);
|
|
|
|
for (y = 0; y < height; ++y)
|
|
for (x = 0; x < width; ++x)
|
|
CHECK(pixel[y * stride_pixels + x] == ((y << 16) | x));
|
|
|
|
sync_end.flags = DMA_BUF_SYNC_END | DMA_BUF_SYNC_READ;
|
|
ret = HANDLE_EINTR(ioctl(prime_fd, DMA_BUF_IOCTL_SYNC, &sync_end));
|
|
CHECK(ret == 0);
|
|
|
|
ret = munmap(addr, length);
|
|
CHECK(ret == 0);
|
|
|
|
ret = close(prime_fd);
|
|
CHECK(ret == 0);
|
|
|
|
addr = gbm_bo_map2(bo, 0, 0, width, height, GBM_BO_TRANSFER_READ, &stride,
|
|
&map_data, 0);
|
|
|
|
CHECK(addr != MAP_FAILED);
|
|
CHECK(map_data);
|
|
CHECK(stride > 0);
|
|
|
|
pixel = (uint32_t *)addr;
|
|
|
|
for (y = 0; y < height; ++y)
|
|
for (x = 0; x < width; ++x)
|
|
CHECK(pixel[y * stride_pixels + x] == ((y << 16) | x));
|
|
|
|
gbm_bo_unmap(bo, map_data);
|
|
gbm_bo_destroy(bo);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int test_gem_map_tiling(enum gbm_bo_flags buffer_create_flag)
|
|
{
|
|
uint32_t *pixel, pixel_size;
|
|
struct gbm_bo *bo;
|
|
void *map_data, *addr;
|
|
|
|
uint32_t stride = 0;
|
|
uint32_t stride_pixels = 0;
|
|
const int width = 666;
|
|
const int height = 777;
|
|
int x, y;
|
|
|
|
addr = map_data = NULL;
|
|
|
|
bo = gbm_bo_create(gbm, width, height, GBM_FORMAT_ARGB8888, buffer_create_flag);
|
|
CHECK(check_bo(bo));
|
|
|
|
addr = gbm_bo_map2(bo, 0, 0, width, height, GBM_BO_TRANSFER_WRITE, &stride,
|
|
&map_data, 0);
|
|
|
|
CHECK(addr != MAP_FAILED);
|
|
CHECK(map_data);
|
|
CHECK(stride > 0);
|
|
|
|
pixel = (uint32_t *)addr;
|
|
pixel_size = sizeof(*pixel);
|
|
stride_pixels = stride / pixel_size;
|
|
|
|
for (y = 0; y < height; ++y)
|
|
for (x = 0; x < width; ++x)
|
|
pixel[y * stride_pixels + x] = ((y << 16) | x);
|
|
|
|
gbm_bo_unmap(bo, map_data);
|
|
|
|
/* Re-map and verify written previously data. */
|
|
stride = 0;
|
|
addr = map_data = NULL;
|
|
|
|
addr = gbm_bo_map2(bo, 0, 0, width, height, GBM_BO_TRANSFER_READ, &stride,
|
|
&map_data, 0);
|
|
|
|
CHECK(addr != MAP_FAILED);
|
|
CHECK(map_data);
|
|
CHECK(stride > 0);
|
|
|
|
pixel = (uint32_t *)addr;
|
|
pixel_size = sizeof(*pixel);
|
|
stride_pixels = stride / pixel_size;
|
|
|
|
for (y = 0; y < height; ++y)
|
|
for (x = 0; x < width; ++x)
|
|
CHECK(pixel[y * stride_pixels + x] == ((y << 16) | x));
|
|
|
|
gbm_bo_unmap(bo, map_data);
|
|
gbm_bo_destroy(bo);
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
static int test_gem_map_format(int format_index,
|
|
enum gbm_bo_flags buffer_create_flag)
|
|
{
|
|
uint8_t *pixel;
|
|
struct gbm_bo *bo;
|
|
void *map_data, *addr;
|
|
uint32_t x, y, p, w, h, b, planes, bytes_per_pixel, pixel_data_mask, idx;
|
|
uint8_t byte_mask;
|
|
uint32_t stride = 0;
|
|
const int width = 333;
|
|
const int height = 444;
|
|
const uint32_t pixel_format = format_info_list[format_index].pixel_format;
|
|
|
|
addr = map_data = NULL;
|
|
if (!gbm_device_is_format_supported(gbm, pixel_format, buffer_create_flag))
|
|
return 1;
|
|
|
|
bo = gbm_bo_create(gbm, width, height, pixel_format, buffer_create_flag);
|
|
CHECK(check_bo(bo));
|
|
planes = gbm_bo_get_plane_count(bo);
|
|
CHECK(planes == format_info_list[format_index].num_planes);
|
|
|
|
for (p = 0; p < planes; ++p) {
|
|
w = width / format_info_list[format_index].planes[p].subsample_rate;
|
|
h = height / format_info_list[format_index].planes[p].subsample_rate;
|
|
addr = gbm_bo_map2(bo, 0, 0, w, h, GBM_BO_TRANSFER_WRITE, &stride,
|
|
&map_data, p);
|
|
|
|
CHECK(addr != MAP_FAILED);
|
|
CHECK(map_data);
|
|
CHECK(stride > 0);
|
|
|
|
pixel = (uint8_t *)addr;
|
|
bytes_per_pixel = format_info_list[format_index].planes[p].bits_per_pixel / 8;
|
|
for (y = 0; y < h; ++y) {
|
|
for (x = 0; x < w; ++x) {
|
|
idx = y * stride + x * bytes_per_pixel;
|
|
for (b = 0; b < bytes_per_pixel; ++b)
|
|
pixel[idx + b] = y ^ x ^ b;
|
|
}
|
|
}
|
|
gbm_bo_unmap(bo, map_data);
|
|
stride = 0;
|
|
addr = map_data = NULL;
|
|
}
|
|
|
|
/* Re-map and verify written previously data. */
|
|
for (p = 0; p < planes; ++p) {
|
|
w = width / format_info_list[format_index].planes[p].subsample_rate;
|
|
h = height / format_info_list[format_index].planes[p].subsample_rate;
|
|
addr = gbm_bo_map2(bo, 0, 0, w, h, GBM_BO_TRANSFER_READ, &stride,
|
|
&map_data, p);
|
|
|
|
CHECK(addr != MAP_FAILED);
|
|
CHECK(map_data);
|
|
CHECK(stride > 0);
|
|
|
|
pixel = (uint8_t *)addr;
|
|
bytes_per_pixel = format_info_list[format_index].planes[p].bits_per_pixel / 8;
|
|
pixel_data_mask = format_info_list[format_index].planes[p].data_mask;
|
|
for (y = 0; y < h; ++y) {
|
|
for (x = 0; x < w; ++x) {
|
|
idx = y * stride + x * bytes_per_pixel;
|
|
for (b = 0; b < bytes_per_pixel; ++b) {
|
|
byte_mask = pixel_data_mask >> (8 * b);
|
|
CHECK((pixel[idx + b] & byte_mask) == ((uint8_t)(y ^ x ^ b) & byte_mask));
|
|
}
|
|
}
|
|
}
|
|
gbm_bo_unmap(bo, map_data);
|
|
stride = 0;
|
|
addr = map_data = NULL;
|
|
}
|
|
|
|
gbm_bo_destroy(bo);
|
|
return 1;
|
|
}
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
int result, i, j;
|
|
|
|
result = test_init();
|
|
if (result == ENODRM) {
|
|
printf("[ FAILED ] graphics_Gbm test initialization failed\n");
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
result &= test_reinit();
|
|
result &= test_alloc_free();
|
|
result &= test_alloc_free_sizes();
|
|
result &= test_alloc_free_formats();
|
|
result &= test_alloc_free_usage();
|
|
result &= test_user_data();
|
|
result &= test_export();
|
|
result &= test_import_vgem();
|
|
result &= test_import_dmabuf();
|
|
result &= test_import_modifier();
|
|
result &= test_gem_map();
|
|
|
|
// TODO(crbug.com/752669)
|
|
if (strcmp(gbm_device_get_backend_name(gbm), "tegra")) {
|
|
for (i = 0; i < ARRAY_SIZE(buffer_list); ++i) {
|
|
result &= test_gem_map_tiling(buffer_list[i]);
|
|
for (j = 0; j < ARRAY_SIZE(format_info_list); ++j)
|
|
result &= test_gem_map_format(j, buffer_list[i]);
|
|
}
|
|
|
|
result &= test_dmabuf_map();
|
|
}
|
|
result &= test_destroy();
|
|
|
|
if (!result) {
|
|
printf("[ FAILED ] graphics_Gbm test failed\n");
|
|
return EXIT_FAILURE;
|
|
} else {
|
|
printf("[ PASSED ] graphics_Gbm test success\n");
|
|
return EXIT_SUCCESS;
|
|
}
|
|
}
|