compositor: Add G2d render in DRM compositor

Upstream-Status: Inappropriate [i.MX-specific]

Signed-off-by: Yong Gan <yong.gan@nxp.com>
diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c
index 3891176..bf0a227 100644
--- a/libweston/compositor-drm.c
+++ b/libweston/compositor-drm.c
@@ -53,7 +53,16 @@
 #include "compositor-drm.h"
 #include "shared/helpers.h"
 #include "shared/timespec-util.h"
+
+#if defined(ENABLE_IMXGPU)
+#if defined(ENABLE_OPENGL)
 #include "gl-renderer.h"
+#endif
+#if defined(ENABLE_IMXG2D)
+#include "g2d-renderer.h"
+#endif
+#endif
+
 #include "weston-egl-ext.h"
 #include "pixman-renderer.h"
 #include "pixel-formats.h"
@@ -290,6 +299,9 @@
 	bool atomic_modeset;
 
 	int use_pixman;
+#if defined(ENABLE_IMXGPU) && defined(ENABLE_IMXG2D)
+	int use_g2d;
+#endif
 	bool use_pixman_shadow;
 
 	struct udev_input input;
@@ -496,6 +508,9 @@
 
 	struct drm_fb *dumb[2];
 	pixman_image_t *image[2];
+#if defined(ENABLE_IMXGPU) && defined(ENABLE_IMXG2D)
+	struct g2d_surfaceEx g2d_image[2];
+#endif
 	int current_image;
 	pixman_region32_t previous_damage;
 
@@ -513,7 +528,14 @@
 	[WESTON_MODE_PIC_AR_256_135] = " 256:135",
 };
 
+#if defined(ENABLE_IMXGPU)
+#if defined(ENABLE_OPENGL)
 static struct gl_renderer_interface *gl_renderer;
+#endif
+#if defined(ENABLE_IMXG2D)
+static struct g2d_renderer_interface *g2d_renderer;
+#endif
+#endif
 
 static const char default_seat[] = "seat0";
 
@@ -2052,6 +2074,36 @@
 	return drm_fb_ref(output->dumb[output->current_image]);
 }
 
+#if defined(ENABLE_IMXGPU) && defined(ENABLE_IMXG2D)
+static struct drm_fb *
+drm_output_render_g2d(struct drm_output_state *state, pixman_region32_t *damage)
+{
+	struct drm_output *output = state->output;
+	struct weston_compositor *ec = output->base.compositor;
+	pixman_region32_t total_damage, previous_damage;
+
+	pixman_region32_init(&total_damage);
+	pixman_region32_init(&previous_damage);
+
+	pixman_region32_copy(&previous_damage, damage);
+
+	pixman_region32_union(&total_damage, damage, &output->previous_damage);
+	pixman_region32_copy(&output->previous_damage, &previous_damage);
+
+	output->current_image ^= 1;
+
+	g2d_renderer->output_set_buffer(&output->base,
+					  &output->g2d_image[output->current_image]);
+
+	ec->renderer->repaint_output(&output->base, &total_damage);
+
+	pixman_region32_fini(&total_damage);
+	pixman_region32_fini(&previous_damage);
+
+	return drm_fb_ref(output->dumb[output->current_image]);
+}
+#endif
+
 static void
 drm_output_render(struct drm_output_state *state, pixman_region32_t *damage)
 {
@@ -2080,9 +2132,17 @@
 		fb = drm_fb_ref(scanout_plane->state_cur->fb);
 	} else if (b->use_pixman) {
 		fb = drm_output_render_pixman(state, damage);
-	} else {
-		fb = drm_output_render_gl(state, damage);
 	}
