backend-drm: add additional-devices to support multi GPU
Add the --additional-devices parameter to Weston to add secondary drm devices that will only be used as outputs, but not for rendering. We can only fail the repaint for the entire backend, but not for single devices. Thus, if one of the devices fail, we have to fail the repaint for the entire backend. Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
This commit is contained in:
parent
3f9f4277c3
commit
3c6cfe6bf4
|
@ -2912,6 +2912,7 @@ load_drm_backend(struct weston_compositor *c, int *argc, char **argv,
|
|||
const struct weston_option options[] = {
|
||||
{ WESTON_OPTION_STRING, "seat", 0, &config.seat_id },
|
||||
{ WESTON_OPTION_STRING, "drm-device", 0, &config.specific_device },
|
||||
{ WESTON_OPTION_STRING, "additional-devices", 0, &config.additional_devices},
|
||||
{ WESTON_OPTION_BOOLEAN, "current-mode", 0, &wet->drm_use_current_mode },
|
||||
{ WESTON_OPTION_BOOLEAN, "use-pixman", 0, &force_pixman },
|
||||
{ WESTON_OPTION_BOOLEAN, "continue-without-input", false, &without_input }
|
||||
|
|
|
@ -250,6 +250,14 @@ struct weston_drm_backend_config {
|
|||
|
||||
/** Use shadow buffer if using Pixman-renderer. */
|
||||
bool use_pixman_shadow;
|
||||
|
||||
/** Additional DRM devices to open
|
||||
*
|
||||
* A comma-separated list of DRM devices names, like "card1", to open.
|
||||
* The devices will be used as additional scanout devices, but not as a
|
||||
* rendering device.
|
||||
*/
|
||||
char *additional_devices;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -337,6 +337,9 @@ struct drm_device {
|
|||
*/
|
||||
int min_width, max_width;
|
||||
int min_height, max_height;
|
||||
|
||||
/* drm_backend::kms_list */
|
||||
struct wl_list link;
|
||||
};
|
||||
|
||||
struct drm_backend {
|
||||
|
@ -350,6 +353,8 @@ struct drm_backend {
|
|||
struct wl_event_source *udev_drm_source;
|
||||
|
||||
struct drm_device *drm;
|
||||
/* drm_device::link */
|
||||
struct wl_list kms_list;
|
||||
struct gbm_device *gbm;
|
||||
struct wl_listener session_listener;
|
||||
const struct pixel_format_info *format;
|
||||
|
|
|
@ -630,9 +630,10 @@ static void
|
|||
drm_repaint_begin(struct weston_backend *backend)
|
||||
{
|
||||
struct drm_backend *b = container_of(backend, struct drm_backend, base);
|
||||
struct drm_device *device = b->drm;
|
||||
struct drm_device *device;
|
||||
struct drm_pending_state *pending_state;
|
||||
|
||||
device = b->drm;
|
||||
pending_state = drm_pending_state_alloc(device);
|
||||
device->repaint_data = pending_state;
|
||||
|
||||
|
@ -643,6 +644,19 @@ drm_repaint_begin(struct weston_backend *backend)
|
|||
drm_debug(b, "%s", dbg);
|
||||
free(dbg);
|
||||
}
|
||||
|
||||
wl_list_for_each(device, &b->kms_list, link) {
|
||||
pending_state = drm_pending_state_alloc(device);
|
||||
device->repaint_data = pending_state;
|
||||
|
||||
if (weston_log_scope_is_enabled(b->debug)) {
|
||||
char *dbg = weston_compositor_print_scene_graph(b->compositor);
|
||||
drm_debug(b, "[repaint] Beginning repaint; pending_state %p\n",
|
||||
pending_state);
|
||||
drm_debug(b, "%s", dbg);
|
||||
free(dbg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -658,10 +672,12 @@ static int
|
|||
drm_repaint_flush(struct weston_backend *backend)
|
||||
{
|
||||
struct drm_backend *b = container_of(backend, struct drm_backend, base);
|
||||
struct drm_device *device = b->drm;
|
||||
struct drm_pending_state *pending_state = device->repaint_data;
|
||||
struct drm_device *device;
|
||||
struct drm_pending_state *pending_state;
|
||||
int ret;
|
||||
|
||||
device = b->drm;
|
||||
pending_state = device->repaint_data;
|
||||
ret = drm_pending_state_apply(pending_state);
|
||||
if (ret != 0)
|
||||
weston_log("repaint-flush failed: %s\n", strerror(errno));
|
||||
|
@ -669,6 +685,16 @@ drm_repaint_flush(struct weston_backend *backend)
|
|||
drm_debug(b, "[repaint] flushed pending_state %p\n", pending_state);
|
||||
device->repaint_data = NULL;
|
||||
|
||||
wl_list_for_each(device, &b->kms_list, link) {
|
||||
pending_state = device->repaint_data;
|
||||
ret = drm_pending_state_apply(pending_state);
|
||||
if (ret != 0)
|
||||
weston_log("repaint-flush failed: %s\n", strerror(errno));
|
||||
|
||||
drm_debug(b, "[repaint] flushed pending_state %p\n", pending_state);
|
||||
device->repaint_data = NULL;
|
||||
}
|
||||
|
||||
return (ret == -EACCES || ret == -EBUSY) ? ret : 0;
|
||||
}
|
||||
|
||||
|
@ -682,12 +708,21 @@ static void
|
|||
drm_repaint_cancel(struct weston_backend *backend)
|
||||
{
|
||||
struct drm_backend *b = container_of(backend, struct drm_backend, base);
|
||||
struct drm_device *device = b->drm;
|
||||
struct drm_pending_state *pending_state = device->repaint_data;
|
||||
struct drm_device *device;
|
||||
struct drm_pending_state *pending_state;
|
||||
|
||||
device = b->drm;
|
||||
pending_state = device->repaint_data;
|
||||
drm_pending_state_free(pending_state);
|
||||
drm_debug(b, "[repaint] cancel pending_state %p\n", pending_state);
|
||||
device->repaint_data = NULL;
|
||||
|
||||
wl_list_for_each(device, &b->kms_list, link) {
|
||||
pending_state = device->repaint_data;
|
||||
drm_pending_state_free(pending_state);
|
||||
drm_debug(b, "[repaint] cancel pending_state %p\n", pending_state);
|
||||
device->repaint_data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -2330,6 +2365,26 @@ drm_head_destroy(struct weston_head *base)
|
|||
free(head);
|
||||
}
|
||||
|
||||
static struct drm_device *
|
||||
drm_device_find_by_output(struct weston_compositor *compositor, const char *name)
|
||||
{
|
||||
struct drm_device *device = NULL;
|
||||
struct weston_head *base = NULL;
|
||||
struct drm_head *head;
|
||||
const char *tmp;
|
||||
|
||||
while ((base = weston_compositor_iterate_heads(compositor, base))) {
|
||||
tmp = weston_head_get_name(base);
|
||||
if (strcmp(name, tmp) != 0)
|
||||
continue;
|
||||
head = to_drm_head(base);
|
||||
device = head->connector.device;
|
||||
break;
|
||||
}
|
||||
|
||||
return device;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Weston output structure
|
||||
*
|
||||
|
@ -2347,9 +2402,13 @@ static struct weston_output *
|
|||
drm_output_create(struct weston_backend *backend, const char *name)
|
||||
{
|
||||
struct drm_backend *b = container_of(backend, struct drm_backend, base);
|
||||
struct drm_device *device = b->drm;
|
||||
struct drm_device *device;
|
||||
struct drm_output *output;
|
||||
|
||||
device = drm_device_find_by_output(b->compositor, name);
|
||||
if (!device)
|
||||
return NULL;
|
||||
|
||||
output = zalloc(sizeof *output);
|
||||
if (output == NULL)
|
||||
return NULL;
|
||||
|
@ -2688,6 +2747,7 @@ udev_drm_event(int fd, uint32_t mask, void *data)
|
|||
struct drm_backend *b = data;
|
||||
struct udev_device *event;
|
||||
uint32_t conn_id, prop_id;
|
||||
struct drm_device *device;
|
||||
|
||||
event = udev_monitor_receive_device(b->udev_monitor);
|
||||
|
||||
|
@ -2698,6 +2758,15 @@ udev_drm_event(int fd, uint32_t mask, void *data)
|
|||
drm_backend_update_connectors(b->drm, event);
|
||||
}
|
||||
|
||||
wl_list_for_each(device, &b->kms_list, link) {
|
||||
if (udev_event_is_hotplug(device, event)) {
|
||||
if (udev_event_is_conn_prop_change(b, event, &conn_id, &prop_id))
|
||||
drm_backend_update_conn_props(b, conn_id, prop_id);
|
||||
else
|
||||
drm_backend_update_connectors(device, event);
|
||||
}
|
||||
}
|
||||
|
||||
udev_device_unref(event);
|
||||
|
||||
return 1;
|
||||
|
@ -3125,6 +3194,91 @@ recorder_binding(struct weston_keyboard *keyboard, const struct timespec *time,
|
|||
}
|
||||
#endif
|
||||
|
||||
static struct drm_device *
|
||||
drm_device_create(struct drm_backend *backend, const char *name)
|
||||
{
|
||||
struct weston_compositor *compositor = backend->compositor;
|
||||
struct udev_device *udev_device;
|
||||
struct drm_device *device;
|
||||
struct wl_event_loop *loop;
|
||||
drmModeRes *res;
|
||||
|
||||
device = zalloc(sizeof *device);
|
||||
if (device == NULL)
|
||||
return NULL;
|
||||
device->state_invalid = true;
|
||||
device->drm.fd = -1;
|
||||
device->backend = backend;
|
||||
device->gem_handle_refcnt = hash_table_create();
|
||||
|
||||
udev_device = open_specific_drm_device(backend, device, name);
|
||||
if (!udev_device) {
|
||||
free(device);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (init_kms_caps(device) < 0) {
|
||||
weston_log("failed to initialize kms\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
res = drmModeGetResources(device->drm.fd);
|
||||
if (!res) {
|
||||
weston_log("Failed to get drmModeRes\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
wl_list_init(&device->crtc_list);
|
||||
if (drm_backend_create_crtc_list(device, res) == -1) {
|
||||
weston_log("Failed to create CRTC list for DRM-backend\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
loop = wl_display_get_event_loop(compositor->wl_display);
|
||||
wl_event_loop_add_fd(loop, device->drm.fd,
|
||||
WL_EVENT_READABLE, on_drm_input, device);
|
||||
|
||||
wl_list_init(&device->plane_list);
|
||||
create_sprites(device);
|
||||
|
||||
wl_list_init(&device->writeback_connector_list);
|
||||
if (drm_backend_discover_connectors(device, udev_device, res) < 0) {
|
||||
weston_log("Failed to create heads for %s\n", device->drm.filename);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* 'compute' faked zpos values in case HW doesn't expose any */
|
||||
drm_backend_create_faked_zpos(device);
|
||||
|
||||
return device;
|
||||
err:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
open_additional_devices(struct drm_backend *backend, const char *cards)
|
||||
{
|
||||
struct drm_device *device;
|
||||
char *tokenize = strdup(cards);
|
||||
char *card = strtok(tokenize, ",");
|
||||
|
||||
while (card) {
|
||||
device = drm_device_create(backend, card);
|
||||
if (!device) {
|
||||
weston_log("unable to use card %s\n", card);
|
||||
goto next;
|
||||
}
|
||||
|
||||
weston_log("adding secondary device %s\n",
|
||||
device->drm.filename);
|
||||
wl_list_insert(&backend->kms_list, &device->link);
|
||||
|
||||
next:
|
||||
card = strtok(NULL, ",");
|
||||
}
|
||||
|
||||
free(tokenize);
|
||||
}
|
||||
|
||||
static const struct weston_drm_output_api api = {
|
||||
drm_output_set_mode,
|
||||
|
@ -3169,6 +3323,7 @@ drm_backend_create(struct weston_compositor *compositor,
|
|||
device->backend = b;
|
||||
|
||||
b->drm = device;
|
||||
wl_list_init(&b->kms_list);
|
||||
|
||||
b->compositor = compositor;
|
||||
b->pageflip_timeout = config->pageflip_timeout;
|
||||
|
@ -3217,6 +3372,9 @@ drm_backend_create(struct weston_compositor *compositor,
|
|||
goto err_udev_dev;
|
||||
}
|
||||
|
||||
if (config->additional_devices)
|
||||
open_additional_devices(b, config->additional_devices);
|
||||
|
||||
if (config->renderer == WESTON_RENDERER_AUTO) {
|
||||
#ifdef BUILD_DRM_GBM
|
||||
config->renderer = WESTON_RENDERER_GL;
|
||||
|
|
Loading…
Reference in New Issue