diff options
Diffstat (limited to 'src/compositor-drm.c')
-rw-r--r-- | src/compositor-drm.c | 336 |
1 files changed, 233 insertions, 103 deletions
diff --git a/src/compositor-drm.c b/src/compositor-drm.c index eb1a2dfd..befe34cb 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; } @@ -1330,6 +1351,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; @@ -1360,12 +1384,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); @@ -1464,9 +1486,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"); @@ -1553,11 +1573,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 @@ -1570,6 +1585,39 @@ create_gbm_device(int fd) return gbm; } +static EGLDeviceEXT +find_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 substitute an ARGB format for an XRGB one. * @@ -1596,38 +1644,61 @@ fallback_format_for(uint32_t format) static int drm_backend_create_gl_renderer(struct drm_backend *b) { - EGLint format[3] = { - b->gbm_format, - fallback_format_for(b->gbm_format), - 0, - }; - int n_formats = 2; - - if (format[1]) - n_formats = 3; - if (gl_renderer->display_create(b->compositor, - EGL_PLATFORM_GBM_KHR, - (void *)b->gbm, - NULL, - gl_renderer->opaque_attribs, - format, - n_formats) < 0) { - return -1; - } + if (b->use_egldevice) { + EGLint device_platform_attribs[] = { + EGL_DRM_MASTER_FD_EXT, b->drm.fd, + EGL_NONE + }; - return 0; + return gl_renderer->display_create(b->compositor, + EGL_PLATFORM_DEVICE_EXT, + (void *)b->egldevice, + device_platform_attribs, + gl_renderer->opaque_stream_attribs, + NULL, + 0); + } else { + EGLint format[] = { + b->gbm_format, + fallback_format_for(b->gbm_format), + 0 + }; + int n_formats = 2; + + if (format[1]) + n_formats = 3; + + return gl_renderer->display_create(b->compositor, + EGL_PLATFORM_GBM_KHR, + (void *)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 = find_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; } @@ -1854,55 +1925,95 @@ 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 black 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; + } + memset(output->dumb[0]->map, 0, output->dumb[0]->size); - 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) { @@ -2376,10 +2487,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); @@ -2990,6 +3102,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); @@ -3045,11 +3162,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 = find_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) @@ -3058,7 +3184,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); @@ -3124,6 +3251,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, @@ -3248,7 +3376,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); @@ -3277,6 +3406,7 @@ backend_init(struct weston_compositor *compositor, int *argc, char *argv[], { WESTON_OPTION_INTEGER, "tty", 0, ¶m.tty }, { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode }, { WESTON_OPTION_BOOLEAN, "use-pixman", 0, ¶m.use_pixman }, + { WESTON_OPTION_BOOLEAN, "use-egldevice", 0, ¶m.use_egldevice }, }; param.seat_id = default_seat; |