+#if defined(ENABLE_IMXGPU)
+#if defined(ENABLE_IMXG2D)
+	else if (b->use_g2d)
+		fb = drm_output_render_g2d(state, damage);
+#endif
+#if defined(ENABLE_OPENGL)
+	else
+		fb = drm_output_render_gl(state, damage);
+#endif
+#endif
 
 	if (!fb) {
 		drm_plane_state_put_back(scanout_state);
@@ -2228,14 +2288,8 @@
 	 * legacy PageFlip API doesn't allow us to do clipping either. */
 	assert(scanout_state->src_x == 0);
 	assert(scanout_state->src_y == 0);
-	assert(scanout_state->src_w ==
-		(unsigned) (output->base.current_mode->width << 16));
-	assert(scanout_state->src_h ==
-		(unsigned) (output->base.current_mode->height << 16));
 	assert(scanout_state->dest_x == 0);
 	assert(scanout_state->dest_y == 0);
-	assert(scanout_state->dest_w == scanout_state->src_w >> 16);
-	assert(scanout_state->dest_h == scanout_state->src_h >> 16);
 
 	mode = to_drm_mode(output->base.current_mode);
 	if (backend->state_invalid ||
@@ -3689,13 +3743,23 @@
 }
 
 static int
-drm_output_init_egl(struct drm_output *output, struct drm_backend *b);
-static void
-drm_output_fini_egl(struct drm_output *output);
-static int
 drm_output_init_pixman(struct drm_output *output, struct drm_backend *b);
 static void
 drm_output_fini_pixman(struct drm_output *output);
+#if defined(ENABLE_IMXGPU)
+#if defined(ENABLE_OPENGL)
+static int
+drm_output_init_egl(struct drm_output *output, struct drm_backend *b);
+static void
+drm_output_fini_egl(struct drm_output *output);
+#endif
+#if defined(ENABLE_IMXG2D)
+static int
+drm_output_init_g2d(struct drm_output *output, struct drm_backend *b);
+static void
+drm_output_fini_g2d(struct drm_output *output);
+#endif
+#endif
 
 static int
 drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
@@ -3734,6 +3798,17 @@
 				   "new mode\n");
 			return -1;
 		}
+#if defined(ENABLE_IMXGPU)
+#if defined(ENABLE_IMXG2D)
+	} else if (b->use_g2d) {
+		drm_output_fini_g2d(output);
+		if (drm_output_init_g2d(output, b) < 0) {
+			weston_log("failed to init output g2d state with "
+				   "new mode\n");
+			return -1;
+		}
+#endif
+#if defined(ENABLE_OPENGL)
 	} else {
 		drm_output_fini_egl(output);
 		if (drm_output_init_egl(output, b) < 0) {
@@ -3741,6 +3816,8 @@
 				   "new mode");
 			return -1;
 		}
+#endif
+#endif
 	}
 
 	return 0;
@@ -3841,6 +3918,7 @@
 	return 0;
 }
 
+#if defined(ENABLE_IMXGPU) && defined(ENABLE_OPENGL)
 static struct gbm_device *
 create_gbm_device(int fd)
 {
@@ -3926,6 +4004,7 @@
 
 	return 0;
 }
+#endif
 
 static int
 init_pixman(struct drm_backend *b)
@@ -3933,6 +4012,43 @@
 	return pixman_renderer_init(b->compositor);
 }
 
+#if defined(ENABLE_IMXGPU) && defined(ENABLE_IMXG2D)
+static int
+drm_backend_create_g2d_renderer(struct drm_backend *b)
+{
+	if (g2d_renderer->drm_display_create(b->compositor,
+					(void *)b->gbm) < 0) {
+		return -1;
+	}
+
+	return 0;
+}
+#endif
+
+#if defined(ENABLE_IMXGPU) && defined(ENABLE_IMXG2D)
+static int
+init_g2d(struct drm_backend *b)
+{
+	g2d_renderer = weston_load_module("g2d-renderer.so",
+						 "g2d_renderer_interface");
+	if (!g2d_renderer) {
+		weston_log("Could not load g2d renderer\n");
+		return -1;
+	}
+
+	b->gbm = gbm_create_device(b->drm.fd);
+	if (!b->gbm)
+		return -1;
+
+	if (drm_backend_create_g2d_renderer(b) < 0) {
+		gbm_device_destroy(b->gbm);
+		return -1;
+	}
+
+	return 0;
+}
+#endif
+
 #ifdef HAVE_DRM_FORMATS_BLOB
 static inline uint32_t *
 formats_ptr(struct drm_format_modifier_blob *blob)
@@ -4627,6 +4743,7 @@
 	return -1;
 }
 
