summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2012-04-26 20:00:00 +0100
committerRay Strode <rstrode@redhat.com>2012-05-02 18:38:43 -0400
commit5d29689fd727d94830d31cd7a69935b6a8256e77 (patch)
treef9e95cd2460d3f5a89cd328f9bcf704e7acf5590
parentc20cd45346b03aa02ac0e8855dec3974e090c9e7 (diff)
drm: add generic driver to drm renderer plugingeneric-drm-driver
Since around 2.6.39, the kernel has offered a generic ioctl interface for modesetting (the KMS 'dumb' interface). This interface is now provided by most all of the modesetting drivers. Adding support for this interface means that plymouth will automatically gain support for new modesetting drivers going forward. This commit adds that support. Some changes made by Ray Strode.
-rw-r--r--configure.ac1
-rw-r--r--src/plugins/renderers/drm/Makefile.am3
-rw-r--r--src/plugins/renderers/drm/plugin.c20
-rw-r--r--src/plugins/renderers/drm/ply-renderer-generic-driver.c377
-rw-r--r--src/plugins/renderers/drm/ply-renderer-generic-driver.h33
5 files changed, 434 insertions, 0 deletions
diff --git a/configure.ac b/configure.ac
index db29de88..d872b184 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4,6 +4,7 @@ AC_CONFIG_HEADER(config.h)
AC_CONFIG_AUX_DIR(build-tools)
AC_USE_SYSTEM_EXTENSIONS
+AC_SYS_LARGEFILE
AC_PROG_AWK
AC_PROG_CC
AM_PROG_CC_C_O
diff --git a/src/plugins/renderers/drm/Makefile.am b/src/plugins/renderers/drm/Makefile.am
index 8434d0ec..2209b306 100644
--- a/src/plugins/renderers/drm/Makefile.am
+++ b/src/plugins/renderers/drm/Makefile.am
@@ -18,6 +18,9 @@ drm_la_LIBADD = $(PLYMOUTH_LIBS) $(DRM_LIBS) \
../../../libply-splash-core/libply-splash-core.la
drm_la_SOURCES = $(srcdir)/plugin.c \
$(srcdir)/ply-renderer-driver.h
+drm_la_SOURCES += $(srcdir)/ply-renderer-generic-driver.h \
+ $(srcdir)/ply-renderer-generic-driver.c
+
if ENABLE_LIBDRM_INTEL
drm_la_SOURCES += $(srcdir)/ply-renderer-i915-driver.h \
$(srcdir)/ply-renderer-i915-driver.c
diff --git a/src/plugins/renderers/drm/plugin.c b/src/plugins/renderers/drm/plugin.c
index a418a598..1381c5fa 100644
--- a/src/plugins/renderers/drm/plugin.c
+++ b/src/plugins/renderers/drm/plugin.c
@@ -59,6 +59,7 @@
#include "ply-renderer.h"
#include "ply-renderer-plugin.h"
#include "ply-renderer-driver.h"
+#include "ply-renderer-generic-driver.h"
#ifdef PLY_ENABLE_LIBDRM_INTEL
#include "ply-renderer-i915-driver.h"
#endif
@@ -506,6 +507,25 @@ load_driver (ply_renderer_backend_t *backend)
return false;
}
backend->driver_interface = NULL;
+
+/* Try intel driver first if we're supporting the legacy GDM transition
+ * since it can map the kernel console, which gives us the ability to do
+ * a more seamless transition when plymouth quits before X starts
+ */
+#if defined(PLY_ENABLE_GDM_TRANSITION) && defined(PLY_ENABLE_LIBDRM_INTEL)
+ if (backend->driver_interface == NULL && strcmp (driver_name, "i915") == 0)
+ {
+ backend->driver_interface = ply_renderer_i915_driver_get_interface ();
+ backend->driver_supports_mapping_console = true;
+ }
+#endif
+
+ if (backend->driver_interface == NULL)
+ {
+ backend->driver_interface = ply_renderer_generic_driver_get_interface (device_fd);
+ backend->driver_supports_mapping_console = false;
+ }
+
#ifdef PLY_ENABLE_LIBDRM_INTEL
if (backend->driver_interface == NULL && strcmp (driver_name, "i915") == 0)
{
diff --git a/src/plugins/renderers/drm/ply-renderer-generic-driver.c b/src/plugins/renderers/drm/ply-renderer-generic-driver.c
new file mode 100644
index 00000000..50fde64f
--- /dev/null
+++ b/src/plugins/renderers/drm/ply-renderer-generic-driver.c
@@ -0,0 +1,377 @@
+/* ply-renderer-generic-driver.c - interface to generic drm kms api
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Written by: Dave Airlie
+ * Based on other renderer drivers written by Ray Strode
+ */
+#include "config.h"
+
+#include "ply-renderer-generic-driver.h"
+
+#include <arpa/inet.h>
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <string.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <values.h>
+#include <unistd.h>
+
+#include <drm.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include "ply-hashtable.h"
+#include "ply-logger.h"
+#include "ply-renderer-driver.h"
+
+typedef struct _ply_renderer_buffer ply_renderer_buffer_t;
+
+struct _ply_renderer_buffer
+{
+ uint32_t id;
+
+ uint32_t handle;
+ uint32_t width;
+ uint32_t height;
+ uint32_t row_stride;
+
+ void *map_address;
+ uint32_t map_size;
+ int map_count;
+
+ uint32_t added_fb : 1;
+};
+
+struct _ply_renderer_driver
+{
+ int device_fd;
+ ply_hashtable_t *buffers;
+};
+
+static bool
+ply_renderer_buffer_map (ply_renderer_driver_t *driver,
+ ply_renderer_buffer_t *buffer)
+{
+ struct drm_mode_map_dumb map_dumb_buffer_request;
+ void *map_address;
+
+ if (buffer->map_address != MAP_FAILED)
+ {
+ buffer->map_count++;
+ return true;
+ }
+
+ memset (&map_dumb_buffer_request, 0, sizeof (struct drm_mode_map_dumb));
+ map_dumb_buffer_request.handle = buffer->handle;
+ if (drmIoctl (driver->device_fd, DRM_IOCTL_MODE_MAP_DUMB, &map_dumb_buffer_request) < 0)
+ {
+ ply_trace ("Could not map GEM object %u: %m", buffer->handle);
+ return false;
+ }
+
+ map_address = mmap (0, buffer->map_size,
+ PROT_READ | PROT_WRITE, MAP_SHARED,
+ driver->device_fd, map_dumb_buffer_request.offset);
+
+ if (map_address == MAP_FAILED)
+ return false;
+
+ buffer->map_address = map_address;
+ buffer->map_count++;
+
+ return true;
+}
+
+static void
+ply_renderer_buffer_unmap (ply_renderer_driver_t *driver,
+ ply_renderer_buffer_t *buffer)
+{
+ buffer->map_count--;
+
+ assert (buffer->map_count >= 0);
+}
+
+static ply_renderer_driver_t *
+create_driver (int device_fd)
+{
+ ply_renderer_driver_t *driver;
+
+ driver = calloc (1, sizeof (ply_renderer_driver_t));
+ driver->device_fd = device_fd;
+
+ driver->buffers = ply_hashtable_new (ply_hashtable_direct_hash,
+ ply_hashtable_direct_compare);
+
+ return driver;
+}
+
+static void
+destroy_driver (ply_renderer_driver_t *driver)
+{
+ ply_hashtable_free (driver->buffers);
+
+ free (driver);
+}
+
+static ply_renderer_buffer_t *
+ply_renderer_buffer_new (ply_renderer_driver_t *driver,
+ uint32_t width,
+ uint32_t height)
+{
+ ply_renderer_buffer_t *buffer;
+ struct drm_mode_create_dumb create_dumb_buffer_request;
+
+ buffer = calloc (1, sizeof (ply_renderer_buffer_t));
+ buffer->width = width;
+ buffer->height = height;
+ buffer->map_address = MAP_FAILED;
+
+ memset (&create_dumb_buffer_request, 0, sizeof (struct drm_mode_create_dumb));
+
+ create_dumb_buffer_request.width = width;
+ create_dumb_buffer_request.height = height;
+ create_dumb_buffer_request.bpp = 32;
+ create_dumb_buffer_request.flags = 0;
+
+ if (drmIoctl (driver->device_fd,
+ DRM_IOCTL_MODE_CREATE_DUMB,
+ &create_dumb_buffer_request) < 0)
+ {
+ free (buffer);
+ ply_trace ("Could not allocate GEM object for frame buffer: %m");
+ return NULL;
+ }
+
+ buffer->handle = create_dumb_buffer_request.handle;
+ buffer->row_stride = create_dumb_buffer_request.pitch;
+ buffer->map_size = create_dumb_buffer_request.size;
+
+ ply_trace ("returning %ux%u buffer with stride %u",
+ width, height, buffer->row_stride);
+
+ return buffer;
+}
+
+static void
+ply_renderer_buffer_free (ply_renderer_driver_t *driver,
+ ply_renderer_buffer_t *buffer)
+{
+ struct drm_mode_destroy_dumb destroy_dumb_buffer_request;
+
+ if (buffer->added_fb)
+ drmModeRmFB (driver->device_fd, buffer->id);
+
+ if (buffer->map_address != MAP_FAILED)
+ {
+ munmap (buffer->map_address, buffer->map_size);
+ buffer->map_address = MAP_FAILED;
+ }
+
+ memset (&destroy_dumb_buffer_request, 0, sizeof (struct drm_mode_destroy_dumb));
+ destroy_dumb_buffer_request.handle = buffer->handle;
+
+ if (drmIoctl (driver->device_fd,
+ DRM_IOCTL_MODE_DESTROY_DUMB,
+ &destroy_dumb_buffer_request) < 0)
+ {
+ ply_trace ("Could not deallocate GEM object %u: %m", buffer->handle);
+ }
+
+ free (buffer);
+}
+
+static ply_renderer_buffer_t *
+get_buffer_from_id (ply_renderer_driver_t *driver,
+ uint32_t id)
+{
+ static ply_renderer_buffer_t *buffer;
+
+ buffer = ply_hashtable_lookup (driver->buffers, (void *) (uintptr_t) id);
+
+ return buffer;
+}
+
+static bool
+fetch_buffer (ply_renderer_driver_t *driver,
+ uint32_t buffer_id,
+ unsigned long *width,
+ unsigned long *height,
+ unsigned long *row_stride)
+{
+ ply_renderer_buffer_t *buffer;
+
+ buffer = get_buffer_from_id (driver, buffer_id);
+
+ if (buffer == NULL)
+ {
+ ply_trace ("could not fetch buffer %u", buffer_id);
+ return false;
+ }
+
+ if (width != NULL)
+ *width = buffer->width;
+
+ if (height != NULL)
+ *height = buffer->height;
+
+ if (row_stride != NULL)
+ *row_stride = buffer->row_stride;
+
+ ply_trace ("fetched %ux%u buffer with stride %u",
+ buffer->width, buffer->height, buffer->row_stride);
+ return true;
+}
+
+static uint32_t
+create_buffer (ply_renderer_driver_t *driver,
+ unsigned long width,
+ unsigned long height,
+ unsigned long *row_stride)
+{
+ ply_renderer_buffer_t *buffer;
+
+ buffer = ply_renderer_buffer_new (driver, width, height);
+
+ if (buffer == NULL)
+ {
+ ply_trace ("Could not allocate GEM object for frame buffer: %m");
+ return 0;
+ }
+
+ if (drmModeAddFB (driver->device_fd, width, height,
+ 24, 32, buffer->row_stride, buffer->handle,
+ &buffer->id) != 0)
+ {
+ ply_trace ("Could not set up GEM object as frame buffer: %m");
+ ply_renderer_buffer_free (driver, buffer);
+ return 0;
+ }
+
+ *row_stride = buffer->row_stride;
+
+ buffer->added_fb = true;
+ ply_hashtable_insert (driver->buffers,
+ (void *) (uintptr_t) buffer->id,
+ buffer);
+
+ return buffer->id;
+}
+
+static bool
+map_buffer (ply_renderer_driver_t *driver,
+ uint32_t buffer_id)
+{
+ ply_renderer_buffer_t *buffer;
+
+ buffer = get_buffer_from_id (driver, buffer_id);
+
+ assert (buffer != NULL);
+
+ return ply_renderer_buffer_map (driver, buffer);
+}
+
+static void
+unmap_buffer (ply_renderer_driver_t *driver,
+ uint32_t buffer_id)
+{
+ ply_renderer_buffer_t *buffer;
+
+ buffer = get_buffer_from_id (driver, buffer_id);
+
+ assert (buffer != NULL);
+
+ ply_renderer_buffer_unmap (driver, buffer);
+}
+
+static char *
+begin_flush (ply_renderer_driver_t *driver,
+ uint32_t buffer_id)
+{
+ ply_renderer_buffer_t *buffer;
+
+ buffer = get_buffer_from_id (driver, buffer_id);
+
+ assert (buffer != NULL);
+
+ return buffer->map_address;
+}
+
+static void
+end_flush (ply_renderer_driver_t *driver,
+ uint32_t buffer_id)
+{
+ ply_renderer_buffer_t *buffer;
+
+ buffer = get_buffer_from_id (driver, buffer_id);
+
+ assert (buffer != NULL);
+}
+
+static void
+destroy_buffer (ply_renderer_driver_t *driver,
+ uint32_t buffer_id)
+{
+ ply_renderer_buffer_t *buffer;
+
+ buffer = ply_hashtable_remove (driver->buffers,
+ (void *) (uintptr_t) buffer_id);
+
+ assert (buffer != NULL);
+
+ ply_renderer_buffer_free (driver, buffer);
+}
+
+ply_renderer_driver_interface_t *
+ply_renderer_generic_driver_get_interface (int device_fd)
+{
+ uint64_t supports_dumb_buffers;
+
+ static ply_renderer_driver_interface_t driver_interface =
+ {
+ .create_driver = create_driver,
+ .destroy_driver = destroy_driver,
+ .create_buffer = create_buffer,
+ .fetch_buffer = fetch_buffer,
+ .map_buffer = map_buffer,
+ .unmap_buffer = unmap_buffer,
+ .begin_flush = begin_flush,
+ .end_flush = end_flush,
+ .destroy_buffer = destroy_buffer,
+ };
+
+
+ if (drmGetCap (device_fd, DRM_CAP_DUMB_BUFFER, &supports_dumb_buffers) < 0)
+ return NULL;
+
+ if (!supports_dumb_buffers)
+ return NULL;
+
+ return &driver_interface;
+}
+
+/* vim: set ts=4 sw=4 et ai ci cino={.5s,^-2,+.5s,t0,g0,e-2,n-2,p2s, (0,=.5s,:.5s */
diff --git a/src/plugins/renderers/drm/ply-renderer-generic-driver.h b/src/plugins/renderers/drm/ply-renderer-generic-driver.h
new file mode 100644
index 00000000..053587ab
--- /dev/null
+++ b/src/plugins/renderers/drm/ply-renderer-generic-driver.h
@@ -0,0 +1,33 @@
+/* ply-renderer-generic-driver.h
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Written by: Dave Airlie
+ * Based on other renderer drivers written by Ray Strode
+ */
+#ifndef PLY_RENDERER_DUMB_DRIVER_H
+#define PLY_RENDERER_DUMB_DRIVER_H
+
+#include "ply-renderer-driver.h"
+
+#ifndef PLY_HIDE_FUNCTION_DECLARATIONS
+ply_renderer_driver_interface_t *ply_renderer_generic_driver_get_interface (int device_fd);
+#endif
+
+#endif /* PLY_RENDERER_GENERIC_DRIVER_H */
+/* vim: set ts=4 sw=4 et ai ci cino={.5s,^-2,+.5s,t0,g0,e-2,n-2,p2s,(0,=.5s,:.5s */