]> git.ipfire.org Git - thirdparty/plymouth.git/commitdiff
[drm] Allow multiple monitors to share one controller
authorRay Strode <rstrode@redhat.com>
Thu, 19 Aug 2010 18:22:48 +0000 (14:22 -0400)
committerRay Strode <rstrode@redhat.com>
Thu, 19 Aug 2010 23:59:46 +0000 (19:59 -0400)
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.

src/plugins/renderers/drm/plugin.c

index f936d0a6c9e6ccadf7ff39089ef2daa7c41f0ff5..fcb528454c003f9e7200f10db38914bfc0ff5e41 100644 (file)
 #include <xf86drm.h>
 #include <xf86drmMode.h>
 
+#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