On Mon, Mar 21, 2016 at 05:41:32PM +0100, Miguel A. Vico wrote:
> As previously stated, EGLDevice and EGLOutput will provide means
> to access native device objects and different portions of display
> control hardware respectively.
> 
> Whenever EGL_EXT_device_drm extension is present, EGLDevice can
> be used to enumerate and access DRM KMS devices, and EGLOutputLayer
> to enumerate and access DRM KMS crtcs and planes.
> 
> By using EGLStreams and attaching an EGLOutputLayer consumer
> (representing a DRM KMS crtc or plane) to it, compositor-drm can
> produce final composition frames and present them on a DRM device.
> 
> This change adds required logic to support presentation through
> EGLDevice+EGLOutput+EGLStream. Whether GBM or EGLDevice should be
> used can be controlled by --use-egldevice backend argument.
> 
> Signed-off-by: Miguel A Vico Moya <mvicom...@nvidia.com>
> Reviewed-by: Andy Ritger <arit...@nvidia.com>
> Reviewed-by: Adam Cheney <ache...@nvidia.com>

Andy did a presentation about these extensions at xdc 2014, and consensus
reply from folks (not just me) was "no way". I've seen a few other
discussions fly by meanwhile, with exactly the same opinions.

If you really can't have a display driver in the kernel, why not fake
proper drm with something like CUSE (or well similar, probably need to
interface with at least dma-bufs from the kernel blob somwehere)? Or just
like use the existing kernel driver and improve that to suit your needs,
like everyone else at least plans to.

I don't expect you'll ever be able to sell this to the community and get
it merged.
-Daniel