+#if defined(ENABLE_IMXGPU) && defined(ENABLE_OPENGL)
 /* Init output state that depends on gl or gbm */
 static int
 drm_output_init_egl(struct drm_output *output, struct drm_backend *b)
@@ -4691,7 +4808,9 @@
 
 	return 0;
 }
+#endif
 
+#if defined(ENABLE_IMXGPU) && defined(ENABLE_OPENGL)
 static void
 drm_output_fini_egl(struct drm_output *output)
 {
@@ -4712,6 +4831,7 @@
 	gbm_surface_destroy(output->gbm_surface);
 	drm_output_fini_cursor_egl(output);
 }
+#endif
 
 static int
 drm_output_init_pixman(struct drm_output *output, struct drm_backend *b)
@@ -4805,6 +4925,86 @@
 	}
 }
 
+#if defined(ENABLE_IMXGPU) && defined(ENABLE_IMXG2D)
+static int
+drm_output_init_g2d(struct drm_output *output, struct drm_backend *b)
+{
+	int w = output->base.current_mode->width;
+	int h = output->base.current_mode->height;
+	uint32_t format = output->gbm_format;
+	enum g2d_format g2dFormat;
+	uint32_t i = 0;
+
+	switch (format) {
+		case GBM_FORMAT_XRGB8888:
+			g2dFormat = G2D_BGRX8888;
+			break;
+		case GBM_FORMAT_RGB565:
+			g2dFormat = G2D_RGB565;
+			break;
+		default:
+			weston_log("Unsupported pixman format 0x%x\n", format);
+			return -1;
+	}
+
+	for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
+		struct g2d_surfaceEx* g2dSurface = &(output->g2d_image[i]);
+		int ret, dmafd = 0;
+		output->dumb[i] = drm_fb_create_dumb(b, w, h, format);
+		if (!output->dumb[i])
+			goto err;
+
+		ret = drmPrimeHandleToFD(b->drm.fd, output->dumb[i]->handles[0], DRM_CLOEXEC,
+				       &dmafd);
+		if(ret < 0)
+			goto err;
+
+		ret = g2d_renderer->create_g2d_image(g2dSurface, g2dFormat,
+						output->dumb[i]->map,
+						w, h,
+						output->dumb[i]->strides[0],
+						output->dumb[i]->size,
+						dmafd);
+		if (ret < 0)
+			goto err;
+	}
+
+	if (g2d_renderer->drm_output_create(&output->base) < 0)
+		goto err;
+
+	drm_output_init_cursor_egl(output, b);
+
+	return 0;
+
+err:
+	weston_log("drm_output_init_g2d failed.\n");
+	for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
+		if (output->dumb[i])
+			drm_fb_unref(output->dumb[i]);
+
+		output->dumb[i] = NULL;
+	}
+
+	return -1;
+}
+#endif
+
+#if defined(ENABLE_IMXGPU) && defined(ENABLE_IMXG2D)
+static void
+drm_output_fini_g2d(struct drm_output *output)
+{
+	unsigned int i;
+
+	pixman_region32_fini(&output->previous_damage);
+
+	for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
+		drm_fb_unref(output->dumb[i]);
+		output->dumb[i] = NULL;
+	}
+	g2d_renderer->output_destroy(&output->base);
+}
+#endif
+
 static void
 edid_parse_string(const uint8_t *data, char text[])
 {
@@ -5076,6 +5276,8 @@
 		*gbm_format = default_value;
 	else if (strcmp(s, "xrgb8888") == 0)
 		*gbm_format = GBM_FORMAT_XRGB8888;
+	else if (strcmp(s, "argb8888") == 0)
+		*gbm_format = GBM_FORMAT_ARGB8888;
 	else if (strcmp(s, "rgb565") == 0)
 		*gbm_format = GBM_FORMAT_RGB565;
 	else if (strcmp(s, "xrgb2101010") == 0)
@@ -5749,9 +5951,20 @@
 			weston_log("Failed to init output pixman state\n");
 			goto err;
 		}
