1
0

exynos_fimg2d.c 27 KB

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