> ---
>  src/compositor-drm.c | 319 
> +++++++++++++++++++++++++++++++++++----------------
>  src/main.c           |   1 +
>  2 files changed, 224 insertions(+), 96 deletions(-)
> 
> diff --git a/src/compositor-drm.c b/src/compositor-drm.c
> index ecb340d..82097ff 100644
> --- a/src/compositor-drm.c
> +++ b/src/compositor-drm.c
> @@ -75,6 +75,10 @@
>  #define GBM_BO_USE_CURSOR GBM_BO_USE_CURSOR_64X64
>  #endif
>  
> +#ifndef EGL_DRM_MASTER_FD_EXT
> +#define EGL_DRM_MASTER_FD_EXT 0x333C
> +#endif
> +
>  static int option_current_mode = 0;
>  
>  enum output_config {
> @@ -101,7 +105,10 @@ struct drm_backend {
>               int fd;
>               char *filename;
>       } drm;
> +
> +     EGLDeviceEXT egldevice;
>       struct gbm_device *gbm;
> +
>       uint32_t *crtcs;
>       int num_crtcs;
>       uint32_t crtc_allocator;
> @@ -124,6 +131,7 @@ struct drm_backend {
>       int cursors_are_broken;
>  
>       int use_pixman;
> +     int use_egldevice;
>  
>       uint32_t prev_state;
>  
> @@ -225,6 +233,7 @@ struct drm_parameters {
>       int connector;
>       int tty;
>       int use_pixman;
> +     int use_egldevice;
>       const char *seat_id;
>  };
>  
> @@ -531,17 +540,21 @@ drm_output_render_gl(struct drm_output *output, 
> pixman_region32_t *damage)
>       output->base.compositor->renderer->repaint_output(&output->base,
>                                                         damage);
>  
> -     bo = gbm_surface_lock_front_buffer(output->gbm_surface);
> -     if (!bo) {
> -             weston_log("failed to lock front buffer: %m\n");
> -             return;
> -     }
> +     if (b->use_egldevice)
> +             output->next = output->dumb[0];
> +     else {
> +             bo = gbm_surface_lock_front_buffer(output->gbm_surface);
> +             if (!bo) {
> +                     weston_log("failed to lock front buffer: %m\n");
> +                     return;
> +             }
>  
> -     output->next = drm_fb_get_from_bo(bo, b, output->gbm_format);
> -     if (!output->next) {
> -             weston_log("failed to get drm_fb for bo\n");
> -             gbm_surface_release_buffer(output->gbm_surface, bo);
> -             return;
> +             output->next = drm_fb_get_from_bo(bo, b, output->gbm_format);
> +             if (!output->next) {
> +                     weston_log("failed to get drm_fb for bo\n");
> +                     gbm_surface_release_buffer(output->gbm_surface, bo);
> +                     return;
> +             }
>       }
>  }
>  
> @@ -666,9 +679,14 @@ drm_output_repaint(struct weston_output *output_base,
>               output_base->set_dpms(output_base, WESTON_DPMS_ON);
>       }
>  
> -     if (drmModePageFlip(backend->drm.fd, output->crtc_id,
> -                         output->next->fb_id,
> -                         DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
> +     if (backend->use_egldevice)
> +             ret = gl_renderer->output_stream_flip(&output->base, output);
> +     else
> +             ret = drmModePageFlip(backend->drm.fd, output->crtc_id,
> +                                   output->next->fb_id,
> +                                   DRM_MODE_PAGE_FLIP_EVENT, output);
> +
> +     if (ret < 0) {
>               weston_log("queueing pageflip failed: %m\n");
>               goto err_pageflip;
>       }
> @@ -739,7 +757,6 @@ drm_output_start_repaint_loop(struct weston_output 
> *output_base)
>       struct drm_output *output = (struct drm_output *) output_base;
>       struct drm_backend *backend = (struct drm_backend *)
>               output_base->compositor->backend;
> -     uint32_t fb_id;
>       struct timespec ts, tnow;
>       struct timespec vbl2now;
>       int64_t refresh_nsec;
> @@ -795,10 +812,14 @@ drm_output_start_repaint_loop(struct weston_output 
> *output_base)
>       /* Immediate query succeeded, but didn't provide valid timestamp.
>        * Use pageflip fallback.
>        */
> -     fb_id = output->current->fb_id;
> +     if (backend->use_egldevice)
> +             ret = gl_renderer->output_stream_flip(&output->base, output);
> +     else
> +             ret = drmModePageFlip(backend->drm.fd, output->crtc_id,
> +                                   output->current->fb_id,
> +                                   DRM_MODE_PAGE_FLIP_EVENT, output);
>  
> -     if (drmModePageFlip(backend->drm.fd, output->crtc_id, fb_id,
> -                         DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
> +     if (ret < 0) {
>               weston_log("queueing pageflip failed: %m\n");
>               goto finish_frame;
>       }
> @@ -1328,6 +1349,9 @@ static void
>  drm_output_fini_pixman(struct drm_output *output);
>  
>  static void
> +drm_output_fini_egl(struct drm_output *output);
> +
> +static void
>  drm_output_destroy(struct weston_output *output_base)
>  {
>       struct drm_output *output = (struct drm_output *) output_base;
> @@ -1358,12 +1382,10 @@ drm_output_destroy(struct weston_output *output_base)
>       b->crtc_allocator &= ~(1 << output->crtc_id);
>       b->connector_allocator &= ~(1 << output->connector_id);
>  
> -     if (b->use_pixman) {
> +     if (b->use_pixman)
>               drm_output_fini_pixman(output);
> -     } else {
> -             gl_renderer->output_destroy(output_base);
> -             gbm_surface_destroy(output->gbm_surface);
> -     }
> +     else
> +             drm_output_fini_egl(output);
>  
>       weston_plane_release(&output->fb_plane);
>       weston_plane_release(&output->cursor_plane);
> @@ -1462,9 +1484,7 @@ drm_output_switch_mode(struct weston_output 
> *output_base, struct weston_mode *mo
>                       return -1;
>               }
>       } else {
> -             gl_renderer->output_destroy(&output->base);
> -             gbm_surface_destroy(output->gbm_surface);
> -
> +             drm_output_fini_egl(output);
>               if (drm_output_init_egl(output, b) < 0) {
>                       weston_log("failed to init output egl state with "
>                                  "new mode");
> @@ -1551,11 +1571,6 @@ create_gbm_device(int fd)
>  {
>       struct gbm_device *gbm;
>  
> -     gl_renderer = weston_load_module("gl-renderer.so",
> -                                      "gl_renderer_interface");
> -     if (!gl_renderer)
> -             return NULL;
> -
>       /* GBM will load a dri driver, but even though they need symbols from
>        * libglapi, in some version of Mesa they are not linked to it. Since
>        * only the gl-renderer module links to it, the call above won't make
> @@ -1568,6 +1583,39 @@ create_gbm_device(int fd)
>       return gbm;
>  }
>  
> +static EGLDeviceEXT
> +create_egldevice(const char *filename)
> +{
> +     EGLDeviceEXT egldevice = EGL_NO_DEVICE_EXT;
> +     EGLDeviceEXT *devices;
> +     EGLint num_devices;
> +     const char *drm_path;
> +     int i;
> +
> +     if (gl_renderer->get_devices(0, NULL, &num_devices) < 0 ||
> +         num_devices < 1)
> +             return EGL_NO_DEVICE_EXT;
> +
> +     devices = zalloc(num_devices * sizeof *devices);
> +     if (!devices)
> +             return EGL_NO_DEVICE_EXT;
> +
> +     if (gl_renderer->get_devices(num_devices, devices, &num_devices) < 0) {
> +             free(devices);
> +             return EGL_NO_DEVICE_EXT;
> +     }
> +
> +     for (i = 0; i < num_devices; i++)
> +             if (gl_renderer->get_drm_device_file(devices[i], &drm_path) == 
> 0 &&
> +                 strcmp(filename, drm_path) == 0) {
> +                     egldevice = devices[i];
> +                     break;
> +             }
> +
> +     free(devices);
> +     return egldevice;
> +}
> +
>  /* When initializing EGL, if the preferred buffer format isn't available
>   * we may be able to susbstitute an ARGB format for an XRGB one.
>   *
> @@ -1594,38 +1642,59 @@ fallback_format_for(uint32_t format)
>  static int
>  drm_backend_create_gl_renderer(struct drm_backend *b)
>  {
> -     EGLint format[3] = {
> +     EGLint platform_attribs[] = {
> +             EGL_DRM_MASTER_FD_EXT, b->drm.fd,
> +             EGL_NONE
> +     };
> +     EGLint format[] = {
>               b->gbm_format,
>               fallback_format_for(b->gbm_format),
> -             0,
> +             0
>       };
>       int n_formats = 2;
>  
>       if (format[1])
>               n_formats = 3;
> -     if (gl_renderer->create(b->compositor,
> -                             EGL_PLATFORM_GBM_KHR,
> -                             (void *)b->gbm,
> -                             NULL,
> -                             gl_renderer->opaque_attribs,
> -                             format,
> -                             n_formats) < 0) {
> -             return -1;
> -     }
>  
> -     return 0;
> +     if (b->use_egldevice)
> +             return gl_renderer->create(b->compositor,
> +                                        EGL_PLATFORM_DEVICE_EXT,
> +                                        (void *)b->egldevice,
> +                                        platform_attribs,
> +                                        gl_renderer->opaque_stream_attribs,
> +                                        NULL,
> +                                        0);
> +     else
> +             return gl_renderer->create(b->compositor,
> +                                        EGL_PLATFORM_GBM_KHR,
> +                                        b->gbm,
> +                                        NULL,
> +                                        gl_renderer->opaque_attribs,
> +                                        format,
> +                                        n_formats);
>  }
>  
>  static int
>  init_egl(struct drm_backend *b)
>  {
> -     b->gbm = create_gbm_device(b->drm.fd);
> -
> -     if (!b->gbm)
> +     gl_renderer = weston_load_module("gl-renderer.so",
> +                                      "gl_renderer_interface");
> +     if (!gl_renderer)
>               return -1;
>  
> +     if (b->use_egldevice) {
> +             b->egldevice = create_egldevice(b->drm.filename);
> +             if (b->egldevice == EGL_NO_DEVICE_EXT)
> +                     return -1;
> +     } else {
> +             b->gbm = create_gbm_device(b->drm.fd);
> +             if (!b->gbm)
> +                     return -1;
> +     }
> +
>       if (drm_backend_create_gl_renderer(b) < 0) {
> -             gbm_device_destroy(b->gbm);
> +             if (b->gbm)
> +                     gbm_device_destroy(b->gbm);
>               return -1;
>       }
>  
> @@ -1852,55 +1921,94 @@ find_crtc_for_connector(struct drm_backend *b,
>  static int
>  drm_output_init_egl(struct drm_output *output, struct drm_backend *b)
>  {
> -     EGLint format[2] = {
> -             output->gbm_format,
> -             fallback_format_for(output->gbm_format),
> -     };
> -     int i, flags, n_formats = 1;
> -
> -     output->gbm_surface = gbm_surface_create(b->gbm,
> -                                          output->base.current_mode->width,
> -                                          output->base.current_mode->height,
> -                                          format[0],
> -                                          GBM_BO_USE_SCANOUT |
> -                                          GBM_BO_USE_RENDERING);
> -     if (!output->gbm_surface) {
> -             weston_log("failed to create gbm surface\n");
> -             return -1;
> -     }
> +     if (b->use_egldevice) {
> +             int w = output->base.current_mode->width;
> +             int h = output->base.current_mode->height;
>  
> -     if (format[1])
> -             n_formats = 2;
> -     if (gl_renderer->output_window_create(&output->base,
> -                                    (EGLNativeWindowType)output->gbm_surface,
> -                                    output->gbm_surface,
> -                                    gl_renderer->opaque_attribs,
> -                                    format,
> -                                    n_formats) < 0) {
> -             weston_log("failed to create gl renderer output state\n");
> -             gbm_surface_destroy(output->gbm_surface);
> -             return -1;
> -     }
> +             /* Create a dumb fb for modesetting */
> +             output->dumb[0] = drm_fb_create_dumb(b, w, h);
> +             if (!output->dumb[0]) {
> +                     weston_log("failed to create dumb framebuffer\n");
> +                     return -1;
> +             }
>  
> -     flags = GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE;
> +             if (gl_renderer->output_stream_create(&output->base, ~0u,
> +                                                   output->crtc_id) < 0) {
> +                     weston_log("failed to create gl renderer output stream 
> state\n");
> +                     drm_fb_destroy_dumb(output->dumb[0]);
> +                     output->dumb[0] = NULL;
> +                     return -1;
> +             }
>  
> -     for (i = 0; i < 2; i++) {
> -             if (output->gbm_cursor_bo[i])
> -                     continue;
> +             /* FIXME: Add hw planes and cursors for EGL device when 
> supported */
> +             b->sprites_are_broken = 1;
> +             b->cursors_are_broken = 1;
> +     } else {
> +             EGLint format[2] = {
> +                     output->gbm_format,
> +                     fallback_format_for(output->gbm_format),
> +             };
> +             int i, flags, n_formats = 1;
> +
> +             output->gbm_surface = gbm_surface_create(b->gbm,
> +                                       output->base.current_mode->width,
> +                                       output->base.current_mode->height,
> +                                       format[0],
> +                                       GBM_BO_USE_SCANOUT |
> +                                       GBM_BO_USE_RENDERING);
> +             if (!output->gbm_surface) {
> +                     weston_log("failed to create gbm surface\n");
> +                     return -1;
> +             }
>  
> -             output->gbm_cursor_bo[i] =
> -                     gbm_bo_create(b->gbm, b->cursor_width, b->cursor_height,
> -                             GBM_FORMAT_ARGB8888, flags);
> -     }
> +             if (format[1])
> +                     n_formats = 2;
> +             if (gl_renderer->output_window_create(
> +                                     &output->base,
> +                                     
> (EGLNativeWindowType)output->gbm_surface,
> +                                     output->gbm_surface,
> +                                     gl_renderer->opaque_attribs,
> +                                     format,
> +                                     n_formats) < 0) {
> +                     weston_log("failed to create gl renderer output 
> state\n");
> +                     gbm_surface_destroy(output->gbm_surface);
> +                     return -1;
> +             }
>  
> -     if (output->gbm_cursor_bo[0] == NULL || output->gbm_cursor_bo[1] == 
> NULL) {
> -             weston_log("cursor buffers unavailable, using gl cursors\n");
> -             b->cursors_are_broken = 1;
> +             flags = GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE;
> +
> +             for (i = 0; i < 2; i++) {
> +                     if (output->gbm_cursor_bo[i])
> +                             continue;
> +
> +                     output->gbm_cursor_bo[i] =
> +                             gbm_bo_create(b->gbm, b->cursor_width, 
> b->cursor_height,
> +                                           GBM_FORMAT_ARGB8888, flags);
> +             }
> +
> +             if (output->gbm_cursor_bo[0] == NULL || 
> output->gbm_cursor_bo[1] == NULL) {
> +                     weston_log("cursor buffers unavailable, using gl 
> cursors\n");
> +                     b->cursors_are_broken = 1;
> +             }
>       }
>  
>       return 0;
>  }
>  
> +static void
> +drm_output_fini_egl(struct drm_output *output)
> +{
> +     gl_renderer->output_destroy(&output->base);
> +
> +     if (output->dumb[0]) {
> +             drm_fb_destroy_dumb(output->dumb[0]);
> +             output->dumb[0] = NULL;
> +     }
> +
> +     if (output->gbm_surface)
> +             gbm_surface_destroy(output->gbm_surface);
> +}
> +
>  static int
>  drm_output_init_pixman(struct drm_output *output, struct drm_backend *b)
>  {
> @@ -2374,10 +2482,11 @@ create_output_for_connector(struct drm_backend *b,
>  
>       free(s);
>  
> -     if (get_gbm_format_from_section(section,
> -                                     b->gbm_format,
> -                                     &output->gbm_format) == -1)
> -             output->gbm_format = b->gbm_format;
> +     if (!b->use_egldevice)
> +             if (get_gbm_format_from_section(section,
> +                                             b->gbm_format,
> +                                             &output->gbm_format) == -1)
> +                     output->gbm_format = b->gbm_format;
>  
>       weston_config_section_get_string(section, "seat", &s, "");
>       setup_output_seat_constraint(b, &output->base, s);
> @@ -2988,6 +3097,11 @@ recorder_binding(struct weston_keyboard *keyboard, 
> uint32_t time, uint32_t key,
>       struct drm_output *output;
>       int width, height;
>  
> +     if (b->use_egldevice) {
> +             weston_log("recorder not supported with EGL device\n");
> +             return;
> +     }
> +
>       output = container_of(b->compositor->output_list.next,
>                             struct drm_output, base.link);
>  
> @@ -3043,11 +3157,20 @@ switch_to_gl_renderer(struct drm_backend *b)
>  
>       weston_log("Switching to GL renderer\n");
>  
> -     b->gbm = create_gbm_device(b->drm.fd);
> -     if (!b->gbm) {
> -             weston_log("Failed to create gbm device. "
> -                        "Aborting renderer switch\n");
> -             return;
> +     if (b->use_egldevice) {
> +             b->egldevice = create_egldevice(b->drm.filename);
> +             if (b->egldevice == EGL_NO_DEVICE_EXT) {
> +                     weston_log("Failed to create EGL device. "
> +                                "Aborting renderer switch\n");
> +                     return;
> +             }
> +     } else {
> +             b->gbm = create_gbm_device(b->drm.fd);
> +             if (!b->gbm) {
> +                     weston_log("Failed to create gbm device. "
> +                                "Aborting renderer switch\n");
> +                     return;
> +             }
>       }
>  
>       wl_list_for_each(output, &b->compositor->output_list, base.link)
> @@ -3056,7 +3179,8 @@ switch_to_gl_renderer(struct drm_backend *b)
>       b->compositor->renderer->destroy(b->compositor);
>  
>       if (drm_backend_create_gl_renderer(b) < 0) {
> -             gbm_device_destroy(b->gbm);
> +             if (b->gbm)
> +                     gbm_device_destroy(b->gbm);
>               weston_log("Failed to create GL renderer. Quitting.\n");
>               /* FIXME: we need a function to shutdown cleanly */
>               assert(0);
> @@ -3122,6 +3246,7 @@ drm_backend_create(struct weston_compositor *compositor,
>               goto err_base;
>  
>       b->use_pixman = param->use_pixman;
> +     b->use_egldevice = param->use_egldevice;
>  
>       /* Check if we run drm-backend using weston-launch */
>       compositor->launcher = weston_launcher_connect(compositor, param->tty,
> @@ -3246,7 +3371,8 @@ err_drm_source:
>  err_udev_input:
>       udev_input_destroy(&b->input);
>  err_sprite:
> -     gbm_device_destroy(b->gbm);
> +     if (b->gbm)
> +             gbm_device_destroy(b->gbm);
>       destroy_sprites(b);
>  err_udev_dev:
>       udev_device_unref(drm_device);
> @@ -3275,6 +3401,7 @@ backend_init(struct weston_compositor *compositor, int 
> *argc, char *argv[],
>               { WESTON_OPTION_INTEGER, "tty", 0, &param.tty },
>               { WESTON_OPTION_BOOLEAN, "current-mode", 0, 
> &option_current_mode },
>               { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &param.use_pixman },
> +             { WESTON_OPTION_BOOLEAN, "use-egldevice", 0, 
> &param.use_egldevice },
>       };
>  
>       param.seat_id = default_seat;
> diff --git a/src/main.c b/src/main.c
> index 1850fa6..2494414 100644
> --- a/src/main.c
> +++ b/src/main.c
> @@ -266,6 +266,7 @@ usage(int error_code)
>               "  --seat=SEAT\t\tThe seat that weston should run on\n"
>               "  --tty=TTY\t\tThe tty to use\n"
>               "  --use-pixman\t\tUse the pixman (CPU) renderer\n"
> +             "  --use-egldevice\tUse EGLDevice and EGLOutput with the GL 
> renderer\n"
>               "  --current-mode\tPrefer current KMS mode over EDID preferred 
> mode\n\n");
>  #endif
>  
> -- 
> 2.7.1
> 
> _______________________________________________
> wayland-devel mailing list
> wayland-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/wayland-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
wayland-devel mailing list
wayland-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to