2 * gstvaapidisplay_drm.c - VA/DRM display abstraction
4 * Copyright (C) 2012-2013 Intel Corporation
5 * Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public License
9 * as published by the Free Software Foundation; either version 2.1
10 * of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301 USA
24 * SECTION:gstvaapidisplay_drm
25 * @short_description: VA/DRM display abstraction
34 #include <va/va_drm.h>
35 #include "gstvaapiutils.h"
36 #include "gstvaapidisplay_priv.h"
37 #include "gstvaapidisplay_drm.h"
38 #include "gstvaapidisplay_drm_priv.h"
39 #include "gstvaapiwindow_drm.h"
41 #define DEBUG_VAAPI_DISPLAY 1
42 #include "gstvaapidebug.h"
44 G_DEFINE_TYPE_WITH_PRIVATE (GstVaapiDisplayDRM, gst_vaapi_display_drm,
45 GST_TYPE_VAAPI_DISPLAY);
49 DRM_DEVICE_LEGACY = 1,
50 DRM_DEVICE_RENDERNODES,
53 static DRMDeviceType g_drm_device_type;
54 static GMutex g_drm_device_type_lock;
55 static const gchar *allowed_subsystems[] = { "pci", "platform", NULL };
58 supports_vaapi (int fd)
63 va_dpy = vaGetDisplayDRM (fd);
67 ret = vaapi_initialize (va_dpy);
72 /* Get default device path. Actually, the first match in the DRM subsystem */
74 get_default_device_path (GstVaapiDisplay * display)
76 GstVaapiDisplayDRMPrivate *const priv =
77 GST_VAAPI_DISPLAY_DRM_PRIVATE (display);
78 const gchar *syspath, *devpath;
79 struct udev *udev = NULL;
80 struct udev_device *device, *parent;
81 struct udev_enumerate *e = NULL;
82 struct udev_list_entry *l;
86 if (!priv->device_path_default) {
91 e = udev_enumerate_new (udev);
95 udev_enumerate_add_match_subsystem (e, "drm");
96 switch (g_drm_device_type) {
97 case DRM_DEVICE_LEGACY:
98 udev_enumerate_add_match_sysname (e, "card[0-9]*");
100 case DRM_DEVICE_RENDERNODES:
101 udev_enumerate_add_match_sysname (e, "renderD[0-9]*");
104 GST_ERROR ("unknown drm device type (%d)", g_drm_device_type);
107 udev_enumerate_scan_devices (e);
108 udev_list_entry_foreach (l, udev_enumerate_get_list_entry (e)) {
109 syspath = udev_list_entry_get_name (l);
110 device = udev_device_new_from_syspath (udev, syspath);
111 parent = udev_device_get_parent (device);
113 for (i = 0; allowed_subsystems[i] != NULL; i++)
114 if (g_strcmp0 (udev_device_get_subsystem (parent),
115 allowed_subsystems[i]) == 0)
118 if (allowed_subsystems[i] == NULL) {
119 udev_device_unref (device);
123 devpath = udev_device_get_devnode (device);
124 fd = open (devpath, O_RDWR | O_CLOEXEC);
126 udev_device_unref (device);
130 if (supports_vaapi (fd))
131 priv->device_path_default = g_strdup (devpath);
133 udev_device_unref (device);
134 if (priv->device_path_default)
140 udev_enumerate_unref (e);
144 return priv->device_path_default;
147 /* Reconstruct a device path without our prefix */
149 get_device_path (GstVaapiDisplay * display)
151 GstVaapiDisplayDRMPrivate *const priv =
152 GST_VAAPI_DISPLAY_DRM_PRIVATE (display);
153 const gchar *device_path = priv->device_path;
155 if (!device_path || *device_path == '\0')
160 /* Mangle device path with our prefix */
162 set_device_path (GstVaapiDisplay * display, const gchar * device_path)
164 GstVaapiDisplayDRMPrivate *const priv =
165 GST_VAAPI_DISPLAY_DRM_PRIVATE (display);
167 g_free (priv->device_path);
168 priv->device_path = NULL;
171 device_path = get_default_device_path (display);
175 priv->device_path = g_strdup (device_path);
176 return priv->device_path != NULL;
179 /* Set device path from file descriptor */
181 set_device_path_from_fd (GstVaapiDisplay * display, gint drm_device)
183 GstVaapiDisplayDRMPrivate *const priv =
184 GST_VAAPI_DISPLAY_DRM_PRIVATE (display);
185 const gchar *busid, *path, *str;
186 gsize busid_length, path_length;
187 struct udev *udev = NULL;
188 struct udev_device *device;
189 struct udev_enumerate *e = NULL;
190 struct udev_list_entry *l;
191 gboolean success = FALSE;
194 g_free (priv->device_path);
195 priv->device_path = NULL;
200 busid = drmGetBusid (drm_device);
204 for (i = 0; allowed_subsystems[i] != NULL; i++) {
205 busid_length = strlen (allowed_subsystems[i]);
207 if (strncmp (busid, allowed_subsystems[i], busid_length) == 0) {
208 busid += busid_length + 1;
209 busid_length = strlen (busid);
213 if (allowed_subsystems[i] == NULL)
220 e = udev_enumerate_new (udev);
224 udev_enumerate_add_match_subsystem (e, "drm");
225 udev_enumerate_scan_devices (e);
226 udev_list_entry_foreach (l, udev_enumerate_get_list_entry (e)) {
227 path = udev_list_entry_get_name (l);
228 str = strstr (path, busid);
229 if (!str || str <= path || str[-1] != '/')
232 path_length = strlen (path);
233 if (str + busid_length >= path + path_length)
235 if (strncmp (&str[busid_length], "/drm/card", 9) != 0 &&
236 strncmp (&str[busid_length], "/drm/renderD", 12) != 0)
239 device = udev_device_new_from_syspath (udev, path);
243 path = udev_device_get_devnode (device);
244 priv->device_path = g_strdup (path);
245 udev_device_unref (device);
252 udev_enumerate_unref (e);
259 gst_vaapi_display_drm_bind_display (GstVaapiDisplay * display,
260 gpointer native_display)
262 GstVaapiDisplayDRMPrivate *const priv =
263 GST_VAAPI_DISPLAY_DRM_PRIVATE (display);
265 priv->drm_device = GPOINTER_TO_INT (native_display);
266 priv->use_foreign_display = TRUE;
268 if (!set_device_path_from_fd (display, priv->drm_device))
274 gst_vaapi_display_drm_open_display (GstVaapiDisplay * display,
277 GstVaapiDisplayDRMPrivate *const priv =
278 GST_VAAPI_DISPLAY_DRM_PRIVATE (display);
280 if (!set_device_path (display, name))
283 priv->drm_device = open (get_device_path (display), O_RDWR | O_CLOEXEC);
284 if (priv->drm_device < 0)
286 priv->use_foreign_display = FALSE;
292 gst_vaapi_display_drm_close_display (GstVaapiDisplay * display)
294 GstVaapiDisplayDRMPrivate *const priv =
295 GST_VAAPI_DISPLAY_DRM_PRIVATE (display);
297 if (priv->drm_device >= 0) {
298 if (!priv->use_foreign_display)
299 close (priv->drm_device);
300 priv->drm_device = -1;
303 g_clear_pointer (&priv->device_path, g_free);
304 g_clear_pointer (&priv->device_path_default, g_free);
308 gst_vaapi_display_drm_get_display_info (GstVaapiDisplay * display,
309 GstVaapiDisplayInfo * info)
311 GstVaapiDisplayDRMPrivate *const priv =
312 GST_VAAPI_DISPLAY_DRM_PRIVATE (display);
314 info->native_display = GINT_TO_POINTER (priv->drm_device);
315 info->display_name = priv->device_path;
316 if (!info->va_display) {
317 info->va_display = vaGetDisplayDRM (priv->drm_device);
318 if (!info->va_display)
324 static GstVaapiWindow *
325 gst_vaapi_display_drm_create_window (GstVaapiDisplay * display, GstVaapiID id,
326 guint width, guint height)
328 return id != GST_VAAPI_ID_INVALID ?
329 NULL : gst_vaapi_window_drm_new (display, width, height);
333 gst_vaapi_display_drm_init (GstVaapiDisplayDRM * display)
335 GstVaapiDisplayDRMPrivate *const priv =
336 gst_vaapi_display_drm_get_instance_private (display);
338 display->priv = priv;
339 priv->drm_device = -1;
343 gst_vaapi_display_drm_class_init (GstVaapiDisplayDRMClass * klass)
345 GstVaapiDisplayClass *const dpy_class = GST_VAAPI_DISPLAY_CLASS (klass);
347 dpy_class->display_type = GST_VAAPI_DISPLAY_TYPE_DRM;
348 dpy_class->bind_display = gst_vaapi_display_drm_bind_display;
349 dpy_class->open_display = gst_vaapi_display_drm_open_display;
350 dpy_class->close_display = gst_vaapi_display_drm_close_display;
351 dpy_class->get_display = gst_vaapi_display_drm_get_display_info;
352 dpy_class->create_window = gst_vaapi_display_drm_create_window;
356 * gst_vaapi_display_drm_new:
357 * @device_path: the DRM device path
359 * Opens an DRM file descriptor using @device_path and returns a newly
360 * allocated #GstVaapiDisplay object. The DRM display will be cloed
361 * when the reference count of the object reaches zero.
363 * If @device_path is NULL, the DRM device path will be automatically
364 * determined as the first positive match in the list of available DRM
367 * Return value: a newly allocated #GstVaapiDisplay object
370 gst_vaapi_display_drm_new (const gchar * device_path)
372 GstVaapiDisplay *display;
373 guint types[2], i, num_types = 0;
375 g_mutex_lock (&g_drm_device_type_lock);
377 types[num_types++] = 0;
378 else if (g_drm_device_type)
379 types[num_types++] = g_drm_device_type;
381 types[num_types++] = DRM_DEVICE_RENDERNODES;
382 types[num_types++] = DRM_DEVICE_LEGACY;
385 for (i = 0; i < num_types; i++) {
386 g_drm_device_type = types[i];
387 display = g_object_new (GST_TYPE_VAAPI_DISPLAY_DRM, NULL);
388 display = gst_vaapi_display_config (display,
389 GST_VAAPI_DISPLAY_INIT_FROM_DISPLAY_NAME, (gpointer) device_path);
390 if (display || device_path)
393 g_mutex_unlock (&g_drm_device_type_lock);
398 * gst_vaapi_display_drm_new_with_device:
399 * @device: an open DRM device (file descriptor)
401 * Creates a #GstVaapiDisplay based on the open DRM @device. The
402 * caller still owns the device file descriptor and must call close()
403 * when all #GstVaapiDisplay references are released. Doing so too
404 * early can yield undefined behaviour.
406 * Return value: a newly allocated #GstVaapiDisplay object
409 gst_vaapi_display_drm_new_with_device (gint device)
411 GstVaapiDisplay *display;
413 g_return_val_if_fail (device >= 0, NULL);
415 display = g_object_new (GST_TYPE_VAAPI_DISPLAY_DRM, NULL);
416 return gst_vaapi_display_config (display,
417 GST_VAAPI_DISPLAY_INIT_FROM_NATIVE_DISPLAY, GINT_TO_POINTER (device));
421 * gst_vaapi_display_drm_get_device:
422 * @display: a #GstVaapiDisplayDRM
424 * Returns the underlying DRM device file descriptor that was created
425 * by gst_vaapi_display_drm_new() or that was bound from
426 * gst_vaapi_display_drm_new_with_device().
428 * Return value: the DRM file descriptor attached to @display
431 gst_vaapi_display_drm_get_device (GstVaapiDisplayDRM * display)
433 g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_DRM (display), -1);
435 return GST_VAAPI_DISPLAY_DRM_DEVICE (display);
439 * gst_vaapi_display_drm_get_device_path:
440 * @display: a #GstVaapiDisplayDRM
442 * Returns the underlying DRM device path name was created by
443 * gst_vaapi_display_drm_new() or that was bound from
444 * gst_vaapi_display_drm_new_with_device().
446 * Note: the #GstVaapiDisplayDRM object owns the resulting string, so
447 * it shall not be deallocated.
449 * Return value: the DRM device path name attached to @display
452 gst_vaapi_display_drm_get_device_path (GstVaapiDisplayDRM * display)
454 g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_DRM (display), NULL);
456 return get_device_path (GST_VAAPI_DISPLAY_CAST (display));