1d722e3fbSopenharmony_ci/* 2d722e3fbSopenharmony_ci * Copyright (C) 2015 - Tobias Jakobi 3d722e3fbSopenharmony_ci * 4d722e3fbSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5d722e3fbSopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6d722e3fbSopenharmony_ci * to deal in the Software without restriction, including without limitation 7d722e3fbSopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8d722e3fbSopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 9d722e3fbSopenharmony_ci * Software is furnished to do so, subject to the following conditions: 10d722e3fbSopenharmony_ci * 11d722e3fbSopenharmony_ci * The above copyright notice and this permission notice (including the next 12d722e3fbSopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13d722e3fbSopenharmony_ci * Software. 14d722e3fbSopenharmony_ci * 15d722e3fbSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16d722e3fbSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17d722e3fbSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18d722e3fbSopenharmony_ci * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 19d722e3fbSopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20d722e3fbSopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 21d722e3fbSopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE. 22d722e3fbSopenharmony_ci */ 23d722e3fbSopenharmony_ci 24d722e3fbSopenharmony_ci#include <unistd.h> 25d722e3fbSopenharmony_ci#include <poll.h> 26d722e3fbSopenharmony_ci 27d722e3fbSopenharmony_ci#include <stdlib.h> 28d722e3fbSopenharmony_ci#include <stdio.h> 29d722e3fbSopenharmony_ci#include <time.h> 30d722e3fbSopenharmony_ci#include <getopt.h> 31d722e3fbSopenharmony_ci 32d722e3fbSopenharmony_ci#include <pthread.h> 33d722e3fbSopenharmony_ci 34d722e3fbSopenharmony_ci#include <xf86drm.h> 35d722e3fbSopenharmony_ci 36d722e3fbSopenharmony_ci#include "exynos_drm.h" 37d722e3fbSopenharmony_ci#include "exynos_drmif.h" 38d722e3fbSopenharmony_ci#include "exynos_fimg2d.h" 39d722e3fbSopenharmony_ci 40d722e3fbSopenharmony_cistruct g2d_job { 41d722e3fbSopenharmony_ci unsigned int id; 42d722e3fbSopenharmony_ci unsigned int busy; 43d722e3fbSopenharmony_ci}; 44d722e3fbSopenharmony_ci 45d722e3fbSopenharmony_cistruct exynos_evhandler { 46d722e3fbSopenharmony_ci struct pollfd fds; 47d722e3fbSopenharmony_ci struct exynos_event_context evctx; 48d722e3fbSopenharmony_ci}; 49d722e3fbSopenharmony_ci 50d722e3fbSopenharmony_cistruct threaddata { 51d722e3fbSopenharmony_ci unsigned int stop; 52d722e3fbSopenharmony_ci struct exynos_device *dev; 53d722e3fbSopenharmony_ci struct exynos_evhandler evhandler; 54d722e3fbSopenharmony_ci}; 55d722e3fbSopenharmony_ci 56d722e3fbSopenharmony_cistatic void g2d_event_handler(int fd, unsigned int cmdlist_no, unsigned int tv_sec, 57d722e3fbSopenharmony_ci unsigned int tv_usec, void *user_data) 58d722e3fbSopenharmony_ci{ 59d722e3fbSopenharmony_ci struct g2d_job *job = user_data; 60d722e3fbSopenharmony_ci 61d722e3fbSopenharmony_ci fprintf(stderr, "info: g2d job (id = %u, cmdlist number = %u) finished!\n", 62d722e3fbSopenharmony_ci job->id, cmdlist_no); 63d722e3fbSopenharmony_ci 64d722e3fbSopenharmony_ci job->busy = 0; 65d722e3fbSopenharmony_ci} 66d722e3fbSopenharmony_ci 67d722e3fbSopenharmony_cistatic void setup_g2d_event_handler(struct exynos_evhandler *evhandler, int fd) 68d722e3fbSopenharmony_ci{ 69d722e3fbSopenharmony_ci evhandler->fds.fd = fd; 70d722e3fbSopenharmony_ci evhandler->fds.events = POLLIN; 71d722e3fbSopenharmony_ci evhandler->evctx.base.version = 2; 72d722e3fbSopenharmony_ci evhandler->evctx.version = 1; 73d722e3fbSopenharmony_ci evhandler->evctx.g2d_event_handler = g2d_event_handler; 74d722e3fbSopenharmony_ci} 75d722e3fbSopenharmony_ci 76d722e3fbSopenharmony_cistatic void* threadfunc(void *arg) { 77d722e3fbSopenharmony_ci const int timeout = 0; 78d722e3fbSopenharmony_ci struct threaddata *data; 79d722e3fbSopenharmony_ci 80d722e3fbSopenharmony_ci data = arg; 81d722e3fbSopenharmony_ci 82d722e3fbSopenharmony_ci while (1) { 83d722e3fbSopenharmony_ci if (data->stop) break; 84d722e3fbSopenharmony_ci 85d722e3fbSopenharmony_ci usleep(500); 86d722e3fbSopenharmony_ci 87d722e3fbSopenharmony_ci data->evhandler.fds.revents = 0; 88d722e3fbSopenharmony_ci 89d722e3fbSopenharmony_ci if (poll(&data->evhandler.fds, 1, timeout) < 0) 90d722e3fbSopenharmony_ci continue; 91d722e3fbSopenharmony_ci 92d722e3fbSopenharmony_ci if (data->evhandler.fds.revents & (POLLHUP | POLLERR)) 93d722e3fbSopenharmony_ci continue; 94d722e3fbSopenharmony_ci 95d722e3fbSopenharmony_ci if (data->evhandler.fds.revents & POLLIN) 96d722e3fbSopenharmony_ci exynos_handle_event(data->dev, &data->evhandler.evctx); 97d722e3fbSopenharmony_ci } 98d722e3fbSopenharmony_ci 99d722e3fbSopenharmony_ci pthread_exit(0); 100d722e3fbSopenharmony_ci} 101d722e3fbSopenharmony_ci 102d722e3fbSopenharmony_ci/* 103d722e3fbSopenharmony_ci * We need to wait until all G2D jobs are finished, otherwise we 104d722e3fbSopenharmony_ci * potentially remove a BO which the engine still operates on. 105d722e3fbSopenharmony_ci * This results in the following kernel message: 106d722e3fbSopenharmony_ci * [drm:exynos_drm_gem_put_dma_addr] *ERROR* failed to lookup gem object. 107d722e3fbSopenharmony_ci * Also any subsequent BO allocations fail then with: 108d722e3fbSopenharmony_ci * [drm:exynos_drm_alloc_buf] *ERROR* failed to allocate buffer. 109d722e3fbSopenharmony_ci */ 110d722e3fbSopenharmony_cistatic void wait_all_jobs(struct g2d_job* jobs, unsigned num_jobs) 111d722e3fbSopenharmony_ci{ 112d722e3fbSopenharmony_ci unsigned i; 113d722e3fbSopenharmony_ci 114d722e3fbSopenharmony_ci for (i = 0; i < num_jobs; ++i) { 115d722e3fbSopenharmony_ci while (jobs[i].busy) 116d722e3fbSopenharmony_ci usleep(500); 117d722e3fbSopenharmony_ci } 118d722e3fbSopenharmony_ci 119d722e3fbSopenharmony_ci} 120d722e3fbSopenharmony_ci 121d722e3fbSopenharmony_cistatic struct g2d_job* free_job(struct g2d_job* jobs, unsigned num_jobs) 122d722e3fbSopenharmony_ci{ 123d722e3fbSopenharmony_ci unsigned i; 124d722e3fbSopenharmony_ci 125d722e3fbSopenharmony_ci for (i = 0; i < num_jobs; ++i) { 126d722e3fbSopenharmony_ci if (jobs[i].busy == 0) 127d722e3fbSopenharmony_ci return &jobs[i]; 128d722e3fbSopenharmony_ci } 129d722e3fbSopenharmony_ci 130d722e3fbSopenharmony_ci return NULL; 131d722e3fbSopenharmony_ci} 132d722e3fbSopenharmony_ci 133d722e3fbSopenharmony_cistatic int g2d_work(struct g2d_context *ctx, struct g2d_image *img, 134d722e3fbSopenharmony_ci unsigned num_jobs, unsigned iterations) 135d722e3fbSopenharmony_ci{ 136d722e3fbSopenharmony_ci struct g2d_job *jobs = calloc(num_jobs, sizeof(struct g2d_job)); 137d722e3fbSopenharmony_ci int ret; 138d722e3fbSopenharmony_ci unsigned i; 139d722e3fbSopenharmony_ci 140d722e3fbSopenharmony_ci /* setup job ids */ 141d722e3fbSopenharmony_ci for (i = 0; i < num_jobs; ++i) 142d722e3fbSopenharmony_ci jobs[i].id = i; 143d722e3fbSopenharmony_ci 144d722e3fbSopenharmony_ci for (i = 0; i < iterations; ++i) { 145d722e3fbSopenharmony_ci unsigned x, y, w, h; 146d722e3fbSopenharmony_ci 147d722e3fbSopenharmony_ci struct g2d_job *j = NULL; 148d722e3fbSopenharmony_ci 149d722e3fbSopenharmony_ci while (1) { 150d722e3fbSopenharmony_ci j = free_job(jobs, num_jobs); 151d722e3fbSopenharmony_ci 152d722e3fbSopenharmony_ci if (j) 153d722e3fbSopenharmony_ci break; 154d722e3fbSopenharmony_ci else 155d722e3fbSopenharmony_ci usleep(500); 156d722e3fbSopenharmony_ci } 157d722e3fbSopenharmony_ci 158d722e3fbSopenharmony_ci x = rand() % img->width; 159d722e3fbSopenharmony_ci y = rand() % img->height; 160d722e3fbSopenharmony_ci 161d722e3fbSopenharmony_ci if (x == (img->width - 1)) 162d722e3fbSopenharmony_ci x -= 1; 163d722e3fbSopenharmony_ci if (y == (img->height - 1)) 164d722e3fbSopenharmony_ci y -= 1; 165d722e3fbSopenharmony_ci 166d722e3fbSopenharmony_ci w = rand() % (img->width - x); 167d722e3fbSopenharmony_ci h = rand() % (img->height - y); 168d722e3fbSopenharmony_ci 169d722e3fbSopenharmony_ci if (w == 0) w = 1; 170d722e3fbSopenharmony_ci if (h == 0) h = 1; 171d722e3fbSopenharmony_ci 172d722e3fbSopenharmony_ci img->color = rand(); 173d722e3fbSopenharmony_ci 174d722e3fbSopenharmony_ci j->busy = 1; 175d722e3fbSopenharmony_ci g2d_config_event(ctx, j); 176d722e3fbSopenharmony_ci 177d722e3fbSopenharmony_ci ret = g2d_solid_fill(ctx, img, x, y, w, h); 178d722e3fbSopenharmony_ci 179d722e3fbSopenharmony_ci if (ret == 0) 180d722e3fbSopenharmony_ci g2d_exec(ctx); 181d722e3fbSopenharmony_ci 182d722e3fbSopenharmony_ci if (ret != 0) { 183d722e3fbSopenharmony_ci fprintf(stderr, "error: iteration %u (x = %u, x = %u, x = %u, x = %u) failed\n", 184d722e3fbSopenharmony_ci i, x, y, w, h); 185d722e3fbSopenharmony_ci break; 186d722e3fbSopenharmony_ci } 187d722e3fbSopenharmony_ci } 188d722e3fbSopenharmony_ci 189d722e3fbSopenharmony_ci wait_all_jobs(jobs, num_jobs); 190d722e3fbSopenharmony_ci free(jobs); 191d722e3fbSopenharmony_ci 192d722e3fbSopenharmony_ci return 0; 193d722e3fbSopenharmony_ci} 194d722e3fbSopenharmony_ci 195d722e3fbSopenharmony_cistatic void usage(const char *name) 196d722e3fbSopenharmony_ci{ 197d722e3fbSopenharmony_ci fprintf(stderr, "usage: %s [-ijwh]\n\n", name); 198d722e3fbSopenharmony_ci 199d722e3fbSopenharmony_ci fprintf(stderr, "\t-i <number of iterations>\n"); 200d722e3fbSopenharmony_ci fprintf(stderr, "\t-j <number of G2D jobs> (default = 4)\n\n"); 201d722e3fbSopenharmony_ci 202d722e3fbSopenharmony_ci fprintf(stderr, "\t-w <buffer width> (default = 4096)\n"); 203d722e3fbSopenharmony_ci fprintf(stderr, "\t-h <buffer height> (default = 4096)\n"); 204d722e3fbSopenharmony_ci 205d722e3fbSopenharmony_ci exit(0); 206d722e3fbSopenharmony_ci} 207d722e3fbSopenharmony_ci 208d722e3fbSopenharmony_ciint main(int argc, char **argv) 209d722e3fbSopenharmony_ci{ 210d722e3fbSopenharmony_ci int fd, ret, c, parsefail; 211d722e3fbSopenharmony_ci 212d722e3fbSopenharmony_ci pthread_t event_thread; 213d722e3fbSopenharmony_ci struct threaddata event_data = {0}; 214d722e3fbSopenharmony_ci 215d722e3fbSopenharmony_ci struct exynos_device *dev; 216d722e3fbSopenharmony_ci struct g2d_context *ctx; 217d722e3fbSopenharmony_ci struct exynos_bo *bo; 218d722e3fbSopenharmony_ci 219d722e3fbSopenharmony_ci struct g2d_image img = {0}; 220d722e3fbSopenharmony_ci 221d722e3fbSopenharmony_ci unsigned int iters = 0, njobs = 4; 222d722e3fbSopenharmony_ci unsigned int bufw = 4096, bufh = 4096; 223d722e3fbSopenharmony_ci 224d722e3fbSopenharmony_ci ret = 0; 225d722e3fbSopenharmony_ci parsefail = 0; 226d722e3fbSopenharmony_ci 227d722e3fbSopenharmony_ci while ((c = getopt(argc, argv, "i:j:w:h:")) != -1) { 228d722e3fbSopenharmony_ci switch (c) { 229d722e3fbSopenharmony_ci case 'i': 230d722e3fbSopenharmony_ci if (sscanf(optarg, "%u", &iters) != 1) 231d722e3fbSopenharmony_ci parsefail = 1; 232d722e3fbSopenharmony_ci break; 233d722e3fbSopenharmony_ci case 'j': 234d722e3fbSopenharmony_ci if (sscanf(optarg, "%u", &njobs) != 1) 235d722e3fbSopenharmony_ci parsefail = 1; 236d722e3fbSopenharmony_ci break; 237d722e3fbSopenharmony_ci case 'w': 238d722e3fbSopenharmony_ci if (sscanf(optarg, "%u", &bufw) != 1) 239d722e3fbSopenharmony_ci parsefail = 1; 240d722e3fbSopenharmony_ci break; 241d722e3fbSopenharmony_ci case 'h': 242d722e3fbSopenharmony_ci if (sscanf(optarg, "%u", &bufh) != 1) 243d722e3fbSopenharmony_ci parsefail = 1; 244d722e3fbSopenharmony_ci break; 245d722e3fbSopenharmony_ci default: 246d722e3fbSopenharmony_ci parsefail = 1; 247d722e3fbSopenharmony_ci break; 248d722e3fbSopenharmony_ci } 249d722e3fbSopenharmony_ci } 250d722e3fbSopenharmony_ci 251d722e3fbSopenharmony_ci if (parsefail || (argc == 1) || (iters == 0)) 252d722e3fbSopenharmony_ci usage(argv[0]); 253d722e3fbSopenharmony_ci 254d722e3fbSopenharmony_ci if (bufw > 4096 || bufh > 4096) { 255d722e3fbSopenharmony_ci fprintf(stderr, "error: buffer width/height should be less than 4096.\n"); 256d722e3fbSopenharmony_ci ret = -1; 257d722e3fbSopenharmony_ci 258d722e3fbSopenharmony_ci goto out; 259d722e3fbSopenharmony_ci } 260d722e3fbSopenharmony_ci 261d722e3fbSopenharmony_ci if (bufw == 0 || bufh == 0) { 262d722e3fbSopenharmony_ci fprintf(stderr, "error: buffer width/height should be non-zero.\n"); 263d722e3fbSopenharmony_ci ret = -1; 264d722e3fbSopenharmony_ci 265d722e3fbSopenharmony_ci goto out; 266d722e3fbSopenharmony_ci } 267d722e3fbSopenharmony_ci 268d722e3fbSopenharmony_ci fd = drmOpen("exynos", NULL); 269d722e3fbSopenharmony_ci if (fd < 0) { 270d722e3fbSopenharmony_ci fprintf(stderr, "error: failed to open drm\n"); 271d722e3fbSopenharmony_ci ret = -1; 272d722e3fbSopenharmony_ci 273d722e3fbSopenharmony_ci goto out; 274d722e3fbSopenharmony_ci } 275d722e3fbSopenharmony_ci 276d722e3fbSopenharmony_ci dev = exynos_device_create(fd); 277d722e3fbSopenharmony_ci if (dev == NULL) { 278d722e3fbSopenharmony_ci fprintf(stderr, "error: failed to create device\n"); 279d722e3fbSopenharmony_ci ret = -2; 280d722e3fbSopenharmony_ci 281d722e3fbSopenharmony_ci goto fail; 282d722e3fbSopenharmony_ci } 283d722e3fbSopenharmony_ci 284d722e3fbSopenharmony_ci ctx = g2d_init(fd); 285d722e3fbSopenharmony_ci if (ctx == NULL) { 286d722e3fbSopenharmony_ci fprintf(stderr, "error: failed to init G2D\n"); 287d722e3fbSopenharmony_ci ret = -3; 288d722e3fbSopenharmony_ci 289d722e3fbSopenharmony_ci goto g2d_fail; 290d722e3fbSopenharmony_ci } 291d722e3fbSopenharmony_ci 292d722e3fbSopenharmony_ci bo = exynos_bo_create(dev, bufw * bufh * 4, 0); 293d722e3fbSopenharmony_ci if (bo == NULL) { 294d722e3fbSopenharmony_ci fprintf(stderr, "error: failed to create bo\n"); 295d722e3fbSopenharmony_ci ret = -4; 296d722e3fbSopenharmony_ci 297d722e3fbSopenharmony_ci goto bo_fail; 298d722e3fbSopenharmony_ci } 299d722e3fbSopenharmony_ci 300d722e3fbSopenharmony_ci /* setup g2d image object */ 301d722e3fbSopenharmony_ci img.width = bufw; 302d722e3fbSopenharmony_ci img.height = bufh; 303d722e3fbSopenharmony_ci img.stride = bufw * 4; 304d722e3fbSopenharmony_ci img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; 305d722e3fbSopenharmony_ci img.buf_type = G2D_IMGBUF_GEM; 306d722e3fbSopenharmony_ci img.bo[0] = bo->handle; 307d722e3fbSopenharmony_ci 308d722e3fbSopenharmony_ci event_data.dev = dev; 309d722e3fbSopenharmony_ci setup_g2d_event_handler(&event_data.evhandler, fd); 310d722e3fbSopenharmony_ci 311d722e3fbSopenharmony_ci pthread_create(&event_thread, NULL, threadfunc, &event_data); 312d722e3fbSopenharmony_ci 313d722e3fbSopenharmony_ci ret = g2d_work(ctx, &img, njobs, iters); 314d722e3fbSopenharmony_ci if (ret != 0) 315d722e3fbSopenharmony_ci fprintf(stderr, "error: g2d_work failed\n"); 316d722e3fbSopenharmony_ci 317d722e3fbSopenharmony_ci event_data.stop = 1; 318d722e3fbSopenharmony_ci pthread_join(event_thread, NULL); 319d722e3fbSopenharmony_ci 320d722e3fbSopenharmony_ci exynos_bo_destroy(bo); 321d722e3fbSopenharmony_ci 322d722e3fbSopenharmony_cibo_fail: 323d722e3fbSopenharmony_ci g2d_fini(ctx); 324d722e3fbSopenharmony_ci 325d722e3fbSopenharmony_cig2d_fail: 326d722e3fbSopenharmony_ci exynos_device_destroy(dev); 327d722e3fbSopenharmony_ci 328d722e3fbSopenharmony_cifail: 329d722e3fbSopenharmony_ci drmClose(fd); 330d722e3fbSopenharmony_ci 331d722e3fbSopenharmony_ciout: 332d722e3fbSopenharmony_ci return ret; 333d722e3fbSopenharmony_ci} 334