+#if defined(ENABLE_IMXGPU)
+#if defined(ENABLE_IMXG2D)
+	} else if (b->use_g2d) {
+		if (drm_output_init_g2d(output, b) < 0) {
+			weston_log("Failed to init output g2d state\n");
+			goto err;
+		}
+#endif
+#if defined(ENABLE_OPENGL)
 	} else if (drm_output_init_egl(output, b) < 0) {
 		weston_log("Failed to init output gl state\n");
 		goto err;
+#endif
+#endif
 	}
 
 	drm_output_init_backlight(output);
@@ -5794,8 +6007,16 @@
 
 	if (b->use_pixman)
 		drm_output_fini_pixman(output);
+#if defined(ENABLE_IMXGPU)
+#if defined(ENABLE_IMXG2D)
+	else if (b->use_g2d)
+		drm_output_fini_g2d(output);
+#endif
+#if defined(ENABLE_OPENGL)
 	else
 		drm_output_fini_egl(output);
+#endif
+#endif
 
 	/* Since our planes are no longer in use anywhere, remove their base
 	 * weston_plane's link from the plane stacking list, unless we're
@@ -6628,6 +6849,7 @@
 }
 #endif
 
+#if defined(ENABLE_IMXGPU) && defined(ENABLE_OPENGL)
 static void
 switch_to_gl_renderer(struct drm_backend *b)
 {
@@ -6671,7 +6893,9 @@
 				   "support failed.\n");
 	}
 }
+#endif
 
+#if defined(ENABLE_IMXGPU) && defined(ENABLE_OPENGL)
 static void
 renderer_switch_binding(struct weston_keyboard *keyboard,
 			const struct timespec *time, uint32_t key, void *data)
@@ -6681,6 +6905,7 @@
 
 	switch_to_gl_renderer(b);
 }
+#endif
 
 static const struct weston_drm_output_api api = {
 	drm_output_set_mode,
@@ -6718,6 +6943,9 @@
 
 	b->compositor = compositor;
 	b->use_pixman = config->use_pixman;
+#if defined(ENABLE_IMXGPU) && defined(ENABLE_IMXG2D)
+	b->use_g2d = config->use_g2d;
+#endif
 	b->pageflip_timeout = config->pageflip_timeout;
 	b->use_pixman_shadow = config->use_pixman_shadow;
 
@@ -6764,11 +6992,22 @@
 			weston_log("failed to initialize pixman renderer\n");
 			goto err_udev_dev;
 		}
+#if defined(ENABLE_IMXGPU)
+#if defined(ENABLE_IMXG2D)
+	} else if(b->use_g2d){
+		if (init_g2d(b) < 0) {
+			weston_log("failed to initialize g2d render\n");
+			goto err_udev_dev;
+		}
+#endif
+#if defined(ENABLE_OPENGL)
 	} else {
 		if (init_egl(b) < 0) {
 			weston_log("failed to initialize egl\n");
 			goto err_udev_dev;
 		}
+#endif
+#endif
 	}
 
 	b->base.destroy = drm_destroy;
@@ -6831,8 +7070,10 @@
 					    planes_binding, b);
 	weston_compositor_add_debug_binding(compositor, KEY_Q,
 					    recorder_binding, b);
+#if defined(ENABLE_IMXGPU) && defined(ENABLE_OPENGL)
 	weston_compositor_add_debug_binding(compositor, KEY_W,
 					    renderer_switch_binding, b);
+#endif
 
 	if (compositor->renderer->import_dmabuf) {
 		if (linux_dmabuf_setup(compositor) < 0)
@@ -6876,7 +7117,20 @@
 static void
 config_init_to_defaults(struct weston_drm_backend_config *config)
 {
+#if !defined(ENABLE_IMXGPU) || !defined(ENABLE_OPENGL) && !defined(ENABLE_IMXG2D)
+	config->use_pixman = 1;
 	config->use_pixman_shadow = true;
+#else
+	config->use_pixman = 0;
+	config->use_pixman_shadow = false;
+#endif
+#if defined(ENABLE_IMXGPU) && defined(ENABLE_IMXG2D)
+#if !defined(ENABLE_OPENGL)
+	config->use_g2d = 1;
+#else
+	config->use_g2d = 0;
+#endif
+#endif
 }
 
 WL_EXPORT int