From: Ray Strode Date: Thu, 19 Aug 2010 18:22:48 +0000 (-0400) Subject: [drm] Allow multiple monitors to share one controller X-Git-Tag: 0.8.4~168 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=dff1924448a20fa68de575aecaf4679b2ca88381;p=thirdparty%2Fplymouth.git [drm] Allow multiple monitors to share one controller Some underpowered video cards will have multiple connectors tied to one controller. In this case all connectors get the same "cloned" output automatically. This commit detects this situation and prevents plymouth from wastefully trying to allocate several frame buffers. This commit also prevents plymouth from constantly trying to switch between those allocated frame buffers every frame of the animation. --- diff --git a/src/plugins/renderers/drm/plugin.c b/src/plugins/renderers/drm/plugin.c index f936d0a6..fcb52845 100644 --- a/src/plugins/renderers/drm/plugin.c +++ b/src/plugins/renderers/drm/plugin.c @@ -46,10 +46,12 @@ #include #include +#include "ply-array.h" #include "ply-buffer.h" #include "ply-event-loop.h" #include "ply-list.h" #include "ply-logger.h" +#include "ply-hashtable.h" #include "ply-rectangle.h" #include "ply-region.h" #include "ply-terminal.h" @@ -71,8 +73,9 @@ struct _ply_renderer_head unsigned long row_stride; - drmModeConnector *connector; - int connector_mode_index; + ply_array_t *connector_ids; + drmModeConnector *connector0; + int connector0_mode_index; uint32_t controller_id; uint32_t encoder_id; @@ -106,6 +109,7 @@ struct _ply_renderer_backend ply_renderer_input_source_t input_source; ply_list_t *heads; + ply_hashtable_t *heads_by_connector_id; int32_t dither_red; int32_t dither_green; @@ -120,6 +124,34 @@ static void ply_renderer_head_redraw (ply_renderer_backend_t *backend, static bool open_input_source (ply_renderer_backend_t *backend, ply_renderer_input_source_t *input_source); +static bool +ply_renderer_head_add_connector (ply_renderer_head_t *head, + drmModeConnector *connector, + int connector_mode_index) +{ + drmModeModeInfo *mode; + + mode = &connector->modes[connector_mode_index]; + + if (mode->hdisplay != head->area.width || mode->vdisplay != head->area.height) + { + ply_trace ("Tried to add connector with resolution %dx%d to %dx%d head", + (int) mode->hdisplay, (int) mode->vdisplay, + (int) head->area.width, (int) head->area.height); + return false; + } + else + { + ply_trace ("Adding connector with id %d to %dx%d head", + (int) connector->connector_id, + (int) head->area.width, (int) head->area.height); + } + + ply_array_add_uint32_element (head->connector_ids, connector->connector_id); + + return true; +} + static ply_renderer_head_t * ply_renderer_head_new (ply_renderer_backend_t *backend, drmModeConnector *connector, @@ -134,20 +166,25 @@ ply_renderer_head_new (ply_renderer_backend_t *backend, head = calloc (1, sizeof (ply_renderer_head_t)); head->backend = backend; - head->connector = connector; head->encoder_id = encoder_id; + head->connector_ids = ply_array_new (PLY_ARRAY_ELEMENT_TYPE_UINT32); head->controller_id = controller_id; head->console_buffer_id = console_buffer_id; - head->connector_mode_index = connector_mode_index; assert (connector_mode_index < connector->count_modes); - mode = &head->connector->modes[head->connector_mode_index]; + mode = &connector->modes[connector_mode_index]; + + head->connector0 = connector; + head->connector0_mode_index = connector_mode_index; head->area.x = 0; head->area.y = 0; head->area.width = mode->hdisplay; head->area.height = mode->vdisplay; + ply_renderer_head_add_connector (head, connector, connector_mode_index); + assert (ply_array_get_size (head->connector_ids) > 0); + head->pixel_buffer = ply_pixel_buffer_new (head->area.width, head->area.height); ply_trace ("Creating %ldx%ld renderer head", head->area.width, head->area.height); @@ -162,7 +199,8 @@ ply_renderer_head_free (ply_renderer_head_t *head) { ply_trace ("freeing %ldx%ld renderer head", head->area.width, head->area.height); ply_pixel_buffer_free (head->pixel_buffer); - drmModeFreeConnector (head->connector); + + ply_array_free (head->connector_ids); free (head); } @@ -172,15 +210,23 @@ ply_renderer_head_set_scan_out_buffer (ply_renderer_backend_t *backend, uint32_t buffer_id) { drmModeModeInfo *mode; + uint32_t *connector_ids; + int number_of_connectors; - assert (head->connector_mode_index < head->connector->count_modes); - mode = &head->connector->modes[head->connector_mode_index]; + connector_ids = (uint32_t *) ply_array_get_uint32_elements (head->connector_ids); + number_of_connectors = ply_array_get_size (head->connector_ids); - /* Tell the controller to use the allocated scan out buffer - */ + mode = &head->connector0->modes[head->connector0_mode_index]; + + /* Tell the controller to use the allocated scan out buffer on each connectors + */ if (drmModeSetCrtc (backend->device_fd, head->controller_id, buffer_id, - 0, 0, &head->connector->connector_id, 1, mode) < 0) - return false; + 0, 0, connector_ids, number_of_connectors, mode) < 0) + { + ply_trace ("Couldn't set scan out buffer for head with controller id %d", + head->controller_id); + return false; + } return true; } @@ -343,7 +389,6 @@ destroy_backend (ply_renderer_backend_t *backend) { ply_trace ("destroying renderer backend for device %s", backend->device_name); free_heads (backend); - ply_list_free (backend->heads); free (backend->device_name); @@ -771,6 +816,9 @@ create_heads_for_active_connectors (ply_renderer_backend_t *backend) { int i; drmModeConnector *connector; + ply_hashtable_t *heads_by_controller_id; + + heads_by_controller_id = ply_hashtable_new (NULL, NULL); for (i = 0; i < backend->resources->count_connectors; i++) { @@ -833,13 +881,34 @@ create_heads_for_active_connectors (ply_renderer_backend_t *backend) console_buffer_id = controller->buffer_id; drmModeFreeCrtc (controller); - head = ply_renderer_head_new (backend, connector, connector_mode_index, - encoder_id, controller_id, - console_buffer_id); + head = ply_hashtable_lookup (heads_by_controller_id, + (void *) (intptr_t) controller_id); + + if (head == NULL) + { + head = ply_renderer_head_new (backend, connector, connector_mode_index, + encoder_id, controller_id, + console_buffer_id); + + ply_list_append_data (backend->heads, head); + + ply_hashtable_insert (heads_by_controller_id, + (void *) (intptr_t) controller_id, + head); + } + else + { + if (!ply_renderer_head_add_connector (head, connector, connector_mode_index)) + { + ply_trace ("couldn't connect monitor to existing head"); + } - ply_list_append_data (backend->heads, head); + drmModeFreeConnector (connector); + } } + ply_hashtable_free (heads_by_controller_id); + #ifdef PLY_ENABLE_GDM_TRANSITION /* If the driver doesn't support mapping the fb console * then we can't get a smooth crossfade transition to @@ -852,12 +921,21 @@ create_heads_for_active_connectors (ply_renderer_backend_t *backend) if (!backend->driver_supports_mapping_console && ply_list_get_length (backend->heads) == 1) { - ply_trace ("Only one monitor configured, and driver doesn't " - "support mapping console, so letting frame-buffer " - "take over"); + ply_list_node_t *node; + ply_renderer_head_t *head; - free_heads (backend); - return false; + node = ply_list_get_first_node (backend->heads); + head = (ply_renderer_head_t *) ply_list_node_get_data (node); + + if (ply_array_get_size (head->connector_ids) == 1) + { + ply_trace ("Only one monitor configured, and driver doesn't " + "support mapping console, so letting frame-buffer " + "take over"); + + free_heads (backend); + return false; + } } #endif