mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-23 16:50:47 +00:00
gl: Add Mesa3D GBM backend
This makes it possible to use the GStreamer OpenGL elements without a windowing system if a libdrm- and Mesa3D-supported GPU is present https://bugzilla.gnome.org/show_bug.cgi?id=782923
This commit is contained in:
parent
79f9f9e600
commit
4df219f336
14 changed files with 1592 additions and 1 deletions
|
@ -951,6 +951,7 @@ gst-libs/gst/gl/wayland/Makefile
|
|||
gst-libs/gst/gl/win32/Makefile
|
||||
gst-libs/gst/gl/x11/Makefile
|
||||
gst-libs/gst/gl/viv-fb/Makefile
|
||||
gst-libs/gst/gl/gbm/Makefile
|
||||
gst-libs/gst/riff/Makefile
|
||||
gst-libs/gst/rtp/Makefile
|
||||
gst-libs/gst/rtsp/Makefile
|
||||
|
|
|
@ -134,6 +134,11 @@ SUBDIRS += viv-fb
|
|||
libgstgl_@GST_API_VERSION@_la_LIBADD += viv-fb/libgstgl-viv-fb.la
|
||||
endif
|
||||
|
||||
if HAVE_WINDOW_GBM
|
||||
SUBDIRS += gbm
|
||||
libgstgl_@GST_API_VERSION@_la_LIBADD += gbm/libgstgl-gbm.la
|
||||
endif
|
||||
|
||||
if USE_EGL
|
||||
SUBDIRS += egl
|
||||
libgstgl_@GST_API_VERSION@_la_LIBADD += egl/libgstgl-egl.la
|
||||
|
|
|
@ -149,6 +149,14 @@ gst_gl_display_egl_get_from_native (GstGLDisplayType type, guintptr display)
|
|||
ret = _gst_eglGetPlatformDisplay (EGL_PLATFORM_WAYLAND, (gpointer) display,
|
||||
NULL);
|
||||
}
|
||||
#endif
|
||||
#if GST_GL_HAVE_WINDOW_GBM
|
||||
if (ret == EGL_NO_DISPLAY && (type & GST_GL_DISPLAY_TYPE_GBM) &&
|
||||
(gst_gl_check_extension ("EGL_MESA_platform_gbm", egl_exts) ||
|
||||
gst_gl_check_extension ("EGL_MESA_platform_gbm", egl_exts))) {
|
||||
ret = _gst_eglGetPlatformDisplay (EGL_PLATFORM_GBM_MESA, (gpointer) display,
|
||||
NULL);
|
||||
}
|
||||
#endif
|
||||
/* android only has one winsys/display connection */
|
||||
|
||||
|
|
31
gst-libs/gst/gl/gbm/Makefile.am
Normal file
31
gst-libs/gst/gl/gbm/Makefile.am
Normal file
|
@ -0,0 +1,31 @@
|
|||
## Process this file with automake to produce Makefile.in
|
||||
|
||||
noinst_LTLIBRARIES = libgstgl-gbm.la
|
||||
|
||||
libgstgl_gbm_la_SOURCES = \
|
||||
gstgl_gbm_utils.c \
|
||||
gstgldisplay_gbm.c \
|
||||
gstglwindow_gbm_egl.c
|
||||
|
||||
noinst_HEADERS = \
|
||||
gstgl_gbm_utils.h \
|
||||
gstgldisplay_gbm.h \
|
||||
gstglwindow_gbm_egl.h
|
||||
|
||||
libgstgl_gbm_la_CFLAGS = \
|
||||
-I$(top_srcdir)/gst-libs \
|
||||
-I$(top_builddir)/gst-libs \
|
||||
$(GL_CFLAGS) \
|
||||
$(GST_PLUGINS_BASE_CFLAGS) \
|
||||
$(GST_BASE_CFLAGS) \
|
||||
$(GST_CFLAGS) \
|
||||
$(DRM_CFLAGS) \
|
||||
$(GBM_CFLAGS) \
|
||||
$(G_UDEV_CFLAGS)
|
||||
|
||||
libgstgl_gbm_la_LDFLAGS = \
|
||||
$(GST_LIB_LDFLAGS) \
|
||||
$(GST_ALL_LDFLAGS) \
|
||||
$(DRM_LIBS) \
|
||||
$(GBM_LIBS) \
|
||||
$(G_UDEV_LIBS)
|
529
gst-libs/gst/gl/gbm/gstgl_gbm_utils.c
Normal file
529
gst-libs/gst/gl/gbm/gstgl_gbm_utils.c
Normal file
|
@ -0,0 +1,529 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2018 Carlos Rafael Giani <dv@pseudoterminal.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <gudev/gudev.h>
|
||||
#include "gstgl_gbm_utils.h"
|
||||
|
||||
GST_DEBUG_CATEGORY_EXTERN (gst_gl_gbm_debug);
|
||||
#define GST_CAT_DEFAULT gst_gl_gbm_debug
|
||||
|
||||
|
||||
const gchar *
|
||||
gst_gl_gbm_get_name_for_drm_connector (drmModeConnector * connector)
|
||||
{
|
||||
g_assert (connector != NULL);
|
||||
|
||||
switch (connector->connector_type) {
|
||||
case DRM_MODE_CONNECTOR_Unknown:
|
||||
return "Unknown";
|
||||
case DRM_MODE_CONNECTOR_VGA:
|
||||
return "VGA";
|
||||
case DRM_MODE_CONNECTOR_DVII:
|
||||
return "DVI-I";
|
||||
case DRM_MODE_CONNECTOR_DVID:
|
||||
return "DVI-D";
|
||||
case DRM_MODE_CONNECTOR_DVIA:
|
||||
return "DVI-A";
|
||||
case DRM_MODE_CONNECTOR_Composite:
|
||||
return "Composite";
|
||||
case DRM_MODE_CONNECTOR_SVIDEO:
|
||||
return "S-Video";
|
||||
case DRM_MODE_CONNECTOR_LVDS:
|
||||
return "LVDS";
|
||||
case DRM_MODE_CONNECTOR_Component:
|
||||
return "Component";
|
||||
case DRM_MODE_CONNECTOR_9PinDIN:
|
||||
return "9-Pin DIN";
|
||||
case DRM_MODE_CONNECTOR_DisplayPort:
|
||||
return "DisplayPort";
|
||||
case DRM_MODE_CONNECTOR_HDMIA:
|
||||
return "HDMI-A";
|
||||
case DRM_MODE_CONNECTOR_HDMIB:
|
||||
return "HDMI-B";
|
||||
case DRM_MODE_CONNECTOR_TV:
|
||||
return "TV";
|
||||
case DRM_MODE_CONNECTOR_eDP:
|
||||
return "eDP";
|
||||
case DRM_MODE_CONNECTOR_VIRTUAL:
|
||||
return "Virtual";
|
||||
case DRM_MODE_CONNECTOR_DSI:
|
||||
return "DSI";
|
||||
default:
|
||||
return "<unknown>";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const gchar *
|
||||
gst_gl_gbm_get_name_for_drm_encoder (drmModeEncoder * encoder)
|
||||
{
|
||||
switch (encoder->encoder_type) {
|
||||
case DRM_MODE_ENCODER_NONE:
|
||||
return "none";
|
||||
case DRM_MODE_ENCODER_DAC:
|
||||
return "DAC";
|
||||
case DRM_MODE_ENCODER_TMDS:
|
||||
return "TMDS";
|
||||
case DRM_MODE_ENCODER_LVDS:
|
||||
return "LVDS";
|
||||
case DRM_MODE_ENCODER_TVDAC:
|
||||
return "TVDAC";
|
||||
case DRM_MODE_ENCODER_VIRTUAL:
|
||||
return "Virtual";
|
||||
case DRM_MODE_ENCODER_DSI:
|
||||
return "DSI";
|
||||
default:
|
||||
return "<unknown>";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const gchar *
|
||||
gst_gl_gbm_format_to_string (guint32 format)
|
||||
{
|
||||
if (format == GBM_BO_FORMAT_XRGB8888)
|
||||
format = GBM_FORMAT_XRGB8888;
|
||||
if (format == GBM_BO_FORMAT_ARGB8888)
|
||||
format = GBM_FORMAT_ARGB8888;
|
||||
|
||||
switch (format) {
|
||||
case GBM_FORMAT_C8:
|
||||
return "C8";
|
||||
case GBM_FORMAT_RGB332:
|
||||
return "RGB332";
|
||||
case GBM_FORMAT_BGR233:
|
||||
return "BGR233";
|
||||
case GBM_FORMAT_NV12:
|
||||
return "NV12";
|
||||
case GBM_FORMAT_XRGB4444:
|
||||
return "XRGB4444";
|
||||
case GBM_FORMAT_XBGR4444:
|
||||
return "XBGR4444";
|
||||
case GBM_FORMAT_RGBX4444:
|
||||
return "RGBX4444";
|
||||
case GBM_FORMAT_BGRX4444:
|
||||
return "BGRX4444";
|
||||
case GBM_FORMAT_XRGB1555:
|
||||
return "XRGB1555";
|
||||
case GBM_FORMAT_XBGR1555:
|
||||
return "XBGR1555";
|
||||
case GBM_FORMAT_RGBX5551:
|
||||
return "RGBX5551";
|
||||
case GBM_FORMAT_BGRX5551:
|
||||
return "BGRX5551";
|
||||
case GBM_FORMAT_ARGB4444:
|
||||
return "ARGB4444";
|
||||
case GBM_FORMAT_ABGR4444:
|
||||
return "ABGR4444";
|
||||
case GBM_FORMAT_RGBA4444:
|
||||
return "RGBA4444";
|
||||
case GBM_FORMAT_BGRA4444:
|
||||
return "BGRA4444";
|
||||
case GBM_FORMAT_ARGB1555:
|
||||
return "ARGB1555";
|
||||
case GBM_FORMAT_ABGR1555:
|
||||
return "ABGR1555";
|
||||
case GBM_FORMAT_RGBA5551:
|
||||
return "RGBA5551";
|
||||
case GBM_FORMAT_BGRA5551:
|
||||
return "BGRA5551";
|
||||
case GBM_FORMAT_RGB565:
|
||||
return "RGB565";
|
||||
case GBM_FORMAT_BGR565:
|
||||
return "BGR565";
|
||||
case GBM_FORMAT_YUYV:
|
||||
return "YUYV";
|
||||
case GBM_FORMAT_YVYU:
|
||||
return "YVYU";
|
||||
case GBM_FORMAT_UYVY:
|
||||
return "UYVY";
|
||||
case GBM_FORMAT_VYUY:
|
||||
return "VYUY";
|
||||
case GBM_FORMAT_RGB888:
|
||||
return "RGB888";
|
||||
case GBM_FORMAT_BGR888:
|
||||
return "BGR888";
|
||||
case GBM_FORMAT_XRGB8888:
|
||||
return "XRGB8888";
|
||||
case GBM_FORMAT_XBGR8888:
|
||||
return "XBGR8888";
|
||||
case GBM_FORMAT_RGBX8888:
|
||||
return "RGBX8888";
|
||||
case GBM_FORMAT_BGRX8888:
|
||||
return "BGRX8888";
|
||||
case GBM_FORMAT_AYUV:
|
||||
return "AYUV";
|
||||
case GBM_FORMAT_XRGB2101010:
|
||||
return "XRGB2101010";
|
||||
case GBM_FORMAT_XBGR2101010:
|
||||
return "XBGR2101010";
|
||||
case GBM_FORMAT_RGBX1010102:
|
||||
return "RGBX1010102";
|
||||
case GBM_FORMAT_BGRX1010102:
|
||||
return "BGRX1010102";
|
||||
case GBM_FORMAT_ARGB8888:
|
||||
return "ARGB8888";
|
||||
case GBM_FORMAT_ABGR8888:
|
||||
return "ABGR8888";
|
||||
case GBM_FORMAT_RGBA8888:
|
||||
return "RGBA8888";
|
||||
case GBM_FORMAT_BGRA8888:
|
||||
return "BGRA8888";
|
||||
case GBM_FORMAT_ARGB2101010:
|
||||
return "ARGB2101010";
|
||||
case GBM_FORMAT_ABGR2101010:
|
||||
return "ABGR2101010";
|
||||
case GBM_FORMAT_RGBA1010102:
|
||||
return "RGBA1010102";
|
||||
case GBM_FORMAT_BGRA1010102:
|
||||
return "BGRA1010102";
|
||||
|
||||
default:
|
||||
return "<unknown>";
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
gst_gl_gbm_depth_from_format (guint32 format)
|
||||
{
|
||||
if (format == GBM_BO_FORMAT_XRGB8888)
|
||||
format = GBM_FORMAT_XRGB8888;
|
||||
if (format == GBM_BO_FORMAT_ARGB8888)
|
||||
format = GBM_FORMAT_ARGB8888;
|
||||
|
||||
switch (format) {
|
||||
case GBM_FORMAT_C8:
|
||||
case GBM_FORMAT_RGB332:
|
||||
case GBM_FORMAT_BGR233:
|
||||
return 8;
|
||||
|
||||
case GBM_FORMAT_NV12:
|
||||
case GBM_FORMAT_XRGB4444:
|
||||
case GBM_FORMAT_XBGR4444:
|
||||
case GBM_FORMAT_RGBX4444:
|
||||
case GBM_FORMAT_BGRX4444:
|
||||
return 12;
|
||||
|
||||
case GBM_FORMAT_XRGB1555:
|
||||
case GBM_FORMAT_XBGR1555:
|
||||
case GBM_FORMAT_RGBX5551:
|
||||
case GBM_FORMAT_BGRX5551:
|
||||
return 15;
|
||||
|
||||
case GBM_FORMAT_ARGB4444:
|
||||
case GBM_FORMAT_ABGR4444:
|
||||
case GBM_FORMAT_RGBA4444:
|
||||
case GBM_FORMAT_BGRA4444:
|
||||
case GBM_FORMAT_ARGB1555:
|
||||
case GBM_FORMAT_ABGR1555:
|
||||
case GBM_FORMAT_RGBA5551:
|
||||
case GBM_FORMAT_BGRA5551:
|
||||
case GBM_FORMAT_RGB565:
|
||||
case GBM_FORMAT_BGR565:
|
||||
case GBM_FORMAT_YUYV:
|
||||
case GBM_FORMAT_YVYU:
|
||||
case GBM_FORMAT_UYVY:
|
||||
case GBM_FORMAT_VYUY:
|
||||
return 16;
|
||||
|
||||
case GBM_FORMAT_RGB888:
|
||||
case GBM_FORMAT_BGR888:
|
||||
case GBM_FORMAT_XRGB8888:
|
||||
case GBM_FORMAT_XBGR8888:
|
||||
case GBM_FORMAT_RGBX8888:
|
||||
case GBM_FORMAT_BGRX8888:
|
||||
case GBM_FORMAT_AYUV:
|
||||
return 24;
|
||||
|
||||
case GBM_FORMAT_XRGB2101010:
|
||||
case GBM_FORMAT_XBGR2101010:
|
||||
case GBM_FORMAT_RGBX1010102:
|
||||
case GBM_FORMAT_BGRX1010102:
|
||||
return 30;
|
||||
|
||||
case GBM_FORMAT_ARGB8888:
|
||||
case GBM_FORMAT_ABGR8888:
|
||||
case GBM_FORMAT_RGBA8888:
|
||||
case GBM_FORMAT_BGRA8888:
|
||||
case GBM_FORMAT_ARGB2101010:
|
||||
case GBM_FORMAT_ABGR2101010:
|
||||
case GBM_FORMAT_RGBA1010102:
|
||||
case GBM_FORMAT_BGRA1010102:
|
||||
return 32;
|
||||
|
||||
default:
|
||||
GST_ERROR ("unknown GBM format %" G_GUINT32_FORMAT, format);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
gst_gl_gbm_bpp_from_format (guint32 format)
|
||||
{
|
||||
if (format == GBM_BO_FORMAT_XRGB8888)
|
||||
format = GBM_FORMAT_XRGB8888;
|
||||
if (format == GBM_BO_FORMAT_ARGB8888)
|
||||
format = GBM_FORMAT_ARGB8888;
|
||||
|
||||
switch (format) {
|
||||
case GBM_FORMAT_C8:
|
||||
case GBM_FORMAT_RGB332:
|
||||
case GBM_FORMAT_BGR233:
|
||||
return 8;
|
||||
|
||||
case GBM_FORMAT_NV12:
|
||||
return 12;
|
||||
|
||||
case GBM_FORMAT_XRGB4444:
|
||||
case GBM_FORMAT_XBGR4444:
|
||||
case GBM_FORMAT_RGBX4444:
|
||||
case GBM_FORMAT_BGRX4444:
|
||||
case GBM_FORMAT_ARGB4444:
|
||||
case GBM_FORMAT_ABGR4444:
|
||||
case GBM_FORMAT_RGBA4444:
|
||||
case GBM_FORMAT_BGRA4444:
|
||||
case GBM_FORMAT_XRGB1555:
|
||||
case GBM_FORMAT_XBGR1555:
|
||||
case GBM_FORMAT_RGBX5551:
|
||||
case GBM_FORMAT_BGRX5551:
|
||||
case GBM_FORMAT_ARGB1555:
|
||||
case GBM_FORMAT_ABGR1555:
|
||||
case GBM_FORMAT_RGBA5551:
|
||||
case GBM_FORMAT_BGRA5551:
|
||||
case GBM_FORMAT_RGB565:
|
||||
case GBM_FORMAT_BGR565:
|
||||
case GBM_FORMAT_YUYV:
|
||||
case GBM_FORMAT_YVYU:
|
||||
case GBM_FORMAT_UYVY:
|
||||
case GBM_FORMAT_VYUY:
|
||||
return 16;
|
||||
|
||||
case GBM_FORMAT_RGB888:
|
||||
case GBM_FORMAT_BGR888:
|
||||
return 24;
|
||||
|
||||
case GBM_FORMAT_XRGB8888:
|
||||
case GBM_FORMAT_XBGR8888:
|
||||
case GBM_FORMAT_RGBX8888:
|
||||
case GBM_FORMAT_BGRX8888:
|
||||
case GBM_FORMAT_ARGB8888:
|
||||
case GBM_FORMAT_ABGR8888:
|
||||
case GBM_FORMAT_RGBA8888:
|
||||
case GBM_FORMAT_BGRA8888:
|
||||
case GBM_FORMAT_XRGB2101010:
|
||||
case GBM_FORMAT_XBGR2101010:
|
||||
case GBM_FORMAT_RGBX1010102:
|
||||
case GBM_FORMAT_BGRX1010102:
|
||||
case GBM_FORMAT_ARGB2101010:
|
||||
case GBM_FORMAT_ABGR2101010:
|
||||
case GBM_FORMAT_RGBA1010102:
|
||||
case GBM_FORMAT_BGRA1010102:
|
||||
case GBM_FORMAT_AYUV:
|
||||
return 32;
|
||||
|
||||
default:
|
||||
GST_ERROR ("unknown GBM format %" G_GUINT32_FORMAT, format);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gst_gl_gbm_drm_fb_destroy_callback (struct gbm_bo *bo, void *data)
|
||||
{
|
||||
int drm_fd = gbm_device_get_fd (gbm_bo_get_device (bo));
|
||||
GstGLDRMFramebuffer *fb = (GstGLDRMFramebuffer *) (data);
|
||||
|
||||
if (fb->fb_id)
|
||||
drmModeRmFB (drm_fd, fb->fb_id);
|
||||
|
||||
g_slice_free1 (sizeof (GstGLDRMFramebuffer), fb);
|
||||
}
|
||||
|
||||
|
||||
GstGLDRMFramebuffer *
|
||||
gst_gl_gbm_drm_fb_get_from_bo (struct gbm_bo *bo)
|
||||
{
|
||||
GstGLDRMFramebuffer *fb;
|
||||
int drm_fd;
|
||||
guint32 width, height, stride, format, handle;
|
||||
int depth, bpp;
|
||||
int ret;
|
||||
|
||||
/* We want to use this buffer object (abbr. "bo") as a scanout buffer.
|
||||
* To that end, we associate the bo with the DRM by using drmModeAddFB().
|
||||
* However, this needs to be called exactly once for the given bo, and the
|
||||
* counterpart, drmModeRmFB(), needs to be called when the bo is cleaned up.
|
||||
*
|
||||
* To fulfill these requirements, add extra framebuffer information to the
|
||||
* bo as "user data". This way, if this user data pointer is NULL, it means
|
||||
* that no framebuffer information was generated yet & the bo was not set
|
||||
* as a scanout buffer with drmModeAddFB() yet, and we have perform these
|
||||
* steps. Otherwise, if it is non-NULL, we know we do not have to set up
|
||||
* anything (since it was done already) and just return the pointer to the
|
||||
* framebuffer information. */
|
||||
fb = (GstGLDRMFramebuffer *) (gbm_bo_get_user_data (bo));
|
||||
if (fb != NULL) {
|
||||
/* The bo was already set up as a scanout framebuffer. Just
|
||||
* return the framebuffer information. */
|
||||
return fb;
|
||||
}
|
||||
|
||||
/* If this point is reached, then we have to setup the bo as a
|
||||
* scanout framebuffer. */
|
||||
|
||||
drm_fd = gbm_device_get_fd (gbm_bo_get_device (bo));
|
||||
|
||||
fb = g_slice_alloc0 (sizeof (GstGLDRMFramebuffer));
|
||||
fb->bo = bo;
|
||||
|
||||
width = gbm_bo_get_width (bo);
|
||||
height = gbm_bo_get_height (bo);
|
||||
stride = gbm_bo_get_stride (bo);
|
||||
format = gbm_bo_get_format (bo);
|
||||
handle = gbm_bo_get_handle (bo).u32;
|
||||
|
||||
depth = gst_gl_gbm_depth_from_format (format);
|
||||
bpp = gst_gl_gbm_bpp_from_format (format);
|
||||
|
||||
GST_DEBUG ("Attempting to add GBM BO as scanout framebuffer width/height: %"
|
||||
G_GUINT32_FORMAT "/%" G_GUINT32_FORMAT " pixels stride: %"
|
||||
G_GUINT32_FORMAT " bytes format: %s depth: %d bits total bpp: %d bits",
|
||||
width, height, stride, gst_gl_gbm_format_to_string (format), depth, bpp);
|
||||
|
||||
/* Set the bo as a scanout framebuffer */
|
||||
ret = drmModeAddFB (drm_fd, width, height, depth, bpp, stride, handle,
|
||||
&fb->fb_id);
|
||||
if (ret != 0) {
|
||||
GST_ERROR ("Failed to add GBM BO as scanout framebuffer: %s (%d)",
|
||||
g_strerror (errno), errno);
|
||||
g_slice_free1 (sizeof (GstGLDRMFramebuffer), fb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Add the framebuffer information to the bo as user data, and also install a callback
|
||||
* that cleans up this extra information whenever the bo itself is discarded */
|
||||
gbm_bo_set_user_data (bo, fb, gst_gl_gbm_drm_fb_destroy_callback);
|
||||
|
||||
return fb;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
gst_gl_gbm_find_and_open_drm_node (void)
|
||||
{
|
||||
/* In here we use GUDev to try to autodetect the GPU */
|
||||
|
||||
int drm_fd = -1;
|
||||
GUdevClient *gudev_client = NULL;
|
||||
GUdevEnumerator *gudev_enum = NULL;
|
||||
GList *devlist = NULL;
|
||||
GList *deventry = NULL;
|
||||
const gchar *subsystems[2] = { "drm", NULL };
|
||||
|
||||
gudev_client = g_udev_client_new (subsystems);
|
||||
if (gudev_client == NULL) {
|
||||
GST_ERROR ("Could not create gudev client");
|
||||
goto cleanup;
|
||||
}
|
||||
GST_DEBUG ("Created gudev client");
|
||||
|
||||
gudev_enum = g_udev_enumerator_new (gudev_client);
|
||||
if (gudev_enum == NULL) {
|
||||
GST_ERROR ("Could not create gudev enumerator");
|
||||
goto cleanup;
|
||||
}
|
||||
GST_DEBUG ("Created gudev enumerator");
|
||||
|
||||
/* TODO: To be 100% sure we pick the right device, also check
|
||||
* if this is a GPU, because a pure scanout device could also
|
||||
* have a DRM subsystem for example. However, currently it is
|
||||
* unclear how to do that. By trying to create an EGL context? */
|
||||
g_udev_enumerator_add_match_subsystem (gudev_enum, "drm");
|
||||
devlist = g_udev_enumerator_execute (gudev_enum);
|
||||
GST_DEBUG ("Scanned for udev devices with a drm subsytem");
|
||||
|
||||
if (devlist == NULL) {
|
||||
GST_WARNING ("Found no matching DRM devices");
|
||||
goto cleanup;
|
||||
}
|
||||
GST_DEBUG ("Got %u potentially matching device(s)", g_list_length (devlist));
|
||||
|
||||
for (deventry = devlist; deventry != NULL; deventry = deventry->next) {
|
||||
GUdevDevice *gudevice = G_UDEV_DEVICE (deventry->data);
|
||||
const gchar *devnode = g_udev_device_get_device_file (gudevice);
|
||||
|
||||
if ((devnode == NULL) || !g_str_has_prefix (devnode, "/dev/dri/card"))
|
||||
continue;
|
||||
|
||||
GST_DEBUG ("Found DRM device with device node \"%s\"", devnode);
|
||||
|
||||
drm_fd = open (devnode, O_RDWR | O_CLOEXEC);
|
||||
if (drm_fd < 0) {
|
||||
GST_WARNING ("Cannot open device node \"%s\": %s (%d)", devnode,
|
||||
g_strerror (errno), errno);
|
||||
continue;
|
||||
}
|
||||
|
||||
GST_DEBUG ("Device node \"%s\" is a valid DRM device node", devnode);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
done:
|
||||
|
||||
if (devlist != NULL) {
|
||||
g_list_free_full (devlist, g_object_unref);
|
||||
devlist = NULL;
|
||||
GST_DEBUG ("Cleaned up device list");
|
||||
}
|
||||
|
||||
if (gudev_enum != NULL) {
|
||||
g_object_unref (G_OBJECT (gudev_enum));
|
||||
gudev_enum = NULL;
|
||||
GST_DEBUG ("Cleaned up gudev enumerator");
|
||||
}
|
||||
|
||||
if (gudev_client != NULL) {
|
||||
g_object_unref (G_OBJECT (gudev_client));
|
||||
gudev_client = NULL;
|
||||
GST_DEBUG ("Cleaned up gudev client");
|
||||
}
|
||||
|
||||
return drm_fd;
|
||||
|
||||
|
||||
cleanup:
|
||||
|
||||
if (drm_fd >= 0) {
|
||||
close (drm_fd);
|
||||
drm_fd = -1;
|
||||
}
|
||||
|
||||
goto done;
|
||||
}
|
49
gst-libs/gst/gl/gbm/gstgl_gbm_utils.h
Normal file
49
gst-libs/gst/gl/gbm/gstgl_gbm_utils.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2018 Carlos Rafael Giani <dv@pseudoterminal.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_GL_GBM_PRIVATE_H__
|
||||
#define __GST_GL_GBM_PRIVATE_H__
|
||||
|
||||
#include <gbm.h>
|
||||
#include <xf86drm.h>
|
||||
#include <xf86drmMode.h>
|
||||
#include <gst/gst.h>
|
||||
|
||||
|
||||
typedef struct _GstGLDRMFramebuffer GstGLDRMFramebuffer;
|
||||
|
||||
struct _GstGLDRMFramebuffer
|
||||
{
|
||||
struct gbm_bo *bo;
|
||||
guint32 fb_id;
|
||||
};
|
||||
|
||||
const gchar* gst_gl_gbm_get_name_for_drm_connector (drmModeConnector * connector);
|
||||
const gchar* gst_gl_gbm_get_name_for_drm_encoder (drmModeEncoder * encoder);
|
||||
const gchar* gst_gl_gbm_format_to_string (guint32 format);
|
||||
int gst_gl_gbm_depth_from_format (guint32 format);
|
||||
int gst_gl_gbm_bpp_from_format (guint32 format);
|
||||
|
||||
GstGLDRMFramebuffer* gst_gl_gbm_drm_fb_get_from_bo (struct gbm_bo *bo);
|
||||
|
||||
int gst_gl_gbm_find_and_open_drm_node (void);
|
||||
|
||||
|
||||
#endif /* __GST_GL_DISPLAY_GBM_UTILS_H__ */
|
423
gst-libs/gst/gl/gbm/gstgldisplay_gbm.c
Normal file
423
gst-libs/gst/gl/gbm/gstgldisplay_gbm.c
Normal file
|
@ -0,0 +1,423 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2018 Carlos Rafael Giani <dv@pseudoterminal.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "gstgldisplay_gbm.h"
|
||||
#include "gstgl_gbm_utils.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
GST_DEBUG_CATEGORY (gst_gl_gbm_debug);
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (gst_gl_display_debug);
|
||||
#define GST_CAT_DEFAULT gst_gl_display_debug
|
||||
|
||||
|
||||
#define INVALID_CRTC ((guint32)0)
|
||||
|
||||
|
||||
G_DEFINE_TYPE (GstGLDisplayGBM, gst_gl_display_gbm, GST_TYPE_GL_DISPLAY);
|
||||
|
||||
|
||||
static void gst_gl_display_gbm_finalize (GObject * object);
|
||||
static guintptr gst_gl_display_gbm_get_handle (GstGLDisplay * display);
|
||||
|
||||
static guint32 gst_gl_gbm_find_crtc_id_for_encoder (GstGLDisplayGBM *
|
||||
display_gbm, drmModeEncoder const *encoder);
|
||||
static guint32 gst_gl_gbm_find_crtc_id_for_connector (GstGLDisplayGBM *
|
||||
display_gbm);
|
||||
|
||||
static gboolean gst_gl_display_gbm_setup_drm (GstGLDisplayGBM * display_gbm);
|
||||
static void gst_gl_display_gbm_shutdown_drm (GstGLDisplayGBM * display_gbm);
|
||||
|
||||
static gboolean gst_gl_display_gbm_setup_gbm (GstGLDisplayGBM * display_gbm);
|
||||
static void gst_gl_display_gbm_shutdown_gbm (GstGLDisplayGBM * display_gbm);
|
||||
|
||||
|
||||
static void
|
||||
gst_gl_display_gbm_class_init (GstGLDisplayGBMClass * klass)
|
||||
{
|
||||
GST_GL_DISPLAY_CLASS (klass)->get_handle =
|
||||
GST_DEBUG_FUNCPTR (gst_gl_display_gbm_get_handle);
|
||||
|
||||
G_OBJECT_CLASS (klass)->finalize = gst_gl_display_gbm_finalize;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_gl_display_gbm_init (GstGLDisplayGBM * display_gbm)
|
||||
{
|
||||
GstGLDisplay *display = (GstGLDisplay *) display_gbm;
|
||||
display->type = GST_GL_DISPLAY_TYPE_GBM;
|
||||
|
||||
display_gbm->drm_fd = -1;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_gl_display_gbm_finalize (GObject * object)
|
||||
{
|
||||
GstGLDisplayGBM *display_gbm = GST_GL_DISPLAY_GBM (object);
|
||||
|
||||
gst_gl_display_gbm_shutdown_gbm (display_gbm);
|
||||
gst_gl_display_gbm_shutdown_drm (display_gbm);
|
||||
|
||||
G_OBJECT_CLASS (gst_gl_display_gbm_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static guintptr
|
||||
gst_gl_display_gbm_get_handle (GstGLDisplay * display)
|
||||
{
|
||||
return (guintptr) GST_GL_DISPLAY_GBM (display)->gbm_dev;
|
||||
}
|
||||
|
||||
|
||||
static guint32
|
||||
gst_gl_gbm_find_crtc_id_for_encoder (GstGLDisplayGBM * display_gbm,
|
||||
drmModeEncoder const *encoder)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < display_gbm->drm_mode_resources->count_crtcs; ++i) {
|
||||
/* possible_crtcs is a bitmask as described here:
|
||||
* https://dvdhrm.wordpress.com/2012/09/13/linux-drm-mode-setting-api */
|
||||
guint32 const crtc_mask = 1 << i;
|
||||
guint32 const crtc_id = display_gbm->drm_mode_resources->crtcs[i];
|
||||
|
||||
if (encoder->possible_crtcs & crtc_mask)
|
||||
return crtc_id;
|
||||
}
|
||||
|
||||
/* No match found */
|
||||
return INVALID_CRTC;
|
||||
}
|
||||
|
||||
|
||||
static guint32
|
||||
gst_gl_gbm_find_crtc_id_for_connector (GstGLDisplayGBM * display_gbm)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < display_gbm->drm_mode_connector->count_encoders; ++i) {
|
||||
guint32 encoder_id = display_gbm->drm_mode_connector->encoders[i];
|
||||
drmModeEncoder *encoder =
|
||||
drmModeGetEncoder (display_gbm->drm_fd, encoder_id);
|
||||
|
||||
if (encoder != NULL) {
|
||||
guint32 crtc_id =
|
||||
gst_gl_gbm_find_crtc_id_for_encoder (display_gbm, encoder);
|
||||
drmModeFreeEncoder (encoder);
|
||||
|
||||
if (crtc_id != INVALID_CRTC)
|
||||
return crtc_id;
|
||||
}
|
||||
}
|
||||
|
||||
/* No match found */
|
||||
return INVALID_CRTC;
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
gst_gl_display_gbm_setup_drm (GstGLDisplayGBM * display_gbm)
|
||||
{
|
||||
int i;
|
||||
|
||||
g_assert (display_gbm != NULL);
|
||||
g_assert (display_gbm->drm_fd >= 0);
|
||||
|
||||
/* Get the DRM mode resources */
|
||||
display_gbm->drm_mode_resources = drmModeGetResources (display_gbm->drm_fd);
|
||||
if (display_gbm->drm_mode_resources == NULL) {
|
||||
GST_ERROR ("Could not get DRM resources: %s (%d)", g_strerror (errno),
|
||||
errno);
|
||||
goto cleanup;
|
||||
}
|
||||
GST_DEBUG ("Got DRM resources");
|
||||
|
||||
/* Find a connected connector. The connector is where the pixel data is
|
||||
* finally sent to, and typically connects to some form of display, like an
|
||||
* HDMI TV, an LVDS panel etc. */
|
||||
{
|
||||
drmModeConnector *connector = NULL;
|
||||
|
||||
GST_DEBUG ("Checking %d DRM connector(s)",
|
||||
display_gbm->drm_mode_resources->count_connectors);
|
||||
for (i = 0; i < display_gbm->drm_mode_resources->count_connectors; ++i) {
|
||||
connector = drmModeGetConnector (display_gbm->drm_fd,
|
||||
display_gbm->drm_mode_resources->connectors[i]);
|
||||
GST_DEBUG ("Found DRM connector #%d \"%s\" with ID %" G_GUINT32_FORMAT, i,
|
||||
gst_gl_gbm_get_name_for_drm_connector (connector),
|
||||
connector->connector_id);
|
||||
|
||||
if (connector->connection == DRM_MODE_CONNECTED) {
|
||||
GST_DEBUG ("DRM connector #%d is connected", i);
|
||||
break;
|
||||
}
|
||||
|
||||
drmModeFreeConnector (connector);
|
||||
connector = NULL;
|
||||
}
|
||||
|
||||
if (connector == NULL) {
|
||||
GST_ERROR ("No connected DRM connector found");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
display_gbm->drm_mode_connector = connector;
|
||||
}
|
||||
|
||||
/* Check out what modes are supported by the chosen connector,
|
||||
* and pick either the "preferred" mode or the one with the largest
|
||||
* pixel area. */
|
||||
{
|
||||
int selected_mode_index = -1;
|
||||
int selected_mode_area = -1;
|
||||
|
||||
GST_DEBUG ("Checking %d DRM mode(s) from selected connector",
|
||||
display_gbm->drm_mode_connector->count_modes);
|
||||
for (i = 0; i < display_gbm->drm_mode_connector->count_modes; ++i) {
|
||||
drmModeModeInfo *current_mode =
|
||||
&(display_gbm->drm_mode_connector->modes[i]);
|
||||
int current_mode_area = current_mode->hdisplay * current_mode->vdisplay;
|
||||
|
||||
GST_DEBUG ("Found DRM mode #%d width/height %" G_GUINT16_FORMAT "/%"
|
||||
G_GUINT16_FORMAT " hsync/vsync start %" G_GUINT16_FORMAT "/%"
|
||||
G_GUINT16_FORMAT " hsync/vsync end %" G_GUINT16_FORMAT "/%"
|
||||
G_GUINT16_FORMAT " htotal/vtotal %" G_GUINT16_FORMAT "/%"
|
||||
G_GUINT16_FORMAT " hskew %" G_GUINT16_FORMAT " vscan %"
|
||||
G_GUINT16_FORMAT " vrefresh %" G_GUINT32_FORMAT " preferred %d", i,
|
||||
current_mode->hdisplay, current_mode->vdisplay,
|
||||
current_mode->hsync_start, current_mode->vsync_start,
|
||||
current_mode->hsync_end, current_mode->vsync_end,
|
||||
current_mode->htotal, current_mode->vtotal, current_mode->hskew,
|
||||
current_mode->vscan, current_mode->vrefresh,
|
||||
(current_mode->type & DRM_MODE_TYPE_PREFERRED) ? TRUE : FALSE);
|
||||
|
||||
if ((current_mode->type & DRM_MODE_TYPE_PREFERRED) ||
|
||||
(current_mode_area > selected_mode_area)) {
|
||||
display_gbm->drm_mode_info = current_mode;
|
||||
selected_mode_area = current_mode_area;
|
||||
selected_mode_index = i;
|
||||
|
||||
if (current_mode->type & DRM_MODE_TYPE_PREFERRED)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (display_gbm->drm_mode_info == NULL) {
|
||||
GST_ERROR ("No usable DRM mode found");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
GST_DEBUG ("Selected DRM mode #%d", selected_mode_index);
|
||||
}
|
||||
|
||||
/* Find an encoder that is attached to the chosen connector. Also find the
|
||||
* index/id of the CRTC associated with this encoder. The encoder takes pixel
|
||||
* data from the CRTC and transmits it to the connector. The CRTC roughly
|
||||
* represents the scanout framebuffer.
|
||||
*
|
||||
* Ultimately, we only care about the CRTC index & ID, so the encoder
|
||||
* reference is discarded here once these are found. The CRTC index is the
|
||||
* index in the m_drm_mode_resources' CRTC array, while the ID is an identifier
|
||||
* used by the DRM to refer to the CRTC universally. (We need the CRTC
|
||||
* information for page flipping and DRM scanout framebuffer configuration.) */
|
||||
{
|
||||
drmModeEncoder *encoder = NULL;
|
||||
|
||||
GST_DEBUG ("Checking %d DRM encoder(s)",
|
||||
display_gbm->drm_mode_resources->count_encoders);
|
||||
for (i = 0; i < display_gbm->drm_mode_resources->count_encoders; ++i) {
|
||||
encoder = drmModeGetEncoder (display_gbm->drm_fd,
|
||||
display_gbm->drm_mode_resources->encoders[i]);
|
||||
|
||||
GST_DEBUG ("Found DRM encoder #%d \"%s\"", i,
|
||||
gst_gl_gbm_get_name_for_drm_encoder (encoder));
|
||||
|
||||
if (encoder->encoder_id == display_gbm->drm_mode_connector->encoder_id) {
|
||||
GST_DEBUG ("DRM encoder #%d corresponds to selected DRM connector "
|
||||
"-> selected", i);
|
||||
break;
|
||||
}
|
||||
drmModeFreeEncoder (encoder);
|
||||
encoder = NULL;
|
||||
}
|
||||
|
||||
if (encoder == NULL) {
|
||||
GST_DEBUG ("No encoder found; searching for CRTC ID in the connector");
|
||||
display_gbm->crtc_id =
|
||||
gst_gl_gbm_find_crtc_id_for_connector (display_gbm);
|
||||
} else {
|
||||
GST_DEBUG ("Using CRTC ID from selected encoder");
|
||||
display_gbm->crtc_id = encoder->crtc_id;
|
||||
drmModeFreeEncoder (encoder);
|
||||
}
|
||||
|
||||
if (display_gbm->crtc_id == INVALID_CRTC) {
|
||||
GST_ERROR ("No CRTC found");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
GST_DEBUG ("CRTC with ID %" G_GUINT32_FORMAT " found; now locating it in "
|
||||
"the DRM mode resources CRTC array", display_gbm->crtc_id);
|
||||
|
||||
for (i = 0; i < display_gbm->drm_mode_resources->count_crtcs; ++i) {
|
||||
if (display_gbm->drm_mode_resources->crtcs[i] == display_gbm->crtc_id) {
|
||||
display_gbm->crtc_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (display_gbm->crtc_index < 0) {
|
||||
GST_ERROR ("No matching CRTC entry in DRM resources found");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
GST_DEBUG ("CRTC with ID %" G_GUINT32_FORMAT " can be found at index #%d "
|
||||
"in the DRM mode resources CRTC array", display_gbm->crtc_id,
|
||||
display_gbm->crtc_index);
|
||||
}
|
||||
|
||||
GST_DEBUG ("DRM structures initialized");
|
||||
return TRUE;
|
||||
|
||||
cleanup:
|
||||
gst_gl_display_gbm_shutdown_drm (display_gbm);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gst_gl_display_gbm_shutdown_drm (GstGLDisplayGBM * display_gbm)
|
||||
{
|
||||
g_assert (display_gbm != NULL);
|
||||
|
||||
display_gbm->drm_mode_info = NULL;
|
||||
|
||||
display_gbm->crtc_index = -1;
|
||||
display_gbm->crtc_id = INVALID_CRTC;
|
||||
|
||||
if (display_gbm->drm_mode_connector != NULL) {
|
||||
drmModeFreeConnector (display_gbm->drm_mode_connector);
|
||||
display_gbm->drm_mode_connector = NULL;
|
||||
}
|
||||
|
||||
if (display_gbm->drm_mode_resources != NULL) {
|
||||
drmModeFreeResources (display_gbm->drm_mode_resources);
|
||||
display_gbm->drm_mode_resources = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
gst_gl_display_gbm_setup_gbm (GstGLDisplayGBM * display_gbm)
|
||||
{
|
||||
display_gbm->gbm_dev = gbm_create_device (display_gbm->drm_fd);
|
||||
if (display_gbm->gbm_dev == NULL) {
|
||||
GST_ERROR ("Creating GBM device failed");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GST_DEBUG ("GBM structures initialized");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gst_gl_display_gbm_shutdown_gbm (GstGLDisplayGBM * display_gbm)
|
||||
{
|
||||
if (display_gbm->gbm_dev != NULL) {
|
||||
gbm_device_destroy (display_gbm->gbm_dev);
|
||||
display_gbm->gbm_dev = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
_init_debug (void)
|
||||
{
|
||||
static volatile gsize _init = 0;
|
||||
|
||||
if (g_once_init_enter (&_init)) {
|
||||
GST_DEBUG_CATEGORY_GET (gst_gl_display_debug, "gldisplay");
|
||||
GST_DEBUG_CATEGORY_INIT (gst_gl_gbm_debug, "gleglgbm", 0,
|
||||
"Mesa3D EGL GBM debugging");
|
||||
g_once_init_leave (&_init, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
GstGLDisplayGBM *
|
||||
gst_gl_display_gbm_new (void)
|
||||
{
|
||||
int drm_fd = -1;
|
||||
GstGLDisplayGBM *display;
|
||||
const gchar *drm_node_name;
|
||||
|
||||
_init_debug ();
|
||||
|
||||
drm_node_name = g_getenv ("GST_GL_GBM_DRM_DEVICE");
|
||||
|
||||
if (drm_node_name != NULL) {
|
||||
GST_DEBUG ("attempting to open device %s (specified by the "
|
||||
"GST_GL_GBM_DRM_DEVICE environment variable)", drm_node_name);
|
||||
drm_fd = open (drm_node_name, O_RDWR | O_CLOEXEC);
|
||||
if (drm_fd < 0) {
|
||||
GST_ERROR ("could not open DRM device %s: %s (%d)", drm_node_name,
|
||||
g_strerror (errno), errno);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
GST_DEBUG ("GST_GL_GBM_DRM_DEVICE environment variable is not "
|
||||
"set - trying to autodetect device");
|
||||
drm_fd = gst_gl_gbm_find_and_open_drm_node ();
|
||||
if (drm_fd < 0) {
|
||||
GST_ERROR ("could not find or open DRM device");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
display = g_object_new (GST_TYPE_GL_DISPLAY_GBM, NULL);
|
||||
display->drm_fd = drm_fd;
|
||||
|
||||
if (!gst_gl_display_gbm_setup_drm (display)) {
|
||||
GST_ERROR ("Failed to initialize DRM");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!gst_gl_display_gbm_setup_gbm (display)) {
|
||||
GST_ERROR ("Failed to initialize GBM");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
GST_DEBUG ("Created GBM EGL display %p", (gpointer) display);
|
||||
|
||||
return display;
|
||||
|
||||
cleanup:
|
||||
gst_gl_display_gbm_shutdown_gbm (display);
|
||||
gst_gl_display_gbm_shutdown_drm (display);
|
||||
gst_object_unref (G_OBJECT (display));
|
||||
if (drm_fd >= 0)
|
||||
close (drm_fd);
|
||||
return NULL;
|
||||
}
|
77
gst-libs/gst/gl/gbm/gstgldisplay_gbm.h
Normal file
77
gst-libs/gst/gl/gbm/gstgldisplay_gbm.h
Normal file
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2018 Carlos Rafael Giani <dv@pseudoterminal.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_GL_DISPLAY_GBM_H__
|
||||
#define __GST_GL_DISPLAY_GBM_H__
|
||||
|
||||
#include <gbm.h>
|
||||
#include <xf86drm.h>
|
||||
#include <xf86drmMode.h>
|
||||
#include <gst/gst.h>
|
||||
#include <gst/gl/gstgldisplay.h>
|
||||
#include <gst/gl/egl/gstegl.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
GType gst_gl_display_gbm_get_type (void);
|
||||
|
||||
#define GST_TYPE_GL_DISPLAY_GBM (gst_gl_display_gbm_get_type())
|
||||
#define GST_GL_DISPLAY_GBM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_DISPLAY_GBM,GstGLDisplayGBM))
|
||||
#define GST_GL_DISPLAY_GBM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_GL_DISPLAY_GBM,GstGLDisplayGBMClass))
|
||||
#define GST_IS_GL_DISPLAY_GBM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_DISPLAY_GBM))
|
||||
#define GST_IS_GL_DISPLAY_GBM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_GL_DISPLAY_GBM))
|
||||
#define GST_GL_DISPLAY_GBM_CAST(obj) ((GstGLDisplayGBM*)(obj))
|
||||
|
||||
#define GST_GL_DISPLAY_GBM_PRIVATE(obj) (((GstGLDisplayGBM*)(obj))->priv)
|
||||
|
||||
typedef struct _GstGLDisplayGBM GstGLDisplayGBM;
|
||||
typedef struct _GstGLDisplayGBMClass GstGLDisplayGBMClass;
|
||||
|
||||
struct _GstGLDisplayGBM
|
||||
{
|
||||
GstGLDisplay parent;
|
||||
|
||||
/* <private> */
|
||||
|
||||
int drm_fd;
|
||||
drmModeRes *drm_mode_resources;
|
||||
drmModeConnector *drm_mode_connector;
|
||||
drmModeModeInfo *drm_mode_info;
|
||||
int crtc_index;
|
||||
guint32 crtc_id;
|
||||
|
||||
struct gbm_device *gbm_dev;
|
||||
|
||||
gpointer _reserved[GST_PADDING];
|
||||
};
|
||||
|
||||
struct _GstGLDisplayGBMClass
|
||||
{
|
||||
GstGLDisplayClass object_class;
|
||||
|
||||
/*< private >*/
|
||||
gpointer _reserved[GST_PADDING_LARGE];
|
||||
};
|
||||
|
||||
GstGLDisplayGBM *gst_gl_display_gbm_new (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_GL_DISPLAY_GBM_H__ */
|
357
gst-libs/gst/gl/gbm/gstglwindow_gbm_egl.c
Normal file
357
gst-libs/gst/gl/gbm/gstglwindow_gbm_egl.c
Normal file
|
@ -0,0 +1,357 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2018 Carlos Rafael Giani <dv@pseudoterminal.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <poll.h>
|
||||
|
||||
#include "../gstgl_fwd.h"
|
||||
#include <gst/gl/gstglcontext.h>
|
||||
#include <gst/gl/egl/gstglcontext_egl.h>
|
||||
|
||||
#include "gstgldisplay_gbm.h"
|
||||
#include "gstglwindow_gbm_egl.h"
|
||||
#include "gstgl_gbm_utils.h"
|
||||
#include "../gstglwindow_private.h"
|
||||
|
||||
#define GST_CAT_DEFAULT gst_gl_window_debug
|
||||
|
||||
|
||||
#define GST_GL_WINDOW_GBM_EGL_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
|
||||
GST_TYPE_GL_WINDOW_GBM_EGL, GstGLWindowGBMEGLPrivate))
|
||||
|
||||
|
||||
G_DEFINE_TYPE (GstGLWindowGBMEGL, gst_gl_window_gbm_egl, GST_TYPE_GL_WINDOW);
|
||||
|
||||
|
||||
static guintptr gst_gl_window_gbm_egl_get_window_handle (GstGLWindow * window);
|
||||
static guintptr gst_gl_window_gbm_egl_get_display (GstGLWindow * window);
|
||||
static void gst_gl_window_gbm_egl_set_window_handle (GstGLWindow * window,
|
||||
guintptr handle);
|
||||
static void gst_gl_window_gbm_egl_close (GstGLWindow * window);
|
||||
static void gst_gl_window_gbm_egl_draw (GstGLWindow * window);
|
||||
|
||||
static gboolean gst_gl_window_gbm_init_surface (GstGLWindowGBMEGL * window_egl);
|
||||
static void gst_gl_window_gbm_egl_cleanup (GstGLWindowGBMEGL * window_egl);
|
||||
|
||||
|
||||
|
||||
static void
|
||||
gst_gl_window_gbm_egl_class_init (GstGLWindowGBMEGLClass * klass)
|
||||
{
|
||||
GstGLWindowClass *window_class = (GstGLWindowClass *) klass;
|
||||
|
||||
window_class->get_window_handle =
|
||||
GST_DEBUG_FUNCPTR (gst_gl_window_gbm_egl_get_window_handle);
|
||||
window_class->get_display =
|
||||
GST_DEBUG_FUNCPTR (gst_gl_window_gbm_egl_get_display);
|
||||
window_class->set_window_handle =
|
||||
GST_DEBUG_FUNCPTR (gst_gl_window_gbm_egl_set_window_handle);
|
||||
window_class->close = GST_DEBUG_FUNCPTR (gst_gl_window_gbm_egl_close);
|
||||
window_class->draw = GST_DEBUG_FUNCPTR (gst_gl_window_gbm_egl_draw);
|
||||
|
||||
/* TODO: add support for set_render_rectangle (assuming this functionality
|
||||
* is possible with libdrm/gbm) */
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gst_gl_window_gbm_egl_init (GstGLWindowGBMEGL * window_gbm)
|
||||
{
|
||||
window_gbm->gbm_surf = NULL;
|
||||
window_gbm->current_bo = NULL;
|
||||
window_gbm->prev_bo = NULL;
|
||||
window_gbm->waiting_for_flip = 0;
|
||||
}
|
||||
|
||||
|
||||
static guintptr
|
||||
gst_gl_window_gbm_egl_get_window_handle (GstGLWindow * window)
|
||||
{
|
||||
GstGLWindowGBMEGL *window_egl = GST_GL_WINDOW_GBM_EGL (window);
|
||||
|
||||
/* This function is called in here, and not in the open()
|
||||
* vmethod. The reason for this is explained inside the
|
||||
* gst_gl_window_gbm_init_surface() function. */
|
||||
if (window_egl->gbm_surf == NULL) {
|
||||
if (!gst_gl_window_gbm_init_surface (window_egl))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (guintptr) GST_GL_WINDOW_GBM_EGL (window)->gbm_surf;
|
||||
}
|
||||
|
||||
|
||||
static guintptr
|
||||
gst_gl_window_gbm_egl_get_display (GstGLWindow * window)
|
||||
{
|
||||
return gst_gl_display_get_handle (window->display);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gst_gl_window_gbm_egl_set_window_handle (G_GNUC_UNUSED GstGLWindow * window,
|
||||
G_GNUC_UNUSED guintptr handle)
|
||||
{
|
||||
/* TODO: Currently, it is unclear how to use external GBM buffer objects,
|
||||
* since it is not defined how this would work together with DRM page flips
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gst_gl_window_gbm_egl_close (GstGLWindow * window)
|
||||
{
|
||||
GstGLWindowGBMEGL *window_egl = GST_GL_WINDOW_GBM_EGL (window);
|
||||
|
||||
gst_gl_window_gbm_egl_cleanup (window_egl);
|
||||
|
||||
GST_GL_WINDOW_CLASS (gst_gl_window_gbm_egl_parent_class)->close (window);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
_page_flip_handler (G_GNUC_UNUSED int fd, G_GNUC_UNUSED unsigned int frame,
|
||||
G_GNUC_UNUSED unsigned int sec, G_GNUC_UNUSED unsigned int usec, void *data)
|
||||
{
|
||||
/* If we reach this point, it means the page flip has been completed.
|
||||
* Signal this by clearing the flag so the poll() loop in draw_cb()
|
||||
* can exit. */
|
||||
int *waiting_for_flip = data;
|
||||
*waiting_for_flip = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
draw_cb (gpointer data)
|
||||
{
|
||||
GstGLWindowGBMEGL *window_egl = data;
|
||||
GstGLWindow *window = GST_GL_WINDOW (window_egl);
|
||||
GstGLContext *context = gst_gl_window_get_context (window);
|
||||
GstGLContextClass *context_class = GST_GL_CONTEXT_GET_CLASS (context);
|
||||
GstGLDisplayGBM *display = (GstGLDisplayGBM *) window->display;
|
||||
struct gbm_bo *next_bo;
|
||||
GstGLDRMFramebuffer *framebuf;
|
||||
int ret;
|
||||
|
||||
drmEventContext evctx = {
|
||||
.version = DRM_EVENT_CONTEXT_VERSION,
|
||||
.page_flip_handler = _page_flip_handler,
|
||||
};
|
||||
|
||||
struct pollfd pfd = {
|
||||
.fd = display->drm_fd,
|
||||
.events = POLLIN,
|
||||
.revents = 0,
|
||||
};
|
||||
|
||||
/* Rendering, page flipping etc. are connect this way:
|
||||
*
|
||||
* The frames are stored in buffer objects (BOs). Inside the eglSwapBuffers()
|
||||
* call, GBM creates new BOs if necessary. BOs can be "locked" for rendering,
|
||||
* meaning that EGL cannot use them as a render target. If all available
|
||||
* BOs are locked, the GBM code inside eglSwapBuffers() creates a new,
|
||||
* unlocked one. We make use of this to implement triple buffering.
|
||||
*
|
||||
* There are 3 BOs in play:
|
||||
*
|
||||
* * next_bo: The BO we just rendered into.
|
||||
* * current_bo: The currently displayed BO.
|
||||
* * prev_bo: The previously displayed BO.
|
||||
*
|
||||
* current_bo and prev_bo are involed in page flipping. next_bo is not.
|
||||
*
|
||||
* Once rendering is done, the next_bo is retrieved and locked. Then, we
|
||||
* wait until any ongoing page flipping finishes. Once it does, the
|
||||
* current_bo is displayed on screen, and the prev_bo isn't anymore. At
|
||||
* this point, it is safe to release the prev_bo, which unlocks it and
|
||||
* makes it available again as a render target. Then we initiate the
|
||||
* next page flipping; this time, we flip to next_bo. At that point,
|
||||
* next_bo becomes current_bo, and current_bo becomes prev_bo.
|
||||
*/
|
||||
|
||||
/*
|
||||
* There is a special case at the beginning. There is no currently
|
||||
* displayed BO at first, so we create an empty one to get the page
|
||||
* flipping cycle going. Also, we use this first BO for setting up
|
||||
* the CRTC.
|
||||
*/
|
||||
if (window_egl->current_bo == NULL) {
|
||||
/* Call eglSwapBuffers() to create a BO. */
|
||||
context_class->swap_buffers (context);
|
||||
|
||||
/* Lock the BO so we get our first current_bo. */
|
||||
window_egl->current_bo =
|
||||
gbm_surface_lock_front_buffer (window_egl->gbm_surf);
|
||||
framebuf = gst_gl_gbm_drm_fb_get_from_bo (window_egl->current_bo);
|
||||
|
||||
/* Configure CRTC to show this first BO. */
|
||||
ret = drmModeSetCrtc (display->drm_fd, display->crtc_id, framebuf->fb_id,
|
||||
0, 0, &(display->drm_mode_connector->connector_id), 1,
|
||||
display->drm_mode_info);
|
||||
|
||||
if (ret != 0) {
|
||||
GST_ERROR ("Could not set DRM CRTC: %s (%d)", g_strerror (errno), errno);
|
||||
/* XXX: it is not possible to communicate the error to the pipeline */
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Do the actual drawing */
|
||||
if (window->draw)
|
||||
window->draw (window->draw_data);
|
||||
|
||||
/* Let the context class call eglSwapBuffers(). As mentioned above,
|
||||
* if necessary, this function creates a new unlocked framebuffer
|
||||
* that can be used as render target. */
|
||||
context_class->swap_buffers (context);
|
||||
gst_object_unref (context);
|
||||
|
||||
next_bo = gbm_surface_lock_front_buffer (window_egl->gbm_surf);
|
||||
framebuf = gst_gl_gbm_drm_fb_get_from_bo (next_bo);
|
||||
GST_LOG ("rendered new frame into bo %p", (gpointer) next_bo);
|
||||
|
||||
/* Wait until any ongoing page flipping is done. After this is done,
|
||||
* prev_bo is no longer involved in any page flipping, and can be
|
||||
* safely released. */
|
||||
while (window_egl->waiting_for_flip) {
|
||||
ret = poll (&pfd, 1, -1);
|
||||
if (ret < 0) {
|
||||
if (errno == EINTR)
|
||||
GST_DEBUG ("Signal caught during poll() call");
|
||||
else
|
||||
GST_ERROR ("poll() failed: %s (%d)", g_strerror (errno), errno);
|
||||
/* XXX: it is not possible to communicate errors and interruptions
|
||||
* to the pipeline */
|
||||
return;
|
||||
}
|
||||
|
||||
drmHandleEvent (display->drm_fd, &evctx);
|
||||
}
|
||||
GST_LOG ("now showing bo %p", (gpointer) (window_egl->current_bo));
|
||||
|
||||
/* Release prev_bo, since it is no longer shown on screen. */
|
||||
if (G_LIKELY (window_egl->prev_bo != NULL)) {
|
||||
gbm_surface_release_buffer (window_egl->gbm_surf, window_egl->prev_bo);
|
||||
GST_LOG ("releasing bo %p", (gpointer) (window_egl->prev_bo));
|
||||
}
|
||||
|
||||
/* Presently, current_bo is shown on screen. Schedule the next page
|
||||
* flip, this time flip to next_bo. The flip happens asynchronously, so
|
||||
* we can continue and render etc. in the meantime. */
|
||||
window_egl->waiting_for_flip = 1;
|
||||
ret = drmModePageFlip (display->drm_fd, display->crtc_id, framebuf->fb_id,
|
||||
DRM_MODE_PAGE_FLIP_EVENT, &(window_egl->waiting_for_flip));
|
||||
if (ret != 0) {
|
||||
/* NOTE: According to libdrm sources, the page is _not_
|
||||
* considered flipped if drmModePageFlip() reports an error,
|
||||
* so we do not update the priv->current_bo pointer here */
|
||||
GST_ERROR ("Could not initialize GBM surface");
|
||||
/* XXX: it is not possible to communicate the error to the pipeline */
|
||||
return;
|
||||
}
|
||||
|
||||
/* At this point, we relabel the current_bo as the prev_bo.
|
||||
* This may not actually be the case yet, but it will be soon - latest
|
||||
* when the wait loop above finishes.
|
||||
* Also, next_bo becomes current_bo. */
|
||||
window_egl->prev_bo = window_egl->current_bo;
|
||||
window_egl->current_bo = next_bo;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gst_gl_window_gbm_egl_draw (GstGLWindow * window)
|
||||
{
|
||||
gst_gl_window_send_message (window, (GstGLWindowCB) draw_cb, window);
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
gst_gl_window_gbm_init_surface (GstGLWindowGBMEGL * window_egl)
|
||||
{
|
||||
/* NOTE: This function cannot be called in the open() vmethod
|
||||
* since context_egl->egl_display and context_egl->egl_config
|
||||
* must have been set to valid values at this point, and open()
|
||||
* is called _before_ these are set.
|
||||
* Also, eglInitialize() is called _after_ the open() vmethod,
|
||||
* which means that the return value of gbm_surface_create()
|
||||
* contains some function pointers that are set to NULL and
|
||||
* shouldn't be. This is because Mesa's eglInitialize() loads
|
||||
* the DRI2 driver and the relevant functions aren't available
|
||||
* until then. */
|
||||
|
||||
GstGLWindow *window = GST_GL_WINDOW (window_egl);
|
||||
GstGLDisplayGBM *display = (GstGLDisplayGBM *) window->display;
|
||||
drmModeModeInfo *drm_mode_info = display->drm_mode_info;
|
||||
GstGLContext *context = gst_gl_window_get_context (window);
|
||||
GstGLContextEGL *context_egl = GST_GL_CONTEXT_EGL (context);
|
||||
EGLint gbm_format;
|
||||
|
||||
/* With GBM-based EGL displays and configs, the native visual ID
|
||||
* is a GBM pixel format. */
|
||||
if (!eglGetConfigAttrib (context_egl->egl_display, context_egl->egl_config,
|
||||
EGL_NATIVE_VISUAL_ID, &gbm_format)) {
|
||||
GST_ERROR ("eglGetConfigAttrib failed: %s",
|
||||
gst_egl_get_error_string (eglGetError ()));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Create a GBM surface that shall contain the BOs we are
|
||||
* going to render into. */
|
||||
window_egl->gbm_surf = gbm_surface_create (display->gbm_dev,
|
||||
drm_mode_info->hdisplay, drm_mode_info->vdisplay, gbm_format,
|
||||
GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
|
||||
|
||||
gst_gl_window_resize (window, drm_mode_info->hdisplay,
|
||||
drm_mode_info->vdisplay);
|
||||
|
||||
GST_DEBUG ("Successfully created GBM surface");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gst_gl_window_gbm_egl_cleanup (GstGLWindowGBMEGL * window_egl)
|
||||
{
|
||||
if (window_egl->gbm_surf != NULL) {
|
||||
if (window_egl->current_bo != NULL) {
|
||||
gbm_surface_release_buffer (window_egl->gbm_surf, window_egl->current_bo);
|
||||
window_egl->current_bo = NULL;
|
||||
}
|
||||
|
||||
gbm_surface_destroy (window_egl->gbm_surf);
|
||||
window_egl->gbm_surf = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Must be called in the gl thread */
|
||||
GstGLWindowGBMEGL *
|
||||
gst_gl_window_gbm_egl_new (GstGLDisplay * display)
|
||||
{
|
||||
GstGLWindowGBMEGL *window_egl;
|
||||
|
||||
if ((gst_gl_display_get_handle_type (display) & GST_GL_DISPLAY_TYPE_GBM) == 0)
|
||||
/* we require a GBM display to create windows */
|
||||
return NULL;
|
||||
|
||||
window_egl = g_object_new (GST_TYPE_GL_WINDOW_GBM_EGL, NULL);
|
||||
|
||||
return window_egl;
|
||||
}
|
69
gst-libs/gst/gl/gbm/gstglwindow_gbm_egl.h
Normal file
69
gst-libs/gst/gl/gbm/gstglwindow_gbm_egl.h
Normal file
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2018 Carlos Rafael Giani <dv@pseudoterminal.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_GL_WINDOW_GBM_EGL_H__
|
||||
#define __GST_GL_WINDOW_GBM_EGL_H__
|
||||
|
||||
#include <gbm.h>
|
||||
#include <gst/gl/gl.h>
|
||||
#include <gst/gl/egl/gstegl.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_GL_WINDOW_GBM_EGL (gst_gl_window_gbm_egl_get_type())
|
||||
#define GST_GL_WINDOW_GBM_EGL(o) (G_TYPE_CHECK_INSTANCE_CAST((o), GST_TYPE_GL_WINDOW_GBM_EGL, GstGLWindowGBMEGL))
|
||||
#define GST_GL_WINDOW_GBM_EGL_CLASS(k) (G_TYPE_CHECK_CLASS((k), GST_TYPE_GL_WINDOW_GBM_EGL, GstGLWindowGBMEGLClass))
|
||||
#define GST_IS_GL_WINDOW_GBM_EGL(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), GST_TYPE_GL_WINDOW_GBM_EGL))
|
||||
#define GST_IS_GL_WINDOW_GBM_EGL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), GST_TYPE_GL_WINDOW_GBM_EGL))
|
||||
#define GST_GL_WINDOW_GBM_EGL_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GST_TYPE_GL_WINDOW_GBM_EGL, GstGLWindowGBMEGL_Class))
|
||||
|
||||
typedef struct _GstGLWindowGBMEGL GstGLWindowGBMEGL;
|
||||
typedef struct _GstGLWindowGBMEGLClass GstGLWindowGBMEGLClass;
|
||||
|
||||
typedef struct _GstGLDisplayGBM GstGLDisplayGBM;
|
||||
|
||||
struct _GstGLWindowGBMEGL {
|
||||
/*< private >*/
|
||||
GstGLWindow parent;
|
||||
|
||||
struct gbm_surface *gbm_surf;
|
||||
struct gbm_bo *current_bo, *prev_bo;
|
||||
int waiting_for_flip;
|
||||
|
||||
GstGLDisplayGBM *display;
|
||||
|
||||
gpointer _reserved[GST_PADDING];
|
||||
};
|
||||
|
||||
struct _GstGLWindowGBMEGLClass {
|
||||
/*< private >*/
|
||||
GstGLWindowClass parent_class;
|
||||
|
||||
/*< private >*/
|
||||
gpointer _reserved[GST_PADDING_LARGE];
|
||||
};
|
||||
|
||||
GType gst_gl_window_gbm_egl_get_type (void);
|
||||
|
||||
GstGLWindowGBMEGL * gst_gl_window_gbm_egl_new (GstGLDisplay * display);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_GL_WINDOW_GBM_EGL_H__ */
|
|
@ -73,6 +73,9 @@
|
|||
#if GST_GL_HAVE_WINDOW_VIV_FB
|
||||
#include <gst/gl/viv-fb/gstgldisplay_viv_fb.h>
|
||||
#endif
|
||||
#if GST_GL_HAVE_WINDOW_GBM
|
||||
#include <gst/gl/gbm/gstgldisplay_gbm.h>
|
||||
#endif
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (gst_context);
|
||||
GST_DEBUG_CATEGORY_STATIC (gst_gl_display_debug);
|
||||
|
@ -313,6 +316,11 @@ gst_gl_display_new (void)
|
|||
display = GST_GL_DISPLAY (gst_gl_display_viv_fb_new (disp_idx));
|
||||
}
|
||||
#endif
|
||||
#if GST_GL_HAVE_WINDOW_GBM
|
||||
if (!display && (!user_choice || g_strstr_len (user_choice, 3, "gbm"))) {
|
||||
display = GST_GL_DISPLAY (gst_gl_display_gbm_new ());
|
||||
}
|
||||
#endif
|
||||
#if GST_GL_HAVE_PLATFORM_EGL
|
||||
if (!display && (!platform_choice
|
||||
|| g_strstr_len (platform_choice, 3, "egl")))
|
||||
|
|
|
@ -49,6 +49,7 @@ GType gst_gl_display_get_type (void);
|
|||
* @GST_GL_DISPLAY_TYPE_DISPMANX: Dispmanx display
|
||||
* @GST_GL_DISPLAY_TYPE_EGL: EGL display
|
||||
* @GST_GL_DISPLAY_TYPE_VIV_FB: Vivante Framebuffer display
|
||||
* @GST_GL_DISPLAY_TYPE_GBM: Mesa3D GBM display
|
||||
* @GST_GL_DISPLAY_TYPE_ANY: any display type
|
||||
*/
|
||||
typedef enum
|
||||
|
@ -61,6 +62,7 @@ typedef enum
|
|||
GST_GL_DISPLAY_TYPE_DISPMANX = (1 << 4),
|
||||
GST_GL_DISPLAY_TYPE_EGL = (1 << 5),
|
||||
GST_GL_DISPLAY_TYPE_VIV_FB = (1 << 6),
|
||||
GST_GL_DISPLAY_TYPE_GBM = (1 << 7),
|
||||
|
||||
GST_GL_DISPLAY_TYPE_ANY = G_MAXUINT32
|
||||
} GstGLDisplayType;
|
||||
|
|
|
@ -62,6 +62,9 @@
|
|||
#if GST_GL_HAVE_WINDOW_VIV_FB
|
||||
#include "viv-fb/gstglwindow_viv_fb_egl.h"
|
||||
#endif
|
||||
#if GST_GL_HAVE_WINDOW_GBM
|
||||
#include "gbm/gstglwindow_gbm_egl.h"
|
||||
#endif
|
||||
#if GST_GL_HAVE_WINDOW_DISPMANX
|
||||
#include "dispmanx/gstglwindow_dispmanx_egl.h"
|
||||
#endif
|
||||
|
@ -279,6 +282,10 @@ gst_gl_window_new (GstGLDisplay * display)
|
|||
if (!window && (!user_choice || g_strstr_len (user_choice, 6, "viv-fb")))
|
||||
window = GST_GL_WINDOW (gst_gl_window_viv_fb_egl_new (display));
|
||||
#endif
|
||||
#if GST_GL_HAVE_WINDOW_GBM
|
||||
if (!window && (!user_choice || g_strstr_len (user_choice, 3, "gbm")))
|
||||
window = GST_GL_WINDOW (gst_gl_window_gbm_egl_new (display));
|
||||
#endif
|
||||
|
||||
if (!window) {
|
||||
/* subclass returned a NULL window */
|
||||
|
|
27
m4/gst-gl.m4
27
m4/gst-gl.m4
|
@ -126,6 +126,7 @@ HAVE_GLES2=no
|
|||
HAVE_GLES3_H=no
|
||||
HAVE_WAYLAND_EGL=no
|
||||
HAVE_VIV_FB_EGL=no
|
||||
HAVE_GBM_EGL=no
|
||||
HAVE_EGL_RPI=no
|
||||
|
||||
case $host in
|
||||
|
@ -171,6 +172,12 @@ case $host in
|
|||
AC_CHECK_LIB([EGL], [fbGetDisplay], [HAVE_VIV_FB_EGL=yes])
|
||||
fi
|
||||
|
||||
if test "x$HAVE_EGL" = "xyes" -a "x$HAVE_DRM" = "xyes"; then
|
||||
PKG_CHECK_MODULES(GBM, gbm, HAVE_GBM_EGL=yes, HAVE_GBM_EGL=no)
|
||||
AC_SUBST(GBM_CFLAGS)
|
||||
AC_SUBST(GBM_LIBS)
|
||||
fi
|
||||
|
||||
dnl FIXME: Mali EGL depends on GLESv1 or GLESv2
|
||||
AC_CHECK_HEADER([EGL/fbdev_window.h],
|
||||
[
|
||||
|
@ -467,6 +474,16 @@ case $host in
|
|||
fi
|
||||
fi
|
||||
|
||||
if test "x$HAVE_GBM_EGL" = "xyes"; then
|
||||
if test "x$NEED_EGL" = "xno" -o "x$HAVE_EGL" = "xno"; then
|
||||
AC_MSG_WARN([EGL is required by the Mesa GBM EGL backend])
|
||||
else
|
||||
HAVE_WINDOW_GBM=yes
|
||||
GL_LIBS="$GL_LIBS"
|
||||
GL_CFLAGS="$GL_CFLAGS"
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "x$HAVE_X11_XCB" = "xyes" -a "x$HAVE_EGL_RPI" = "xno"; then
|
||||
if test "x$NEED_X11" != "xno"; then
|
||||
GL_LIBS="$GL_LIBS $X11_XCB_LIBS"
|
||||
|
@ -511,7 +528,7 @@ case $host in
|
|||
fi
|
||||
else
|
||||
if test "x$NEED_EGL" != "xno"; then
|
||||
if test "x$HAVE_WINDOW_WAYLAND" = "xyes" -o "x$HAVE_WINDOW_X11" = "xyes" -o "x$HAVE_WINDOW_DISPMANX" = "xyes" -o "x$HAVE_WINDOW_VIV_FB" = "xyes"; then
|
||||
if test "x$HAVE_WINDOW_WAYLAND" = "xyes" -o "x$HAVE_WINDOW_X11" = "xyes" -o "x$HAVE_WINDOW_DISPMANX" = "xyes" -o "x$HAVE_WINDOW_VIV_FB" = "xyes" -o "x$HAVE_WINDOW_GBM" = "xyes"; then
|
||||
GL_LIBS="$GL_LIBS -lEGL $EGL_LIBS"
|
||||
GL_CFLAGS="$GL_CFLAGS $EGL_CFLAGS"
|
||||
USE_EGL=yes
|
||||
|
@ -669,6 +686,7 @@ GST_GL_HAVE_WINDOW_ANDROID=0
|
|||
GST_GL_HAVE_WINDOW_DISPMANX=0
|
||||
GST_GL_HAVE_WINDOW_EAGL=0
|
||||
GST_GL_HAVE_WINDOW_VIV_FB=0
|
||||
GST_GL_HAVE_WINDOW_GBM=0
|
||||
|
||||
if test "x$HAVE_WINDOW_X11" = "xyes"; then
|
||||
GL_WINDOWS="x11 $GL_WINDOWS"
|
||||
|
@ -702,6 +720,10 @@ if test "x$HAVE_WINDOW_VIV_FB" = "xyes"; then
|
|||
GL_WINDOWS="viv-fb $GL_WINDOWS"
|
||||
GST_GL_HAVE_WINDOW_VIV_FB=1
|
||||
fi
|
||||
if test "x$HAVE_WINDOW_GBM" = "xyes"; then
|
||||
GL_WINDOWS="gbm $GL_WINDOWS"
|
||||
GST_GL_HAVE_WINDOW_GBM=1
|
||||
fi
|
||||
|
||||
GL_CONFIG_DEFINES="$GL_CONFIG_DEFINES
|
||||
#define GST_GL_HAVE_WINDOW_X11 $GST_GL_HAVE_WINDOW_X11
|
||||
|
@ -712,6 +734,7 @@ GL_CONFIG_DEFINES="$GL_CONFIG_DEFINES
|
|||
#define GST_GL_HAVE_WINDOW_DISPMANX $GST_GL_HAVE_WINDOW_DISPMANX
|
||||
#define GST_GL_HAVE_WINDOW_EAGL $GST_GL_HAVE_WINDOW_EAGL
|
||||
#define GST_GL_HAVE_WINDOW_VIV_FB $GST_GL_HAVE_WINDOW_VIV_FB
|
||||
#define GST_GL_HAVE_WINDOW_GBM $GST_GL_HAVE_WINDOW_GBM
|
||||
"
|
||||
|
||||
dnl PLATFORM's
|
||||
|
@ -789,6 +812,7 @@ if test "x$GL_APIS" = "x" -o "x$GL_PLATFORMS" = "x" -o "x$GL_WINDOWS" = "x"; the
|
|||
HAVE_WINDOW_COCOA=no
|
||||
HAVE_WINDOW_EAGL=no
|
||||
HAVE_WINDOW_VIV_FB=no
|
||||
HAVE_WINDOW_GBM=no
|
||||
fi
|
||||
|
||||
AC_SUBST(GL_APIS)
|
||||
|
@ -808,6 +832,7 @@ AM_CONDITIONAL(HAVE_WINDOW_WAYLAND, test "x$HAVE_WINDOW_WAYLAND" = "xyes")
|
|||
AM_CONDITIONAL(HAVE_WINDOW_ANDROID, test "x$HAVE_WINDOW_ANDROID" = "xyes")
|
||||
AM_CONDITIONAL(HAVE_WINDOW_EAGL, test "x$HAVE_WINDOW_EAGL" = "xyes")
|
||||
AM_CONDITIONAL(HAVE_WINDOW_VIV_FB, test "x$HAVE_WINDOW_VIV_FB" = "xyes")
|
||||
AM_CONDITIONAL(HAVE_WINDOW_GBM, test "x$HAVE_WINDOW_GBM" = "xyes")
|
||||
|
||||
AM_CONDITIONAL(USE_OPENGL, test "x$USE_OPENGL" = "xyes")
|
||||
AM_CONDITIONAL(USE_GLES2, test "x$USE_GLES2" = "xyes")
|
||||
|
|
Loading…
Reference in a new issue