return 0;
}
-static enum weston_drm_backend_output_mode
-drm_configure_output(struct weston_compositor *c,
- bool use_current_mode,
- const char *name,
- struct weston_drm_backend_output_config *config)
-{
- struct weston_config *wc = wet_get_config(c);
- struct weston_config_section *section;
- char *s;
- int scale;
- enum weston_drm_backend_output_mode mode =
- WESTON_DRM_BACKEND_OUTPUT_PREFERRED;
-
- section = weston_config_get_section(wc, "output", "name", name);
- weston_config_section_get_string(section, "mode", &s, "preferred");
- if (strcmp(s, "off") == 0) {
- free(s);
- return WESTON_DRM_BACKEND_OUTPUT_OFF;
- }
-
- if (use_current_mode || strcmp(s, "current") == 0) {
- mode = WESTON_DRM_BACKEND_OUTPUT_CURRENT;
- } else if (strcmp(s, "preferred") != 0) {
- config->modeline = s;
- s = NULL;
- }
- free(s);
-
- weston_config_section_get_int(section, "scale", &scale, 1);
- config->base.scale = scale >= 1 ? scale : 1;
- weston_config_section_get_string(section, "transform", &s, "normal");
- if (weston_parse_transform(s, &config->base.transform) < 0)
- weston_log("Invalid transform \"%s\" for output %s\n",
- s, name);
- free(s);
-
- weston_config_section_get_string(section,
- "gbm-format", &config->gbm_format, NULL);
- weston_config_section_get_string(section, "seat", &config->seat, "");
- return mode;
-}
-
static void
configure_input_device(struct weston_compositor *compositor,
struct libinput_device *device)
}
}
+static void
+drm_backend_output_configure(struct wl_listener *listener, void *data)
+{
+ struct weston_output *output = data;
+ struct weston_config *wc = wet_get_config(output->compositor);
+ struct weston_config_section *section;
+ const struct weston_drm_output_api *api = weston_drm_output_get_api(output->compositor);
+ enum weston_drm_backend_output_mode mode =
+ WESTON_DRM_BACKEND_OUTPUT_PREFERRED;
+
+ char *s;
+ char *modeline = NULL;
+ char *gbm_format = NULL;
+ char *seat = NULL;
+
+ if (!api) {
+ weston_log("Cannot use weston_drm_output_api.\n");
+ return;
+ }
+
+ section = weston_config_get_section(wc, "output", "name", output->name);
+ weston_config_section_get_string(section, "mode", &s, "preferred");
+
+ if (strcmp(s, "off") == 0) {
+ weston_output_disable(output);
+ free(s);
+ return;
+ } else if (strcmp(s, "current") == 0) {
+ mode = WESTON_DRM_BACKEND_OUTPUT_CURRENT;
+ } else if (strcmp(s, "preferred") != 0) {
+ modeline = s;
+ s = NULL;
+ }
+ free(s);
+
+ if (api->set_mode(output, mode, modeline) < 0) {
+ weston_log("Cannot configure an output using weston_drm_output_api.\n");
+ free(modeline);
+ return;
+ }
+ free(modeline);
+
+ wet_output_set_scale(output, section, 1, 0);
+ wet_output_set_transform(output, section, WL_OUTPUT_TRANSFORM_NORMAL, UINT32_MAX);
+
+ weston_config_section_get_string(section,
+ "gbm-format", &gbm_format, NULL);
+
+ api->set_gbm_format(output, gbm_format);
+ free(gbm_format);
+
+ weston_config_section_get_string(section, "seat", &seat, "");
+
+ api->set_seat(output, seat);
+ free(seat);
+
+ weston_output_enable(output);
+}
+
static int
load_drm_backend(struct weston_compositor *c,
int *argc, char **argv, struct weston_config *wc)
config.base.struct_version = WESTON_DRM_BACKEND_CONFIG_VERSION;
config.base.struct_size = sizeof(struct weston_drm_backend_config);
- config.configure_output = drm_configure_output;
config.configure_device = configure_input_device;
ret = weston_compositor_load_backend(c, WESTON_BACKEND_DRM,
&config.base);
+ wet_set_pending_output_handler(c, drm_backend_output_configure);
+
free(config.gbm_format);
free(config.seat_id);
int32_t cursor_width;
int32_t cursor_height;
- /** Callback used to configure the outputs.
- *
- * This function will be called by the backend when a new DRM
- * output needs to be configured.
- */
- enum weston_drm_backend_output_mode
- (*configure_output)(struct weston_compositor *compositor,
- bool use_current_mode,
- const char *name,
- struct weston_drm_backend_output_config *output_config);
bool use_current_mode;
};
};
struct drm_output {
- struct weston_output base;
+ struct weston_output base;
+ drmModeConnector *connector;
uint32_t crtc_id;
int pipe;
int vblank_pending;
int page_flip_pending;
int destroy_pending;
+ int disable_pending;
struct gbm_surface *gbm_surface;
struct gbm_bo *gbm_cursor_bo[2];
struct drm_mode *mode;
int ret = 0;
- if (output->destroy_pending)
+ if (output->disable_pending || output->destroy_pending)
return -1;
if (!output->next)
.request.signal = 0,
};
- if (output->destroy_pending)
+ if (output->disable_pending || output->destroy_pending)
return;
if (!output->current) {
}
static void
-drm_output_destroy(struct weston_output *output_base);
+drm_output_destroy(struct weston_output *base);
static void
page_flip_handler(int fd, unsigned int frame,
if (output->destroy_pending)
drm_output_destroy(&output->base);
+ else if (output->disable_pending)
+ weston_output_disable(&output->base);
else if (!output->vblank_pending) {
ts.tv_sec = sec;
ts.tv_nsec = usec * 1000;
static void
drm_output_fini_pixman(struct drm_output *output);
-static void
-drm_output_destroy(struct weston_output *output_base)
-{
- struct drm_output *output = to_drm_output(output_base);
- struct drm_backend *b = to_drm_backend(output->base.compositor);
- drmModeCrtcPtr origcrtc = output->original_crtc;
-
- if (output->page_flip_pending) {
- output->destroy_pending = 1;
- weston_log("destroy output while page flip pending\n");
- return;
- }
-
- if (output->backlight)
- backlight_destroy(output->backlight);
-
- drmModeFreeProperty(output->dpms_prop);
-
- /* Turn off hardware cursor */
- drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
-
- /* Restore original CRTC state */
- drmModeSetCrtc(b->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
- origcrtc->x, origcrtc->y,
- &output->connector_id, 1, &origcrtc->mode);
- drmModeFreeCrtc(origcrtc);
-
- b->crtc_allocator &= ~(1 << output->crtc_id);
- b->connector_allocator &= ~(1 << output->connector_id);
-
- if (b->use_pixman) {
- drm_output_fini_pixman(output);
- } else {
- gl_renderer->output_destroy(output_base);
- gbm_surface_destroy(output->gbm_surface);
- }
-
- weston_plane_release(&output->fb_plane);
- weston_plane_release(&output->cursor_plane);
-
- weston_output_destroy(&output->base);
-
- free(output);
-}
-
/**
* Find the closest-matching mode for a given target
*
drm_output_choose_initial_mode(struct drm_backend *backend,
struct drm_output *output,
enum weston_drm_backend_output_mode mode,
- struct weston_drm_backend_output_config *config,
+ const char *modeline,
const drmModeModeInfo *current_mode)
{
struct drm_mode *preferred = NULL;
struct drm_mode *configured = NULL;
struct drm_mode *best = NULL;
struct drm_mode *drm_mode;
- drmModeModeInfo modeline;
+ drmModeModeInfo drm_modeline;
int32_t width = 0;
int32_t height = 0;
- if (mode == WESTON_DRM_BACKEND_OUTPUT_PREFERRED && config->modeline) {
- if (sscanf(config->modeline, "%dx%d", &width, &height) != 2) {
+ if (mode == WESTON_DRM_BACKEND_OUTPUT_PREFERRED && modeline) {
+ if (sscanf(modeline, "%dx%d", &width, &height) != 2) {
width = -1;
- if (parse_modeline(config->modeline, &modeline) == 0) {
- configured = drm_output_add_mode(output, &modeline);
+ if (parse_modeline(modeline, &drm_modeline) == 0) {
+ configured = drm_output_add_mode(output, &drm_modeline);
if (!configured)
return NULL;
} else {
weston_log("Invalid modeline \"%s\" for output %s\n",
- config->modeline, output->base.name);
+ modeline, output->base.name);
}
}
}
return 0;
}
-/**
- * Create and configure a Weston output structure
- *
- * Given a DRM connector, create a matching drm_output structure and add it
- * to Weston's output list.
- *
- * @param b Weston backend structure structure
- * @param resources DRM resources for this device
- * @param connector DRM connector to use for this new output
- * @param x Horizontal offset to use into global co-ordinate space
- * @param y Vertical offset to use into global co-ordinate space
- * @param drm_device udev device pointer
- * @returns 0 on success, or -1 on failure
- */
static int
-create_output_for_connector(struct drm_backend *b,
- drmModeRes *resources,
- drmModeConnector *connector,
- int x, int y, struct udev_device *drm_device)
+drm_output_set_mode(struct weston_output *base,
+ enum weston_drm_backend_output_mode mode,
+ const char *modeline)
{
- struct drm_output *output;
- struct drm_mode *drm_mode, *next, *current;
- struct weston_mode *m;
+ struct drm_output *output = to_drm_output(base);
+ struct drm_backend *b = to_drm_backend(base->compositor);
+ struct drm_mode *drm_mode, *next, *current;
drmModeModeInfo crtc_mode;
int i;
- enum weston_drm_backend_output_mode mode;
- struct weston_drm_backend_output_config config = {{ 0 }};
- i = find_crtc_for_connector(b, resources, connector);
- if (i < 0) {
- weston_log("No usable crtc/encoder pair for connector.\n");
- return -1;
- }
-
- output = zalloc(sizeof *output);
- if (output == NULL)
- return -1;
-
- output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
- output->base.name = make_connector_name(connector);
output->base.make = "unknown";
output->base.model = "unknown";
output->base.serial_number = "unknown";
wl_list_init(&output->base.mode_list);
- mode = b->configure_output(b->compositor, b->use_current_mode,
- output->base.name, &config);
- if (parse_gbm_format(config.gbm_format, b->gbm_format, &output->gbm_format) == -1)
- output->gbm_format = b->gbm_format;
-
- setup_output_seat_constraint(b, &output->base,
- config.seat ? config.seat : "");
- free(config.seat);
-
- output->crtc_id = resources->crtcs[i];
- output->pipe = i;
- b->crtc_allocator |= (1 << output->crtc_id);
- output->connector_id = connector->connector_id;
- b->connector_allocator |= (1 << output->connector_id);
-
output->original_crtc = drmModeGetCrtc(b->drm.fd, output->crtc_id);
- output->dpms_prop = drm_get_prop(b->drm.fd, connector, "DPMS");
- if (connector_get_current_mode(connector, b->drm.fd, &crtc_mode) < 0)
+ if (connector_get_current_mode(output->connector, b->drm.fd, &crtc_mode) < 0)
goto err_free;
- for (i = 0; i < connector->count_modes; i++) {
- drm_mode = drm_output_add_mode(output, &connector->modes[i]);
+ for (i = 0; i < output->connector->count_modes; i++) {
+ drm_mode = drm_output_add_mode(output, &output->connector->modes[i]);
if (!drm_mode)
goto err_free;
}
- if (mode == WESTON_DRM_BACKEND_OUTPUT_OFF) {
- weston_log("Disabling output %s\n", output->base.name);
- drmModeSetCrtc(b->drm.fd, output->crtc_id,
- 0, 0, 0, 0, 0, NULL);
- goto err_free;
- }
-
- current = drm_output_choose_initial_mode(b, output, mode, &config,
- &crtc_mode);
+ current = drm_output_choose_initial_mode(b, output, mode, modeline, &crtc_mode);
if (!current)
goto err_free;
+
output->base.current_mode = ¤t->base;
output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
- weston_output_init(&output->base, b->compositor, x, y,
- connector->mmWidth, connector->mmHeight,
- config.base.transform, config.base.scale);
+ /* Set native_ fields, so weston_output_mode_switch_to_native() works */
+ output->base.native_mode = output->base.current_mode;
+ output->base.native_scale = output->base.current_scale;
+
+ output->base.mm_width = output->connector->mmWidth;
+ output->base.mm_height = output->connector->mmHeight;
+
+ return 0;
+
+err_free:
+ drmModeFreeCrtc(output->original_crtc);
+ output->original_crtc = NULL;
+
+ wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
+ base.link) {
+ wl_list_remove(&drm_mode->base.link);
+ free(drm_mode);
+ }
+
+ return -1;
+}
+
+static void
+drm_output_set_gbm_format(struct weston_output *base,
+ const char *gbm_format)
+{
+ struct drm_output *output = to_drm_output(base);
+ struct drm_backend *b = to_drm_backend(base->compositor);
+
+ if (parse_gbm_format(gbm_format, b->gbm_format, &output->gbm_format) == -1)
+ output->gbm_format = b->gbm_format;
+}
+
+static void
+drm_output_set_seat(struct weston_output *base,
+ const char *seat)
+{
+ struct drm_output *output = to_drm_output(base);
+ struct drm_backend *b = to_drm_backend(base->compositor);
+
+ setup_output_seat_constraint(b, &output->base,
+ seat ? seat : "");
+}
+
+static int
+drm_output_enable(struct weston_output *base)
+{
+ struct drm_output *output = to_drm_output(base);
+ struct drm_backend *b = to_drm_backend(base->compositor);
+ struct weston_mode *m;
+
+ output->dpms_prop = drm_get_prop(b->drm.fd, output->connector, "DPMS");
if (b->use_pixman) {
if (drm_output_init_pixman(output, b) < 0) {
weston_log("Failed to init output pixman state\n");
- goto err_output;
+ goto err_free;
}
} else if (drm_output_init_egl(output, b) < 0) {
weston_log("Failed to init output gl state\n");
- goto err_output;
+ goto err_free;
}
- output->backlight = backlight_init(drm_device,
- connector->connector_type);
if (output->backlight) {
weston_log("Initialized backlight, device %s\n",
output->backlight->path);
weston_log("Failed to initialize backlight\n");
}
- weston_compositor_add_output(b->compositor, &output->base);
-
- find_and_parse_output_edid(b, output, connector);
- if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
- output->base.connection_internal = 1;
-
output->base.start_repaint_loop = drm_output_start_repaint_loop;
output->base.repaint = drm_output_repaint;
- output->base.destroy = drm_output_destroy;
output->base.assign_planes = drm_assign_planes;
output->base.set_dpms = drm_set_dpms;
output->base.switch_mode = drm_output_switch_mode;
output->base.gamma_size = output->original_crtc->gamma_size;
output->base.set_gamma = drm_output_set_gamma;
+ output->base.subpixel = drm_subpixel_to_wayland(output->connector->subpixel);
+
+ find_and_parse_output_edid(b, output, output->connector);
+ if (output->connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
+ output->base.connection_internal = 1;
+
weston_plane_init(&output->cursor_plane, b->compositor,
INT32_MIN, INT32_MIN);
weston_plane_init(&output->fb_plane, b->compositor, 0, 0);
", preferred" : "",
m->flags & WL_OUTPUT_MODE_CURRENT ?
", current" : "",
- connector->count_modes == 0 ?
+ output->connector->count_modes == 0 ?
", built-in" : "");
- /* Set native_ fields, so weston_output_mode_switch_to_native() works */
- output->base.native_mode = output->base.current_mode;
- output->base.native_scale = output->base.current_scale;
-
return 0;
-err_output:
- weston_output_destroy(&output->base);
err_free:
- wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
- base.link) {
- wl_list_remove(&drm_mode->base.link);
- free(drm_mode);
+ drmModeFreeProperty(output->dpms_prop);
+
+ return -1;
+}
+
+static void
+drm_output_deinit(struct weston_output *base)
+{
+ struct drm_output *output = to_drm_output(base);
+ struct drm_backend *b = to_drm_backend(base->compositor);
+
+ if (b->use_pixman) {
+ drm_output_fini_pixman(output);
+ } else {
+ gl_renderer->output_destroy(&output->base);
+ gbm_surface_destroy(output->gbm_surface);
}
- drmModeFreeCrtc(output->original_crtc);
+ weston_plane_release(&output->fb_plane);
+ weston_plane_release(&output->cursor_plane);
+
+ drmModeFreeProperty(output->dpms_prop);
+
+ /* Turn off hardware cursor */
+ drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
+}
+
+static void
+drm_output_destroy(struct weston_output *base)
+{
+ struct drm_output *output = to_drm_output(base);
+ struct drm_backend *b = to_drm_backend(base->compositor);
+ drmModeCrtcPtr origcrtc = output->original_crtc;
+
+ if (output->page_flip_pending) {
+ output->destroy_pending = 1;
+ weston_log("destroy output while page flip pending\n");
+ return;
+ }
+
+ if (output->base.enabled)
+ drm_output_deinit(&output->base);
+
+ if (origcrtc) {
+ /* Restore original CRTC state */
+ drmModeSetCrtc(b->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
+ origcrtc->x, origcrtc->y,
+ &output->connector_id, 1, &origcrtc->mode);
+ drmModeFreeCrtc(origcrtc);
+ }
+
+ weston_output_destroy(&output->base);
+
+ drmModeFreeConnector(output->connector);
+
+ if (output->backlight)
+ backlight_destroy(output->backlight);
+
b->crtc_allocator &= ~(1 << output->crtc_id);
b->connector_allocator &= ~(1 << output->connector_id);
+
free(output);
- free(config.modeline);
+}
- return -1;
+static int
+drm_output_disable(struct weston_output *base)
+{
+ struct drm_output *output = to_drm_output(base);
+ struct drm_backend *b = to_drm_backend(base->compositor);
+
+ if (output->page_flip_pending) {
+ output->disable_pending = 1;
+ return -1;
+ }
+
+ if (output->base.enabled)
+ drm_output_deinit(&output->base);
+
+ output->disable_pending = 0;
+
+ weston_log("Disabling output %s\n", output->base.name);
+ drmModeSetCrtc(b->drm.fd, output->crtc_id,
+ 0, 0, 0, 0, 0, NULL);
+
+ return 0;
+}
+
+/**
+ * Create a Weston output structure
+ *
+ * Given a DRM connector, create a matching drm_output structure and add it
+ * to Weston's output list. It also takes ownership of the connector, which
+ * is released when output is destroyed.
+ *
+ * @param b Weston backend structure
+ * @param resources DRM resources for this device
+ * @param connector DRM connector to use for this new output
+ * @param drm_device udev device pointer
+ * @returns 0 on success, or -1 on failure
+ */
+static int
+create_output_for_connector(struct drm_backend *b,
+ drmModeRes *resources,
+ drmModeConnector *connector,
+ struct udev_device *drm_device)
+{
+ struct drm_output *output;
+ int i;
+
+ i = find_crtc_for_connector(b, resources, connector);
+ if (i < 0) {
+ weston_log("No usable crtc/encoder pair for connector.\n");
+ return -1;
+ }
+
+ output = zalloc(sizeof *output);
+ if (output == NULL)
+ return -1;
+
+ output->connector = connector;
+ output->crtc_id = resources->crtcs[i];
+ output->pipe = i;
+ output->connector_id = connector->connector_id;
+
+ output->backlight = backlight_init(drm_device,
+ connector->connector_type);
+
+ output->base.enable = drm_output_enable;
+ output->base.destroy = drm_output_destroy;
+ output->base.disable = drm_output_disable;
+ output->base.name = make_connector_name(connector);
+
+ output->destroy_pending = 0;
+ output->disable_pending = 0;
+ output->original_crtc = NULL;
+
+ b->crtc_allocator |= (1 << output->crtc_id);
+ b->connector_allocator |= (1 << output->connector_id);
+
+ weston_output_init_pending(&output->base, b->compositor);
+ weston_compositor_add_pending_output(&output->base, b->compositor);
+
+ return 0;
}
static void
drmModeConnector *connector;
drmModeRes *resources;
int i;
- int x = 0, y = 0;
resources = drmModeGetResources(b->drm.fd);
if (!resources) {
(option_connector == 0 ||
connector->connector_id == option_connector)) {
if (create_output_for_connector(b, resources,
- connector, x, y,
- drm_device) < 0) {
+ connector, drm_device) < 0) {
drmModeFreeConnector(connector);
continue;
}
-
- x += container_of(b->compositor->output_list.prev,
- struct weston_output,
- link)->width;
+ } else {
+ drmModeFreeConnector(connector);
}
-
- drmModeFreeConnector(connector);
}
- if (wl_list_empty(&b->compositor->output_list))
+ if (wl_list_empty(&b->compositor->output_list) &&
+ wl_list_empty(&b->compositor->pending_output_list))
weston_log("No currently active connector found.\n");
drmModeFreeResources(resources);
drmModeConnector *connector;
drmModeRes *resources;
struct drm_output *output, *next;
- int x = 0, y = 0;
uint32_t connected = 0, disconnects = 0;
int i;
connected |= (1 << connector_id);
if (!(b->connector_allocator & (1 << connector_id))) {
- struct weston_output *last =
- container_of(b->compositor->output_list.prev,
- struct weston_output, link);
-
- /* XXX: not yet needed, we die with 0 outputs */
- if (!wl_list_empty(&b->compositor->output_list))
- x = last->x + last->width;
- else
- x = 0;
- y = 0;
create_output_for_connector(b, resources,
- connector, x, y,
- drm_device);
+ connector, drm_device);
weston_log("connector %d connected\n", connector_id);
+ } else {
+ drmModeFreeConnector(connector);
}
- drmModeFreeConnector(connector);
}
drmModeFreeResources(resources);
drm_output_destroy(&output->base);
}
}
+
+ wl_list_for_each_safe(output, next, &b->compositor->pending_output_list,
+ base.link) {
+ if (disconnects & (1 << output->connector_id)) {
+ disconnects &= ~(1 << output->connector_id);
+ weston_log("connector %d disconnected\n",
+ output->connector_id);
+ drm_output_destroy(&output->base);
+ }
+ }
}
}
switch_to_gl_renderer(b);
}
+static const struct weston_drm_output_api api = {
+ drm_output_set_mode,
+ drm_output_set_gbm_format,
+ drm_output_set_seat,
+};
+
static struct drm_backend *
drm_backend_create(struct weston_compositor *compositor,
struct weston_drm_backend_config *config)
struct wl_event_loop *loop;
const char *path;
const char *seat_id = default_seat;
+ int ret;
weston_log("initializing drm backend\n");
b->sprites_are_broken = 1;
b->compositor = compositor;
b->use_pixman = config->use_pixman;
- b->configure_output = config->configure_output;
b->use_current_mode = config->use_current_mode;
if (parse_gbm_format(config->gbm_format, GBM_FORMAT_XRGB8888, &b->gbm_format) < 0)
compositor->backend = &b->base;
+ ret = weston_plugin_api_register(compositor, WESTON_DRM_OUTPUT_API_NAME,
+ &api, sizeof(api));
+
+ if (ret < 0) {
+ weston_log("Failed to register output API.\n");
+ goto err_udev_monitor;
+ }
+
return b;
err_udev_monitor: