1 /*
2 * Copyright (c) 2019, Fuzhou Rockchip Electronics Co., Ltd
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15 #ifdef HAVE_DIX_CONFIG_H
16 #include "dix-config.h"
17 #endif
18
19 #include "exa.h"
20 #include "xf86.h"
21 #include "driver.h"
22 #include "dumb_bo.h"
23 #include "fbpict.h"
24
25 #include <unistd.h>
26
27 #ifdef MODESETTING_WITH_RGA
28 #include <rga/rga.h>
29 #include <rga/RgaApi.h>
30
31 #define RGA_MIN_LINEWIDTH 2
32
33 /* See rga_get_pixmap_format */
34 #define PIXMAP_IS_YUV(pix) ((pix)->drawable.bitsPerPixel == 12)
35 #endif
36
37 #define ABS(n) ((n) < 0 ? -(n) : (n))
38 #define ANGLE(n) ((n) < 0 ? (n) + 360 : (n))
39 #define MIN(a, b) ((a) < (b) ? (a) : (b))
40
41 typedef struct {
42 struct dumb_bo *bo;
43 int fd;
44 int pitch;
45 Bool owned;
46 } ms_exa_pixmap_priv;
47
48 typedef struct {
49 struct {
50 int alu;
51 Pixel planemask;
52 Pixel fg;
53 } solid;
54 struct {
55 PixmapPtr pSrcPixmap;
56 int alu;
57 Pixel planemask;
58 } copy;
59 struct {
60 int op;
61 PicturePtr pSrcPicture;
62 PicturePtr pMaskPicture;
63 PicturePtr pDstPicture;
64 PixmapPtr pSrc;
65 PixmapPtr pMask;
66 PixmapPtr pDst;
67
68 int rotate;
69 Bool reflect_y;
70 } composite;
71 } ms_exa_prepare_args;
72
73 typedef struct {
74 ms_exa_pixmap_priv *scratch_pixmap;
75 ms_exa_prepare_args prepare_args;
76 } ms_exa_ctx;
77
78 #ifdef MODESETTING_WITH_RGA
79
80 static inline RgaSURF_FORMAT
rga_get_pixmap_format(PixmapPtr pPix)81 rga_get_pixmap_format(PixmapPtr pPix)
82 {
83 switch (pPix->drawable.bitsPerPixel) {
84 case 32:
85 if (pPix->drawable.depth == 32)
86 return RK_FORMAT_BGRA_8888;
87 return RK_FORMAT_BGRX_8888;
88 case 12:
89 switch (pPix->drawable.depth) {
90 case 12:
91 return RK_FORMAT_YCbCr_420_SP;
92 /* HACK: Special depth for NV12_10 and NV16*/
93 case 10:
94 return RK_FORMAT_YCbCr_420_SP_10B;
95 default:
96 return RK_FORMAT_YCbCr_422_SP;
97 }
98 default:
99 return RK_FORMAT_UNKNOWN;
100 }
101 }
102
103 static Bool
rga_prepare_info(PixmapPtr pPixmap,rga_info_t * info,int x,int y,int w,int h)104 rga_prepare_info(PixmapPtr pPixmap, rga_info_t *info,
105 int x, int y, int w, int h)
106 {
107 ms_exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPixmap);
108 RgaSURF_FORMAT format;
109 int pitch, wstride, hstride;
110
111 memset(info, 0, sizeof(rga_info_t));
112
113 info->fd = -1;
114 info->mmuFlag = 1;
115
116 if (priv && priv->fd) {
117 info->fd = priv->fd;
118 pitch = priv->pitch;
119 } else {
120 info->virAddr = pPixmap->devPrivate.ptr;
121 pitch = pPixmap->devKind;
122 }
123
124 format = rga_get_pixmap_format(pPixmap);
125
126 /* rga requires yuv image rect align to 2 */
127 if (PIXMAP_IS_YUV(pPixmap)) {
128 x = (x + 1) & ~1;
129 y = (y + 1) & ~1;
130 w = w & ~1;
131 h = h & ~1;
132 }
133
134 /* rga requires image width/height larger than 2 */
135 if (w <= RGA_MIN_LINEWIDTH || h <= RGA_MIN_LINEWIDTH)
136 return FALSE;
137
138 wstride = pitch * 8 / pPixmap->drawable.bitsPerPixel;
139 hstride = pPixmap->drawable.height;
140 if (x < 0 || y < 0 || x + w > wstride || y + h > hstride)
141 return FALSE;
142
143 rga_set_rect(&info->rect, x, y, w, h, wstride, hstride, format);
144
145 return TRUE;
146 }
147
148 static Bool
rga_check_pixmap(PixmapPtr pPixmap)149 rga_check_pixmap(PixmapPtr pPixmap)
150 {
151 ms_exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPixmap);
152 RgaSURF_FORMAT format;
153
154 /* rga requires image width/height larger than 2 */
155 if (pPixmap->drawable.width <= RGA_MIN_LINEWIDTH &&
156 pPixmap->drawable.height <= RGA_MIN_LINEWIDTH)
157 return FALSE;
158
159 format = rga_get_pixmap_format(pPixmap);
160 if (format == RK_FORMAT_UNKNOWN)
161 return FALSE;
162
163 if (pPixmap->devKind && pPixmap->devPrivate.ptr)
164 return TRUE;
165
166 return priv && priv->fd;
167 }
168
169 #endif
170
ms_exa_done(PixmapPtr pPixmap)171 static void ms_exa_done(PixmapPtr pPixmap) {}
172
173 Bool
ms_exa_prepare_access(PixmapPtr pPix,int index)174 ms_exa_prepare_access(PixmapPtr pPix, int index)
175 {
176 ScreenPtr screen = pPix->drawable.pScreen;
177 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
178 modesettingPtr ms = modesettingPTR(scrn);
179 ms_exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPix);
180
181 if (pPix->devPrivate.ptr)
182 return TRUE;
183
184 if (!priv)
185 return FALSE;
186
187 dumb_bo_map(ms->drmmode.fd, priv->bo);
188
189 pPix->devPrivate.ptr = priv->bo->ptr;
190
191 return pPix->devPrivate.ptr != NULL;
192 }
193
194 void
ms_exa_finish_access(PixmapPtr pPix,int index)195 ms_exa_finish_access(PixmapPtr pPix, int index)
196 {
197 ms_exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPix);
198
199 if (priv && priv->bo)
200 pPix->devPrivate.ptr = NULL;
201 }
202
203 static Bool
ms_exa_prepare_solid(PixmapPtr pPixmap,int alu,Pixel planemask,Pixel fg)204 ms_exa_prepare_solid(PixmapPtr pPixmap,
205 int alu, Pixel planemask, Pixel fg)
206 {
207 ScreenPtr screen = pPixmap->drawable.pScreen;
208 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
209 modesettingPtr ms = modesettingPTR(scrn);
210 ms_exa_ctx *ctx = ms->drmmode.exa->priv;
211
212 #ifdef MODESETTING_WITH_RGA
213 //int rop;
214
215 if (planemask != ~0U)
216 return FALSE;
217
218 if (!rga_check_pixmap(pPixmap))
219 return FALSE;
220
221 /* TODO: Support rop */
222 switch (alu) {
223 case GXcopy:
224 break;
225 case GXclear:
226 case GXset:
227 case GXcopyInverted:
228 default:
229 return FALSE;
230 }
231 #endif
232
233 ctx->prepare_args.solid.alu = alu;
234 ctx->prepare_args.solid.planemask = planemask;
235 ctx->prepare_args.solid.fg = fg;
236
237 return TRUE;
238 }
239
240 static void
ms_exa_solid_bail(PixmapPtr pPixmap,int x1,int y1,int x2,int y2)241 ms_exa_solid_bail(PixmapPtr pPixmap, int x1, int y1, int x2, int y2)
242 {
243 ScreenPtr screen = pPixmap->drawable.pScreen;
244 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
245 modesettingPtr ms = modesettingPTR(scrn);
246 ms_exa_ctx *ctx = ms->drmmode.exa->priv;
247
248 ChangeGCVal val[3];
249 GCPtr gc;
250
251 gc = GetScratchGC(pPixmap->drawable.depth, screen);
252
253 val[0].val = ctx->prepare_args.solid.alu;
254 val[1].val = ctx->prepare_args.solid.planemask;
255 val[2].val = ctx->prepare_args.solid.fg;
256 ChangeGC(NullClient, gc, GCFunction | GCPlaneMask | GCForeground, val);
257 ValidateGC(&pPixmap->drawable, gc);
258
259 ms_exa_prepare_access(pPixmap, 0);
260 fbFill(&pPixmap->drawable, gc, x1, y1, x2 - x1, y2 - y1);
261 ms_exa_finish_access(pPixmap, 0);
262
263 FreeScratchGC(gc);
264 }
265
266 static void
ms_exa_solid(PixmapPtr pPixmap,int x1,int y1,int x2,int y2)267 ms_exa_solid(PixmapPtr pPixmap, int x1, int y1, int x2, int y2)
268 {
269 #ifdef MODESETTING_WITH_RGA
270 ScreenPtr screen = pPixmap->drawable.pScreen;
271 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
272 modesettingPtr ms = modesettingPTR(scrn);
273 ms_exa_ctx *ctx = ms->drmmode.exa->priv;
274
275 rga_info_t dst_info = {0};
276 int width = x2 - x1;
277 int height = y2 - y1;
278
279 /* skip small images */
280 if (width * height <= 4096)
281 goto bail;
282
283 if (!rga_prepare_info(pPixmap, &dst_info, x1, y1, x2 - x1, y2 - y1))
284 goto bail;
285
286 dst_info.color = ctx->prepare_args.solid.fg;
287
288 /* rga only support RGBA8888 for color fill */
289 if (pPixmap->drawable.bitsPerPixel != 32)
290 goto bail;
291
292 if (pPixmap->drawable.depth == 24)
293 dst_info.color |= 0xFF << 24;
294
295 dst_info.rect.format = RK_FORMAT_RGBA_8888;
296
297 if (c_RkRgaColorFill(&dst_info) < 0)
298 goto bail;
299
300 return;
301
302 bail:
303 #endif
304
305 ms_exa_solid_bail(pPixmap, x1, y1, x2, y2);
306 }
307
308 static Bool
ms_exa_prepare_copy(PixmapPtr pSrcPixmap,PixmapPtr pDstPixmap,int dx,int dy,int alu,Pixel planemask)309 ms_exa_prepare_copy(PixmapPtr pSrcPixmap,
310 PixmapPtr pDstPixmap,
311 int dx, int dy, int alu, Pixel planemask)
312 {
313 ScreenPtr screen = pSrcPixmap->drawable.pScreen;
314 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
315 modesettingPtr ms = modesettingPTR(scrn);
316 ms_exa_ctx *ctx = ms->drmmode.exa->priv;
317
318 #ifdef MODESETTING_WITH_RGA
319 //int rop;
320
321 if (planemask != ~0U)
322 return FALSE;
323
324 if (!rga_check_pixmap(pSrcPixmap))
325 return FALSE;
326
327 if (!rga_check_pixmap(pDstPixmap))
328 return FALSE;
329
330 /* TODO: Support rop */
331 switch (alu) {
332 case GXcopy:
333 break;
334 case GXclear:
335 case GXset:
336 case GXcopyInverted:
337 default:
338 return FALSE;
339 }
340 #endif
341
342 ctx->prepare_args.copy.pSrcPixmap = pSrcPixmap;
343 ctx->prepare_args.copy.alu = alu;
344 ctx->prepare_args.copy.planemask = planemask;
345
346 return TRUE;
347 }
348
349 static void
ms_exa_copy_bail(PixmapPtr pDstPixmap,int srcX,int srcY,int dstX,int dstY,int width,int height)350 ms_exa_copy_bail(PixmapPtr pDstPixmap, int srcX, int srcY,
351 int dstX, int dstY, int width, int height)
352 {
353 ScreenPtr screen = pDstPixmap->drawable.pScreen;
354 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
355 modesettingPtr ms = modesettingPTR(scrn);
356 ms_exa_ctx *ctx = ms->drmmode.exa->priv;
357
358 PixmapPtr pSrcPixmap = ctx->prepare_args.copy.pSrcPixmap;
359 ChangeGCVal val[2];
360 GCPtr gc;
361
362 gc = GetScratchGC(pDstPixmap->drawable.depth, screen);
363
364 val[0].val = ctx->prepare_args.copy.alu;
365 val[1].val = ctx->prepare_args.copy.planemask;
366 ChangeGC(NullClient, gc, GCFunction | GCPlaneMask, val);
367 ValidateGC(&pDstPixmap->drawable, gc);
368
369 ms_exa_prepare_access(pSrcPixmap, 0);
370 ms_exa_prepare_access(pDstPixmap, 0);
371 fbCopyArea(&pSrcPixmap->drawable, &pDstPixmap->drawable, gc,
372 srcX, srcY, width, height, dstX, dstY);
373 ms_exa_finish_access(pDstPixmap, 0);
374 ms_exa_finish_access(pSrcPixmap, 0);
375
376 FreeScratchGC(gc);
377 }
378
379 static void
ms_exa_copy(PixmapPtr pDstPixmap,int srcX,int srcY,int dstX,int dstY,int width,int height)380 ms_exa_copy(PixmapPtr pDstPixmap, int srcX, int srcY,
381 int dstX, int dstY, int width, int height)
382 {
383 #ifdef MODESETTING_WITH_RGA
384 ScreenPtr screen = pDstPixmap->drawable.pScreen;
385 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
386 modesettingPtr ms = modesettingPTR(scrn);
387 ms_exa_ctx *ctx = ms->drmmode.exa->priv;
388
389 PixmapPtr pSrcPixmap = ctx->prepare_args.copy.pSrcPixmap;
390 rga_info_t src_info = {0};
391 rga_info_t dst_info = {0};
392 rga_info_t tmp_info = {0};
393
394 /* skip small images */
395 if (width * height <= 4096)
396 goto bail;
397
398 if (!rga_prepare_info(pSrcPixmap, &src_info, srcX, srcY, width, height))
399 goto bail;
400
401 if (!rga_prepare_info(pDstPixmap, &dst_info, dstX, dstY, width, height))
402 goto bail;
403
404 /* need an extra buffer for overlap copy */
405 if (pSrcPixmap == pDstPixmap &&
406 (ABS(dstX - srcX) < width || ABS(dstY - srcX) < height)) {
407 tmp_info.fd = ctx->scratch_pixmap->fd;
408 tmp_info.mmuFlag = 1;
409
410 rga_set_rect(&tmp_info.rect, 0, 0, width, height,
411 width, height, rga_get_pixmap_format(pDstPixmap));
412
413 if (c_RkRgaBlit(&src_info, &tmp_info, NULL) < 0)
414 goto bail;
415
416 src_info = tmp_info;
417 }
418
419 if (c_RkRgaBlit(&src_info, &dst_info, NULL) < 0)
420 goto bail;
421
422 return;
423
424 bail:
425 #endif
426
427 ms_exa_copy_bail(pDstPixmap, srcX, srcY, dstX, dstY, width, height);
428 }
429
430 static Bool
ms_exa_check_composite(int op,PicturePtr pSrcPicture,PicturePtr pMaskPicture,PicturePtr pDstPicture)431 ms_exa_check_composite(int op,
432 PicturePtr pSrcPicture,
433 PicturePtr pMaskPicture, PicturePtr pDstPicture)
434 {
435 #ifdef MODESETTING_WITH_RGA
436 /* TODO: Support other op */
437 if (op != PictOpSrc && op != PictOpOver)
438 return FALSE;
439
440 /* TODO: Support mask */
441 if (pMaskPicture)
442 return FALSE;
443
444 /* TODO: Multiply transform from src and dst */
445 if (pDstPicture->transform)
446 return FALSE;
447 #endif
448
449 if (!pSrcPicture->pDrawable)
450 return FALSE;
451
452 return TRUE;
453 }
454
455 static Bool
ms_exa_parse_transform(PictTransformPtr t,int * rotate,Bool * reflect_y)456 ms_exa_parse_transform(PictTransformPtr t, int *rotate, Bool *reflect_y)
457 {
458 PictVector v;
459 double x, y, dx, dy;
460 int r1, r2;
461
462 if (!t) {
463 *rotate = 0;
464 *reflect_y = FALSE;
465 return TRUE;
466 }
467
468 /* Only support affine matrix */
469 if (t->matrix[2][0] || t->matrix[2][1] || !t->matrix[2][2])
470 return FALSE;
471
472 dx = t->matrix[0][2] / (double) t->matrix[2][2];
473 dy = t->matrix[1][2] / (double) t->matrix[2][2];
474
475 v.vector[0] = IntToxFixed(1);
476 v.vector[1] = IntToxFixed(0);
477 v.vector[2] = xFixed1;
478 PictureTransformPoint(t, &v);
479 x = pixman_fixed_to_double(v.vector[0]) - dx;
480 y = pixman_fixed_to_double(v.vector[1]) - dy;
481 r1 = (int) ANGLE(atan2(y, x) * 180 / M_PI);
482
483 /* Only support 0/90/180/270 rotations */
484 if (r1 % 90)
485 return FALSE;
486
487 v.vector[0] = IntToxFixed(0);
488 v.vector[1] = IntToxFixed(1);
489 v.vector[2] = xFixed1;
490 PictureTransformPoint(t, &v);
491 x = pixman_fixed_to_double(v.vector[0]) - dx;
492 y = pixman_fixed_to_double(v.vector[1]) - dy;
493 r2 = (int) ANGLE(atan2(y, x) * 180 / M_PI - 90);
494
495 *rotate = (360 - r1) % 360;
496 *reflect_y = r1 != r2;
497
498 return TRUE;
499 }
500
501 static Bool
ms_exa_prepare_composite(int op,PicturePtr pSrcPicture,PicturePtr pMaskPicture,PicturePtr pDstPicture,PixmapPtr pSrc,PixmapPtr pMask,PixmapPtr pDst)502 ms_exa_prepare_composite(int op,
503 PicturePtr pSrcPicture,
504 PicturePtr pMaskPicture,
505 PicturePtr pDstPicture,
506 PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst)
507 {
508 ScreenPtr screen = pSrc->drawable.pScreen;
509 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
510 modesettingPtr ms = modesettingPTR(scrn);
511 ms_exa_ctx *ctx = ms->drmmode.exa->priv;
512
513 #ifdef MODESETTING_WITH_RGA
514 PictTransformPtr t = pSrcPicture->transform;
515
516 if (!rga_check_pixmap(pSrc))
517 return FALSE;
518
519 if (!rga_check_pixmap(pDst))
520 return FALSE;
521
522 if (pDst == pSrc)
523 return FALSE;
524
525 /* TODO: Support repeat */
526 if (pSrcPicture->repeat)
527 return FALSE;
528
529 /* TODO: Handle pSrcPicture->filter */
530
531 if (!ms_exa_parse_transform(t, &ctx->prepare_args.composite.rotate,
532 &ctx->prepare_args.composite.reflect_y))
533 return FALSE;
534 #endif
535 ctx->prepare_args.composite.op = op;
536 ctx->prepare_args.composite.pSrcPicture = pSrcPicture;
537 ctx->prepare_args.composite.pMaskPicture = pMaskPicture;
538 ctx->prepare_args.composite.pDstPicture = pDstPicture;
539 ctx->prepare_args.composite.pSrc = pSrc;
540 ctx->prepare_args.composite.pMask = pMask;
541
542 return TRUE;
543 }
544
545 static inline void
ms_exa_composite_fix_offsets(DrawablePtr pDrawable,PixmapPtr pPix,int * xoff,int * yoff)546 ms_exa_composite_fix_offsets(DrawablePtr pDrawable, PixmapPtr pPix,
547 int *xoff, int *yoff)
548 {
549 // Base on fb/fb.h#fbGetDrawablePixmap
550 if (pDrawable->type != DRAWABLE_PIXMAP) {
551 ScreenPtr pScreen = pDrawable->pScreen;
552 pPix = pScreen->GetWindowPixmap((WindowPtr) pDrawable);
553
554 #ifdef COMPOSITE
555 *xoff -= pPix->drawable.x - pPix->screen_x;
556 *yoff -= pPix->drawable.y - pPix->screen_y;
557 #else
558 *xoff -= pPix->drawable.x;
559 *yoff -= pPix->drawable.y;
560 #endif
561 } else {
562 *xoff -= pDrawable->x;
563 *yoff -= pDrawable->y;
564 }
565
566 // Based on fb/fbpict.c#create_bits_picture
567 *xoff -= pDrawable->x;
568 *yoff -= pDrawable->y;
569 }
570
571 static void
ms_exa_composite_bail(PixmapPtr pDst,int srcX,int srcY,int maskX,int maskY,int dstX,int dstY,int width,int height)572 ms_exa_composite_bail(PixmapPtr pDst, int srcX, int srcY,
573 int maskX, int maskY, int dstX, int dstY,
574 int width, int height)
575 {
576 ScreenPtr screen = pDst->drawable.pScreen;
577 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
578 modesettingPtr ms = modesettingPTR(scrn);
579 ms_exa_ctx *ctx = ms->drmmode.exa->priv;
580
581 PicturePtr pSrcPicture = ctx->prepare_args.composite.pSrcPicture;
582 PicturePtr pMaskPicture = ctx->prepare_args.composite.pMaskPicture;
583 PicturePtr pDstPicture = ctx->prepare_args.composite.pDstPicture;
584 PixmapPtr pSrc = ctx->prepare_args.composite.pSrc;
585 PixmapPtr pMask = ctx->prepare_args.composite.pMask;
586 int op = ctx->prepare_args.composite.op;
587
588 if (pMask)
589 ms_exa_prepare_access(pMask, 0);
590
591 ms_exa_prepare_access(pSrc, 0);
592 ms_exa_prepare_access(pDst, 0);
593
594 ms_exa_composite_fix_offsets(pSrcPicture->pDrawable, pSrc, &srcX, &srcY);
595 ms_exa_composite_fix_offsets(pDstPicture->pDrawable, pDst, &dstX, &dstY);
596 if (pMaskPicture && pMask)
597 ms_exa_composite_fix_offsets(pMaskPicture->pDrawable,
598 pMask, &maskX, &maskY);
599
600 fbComposite(op, pSrcPicture, pMaskPicture, pDstPicture,
601 srcX, srcY, maskX, maskY,
602 dstX, dstY, width, height);
603
604 ms_exa_finish_access(pDst, 0);
605 ms_exa_finish_access(pSrc, 0);
606
607 if (pMask)
608 ms_exa_finish_access(pMask, 0);
609 }
610
611 static void
ms_exa_composite(PixmapPtr pDst,int srcX,int srcY,int maskX,int maskY,int dstX,int dstY,int width,int height)612 ms_exa_composite(PixmapPtr pDst, int srcX, int srcY,
613 int maskX, int maskY, int dstX, int dstY,
614 int width, int height)
615 {
616 #ifdef MODESETTING_WITH_RGA
617 ScreenPtr screen = pDst->drawable.pScreen;
618 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
619 modesettingPtr ms = modesettingPTR(scrn);
620 ms_exa_ctx *ctx = ms->drmmode.exa->priv;
621
622 PictTransformPtr t = ctx->prepare_args.composite.pSrcPicture->transform;
623 PixmapPtr pSrc = ctx->prepare_args.composite.pSrc;
624 BoxRec box = {
625 .x1 = srcX,
626 .y1 = srcY,
627 .x2 = srcX + width,
628 .y2 = srcY + height,
629 };
630 rga_info_t src_info = {0};
631 rga_info_t dst_info = {0};
632 rga_info_t tmp_info = {0};
633 Bool reflect_y = ctx->prepare_args.composite.reflect_y;
634 int rotate = ctx->prepare_args.composite.rotate;
635 int op = ctx->prepare_args.composite.op;
636 int sw, sh, blend = 0;
637
638 /* skip small images */
639 if (width * height <= 4096)
640 goto bail;
641
642 if (t)
643 pixman_transform_bounds(t, &box);
644
645 sw = box.x2 - box.x1;
646 sh = box.y2 - box.y1;
647
648 /* rga has scale limits */
649 if ((double)sw / width > 16 || (double)width / sw > 16 ||
650 (double)sh / height > 16 || (double)height / sh > 16)
651 goto bail;
652
653 if (!rga_prepare_info(pSrc, &src_info, box.x1, box.y1, sw, sh))
654 goto bail;
655
656 if (!rga_prepare_info(pDst, &dst_info, dstX, dstY, width, height))
657 goto bail;
658
659 /* dst = src + (1 - src.a) * dst */
660 if (op == PictOpOver)
661 blend = 0xFF0405;
662
663 if (rotate == 90)
664 src_info.rotation = HAL_TRANSFORM_ROT_90;
665 else if (rotate == 180)
666 src_info.rotation = HAL_TRANSFORM_ROT_180;
667 else if (rotate == 270)
668 src_info.rotation = HAL_TRANSFORM_ROT_270;
669
670 /* need an extra buffer for reflect + rotate composite */
671 if (reflect_y && rotate) {
672 tmp_info.fd = ctx->scratch_pixmap->fd;
673 tmp_info.mmuFlag = 1;
674
675 rga_set_rect(&tmp_info.rect, 0, 0, width, height,
676 width, height, rga_get_pixmap_format(pDst));
677
678 src_info.blend = blend;
679 if (c_RkRgaBlit(&src_info, &tmp_info, NULL) < 0)
680 goto bail;
681
682 src_info = tmp_info;
683 }
684
685 if (reflect_y)
686 src_info.rotation = HAL_TRANSFORM_FLIP_V;
687
688 src_info.blend = blend;
689 if (c_RkRgaBlit(&src_info, &dst_info, NULL) < 0)
690 goto bail;
691
692 return;
693
694 bail:
695 #endif
696
697 ms_exa_composite_bail(pDst, srcX, srcY, maskX, maskY,
698 dstX, dstY, width, height);
699 }
700
701 static Bool
ms_exa_upload_to_screen(PixmapPtr pDst,int x,int y,int w,int h,char * src,int src_pitch)702 ms_exa_upload_to_screen(PixmapPtr pDst, int x, int y, int w, int h,
703 char *src, int src_pitch)
704 {
705 #ifndef MODESETTING_WITH_RGA
706 return FALSE;
707 #else
708 ScreenPtr screen = pDst->drawable.pScreen;
709 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
710 modesettingPtr ms = modesettingPTR(scrn);
711 ms_exa_ctx *ctx = ms->drmmode.exa->priv;
712
713 PixmapPtr pixmap;
714 Bool ret = FALSE;
715
716 /* rga requires image width/height larger than 2 */
717 if (w <= RGA_MIN_LINEWIDTH || h <= RGA_MIN_LINEWIDTH)
718 return FALSE;
719
720 /* skip small images */
721 if (w * h <= 4096)
722 return FALSE;
723
724 if (!rga_check_pixmap(pDst))
725 return FALSE;
726
727 /* copy the h-1 lines */
728 h -= 1;
729 pixmap = drmmode_create_pixmap_header(screen, w, h,
730 pDst->drawable.depth,
731 pDst->drawable.bitsPerPixel,
732 src_pitch, NULL);
733 if (!pixmap)
734 goto out;
735
736 pixmap->devKind = src_pitch;
737 pixmap->devPrivate.ptr = src;
738 ctx->prepare_args.copy.pSrcPixmap = pixmap;
739 ms_exa_copy(pDst, 0, 0, x, y, w, h);
740
741 screen->DestroyPixmap(pixmap);
742
743 /* copy the last line separately */
744 pixmap = drmmode_create_pixmap_header(screen, w, 1,
745 pDst->drawable.depth,
746 pDst->drawable.bitsPerPixel,
747 src_pitch, NULL);
748 if (!pixmap)
749 goto out;
750
751 pixmap->devKind = w * pDst->drawable.bitsPerPixel / 8;
752 pixmap->devPrivate.ptr = src + src_pitch * h;
753 ctx->prepare_args.copy.pSrcPixmap = pixmap;
754 ms_exa_copy(pDst, 0, 0, x, y + h, w, 1);
755
756 ret = TRUE;
757
758 out:
759 if (pixmap)
760 screen->DestroyPixmap(pixmap);
761
762 return ret;
763 #endif
764 }
765
766 static Bool
ms_exa_download_from_screen(PixmapPtr pSrc,int x,int y,int w,int h,char * dst,int dst_pitch)767 ms_exa_download_from_screen(PixmapPtr pSrc, int x, int y, int w, int h,
768 char *dst, int dst_pitch)
769 {
770 #ifndef MODESETTING_WITH_RGA
771 return FALSE;
772 #else
773 ScreenPtr screen = pSrc->drawable.pScreen;
774 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
775 modesettingPtr ms = modesettingPTR(scrn);
776 ms_exa_ctx *ctx = ms->drmmode.exa->priv;
777
778 PixmapPtr pixmap;
779 Bool ret = FALSE;
780
781 /* rga requires image width/height larger than 2 */
782 if (w <= RGA_MIN_LINEWIDTH || h <= RGA_MIN_LINEWIDTH)
783 return FALSE;
784
785 /* skip small images */
786 if (w * h <= 4096)
787 return FALSE;
788
789 if (!rga_check_pixmap(pSrc))
790 return FALSE;
791
792 ctx->prepare_args.copy.pSrcPixmap = pSrc;
793
794 /* copy the h-1 lines */
795 h -= 1;
796 pixmap = drmmode_create_pixmap_header(screen, w, h,
797 pSrc->drawable.depth,
798 pSrc->drawable.bitsPerPixel,
799 dst_pitch, NULL);
800 if (!pixmap)
801 goto out;
802
803 pixmap->devKind = dst_pitch;
804 pixmap->devPrivate.ptr = dst;
805 ms_exa_copy(pixmap, x, y, 0, 0, w, h);
806
807 screen->DestroyPixmap(pixmap);
808
809 /* copy the last line separately */
810 pixmap = drmmode_create_pixmap_header(screen, w, 1,
811 pSrc->drawable.depth,
812 pSrc->drawable.bitsPerPixel,
813 dst_pitch, NULL);
814 if (!pixmap)
815 goto out;
816
817 pixmap->devKind = w * pSrc->drawable.bitsPerPixel / 8;
818 pixmap->devPrivate.ptr = dst + dst_pitch * h;
819 ms_exa_copy(pixmap, x, y + h, 0, 0, w, 1);
820
821 ret = TRUE;
822
823 out:
824 if (pixmap)
825 screen->DestroyPixmap(pixmap);
826
827 return ret;
828 #endif
829 }
830
831 static void
ms_exa_wait_marker(ScreenPtr pScreen,int marker)832 ms_exa_wait_marker(ScreenPtr pScreen, int marker)
833 {
834 // TODO: Use async rga, and sync for specified request here.
835 }
836
837 static int
ms_exa_mark_sync(ScreenPtr pScreen)838 ms_exa_mark_sync(ScreenPtr pScreen)
839 {
840 // TODO: return latest request(marker).
841 return 0;
842 }
843
844 static void
ms_exa_destroy_pixmap(ScreenPtr pScreen,void * driverPriv)845 ms_exa_destroy_pixmap(ScreenPtr pScreen, void *driverPriv)
846 {
847 ScrnInfoPtr scrn = xf86Screens[pScreen->myNum];
848 modesettingPtr ms = modesettingPTR(scrn);
849 ms_exa_pixmap_priv *priv = driverPriv;
850
851 if (priv->fd > 0)
852 close(priv->fd);
853
854 if (priv->owned && priv->bo)
855 dumb_bo_destroy(ms->drmmode.fd, priv->bo);
856
857 free(priv);
858 }
859
860 static void *
ms_exa_create_pixmap2(ScreenPtr pScreen,int width,int height,int depth,int usage_hint,int bitsPerPixel,int * new_fb_pitch)861 ms_exa_create_pixmap2(ScreenPtr pScreen, int width, int height,
862 int depth, int usage_hint, int bitsPerPixel,
863 int *new_fb_pitch)
864 {
865 ScrnInfoPtr scrn = xf86Screens[pScreen->myNum];
866 modesettingPtr ms = modesettingPTR(scrn);
867 ms_exa_pixmap_priv *priv;
868
869 priv = calloc(1, sizeof(ms_exa_pixmap_priv));
870 if (!priv)
871 return NULL;
872
873 if (!width && !height)
874 return priv;
875
876 priv->bo = dumb_bo_create(ms->drmmode.fd, width, height, bitsPerPixel);
877 if (!priv->bo)
878 goto fail;
879
880 priv->owned = TRUE;
881
882 priv->fd = dumb_bo_get_fd(ms->drmmode.fd, priv->bo, 0);
883 priv->pitch = priv->bo->pitch;
884
885 if (new_fb_pitch)
886 *new_fb_pitch = priv->pitch;
887
888 return priv;
889
890 fail:
891 free(priv);
892 return NULL;
893 }
894
895 static Bool
ms_exa_pixmap_is_offscreen(PixmapPtr pPixmap)896 ms_exa_pixmap_is_offscreen(PixmapPtr pPixmap)
897 {
898 ms_exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPixmap);
899
900 return priv && priv->bo;
901 }
902
903 Bool
ms_exa_set_pixmap_bo(ScrnInfoPtr scrn,PixmapPtr pPixmap,struct dumb_bo * bo,Bool owned)904 ms_exa_set_pixmap_bo(ScrnInfoPtr scrn, PixmapPtr pPixmap,
905 struct dumb_bo *bo, Bool owned)
906 {
907 ms_exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPixmap);
908 modesettingPtr ms = modesettingPTR(scrn);
909
910 if (!ms->drmmode.exa || !priv)
911 return FALSE;
912
913 if (priv->fd > 0)
914 close(priv->fd);
915
916 if (priv->owned && priv->bo)
917 dumb_bo_destroy(ms->drmmode.fd, priv->bo);
918
919 priv->bo = bo;
920 priv->fd = dumb_bo_get_fd(ms->drmmode.fd, priv->bo, 0);
921 priv->pitch = priv->bo->pitch;
922
923 priv->owned = owned;
924
925 pPixmap->devPrivate.ptr = NULL;
926 pPixmap->devKind = priv->pitch;
927
928 return TRUE;
929 }
930
931 struct dumb_bo *
ms_exa_bo_from_pixmap(ScreenPtr screen,PixmapPtr pixmap)932 ms_exa_bo_from_pixmap(ScreenPtr screen, PixmapPtr pixmap)
933 {
934 ms_exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pixmap);
935 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
936 modesettingPtr ms = modesettingPTR(scrn);
937
938 if (!ms->drmmode.exa || !priv)
939 return NULL;
940
941 return priv->bo;
942 }
943
944 void
ms_exa_exchange_buffers(PixmapPtr front,PixmapPtr back)945 ms_exa_exchange_buffers(PixmapPtr front, PixmapPtr back)
946 {
947 ms_exa_pixmap_priv *front_priv = exaGetPixmapDriverPrivate(front);
948 ms_exa_pixmap_priv *back_priv = exaGetPixmapDriverPrivate(back);
949 ms_exa_pixmap_priv tmp_priv;
950
951 tmp_priv = *front_priv;
952 *front_priv = *back_priv;
953 *back_priv = tmp_priv;
954 }
955
956 Bool
ms_exa_back_pixmap_from_fd(PixmapPtr pixmap,int fd,CARD16 width,CARD16 height,CARD16 stride,CARD8 depth,CARD8 bpp)957 ms_exa_back_pixmap_from_fd(PixmapPtr pixmap,
958 int fd,
959 CARD16 width,
960 CARD16 height,
961 CARD16 stride, CARD8 depth, CARD8 bpp)
962 {
963 ScreenPtr screen = pixmap->drawable.pScreen;
964 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
965 modesettingPtr ms = modesettingPTR(scrn);
966 struct dumb_bo *bo;
967 Bool ret;
968
969 bo = dumb_get_bo_from_fd(ms->drmmode.fd, fd,
970 stride, stride * height);
971 if (!bo)
972 return FALSE;
973
974 screen->ModifyPixmapHeader(pixmap, width, height,
975 depth, bpp, stride, NULL);
976
977 ret = ms_exa_set_pixmap_bo(scrn, pixmap, bo, TRUE);
978 if (!ret)
979 dumb_bo_destroy(ms->drmmode.fd, bo);
980
981 return ret;
982 }
983
984 int
ms_exa_shareable_fd_from_pixmap(ScreenPtr screen,PixmapPtr pixmap,CARD16 * stride,CARD32 * size)985 ms_exa_shareable_fd_from_pixmap(ScreenPtr screen,
986 PixmapPtr pixmap,
987 CARD16 *stride,
988 CARD32 *size)
989 {
990 ms_exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pixmap);
991 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
992 modesettingPtr ms = modesettingPTR(scrn);
993
994 if (!ms->drmmode.exa || !priv || !priv->fd)
995 return -1;
996
997 return priv->fd;
998 }
999
1000 Bool
ms_exa_copy_area(PixmapPtr pSrc,PixmapPtr pDst,pixman_f_transform_t * transform,RegionPtr clip)1001 ms_exa_copy_area(PixmapPtr pSrc, PixmapPtr pDst,
1002 pixman_f_transform_t *transform, RegionPtr clip)
1003 {
1004 #ifdef MODESETTING_WITH_RGA
1005 ScreenPtr screen = pSrc->drawable.pScreen;
1006 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
1007 modesettingPtr ms = modesettingPTR(scrn);
1008 rga_info_t src_info = {0};
1009 rga_info_t dst_info = {0};
1010 RegionPtr region = NULL;
1011 BoxPtr box;
1012 int n;
1013
1014 if (!ms->drmmode.exa)
1015 goto bail;
1016
1017 if (!rga_check_pixmap(pSrc))
1018 goto bail;
1019
1020 if (!rga_check_pixmap(pDst))
1021 goto bail;
1022
1023 /* Fallback to compositor for rotate / reflect */
1024 if (transform) {
1025 pixman_transform_t t;
1026 Bool reflect_y = FALSE;
1027 int rotate = 0;
1028
1029 pixman_transform_from_pixman_f_transform(&t, transform);
1030 if (!ms_exa_parse_transform(&t, &rotate, &reflect_y))
1031 goto bail;
1032
1033 if (rotate || reflect_y)
1034 goto bail;
1035 }
1036
1037 region = RegionDuplicate(clip);
1038 n = REGION_NUM_RECTS(region);
1039
1040 while(n--) {
1041 int sx, sy, sw, sh, dx, dy, dw, dh;
1042 box = REGION_RECTS(region) + n;
1043
1044 box->x1 = max(box->x1, 0);
1045 box->y1 = max(box->y1, 0);
1046 box->x2 = min(box->x2, pDst->drawable.width);
1047 box->y2 = min(box->y2, pDst->drawable.height);
1048
1049 dx = box->x1;
1050 dy = box->y1;
1051 dw = box->x2 - box->x1;
1052 dh = box->y2 - box->y1;
1053
1054 if (transform)
1055 pixman_f_transform_bounds(transform, box);
1056
1057 sx = max(box->x1, 0);
1058 sy = max(box->y1, 0);
1059 sw = min(box->x2, pSrc->drawable.width) - sx;
1060 sh = min(box->y2, pSrc->drawable.height) - sy;
1061
1062 /* rga has scale limits */
1063 if ((double)sw / dw > 16 || (double)dw / sw > 16 ||
1064 (double)sh / dh > 16 || (double)dh / sh > 16)
1065 goto err;
1066
1067 if (!rga_prepare_info(pSrc, &src_info, sx, sy, sw, sh))
1068 goto err;
1069
1070 if (!rga_prepare_info(pDst, &dst_info, dx, dy, dw, dh))
1071 goto err;
1072
1073 if (!c_RkRgaBlit(&src_info, &dst_info, NULL))
1074 continue;
1075 err:
1076 /* HACK: Ignoring errors for YUV, since xserver cannot handle it */
1077 if (!PIXMAP_IS_YUV(pSrc) && !PIXMAP_IS_YUV(pDst))
1078 goto bail;
1079 }
1080
1081 RegionDestroy(region);
1082 return TRUE;
1083
1084 bail:
1085 if (region)
1086 RegionDestroy(region);
1087 #endif
1088
1089 return ms_copy_area(pSrc, pDst, transform, clip);
1090 }
1091
1092 static inline void
ms_setup_exa(ExaDriverPtr exa)1093 ms_setup_exa(ExaDriverPtr exa)
1094 {
1095 exa->exa_major = EXA_VERSION_MAJOR;
1096 exa->exa_minor = EXA_VERSION_MINOR;
1097
1098 exa->pixmapPitchAlign = 8;
1099 exa->flags = EXA_OFFSCREEN_PIXMAPS;
1100 exa->maxX = 4096;
1101 exa->maxY = 4096;
1102
1103 exa->PrepareSolid = ms_exa_prepare_solid;
1104 exa->Solid = ms_exa_solid;
1105 exa->DoneSolid = ms_exa_done;
1106
1107 exa->PrepareCopy = ms_exa_prepare_copy;
1108 exa->Copy = ms_exa_copy;
1109 exa->DoneCopy = ms_exa_done;
1110
1111 exa->CheckComposite = ms_exa_check_composite;
1112 exa->PrepareComposite = ms_exa_prepare_composite;
1113 exa->Composite = ms_exa_composite;
1114 exa->DoneComposite = ms_exa_done;
1115
1116 /* Disable upload/download, until rga2 crash issue fixed */
1117 exa->UploadToScreen = ms_exa_upload_to_screen;
1118 exa->DownloadFromScreen = ms_exa_download_from_screen;
1119
1120 exa->WaitMarker = ms_exa_wait_marker;
1121 exa->MarkSync = ms_exa_mark_sync;
1122
1123 // bo based pixmap ops
1124 exa->flags |= EXA_HANDLES_PIXMAPS | EXA_SUPPORTS_PREPARE_AUX;
1125
1126 exa->DestroyPixmap = ms_exa_destroy_pixmap;
1127 exa->CreatePixmap2 = ms_exa_create_pixmap2;
1128 exa->PrepareAccess = ms_exa_prepare_access;
1129 exa->FinishAccess = ms_exa_finish_access;
1130 exa->PixmapIsOffscreen = ms_exa_pixmap_is_offscreen;
1131 }
1132
1133 Bool
ms_init_exa(ScrnInfoPtr scrn)1134 ms_init_exa(ScrnInfoPtr scrn)
1135 {
1136 modesettingPtr ms = modesettingPTR(scrn);
1137 ScreenPtr screen = scrn->pScreen;
1138 drmmode_exa *exa;
1139 ms_exa_ctx *ctx;
1140
1141 if (ms->drmmode.exa)
1142 ms_deinit_exa(scrn);
1143
1144 #ifdef MODESETTING_WITH_RGA
1145 if (c_RkRgaInit() < 0)
1146 return FALSE;
1147
1148 xf86DrvMsg(scrn->scrnIndex, X_INFO, "Using RGA EXA\n");
1149 #else
1150 xf86DrvMsg(scrn->scrnIndex, X_INFO, "Using software EXA\n");
1151 #endif
1152
1153 ms->drmmode.exa = calloc(1, sizeof(drmmode_exa));
1154 if (!ms->drmmode.exa)
1155 return FALSE;
1156
1157 exa = ms->drmmode.exa;
1158 exa->driver = exaDriverAlloc();
1159 if (!exa->driver)
1160 goto bail;
1161
1162 ms_setup_exa(exa->driver);
1163
1164 if (!exaDriverInit(screen, exa->driver))
1165 goto bail;
1166
1167 exa->priv = calloc(1, sizeof(ms_exa_ctx));
1168 if (!exa->priv)
1169 goto bail;
1170
1171 ctx = exa->priv;
1172 ctx->scratch_pixmap = ms_exa_create_pixmap2(screen,
1173 exa->driver->maxX, exa->driver->maxY,
1174 scrn->depth, 0,
1175 scrn->bitsPerPixel,
1176 NULL);
1177 if (!ctx->scratch_pixmap)
1178 goto bail;
1179
1180 return TRUE;
1181
1182 bail:
1183 ms_deinit_exa(scrn);
1184 return FALSE;
1185 }
1186
1187 void
ms_deinit_exa(ScrnInfoPtr scrn)1188 ms_deinit_exa(ScrnInfoPtr scrn)
1189 {
1190 modesettingPtr ms = modesettingPTR(scrn);
1191 ScreenPtr screen = scrn->pScreen;
1192 drmmode_exa *exa;
1193 ms_exa_ctx *ctx;
1194
1195 if (!ms->drmmode.exa)
1196 return;
1197
1198 exa = ms->drmmode.exa;
1199 ctx = exa->priv;
1200
1201 if (ctx) {
1202 if (ctx->scratch_pixmap)
1203 ms_exa_destroy_pixmap(screen, ctx->scratch_pixmap);
1204
1205 free(ctx);
1206 }
1207
1208 if (exa->driver) {
1209 exaDriverFini(screen);
1210 free(exa->driver);
1211 }
1212
1213 free(exa);
1214 ms->drmmode.exa = NULL;
1215
1216 #ifdef MODESETTING_WITH_RGA
1217 c_RkRgaDeInit();
1218 #endif
1219 }
1220