1 /* 2 * Copyright (C) 2013 Samsung Electronics Co.Ltd 3 * Authors: 4 * Inki Dae <inki.dae (at) 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 #include <time.h> 22 #include <unistd.h> 23 24 #include <sys/mman.h> 25 #include <linux/stddef.h> 26 27 #include <xf86drm.h> 28 #include <xf86drmMode.h> 29 #include <libkms.h> 30 #include <drm_fourcc.h> 31 32 #include "exynos_drm.h" 33 #include "exynos_drmif.h" 34 #include "exynos_fimg2d.h" 35 36 #define DRM_MODULE_NAME "exynos" 37 38 static unsigned int screen_width, screen_height; 39 40 struct connector { 41 uint32_t id; 42 char mode_str[64]; 43 drmModeModeInfo *mode; 44 drmModeEncoder *encoder; 45 int crtc; 46 }; 47 48 static void connector_find_mode(int fd, struct connector *c, 49 drmModeRes *resources) 50 { 51 drmModeConnector *connector; 52 int i, j; 53 54 /* First, find the connector & mode */ 55 c->mode = NULL; 56 for (i = 0; i < resources->count_connectors; i++) { 57 connector = drmModeGetConnector(fd, resources->connectors[i]); 58 59 if (!connector) { 60 fprintf(stderr, "could not get connector %i: %s\n", 61 resources->connectors[i], strerror(errno)); 62 drmModeFreeConnector(connector); 63 continue; 64 } 65 66 if (!connector->count_modes) { 67 drmModeFreeConnector(connector); 68 continue; 69 } 70 71 if (connector->connector_id != c->id) { 72 drmModeFreeConnector(connector); 73 continue; 74 } 75 76 for (j = 0; j < connector->count_modes; j++) { 77 c->mode = &connector->modes[j]; 78 if (!strcmp(c->mode->name, c->mode_str)) 79 break; 80 } 81 82 /* Found it, break out */ 83 if (c->mode) 84 break; 85 86 drmModeFreeConnector(connector); 87 } 88 89 if (!c->mode) { 90 fprintf(stderr, "failed to find mode \"%s\"\n", c->mode_str); 91 return; 92 } 93 94 /* Now get the encoder */ 95 for (i = 0; i < resources->count_encoders; i++) { 96 c->encoder = drmModeGetEncoder(fd, resources->encoders[i]); 97 98 if (!c->encoder) { 99 fprintf(stderr, "could not get encoder %i: %s\n", 100 resources->encoders[i], strerror(errno)); 101 drmModeFreeEncoder(c->encoder); 102 continue; 103 } 104 105 if (c->encoder->encoder_id == connector->encoder_id) 106 break; 107 108 drmModeFreeEncoder(c->encoder); 109 } 110 111 if (c->crtc == -1) 112 c->crtc = c->encoder->crtc_id; 113 } 114 115 static int drm_set_crtc(struct exynos_device *dev, struct connector *c, 116 unsigned int fb_id) 117 { 118 int ret; 119 120 ret = drmModeSetCrtc(dev->fd, c->crtc, 121 fb_id, 0, 0, &c->id, 1, c->mode); 122 if (ret) 123 drmMsg("failed to set mode: %s\n", strerror(errno)); 124 125 return ret; 126 } 127 128 static struct exynos_bo *exynos_create_buffer(struct exynos_device *dev, 129 unsigned long size, 130 unsigned int flags) 131 { 132 struct exynos_bo *bo; 133 134 bo = exynos_bo_create(dev, size, flags); 135 if (!bo) 136 return bo; 137 138 if (!exynos_bo_map(bo)) { 139 exynos_bo_destroy(bo); 140 return NULL; 141 } 142 143 return bo; 144 } 145 146 /* Allocate buffer and fill it with checkerboard pattern, where the tiles * 147 * have a random color. The caller has to free the buffer. */ 148 static void *create_checkerboard_pattern(unsigned int num_tiles_x, 149 unsigned int num_tiles_y, unsigned int tile_size) 150 { 151 unsigned int *buf; 152 unsigned int x, y, i, j; 153 const unsigned int stride = num_tiles_x * tile_size; 154 155 if (posix_memalign((void*)&buf, 64, num_tiles_y * tile_size * stride * 4) != 0) 156 return NULL; 157 158 for (x = 0; x < num_tiles_x; ++x) { 159 for (y = 0; y < num_tiles_y; ++y) { 160 const unsigned int color = 0xff000000 + (random() & 0xffffff); 161 162 for (i = 0; i < tile_size; ++i) { 163 for (j = 0; j < tile_size; ++j) { 164 buf[x * tile_size + y * stride * tile_size + i + j * stride] = color; 165 } 166 } 167 } 168 } 169 170 return buf; 171 } 172 173 static void exynos_destroy_buffer(struct exynos_bo *bo) 174 { 175 exynos_bo_destroy(bo); 176 } 177 178 static void wait_for_user_input(int last) 179 { 180 printf("press <ENTER> to %s\n", last ? "exit test application" : 181 "skip to next test"); 182 183 getchar(); 184 } 185 186 static int g2d_solid_fill_test(struct exynos_device *dev, struct exynos_bo *dst) 187 { 188 struct g2d_context *ctx; 189 struct g2d_image img = {0}; 190 unsigned int count, img_w, img_h; 191 int ret = 0; 192 193 ctx = g2d_init(dev->fd); 194 if (!ctx) 195 return -EFAULT; 196 197 img.bo[0] = dst->handle; 198 199 printf("solid fill test.\n"); 200 201 srand(time(NULL)); 202 img_w = screen_width; 203 img_h = screen_height; 204 205 for (count = 0; count < 2; count++) { 206 unsigned int x, y, w, h; 207 208 x = rand() % (img_w / 2); 209 y = rand() % (img_h / 2); 210 w = rand() % (img_w - x); 211 h = rand() % (img_h - y); 212 213 img.width = img_w; 214 img.height = img_h; 215 img.stride = img.width * 4; 216 img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; 217 img.color = 0xff000000 + (random() & 0xffffff); 218 219 ret = g2d_solid_fill(ctx, &img, x, y, w, h); 220 if (ret < 0) 221 goto err_fini; 222 223 ret = g2d_exec(ctx); 224 if (ret < 0) 225 break; 226 } 227 228 err_fini: 229 g2d_fini(ctx); 230 231 return ret; 232 } 233 234 static int g2d_copy_test(struct exynos_device *dev, struct exynos_bo *src, 235 struct exynos_bo *dst, 236 enum e_g2d_buf_type type) 237 { 238 struct g2d_context *ctx; 239 struct g2d_image src_img = {0}, dst_img = {0}; 240 unsigned int src_x, src_y, dst_x, dst_y, img_w, img_h; 241 unsigned long userptr, size; 242 int ret; 243 244 ctx = g2d_init(dev->fd); 245 if (!ctx) 246 return -EFAULT; 247 248 dst_img.bo[0] = dst->handle; 249 250 src_x = 0; 251 src_y = 0; 252 dst_x = 0; 253 dst_y = 0; 254 img_w = screen_width; 255 img_h = screen_height; 256 257 switch (type) { 258 case G2D_IMGBUF_GEM: 259 src_img.bo[0] = src->handle; 260 break; 261 case G2D_IMGBUF_USERPTR: 262 size = img_w * img_h * 4; 263 264 userptr = (unsigned long)malloc(size); 265 if (!userptr) { 266 fprintf(stderr, "failed to allocate userptr.\n"); 267 return -EFAULT; 268 } 269 270 src_img.user_ptr[0].userptr = userptr; 271 src_img.user_ptr[0].size = size; 272 break; 273 case G2D_IMGBUF_COLOR: 274 default: 275 ret = -EFAULT; 276 goto fail; 277 } 278 279 printf("copy test with %s.\n", 280 type == G2D_IMGBUF_GEM ? "gem" : "userptr"); 281 282 src_img.width = img_w; 283 src_img.height = img_h; 284 src_img.stride = src_img.width * 4; 285 src_img.buf_type = type; 286 src_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; 287 src_img.color = 0xffff0000; 288 ret = g2d_solid_fill(ctx, &src_img, src_x, src_y, img_w, img_h); 289 if (ret < 0) 290 goto err_free_userptr; 291 292 dst_img.width = img_w; 293 dst_img.height = img_h; 294 dst_img.stride = dst_img.width * 4; 295 dst_img.buf_type = G2D_IMGBUF_GEM; 296 dst_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; 297 298 ret = g2d_copy(ctx, &src_img, &dst_img, src_x, src_y, dst_x, dst_y, 299 img_w - 4, img_h - 4); 300 if (ret < 0) 301 goto err_free_userptr; 302 303 g2d_exec(ctx); 304 305 err_free_userptr: 306 if (type == G2D_IMGBUF_USERPTR) 307 if (userptr) 308 free((void *)userptr); 309 310 fail: 311 g2d_fini(ctx); 312 313 return ret; 314 } 315 316 static int g2d_move_test(struct exynos_device *dev, 317 struct exynos_bo *tmp, 318 struct exynos_bo *buf, 319 enum e_g2d_buf_type type) 320 { 321 struct g2d_context *ctx; 322 struct g2d_image img = {0}, tmp_img = {0}; 323 unsigned int img_w, img_h, count; 324 int cur_x, cur_y; 325 void *checkerboard; 326 int ret; 327 328 static const struct g2d_step { 329 int x, y; 330 } steps[] = { 331 { 1, 0}, { 0, 1}, 332 {-1, 0}, { 0, -1}, 333 { 1, 1}, {-1, -1}, 334 { 1, -1}, {-1, 1}, 335 { 2, 1}, { 1, 2}, 336 {-2, -1}, {-1, -2}, 337 { 2, -1}, { 1, -2}, 338 {-2, 1}, {-1, 2} 339 }; 340 static const unsigned int num_steps = 341 sizeof(steps) / sizeof(struct g2d_step); 342 343 ctx = g2d_init(dev->fd); 344 if (!ctx) 345 return -EFAULT; 346 347 img.bo[0] = buf->handle; 348 349 /* create pattern of half the screen size */ 350 checkerboard = create_checkerboard_pattern(screen_width / 64, screen_height / 64, 32); 351 if (!checkerboard) { 352 ret = -EFAULT; 353 goto fail; 354 } 355 356 img_w = (screen_width / 64) * 32; 357 img_h = (screen_height / 64) * 32; 358 359 switch (type) { 360 case G2D_IMGBUF_GEM: 361 memcpy(tmp->vaddr, checkerboard, img_w * img_h * 4); 362 tmp_img.bo[0] = tmp->handle; 363 break; 364 case G2D_IMGBUF_USERPTR: 365 tmp_img.user_ptr[0].userptr = (unsigned long)checkerboard; 366 tmp_img.user_ptr[0].size = img_w * img_h * 4; 367 break; 368 case G2D_IMGBUF_COLOR: 369 default: 370 ret = -EFAULT; 371 goto fail; 372 } 373 374 /* solid fill framebuffer with white color */ 375 img.width = screen_width; 376 img.height = screen_height; 377 img.stride = screen_width * 4; 378 img.buf_type = G2D_IMGBUF_GEM; 379 img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; 380 img.color = 0xffffffff; 381 382 /* put checkerboard pattern in the center of the framebuffer */ 383 cur_x = (screen_width - img_w) / 2; 384 cur_y = (screen_height - img_h) / 2; 385 tmp_img.width = img_w; 386 tmp_img.height = img_h; 387 tmp_img.stride = img_w * 4; 388 tmp_img.buf_type = type; 389 tmp_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; 390 391 ret = g2d_solid_fill(ctx, &img, 0, 0, screen_width, screen_height) || 392 g2d_copy(ctx, &tmp_img, &img, 0, 0, cur_x, cur_y, img_w, img_h); 393 394 if (!ret) 395 ret = g2d_exec(ctx); 396 if (ret < 0) 397 goto fail; 398 399 printf("move test with %s.\n", 400 type == G2D_IMGBUF_GEM ? "gem" : "userptr"); 401 402 srand(time(NULL)); 403 for (count = 0; count < 256; ++count) { 404 const struct g2d_step *s; 405 406 /* select step and validate it */ 407 while (1) { 408 s = &steps[random() % num_steps]; 409 410 if (cur_x + s->x < 0 || cur_y + s->y < 0 || 411 cur_x + img_w + s->x >= screen_width || 412 cur_y + img_h + s->y >= screen_height) 413 continue; 414 else 415 break; 416 } 417 418 ret = g2d_move(ctx, &img, cur_x, cur_y, cur_x + s->x, cur_y + s->y, 419 img_w, img_h); 420 if (!ret) 421 ret = g2d_exec(ctx); 422 423 if (ret < 0) 424 goto fail; 425 426 cur_x += s->x; 427 cur_y += s->y; 428 429 usleep(100000); 430 } 431 432 fail: 433 g2d_fini(ctx); 434 435 free(checkerboard); 436 437 return ret; 438 } 439 440 static int g2d_copy_with_scale_test(struct exynos_device *dev, 441 struct exynos_bo *src, 442 struct exynos_bo *dst, 443 enum e_g2d_buf_type type) 444 { 445 struct g2d_context *ctx; 446 struct g2d_image src_img = {0}, dst_img = {0}; 447 unsigned int src_x, src_y, img_w, img_h; 448 unsigned long userptr, size; 449 int ret; 450 451 ctx = g2d_init(dev->fd); 452 if (!ctx) 453 return -EFAULT; 454 455 dst_img.bo[0] = dst->handle; 456 457 src_x = 0; 458 src_y = 0; 459 img_w = screen_width; 460 img_h = screen_height; 461 462 switch (type) { 463 case G2D_IMGBUF_GEM: 464 src_img.bo[0] = src->handle; 465 break; 466 case G2D_IMGBUF_USERPTR: 467 size = img_w * img_h * 4; 468 469 userptr = (unsigned long)malloc(size); 470 if (!userptr) { 471 fprintf(stderr, "failed to allocate userptr.\n"); 472 return -EFAULT; 473 } 474 475 src_img.user_ptr[0].userptr = userptr; 476 src_img.user_ptr[0].size = size; 477 break; 478 case G2D_IMGBUF_COLOR: 479 default: 480 ret = -EFAULT; 481 goto fail; 482 } 483 484 printf("copy and scale 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.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; 492 src_img.color = 0xffffffff; 493 ret = g2d_solid_fill(ctx, &src_img, src_x, src_y, img_w , img_h); 494 if (ret < 0) 495 goto err_free_userptr; 496 497 src_img.color = 0xff00ff00; 498 ret = g2d_solid_fill(ctx, &src_img, 5, 5, 100, 100); 499 if (ret < 0) 500 goto err_free_userptr; 501 502 dst_img.width = img_w; 503 dst_img.height = img_h; 504 dst_img.buf_type = G2D_IMGBUF_GEM; 505 dst_img.stride = dst_img.width * 4; 506 dst_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; 507 508 ret = g2d_copy_with_scale(ctx, &src_img, &dst_img, 5, 5, 100, 100, 509 100, 100, 200, 200, 0); 510 if (ret < 0) 511 goto err_free_userptr; 512 513 g2d_exec(ctx); 514 515 err_free_userptr: 516 if (type == G2D_IMGBUF_USERPTR) 517 if (userptr) 518 free((void *)userptr); 519 520 fail: 521 g2d_fini(ctx); 522 523 return 0; 524 } 525 526 static int g2d_blend_test(struct exynos_device *dev, 527 struct exynos_bo *src, 528 struct exynos_bo *dst, 529 enum e_g2d_buf_type type) 530 { 531 struct g2d_context *ctx; 532 struct g2d_image src_img = {0}, dst_img = {0}; 533 unsigned int src_x, src_y, dst_x, dst_y, img_w, img_h; 534 unsigned long userptr, size; 535 int ret; 536 537 ctx = g2d_init(dev->fd); 538 if (!ctx) 539 return -EFAULT; 540 541 dst_img.bo[0] = dst->handle; 542 543 src_x = 0; 544 src_y = 0; 545 dst_x = 0; 546 dst_y = 0; 547 img_w = screen_width; 548 img_h = screen_height; 549 550 switch (type) { 551 case G2D_IMGBUF_GEM: 552 src_img.bo[0] = src->handle; 553 break; 554 case G2D_IMGBUF_USERPTR: 555 size = img_w * img_h * 4; 556 557 userptr = (unsigned long)malloc(size); 558 if (!userptr) { 559 fprintf(stderr, "failed to allocate userptr.\n"); 560 return -EFAULT; 561 } 562 563 src_img.user_ptr[0].userptr = userptr; 564 src_img.user_ptr[0].size = size; 565 break; 566 case G2D_IMGBUF_COLOR: 567 default: 568 ret = -EFAULT; 569 goto fail; 570 } 571 572 printf("blend test with %s.\n", 573 type == G2D_IMGBUF_GEM ? "gem" : "userptr"); 574 575 src_img.width = img_w; 576 src_img.height = img_h; 577 src_img.stride = src_img.width * 4; 578 src_img.buf_type = type; 579 src_img.select_mode = G2D_SELECT_MODE_NORMAL; 580 src_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; 581 src_img.color = 0xffffffff; 582 ret = g2d_solid_fill(ctx, &src_img, src_x, src_y, img_w, img_h); 583 if (ret < 0) 584 goto err_free_userptr; 585 586 src_img.color = 0x770000ff; 587 ret = g2d_solid_fill(ctx, &src_img, 5, 5, 200, 200); 588 if (ret < 0) 589 goto err_free_userptr; 590 591 dst_img.width = img_w; 592 dst_img.height = img_h; 593 dst_img.stride = dst_img.width * 4; 594 dst_img.buf_type = G2D_IMGBUF_GEM; 595 dst_img.select_mode = G2D_SELECT_MODE_NORMAL; 596 dst_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; 597 dst_img.color = 0xffffffff; 598 ret = g2d_solid_fill(ctx, &dst_img, dst_x, dst_y, img_w, img_h); 599 if (ret < 0) 600 goto err_free_userptr; 601 602 dst_img.color = 0x77ff0000; 603 ret = g2d_solid_fill(ctx, &dst_img, 105, 105, 200, 200); 604 if (ret < 0) 605 goto err_free_userptr; 606 607 ret = g2d_blend(ctx, &src_img, &dst_img, 5, 5, 105, 105, 200, 200, 608 G2D_OP_OVER); 609 if (ret < 0) 610 goto err_free_userptr; 611 612 g2d_exec(ctx); 613 614 err_free_userptr: 615 if (type == G2D_IMGBUF_USERPTR) 616 if (userptr) 617 free((void *)userptr); 618 619 fail: 620 g2d_fini(ctx); 621 622 return 0; 623 } 624 625 static int g2d_checkerboard_test(struct exynos_device *dev, 626 struct exynos_bo *src, 627 struct exynos_bo *dst, 628 enum e_g2d_buf_type type) 629 { 630 struct g2d_context *ctx; 631 struct g2d_image src_img = {0}, dst_img = {0}; 632 unsigned int src_x, src_y, dst_x, dst_y, img_w, img_h; 633 void *checkerboard = NULL; 634 int ret; 635 636 ctx = g2d_init(dev->fd); 637 if (!ctx) 638 return -EFAULT; 639 640 dst_img.bo[0] = dst->handle; 641 642 src_x = 0; 643 src_y = 0; 644 dst_x = 0; 645 dst_y = 0; 646 647 checkerboard = create_checkerboard_pattern(screen_width / 32, screen_height / 32, 32); 648 if (checkerboard == NULL) { 649 ret = -1; 650 goto fail; 651 } 652 653 img_w = screen_width - (screen_width % 32); 654 img_h = screen_height - (screen_height % 32); 655 656 switch (type) { 657 case G2D_IMGBUF_GEM: 658 memcpy(src->vaddr, checkerboard, img_w * img_h * 4); 659 src_img.bo[0] = src->handle; 660 break; 661 case G2D_IMGBUF_USERPTR: 662 src_img.user_ptr[0].userptr = (unsigned long)checkerboard; 663 src_img.user_ptr[0].size = img_w * img_h * 4; 664 break; 665 case G2D_IMGBUF_COLOR: 666 default: 667 ret = -EFAULT; 668 goto fail; 669 } 670 671 printf("checkerboard test with %s.\n", 672 type == G2D_IMGBUF_GEM ? "gem" : "userptr"); 673 674 src_img.width = img_w; 675 src_img.height = img_h; 676 src_img.stride = src_img.width * 4; 677 src_img.buf_type = type; 678 src_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; 679 680 dst_img.width = screen_width; 681 dst_img.height = screen_height; 682 dst_img.stride = dst_img.width * 4; 683 dst_img.buf_type = G2D_IMGBUF_GEM; 684 dst_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; 685 src_img.color = 0xff000000; 686 ret = g2d_solid_fill(ctx, &dst_img, src_x, src_y, screen_width, screen_height); 687 if (ret < 0) 688 goto fail; 689 690 ret = g2d_copy(ctx, &src_img, &dst_img, src_x, src_y, dst_x, dst_y, 691 img_w, img_h); 692 if (ret < 0) 693 goto fail; 694 695 g2d_exec(ctx); 696 697 fail: 698 free(checkerboard); 699 g2d_fini(ctx); 700 701 return ret; 702 } 703 704 static void usage(char *name) 705 { 706 fprintf(stderr, "usage: %s [-s]\n", name); 707 fprintf(stderr, "-s <connector_id>@<crtc_id>:<mode>\n"); 708 exit(0); 709 } 710 711 extern char *optarg; 712 static const char optstr[] = "s:"; 713 714 int main(int argc, char **argv) 715 { 716 struct exynos_device *dev; 717 struct exynos_bo *bo, *src; 718 struct connector con; 719 unsigned int fb_id; 720 uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0}; 721 drmModeRes *resources; 722 int ret, fd, c; 723 724 memset(&con, 0, sizeof(struct connector)); 725 726 if (argc != 3) { 727 usage(argv[0]); 728 return -EINVAL; 729 } 730 731 while ((c = getopt(argc, argv, optstr)) != -1) { 732 switch (c) { 733 case 's': 734 con.crtc = -1; 735 if (sscanf(optarg, "%d:0x%64s", 736 &con.id, 737 con.mode_str) != 2 && 738 sscanf(optarg, "%d@%d:%64s", 739 &con.id, 740 &con.crtc, 741 con.mode_str) != 3) 742 usage(argv[0]); 743 break; 744 default: 745 usage(argv[0]); 746 break; 747 } 748 } 749 750 fd = drmOpen(DRM_MODULE_NAME, NULL); 751 if (fd < 0) { 752 fprintf(stderr, "failed to open.\n"); 753 return fd; 754 } 755 756 dev = exynos_device_create(fd); 757 if (!dev) { 758 drmClose(dev->fd); 759 return -EFAULT; 760 } 761 762 resources = drmModeGetResources(dev->fd); 763 if (!resources) { 764 fprintf(stderr, "drmModeGetResources failed: %s\n", 765 strerror(errno)); 766 ret = -EFAULT; 767 goto err_drm_close; 768 } 769 770 connector_find_mode(dev->fd, &con, resources); 771 drmModeFreeResources(resources); 772 773 if (!con.mode) { 774 fprintf(stderr, "failed to find usable connector\n"); 775 ret = -EFAULT; 776 goto err_drm_close; 777 } 778 779 screen_width = con.mode->hdisplay; 780 screen_height = con.mode->vdisplay; 781 782 if (screen_width == 0 || screen_height == 0) { 783 fprintf(stderr, "failed to find sane resolution on connector\n"); 784 ret = -EFAULT; 785 goto err_drm_close; 786 } 787 788 printf("screen width = %d, screen height = %d\n", screen_width, 789 screen_height); 790 791 bo = exynos_create_buffer(dev, screen_width * screen_height * 4, 0); 792 if (!bo) { 793 ret = -EFAULT; 794 goto err_drm_close; 795 } 796 797 handles[0] = bo->handle; 798 pitches[0] = screen_width * 4; 799 offsets[0] = 0; 800 801 ret = drmModeAddFB2(dev->fd, screen_width, screen_height, 802 DRM_FORMAT_XRGB8888, handles, 803 pitches, offsets, &fb_id, 0); 804 if (ret < 0) 805 goto err_destroy_buffer; 806 807 memset(bo->vaddr, 0xff, screen_width * screen_height * 4); 808 809 ret = drm_set_crtc(dev, &con, fb_id); 810 if (ret < 0) 811 goto err_rm_fb; 812 813 ret = g2d_solid_fill_test(dev, bo); 814 if (ret < 0) { 815 fprintf(stderr, "failed to solid fill operation.\n"); 816 goto err_rm_fb; 817 } 818 819 wait_for_user_input(0); 820 821 src = exynos_create_buffer(dev, screen_width * screen_height * 4, 0); 822 if (!src) { 823 ret = -EFAULT; 824 goto err_rm_fb; 825 } 826 827 ret = g2d_copy_test(dev, src, bo, G2D_IMGBUF_GEM); 828 if (ret < 0) { 829 fprintf(stderr, "failed to test copy operation.\n"); 830 goto err_free_src; 831 } 832 833 wait_for_user_input(0); 834 835 ret = g2d_move_test(dev, src, bo, G2D_IMGBUF_GEM); 836 if (ret < 0) { 837 fprintf(stderr, "failed to test move operation.\n"); 838 goto err_free_src; 839 } 840 841 wait_for_user_input(0); 842 843 ret = g2d_copy_with_scale_test(dev, src, bo, G2D_IMGBUF_GEM); 844 if (ret < 0) { 845 fprintf(stderr, "failed to test copy and scale operation.\n"); 846 goto err_free_src; 847 } 848 849 wait_for_user_input(0); 850 851 ret = g2d_checkerboard_test(dev, src, bo, G2D_IMGBUF_GEM); 852 if (ret < 0) { 853 fprintf(stderr, "failed to issue checkerboard test.\n"); 854 goto err_free_src; 855 } 856 857 wait_for_user_input(1); 858 859 /* 860 * The blend test uses the userptr functionality of exynos-drm, which 861 * is currently not safe to use. If the kernel hasn't been build with 862 * exynos-iommu support, then the blend test is going to produce (kernel) 863 * memory corruption, eventually leading to a system crash. 864 * 865 * Disable the test for now, until the kernel code has been sanitized. 866 */ 867 #if 0 868 ret = g2d_blend_test(dev, src, bo, G2D_IMGBUF_USERPTR); 869 if (ret < 0) 870 fprintf(stderr, "failed to test blend operation.\n"); 871 872 getchar(); 873 #endif 874 875 err_free_src: 876 if (src) 877 exynos_destroy_buffer(src); 878 879 err_rm_fb: 880 drmModeRmFB(dev->fd, fb_id); 881 882 err_destroy_buffer: 883 exynos_destroy_buffer(bo); 884 885 err_drm_close: 886 drmClose(dev->fd); 887 exynos_device_destroy(dev); 888 889 return 0; 890 } 891