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

David Herrmann dh.herrmann at googlemail.com
Wed Mar 7 02:22:46 PST 2012


Hi

On Wed, Mar 7, 2012 at 10:01 AM,  <zhiwen.wu at linux.intel.com> wrote:
> From: Alex Wu <zhiwen.wu at linux.intel.com>
>
> Implement switch_mode hook for drm back end.
> ---
>  src/compositor-drm.c |  143 +++++++++++++++++++++++++++++++++++++++++++++++++-
>  1 files changed, 142 insertions(+), 1 deletions(-)
>
> diff --git a/src/compositor-drm.c b/src/compositor-drm.c
> index 1b0a9b9..e9583fe 100644
> --- a/src/compositor-drm.c
> +++ b/src/compositor-drm.c
> @@ -120,6 +120,23 @@ 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, *next;
> +
> +       wl_list_for_each_safe(mode, next, &output->base.mode_list,base.link) {
> +               if (mode->mode_info.hdisplay == width && mode->mode_info.vdisplay == height) {
> +                       if (mode->mode_info.vrefresh == refresh)
> +                               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)
>  {
> @@ -742,6 +759,130 @@ 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;
> +       struct weston_mode *old_mode;
> +       int i, ret;
> +       unsigned handle, stride;
> +       struct drm_compositor *ec;
> +
> +       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;
> +       old_mode  = output->base.current;
> +       drm_mode  = choose_mode (output, width, height, refresh);
> +
> +       if (!drm_mode) {
> +               printf("%s, invalid resolution:%dx%d\n", __func__, width, height);
> +               return -1;
> +       }
> +
> +       glFramebufferRenderbuffer(GL_FRAMEBUFFER,
> +                                 GL_COLOR_ATTACHMENT0,
> +                                 GL_RENDERBUFFER, 0);
> +
> +       /* Destroy output buffers */
> +       for (i = 0; i < 2; i++) {
> +               drmModeRmFB(ec->drm.fd, output->fb_id[i]);
> +               ec->base.destroy_image(ec->base.display, output->image[i]);
> +               gbm_bo_destroy(output->bo[i]);
> +       }

output->fb_id[0] = -1;
output->fb_id[1] = -1;
output->image[0] = NULL;
... see below ...

> +
> +       glBindRenderbuffer(GL_RENDERBUFFER, 0);
> +       glDeleteRenderbuffers(2, output->rbo);
> +       weston_output_destroy(&output->base);
> +
> +       output->base.current = &drm_mode->base;
> +       drm_mode->base.flags =
> +               WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
> +
> +       /* create new output buffers */
> +       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;
> +       }
> +
> +       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]);

This doesn't make sense if you do not reset them to -1 before:
See "create_output_for_connector".

> +               if (output->image[i])
> +                       ec->base.destroy_image(ec->base.display,
> +                                              output->image[i]);

Same here.

> +               if (output->bo[i])
> +                       gbm_bo_destroy(output->bo[i]);

And here.
Even if setting this failed and output->bo[0] is NULL, this doesn't
mean that output->bo[1] is NULL, too so reset them properly first.

> +       }
> +       glBindRenderbuffer(GL_RENDERBUFFER, 0);
> +       glDeleteRenderbuffers(2, output->rbo);
> +
> +       output->base.current = old_mode;
> +       return -1;

What happens to this output if this function fails? As I see it it
keeps it in the list but should rather remove it entirely from the
output-list so the next update_outputs() call will reenable this one
and not leave it disabled.

> +}
> +
> +static int
>  on_drm_input(int fd, uint32_t mask, void *data)
>  {
>        drmEventContext evctx;
> @@ -1140,7 +1281,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;
>
> --

Regards
David


More information about the wayland-devel mailing list