xref: /OK3568_Linux_fs/external/xserver/hw/xfree86/drivers/modesetting/exa.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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