1From 3e5a0cdf3bea40440f5940db6b7d62d74847f258 Mon Sep 17 00:00:00 2001
2From: Jeffy Chen <jeffy.chen@rock-chips.com>
3Date: Fri, 1 Nov 2019 17:55:06 +0800
4Subject: [PATCH 5/6] pixman_image_composite32: Support rockchip RGA 2D accel
5
6Disabled by default, set env PIXMAN_USE_RGA=1 to enable.
7
8Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
9---
10 configure.ac       |   7 ++
11 pixman/Makefile.am |   2 +-
12 pixman/pixman.c    | 278 +++++++++++++++++++++++++++++++++++++++++++++
13 3 files changed, 286 insertions(+), 1 deletion(-)
14
15diff --git a/configure.ac b/configure.ac
16index 43e9b20..5db5f9b 100644
17--- a/configure.ac
18+++ b/configure.ac
19@@ -187,6 +187,13 @@ PIXMAN_CHECK_CFLAG([-Wdeclaration-after-statement])
20 PIXMAN_CHECK_CFLAG([-Wno-unused-local-typedefs])
21 PIXMAN_CHECK_CFLAG([-fno-strict-aliasing])
22
23+dnl check for rockchip RGA
24+PKG_CHECK_MODULES(RGA, [librga],
25+                  AC_DEFINE(HAVE_RGA, 1, [Have rockchip RGA])],
26+                  AC_MSG_NOTICE([Without rockchip RGA]))
27+AC_SUBST(RGA_CFLAGS)
28+AC_SUBST(RGA_LIBS)
29+
30 dnl =========================================================================
31 dnl OpenMP for the test suite?
32 dnl
33diff --git a/pixman/Makefile.am b/pixman/Makefile.am
34index 8f780a1..a9669ab 100644
35--- a/pixman/Makefile.am
36+++ b/pixman/Makefile.am
37@@ -3,7 +3,7 @@ include $(top_srcdir)/pixman/Makefile.sources
38 lib_LTLIBRARIES = libpixman-1.la
39
40 libpixman_1_la_LDFLAGS = -version-info $(LT_VERSION_INFO) -no-undefined @PTHREAD_LDFLAGS@
41-libpixman_1_la_LIBADD = @PTHREAD_LIBS@ -lm
42+libpixman_1_la_LIBADD = @PTHREAD_LIBS@ -lm $(RGA_LIBS)
43 libpixman_1_la_SOURCES = $(libpixman_sources) $(libpixman_headers)
44
45 libpixmanincludedir = $(includedir)/pixman-1
46diff --git a/pixman/pixman.c b/pixman/pixman.c
47index cd7479a..371e421 100644
48--- a/pixman/pixman.c
49+++ b/pixman/pixman.c
50@@ -28,8 +28,19 @@
51 #endif
52 #include "pixman-private.h"
53
54+#include <math.h>
55 #include <stdlib.h>
56
57+#ifdef HAVE_RGA
58+#include <rga/rga.h>
59+#include <rga/RgaApi.h>
60+#endif
61+
62+#define CLAMP(v, low, high)                                             \
63+    (((v) < low)? low : (((v) > high) ? high : (v)))
64+
65+#define ANGLE(n) ((n) < 0 ? (n) + 360 : (n))
66+
67 pixman_implementation_t *global_implementation;
68
69 #ifdef TOOLCHAIN_SUPPORTS_ATTRIBUTE_CONSTRUCTOR
70@@ -540,6 +551,267 @@ analyze_extent (pixman_image_t       *image,
71     return TRUE;
72 }
73
74+#ifdef HAVE_RGA
75+static RgaSURF_FORMAT
76+rga_get_format (pixman_image_t * image)
77+{
78+    switch (image->bits.format)
79+    {
80+    case PIXMAN_a8r8g8b8:
81+    case PIXMAN_x8r8g8b8:
82+	return RK_FORMAT_BGRA_8888;
83+    case PIXMAN_a8b8g8r8:
84+	return RK_FORMAT_RGBA_8888;
85+    case PIXMAN_x8b8g8r8:
86+	return RK_FORMAT_RGBX_8888;
87+    case PIXMAN_r8g8b8:
88+	return RK_FORMAT_BGR_888;
89+    case PIXMAN_b8g8r8:
90+	return RK_FORMAT_RGB_888;
91+    case PIXMAN_r5g6b5:
92+	return RK_FORMAT_RGB_565;
93+    case PIXMAN_a1b5g5r5:
94+    case PIXMAN_x1b5g5r5:
95+	return RK_FORMAT_RGBA_5551;
96+    case PIXMAN_yv12:
97+	return RK_FORMAT_YCrCb_420_P;
98+    case PIXMAN_i420:
99+	return RK_FORMAT_YCbCr_420_P;
100+    case PIXMAN_nv12:
101+	return RK_FORMAT_YCbCr_420_SP;
102+    case PIXMAN_nv16:
103+	return RK_FORMAT_YCbCr_422_SP;
104+    default:
105+	return RK_FORMAT_UNKNOWN;
106+    }
107+}
108+
109+static pixman_bool_t
110+rga_check_image (pixman_image_t * image)
111+{
112+    if (!image)
113+	return FALSE;
114+
115+    /* TODO: Support this */
116+    if (image->bits.rowstride <= 0)
117+	return FALSE;
118+
119+    /* RGA requires image width/height larger than 2 */
120+    if (image->bits.width <= 2 || image->bits.height <= 2)
121+	return FALSE;
122+
123+    return rga_get_format (image) != RK_FORMAT_UNKNOWN;
124+}
125+
126+static pixman_bool_t
127+pixman_transform_to_rga_rotate (pixman_transform_t * transform, int * rotate)
128+{
129+    pixman_vector_t v;
130+    double x, y, dx, dy;
131+    int r1, r2;
132+
133+    *rotate = 0;
134+
135+    if (!transform)
136+	return TRUE;
137+
138+    if (transform->matrix[2][0] || transform->matrix[2][1] ||
139+	!transform->matrix[2][2])
140+        return FALSE;
141+
142+    dx = transform->matrix[0][2] / (double) transform->matrix[2][2];
143+    dy = transform->matrix[1][2] / (double) transform->matrix[2][2];
144+
145+    v.vector[0] = pixman_int_to_fixed (1);
146+    v.vector[1] = pixman_int_to_fixed (0);
147+    v.vector[2] = pixman_fixed_1;
148+    if (!pixman_transform_point_3d (transform, &v))
149+	return FALSE;
150+
151+    x = pixman_fixed_to_double (v.vector[0]) - dx;
152+    y = pixman_fixed_to_double (v.vector[1]) - dy;
153+    r1 = (int) ANGLE (atan2 (y, x) * 180 / M_PI);
154+
155+    /* Only support 0/90/180/270 rotations */
156+    if (r1 % 90)
157+        return FALSE;
158+
159+    v.vector[0] = pixman_int_to_fixed (0);
160+    v.vector[1] = pixman_int_to_fixed (1);
161+    v.vector[2] = pixman_fixed_1;
162+    if (!pixman_transform_point_3d (transform, &v))
163+	return FALSE;
164+
165+    x = pixman_fixed_to_double (v.vector[0]) - dx;
166+    y = pixman_fixed_to_double (v.vector[1]) - dy;
167+    r2 = (int) ANGLE (atan2 (y, x) * 180 / M_PI - 90);
168+
169+    /* TODO: Support reflect */
170+    if (r1 != r2)
171+	return FALSE;
172+
173+    /* Reverse the rotation */
174+    if (r1 == 90)
175+        *rotate = HAL_TRANSFORM_ROT_270;
176+    else if (r1 == 180)
177+        *rotate = HAL_TRANSFORM_ROT_180;
178+    else if (r1 == 270)
179+        *rotate = HAL_TRANSFORM_ROT_90;
180+
181+    return TRUE;
182+}
183+
184+static pixman_bool_t
185+pixman_composite_try_rga (pixman_composite_info_t * info,
186+			  const pixman_box32_t * pbox, int n,
187+			  pixman_implementation_t * imp,
188+			  pixman_composite_func_t func,
189+			  int src_x, int src_y, int dest_x, int dest_y)
190+{
191+    pixman_image_t * src = info->src_image;
192+    pixman_image_t * mask = info->mask_image;
193+    pixman_image_t * dest = info->dest_image;
194+    pixman_transform_t * transform;
195+    rga_info_t src_info = { 0 };
196+    rga_info_t dst_info = { 0 };
197+    int src_stride, is_yuv;
198+
199+    static int rga_supported = 1;
200+    static int rga_inited = 0;
201+    const char *buf;
202+
203+    buf = getenv ("PIXMAN_USE_RGA");
204+    if (!buf || strcmp (buf, "1"))
205+	return FALSE;
206+
207+    if (!rga_supported)
208+	return FALSE;
209+
210+    if (!rga_inited) {
211+	if (c_RkRgaInit () < 0) {
212+	    rga_supported = 0;
213+	    return FALSE;
214+	}
215+	rga_inited = 1;
216+    }
217+
218+    if (mask || src == dest)
219+	return FALSE;
220+
221+    if (!rga_check_image (src) || !rga_check_image (dest))
222+	return FALSE;
223+
224+    /* TODO: Support more op */
225+    if (info->op == PIXMAN_OP_OVER)
226+	src_info.blend = 0xFF0405;
227+    else if (info->op != PIXMAN_OP_SRC)
228+	return FALSE;
229+
230+    /* TODO: Support SOLID */
231+    if (src->type != BITS)
232+	return FALSE;
233+
234+    transform = src->common.transform;
235+    if (!pixman_transform_to_rga_rotate (transform, &src_info.rotation))
236+	return FALSE;
237+
238+    src_info.mmuFlag = 1;
239+    src_info.virAddr = src->bits.bits;
240+
241+    dst_info.mmuFlag = 1;
242+    dst_info.virAddr = dest->bits.bits;
243+
244+    switch (src->bits.format) {
245+    case PIXMAN_yv12:
246+    case PIXMAN_i420:
247+    case PIXMAN_nv12:
248+    case PIXMAN_nv16:
249+	is_yuv = 1;
250+
251+	/* rowstride = rowstride_bytes / (int) sizeof (uint32_t) */
252+	src_stride = src->bits.rowstride * (int) sizeof (uint32_t);
253+	break;
254+    default:
255+	is_yuv = 0;
256+	src_stride = src->bits.rowstride;
257+	break;
258+    }
259+
260+    while (n--)
261+    {
262+	pixman_box16_t box;
263+	int sx, sy, sw, sh, dx, dy, dw, dh;
264+
265+	dx = pbox[n].x1;
266+	dy = pbox[n].y1;
267+	dw = pbox[n].x2 - pbox[n].x1;
268+	dh = pbox[n].y2 - pbox[n].y1;
269+
270+	box.x1 = pbox[n].x1 + src_x - dest_x;
271+	box.y1 = pbox[n].y1 + src_y - dest_y;
272+	box.x2 = pbox[n].x2 + src_x - dest_x;
273+	box.y2 = pbox[n].y2 + src_y - dest_y;
274+
275+	if (transform)
276+	    pixman_transform_bounds (transform, &box);
277+
278+	sx = CLAMP(box.x1, 0, src_stride);
279+	sy = CLAMP(box.y1, 0, src->bits.height);
280+	sw = CLAMP(box.x2 - box.x1, 0, src_stride);
281+	sh = CLAMP(box.y2 - box.y1, 0, src->bits.height);
282+
283+	/* TODO: Support repeat? */
284+	if (sw != dw || sh != dh)
285+	    goto bail;
286+
287+	if (is_yuv) {
288+	    /* RGA requires yuv image rect align to 2 */
289+	    sx = (sx + 1) & ~1;
290+	    sy = (sy + 1) & ~1;
291+	    sw = sw & ~1;
292+	    sh = sh & ~1;
293+
294+	    /* RGA requires yuv image stride align to 2 */
295+	    if (src_stride % 2)
296+		goto bail;
297+	}
298+
299+	/* RGA requires w >= 2 and h >= 2 */
300+	if (sw < 2 || sh < 2 || dw < 2 || dh < 2)
301+	    goto bail;
302+
303+	/* RGA has scale limits */
304+	if ((double) sw / dw > 16 || (double) dw / sw > 16 ||
305+	    (double) sh / dh > 16 || (double) dh / sh > 16)
306+	    goto bail;
307+
308+	rga_set_rect (&src_info.rect, sx, sy, sw, sh,
309+		      src_stride, src->bits.height, rga_get_format (src));
310+
311+	rga_set_rect (&dst_info.rect, dx, dy, dw, dh,
312+		      dest->bits.rowstride, dest->bits.height,
313+		      rga_get_format (dest));
314+
315+	if (c_RkRgaBlit (&src_info, &dst_info, NULL) < 0)
316+	    goto bail;
317+
318+	continue;
319+
320+bail:
321+	info->src_x = pbox[n].x1 + src_x - dest_x;
322+	info->src_y = pbox[n].y1 + src_y - dest_y;
323+	info->dest_x = pbox[n].x1;
324+	info->dest_y = pbox[n].y1;
325+	info->width = pbox[n].x2 - pbox[n].x1;
326+	info->height = pbox[n].y2 - pbox[n].y1;
327+
328+	func (imp, info);
329+    }
330+
331+    return TRUE;
332+}
333+#endif
334+
335 /*
336  * Work around GCC bug causing crashes in Mozilla with SSE2
337  *
338@@ -686,6 +958,12 @@ pixman_image_composite32 (pixman_op_t      op,
339
340     pbox = pixman_region32_rectangles (&region, &n);
341
342+#ifdef HAVE_RGA
343+    if (pixman_composite_try_rga (&info, pbox, n, imp, func,
344+				  src_x, src_y, dest_x, dest_y))
345+	goto out;
346+#endif
347+
348     while (n--)
349     {
350 	info.src_x = pbox->x1 + src_x - dest_x;
351--
3522.20.1
353
354