compositor-drm: Add switch_mode support.

Implement switch_mode hook for drm backend.
Alex Wu 13 years ago committed by Kristian Høgsberg
parent 2dda604093
commit b7b8bda600
  1. 150
      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)
{
@ -1166,7 +1314,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;

Loading…
Cancel
Save