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