1e88f27b3Smrg/* 2e88f27b3Smrg * Copyright (C) 2013 Samsung Electronics Co.Ltd 3e88f27b3Smrg * Authors: 4e88f27b3Smrg * Inki Dae <inki.dae@samsung.com> 5e88f27b3Smrg * 600a23bdaSmrg * Permission is hereby granted, free of charge, to any person obtaining a 700a23bdaSmrg * copy of this software and associated documentation files (the "Software"), 800a23bdaSmrg * to deal in the Software without restriction, including without limitation 900a23bdaSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 1000a23bdaSmrg * and/or sell copies of the Software, and to permit persons to whom the 1100a23bdaSmrg * Software is furnished to do so, subject to the following conditions: 12e88f27b3Smrg * 1300a23bdaSmrg * The above copyright notice and this permission notice (including the next 1400a23bdaSmrg * paragraph) shall be included in all copies or substantial portions of the 1500a23bdaSmrg * Software. 1600a23bdaSmrg * 1700a23bdaSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1800a23bdaSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1900a23bdaSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 2000a23bdaSmrg * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 2100a23bdaSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 2200a23bdaSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 2300a23bdaSmrg * OTHER DEALINGS IN THE SOFTWARE. 24e88f27b3Smrg */ 25e88f27b3Smrg 26e88f27b3Smrg#include <stdlib.h> 27e88f27b3Smrg#include <stdio.h> 28e88f27b3Smrg#include <string.h> 29e88f27b3Smrg#include <errno.h> 30e6188e58Smrg#include <time.h> 31e6188e58Smrg#include <unistd.h> 32e88f27b3Smrg 33e88f27b3Smrg#include <sys/mman.h> 34e88f27b3Smrg 35e88f27b3Smrg#include <xf86drm.h> 36e88f27b3Smrg#include <xf86drmMode.h> 37e88f27b3Smrg#include <drm_fourcc.h> 38e88f27b3Smrg 39e88f27b3Smrg#include "exynos_drm.h" 40e88f27b3Smrg#include "exynos_drmif.h" 41e6188e58Smrg#include "exynos_fimg2d.h" 42e88f27b3Smrg 43e88f27b3Smrg#define DRM_MODULE_NAME "exynos" 44e88f27b3Smrg 45e88f27b3Smrgstatic unsigned int screen_width, screen_height; 46e88f27b3Smrg 47e88f27b3Smrgstruct connector { 48e88f27b3Smrg uint32_t id; 49e88f27b3Smrg char mode_str[64]; 50e88f27b3Smrg drmModeModeInfo *mode; 51e88f27b3Smrg drmModeEncoder *encoder; 52e88f27b3Smrg int crtc; 53e88f27b3Smrg}; 54e88f27b3Smrg 55e88f27b3Smrgstatic void connector_find_mode(int fd, struct connector *c, 56e88f27b3Smrg drmModeRes *resources) 57e88f27b3Smrg{ 58e88f27b3Smrg drmModeConnector *connector; 59e88f27b3Smrg int i, j; 60e88f27b3Smrg 61e88f27b3Smrg /* First, find the connector & mode */ 62e88f27b3Smrg c->mode = NULL; 63e88f27b3Smrg for (i = 0; i < resources->count_connectors; i++) { 64e88f27b3Smrg connector = drmModeGetConnector(fd, resources->connectors[i]); 65e88f27b3Smrg 66e88f27b3Smrg if (!connector) { 67e88f27b3Smrg fprintf(stderr, "could not get connector %i: %s\n", 68e88f27b3Smrg resources->connectors[i], strerror(errno)); 69e88f27b3Smrg continue; 70e88f27b3Smrg } 71e88f27b3Smrg 72e88f27b3Smrg if (!connector->count_modes) { 73e88f27b3Smrg drmModeFreeConnector(connector); 74e88f27b3Smrg continue; 75e88f27b3Smrg } 76e88f27b3Smrg 77e88f27b3Smrg if (connector->connector_id != c->id) { 78e88f27b3Smrg drmModeFreeConnector(connector); 79e88f27b3Smrg continue; 80e88f27b3Smrg } 81e88f27b3Smrg 82e88f27b3Smrg for (j = 0; j < connector->count_modes; j++) { 83e88f27b3Smrg c->mode = &connector->modes[j]; 84e88f27b3Smrg if (!strcmp(c->mode->name, c->mode_str)) 85e88f27b3Smrg break; 86e88f27b3Smrg } 87e88f27b3Smrg 88e88f27b3Smrg /* Found it, break out */ 89e88f27b3Smrg if (c->mode) 90e88f27b3Smrg break; 91e88f27b3Smrg 92e88f27b3Smrg drmModeFreeConnector(connector); 93e88f27b3Smrg } 94e88f27b3Smrg 95e88f27b3Smrg if (!c->mode) { 96e88f27b3Smrg fprintf(stderr, "failed to find mode \"%s\"\n", c->mode_str); 97e88f27b3Smrg return; 98e88f27b3Smrg } 99e88f27b3Smrg 100e88f27b3Smrg /* Now get the encoder */ 101e88f27b3Smrg for (i = 0; i < resources->count_encoders; i++) { 102e88f27b3Smrg c->encoder = drmModeGetEncoder(fd, resources->encoders[i]); 103e88f27b3Smrg 104e88f27b3Smrg if (!c->encoder) { 105e88f27b3Smrg fprintf(stderr, "could not get encoder %i: %s\n", 106e88f27b3Smrg resources->encoders[i], strerror(errno)); 107e88f27b3Smrg continue; 108e88f27b3Smrg } 109e88f27b3Smrg 110e88f27b3Smrg if (c->encoder->encoder_id == connector->encoder_id) 111e88f27b3Smrg break; 112e88f27b3Smrg 113e88f27b3Smrg drmModeFreeEncoder(c->encoder); 114e88f27b3Smrg } 115e88f27b3Smrg 116e88f27b3Smrg if (c->crtc == -1) 117e88f27b3Smrg c->crtc = c->encoder->crtc_id; 118e88f27b3Smrg} 119e88f27b3Smrg 120e88f27b3Smrgstatic int drm_set_crtc(struct exynos_device *dev, struct connector *c, 121e88f27b3Smrg unsigned int fb_id) 122e88f27b3Smrg{ 123e88f27b3Smrg int ret; 124e88f27b3Smrg 125e88f27b3Smrg ret = drmModeSetCrtc(dev->fd, c->crtc, 126e88f27b3Smrg fb_id, 0, 0, &c->id, 1, c->mode); 127e6188e58Smrg if (ret) 128e88f27b3Smrg drmMsg("failed to set mode: %s\n", strerror(errno)); 129e88f27b3Smrg 130e88f27b3Smrg return ret; 131e88f27b3Smrg} 132e88f27b3Smrg 133e88f27b3Smrgstatic struct exynos_bo *exynos_create_buffer(struct exynos_device *dev, 134e88f27b3Smrg unsigned long size, 135e88f27b3Smrg unsigned int flags) 136e88f27b3Smrg{ 137e88f27b3Smrg struct exynos_bo *bo; 138e88f27b3Smrg 139e88f27b3Smrg bo = exynos_bo_create(dev, size, flags); 140e88f27b3Smrg if (!bo) 141e88f27b3Smrg return bo; 142e88f27b3Smrg 143e88f27b3Smrg if (!exynos_bo_map(bo)) { 144e88f27b3Smrg exynos_bo_destroy(bo); 145e88f27b3Smrg return NULL; 146e88f27b3Smrg } 147e88f27b3Smrg 148e88f27b3Smrg return bo; 149e88f27b3Smrg} 150e88f27b3Smrg 151e6188e58Smrg/* Allocate buffer and fill it with checkerboard pattern, where the tiles * 152e6188e58Smrg * have a random color. The caller has to free the buffer. */ 153e6188e58Smrgstatic void *create_checkerboard_pattern(unsigned int num_tiles_x, 154e6188e58Smrg unsigned int num_tiles_y, unsigned int tile_size) 155e6188e58Smrg{ 156e6188e58Smrg unsigned int *buf; 157e6188e58Smrg unsigned int x, y, i, j; 158e6188e58Smrg const unsigned int stride = num_tiles_x * tile_size; 159e6188e58Smrg 160e6188e58Smrg if (posix_memalign((void*)&buf, 64, num_tiles_y * tile_size * stride * 4) != 0) 161e6188e58Smrg return NULL; 162e6188e58Smrg 163e6188e58Smrg for (x = 0; x < num_tiles_x; ++x) { 164e6188e58Smrg for (y = 0; y < num_tiles_y; ++y) { 165e6188e58Smrg const unsigned int color = 0xff000000 + (random() & 0xffffff); 166e6188e58Smrg 167e6188e58Smrg for (i = 0; i < tile_size; ++i) { 168e6188e58Smrg for (j = 0; j < tile_size; ++j) { 169e6188e58Smrg buf[x * tile_size + y * stride * tile_size + i + j * stride] = color; 170e6188e58Smrg } 171e6188e58Smrg } 172e6188e58Smrg } 173e6188e58Smrg } 174e6188e58Smrg 175e6188e58Smrg return buf; 176e6188e58Smrg} 177e6188e58Smrg 178e88f27b3Smrgstatic void exynos_destroy_buffer(struct exynos_bo *bo) 179e88f27b3Smrg{ 180e88f27b3Smrg exynos_bo_destroy(bo); 181e88f27b3Smrg} 182e88f27b3Smrg 183e6188e58Smrgstatic void wait_for_user_input(int last) 184e6188e58Smrg{ 185e6188e58Smrg printf("press <ENTER> to %s\n", last ? "exit test application" : 186e6188e58Smrg "skip to next test"); 187e6188e58Smrg 188e6188e58Smrg getchar(); 189e6188e58Smrg} 190e6188e58Smrg 191e88f27b3Smrgstatic int g2d_solid_fill_test(struct exynos_device *dev, struct exynos_bo *dst) 192e88f27b3Smrg{ 193e88f27b3Smrg struct g2d_context *ctx; 194e6188e58Smrg struct g2d_image img = {0}; 195e88f27b3Smrg unsigned int count, img_w, img_h; 196e88f27b3Smrg int ret = 0; 197e88f27b3Smrg 198e88f27b3Smrg ctx = g2d_init(dev->fd); 199e88f27b3Smrg if (!ctx) 200e88f27b3Smrg return -EFAULT; 201e88f27b3Smrg 202e88f27b3Smrg img.bo[0] = dst->handle; 203e88f27b3Smrg 204e6188e58Smrg printf("solid fill test.\n"); 205e88f27b3Smrg 206e88f27b3Smrg srand(time(NULL)); 207e88f27b3Smrg img_w = screen_width; 208e88f27b3Smrg img_h = screen_height; 209e88f27b3Smrg 210e88f27b3Smrg for (count = 0; count < 2; count++) { 211e88f27b3Smrg unsigned int x, y, w, h; 212e88f27b3Smrg 213e88f27b3Smrg x = rand() % (img_w / 2); 214e88f27b3Smrg y = rand() % (img_h / 2); 215e88f27b3Smrg w = rand() % (img_w - x); 216e88f27b3Smrg h = rand() % (img_h - y); 217e88f27b3Smrg 218e88f27b3Smrg img.width = img_w; 219e88f27b3Smrg img.height = img_h; 220e88f27b3Smrg img.stride = img.width * 4; 221e88f27b3Smrg img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; 222e88f27b3Smrg img.color = 0xff000000 + (random() & 0xffffff); 223e88f27b3Smrg 224e88f27b3Smrg ret = g2d_solid_fill(ctx, &img, x, y, w, h); 225e88f27b3Smrg if (ret < 0) 226e88f27b3Smrg goto err_fini; 227e88f27b3Smrg 228e88f27b3Smrg ret = g2d_exec(ctx); 229e88f27b3Smrg if (ret < 0) 230e88f27b3Smrg break; 231e88f27b3Smrg } 232e88f27b3Smrg 233e88f27b3Smrgerr_fini: 234e88f27b3Smrg g2d_fini(ctx); 235e88f27b3Smrg 236e88f27b3Smrg return ret; 237e88f27b3Smrg} 238e88f27b3Smrg 239e88f27b3Smrgstatic int g2d_copy_test(struct exynos_device *dev, struct exynos_bo *src, 240e88f27b3Smrg struct exynos_bo *dst, 241e88f27b3Smrg enum e_g2d_buf_type type) 242e88f27b3Smrg{ 243e88f27b3Smrg struct g2d_context *ctx; 244e6188e58Smrg struct g2d_image src_img = {0}, dst_img = {0}; 245e88f27b3Smrg unsigned int src_x, src_y, dst_x, dst_y, img_w, img_h; 246e88f27b3Smrg unsigned long userptr, size; 247e88f27b3Smrg int ret; 248e88f27b3Smrg 249e88f27b3Smrg ctx = g2d_init(dev->fd); 250e88f27b3Smrg if (!ctx) 251e88f27b3Smrg return -EFAULT; 252e88f27b3Smrg 253e88f27b3Smrg dst_img.bo[0] = dst->handle; 254e88f27b3Smrg 255e88f27b3Smrg src_x = 0; 256e88f27b3Smrg src_y = 0; 257e88f27b3Smrg dst_x = 0; 258e88f27b3Smrg dst_y = 0; 259e88f27b3Smrg img_w = screen_width; 260e88f27b3Smrg img_h = screen_height; 261e88f27b3Smrg 262e88f27b3Smrg switch (type) { 263e88f27b3Smrg case G2D_IMGBUF_GEM: 264e88f27b3Smrg src_img.bo[0] = src->handle; 265e88f27b3Smrg break; 266e88f27b3Smrg case G2D_IMGBUF_USERPTR: 267e88f27b3Smrg size = img_w * img_h * 4; 268e88f27b3Smrg 269e88f27b3Smrg userptr = (unsigned long)malloc(size); 270e88f27b3Smrg if (!userptr) { 271e88f27b3Smrg fprintf(stderr, "failed to allocate userptr.\n"); 272d8807b2fSmrg ret = -EFAULT; 273d8807b2fSmrg goto fail; 274e88f27b3Smrg } 275e88f27b3Smrg 276e88f27b3Smrg src_img.user_ptr[0].userptr = userptr; 277e88f27b3Smrg src_img.user_ptr[0].size = size; 278e88f27b3Smrg break; 279e6188e58Smrg case G2D_IMGBUF_COLOR: 280e88f27b3Smrg default: 281e6188e58Smrg ret = -EFAULT; 282e6188e58Smrg goto fail; 283e88f27b3Smrg } 284e88f27b3Smrg 285e88f27b3Smrg printf("copy test with %s.\n", 286e88f27b3Smrg type == G2D_IMGBUF_GEM ? "gem" : "userptr"); 287e88f27b3Smrg 288e88f27b3Smrg src_img.width = img_w; 289e88f27b3Smrg src_img.height = img_h; 290e88f27b3Smrg src_img.stride = src_img.width * 4; 291e88f27b3Smrg src_img.buf_type = type; 292e88f27b3Smrg src_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; 293e88f27b3Smrg src_img.color = 0xffff0000; 294e88f27b3Smrg ret = g2d_solid_fill(ctx, &src_img, src_x, src_y, img_w, img_h); 295e88f27b3Smrg if (ret < 0) 296e88f27b3Smrg goto err_free_userptr; 297e88f27b3Smrg 298e88f27b3Smrg dst_img.width = img_w; 299e88f27b3Smrg dst_img.height = img_h; 300e88f27b3Smrg dst_img.stride = dst_img.width * 4; 301e88f27b3Smrg dst_img.buf_type = G2D_IMGBUF_GEM; 302e88f27b3Smrg dst_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; 303e88f27b3Smrg 304e88f27b3Smrg ret = g2d_copy(ctx, &src_img, &dst_img, src_x, src_y, dst_x, dst_y, 305e88f27b3Smrg img_w - 4, img_h - 4); 306e88f27b3Smrg if (ret < 0) 307e88f27b3Smrg goto err_free_userptr; 308e88f27b3Smrg 309e88f27b3Smrg g2d_exec(ctx); 310e88f27b3Smrg 311e88f27b3Smrgerr_free_userptr: 312e88f27b3Smrg if (type == G2D_IMGBUF_USERPTR) 313e88f27b3Smrg if (userptr) 314e88f27b3Smrg free((void *)userptr); 315e88f27b3Smrg 316e6188e58Smrgfail: 317e88f27b3Smrg g2d_fini(ctx); 318e88f27b3Smrg 319e88f27b3Smrg return ret; 320e88f27b3Smrg} 321e88f27b3Smrg 3223f012e29Smrgstatic int g2d_move_test(struct exynos_device *dev, 3233f012e29Smrg struct exynos_bo *tmp, 3243f012e29Smrg struct exynos_bo *buf, 3253f012e29Smrg enum e_g2d_buf_type type) 3263f012e29Smrg{ 3273f012e29Smrg struct g2d_context *ctx; 3283f012e29Smrg struct g2d_image img = {0}, tmp_img = {0}; 3293f012e29Smrg unsigned int img_w, img_h, count; 3303f012e29Smrg int cur_x, cur_y; 3313f012e29Smrg void *checkerboard; 3323f012e29Smrg int ret; 3333f012e29Smrg 3343f012e29Smrg static const struct g2d_step { 3353f012e29Smrg int x, y; 3363f012e29Smrg } steps[] = { 3373f012e29Smrg { 1, 0}, { 0, 1}, 3383f012e29Smrg {-1, 0}, { 0, -1}, 3393f012e29Smrg { 1, 1}, {-1, -1}, 3403f012e29Smrg { 1, -1}, {-1, 1}, 3413f012e29Smrg { 2, 1}, { 1, 2}, 3423f012e29Smrg {-2, -1}, {-1, -2}, 3433f012e29Smrg { 2, -1}, { 1, -2}, 3443f012e29Smrg {-2, 1}, {-1, 2} 3453f012e29Smrg }; 3463f012e29Smrg static const unsigned int num_steps = 3473f012e29Smrg sizeof(steps) / sizeof(struct g2d_step); 3483f012e29Smrg 3493f012e29Smrg ctx = g2d_init(dev->fd); 3503f012e29Smrg if (!ctx) 3513f012e29Smrg return -EFAULT; 3523f012e29Smrg 3533f012e29Smrg img.bo[0] = buf->handle; 3543f012e29Smrg 3553f012e29Smrg /* create pattern of half the screen size */ 3563f012e29Smrg checkerboard = create_checkerboard_pattern(screen_width / 64, screen_height / 64, 32); 3573f012e29Smrg if (!checkerboard) { 3583f012e29Smrg ret = -EFAULT; 3593f012e29Smrg goto fail; 3603f012e29Smrg } 3613f012e29Smrg 3623f012e29Smrg img_w = (screen_width / 64) * 32; 3633f012e29Smrg img_h = (screen_height / 64) * 32; 3643f012e29Smrg 3653f012e29Smrg switch (type) { 3663f012e29Smrg case G2D_IMGBUF_GEM: 3673f012e29Smrg memcpy(tmp->vaddr, checkerboard, img_w * img_h * 4); 3683f012e29Smrg tmp_img.bo[0] = tmp->handle; 3693f012e29Smrg break; 3703f012e29Smrg case G2D_IMGBUF_USERPTR: 3713f012e29Smrg tmp_img.user_ptr[0].userptr = (unsigned long)checkerboard; 3723f012e29Smrg tmp_img.user_ptr[0].size = img_w * img_h * 4; 3733f012e29Smrg break; 3743f012e29Smrg case G2D_IMGBUF_COLOR: 3753f012e29Smrg default: 3763f012e29Smrg ret = -EFAULT; 3773f012e29Smrg goto fail; 3783f012e29Smrg } 3793f012e29Smrg 3803f012e29Smrg /* solid fill framebuffer with white color */ 3813f012e29Smrg img.width = screen_width; 3823f012e29Smrg img.height = screen_height; 3833f012e29Smrg img.stride = screen_width * 4; 3843f012e29Smrg img.buf_type = G2D_IMGBUF_GEM; 3853f012e29Smrg img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; 3863f012e29Smrg img.color = 0xffffffff; 3873f012e29Smrg 3883f012e29Smrg /* put checkerboard pattern in the center of the framebuffer */ 3893f012e29Smrg cur_x = (screen_width - img_w) / 2; 3903f012e29Smrg cur_y = (screen_height - img_h) / 2; 3913f012e29Smrg tmp_img.width = img_w; 3923f012e29Smrg tmp_img.height = img_h; 3933f012e29Smrg tmp_img.stride = img_w * 4; 3943f012e29Smrg tmp_img.buf_type = type; 3953f012e29Smrg tmp_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; 3963f012e29Smrg 3973f012e29Smrg ret = g2d_solid_fill(ctx, &img, 0, 0, screen_width, screen_height) || 3983f012e29Smrg g2d_copy(ctx, &tmp_img, &img, 0, 0, cur_x, cur_y, img_w, img_h); 3993f012e29Smrg 4003f012e29Smrg if (!ret) 4013f012e29Smrg ret = g2d_exec(ctx); 4023f012e29Smrg if (ret < 0) 4033f012e29Smrg goto fail; 4043f012e29Smrg 4053f012e29Smrg printf("move test with %s.\n", 4063f012e29Smrg type == G2D_IMGBUF_GEM ? "gem" : "userptr"); 4073f012e29Smrg 4083f012e29Smrg srand(time(NULL)); 4093f012e29Smrg for (count = 0; count < 256; ++count) { 4103f012e29Smrg const struct g2d_step *s; 4113f012e29Smrg 4123f012e29Smrg /* select step and validate it */ 4133f012e29Smrg while (1) { 4143f012e29Smrg s = &steps[random() % num_steps]; 4153f012e29Smrg 4163f012e29Smrg if (cur_x + s->x < 0 || cur_y + s->y < 0 || 4173f012e29Smrg cur_x + img_w + s->x >= screen_width || 4183f012e29Smrg cur_y + img_h + s->y >= screen_height) 4193f012e29Smrg continue; 4203f012e29Smrg else 4213f012e29Smrg break; 4223f012e29Smrg } 4233f012e29Smrg 4243f012e29Smrg ret = g2d_move(ctx, &img, cur_x, cur_y, cur_x + s->x, cur_y + s->y, 4253f012e29Smrg img_w, img_h); 4263f012e29Smrg if (!ret) 4273f012e29Smrg ret = g2d_exec(ctx); 4283f012e29Smrg 4293f012e29Smrg if (ret < 0) 4303f012e29Smrg goto fail; 4313f012e29Smrg 4323f012e29Smrg cur_x += s->x; 4333f012e29Smrg cur_y += s->y; 4343f012e29Smrg 4353f012e29Smrg usleep(100000); 4363f012e29Smrg } 4373f012e29Smrg 4383f012e29Smrgfail: 4393f012e29Smrg g2d_fini(ctx); 4403f012e29Smrg 4413f012e29Smrg free(checkerboard); 4423f012e29Smrg 4433f012e29Smrg return ret; 4443f012e29Smrg} 4453f012e29Smrg 446e88f27b3Smrgstatic int g2d_copy_with_scale_test(struct exynos_device *dev, 447e88f27b3Smrg struct exynos_bo *src, 448e88f27b3Smrg struct exynos_bo *dst, 449e88f27b3Smrg enum e_g2d_buf_type type) 450e88f27b3Smrg{ 451e88f27b3Smrg struct g2d_context *ctx; 452e6188e58Smrg struct g2d_image src_img = {0}, dst_img = {0}; 453e6188e58Smrg unsigned int src_x, src_y, img_w, img_h; 454e88f27b3Smrg unsigned long userptr, size; 455e88f27b3Smrg int ret; 456e88f27b3Smrg 457e88f27b3Smrg ctx = g2d_init(dev->fd); 458e88f27b3Smrg if (!ctx) 459e88f27b3Smrg return -EFAULT; 460e88f27b3Smrg 461e88f27b3Smrg dst_img.bo[0] = dst->handle; 462e88f27b3Smrg 463e88f27b3Smrg src_x = 0; 464e88f27b3Smrg src_y = 0; 465e88f27b3Smrg img_w = screen_width; 466e88f27b3Smrg img_h = screen_height; 467e88f27b3Smrg 468e88f27b3Smrg switch (type) { 469e88f27b3Smrg case G2D_IMGBUF_GEM: 470e88f27b3Smrg src_img.bo[0] = src->handle; 471e88f27b3Smrg break; 472e88f27b3Smrg case G2D_IMGBUF_USERPTR: 473e88f27b3Smrg size = img_w * img_h * 4; 474e88f27b3Smrg 475e88f27b3Smrg userptr = (unsigned long)malloc(size); 476e88f27b3Smrg if (!userptr) { 477e88f27b3Smrg fprintf(stderr, "failed to allocate userptr.\n"); 478d8807b2fSmrg ret = -EFAULT; 479d8807b2fSmrg goto fail; 480e88f27b3Smrg } 481e88f27b3Smrg 482e88f27b3Smrg src_img.user_ptr[0].userptr = userptr; 483e88f27b3Smrg src_img.user_ptr[0].size = size; 484e88f27b3Smrg break; 485e6188e58Smrg case G2D_IMGBUF_COLOR: 486e88f27b3Smrg default: 487e6188e58Smrg ret = -EFAULT; 488e6188e58Smrg goto fail; 489e88f27b3Smrg } 490e88f27b3Smrg 491e88f27b3Smrg printf("copy and scale test with %s.\n", 492e88f27b3Smrg type == G2D_IMGBUF_GEM ? "gem" : "userptr"); 493e88f27b3Smrg 494e88f27b3Smrg src_img.width = img_w; 495e88f27b3Smrg src_img.height = img_h; 496e88f27b3Smrg src_img.stride = src_img.width * 4; 497e88f27b3Smrg src_img.buf_type = type; 498e88f27b3Smrg src_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; 499e88f27b3Smrg src_img.color = 0xffffffff; 500e88f27b3Smrg ret = g2d_solid_fill(ctx, &src_img, src_x, src_y, img_w , img_h); 501e88f27b3Smrg if (ret < 0) 502e88f27b3Smrg goto err_free_userptr; 503e88f27b3Smrg 504e88f27b3Smrg src_img.color = 0xff00ff00; 505e88f27b3Smrg ret = g2d_solid_fill(ctx, &src_img, 5, 5, 100, 100); 506e88f27b3Smrg if (ret < 0) 507e88f27b3Smrg goto err_free_userptr; 508e88f27b3Smrg 509e88f27b3Smrg dst_img.width = img_w; 510e88f27b3Smrg dst_img.height = img_h; 511e88f27b3Smrg dst_img.buf_type = G2D_IMGBUF_GEM; 512e88f27b3Smrg dst_img.stride = dst_img.width * 4; 513e88f27b3Smrg dst_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; 514e88f27b3Smrg 515e88f27b3Smrg ret = g2d_copy_with_scale(ctx, &src_img, &dst_img, 5, 5, 100, 100, 516e88f27b3Smrg 100, 100, 200, 200, 0); 517e88f27b3Smrg if (ret < 0) 518e88f27b3Smrg goto err_free_userptr; 519e88f27b3Smrg 520e88f27b3Smrg g2d_exec(ctx); 521e88f27b3Smrg 522e88f27b3Smrgerr_free_userptr: 523e88f27b3Smrg if (type == G2D_IMGBUF_USERPTR) 524e88f27b3Smrg if (userptr) 525e88f27b3Smrg free((void *)userptr); 526e88f27b3Smrg 527e6188e58Smrgfail: 528e88f27b3Smrg g2d_fini(ctx); 529e88f27b3Smrg 53000a23bdaSmrg return ret; 531e88f27b3Smrg} 532e88f27b3Smrg 53300a23bdaSmrg#ifdef EXYNOS_G2D_USERPTR_TEST 534e88f27b3Smrgstatic int g2d_blend_test(struct exynos_device *dev, 535e88f27b3Smrg struct exynos_bo *src, 536e88f27b3Smrg struct exynos_bo *dst, 537e88f27b3Smrg enum e_g2d_buf_type type) 538e88f27b3Smrg{ 539e88f27b3Smrg struct g2d_context *ctx; 540e6188e58Smrg struct g2d_image src_img = {0}, dst_img = {0}; 541e88f27b3Smrg unsigned int src_x, src_y, dst_x, dst_y, img_w, img_h; 542e88f27b3Smrg unsigned long userptr, size; 543e88f27b3Smrg int ret; 544e88f27b3Smrg 545e88f27b3Smrg ctx = g2d_init(dev->fd); 546e88f27b3Smrg if (!ctx) 547e88f27b3Smrg return -EFAULT; 548e88f27b3Smrg 549e88f27b3Smrg dst_img.bo[0] = dst->handle; 550e88f27b3Smrg 551e88f27b3Smrg src_x = 0; 552e88f27b3Smrg src_y = 0; 553e88f27b3Smrg dst_x = 0; 554e88f27b3Smrg dst_y = 0; 555e88f27b3Smrg img_w = screen_width; 556e88f27b3Smrg img_h = screen_height; 557e88f27b3Smrg 558e88f27b3Smrg switch (type) { 559e88f27b3Smrg case G2D_IMGBUF_GEM: 560e88f27b3Smrg src_img.bo[0] = src->handle; 561e88f27b3Smrg break; 562e88f27b3Smrg case G2D_IMGBUF_USERPTR: 563e88f27b3Smrg size = img_w * img_h * 4; 564e88f27b3Smrg 565e88f27b3Smrg userptr = (unsigned long)malloc(size); 566e88f27b3Smrg if (!userptr) { 567e88f27b3Smrg fprintf(stderr, "failed to allocate userptr.\n"); 568d8807b2fSmrg ret = -EFAULT; 569d8807b2fSmrg goto fail; 570e88f27b3Smrg } 571e88f27b3Smrg 572e88f27b3Smrg src_img.user_ptr[0].userptr = userptr; 573e88f27b3Smrg src_img.user_ptr[0].size = size; 574e88f27b3Smrg break; 575e6188e58Smrg case G2D_IMGBUF_COLOR: 576e88f27b3Smrg default: 577e6188e58Smrg ret = -EFAULT; 578e6188e58Smrg goto fail; 579e88f27b3Smrg } 580e88f27b3Smrg 581e88f27b3Smrg printf("blend test with %s.\n", 582e88f27b3Smrg type == G2D_IMGBUF_GEM ? "gem" : "userptr"); 583e88f27b3Smrg 584e88f27b3Smrg src_img.width = img_w; 585e88f27b3Smrg src_img.height = img_h; 586e88f27b3Smrg src_img.stride = src_img.width * 4; 587e88f27b3Smrg src_img.buf_type = type; 588e88f27b3Smrg src_img.select_mode = G2D_SELECT_MODE_NORMAL; 589e88f27b3Smrg src_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; 590e88f27b3Smrg src_img.color = 0xffffffff; 591e88f27b3Smrg ret = g2d_solid_fill(ctx, &src_img, src_x, src_y, img_w, img_h); 592e88f27b3Smrg if (ret < 0) 593e88f27b3Smrg goto err_free_userptr; 594e88f27b3Smrg 595e88f27b3Smrg src_img.color = 0x770000ff; 596e88f27b3Smrg ret = g2d_solid_fill(ctx, &src_img, 5, 5, 200, 200); 597e88f27b3Smrg if (ret < 0) 598e88f27b3Smrg goto err_free_userptr; 599e88f27b3Smrg 600e88f27b3Smrg dst_img.width = img_w; 601e88f27b3Smrg dst_img.height = img_h; 602e88f27b3Smrg dst_img.stride = dst_img.width * 4; 603e88f27b3Smrg dst_img.buf_type = G2D_IMGBUF_GEM; 604e88f27b3Smrg dst_img.select_mode = G2D_SELECT_MODE_NORMAL; 605e88f27b3Smrg dst_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; 606e88f27b3Smrg dst_img.color = 0xffffffff; 607e88f27b3Smrg ret = g2d_solid_fill(ctx, &dst_img, dst_x, dst_y, img_w, img_h); 608e88f27b3Smrg if (ret < 0) 609e88f27b3Smrg goto err_free_userptr; 610e88f27b3Smrg 611e88f27b3Smrg dst_img.color = 0x77ff0000; 612e88f27b3Smrg ret = g2d_solid_fill(ctx, &dst_img, 105, 105, 200, 200); 613e88f27b3Smrg if (ret < 0) 614e88f27b3Smrg goto err_free_userptr; 615e88f27b3Smrg 616e88f27b3Smrg ret = g2d_blend(ctx, &src_img, &dst_img, 5, 5, 105, 105, 200, 200, 617e88f27b3Smrg G2D_OP_OVER); 618e88f27b3Smrg if (ret < 0) 619e88f27b3Smrg goto err_free_userptr; 620e88f27b3Smrg 621e88f27b3Smrg g2d_exec(ctx); 622e88f27b3Smrg 623e88f27b3Smrgerr_free_userptr: 624e88f27b3Smrg if (type == G2D_IMGBUF_USERPTR) 625e88f27b3Smrg if (userptr) 626e88f27b3Smrg free((void *)userptr); 627e88f27b3Smrg 628e6188e58Smrgfail: 629e88f27b3Smrg g2d_fini(ctx); 630e88f27b3Smrg 631d8807b2fSmrg return ret; 632e88f27b3Smrg} 633d8807b2fSmrg#endif 634e88f27b3Smrg 635e6188e58Smrgstatic int g2d_checkerboard_test(struct exynos_device *dev, 636e6188e58Smrg struct exynos_bo *src, 637e6188e58Smrg struct exynos_bo *dst, 638e6188e58Smrg enum e_g2d_buf_type type) 639e6188e58Smrg{ 640e6188e58Smrg struct g2d_context *ctx; 641e6188e58Smrg struct g2d_image src_img = {0}, dst_img = {0}; 642e6188e58Smrg unsigned int src_x, src_y, dst_x, dst_y, img_w, img_h; 643e6188e58Smrg void *checkerboard = NULL; 644e6188e58Smrg int ret; 645e6188e58Smrg 646e6188e58Smrg ctx = g2d_init(dev->fd); 647e6188e58Smrg if (!ctx) 648e6188e58Smrg return -EFAULT; 649e6188e58Smrg 650e6188e58Smrg dst_img.bo[0] = dst->handle; 651e6188e58Smrg 652e6188e58Smrg src_x = 0; 653e6188e58Smrg src_y = 0; 654e6188e58Smrg dst_x = 0; 655e6188e58Smrg dst_y = 0; 656e6188e58Smrg 657e6188e58Smrg checkerboard = create_checkerboard_pattern(screen_width / 32, screen_height / 32, 32); 658d8807b2fSmrg if (!checkerboard) { 659d8807b2fSmrg ret = -EFAULT; 660e6188e58Smrg goto fail; 661e6188e58Smrg } 662e6188e58Smrg 663e6188e58Smrg img_w = screen_width - (screen_width % 32); 664e6188e58Smrg img_h = screen_height - (screen_height % 32); 665e6188e58Smrg 666e6188e58Smrg switch (type) { 667e6188e58Smrg case G2D_IMGBUF_GEM: 668e6188e58Smrg memcpy(src->vaddr, checkerboard, img_w * img_h * 4); 669e6188e58Smrg src_img.bo[0] = src->handle; 670e6188e58Smrg break; 671e6188e58Smrg case G2D_IMGBUF_USERPTR: 672e6188e58Smrg src_img.user_ptr[0].userptr = (unsigned long)checkerboard; 673e6188e58Smrg src_img.user_ptr[0].size = img_w * img_h * 4; 674e6188e58Smrg break; 675e6188e58Smrg case G2D_IMGBUF_COLOR: 676e6188e58Smrg default: 677e6188e58Smrg ret = -EFAULT; 678e6188e58Smrg goto fail; 679e6188e58Smrg } 680e6188e58Smrg 681e6188e58Smrg printf("checkerboard test with %s.\n", 682e6188e58Smrg type == G2D_IMGBUF_GEM ? "gem" : "userptr"); 683e6188e58Smrg 684e6188e58Smrg src_img.width = img_w; 685e6188e58Smrg src_img.height = img_h; 686e6188e58Smrg src_img.stride = src_img.width * 4; 687e6188e58Smrg src_img.buf_type = type; 688e6188e58Smrg src_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; 689e6188e58Smrg 690e6188e58Smrg dst_img.width = screen_width; 691e6188e58Smrg dst_img.height = screen_height; 692e6188e58Smrg dst_img.stride = dst_img.width * 4; 693e6188e58Smrg dst_img.buf_type = G2D_IMGBUF_GEM; 694e6188e58Smrg dst_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; 695e6188e58Smrg src_img.color = 0xff000000; 696e6188e58Smrg ret = g2d_solid_fill(ctx, &dst_img, src_x, src_y, screen_width, screen_height); 697e6188e58Smrg if (ret < 0) 698e6188e58Smrg goto fail; 699e6188e58Smrg 700e6188e58Smrg ret = g2d_copy(ctx, &src_img, &dst_img, src_x, src_y, dst_x, dst_y, 701e6188e58Smrg img_w, img_h); 702e6188e58Smrg if (ret < 0) 703e6188e58Smrg goto fail; 704e6188e58Smrg 705e6188e58Smrg g2d_exec(ctx); 706e6188e58Smrg 707e6188e58Smrgfail: 708e6188e58Smrg free(checkerboard); 709e6188e58Smrg g2d_fini(ctx); 710e6188e58Smrg 711e6188e58Smrg return ret; 712e6188e58Smrg} 713e88f27b3Smrg 714e88f27b3Smrgstatic void usage(char *name) 715e88f27b3Smrg{ 716e88f27b3Smrg fprintf(stderr, "usage: %s [-s]\n", name); 717e88f27b3Smrg fprintf(stderr, "-s <connector_id>@<crtc_id>:<mode>\n"); 718e88f27b3Smrg exit(0); 719e88f27b3Smrg} 720e88f27b3Smrg 721e88f27b3Smrgextern char *optarg; 722e88f27b3Smrgstatic const char optstr[] = "s:"; 723e88f27b3Smrg 724e88f27b3Smrgint main(int argc, char **argv) 725e88f27b3Smrg{ 726e88f27b3Smrg struct exynos_device *dev; 727e88f27b3Smrg struct exynos_bo *bo, *src; 728e88f27b3Smrg struct connector con; 729e88f27b3Smrg unsigned int fb_id; 730e88f27b3Smrg uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0}; 731e88f27b3Smrg drmModeRes *resources; 732e88f27b3Smrg int ret, fd, c; 733e88f27b3Smrg 734e88f27b3Smrg memset(&con, 0, sizeof(struct connector)); 735e88f27b3Smrg 736e88f27b3Smrg if (argc != 3) { 737e88f27b3Smrg usage(argv[0]); 738e88f27b3Smrg return -EINVAL; 739e88f27b3Smrg } 740e88f27b3Smrg 741e88f27b3Smrg while ((c = getopt(argc, argv, optstr)) != -1) { 742e88f27b3Smrg switch (c) { 743e88f27b3Smrg case 's': 744e88f27b3Smrg con.crtc = -1; 745e88f27b3Smrg if (sscanf(optarg, "%d:0x%64s", 746e88f27b3Smrg &con.id, 747e88f27b3Smrg con.mode_str) != 2 && 748e88f27b3Smrg sscanf(optarg, "%d@%d:%64s", 749e88f27b3Smrg &con.id, 750e88f27b3Smrg &con.crtc, 751e88f27b3Smrg con.mode_str) != 3) 752e88f27b3Smrg usage(argv[0]); 753e88f27b3Smrg break; 754e88f27b3Smrg default: 755e88f27b3Smrg usage(argv[0]); 756e6188e58Smrg break; 757e88f27b3Smrg } 758e88f27b3Smrg } 759e88f27b3Smrg 760e88f27b3Smrg fd = drmOpen(DRM_MODULE_NAME, NULL); 761e88f27b3Smrg if (fd < 0) { 762e88f27b3Smrg fprintf(stderr, "failed to open.\n"); 763e88f27b3Smrg return fd; 764e88f27b3Smrg } 765e88f27b3Smrg 766e88f27b3Smrg dev = exynos_device_create(fd); 767e88f27b3Smrg if (!dev) { 768d8807b2fSmrg ret = -EFAULT; 769d8807b2fSmrg goto err_drm_close; 770e88f27b3Smrg } 771e88f27b3Smrg 772e88f27b3Smrg resources = drmModeGetResources(dev->fd); 773e88f27b3Smrg if (!resources) { 774e88f27b3Smrg fprintf(stderr, "drmModeGetResources failed: %s\n", 775e88f27b3Smrg strerror(errno)); 776e88f27b3Smrg ret = -EFAULT; 777d8807b2fSmrg goto err_dev_destory; 778e88f27b3Smrg } 779e88f27b3Smrg 780e88f27b3Smrg connector_find_mode(dev->fd, &con, resources); 781e88f27b3Smrg drmModeFreeResources(resources); 782e88f27b3Smrg 783e6188e58Smrg if (!con.mode) { 784e6188e58Smrg fprintf(stderr, "failed to find usable connector\n"); 785e6188e58Smrg ret = -EFAULT; 786d8807b2fSmrg goto err_dev_destory; 787e6188e58Smrg } 788e6188e58Smrg 789e88f27b3Smrg screen_width = con.mode->hdisplay; 790e88f27b3Smrg screen_height = con.mode->vdisplay; 791e88f27b3Smrg 792e6188e58Smrg if (screen_width == 0 || screen_height == 0) { 793e6188e58Smrg fprintf(stderr, "failed to find sane resolution on connector\n"); 794e6188e58Smrg ret = -EFAULT; 795d8807b2fSmrg goto err_dev_destory; 796e6188e58Smrg } 797e6188e58Smrg 798e6188e58Smrg printf("screen width = %d, screen height = %d\n", screen_width, 799e88f27b3Smrg screen_height); 800e88f27b3Smrg 801e88f27b3Smrg bo = exynos_create_buffer(dev, screen_width * screen_height * 4, 0); 802e88f27b3Smrg if (!bo) { 803e88f27b3Smrg ret = -EFAULT; 804d8807b2fSmrg goto err_dev_destory; 805e88f27b3Smrg } 806e88f27b3Smrg 807e88f27b3Smrg handles[0] = bo->handle; 808e88f27b3Smrg pitches[0] = screen_width * 4; 809e88f27b3Smrg offsets[0] = 0; 810e88f27b3Smrg 811e88f27b3Smrg ret = drmModeAddFB2(dev->fd, screen_width, screen_height, 8123f012e29Smrg DRM_FORMAT_XRGB8888, handles, 813e88f27b3Smrg pitches, offsets, &fb_id, 0); 814e88f27b3Smrg if (ret < 0) 815e88f27b3Smrg goto err_destroy_buffer; 816e88f27b3Smrg 817e88f27b3Smrg memset(bo->vaddr, 0xff, screen_width * screen_height * 4); 818e88f27b3Smrg 819e88f27b3Smrg ret = drm_set_crtc(dev, &con, fb_id); 820e88f27b3Smrg if (ret < 0) 821e88f27b3Smrg goto err_rm_fb; 822e88f27b3Smrg 823e6188e58Smrg ret = g2d_solid_fill_test(dev, bo); 824e88f27b3Smrg if (ret < 0) { 825e88f27b3Smrg fprintf(stderr, "failed to solid fill operation.\n"); 826e88f27b3Smrg goto err_rm_fb; 827e88f27b3Smrg } 828e88f27b3Smrg 829e6188e58Smrg wait_for_user_input(0); 830e88f27b3Smrg 831e88f27b3Smrg src = exynos_create_buffer(dev, screen_width * screen_height * 4, 0); 832e88f27b3Smrg if (!src) { 833e88f27b3Smrg ret = -EFAULT; 834e88f27b3Smrg goto err_rm_fb; 835e88f27b3Smrg } 836e88f27b3Smrg 837e6188e58Smrg ret = g2d_copy_test(dev, src, bo, G2D_IMGBUF_GEM); 838e88f27b3Smrg if (ret < 0) { 839e88f27b3Smrg fprintf(stderr, "failed to test copy operation.\n"); 840e88f27b3Smrg goto err_free_src; 841e88f27b3Smrg } 842e88f27b3Smrg 843e6188e58Smrg wait_for_user_input(0); 844e88f27b3Smrg 8453f012e29Smrg ret = g2d_move_test(dev, src, bo, G2D_IMGBUF_GEM); 8463f012e29Smrg if (ret < 0) { 8473f012e29Smrg fprintf(stderr, "failed to test move operation.\n"); 8483f012e29Smrg goto err_free_src; 8493f012e29Smrg } 8503f012e29Smrg 8513f012e29Smrg wait_for_user_input(0); 8523f012e29Smrg 853e6188e58Smrg ret = g2d_copy_with_scale_test(dev, src, bo, G2D_IMGBUF_GEM); 854e88f27b3Smrg if (ret < 0) { 855e88f27b3Smrg fprintf(stderr, "failed to test copy and scale operation.\n"); 856e88f27b3Smrg goto err_free_src; 857e88f27b3Smrg } 858e88f27b3Smrg 859e6188e58Smrg wait_for_user_input(0); 860e88f27b3Smrg 861e6188e58Smrg ret = g2d_checkerboard_test(dev, src, bo, G2D_IMGBUF_GEM); 862e6188e58Smrg if (ret < 0) { 863e6188e58Smrg fprintf(stderr, "failed to issue checkerboard test.\n"); 864e6188e58Smrg goto err_free_src; 865e6188e58Smrg } 866e6188e58Smrg 867e6188e58Smrg wait_for_user_input(1); 868e6188e58Smrg 869e6188e58Smrg /* 870e6188e58Smrg * The blend test uses the userptr functionality of exynos-drm, which 871e6188e58Smrg * is currently not safe to use. If the kernel hasn't been build with 872e6188e58Smrg * exynos-iommu support, then the blend test is going to produce (kernel) 873e6188e58Smrg * memory corruption, eventually leading to a system crash. 874e6188e58Smrg * 875e6188e58Smrg * Disable the test for now, until the kernel code has been sanitized. 876e6188e58Smrg */ 87700a23bdaSmrg#ifdef EXYNOS_G2D_USERPTR_TEST 878e6188e58Smrg ret = g2d_blend_test(dev, src, bo, G2D_IMGBUF_USERPTR); 879e88f27b3Smrg if (ret < 0) 880e88f27b3Smrg fprintf(stderr, "failed to test blend operation.\n"); 881e88f27b3Smrg 882e88f27b3Smrg getchar(); 883e6188e58Smrg#endif 884e88f27b3Smrg 885e88f27b3Smrgerr_free_src: 886e88f27b3Smrg if (src) 887e88f27b3Smrg exynos_destroy_buffer(src); 888e88f27b3Smrg 889e88f27b3Smrgerr_rm_fb: 890baaff307Smrg drmModeRmFB(dev->fd, fb_id); 891e88f27b3Smrg 892e88f27b3Smrgerr_destroy_buffer: 893e88f27b3Smrg exynos_destroy_buffer(bo); 894e88f27b3Smrg 895d8807b2fSmrgerr_dev_destory: 896e88f27b3Smrg exynos_device_destroy(dev); 897e88f27b3Smrg 898d8807b2fSmrgerr_drm_close: 899d8807b2fSmrg drmClose(fd); 900d8807b2fSmrg 901d8807b2fSmrg return ret; 902e88f27b3Smrg} 903