exynos_fimg2d_test.c revision baaff307
1/* 2 * Copyright (C) 2013 Samsung Electronics Co.Ltd 3 * Authors: 4 * Inki Dae <inki.dae@samsung.com> 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License as published by the 8 * Free Software Foundation; either version 2 of the License, or (at your 9 * option) any later version. 10 * 11 */ 12 13#ifdef HAVE_CONFIG_H 14#include "config.h" 15#endif 16 17#include <stdlib.h> 18#include <stdio.h> 19#include <string.h> 20#include <errno.h> 21 22#include <sys/mman.h> 23#include <linux/stddef.h> 24 25#include <xf86drm.h> 26#include <xf86drmMode.h> 27#include <libkms.h> 28#include <drm_fourcc.h> 29 30#include "exynos_drm.h" 31#include "exynos_drmif.h" 32#include "fimg2d.h" 33 34#define DRM_MODULE_NAME "exynos" 35#define MAX_TEST_CASE 8 36 37static unsigned int screen_width, screen_height; 38 39/* 40 * A structure to test fimg2d hw. 41 * 42 * @solid_fild: fill given color data to source buffer. 43 * @copy: copy source to destination buffer. 44 * @copy_with_scale: copy source to destination buffer scaling up or 45 * down properly. 46 * @blend: blend source to destination buffer. 47 */ 48struct fimg2d_test_case { 49 int (*solid_fill)(struct exynos_device *dev, struct exynos_bo *dst); 50 int (*copy)(struct exynos_device *dev, struct exynos_bo *src, 51 struct exynos_bo *dst, enum e_g2d_buf_type); 52 int (*copy_with_scale)(struct exynos_device *dev, 53 struct exynos_bo *src, struct exynos_bo *dst, 54 enum e_g2d_buf_type); 55 int (*blend)(struct exynos_device *dev, 56 struct exynos_bo *src, struct exynos_bo *dst, 57 enum e_g2d_buf_type); 58}; 59 60struct connector { 61 uint32_t id; 62 char mode_str[64]; 63 char format_str[5]; 64 unsigned int fourcc; 65 drmModeModeInfo *mode; 66 drmModeEncoder *encoder; 67 int crtc; 68 int pipe; 69 int plane_zpos; 70 unsigned int fb_id[2], current_fb_id; 71 struct timeval start; 72 73 int swap_count; 74}; 75 76static void connector_find_mode(int fd, struct connector *c, 77 drmModeRes *resources) 78{ 79 drmModeConnector *connector; 80 int i, j; 81 82 /* First, find the connector & mode */ 83 c->mode = NULL; 84 for (i = 0; i < resources->count_connectors; i++) { 85 connector = drmModeGetConnector(fd, resources->connectors[i]); 86 87 if (!connector) { 88 fprintf(stderr, "could not get connector %i: %s\n", 89 resources->connectors[i], strerror(errno)); 90 drmModeFreeConnector(connector); 91 continue; 92 } 93 94 if (!connector->count_modes) { 95 drmModeFreeConnector(connector); 96 continue; 97 } 98 99 if (connector->connector_id != c->id) { 100 drmModeFreeConnector(connector); 101 continue; 102 } 103 104 for (j = 0; j < connector->count_modes; j++) { 105 c->mode = &connector->modes[j]; 106 if (!strcmp(c->mode->name, c->mode_str)) 107 break; 108 } 109 110 /* Found it, break out */ 111 if (c->mode) 112 break; 113 114 drmModeFreeConnector(connector); 115 } 116 117 if (!c->mode) { 118 fprintf(stderr, "failed to find mode \"%s\"\n", c->mode_str); 119 return; 120 } 121 122 /* Now get the encoder */ 123 for (i = 0; i < resources->count_encoders; i++) { 124 c->encoder = drmModeGetEncoder(fd, resources->encoders[i]); 125 126 if (!c->encoder) { 127 fprintf(stderr, "could not get encoder %i: %s\n", 128 resources->encoders[i], strerror(errno)); 129 drmModeFreeEncoder(c->encoder); 130 continue; 131 } 132 133 if (c->encoder->encoder_id == connector->encoder_id) 134 break; 135 136 drmModeFreeEncoder(c->encoder); 137 } 138 139 if (c->crtc == -1) 140 c->crtc = c->encoder->crtc_id; 141} 142 143static int connector_find_plane(int fd, unsigned int *plane_id) 144{ 145 drmModePlaneRes *plane_resources; 146 drmModePlane *ovr; 147 int i; 148 149 plane_resources = drmModeGetPlaneResources(fd); 150 if (!plane_resources) { 151 fprintf(stderr, "drmModeGetPlaneResources failed: %s\n", 152 strerror(errno)); 153 return -1; 154 } 155 156 for (i = 0; i < plane_resources->count_planes; i++) { 157 plane_id[i] = 0; 158 159 ovr = drmModeGetPlane(fd, plane_resources->planes[i]); 160 if (!ovr) { 161 fprintf(stderr, "drmModeGetPlane failed: %s\n", 162 strerror(errno)); 163 continue; 164 } 165 166 if (ovr->possible_crtcs & (1 << 0)) 167 plane_id[i] = ovr->plane_id; 168 drmModeFreePlane(ovr); 169 } 170 171 return 0; 172} 173 174static int drm_set_crtc(struct exynos_device *dev, struct connector *c, 175 unsigned int fb_id) 176{ 177 int ret; 178 179 ret = drmModeSetCrtc(dev->fd, c->crtc, 180 fb_id, 0, 0, &c->id, 1, c->mode); 181 if (ret) { 182 drmMsg("failed to set mode: %s\n", strerror(errno)); 183 goto err; 184 } 185 186 return 0; 187 188err: 189 return ret; 190} 191 192static struct exynos_bo *exynos_create_buffer(struct exynos_device *dev, 193 unsigned long size, 194 unsigned int flags) 195{ 196 struct exynos_bo *bo; 197 198 bo = exynos_bo_create(dev, size, flags); 199 if (!bo) 200 return bo; 201 202 if (!exynos_bo_map(bo)) { 203 exynos_bo_destroy(bo); 204 return NULL; 205 } 206 207 return bo; 208} 209 210static void exynos_destroy_buffer(struct exynos_bo *bo) 211{ 212 exynos_bo_destroy(bo); 213} 214 215static int g2d_solid_fill_test(struct exynos_device *dev, struct exynos_bo *dst) 216{ 217 struct g2d_context *ctx; 218 struct g2d_image img; 219 unsigned int count, img_w, img_h; 220 int ret = 0; 221 222 ctx = g2d_init(dev->fd); 223 if (!ctx) 224 return -EFAULT; 225 226 memset(&img, 0, sizeof(struct g2d_image)); 227 img.bo[0] = dst->handle; 228 229 printf("soild fill test.\n"); 230 231 srand(time(NULL)); 232 img_w = screen_width; 233 img_h = screen_height; 234 235 for (count = 0; count < 2; count++) { 236 unsigned int x, y, w, h; 237 238 x = rand() % (img_w / 2); 239 y = rand() % (img_h / 2); 240 w = rand() % (img_w - x); 241 h = rand() % (img_h - y); 242 243 img.width = img_w; 244 img.height = img_h; 245 img.stride = img.width * 4; 246 img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; 247 img.color = 0xff000000 + (random() & 0xffffff); 248 249 ret = g2d_solid_fill(ctx, &img, x, y, w, h); 250 if (ret < 0) 251 goto err_fini; 252 253 ret = g2d_exec(ctx); 254 if (ret < 0) 255 break; 256 } 257 258err_fini: 259 g2d_fini(ctx); 260 261 return ret; 262} 263 264static int g2d_copy_test(struct exynos_device *dev, struct exynos_bo *src, 265 struct exynos_bo *dst, 266 enum e_g2d_buf_type type) 267{ 268 struct g2d_context *ctx; 269 struct g2d_image src_img, dst_img; 270 unsigned int count; 271 unsigned int src_x, src_y, dst_x, dst_y, img_w, img_h; 272 unsigned long userptr, size; 273 int ret; 274 275 ctx = g2d_init(dev->fd); 276 if (!ctx) 277 return -EFAULT; 278 279 memset(&src_img, 0, sizeof(struct g2d_image)); 280 memset(&dst_img, 0, sizeof(struct g2d_image)); 281 dst_img.bo[0] = dst->handle; 282 283 src_x = 0; 284 src_y = 0; 285 dst_x = 0; 286 dst_y = 0; 287 img_w = screen_width; 288 img_h = screen_height; 289 290 switch (type) { 291 case G2D_IMGBUF_GEM: 292 src_img.bo[0] = src->handle; 293 break; 294 case G2D_IMGBUF_USERPTR: 295 size = img_w * img_h * 4; 296 297 userptr = (unsigned long)malloc(size); 298 if (!userptr) { 299 fprintf(stderr, "failed to allocate userptr.\n"); 300 return -EFAULT; 301 } 302 303 src_img.user_ptr[0].userptr = userptr; 304 src_img.user_ptr[0].size = size; 305 break; 306 default: 307 type = G2D_IMGBUF_GEM; 308 break; 309 } 310 311 printf("copy test with %s.\n", 312 type == G2D_IMGBUF_GEM ? "gem" : "userptr"); 313 314 src_img.width = img_w; 315 src_img.height = img_h; 316 src_img.stride = src_img.width * 4; 317 src_img.buf_type = type; 318 src_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; 319 src_img.color = 0xffff0000; 320 ret = g2d_solid_fill(ctx, &src_img, src_x, src_y, img_w, img_h); 321 if (ret < 0) 322 goto err_free_userptr; 323 324 dst_img.width = img_w; 325 dst_img.height = img_h; 326 dst_img.stride = dst_img.width * 4; 327 dst_img.buf_type = G2D_IMGBUF_GEM; 328 dst_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; 329 330 ret = g2d_copy(ctx, &src_img, &dst_img, src_x, src_y, dst_x, dst_y, 331 img_w - 4, img_h - 4); 332 if (ret < 0) 333 goto err_free_userptr; 334 335 g2d_exec(ctx); 336 337err_free_userptr: 338 if (type == G2D_IMGBUF_USERPTR) 339 if (userptr) 340 free((void *)userptr); 341 342 g2d_fini(ctx); 343 344 return ret; 345} 346 347static int g2d_copy_with_scale_test(struct exynos_device *dev, 348 struct exynos_bo *src, 349 struct exynos_bo *dst, 350 enum e_g2d_buf_type type) 351{ 352 struct g2d_context *ctx; 353 struct g2d_image src_img, dst_img; 354 unsigned int count; 355 unsigned int src_x, src_y, dst_x, dst_y, img_w, img_h; 356 unsigned long userptr, size; 357 int ret; 358 359 ctx = g2d_init(dev->fd); 360 if (!ctx) 361 return -EFAULT; 362 363 memset(&src_img, 0, sizeof(struct g2d_image)); 364 memset(&dst_img, 0, sizeof(struct g2d_image)); 365 dst_img.bo[0] = dst->handle; 366 367 src_x = 0; 368 src_y = 0; 369 dst_x = 0; 370 dst_y = 0; 371 img_w = screen_width; 372 img_h = screen_height; 373 374 switch (type) { 375 case G2D_IMGBUF_GEM: 376 src_img.bo[0] = src->handle; 377 break; 378 case G2D_IMGBUF_USERPTR: 379 size = img_w * img_h * 4; 380 381 userptr = (unsigned long)malloc(size); 382 if (!userptr) { 383 fprintf(stderr, "failed to allocate userptr.\n"); 384 return -EFAULT; 385 } 386 387 src_img.user_ptr[0].userptr = userptr; 388 src_img.user_ptr[0].size = size; 389 break; 390 default: 391 type = G2D_IMGBUF_GEM; 392 break; 393 } 394 395 printf("copy and scale test with %s.\n", 396 type == G2D_IMGBUF_GEM ? "gem" : "userptr"); 397 398 src_img.width = img_w; 399 src_img.height = img_h; 400 src_img.stride = src_img.width * 4; 401 src_img.buf_type = type; 402 src_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; 403 src_img.color = 0xffffffff; 404 ret = g2d_solid_fill(ctx, &src_img, src_x, src_y, img_w , img_h); 405 if (ret < 0) 406 goto err_free_userptr; 407 408 src_img.color = 0xff00ff00; 409 ret = g2d_solid_fill(ctx, &src_img, 5, 5, 100, 100); 410 if (ret < 0) 411 goto err_free_userptr; 412 413 dst_img.width = img_w; 414 dst_img.height = img_h; 415 dst_img.buf_type = G2D_IMGBUF_GEM; 416 dst_img.stride = dst_img.width * 4; 417 dst_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; 418 419 ret = g2d_copy_with_scale(ctx, &src_img, &dst_img, 5, 5, 100, 100, 420 100, 100, 200, 200, 0); 421 if (ret < 0) 422 goto err_free_userptr; 423 424 g2d_exec(ctx); 425 426err_free_userptr: 427 if (type == G2D_IMGBUF_USERPTR) 428 if (userptr) 429 free((void *)userptr); 430 431 g2d_fini(ctx); 432 433 return 0; 434} 435 436static int g2d_blend_test(struct exynos_device *dev, 437 struct exynos_bo *src, 438 struct exynos_bo *dst, 439 enum e_g2d_buf_type type) 440{ 441 struct g2d_context *ctx; 442 struct g2d_image src_img, dst_img; 443 unsigned int count; 444 unsigned int src_x, src_y, dst_x, dst_y, img_w, img_h; 445 unsigned long userptr, size; 446 int ret; 447 448 ctx = g2d_init(dev->fd); 449 if (!ctx) 450 return -EFAULT; 451 452 memset(&src_img, 0, sizeof(struct g2d_image)); 453 memset(&dst_img, 0, sizeof(struct g2d_image)); 454 dst_img.bo[0] = dst->handle; 455 456 src_x = 0; 457 src_y = 0; 458 dst_x = 0; 459 dst_y = 0; 460 img_w = screen_width; 461 img_h = screen_height; 462 463 switch (type) { 464 case G2D_IMGBUF_GEM: 465 src_img.bo[0] = src->handle; 466 break; 467 case G2D_IMGBUF_USERPTR: 468 size = img_w * img_h * 4; 469 470 userptr = (unsigned long)malloc(size); 471 if (!userptr) { 472 fprintf(stderr, "failed to allocate userptr.\n"); 473 return -EFAULT; 474 } 475 476 src_img.user_ptr[0].userptr = userptr; 477 src_img.user_ptr[0].size = size; 478 break; 479 default: 480 type = G2D_IMGBUF_GEM; 481 break; 482 } 483 484 printf("blend test with %s.\n", 485 type == G2D_IMGBUF_GEM ? "gem" : "userptr"); 486 487 src_img.width = img_w; 488 src_img.height = img_h; 489 src_img.stride = src_img.width * 4; 490 src_img.buf_type = type; 491 src_img.select_mode = G2D_SELECT_MODE_NORMAL; 492 src_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; 493 src_img.color = 0xffffffff; 494 ret = g2d_solid_fill(ctx, &src_img, src_x, src_y, img_w, img_h); 495 if (ret < 0) 496 goto err_free_userptr; 497 498 src_img.color = 0x770000ff; 499 ret = g2d_solid_fill(ctx, &src_img, 5, 5, 200, 200); 500 if (ret < 0) 501 goto err_free_userptr; 502 503 dst_img.width = img_w; 504 dst_img.height = img_h; 505 dst_img.stride = dst_img.width * 4; 506 dst_img.buf_type = G2D_IMGBUF_GEM; 507 dst_img.select_mode = G2D_SELECT_MODE_NORMAL; 508 dst_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; 509 dst_img.color = 0xffffffff; 510 ret = g2d_solid_fill(ctx, &dst_img, dst_x, dst_y, img_w, img_h); 511 if (ret < 0) 512 goto err_free_userptr; 513 514 dst_img.color = 0x77ff0000; 515 ret = g2d_solid_fill(ctx, &dst_img, 105, 105, 200, 200); 516 if (ret < 0) 517 goto err_free_userptr; 518 519 ret = g2d_blend(ctx, &src_img, &dst_img, 5, 5, 105, 105, 200, 200, 520 G2D_OP_OVER); 521 if (ret < 0) 522 goto err_free_userptr; 523 524 g2d_exec(ctx); 525 526err_free_userptr: 527 if (type == G2D_IMGBUF_USERPTR) 528 if (userptr) 529 free((void *)userptr); 530 531 g2d_fini(ctx); 532 533 return 0; 534} 535 536static struct fimg2d_test_case test_case = { 537 .solid_fill = &g2d_solid_fill_test, 538 .copy = &g2d_copy_test, 539 .copy_with_scale = &g2d_copy_with_scale_test, 540 .blend = &g2d_blend_test, 541}; 542 543static void usage(char *name) 544{ 545 fprintf(stderr, "usage: %s [-s]\n", name); 546 fprintf(stderr, "-s <connector_id>@<crtc_id>:<mode>\n"); 547 exit(0); 548} 549 550extern char *optarg; 551static const char optstr[] = "s:"; 552 553int main(int argc, char **argv) 554{ 555 struct exynos_device *dev; 556 struct exynos_bo *bo, *src; 557 struct connector con; 558 char *modeset = NULL; 559 unsigned int fb_id; 560 uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0}; 561 drmModeRes *resources; 562 int ret, fd, c; 563 564 memset(&con, 0, sizeof(struct connector)); 565 566 if (argc != 3) { 567 usage(argv[0]); 568 return -EINVAL; 569 } 570 571 while ((c = getopt(argc, argv, optstr)) != -1) { 572 switch (c) { 573 case 's': 574 modeset = strdup(optarg); 575 con.crtc = -1; 576 if (sscanf(optarg, "%d:0x%64s", 577 &con.id, 578 con.mode_str) != 2 && 579 sscanf(optarg, "%d@%d:%64s", 580 &con.id, 581 &con.crtc, 582 con.mode_str) != 3) 583 usage(argv[0]); 584 break; 585 default: 586 usage(argv[0]); 587 return -EINVAL; 588 } 589 } 590 591 fd = drmOpen(DRM_MODULE_NAME, NULL); 592 if (fd < 0) { 593 fprintf(stderr, "failed to open.\n"); 594 return fd; 595 } 596 597 dev = exynos_device_create(fd); 598 if (!dev) { 599 drmClose(dev->fd); 600 return -EFAULT; 601 } 602 603 resources = drmModeGetResources(dev->fd); 604 if (!resources) { 605 fprintf(stderr, "drmModeGetResources failed: %s\n", 606 strerror(errno)); 607 ret = -EFAULT; 608 goto err_drm_close; 609 } 610 611 connector_find_mode(dev->fd, &con, resources); 612 drmModeFreeResources(resources); 613 614 screen_width = con.mode->hdisplay; 615 screen_height = con.mode->vdisplay; 616 617 printf("screen width = %d, screen height = %d\n", screen_width, 618 screen_height); 619 620 bo = exynos_create_buffer(dev, screen_width * screen_height * 4, 0); 621 if (!bo) { 622 ret = -EFAULT; 623 goto err_drm_close; 624 } 625 626 handles[0] = bo->handle; 627 pitches[0] = screen_width * 4; 628 offsets[0] = 0; 629 630 ret = drmModeAddFB2(dev->fd, screen_width, screen_height, 631 DRM_FORMAT_RGBA8888, handles, 632 pitches, offsets, &fb_id, 0); 633 if (ret < 0) 634 goto err_destroy_buffer; 635 636 con.plane_zpos = -1; 637 638 memset(bo->vaddr, 0xff, screen_width * screen_height * 4); 639 640 ret = drm_set_crtc(dev, &con, fb_id); 641 if (ret < 0) 642 goto err_rm_fb; 643 644 ret = test_case.solid_fill(dev, bo); 645 if (ret < 0) { 646 fprintf(stderr, "failed to solid fill operation.\n"); 647 goto err_rm_fb; 648 } 649 650 getchar(); 651 652 src = exynos_create_buffer(dev, screen_width * screen_height * 4, 0); 653 if (!src) { 654 ret = -EFAULT; 655 goto err_rm_fb; 656 } 657 658 ret = test_case.copy(dev, src, bo, G2D_IMGBUF_GEM); 659 if (ret < 0) { 660 fprintf(stderr, "failed to test copy operation.\n"); 661 goto err_free_src; 662 } 663 664 getchar(); 665 666 ret = test_case.copy_with_scale(dev, src, bo, G2D_IMGBUF_GEM); 667 if (ret < 0) { 668 fprintf(stderr, "failed to test copy and scale operation.\n"); 669 goto err_free_src; 670 } 671 672 getchar(); 673 674 ret = test_case.blend(dev, src, bo, G2D_IMGBUF_USERPTR); 675 if (ret < 0) 676 fprintf(stderr, "failed to test blend operation.\n"); 677 678 getchar(); 679 680err_free_src: 681 if (src) 682 exynos_destroy_buffer(src); 683 684err_rm_fb: 685 drmModeRmFB(dev->fd, fb_id); 686 687err_destroy_buffer: 688 exynos_destroy_buffer(bo); 689 690err_drm_close: 691 drmClose(dev->fd); 692 exynos_device_destroy(dev); 693 694 return 0; 695} 696