[PATCH v2 3/4] compositor-drm: Add switch_mode support.

zhiwen.wu at linux.intel.com zhiwen.wu at linux.intel.com
Tue Mar 13 08:18:25 PDT 2012


From: Alex Wu <zhiwen.wu at linux.intel.com>

Implement switch_mode hook for drm backend.
---
 src/compositor-drm.c |  197 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 196 insertions(+), 1 deletions(-)

diff --git a/src/compositor-drm.c b/src/compositor-drm.c
index b01879f..e81b5a4 100644
--- a/src/compositor-drm.c
+++ b/src/compositor-drm.c
@@ -121,6 +121,29 @@ struct drm_sprite {
 	uint32_t formats[];
 };
 
+static struct drm_mode *
+choose_mode (struct drm_output *output, int32_t width, int32_t height, uint32_t refresh)
+{
+	struct drm_mode *tmp_mode = NULL, *mode;
+
+	if (output->base.current->width == width && 
+	    output->base.current->height == height &&
+	    (output->base.current->refresh == refresh ||
+	    refresh == 0))
+		return (struct drm_mode *)output->base.current;
+
+	wl_list_for_each(mode, &output->base.mode_list, base.link) {
+		if (mode->mode_info.hdisplay == width && mode->mode_info.vdisplay == height) {
+			if (mode->mode_info.vrefresh == refresh || refresh == 0) {
+				return mode;
+			} else if (!tmp_mode) 
+				tmp_mode = mode;
+		}
+	}
+
+	return tmp_mode;
+}
+
 static int
 surface_is_primary(struct weston_compositor *ec, struct weston_surface *es)
 {
@@ -743,6 +766,178 @@ drm_output_destroy(struct weston_output *output_base)
 }
 
 static int
