summaryrefslogtreecommitdiff
path: root/src/compositor-drm.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/compositor-drm.c')
-rw-r--r--src/compositor-drm.c336
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, &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;