[PATCH 2/3] compositor-drm: Add switch_mode support.
zhiwen.wu at linux.intel.com
zhiwen.wu at linux.intel.com
Tue Apr 17 02:20:48 PDT 2012
From: Alex Wu <zhiwen.wu at linux.intel.com>
Implement switch_mode hook for drm backend.
---
src/compositor-drm.c | 150 +++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 149 insertions(+), 1 deletions(-)
diff --git a/src/compositor-drm.c b/src/compositor-drm.c
index 4232f78..deda815 100644
--- a/src/compositor-drm.c
+++ b/src/compositor-drm.c
@@ -757,6 +757,154 @@ drm_output_destroy(struct weston_output *output_base)
free(output);
}
+static struct drm_mode *
+choose_mode (struct drm_output *output, struct weston_mode *target_mode)
+{
+ struct drm_mode *tmp_mode = NULL, *mode;
+
+ if (output->base.current->width == target_mode->width &&
+ output->base.current->height == target_mode->height &&
+ (output->base.current->refresh == target_mode->refresh ||
+ target_mode->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 == target_mode->width &&
+ mode->mode_info.vdisplay == target_mode->height) {
+ if (mode->mode_info.vrefresh == target_mode->refresh ||
+ target_mode->refresh == 0) {
+ return mode;
+ } else if (!tmp_mode)
+ tmp_mode = mode;
+ }
+ }
+
+ return tmp_mode;
+}
+
+static int
+drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
+{
+ struct drm_output *output;
+ struct drm_mode *drm_mode;
+ int ret;
+ struct drm_compositor *ec;
+ struct gbm_surface *surface;
+ EGLSurface egl_surface;
+
+ if (output_base == NULL) {
+ fprintf(stderr, "output is NULL.\n");
+ return -1;
+ }
+
+ if (mode == NULL) {
+ fprintf(stderr, "mode is NULL.\n");
+ return -1;
+ }
+
+ ec = (struct drm_compositor *)output_base->compositor;
+ output = (struct drm_output *)output_base;
+ drm_mode = choose_mode (output, mode);
+
+ if (!drm_mode) {
+ printf("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->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->current_fb_id, 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;
+ }
+
+ drm_mode->base.flags =
+ WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
+
+ surface = gbm_surface_create(ec->gbm,
+ drm_mode->base.width,
+ drm_mode->base.height,
+ GBM_FORMAT_XRGB8888,
+ GBM_BO_USE_SCANOUT |
+ GBM_BO_USE_RENDERING);
+ if (!surface) {
+ fprintf(stderr, "failed to create gbm surface\n");
+ return -1;
+ }
+
+ egl_surface =
+ eglCreateWindowSurface(ec->base.display,
+ ec->base.config,
+ surface, NULL);
+
+ if (egl_surface == EGL_NO_SURFACE) {
+ fprintf(stderr, "failed to create egl surface\n");
+ goto err;
+ }
+
+ ret = drmModeSetCrtc(ec->drm.fd,
+ output->crtc_id,
+ output->current_fb_id, 0, 0,
+ &output->connector_id, 1, &drm_mode->mode_info);
+ if (ret) {
+ fprintf(stderr, "failed to set mode\n");
+ goto err;
+ }
+
+ /* reset rendering stuff. */
+ if (output->current_fb_id)
+ drmModeRmFB(ec->drm.fd, output->current_fb_id);
+ output->current_fb_id = 0;
+
+ if (output->next_fb_id)
+ drmModeRmFB(ec->drm.fd, output->next_fb_id);
+ output->next_fb_id = 0;
+
+ if (output->current_bo)
+ gbm_surface_release_buffer(output->surface,
+ output->current_bo);
+ output->current_bo = NULL;
+
+ if (output->next_bo)
+ gbm_surface_release_buffer(output->surface,
+ output->next_bo);
+ output->next_bo = NULL;
+
+ eglDestroySurface(ec->base.display, output->egl_surface);
+ gbm_surface_destroy(output->surface);
+ output->egl_surface = egl_surface;
+ output->surface = surface;
+
+ /*update output*/
+ output->base.current = &drm_mode->base;
+ output->base.dirty = 1;
+ weston_output_move(&output->base, output->base.x, output->base.y);
+ return 0;
+
+err:
+ eglDestroySurface(ec->base.display, egl_surface);
+ gbm_surface_destroy(surface);
+ return -1;
+}
+
static int
on_drm_input(int fd, uint32_t mask, void *data)
{
@@ -1165,7 +1313,7 @@ create_output_for_connector(struct drm_compositor *ec,
output->base.assign_planes = drm_assign_planes;
output->base.read_pixels = drm_output_read_pixels;
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