+drm_output_switch_mode(struct weston_output *output_base, int32_t width, int32_t height, uint32_t refresh)
+{
+	struct drm_output *output;
+	struct drm_mode *drm_mode;
+	int i, ret;
+	unsigned handle, stride;
+	struct drm_compositor *ec;
+	struct weston_mode *old_mode;
+	GLuint old_rbo[2];
+	uint32_t old_fb_id[2];
+	EGLImageKHR old_image[2];
+	struct gbm_bo *old_bo[2];
+
+	if (output_base == NULL) {
+		fprintf(stderr, "output is NULL.\n");
+		return -1;
+	}
+
+	ec = (struct drm_compositor *)output_base->compositor;
+	output = (struct drm_output *)output_base;
+	drm_mode  = choose_mode (output, width, height, refresh);
+
+	if (!drm_mode) {
+		printf("%s, invalid resolution:%dx%d\n", __func__, width, height);
+		return -1;
+	} else if (&drm_mode->base == output->base.current) {
+		return 0;
+	} else if (drm_mode->base.width == output->base.current->width &&
+	           drm_mode->base.height == output->base.current->height) {
+		/* only change refresh value */
+		ret = drmModeSetCrtc(ec->drm.fd,
+				     output->crtc_id,
+				     output->fb_id[output->current], 0, 0,
+				     &output->connector_id, 1, &drm_mode->mode_info);
+
+		if (ret) {
+			fprintf(stderr, "failed to set mode (%dx%d) %u Hz\n",
+				drm_mode->base.width,
+				drm_mode->base.height,
+				drm_mode->base.refresh);
+			ret = -1;
+		} else {
+			output->base.current->flags = 0;
+			output->base.current = &drm_mode->base;
+			drm_mode->base.flags = 
+				WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
+			ret = 0;
+		}
+
+		return ret;
+	}
+
+	/* store the old output stuff */
+	old_mode  = output->base.current;
+	for (i = 0; i < 2; i++) {
+		old_fb_id[i] = output->fb_id[i];
+		old_image[i] = output->image[i];
+		old_bo[i] = output->bo[i];
+		old_rbo[i] = output->rbo[i];
+	}
+
+	/* reset the output stuff */
+	for (i = 0; i < 2; i++) {
+		output->fb_id[i] = -1;
+		output->image[i] = NULL;
+		output->bo[i] = NULL;
+	}
+
+	output->base.current = &drm_mode->base;
+	drm_mode->base.flags =
+		WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
+	glGenRenderbuffers(2, output->rbo);
+	for (i = 0; i < 2; i++) {
+		glBindRenderbuffer(GL_RENDERBUFFER, output->rbo[i]);
+
+		output->bo[i] =
+		gbm_bo_create(ec->gbm,
+			      output->base.current->width,
+			      output->base.current->height,
+			      GBM_BO_FORMAT_XRGB8888,
+			      GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
+
+		if (!output->bo[i])
+			goto err_bufs;
+
+		output->image[i] = ec->base.create_image(ec->base.display,
+							 NULL,
+							 EGL_NATIVE_PIXMAP_KHR,
+							 output->bo[i], NULL);
+		if (!output->image[i])
+			goto err_bufs;
+
+		ec->base.image_target_renderbuffer_storage(GL_RENDERBUFFER,
+							   output->image[i]);
+		stride = gbm_bo_get_pitch(output->bo[i]);
+		handle = gbm_bo_get_handle(output->bo[i]).u32;
+
+		ret = drmModeAddFB(ec->drm.fd,
+				   output->base.current->width,
+				   output->base.current->height,
+				   24, 32, stride, handle, &output->fb_id[i]);
+
+		if (ret) {
+			fprintf(stderr, "failed to add fb %d: %m\n", i);
+			goto err_bufs;
+		}
+	}
+
+	output->current = 0;
+	glFramebufferRenderbuffer(GL_FRAMEBUFFER,
+				  GL_COLOR_ATTACHMENT0,
+				  GL_RENDERBUFFER,
+				  output->rbo[output->current]);
+
+	ret = drmModeSetCrtc(ec->drm.fd,
+			     output->crtc_id,
+			     output->fb_id[output->current ^ 1], 0, 0,
+			     &output->connector_id, 1, &drm_mode->mode_info);
+	if (ret) {
+		fprintf(stderr, "failed to set mode\n");
+		goto err_fb;
+	}
+
+	/* Destroy old output stuff */
+	old_mode->flags = 0;
+	for (i = 0; i < 2; i++) {
+		if (old_fb_id[i] != -1)
+			drmModeRmFB(ec->drm.fd, old_fb_id[i]);
+		if (old_image[i])
+			ec->base.destroy_image(ec->base.display, old_image[i]);
+		if (old_bo[i])
+			gbm_bo_destroy(old_bo[i]);
+	}
+	glDeleteRenderbuffers(2, old_rbo);
+	weston_output_destroy(&output->base);
+
+	/*update output*/
+	output->base.dirty = 1;
+	weston_output_move(&output->base, output->base.x, output->base.y);
+	return 0;
+
+err_fb:
+	glFramebufferRenderbuffer(GL_FRAMEBUFFER,
+				  GL_COLOR_ATTACHMENT0,
+				  GL_RENDERBUFFER, 0);
+err_bufs:
+	for (i = 0; i < 2; i++) {
+		if (output->fb_id[i] != -1)
+			drmModeRmFB(ec->drm.fd, output->fb_id[i]);
+		if (output->image[i])
+			ec->base.destroy_image(ec->base.display,
+					       output->image[i]);
+		if (output->bo[i])
+			gbm_bo_destroy(output->bo[i]);
+	}
+	glDeleteRenderbuffers(2, output->rbo);
+
+	output->base.current->flags = 0;
+	/* restore old output stuff */
+	output->base.current = old_mode;
+	for (i = 0; i < 2; i++) {
+		output->fb_id[i] = old_fb_id[i];
+		output->image[i] = old_image[i];
+		output->bo[i] = old_bo[i];
+		output->rbo[i] = old_rbo[i];
+		glBindRenderbuffer(GL_RENDERBUFFER, output->rbo[i]);
+	}
+	
+	return -1;
+}
+
+static int
 on_drm_input(int fd, uint32_t mask, void *data)
 {
 	drmEventContext evctx;
@@ -1149,7 +1344,7 @@ create_output_for_connector(struct drm_compositor *ec,
 	output->base.destroy = drm_output_destroy;
 	output->base.assign_planes = drm_assign_planes;
 	output->base.set_dpms = drm_set_dpms;
-	output->base.switch_mode = NULL;
+	output->base.switch_mode = drm_output_switch_mode;
 
 	return 0;
 
-- 
1.7.5.4



More information about the wayland-devel mailing list