exynos_fimg2d.c revision e6188e58
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 27#include "libdrm_macros.h" 28#include "exynos_drm.h" 29#include "fimg2d_reg.h" 30#include "exynos_fimg2d.h" 31 32#define SET_BF(val, sc, si, scsa, scda, dc, di, dcsa, dcda) \ 33 val.data.src_coeff = sc; \ 34 val.data.inv_src_color_coeff = si; \ 35 val.data.src_coeff_src_a = scsa; \ 36 val.data.src_coeff_dst_a = scda; \ 37 val.data.dst_coeff = dc; \ 38 val.data.inv_dst_color_coeff = di; \ 39 val.data.dst_coeff_src_a = dcsa; \ 40 val.data.dst_coeff_dst_a = dcda; 41 42#define MIN(a, b) ((a) < (b) ? (a) : (b)) 43 44enum g2d_base_addr_reg { 45 g2d_dst = 0, 46 g2d_src 47}; 48 49static unsigned int g2d_get_scaling(unsigned int src, unsigned int dst) 50{ 51 /* 52 * The G2D hw scaling factor is a normalized inverse of the scaling factor. 53 * For example: When source width is 100 and destination width is 200 54 * (scaling of 2x), then the hw factor is NC * 100 / 200. 55 * The normalization factor (NC) is 2^16 = 0x10000. 56 */ 57 58 return ((src << 16) / dst); 59} 60 61static unsigned int g2d_get_blend_op(enum e_g2d_op op) 62{ 63 union g2d_blend_func_val val; 64 65 val.val = 0; 66 67 switch (op) { 68 case G2D_OP_CLEAR: 69 case G2D_OP_DISJOINT_CLEAR: 70 case G2D_OP_CONJOINT_CLEAR: 71 SET_BF(val, G2D_COEFF_MODE_ZERO, 0, 0, 0, G2D_COEFF_MODE_ZERO, 72 0, 0, 0); 73 break; 74 case G2D_OP_SRC: 75 case G2D_OP_DISJOINT_SRC: 76 case G2D_OP_CONJOINT_SRC: 77 SET_BF(val, G2D_COEFF_MODE_ONE, 0, 0, 0, G2D_COEFF_MODE_ZERO, 78 0, 0, 0); 79 break; 80 case G2D_OP_DST: 81 case G2D_OP_DISJOINT_DST: 82 case G2D_OP_CONJOINT_DST: 83 SET_BF(val, G2D_COEFF_MODE_ZERO, 0, 0, 0, G2D_COEFF_MODE_ONE, 84 0, 0, 0); 85 break; 86 case G2D_OP_OVER: 87 SET_BF(val, G2D_COEFF_MODE_ONE, 0, 0, 0, 88 G2D_COEFF_MODE_SRC_ALPHA, 1, 0, 0); 89 break; 90 case G2D_OP_INTERPOLATE: 91 SET_BF(val, G2D_COEFF_MODE_SRC_ALPHA, 0, 0, 0, 92 G2D_COEFF_MODE_SRC_ALPHA, 1, 0, 0); 93 break; 94 default: 95 fprintf(stderr, "Not support operation(%d).\n", op); 96 SET_BF(val, G2D_COEFF_MODE_ONE, 0, 0, 0, G2D_COEFF_MODE_ZERO, 97 0, 0, 0); 98 break; 99 } 100 101 return val.val; 102} 103 104/* 105 * g2d_add_cmd - set given command and value to user side command buffer. 106 * 107 * @ctx: a pointer to g2d_context structure. 108 * @cmd: command data. 109 * @value: value data. 110 */ 111static int g2d_add_cmd(struct g2d_context *ctx, unsigned long cmd, 112 unsigned long value) 113{ 114 switch (cmd & ~(G2D_BUF_USERPTR)) { 115 case SRC_BASE_ADDR_REG: 116 case SRC_PLANE2_BASE_ADDR_REG: 117 case DST_BASE_ADDR_REG: 118 case DST_PLANE2_BASE_ADDR_REG: 119 case PAT_BASE_ADDR_REG: 120 case MASK_BASE_ADDR_REG: 121 if (ctx->cmd_buf_nr >= G2D_MAX_GEM_CMD_NR) { 122 fprintf(stderr, "Overflow cmd_gem size.\n"); 123 return -EINVAL; 124 } 125 126 ctx->cmd_buf[ctx->cmd_buf_nr].offset = cmd; 127 ctx->cmd_buf[ctx->cmd_buf_nr].data = value; 128 ctx->cmd_buf_nr++; 129 break; 130 default: 131 if (ctx->cmd_nr >= G2D_MAX_CMD_NR) { 132 fprintf(stderr, "Overflow cmd size.\n"); 133 return -EINVAL; 134 } 135 136 ctx->cmd[ctx->cmd_nr].offset = cmd; 137 ctx->cmd[ctx->cmd_nr].data = value; 138 ctx->cmd_nr++; 139 break; 140 } 141 142 return 0; 143} 144 145/* 146 * g2d_add_base_addr - helper function to set dst/src base address register. 147 * 148 * @ctx: a pointer to g2d_context structure. 149 * @img: a pointer to the dst/src g2d_image structure. 150 * @reg: the register that should be set. 151 */ 152static void g2d_add_base_addr(struct g2d_context *ctx, struct g2d_image *img, 153 enum g2d_base_addr_reg reg) 154{ 155 const unsigned long cmd = (reg == g2d_dst) ? 156 DST_BASE_ADDR_REG : SRC_BASE_ADDR_REG; 157 158 if (img->buf_type == G2D_IMGBUF_USERPTR) 159 g2d_add_cmd(ctx, cmd | G2D_BUF_USERPTR, 160 (unsigned long)&img->user_ptr[0]); 161 else 162 g2d_add_cmd(ctx, cmd, img->bo[0]); 163} 164 165/* 166 * g2d_reset - reset fimg2d hardware. 167 * 168 * @ctx: a pointer to g2d_context structure. 169 * 170 */ 171static void g2d_reset(struct g2d_context *ctx) 172{ 173 ctx->cmd_nr = 0; 174 ctx->cmd_buf_nr = 0; 175 176 g2d_add_cmd(ctx, SOFT_RESET_REG, 0x01); 177} 178 179/* 180 * g2d_flush - submit all commands and values in user side command buffer 181 * to command queue aware of fimg2d dma. 182 * 183 * @ctx: a pointer to g2d_context structure. 184 * 185 * This function should be called after all commands and values to user 186 * side command buffer are set. It submits that buffer to the kernel side driver. 187 */ 188static int g2d_flush(struct g2d_context *ctx) 189{ 190 int ret; 191 struct drm_exynos_g2d_set_cmdlist cmdlist = {0}; 192 193 if (ctx->cmd_nr == 0 && ctx->cmd_buf_nr == 0) 194 return -1; 195 196 if (ctx->cmdlist_nr >= G2D_MAX_CMD_LIST_NR) { 197 fprintf(stderr, "Overflow cmdlist.\n"); 198 return -EINVAL; 199 } 200 201 cmdlist.cmd = (uint64_t)(uintptr_t)&ctx->cmd[0]; 202 cmdlist.cmd_buf = (uint64_t)(uintptr_t)&ctx->cmd_buf[0]; 203 cmdlist.cmd_nr = ctx->cmd_nr; 204 cmdlist.cmd_buf_nr = ctx->cmd_buf_nr; 205 cmdlist.event_type = G2D_EVENT_NOT; 206 cmdlist.user_data = 0; 207 208 ctx->cmd_nr = 0; 209 ctx->cmd_buf_nr = 0; 210 211 ret = drmIoctl(ctx->fd, DRM_IOCTL_EXYNOS_G2D_SET_CMDLIST, &cmdlist); 212 if (ret < 0) { 213 fprintf(stderr, "failed to set cmdlist.\n"); 214 return ret; 215 } 216 217 ctx->cmdlist_nr++; 218 219 return ret; 220} 221 222/** 223 * g2d_init - create a new g2d context and get hardware version. 224 * 225 * fd: a file descriptor to an opened drm device. 226 */ 227struct g2d_context *g2d_init(int fd) 228{ 229 struct drm_exynos_g2d_get_ver ver; 230 struct g2d_context *ctx; 231 int ret; 232 233 ctx = calloc(1, sizeof(*ctx)); 234 if (!ctx) { 235 fprintf(stderr, "failed to allocate context.\n"); 236 return NULL; 237 } 238 239 ctx->fd = fd; 240 241 ret = drmIoctl(fd, DRM_IOCTL_EXYNOS_G2D_GET_VER, &ver); 242 if (ret < 0) { 243 fprintf(stderr, "failed to get version.\n"); 244 free(ctx); 245 return NULL; 246 } 247 248 ctx->major = ver.major; 249 ctx->minor = ver.minor; 250 251 printf("g2d version(%d.%d).\n", ctx->major, ctx->minor); 252 return ctx; 253} 254 255void g2d_fini(struct g2d_context *ctx) 256{ 257 free(ctx); 258} 259 260/** 261 * g2d_exec - start the dma to process all commands summited by g2d_flush(). 262 * 263 * @ctx: a pointer to g2d_context structure. 264 */ 265int g2d_exec(struct g2d_context *ctx) 266{ 267 struct drm_exynos_g2d_exec exec; 268 int ret; 269 270 if (ctx->cmdlist_nr == 0) 271 return -EINVAL; 272 273 exec.async = 0; 274 275 ret = drmIoctl(ctx->fd, DRM_IOCTL_EXYNOS_G2D_EXEC, &exec); 276 if (ret < 0) { 277 fprintf(stderr, "failed to execute.\n"); 278 return ret; 279 } 280 281 ctx->cmdlist_nr = 0; 282 283 return ret; 284} 285 286/** 287 * g2d_solid_fill - fill given buffer with given color data. 288 * 289 * @ctx: a pointer to g2d_context structure. 290 * @img: a pointer to g2d_image structure including image and buffer 291 * information. 292 * @x: x start position to buffer filled with given color data. 293 * @y: y start position to buffer filled with given color data. 294 * @w: width value to buffer filled with given color data. 295 * @h: height value to buffer filled with given color data. 296 */ 297int 298g2d_solid_fill(struct g2d_context *ctx, struct g2d_image *img, 299 unsigned int x, unsigned int y, unsigned int w, 300 unsigned int h) 301{ 302 union g2d_bitblt_cmd_val bitblt; 303 union g2d_point_val pt; 304 305 g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_NORMAL); 306 g2d_add_cmd(ctx, DST_COLOR_MODE_REG, img->color_mode); 307 g2d_add_base_addr(ctx, img, g2d_dst); 308 g2d_add_cmd(ctx, DST_STRIDE_REG, img->stride); 309 310 if (x + w > img->width) 311 w = img->width - x; 312 if (y + h > img->height) 313 h = img->height - y; 314 315 pt.val = 0; 316 pt.data.x = x; 317 pt.data.y = y; 318 g2d_add_cmd(ctx, DST_LEFT_TOP_REG, pt.val); 319 320 pt.val = 0; 321 pt.data.x = x + w; 322 pt.data.y = y + h; 323 324 g2d_add_cmd(ctx, DST_RIGHT_BOTTOM_REG, pt.val); 325 326 g2d_add_cmd(ctx, SF_COLOR_REG, img->color); 327 328 bitblt.val = 0; 329 bitblt.data.fast_solid_color_fill_en = 1; 330 g2d_add_cmd(ctx, BITBLT_COMMAND_REG, bitblt.val); 331 332 return g2d_flush(ctx); 333} 334 335/** 336 * g2d_copy - copy contents in source buffer to destination buffer. 337 * 338 * @ctx: a pointer to g2d_context structure. 339 * @src: a pointer to g2d_image structure including image and buffer 340 * information to source. 341 * @dst: a pointer to g2d_image structure including image and buffer 342 * information to destination. 343 * @src_x: x start position to source buffer. 344 * @src_y: y start position to source buffer. 345 * @dst_x: x start position to destination buffer. 346 * @dst_y: y start position to destination buffer. 347 * @w: width value to source and destination buffers. 348 * @h: height value to source and destination buffers. 349 */ 350int 351g2d_copy(struct g2d_context *ctx, struct g2d_image *src, 352 struct g2d_image *dst, unsigned int src_x, unsigned int src_y, 353 unsigned int dst_x, unsigned dst_y, unsigned int w, 354 unsigned int h) 355{ 356 union g2d_rop4_val rop4; 357 union g2d_point_val pt; 358 unsigned int src_w = 0, src_h = 0, dst_w = 0, dst_h = 0; 359 360 g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_BGCOLOR); 361 g2d_add_cmd(ctx, DST_COLOR_MODE_REG, dst->color_mode); 362 g2d_add_base_addr(ctx, dst, g2d_dst); 363 g2d_add_cmd(ctx, DST_STRIDE_REG, dst->stride); 364 365 g2d_add_cmd(ctx, SRC_SELECT_REG, G2D_SELECT_MODE_NORMAL); 366 g2d_add_cmd(ctx, SRC_COLOR_MODE_REG, src->color_mode); 367 g2d_add_base_addr(ctx, src, g2d_src); 368 g2d_add_cmd(ctx, SRC_STRIDE_REG, src->stride); 369 370 src_w = w; 371 src_h = h; 372 if (src_x + src->width > w) 373 src_w = src->width - src_x; 374 if (src_y + src->height > h) 375 src_h = src->height - src_y; 376 377 dst_w = w; 378 dst_h = w; 379 if (dst_x + dst->width > w) 380 dst_w = dst->width - dst_x; 381 if (dst_y + dst->height > h) 382 dst_h = dst->height - dst_y; 383 384 w = MIN(src_w, dst_w); 385 h = MIN(src_h, dst_h); 386 387 if (w <= 0 || h <= 0) { 388 fprintf(stderr, "invalid width or height.\n"); 389 g2d_reset(ctx); 390 return -EINVAL; 391 } 392 393 pt.val = 0; 394 pt.data.x = src_x; 395 pt.data.y = src_y; 396 g2d_add_cmd(ctx, SRC_LEFT_TOP_REG, pt.val); 397 pt.val = 0; 398 pt.data.x = src_x + w; 399 pt.data.y = src_y + h; 400 g2d_add_cmd(ctx, SRC_RIGHT_BOTTOM_REG, pt.val); 401 402 pt.val = 0; 403 pt.data.x = dst_x; 404 pt.data.y = dst_y; 405 g2d_add_cmd(ctx, DST_LEFT_TOP_REG, pt.val); 406 pt.val = 0; 407 pt.data.x = dst_x + w; 408 pt.data.y = dst_y + h; 409 g2d_add_cmd(ctx, DST_RIGHT_BOTTOM_REG, pt.val); 410 411 rop4.val = 0; 412 rop4.data.unmasked_rop3 = G2D_ROP3_SRC; 413 g2d_add_cmd(ctx, ROP4_REG, rop4.val); 414 415 return g2d_flush(ctx); 416} 417 418/** 419 * g2d_copy_with_scale - copy contents in source buffer to destination buffer 420 * scaling up or down properly. 421 * 422 * @ctx: a pointer to g2d_context structure. 423 * @src: a pointer to g2d_image structure including image and buffer 424 * information to source. 425 * @dst: a pointer to g2d_image structure including image and buffer 426 * information to destination. 427 * @src_x: x start position to source buffer. 428 * @src_y: y start position to source buffer. 429 * @src_w: width value to source buffer. 430 * @src_h: height value to source buffer. 431 * @dst_x: x start position to destination buffer. 432 * @dst_y: y start position to destination buffer. 433 * @dst_w: width value to destination buffer. 434 * @dst_h: height value to destination buffer. 435 * @negative: indicate that it uses color negative to source and 436 * destination buffers. 437 */ 438int 439g2d_copy_with_scale(struct g2d_context *ctx, struct g2d_image *src, 440 struct g2d_image *dst, unsigned int src_x, 441 unsigned int src_y, unsigned int src_w, 442 unsigned int src_h, unsigned int dst_x, 443 unsigned int dst_y, unsigned int dst_w, 444 unsigned int dst_h, unsigned int negative) 445{ 446 union g2d_rop4_val rop4; 447 union g2d_point_val pt; 448 unsigned int scale; 449 unsigned int scale_x, scale_y; 450 451 g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_BGCOLOR); 452 g2d_add_cmd(ctx, DST_COLOR_MODE_REG, dst->color_mode); 453 g2d_add_base_addr(ctx, dst, g2d_dst); 454 g2d_add_cmd(ctx, DST_STRIDE_REG, dst->stride); 455 456 g2d_add_cmd(ctx, SRC_SELECT_REG, G2D_SELECT_MODE_NORMAL); 457 g2d_add_cmd(ctx, SRC_COLOR_MODE_REG, src->color_mode); 458 459 g2d_add_cmd(ctx, SRC_REPEAT_MODE_REG, src->repeat_mode); 460 if (src->repeat_mode == G2D_REPEAT_MODE_PAD) 461 g2d_add_cmd(ctx, SRC_PAD_VALUE_REG, dst->color); 462 463 g2d_add_base_addr(ctx, src, g2d_src); 464 g2d_add_cmd(ctx, SRC_STRIDE_REG, src->stride); 465 466 if (src_w == dst_w && src_h == dst_h) 467 scale = 0; 468 else { 469 scale = 1; 470 scale_x = g2d_get_scaling(src_w, dst_w); 471 scale_y = g2d_get_scaling(src_h, dst_h); 472 } 473 474 if (src_x + src_w > src->width) 475 src_w = src->width - src_x; 476 if (src_y + src_h > src->height) 477 src_h = src->height - src_y; 478 479 if (dst_x + dst_w > dst->width) 480 dst_w = dst->width - dst_x; 481 if (dst_y + dst_h > dst->height) 482 dst_h = dst->height - dst_y; 483 484 if (src_w <= 0 || src_h <= 0 || dst_w <= 0 || dst_h <= 0) { 485 fprintf(stderr, "invalid width or height.\n"); 486 g2d_reset(ctx); 487 return -EINVAL; 488 } 489 490 if (negative) { 491 g2d_add_cmd(ctx, BG_COLOR_REG, 0x00FFFFFF); 492 rop4.val = 0; 493 rop4.data.unmasked_rop3 = G2D_ROP3_SRC^G2D_ROP3_DST; 494 g2d_add_cmd(ctx, ROP4_REG, rop4.val); 495 } else { 496 rop4.val = 0; 497 rop4.data.unmasked_rop3 = G2D_ROP3_SRC; 498 g2d_add_cmd(ctx, ROP4_REG, rop4.val); 499 } 500 501 if (scale) { 502 g2d_add_cmd(ctx, SRC_SCALE_CTRL_REG, G2D_SCALE_MODE_BILINEAR); 503 g2d_add_cmd(ctx, SRC_XSCALE_REG, scale_x); 504 g2d_add_cmd(ctx, SRC_YSCALE_REG, scale_y); 505 } 506 507 pt.val = 0; 508 pt.data.x = src_x; 509 pt.data.y = src_y; 510 g2d_add_cmd(ctx, SRC_LEFT_TOP_REG, pt.val); 511 pt.val = 0; 512 pt.data.x = src_x + src_w; 513 pt.data.y = src_y + src_h; 514 g2d_add_cmd(ctx, SRC_RIGHT_BOTTOM_REG, pt.val); 515 516 pt.val = 0; 517 pt.data.x = dst_x; 518 pt.data.y = dst_y; 519 g2d_add_cmd(ctx, DST_LEFT_TOP_REG, pt.val); 520 pt.val = 0; 521 pt.data.x = dst_x + dst_w; 522 pt.data.y = dst_y + dst_h; 523 g2d_add_cmd(ctx, DST_RIGHT_BOTTOM_REG, pt.val); 524 525 return g2d_flush(ctx); 526} 527 528/** 529 * g2d_blend - blend image data in source and destination buffers. 530 * 531 * @ctx: a pointer to g2d_context structure. 532 * @src: a pointer to g2d_image structure including image and buffer 533 * information to source. 534 * @dst: a pointer to g2d_image structure including image and buffer 535 * information to destination. 536 * @src_x: x start position to source buffer. 537 * @src_y: y start position to source buffer. 538 * @dst_x: x start position to destination buffer. 539 * @dst_y: y start position to destination buffer. 540 * @w: width value to source and destination buffer. 541 * @h: height value to source and destination buffer. 542 * @op: blend operation type. 543 */ 544int 545g2d_blend(struct g2d_context *ctx, struct g2d_image *src, 546 struct g2d_image *dst, unsigned int src_x, 547 unsigned int src_y, unsigned int dst_x, unsigned int dst_y, 548 unsigned int w, unsigned int h, enum e_g2d_op op) 549{ 550 union g2d_point_val pt; 551 union g2d_bitblt_cmd_val bitblt; 552 union g2d_blend_func_val blend; 553 unsigned int src_w = 0, src_h = 0, dst_w = 0, dst_h = 0; 554 555 bitblt.val = 0; 556 blend.val = 0; 557 558 if (op == G2D_OP_SRC || op == G2D_OP_CLEAR) 559 g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_BGCOLOR); 560 else 561 g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_NORMAL); 562 563 g2d_add_cmd(ctx, DST_COLOR_MODE_REG, dst->color_mode); 564 g2d_add_base_addr(ctx, dst, g2d_dst); 565 g2d_add_cmd(ctx, DST_STRIDE_REG, dst->stride); 566 567 g2d_add_cmd(ctx, SRC_SELECT_REG, src->select_mode); 568 g2d_add_cmd(ctx, SRC_COLOR_MODE_REG, src->color_mode); 569 570 switch (src->select_mode) { 571 case G2D_SELECT_MODE_NORMAL: 572 g2d_add_base_addr(ctx, src, g2d_src); 573 g2d_add_cmd(ctx, SRC_STRIDE_REG, src->stride); 574 break; 575 case G2D_SELECT_MODE_FGCOLOR: 576 g2d_add_cmd(ctx, FG_COLOR_REG, src->color); 577 break; 578 case G2D_SELECT_MODE_BGCOLOR: 579 g2d_add_cmd(ctx, BG_COLOR_REG, src->color); 580 break; 581 default: 582 fprintf(stderr , "failed to set src.\n"); 583 return -EINVAL; 584 } 585 586 src_w = w; 587 src_h = h; 588 if (src_x + w > src->width) 589 src_w = src->width - src_x; 590 if (src_y + h > src->height) 591 src_h = src->height - src_y; 592 593 dst_w = w; 594 dst_h = h; 595 if (dst_x + w > dst->width) 596 dst_w = dst->width - dst_x; 597 if (dst_y + h > dst->height) 598 dst_h = dst->height - dst_y; 599 600 w = MIN(src_w, dst_w); 601 h = MIN(src_h, dst_h); 602 603 if (w <= 0 || h <= 0) { 604 fprintf(stderr, "invalid width or height.\n"); 605 g2d_reset(ctx); 606 return -EINVAL; 607 } 608 609 bitblt.data.alpha_blend_mode = G2D_ALPHA_BLEND_MODE_ENABLE; 610 blend.val = g2d_get_blend_op(op); 611 g2d_add_cmd(ctx, BITBLT_COMMAND_REG, bitblt.val); 612 g2d_add_cmd(ctx, BLEND_FUNCTION_REG, blend.val); 613 614 pt.val = 0; 615 pt.data.x = src_x; 616 pt.data.y = src_y; 617 g2d_add_cmd(ctx, SRC_LEFT_TOP_REG, pt.val); 618 pt.val = 0; 619 pt.data.x = src_x + w; 620 pt.data.y = src_y + h; 621 g2d_add_cmd(ctx, SRC_RIGHT_BOTTOM_REG, pt.val); 622 623 pt.val = 0; 624 pt.data.x = dst_x; 625 pt.data.y = dst_y; 626 g2d_add_cmd(ctx, DST_LEFT_TOP_REG, pt.val); 627 pt.val = 0; 628 pt.data.x = dst_x + w; 629 pt.data.y = dst_y + h; 630 g2d_add_cmd(ctx, DST_RIGHT_BOTTOM_REG, pt.val); 631 632 return g2d_flush(ctx); 633} 634 635/** 636 * g2d_scale_and_blend - apply scaling to source buffer and then blend to destination buffer 637 * 638 * @ctx: a pointer to g2d_context structure. 639 * @src: a pointer to g2d_image structure including image and buffer 640 * information to source. 641 * @dst: a pointer to g2d_image structure including image and buffer 642 * information to destination. 643 * @src_x: x start position to source buffer. 644 * @src_y: y start position to source buffer. 645 * @src_w: width value to source buffer. 646 * @src_h: height value to source buffer. 647 * @dst_x: x start position to destination buffer. 648 * @dst_y: y start position to destination buffer. 649 * @dst_w: width value to destination buffer. 650 * @dst_h: height value to destination buffer. 651 * @op: blend operation type. 652 */ 653int 654g2d_scale_and_blend(struct g2d_context *ctx, struct g2d_image *src, 655 struct g2d_image *dst, unsigned int src_x, unsigned int src_y, 656 unsigned int src_w, unsigned int src_h, unsigned int dst_x, 657 unsigned int dst_y, unsigned int dst_w, unsigned int dst_h, 658 enum e_g2d_op op) 659{ 660 union g2d_point_val pt; 661 union g2d_bitblt_cmd_val bitblt; 662 union g2d_blend_func_val blend; 663 unsigned int scale; 664 unsigned int scale_x, scale_y; 665 666 bitblt.val = 0; 667 blend.val = 0; 668 669 if (op == G2D_OP_SRC || op == G2D_OP_CLEAR) 670 g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_BGCOLOR); 671 else 672 g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_NORMAL); 673 674 g2d_add_cmd(ctx, DST_COLOR_MODE_REG, dst->color_mode); 675 if (dst->buf_type == G2D_IMGBUF_USERPTR) 676 g2d_add_cmd(ctx, DST_BASE_ADDR_REG | G2D_BUF_USERPTR, 677 (unsigned long)&dst->user_ptr[0]); 678 else 679 g2d_add_cmd(ctx, DST_BASE_ADDR_REG, dst->bo[0]); 680 681 g2d_add_cmd(ctx, DST_STRIDE_REG, dst->stride); 682 683 g2d_add_cmd(ctx, SRC_SELECT_REG, src->select_mode); 684 g2d_add_cmd(ctx, SRC_COLOR_MODE_REG, src->color_mode); 685 686 switch (src->select_mode) { 687 case G2D_SELECT_MODE_NORMAL: 688 if (src->buf_type == G2D_IMGBUF_USERPTR) 689 g2d_add_cmd(ctx, SRC_BASE_ADDR_REG | G2D_BUF_USERPTR, 690 (unsigned long)&src->user_ptr[0]); 691 else 692 g2d_add_cmd(ctx, SRC_BASE_ADDR_REG, src->bo[0]); 693 694 g2d_add_cmd(ctx, SRC_STRIDE_REG, src->stride); 695 break; 696 case G2D_SELECT_MODE_FGCOLOR: 697 g2d_add_cmd(ctx, FG_COLOR_REG, src->color); 698 break; 699 case G2D_SELECT_MODE_BGCOLOR: 700 g2d_add_cmd(ctx, BG_COLOR_REG, src->color); 701 break; 702 default: 703 fprintf(stderr , "failed to set src.\n"); 704 return -EINVAL; 705 } 706 707 if (src_w == dst_w && src_h == dst_h) 708 scale = 0; 709 else { 710 scale = 1; 711 scale_x = g2d_get_scaling(src_w, dst_w); 712 scale_y = g2d_get_scaling(src_h, dst_h); 713 } 714 715 if (src_x + src_w > src->width) 716 src_w = src->width - src_x; 717 if (src_y + src_h > src->height) 718 src_h = src->height - src_y; 719 720 if (dst_x + dst_w > dst->width) 721 dst_w = dst->width - dst_x; 722 if (dst_y + dst_h > dst->height) 723 dst_h = dst->height - dst_y; 724 725 if (src_w <= 0 || src_h <= 0 || dst_w <= 0 || dst_h <= 0) { 726 fprintf(stderr, "invalid width or height.\n"); 727 g2d_reset(ctx); 728 return -EINVAL; 729 } 730 731 if (scale) { 732 g2d_add_cmd(ctx, SRC_SCALE_CTRL_REG, G2D_SCALE_MODE_BILINEAR); 733 g2d_add_cmd(ctx, SRC_XSCALE_REG, scale_x); 734 g2d_add_cmd(ctx, SRC_YSCALE_REG, scale_y); 735 } 736 737 bitblt.data.alpha_blend_mode = G2D_ALPHA_BLEND_MODE_ENABLE; 738 blend.val = g2d_get_blend_op(op); 739 g2d_add_cmd(ctx, BITBLT_COMMAND_REG, bitblt.val); 740 g2d_add_cmd(ctx, BLEND_FUNCTION_REG, blend.val); 741 742 pt.val = 0; 743 pt.data.x = src_x; 744 pt.data.y = src_y; 745 g2d_add_cmd(ctx, SRC_LEFT_TOP_REG, pt.val); 746 pt.val = 0; 747 pt.data.x = src_x + src_w; 748 pt.data.y = src_y + src_h; 749 g2d_add_cmd(ctx, SRC_RIGHT_BOTTOM_REG, pt.val); 750 751 pt.val = 0; 752 pt.data.x = dst_x; 753 pt.data.y = dst_y; 754 g2d_add_cmd(ctx, DST_LEFT_TOP_REG, pt.val); 755 pt.val = 0; 756 pt.data.x = dst_x + dst_w; 757 pt.data.y = dst_y + dst_h; 758 g2d_add_cmd(ctx, DST_RIGHT_BOTTOM_REG, pt.val); 759 760 return g2d_flush(ctx); 761} 762