mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-26 17:18:15 +00:00
new vulkan based video sink
Currently xcb is the only winsys that is implemented and there's no redraws et al
This commit is contained in:
parent
60005b4a12
commit
5de6dd9f40
36 changed files with 5776 additions and 2 deletions
67
configure.ac
67
configure.ac
|
@ -1464,6 +1464,55 @@ AC_SUBST(JPEG_LIBS)
|
|||
AC_SUBST(HAVE_JPEG)
|
||||
AM_CONDITIONAL(HAVE_JPEG, test "x$HAVE_JPEG" = "xyes")
|
||||
|
||||
dnl Vulkan
|
||||
VULKAN_CONFIG_DEFINES=""
|
||||
|
||||
PKG_CHECK_MODULES(XCB, xcb >= 1.10, HAVE_XCB=yes, HAVE_XCB=no)
|
||||
|
||||
AM_CONDITIONAL(USE_XCB, test "x$HAVE_XCB" = "xyes")
|
||||
if test "x$HAVE_XCB" = "xyes"; then
|
||||
VULKAN_CONFIG_DEFINES="$VULKAN_CONFIG_DEFINES
|
||||
#define GST_VULKAN_HAVE_WINDOW_XCB 1"
|
||||
fi
|
||||
|
||||
AC_CONFIG_COMMANDS([ext/vulkan/vkconfig.h], [
|
||||
outfile=vkconfig.h-tmp
|
||||
cat > $outfile <<\_______EOF
|
||||
/* vkconfig.h
|
||||
*
|
||||
* This is a generated file. Please modify `configure.ac'
|
||||
*/
|
||||
|
||||
#ifndef __GST_VULKAN_CONFIG_H__
|
||||
#define __GST_VULKAN_CONFIG_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
_______EOF
|
||||
|
||||
cat >>$outfile <<_______EOF
|
||||
$vulkan_config_defines
|
||||
_______EOF
|
||||
|
||||
cat >>$outfile <<_______EOF
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_VULKAN_CONFIG_H__ */
|
||||
_______EOF
|
||||
|
||||
|
||||
if cmp -s $outfile ext/vulkan/vkconfig.h; then
|
||||
AC_MSG_NOTICE([ext/vulkan/vkconfig.h is unchanged])
|
||||
rm -f $outfile
|
||||
else
|
||||
mv $outfile ext/vulkan/vkconfig.h
|
||||
fi
|
||||
],[
|
||||
vulkan_config_defines='$VULKAN_CONFIG_DEFINES'
|
||||
])
|
||||
|
||||
dnl *** sys plug-ins ***
|
||||
|
||||
|
@ -2851,6 +2900,22 @@ AG_GST_CHECK_FEATURE(QT, [Qt elements], qt, [
|
|||
])
|
||||
])
|
||||
|
||||
dnl *** Vulkan ***
|
||||
translit(dnm, m, l) AM_CONDITIONAL(USE_VULKAN, true)
|
||||
AG_GST_CHECK_FEATURE(VULKAN, [Vulkan elements], vulkan, [
|
||||
HAVE_VULKAN=no
|
||||
AC_CHECK_HEADER(vulkan/vulkan.h, [
|
||||
AC_CHECK_LIB(vulkan, vkCreateDevice, [
|
||||
VULKAN_LIBS="-lvulkan"
|
||||
AC_SUBST(VULKAN_LIBS)
|
||||
dnl TODO check platform support (x11, win32, wayland, android, etc)
|
||||
if test "x$HAVE_XCB" = "xyes"; then
|
||||
HAVE_VULKAN=yes
|
||||
fi
|
||||
], [])
|
||||
], [])
|
||||
])
|
||||
|
||||
dnl *** libvisual ***
|
||||
translit(dnm, m, l) AM_CONDITIONAL(USE_LIBVISUAL, true)
|
||||
AG_GST_CHECK_FEATURE(LIBVISUAL, [libvisual visualization library], libvisual, [
|
||||
|
@ -3636,6 +3701,8 @@ ext/teletextdec/Makefile
|
|||
ext/gme/Makefile
|
||||
ext/spc/Makefile
|
||||
ext/timidity/Makefile
|
||||
ext/vulkan/Makefile
|
||||
ext/vulkan/xcb/Makefile
|
||||
ext/webp/Makefile
|
||||
ext/x265/Makefile
|
||||
ext/xvid/Makefile
|
||||
|
|
|
@ -406,6 +406,12 @@ else
|
|||
DTLS_DIR=
|
||||
endif
|
||||
|
||||
if USE_VULKAN
|
||||
VULKAN_DIR=vulkan
|
||||
else
|
||||
VULKAN_DIR=
|
||||
endif
|
||||
|
||||
SUBDIRS=\
|
||||
$(VOAACENC_DIR) \
|
||||
$(ASSRENDER_DIR) \
|
||||
|
@ -474,7 +480,8 @@ SUBDIRS=\
|
|||
$(HLS_DIR) \
|
||||
$(WEBP_DIR) \
|
||||
$(X265_DIR) \
|
||||
$(DTLS_DIR)
|
||||
$(DTLS_DIR) \
|
||||
$(VULKAN_DIR)
|
||||
|
||||
DIST_SUBDIRS = \
|
||||
assrender \
|
||||
|
@ -541,6 +548,7 @@ DIST_SUBDIRS = \
|
|||
rtmp \
|
||||
webp \
|
||||
x265 \
|
||||
dtls
|
||||
dtls \
|
||||
vulkan
|
||||
|
||||
include $(top_srcdir)/common/parallel-subdirs.mak
|
||||
|
|
1
ext/vulkan/.gitignore
vendored
Normal file
1
ext/vulkan/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
vkconfig.h
|
58
ext/vulkan/Makefile.am
Normal file
58
ext/vulkan/Makefile.am
Normal file
|
@ -0,0 +1,58 @@
|
|||
plugin_LTLIBRARIES = libgstvulkan.la
|
||||
|
||||
SUBDIRS =
|
||||
DIST_SUBDIRS = xcb
|
||||
DISTCLEANFILES = vkconfig.h
|
||||
|
||||
libgstvulkan_la_SOURCES = \
|
||||
gstvulkan.c \
|
||||
vkdevice.c \
|
||||
vkdisplay.c \
|
||||
vkerror.c \
|
||||
vkimagememory.c \
|
||||
vkinstance.c \
|
||||
vkmemory.c \
|
||||
vkqueue.c \
|
||||
vksink.c \
|
||||
vkswapper.c \
|
||||
vkutils.c \
|
||||
vkwindow.c
|
||||
|
||||
noinst_HEADERS = \
|
||||
vk.h \
|
||||
vk_fwd.h \
|
||||
vkdevice.h \
|
||||
vkdisplay.h \
|
||||
vkerror.h \
|
||||
vkimagememory.h \
|
||||
vkinstance.h \
|
||||
vkmemory.h \
|
||||
vkqueue.h \
|
||||
vksink.h \
|
||||
vkswapper.h \
|
||||
vkutils.h \
|
||||
vkwindow.h
|
||||
|
||||
libgstvulkan_la_CFLAGS = \
|
||||
-I$(top_srcdir)/gst-libs \
|
||||
-I$(top_builddir)/gst-libs \
|
||||
$(GST_CFLAGS) \
|
||||
$(GST_BASE_CFLAGS) \
|
||||
$(GST_PLUGINS_BASE_CFLAGS) \
|
||||
$(VULKAN_CFLAGS)
|
||||
|
||||
libgstvulkan_la_LIBADD = \
|
||||
$(GST_BASE_LIBS) \
|
||||
$(GST_PLUGINS_BASE_LIBS) \
|
||||
-lgstvideo-$(GST_API_VERSION) \
|
||||
$(VULKAN_LIBS)
|
||||
|
||||
if USE_XCB
|
||||
SUBDIRS += xcb
|
||||
libgstvulkan_la_LIBADD += xcb/libgstvulkan-xcb.la
|
||||
endif
|
||||
|
||||
libgstvulkan_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||
libgstvulkan_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
|
||||
|
||||
|
63
ext/vulkan/gstvulkan.c
Normal file
63
ext/vulkan/gstvulkan.c
Normal file
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:plugin-vulkan
|
||||
*
|
||||
* Cross-platform Vulkan plugin.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "vksink.h"
|
||||
|
||||
#if GST_VULKAN_HAVE_WINDOW_X11
|
||||
#include <X11/Xlib.h>
|
||||
#endif
|
||||
|
||||
#define GST_CAT_DEFAULT gst_gl_gstgl_debug
|
||||
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
|
||||
|
||||
/* Register filters that make up the gstgl plugin */
|
||||
static gboolean
|
||||
plugin_init (GstPlugin * plugin)
|
||||
{
|
||||
GST_DEBUG_CATEGORY_INIT (gst_gl_gstgl_debug, "gstvulkan", 0, "gstvulkan");
|
||||
|
||||
#if GST_VULKAN_HAVE_WINDOW_X11
|
||||
if (g_getenv ("GST_VULKAN_XINITTHREADS"))
|
||||
XInitThreads ();
|
||||
#endif
|
||||
|
||||
if (!gst_element_register (plugin, "vulkansink",
|
||||
GST_RANK_NONE, GST_TYPE_VULKAN_SINK)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
|
||||
GST_VERSION_MINOR,
|
||||
vulkan,
|
||||
"Vulkan plugin",
|
||||
plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
|
45
ext/vulkan/vk.h
Normal file
45
ext/vulkan/vk.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
|
||||
*
|
||||
* 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 _VK_H_
|
||||
#define _VK_H_
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
#define VK_PROTOTYPES
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <vulkan/vk_debug_report_lunarg.h>
|
||||
#include <vulkan/vk_ext_khr_swapchain.h>
|
||||
#include <vulkan/vk_ext_khr_device_swapchain.h>
|
||||
|
||||
#include "vkconfig.h"
|
||||
#include "vk_fwd.h"
|
||||
|
||||
#include "vkerror.h"
|
||||
#include "vkinstance.h"
|
||||
#include "vkdevice.h"
|
||||
#include "vkqueue.h"
|
||||
#include "vkdisplay.h"
|
||||
#include "vkwindow.h"
|
||||
#include "vkswapper.h"
|
||||
#include "vkmemory.h"
|
||||
#include "vkimagememory.h"
|
||||
|
||||
#endif /* _VK_H_ */
|
58
ext/vulkan/vk_fwd.h
Normal file
58
ext/vulkan/vk_fwd.h
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
|
||||
*
|
||||
* 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 _VK_FWD_H_
|
||||
#define _VK_FWD_H_
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _GstVulkanInstance GstVulkanInstance;
|
||||
typedef struct _GstVulkanInstanceClass GstVulkanInstanceClass;
|
||||
|
||||
typedef struct _GstVulkanDevice GstVulkanDevice;
|
||||
typedef struct _GstVulkanDeviceClass GstVulkanDeviceClass;
|
||||
|
||||
typedef struct _GstVulkanQueue GstVulkanQueue;
|
||||
typedef struct _GstVulkanQueueClass GstVulkanQueueClass;
|
||||
|
||||
typedef struct _GstVulkanDisplay GstVulkanDisplay;
|
||||
typedef struct _GstVulkanDisplayClass GstVulkanDisplayClass;
|
||||
typedef struct _GstVulkanDisplayPrivate GstVulkanDisplayPrivate;
|
||||
|
||||
typedef struct _GstVulkanWindow GstVulkanWindow;
|
||||
typedef struct _GstVulkanWindowClass GstVulkanWindowClass;
|
||||
typedef struct _GstVulkanWindowPrivate GstVulkanWindowPrivate;
|
||||
|
||||
typedef struct _GstVulkanSwapper GstVulkanSwapper;
|
||||
typedef struct _GstVulkanSwapperClass GstVulkanSwapperClass;
|
||||
|
||||
typedef struct _GstVulkanMemory GstVulkanMemory;
|
||||
typedef struct _GstVulkanMemoryAllocator GstVulkanMemoryAllocator;
|
||||
typedef struct _GstVulkanMemoryAllocatorClass GstVulkanMemoryAllocatorClass;
|
||||
|
||||
typedef struct _GstVulkanImageMemory GstVulkanImageMemory;
|
||||
typedef struct _GstVulkanImageMemoryAllocator GstVulkanImageMemoryAllocator;
|
||||
typedef struct _GstVulkanImageMemoryAllocatorClass GstVulkanImageMemoryAllocatorClass;
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* _VK_FWD_H_ */
|
401
ext/vulkan/vkdevice.c
Normal file
401
ext/vulkan/vkdevice.c
Normal file
|
@ -0,0 +1,401 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
|
||||
*
|
||||
* 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 "vkdevice.h"
|
||||
#include "vkutils.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
static const char *device_validation_layers[] = {
|
||||
"Threading",
|
||||
"MemTracker",
|
||||
"ObjectTracker",
|
||||
"DrawState",
|
||||
"ParamChecker",
|
||||
"ShaderChecker",
|
||||
"Swapchain",
|
||||
"DeviceLimits",
|
||||
"Image",
|
||||
};
|
||||
|
||||
#define GST_CAT_DEFAULT gst_vulkan_device_debug
|
||||
GST_DEBUG_CATEGORY (GST_CAT_DEFAULT);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GstVulkanDevice, gst_vulkan_device, GST_TYPE_OBJECT,
|
||||
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "vulkandevice", 0,
|
||||
"Vulkan Device"));
|
||||
|
||||
static void gst_vulkan_device_finalize (GObject * object);
|
||||
|
||||
GstVulkanDevice *
|
||||
gst_vulkan_device_new (GstVulkanInstance * instance)
|
||||
{
|
||||
GstVulkanDevice *device = g_object_new (GST_TYPE_VULKAN_DEVICE, NULL);
|
||||
|
||||
device->instance = gst_object_ref (instance);
|
||||
/* FIXME: select this externally */
|
||||
device->device_index = 0;
|
||||
|
||||
return device;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vulkan_device_init (GstVulkanDevice * device)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vulkan_device_class_init (GstVulkanDeviceClass * device_class)
|
||||
{
|
||||
GObjectClass *gobject_class = (GObjectClass *) device_class;
|
||||
|
||||
gobject_class->finalize = gst_vulkan_device_finalize;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vulkan_device_finalize (GObject * object)
|
||||
{
|
||||
GstVulkanDevice *device = GST_VULKAN_DEVICE (object);
|
||||
|
||||
if (device->cmd_pool.handle)
|
||||
vkDestroyCommandPool (device->device, device->cmd_pool);
|
||||
device->cmd_pool.handle = 0;
|
||||
|
||||
if (device->device)
|
||||
vkDestroyDevice (device->device);
|
||||
device->device = NULL;
|
||||
|
||||
if (device->instance)
|
||||
gst_object_unref (device->instance);
|
||||
device->instance = NULL;
|
||||
}
|
||||
|
||||
static const gchar *
|
||||
_device_type_to_string (VkPhysicalDeviceType type)
|
||||
{
|
||||
switch (type) {
|
||||
case VK_PHYSICAL_DEVICE_TYPE_OTHER:
|
||||
return "other";
|
||||
case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
|
||||
return "integrated";
|
||||
case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
|
||||
return "discrete";
|
||||
case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
|
||||
return "virtual";
|
||||
case VK_PHYSICAL_DEVICE_TYPE_CPU:
|
||||
return "CPU";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_physical_device_info (GstVulkanDevice * device, GError ** error)
|
||||
{
|
||||
VkPhysicalDeviceProperties props;
|
||||
VkPhysicalDevice gpu;
|
||||
VkResult err;
|
||||
|
||||
gpu = gst_vulkan_device_get_physical_device (device);
|
||||
|
||||
err = vkGetPhysicalDeviceProperties (gpu, &props);
|
||||
if (gst_vulkan_error_to_g_error (err, error,
|
||||
"vkGetPhysicalDeviceProperties") < 0)
|
||||
return FALSE;
|
||||
|
||||
GST_INFO_OBJECT (device, "device name %s type %s api version %u, "
|
||||
"driver version %u vendor ID 0x%x, device ID 0x%x", props.deviceName,
|
||||
_device_type_to_string (props.deviceType), props.apiVersion,
|
||||
props.driverVersion, props.vendorId, props.deviceId);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_vulkan_device_open (GstVulkanDevice * device, GError ** error)
|
||||
{
|
||||
const char *extension_names[64];
|
||||
uint32_t enabled_extension_count = 0;
|
||||
uint32_t device_extension_count = 0;
|
||||
VkExtensionProperties *device_extensions = NULL;
|
||||
uint32_t enabled_layer_count = 0;
|
||||
uint32_t device_layer_count = 0;
|
||||
VkLayerProperties *device_layers;
|
||||
gboolean have_swapchain_ext;
|
||||
gboolean validation_found;
|
||||
VkPhysicalDevice gpu;
|
||||
VkResult err;
|
||||
guint i;
|
||||
|
||||
g_return_val_if_fail (GST_IS_VULKAN_DEVICE (device), FALSE);
|
||||
|
||||
if (!_physical_device_info (device, error))
|
||||
return FALSE;
|
||||
|
||||
gpu = gst_vulkan_device_get_physical_device (device);
|
||||
|
||||
/* Look for validation layers */
|
||||
err = vkEnumerateDeviceLayerProperties (gpu, &device_layer_count, NULL);
|
||||
if (gst_vulkan_error_to_g_error (err, error,
|
||||
"vkEnumerateDeviceLayerProperties") < 0)
|
||||
return FALSE;
|
||||
|
||||
device_layers = g_new0 (VkLayerProperties, device_layer_count);
|
||||
err =
|
||||
vkEnumerateDeviceLayerProperties (gpu, &device_layer_count,
|
||||
device_layers);
|
||||
if (gst_vulkan_error_to_g_error (err, error,
|
||||
"vkEnumerateDeviceLayerProperties") < 0) {
|
||||
g_free (device_layers);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
validation_found =
|
||||
_check_for_all_layers (G_N_ELEMENTS (device_validation_layers),
|
||||
device_validation_layers, device_layer_count, device_layers);
|
||||
g_free (device_layers);
|
||||
device_layers = NULL;
|
||||
if (!validation_found) {
|
||||
g_error ("vkEnumerateDeviceLayerProperties failed to find"
|
||||
"a required validation layer.\n\n"
|
||||
"Please look at the Getting Started guide for additional "
|
||||
"information.\nvkCreateDevice Failure");
|
||||
return FALSE;
|
||||
}
|
||||
enabled_layer_count = G_N_ELEMENTS (device_validation_layers);
|
||||
|
||||
err =
|
||||
vkEnumerateDeviceExtensionProperties (gpu, NULL,
|
||||
&device_extension_count, NULL);
|
||||
if (gst_vulkan_error_to_g_error (err, error,
|
||||
"vkEnumerateDeviceExtensionProperties") < 0)
|
||||
return FALSE;
|
||||
|
||||
have_swapchain_ext = 0;
|
||||
enabled_extension_count = 0;
|
||||
memset (extension_names, 0, sizeof (extension_names));
|
||||
device_extensions = g_new0 (VkExtensionProperties, device_extension_count);
|
||||
err = vkEnumerateDeviceExtensionProperties (gpu, NULL,
|
||||
&device_extension_count, device_extensions);
|
||||
if (gst_vulkan_error_to_g_error (err, error,
|
||||
"vkEnumerateDeviceExtensionProperties") < 0) {
|
||||
g_free (device_extensions);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < device_extension_count; i++) {
|
||||
if (!strcmp ("VK_EXT_KHR_device_swapchain", device_extensions[i].extName)) {
|
||||
have_swapchain_ext = TRUE;
|
||||
extension_names[enabled_extension_count++] =
|
||||
"VK_EXT_KHR_device_swapchain";
|
||||
}
|
||||
g_assert (enabled_extension_count < 64);
|
||||
}
|
||||
if (!have_swapchain_ext) {
|
||||
g_error ("vkEnumerateDeviceExtensionProperties failed to find the "
|
||||
"\"VK_EXT_KHR_device_swapchain\" extension.\n\nDo you have a compatible "
|
||||
"Vulkan installable client driver (ICD) installed?\nPlease "
|
||||
"look at the Getting Started guide for additional "
|
||||
"information.\nvkCreateInstance Failure");
|
||||
}
|
||||
g_free (device_extensions);
|
||||
|
||||
err = vkGetPhysicalDeviceProperties (gpu, &device->gpu_props);
|
||||
if (gst_vulkan_error_to_g_error (err, error,
|
||||
"vkGetPhysicalDeviceProperties") < 0)
|
||||
return FALSE;
|
||||
|
||||
err = vkGetPhysicalDeviceMemoryProperties (gpu, &device->memory_properties);
|
||||
if (gst_vulkan_error_to_g_error (err, error,
|
||||
"vkGetPhysicalDeviceProperties") < 0)
|
||||
return FALSE;
|
||||
|
||||
err = vkGetPhysicalDeviceFeatures (gpu, &device->gpu_features);
|
||||
if (gst_vulkan_error_to_g_error (err, error,
|
||||
"vkGetPhysicalDeviceFeatures") < 0)
|
||||
return FALSE;
|
||||
|
||||
/* Call with NULL data to get count */
|
||||
err =
|
||||
vkGetPhysicalDeviceQueueFamilyProperties (gpu, &device->n_queue_families,
|
||||
NULL);
|
||||
if (gst_vulkan_error_to_g_error (err, error,
|
||||
"vkGetPhysicalDeviceQueueFamilyProperties") < 0)
|
||||
return FALSE;
|
||||
g_assert (device->n_queue_families >= 1);
|
||||
|
||||
device->queue_family_props =
|
||||
g_new0 (VkQueueFamilyProperties, device->n_queue_families);
|
||||
err =
|
||||
vkGetPhysicalDeviceQueueFamilyProperties (gpu, &device->n_queue_families,
|
||||
device->queue_family_props);
|
||||
if (gst_vulkan_error_to_g_error (err, error,
|
||||
"vkGetPhysicalDeviceQueueFamilyProperties") < 0)
|
||||
return FALSE;
|
||||
|
||||
/* FIXME: allow overriding/selecting */
|
||||
for (i = 0; i < device->n_queue_families; i++) {
|
||||
if (device->queue_family_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)
|
||||
break;
|
||||
}
|
||||
if (i >= device->n_queue_families) {
|
||||
g_set_error (error, GST_VULKAN_ERROR,
|
||||
GST_VULKAN_ERROR_INITIALIZATION_FAILED,
|
||||
"Failed to find a compatible queue family");
|
||||
return FALSE;
|
||||
}
|
||||
device->queue_family_id = i;
|
||||
device->n_queues = 1;
|
||||
|
||||
{
|
||||
const VkDeviceQueueCreateInfo queue_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
|
||||
.pNext = NULL,
|
||||
.queueFamilyIndex = device->queue_family_id,
|
||||
.queueCount = device->n_queues,
|
||||
};
|
||||
VkDeviceCreateInfo device_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
||||
.pNext = NULL,
|
||||
.queueRecordCount = 1,
|
||||
.pRequestedQueues = &queue_info,
|
||||
.layerCount = enabled_layer_count,
|
||||
.ppEnabledLayerNames = (const char *const *) device_validation_layers,
|
||||
.extensionCount = enabled_extension_count,
|
||||
.ppEnabledExtensionNames = (const char *const *) extension_names,
|
||||
.pEnabledFeatures = NULL, // If specific features are required, pass them in here
|
||||
};
|
||||
|
||||
err = vkCreateDevice (gpu, &device_info, &device->device);
|
||||
if (gst_vulkan_error_to_g_error (err, error, "vkCreateDevice") < 0)
|
||||
return FALSE;
|
||||
}
|
||||
{
|
||||
const VkCmdPoolCreateInfo cmd_pool_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_CMD_POOL_CREATE_INFO,
|
||||
.pNext = NULL,
|
||||
.queueFamilyIndex = device->queue_family_id,
|
||||
.flags = 0,
|
||||
};
|
||||
err =
|
||||
vkCreateCommandPool (device->device, &cmd_pool_info, &device->cmd_pool);
|
||||
if (gst_vulkan_error_to_g_error (err, error, "vkCreateCommandPool") < 0)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
GstVulkanQueue *
|
||||
gst_vulkan_device_get_queue (GstVulkanDevice * device, guint32 queue_family,
|
||||
guint32 queue_i, GError ** error)
|
||||
{
|
||||
GstVulkanQueue *ret;
|
||||
VkResult err;
|
||||
|
||||
g_return_val_if_fail (GST_IS_VULKAN_DEVICE (device), NULL);
|
||||
g_return_val_if_fail (device->device != NULL, NULL);
|
||||
g_return_val_if_fail (queue_family < device->n_queues, NULL);
|
||||
g_return_val_if_fail (queue_i <
|
||||
device->queue_family_props[queue_family].queueCount, NULL);
|
||||
|
||||
ret = g_object_new (GST_TYPE_VULKAN_QUEUE, NULL);
|
||||
ret->device = gst_object_ref (device);
|
||||
ret->family = queue_family;
|
||||
ret->index = queue_i;
|
||||
|
||||
err = vkGetDeviceQueue (device->device, queue_family, queue_i, &ret->queue);
|
||||
if (gst_vulkan_error_to_g_error (err, error, "vkGetDeviceQueue") < 0) {
|
||||
gst_object_unref (ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
gpointer
|
||||
gst_vulkan_device_get_proc_address (GstVulkanDevice * device,
|
||||
const gchar * name)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_VULKAN_DEVICE (device), NULL);
|
||||
g_return_val_if_fail (device->device != NULL, NULL);
|
||||
g_return_val_if_fail (name != NULL, NULL);
|
||||
|
||||
GST_TRACE_OBJECT (device, "%s", name);
|
||||
|
||||
return vkGetDeviceProcAddr (device->device, name);
|
||||
}
|
||||
|
||||
GstVulkanInstance *
|
||||
gst_vulkan_device_get_instance (GstVulkanDevice * device)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_VULKAN_DEVICE (device), NULL);
|
||||
|
||||
return device->instance ? gst_object_ref (device->instance) : NULL;
|
||||
}
|
||||
|
||||
VkPhysicalDevice
|
||||
gst_vulkan_device_get_physical_device (GstVulkanDevice * device)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_VULKAN_DEVICE (device), NULL);
|
||||
|
||||
if (device->instance->physical_devices == NULL)
|
||||
return NULL;
|
||||
if (device->device_index >= device->instance->n_physical_devices)
|
||||
return NULL;
|
||||
|
||||
return device->instance->physical_devices[device->device_index];
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_vulkan_device_create_cmd_buffer (GstVulkanDevice * device,
|
||||
VkCmdBuffer * cmd, GError ** error)
|
||||
{
|
||||
VkResult err;
|
||||
|
||||
const VkCmdBufferCreateInfo cmd_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_CMD_BUFFER_CREATE_INFO,
|
||||
.pNext = NULL,
|
||||
.cmdPool = device->cmd_pool,
|
||||
.level = VK_CMD_BUFFER_LEVEL_PRIMARY,
|
||||
.flags = 0,
|
||||
};
|
||||
|
||||
err = vkCreateCommandBuffer (device->device, &cmd_info, cmd);
|
||||
if (gst_vulkan_error_to_g_error (err, error, "vkCreateCommandBuffer") < 0)
|
||||
return FALSE;
|
||||
|
||||
GST_LOG_OBJECT (device, "created cmd buffer %p", cmd);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
gst_vulkan_device_close (GstVulkanDevice * device)
|
||||
{
|
||||
g_return_if_fail (GST_IS_VULKAN_DEVICE (device));
|
||||
g_return_if_fail (device->device != NULL);
|
||||
|
||||
g_free (device->queue_family_props);
|
||||
}
|
82
ext/vulkan/vkdevice.h
Normal file
82
ext/vulkan/vkdevice.h
Normal file
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
|
||||
*
|
||||
* 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 _VK_DEVICE_H_
|
||||
#define _VK_DEVICE_H_
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include "vk.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_VULKAN_DEVICE (gst_vulkan_device_get_type())
|
||||
#define GST_VULKAN_DEVICE(o) (G_TYPE_CHECK_INSTANCE_CAST((o), GST_TYPE_VULKAN_DEVICE, GstVulkanDevice))
|
||||
#define GST_VULKAN_DEVICE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GST_TYPE_VULKAN_DEVICE, GstVulkanDeviceClass))
|
||||
#define GST_IS_VULKAN_DEVICE(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), GST_TYPE_VULKAN_DEVICE))
|
||||
#define GST_IS_VULKAN_DEVICE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), GST_TYPE_VULKAN_DEVICE))
|
||||
#define GST_VULKAN_DEVICE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GST_TYPE_VULKAN_DEVICE, GstVulkanDeviceClass))
|
||||
GType gst_vulkan_device_get_type (void);
|
||||
|
||||
struct _GstVulkanDevice
|
||||
{
|
||||
GstObject parent;
|
||||
|
||||
GstVulkanInstance *instance;
|
||||
|
||||
guint device_index;
|
||||
VkDevice device; /* hides a pointer */
|
||||
VkPhysicalDeviceProperties gpu_props;
|
||||
VkPhysicalDeviceFeatures gpu_features;
|
||||
VkPhysicalDeviceMemoryProperties memory_properties;
|
||||
|
||||
VkQueueFamilyProperties *queue_family_props;
|
||||
guint32 n_queue_families;
|
||||
|
||||
guint32 queue_family_id;
|
||||
guint32 n_queues;
|
||||
|
||||
VkCmdPool cmd_pool;
|
||||
};
|
||||
|
||||
struct _GstVulkanDeviceClass
|
||||
{
|
||||
GstObjectClass parent_class;
|
||||
};
|
||||
|
||||
GstVulkanDevice * gst_vulkan_device_new (GstVulkanInstance * instance);
|
||||
GstVulkanInstance * gst_vulkan_device_get_instance (GstVulkanDevice * device);
|
||||
gboolean gst_vulkan_device_open (GstVulkanDevice * device,
|
||||
GError ** error);
|
||||
void gst_vulkan_device_close (GstVulkanDevice * device);
|
||||
|
||||
gpointer gst_vulkan_device_get_proc_address (GstVulkanDevice * device,
|
||||
const gchar * name);
|
||||
GstVulkanQueue * gst_vulkan_device_get_queue (GstVulkanDevice * device,
|
||||
guint32 queue_family,
|
||||
guint32 queue_i,
|
||||
GError ** error);
|
||||
VkPhysicalDevice gst_vulkan_device_get_physical_device (GstVulkanDevice * device);
|
||||
gboolean gst_vulkan_device_create_cmd_buffer (GstVulkanDevice * device,
|
||||
VkCmdBuffer * cmd,
|
||||
GError ** error);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* _VK_DEVICE_H_ */
|
246
ext/vulkan/vkdisplay.c
Normal file
246
ext/vulkan/vkdisplay.c
Normal file
|
@ -0,0 +1,246 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2007 David A. Schleef <ds@schleef.org>
|
||||
* Copyright (C) 2008 Julien Isorce <julien.isorce@gmail.com>
|
||||
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com>
|
||||
* Copyright (C) 2013 Matthew Waters <ystreet00@gmail.com>
|
||||
*
|
||||
* 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 "vkdisplay.h"
|
||||
|
||||
#if GST_VULKAN_HAVE_WINDOW_X11
|
||||
#include "x11/vkdisplay_x11.h"
|
||||
#endif
|
||||
#if GST_VULKAN_HAVE_WINDOW_XCB
|
||||
#include "xcb/vkdisplay_xcb.h"
|
||||
#endif
|
||||
|
||||
#define GST_CAT_DEFAULT gst_vulkan_display_debug
|
||||
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
|
||||
|
||||
static void
|
||||
_init_debug (void)
|
||||
{
|
||||
static volatile gsize _init = 0;
|
||||
|
||||
if (g_once_init_enter (&_init)) {
|
||||
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "vulkandisplay", 0,
|
||||
"Vulkan display");
|
||||
g_once_init_leave (&_init, 1);
|
||||
}
|
||||
}
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GstVulkanDisplay, gst_vulkan_display, GST_TYPE_OBJECT,
|
||||
_init_debug ());
|
||||
|
||||
#define GST_VULKAN_DISPLAY_GET_PRIVATE(o) \
|
||||
(G_TYPE_INSTANCE_GET_PRIVATE((o), GST_TYPE_VULKAN_DISPLAY, GstVulkanDisplayPrivate))
|
||||
|
||||
enum
|
||||
{
|
||||
SIGNAL_0,
|
||||
CREATE_CONTEXT,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
/* static guint gst_vulkan_display_signals[LAST_SIGNAL] = { 0 }; */
|
||||
|
||||
static void gst_vulkan_display_finalize (GObject * object);
|
||||
static gpointer gst_vulkan_display_default_get_handle (GstVulkanDisplay *
|
||||
display);
|
||||
static gpointer gst_vulkan_display_default_get_platform_handle (GstVulkanDisplay
|
||||
* display);
|
||||
static GstVulkanWindow
|
||||
* gst_vulkan_display_default_create_window (GstVulkanDisplay * display);
|
||||
|
||||
struct _GstVulkanDisplayPrivate
|
||||
{
|
||||
gint dummy;
|
||||
};
|
||||
|
||||
static void
|
||||
gst_vulkan_display_class_init (GstVulkanDisplayClass * klass)
|
||||
{
|
||||
g_type_class_add_private (klass, sizeof (GstVulkanDisplayPrivate));
|
||||
|
||||
klass->get_handle = gst_vulkan_display_default_get_handle;
|
||||
klass->get_platform_handle = gst_vulkan_display_default_get_platform_handle;
|
||||
klass->create_window = gst_vulkan_display_default_create_window;
|
||||
|
||||
G_OBJECT_CLASS (klass)->finalize = gst_vulkan_display_finalize;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vulkan_display_init (GstVulkanDisplay * display)
|
||||
{
|
||||
display->priv = GST_VULKAN_DISPLAY_GET_PRIVATE (display);
|
||||
display->type = GST_VULKAN_DISPLAY_TYPE_ANY;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vulkan_display_finalize (GObject * object)
|
||||
{
|
||||
G_OBJECT_CLASS (gst_vulkan_display_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_vulkan_display_new:
|
||||
*
|
||||
* Returns: (transfer full): a new #GstVulkanDisplay
|
||||
*
|
||||
* Since: 1.10
|
||||
*/
|
||||
GstVulkanDisplay *
|
||||
gst_vulkan_display_new (void)
|
||||
{
|
||||
GstVulkanDisplay *display = NULL;
|
||||
const gchar *user_choice, *platform_choice;
|
||||
|
||||
_init_debug ();
|
||||
|
||||
user_choice = g_getenv ("GST_GL_WINDOW");
|
||||
platform_choice = g_getenv ("GST_GL_PLATFORM");
|
||||
GST_INFO ("creating a display, user choice:%s (platform: %s)",
|
||||
GST_STR_NULL (user_choice), GST_STR_NULL (platform_choice));
|
||||
|
||||
#if GST_VULKAN_HAVE_WINDOW_XCB
|
||||
if (!display && (!user_choice || g_strstr_len (user_choice, 3, "xcb")))
|
||||
display = GST_VULKAN_DISPLAY (gst_vulkan_display_xcb_new (NULL));
|
||||
#endif
|
||||
#if GST_VULKAN_HAVE_WINDOW_X11
|
||||
if (!display && (!user_choice || g_strstr_len (user_choice, 3, "x11")))
|
||||
display = GST_VULKAN_DISPLAY (gst_vulkan_display_x11_new (NULL));
|
||||
#endif
|
||||
if (!display) {
|
||||
/* subclass returned a NULL window */
|
||||
GST_WARNING ("Could not create display. user specified %s "
|
||||
"(platform: %s), creating dummy",
|
||||
GST_STR_NULL (user_choice), GST_STR_NULL (platform_choice));
|
||||
|
||||
return g_object_new (GST_TYPE_VULKAN_DISPLAY, NULL);
|
||||
}
|
||||
|
||||
return display;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_vulkan_display_get_handle:
|
||||
* @display: a #GstVulkanDisplay
|
||||
*
|
||||
* Returns: the winsys specific handle of @display
|
||||
*
|
||||
* Since: 1.10
|
||||
*/
|
||||
gpointer
|
||||
gst_vulkan_display_get_handle (GstVulkanDisplay * display)
|
||||
{
|
||||
GstVulkanDisplayClass *klass;
|
||||
|
||||
g_return_val_if_fail (GST_IS_VULKAN_DISPLAY (display), NULL);
|
||||
klass = GST_VULKAN_DISPLAY_GET_CLASS (display);
|
||||
g_return_val_if_fail (klass->get_handle != NULL, NULL);
|
||||
|
||||
return klass->get_handle (display);
|
||||
}
|
||||
|
||||
static gpointer
|
||||
gst_vulkan_display_default_get_handle (GstVulkanDisplay * display)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_vulkan_display_get_platform_handle:
|
||||
* @display: a #GstVulkanDisplay
|
||||
*
|
||||
* Returns: the winsys specific handle of @display for use with the
|
||||
* VK_EXT_KHR_swapchain extension.
|
||||
*
|
||||
* Since: 1.10
|
||||
*/
|
||||
gpointer
|
||||
gst_vulkan_display_get_platform_handle (GstVulkanDisplay * display)
|
||||
{
|
||||
GstVulkanDisplayClass *klass;
|
||||
|
||||
g_return_val_if_fail (GST_IS_VULKAN_DISPLAY (display), NULL);
|
||||
klass = GST_VULKAN_DISPLAY_GET_CLASS (display);
|
||||
g_return_val_if_fail (klass->get_handle != NULL, NULL);
|
||||
|
||||
return klass->get_platform_handle (display);
|
||||
}
|
||||
|
||||
static gpointer
|
||||
gst_vulkan_display_default_get_platform_handle (GstVulkanDisplay * display)
|
||||
{
|
||||
return (gpointer) gst_vulkan_display_get_handle (display);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_vulkan_display_get_handle_type:
|
||||
* @display: a #GstVulkanDisplay
|
||||
*
|
||||
* Returns: the #GstVulkanDisplayType of @display
|
||||
*
|
||||
* Since: 1.10
|
||||
*/
|
||||
GstVulkanDisplayType
|
||||
gst_vulkan_display_get_handle_type (GstVulkanDisplay * display)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_VULKAN_DISPLAY (display),
|
||||
GST_VULKAN_DISPLAY_TYPE_NONE);
|
||||
|
||||
return display->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_vulkan_display_create_window:
|
||||
* @display: a #GstVulkanDisplay
|
||||
*
|
||||
* Returns: a new #GstVulkanWindow for @display or %NULL.
|
||||
*/
|
||||
GstVulkanWindow *
|
||||
gst_vulkan_display_create_window (GstVulkanDisplay * display)
|
||||
{
|
||||
GstVulkanDisplayClass *klass;
|
||||
GstVulkanWindow *window;
|
||||
|
||||
g_return_val_if_fail (GST_IS_VULKAN_DISPLAY (display), NULL);
|
||||
klass = GST_VULKAN_DISPLAY_GET_CLASS (display);
|
||||
g_return_val_if_fail (klass->create_window != NULL, NULL);
|
||||
|
||||
window = klass->create_window (display);
|
||||
|
||||
if (window) {
|
||||
GST_OBJECT_LOCK (display);
|
||||
display->windows = g_list_prepend (display->windows, window);
|
||||
GST_OBJECT_UNLOCK (display);
|
||||
}
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
static GstVulkanWindow *
|
||||
gst_vulkan_display_default_create_window (GstVulkanDisplay * display)
|
||||
{
|
||||
return gst_vulkan_window_new (display);
|
||||
}
|
91
ext/vulkan/vkdisplay.h
Normal file
91
ext/vulkan/vkdisplay.h
Normal file
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2007 David A. Schleef <ds@schleef.org>
|
||||
* Copyright (C) 2008 Julien Isorce <julien.isorce@gmail.com>
|
||||
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com>
|
||||
* Copyright (C) 2013 Matthew Waters <ystreet00@gmail.com>
|
||||
*
|
||||
* 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_VULKAN_DISPLAY_H__
|
||||
#define __GST_VULKAN_DISPLAY_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
#include <vk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_VULKAN_DISPLAY (gst_vulkan_display_get_type())
|
||||
#define GST_VULKAN_DISPLAY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VULKAN_DISPLAY,GstVulkanDisplay))
|
||||
#define GST_VULKAN_DISPLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_VULKAN_DISPLAY,GstVulkanDisplayClass))
|
||||
#define GST_IS_VULKAN_DISPLAY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VULKAN_DISPLAY))
|
||||
#define GST_IS_VULKAN_DISPLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_VULKAN_DISPLAY))
|
||||
#define GST_VULKAN_DISPLAY_CAST(obj) ((GstVulkanDisplay*)(obj))
|
||||
#define GST_VULKAN_DISPLAY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GST_TYPE_VULKAN_DISPLAY, GstVulkanDisplayClass))
|
||||
GType gst_vulkan_display_get_type (void);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GST_VULKAN_DISPLAY_TYPE_NONE = 0,
|
||||
GST_VULKAN_DISPLAY_TYPE_X11 = (1 << 0),
|
||||
GST_VULKAN_DISPLAY_TYPE_XCB = (1 << 1),
|
||||
GST_VULKAN_DISPLAY_TYPE_WAYLAND = (1 << 2),
|
||||
GST_VULKAN_DISPLAY_TYPE_MIR = (1 << 3),
|
||||
GST_VULKAN_DISPLAY_TYPE_WIN32 = (1 << 4),
|
||||
|
||||
GST_VULKAN_DISPLAY_TYPE_ANY = G_MAXUINT32
|
||||
} GstVulkanDisplayType;
|
||||
|
||||
/**
|
||||
* GstVulkanDisplay:
|
||||
*
|
||||
* The contents of a #GstVulkanDisplay are private and should only be accessed
|
||||
* through the provided API
|
||||
*/
|
||||
struct _GstVulkanDisplay
|
||||
{
|
||||
/* <private> */
|
||||
GstObject object;
|
||||
|
||||
GstVulkanDisplayType type;
|
||||
|
||||
/* <protected> */
|
||||
GList *windows; /* OBJECT lock */
|
||||
|
||||
GstVulkanDisplayPrivate *priv;
|
||||
};
|
||||
|
||||
struct _GstVulkanDisplayClass
|
||||
{
|
||||
GstObjectClass object_class;
|
||||
|
||||
gpointer (*get_handle) (GstVulkanDisplay * display);
|
||||
gpointer (*get_platform_handle) (GstVulkanDisplay * display); /* default chains up to @get_handle */
|
||||
GstVulkanWindow * (*create_window) (GstVulkanDisplay * display);
|
||||
};
|
||||
|
||||
GstVulkanDisplay *gst_vulkan_display_new (void);
|
||||
|
||||
gpointer gst_vulkan_display_get_handle (GstVulkanDisplay * display);
|
||||
GstVulkanDisplayType gst_vulkan_display_get_handle_type (GstVulkanDisplay * display);
|
||||
gpointer gst_vulkan_display_get_platform_handle (GstVulkanDisplay * display);
|
||||
GstVulkanWindow * gst_vulkan_display_create_window (GstVulkanDisplay * display);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_VULKAN_DISPLAY_H__ */
|
129
ext/vulkan/vkerror.c
Normal file
129
ext/vulkan/vkerror.c
Normal file
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
|
||||
*
|
||||
* 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 <glib/gprintf.h>
|
||||
|
||||
#include "vkerror.h"
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
static const struct
|
||||
{
|
||||
VkResult result;
|
||||
const char *str;
|
||||
} vk_result_string_map[] = {
|
||||
{VK_ERROR_OUT_OF_HOST_MEMORY, "Out Of Host Memory"},
|
||||
{VK_ERROR_OUT_OF_DEVICE_MEMORY, "Out of Device Memory"},
|
||||
{VK_ERROR_INITIALIZATION_FAILED, "Initialization Failed"},
|
||||
{VK_ERROR_DEVICE_LOST, "Device Lost"},
|
||||
{VK_ERROR_MEMORY_MAP_FAILED, "Map Failed"},
|
||||
{VK_ERROR_LAYER_NOT_PRESENT, "Layer Not Present"},
|
||||
{VK_ERROR_EXTENSION_NOT_PRESENT, "Extension Not Present"},
|
||||
{VK_ERROR_INCOMPATIBLE_DRIVER, "Incompatible Driver"},
|
||||
};
|
||||
|
||||
static const struct
|
||||
{
|
||||
VkResult result;
|
||||
GstVulkanError gst_enum;
|
||||
} vk_result_gst_error_map[] = {
|
||||
{VK_ERROR_OUT_OF_HOST_MEMORY, GST_VULKAN_ERROR_OUT_OF_HOST_MEMORY},
|
||||
{VK_ERROR_OUT_OF_DEVICE_MEMORY, VK_ERROR_OUT_OF_DEVICE_MEMORY},
|
||||
{VK_ERROR_INITIALIZATION_FAILED, GST_VULKAN_ERROR_INITIALIZATION_FAILED},
|
||||
{VK_ERROR_DEVICE_LOST, GST_VULKAN_ERROR_DEVICE_LOST},
|
||||
{VK_ERROR_MEMORY_MAP_FAILED, GST_VULKAN_ERROR_MEMORY_MAP_FAILED},
|
||||
{VK_ERROR_LAYER_NOT_PRESENT, GST_VULKAN_ERROR_LAYER_NOT_PRESENT},
|
||||
{VK_ERROR_EXTENSION_NOT_PRESENT, GST_VULKAN_ERROR_EXTENSION_NOT_PRESENT},
|
||||
{VK_ERROR_INCOMPATIBLE_DRIVER, GST_VULKAN_ERROR_INCOMPATIBLE_DRIVER},
|
||||
};
|
||||
/* *INDENT-ON* */
|
||||
|
||||
GQuark
|
||||
gst_vulkan_error_quark (void)
|
||||
{
|
||||
return g_quark_from_static_string ("gst-vulkan-error");
|
||||
}
|
||||
|
||||
static const char *
|
||||
_vk_result_to_string (VkResult result)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (result >= 0)
|
||||
return NULL;
|
||||
if (result < VK_RESULT_BEGIN_RANGE)
|
||||
return "Unknown Error";
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (vk_result_string_map); i++) {
|
||||
if (result == vk_result_string_map[i].result)
|
||||
return vk_result_string_map[i].str;
|
||||
}
|
||||
|
||||
return "Unknown Error";
|
||||
}
|
||||
|
||||
static GstVulkanError
|
||||
_vk_result_to_g_error_enum (VkResult result)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (result >= 0)
|
||||
return 0;
|
||||
if (result < VK_RESULT_BEGIN_RANGE)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (vk_result_gst_error_map); i++) {
|
||||
if (result == vk_result_gst_error_map[i].result)
|
||||
return vk_result_gst_error_map[i].gst_enum;
|
||||
}
|
||||
|
||||
return GST_VULKAN_ERROR_FAILED;
|
||||
}
|
||||
|
||||
VkResult
|
||||
gst_vulkan_error_to_g_error (VkResult result, GError ** error,
|
||||
const char *format, ...)
|
||||
{
|
||||
GstVulkanError gst_enum;
|
||||
const char *result_str;
|
||||
gchar *string;
|
||||
va_list args;
|
||||
|
||||
if (error == NULL)
|
||||
/* we don't have an error to set */
|
||||
return result;
|
||||
|
||||
result_str = _vk_result_to_string (result);
|
||||
if (result_str == NULL)
|
||||
return result;
|
||||
|
||||
gst_enum = _vk_result_to_g_error_enum (result);
|
||||
|
||||
va_start (args, format);
|
||||
g_vasprintf (&string, format, args);
|
||||
va_end (args);
|
||||
|
||||
g_set_error (error, GST_VULKAN_ERROR, gst_enum, "%s: %s", result_str, string);
|
||||
|
||||
return result;
|
||||
}
|
50
ext/vulkan/vkerror.h
Normal file
50
ext/vulkan/vkerror.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
|
||||
*
|
||||
* 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 _VK_ERROR_H_
|
||||
#define _VK_ERROR_H_
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_VULKAN_ERROR (gst_vulkan_error_quark ())
|
||||
GQuark gst_vulkan_error_quark (void);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GST_VULKAN_ERROR_FAILED = 0,
|
||||
GST_VULKAN_ERROR_OUT_OF_HOST_MEMORY = -1,
|
||||
GST_VULKAN_ERROR_OUT_OF_DEVICE_MEMORY = -2,
|
||||
GST_VULKAN_ERROR_INITIALIZATION_FAILED = -3,
|
||||
GST_VULKAN_ERROR_DEVICE_LOST = -4,
|
||||
GST_VULKAN_ERROR_MEMORY_MAP_FAILED = -5,
|
||||
GST_VULKAN_ERROR_LAYER_NOT_PRESENT = -6,
|
||||
GST_VULKAN_ERROR_EXTENSION_NOT_PRESENT = -7,
|
||||
GST_VULKAN_ERROR_INCOMPATIBLE_DRIVER = -8,
|
||||
} GstVulkanError;
|
||||
|
||||
/* only fills error iff error != NULL and result < 0 */
|
||||
VkResult gst_vulkan_error_to_g_error (VkResult result, GError ** error, const char * format, ...) G_GNUC_PRINTF (3, 4);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* _VK_INSTANCE_H_ */
|
578
ext/vulkan/vkimagememory.c
Normal file
578
ext/vulkan/vkimagememory.c
Normal file
|
@ -0,0 +1,578 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
|
||||
*
|
||||
* 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 "vkimagememory.h"
|
||||
|
||||
/**
|
||||
* SECTION:vkimagememory
|
||||
* @short_description: memory subclass for Vulkan image memory
|
||||
* @see_also: #GstMemory, #GstAllocator
|
||||
*
|
||||
* GstVulkanImageMemory is a #GstMemory subclass providing support for the
|
||||
* mapping of Vulkan device memory.
|
||||
*/
|
||||
|
||||
#define GST_CAT_DEFUALT GST_CAT_VULKAN_IMAGE_MEMORY
|
||||
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFUALT);
|
||||
|
||||
static GstAllocator *_vulkan_image_memory_allocator;
|
||||
|
||||
VkFormat
|
||||
gst_vulkan_format_from_video_format (GstVideoFormat v_format, guint plane)
|
||||
{
|
||||
guint n_plane_components;
|
||||
|
||||
switch (v_format) {
|
||||
case GST_VIDEO_FORMAT_RGBx:
|
||||
case GST_VIDEO_FORMAT_BGRx:
|
||||
case GST_VIDEO_FORMAT_xRGB:
|
||||
case GST_VIDEO_FORMAT_xBGR:
|
||||
case GST_VIDEO_FORMAT_RGBA:
|
||||
case GST_VIDEO_FORMAT_BGRA:
|
||||
case GST_VIDEO_FORMAT_ARGB:
|
||||
case GST_VIDEO_FORMAT_ABGR:
|
||||
case GST_VIDEO_FORMAT_AYUV:
|
||||
n_plane_components = 4;
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_RGB:
|
||||
case GST_VIDEO_FORMAT_BGR:
|
||||
n_plane_components = 3;
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_RGB16:
|
||||
case GST_VIDEO_FORMAT_BGR16:
|
||||
return GST_VIDEO_GL_TEXTURE_TYPE_RGB16;
|
||||
case GST_VIDEO_FORMAT_GRAY16_BE:
|
||||
case GST_VIDEO_FORMAT_GRAY16_LE:
|
||||
case GST_VIDEO_FORMAT_YUY2:
|
||||
case GST_VIDEO_FORMAT_UYVY:
|
||||
n_plane_components = 2;
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_NV12:
|
||||
case GST_VIDEO_FORMAT_NV21:
|
||||
n_plane_components = plane == 0 ? 1 : 2;
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_GRAY8:
|
||||
case GST_VIDEO_FORMAT_Y444:
|
||||
case GST_VIDEO_FORMAT_Y42B:
|
||||
case GST_VIDEO_FORMAT_Y41B:
|
||||
case GST_VIDEO_FORMAT_I420:
|
||||
case GST_VIDEO_FORMAT_YV12:
|
||||
n_plane_components = 1;
|
||||
break;
|
||||
default:
|
||||
n_plane_components = 4;
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
|
||||
switch (n_plane_components) {
|
||||
case 4:
|
||||
return VK_FORMAT_R8G8B8A8_UNORM;
|
||||
case 3:
|
||||
return VK_FORMAT_R8G8B8_UNORM;
|
||||
case 2:
|
||||
return VK_FORMAT_R8G8_UNORM;
|
||||
case 1:
|
||||
return VK_FORMAT_R8_UNORM;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
return VK_FORMAT_R8G8B8A8_UNORM;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_view_create_info (VkImage image, VkFormat format, VkImageViewCreateInfo * info)
|
||||
{
|
||||
info->sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
info->pNext = NULL;
|
||||
info->image = image;
|
||||
info->format = format;
|
||||
info->channels.r = VK_CHANNEL_SWIZZLE_R;
|
||||
info->channels.g = VK_CHANNEL_SWIZZLE_G;
|
||||
info->channels.b = VK_CHANNEL_SWIZZLE_B;
|
||||
info->channels.a = VK_CHANNEL_SWIZZLE_A;
|
||||
info->subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
info->subresourceRange.baseMipLevel = 0;
|
||||
info->subresourceRange.mipLevels = 1;
|
||||
info->subresourceRange.baseArrayLayer = 0;
|
||||
info->subresourceRange.arraySize = 1;
|
||||
info->viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
info->flags = 0;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_find_memory_type_index_with_type_properties (GstVulkanDevice * device,
|
||||
guint32 typeBits, VkFlags properties, guint32 * typeIndex)
|
||||
{
|
||||
guint32 i;
|
||||
|
||||
/* Search memtypes to find first index with those properties */
|
||||
for (i = 0; i < 32; i++) {
|
||||
if ((typeBits & 1) == 1) {
|
||||
/* Type is available, does it match user properties? */
|
||||
if ((device->memory_properties.memoryTypes[i].
|
||||
propertyFlags & properties) == properties) {
|
||||
*typeIndex = i;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
typeBits >>= 1;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_create_info_from_args (VkImageCreateInfo * info, VkFormat format, gsize width,
|
||||
gsize height, VkImageTiling tiling, VkImageUsageFlags usage)
|
||||
{
|
||||
/* FIXME: validate these */
|
||||
|
||||
info->sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
info->pNext = NULL;
|
||||
info->imageType = VK_IMAGE_TYPE_2D;
|
||||
info->format = format;
|
||||
info->extent.width = (gint32) width;
|
||||
info->extent.height = (gint32) height;
|
||||
info->extent.depth = 1;
|
||||
info->mipLevels = 1;
|
||||
info->arraySize = 1;
|
||||
info->samples = 1;
|
||||
info->tiling = tiling;
|
||||
info->usage = usage;
|
||||
info->sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
info->queueFamilyCount = 0;
|
||||
info->pQueueFamilyIndices = NULL;
|
||||
info->initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
_vk_image_mem_init (GstVulkanImageMemory * mem, GstAllocator * allocator,
|
||||
GstMemory * parent, GstVulkanDevice * device, GstAllocationParams * params,
|
||||
gsize size, gpointer user_data, GDestroyNotify notify)
|
||||
{
|
||||
gsize align = gst_memory_alignment, offset = 0, maxsize = size;
|
||||
GstMemoryFlags flags = 0;
|
||||
|
||||
if (params) {
|
||||
flags = params->flags;
|
||||
align |= params->align;
|
||||
offset = params->prefix;
|
||||
maxsize += params->prefix + params->padding + align;
|
||||
}
|
||||
|
||||
gst_memory_init (GST_MEMORY_CAST (mem), flags, allocator, parent, maxsize,
|
||||
align, offset, size);
|
||||
|
||||
mem->device = gst_object_ref (device);
|
||||
mem->image_layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
mem->wrapped = FALSE;
|
||||
mem->notify = notify;
|
||||
mem->user_data = user_data;
|
||||
|
||||
g_mutex_init (&mem->lock);
|
||||
|
||||
GST_CAT_DEBUG (GST_CAT_VULKAN_IMAGE_MEMORY, "new GL buffer memory:%p size:%"
|
||||
G_GSIZE_FORMAT, mem, maxsize);
|
||||
}
|
||||
|
||||
static GstVulkanImageMemory *
|
||||
_vk_image_mem_new_alloc (GstAllocator * allocator, GstMemory * parent,
|
||||
GstVulkanDevice * device, VkFormat format, gsize width, gsize height,
|
||||
VkImageTiling tiling, VkImageUsageFlags usage,
|
||||
VkMemoryPropertyFlags mem_prop_flags, gpointer user_data,
|
||||
GDestroyNotify notify)
|
||||
{
|
||||
GstVulkanImageMemory *mem = g_new0 (GstVulkanImageMemory, 1);
|
||||
GstAllocationParams params = { 0, };
|
||||
VkImageViewCreateInfo view_info;
|
||||
VkImageCreateInfo image_info;
|
||||
guint32 memory_type_index;
|
||||
VkPhysicalDevice gpu;
|
||||
GError *error = NULL;
|
||||
VkImage image;
|
||||
VkResult err;
|
||||
|
||||
gpu = gst_vulkan_device_get_physical_device (device);
|
||||
if (!_create_info_from_args (&image_info, format, width, height, tiling,
|
||||
usage)) {
|
||||
GST_CAT_ERROR (GST_CAT_VULKAN_IMAGE_MEMORY, "Incorrect image parameters");
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = vkCreateImage (device->device, &image_info, &image);
|
||||
if (gst_vulkan_error_to_g_error (err, &error, "vkCreateImage") < 0)
|
||||
goto vk_error;
|
||||
|
||||
err =
|
||||
vkGetImageMemoryRequirements (device->device, image, &mem->requirements);
|
||||
if (gst_vulkan_error_to_g_error (err, &error,
|
||||
"vkGetImageMemoryRequirements") < 0) {
|
||||
vkDestroyImage (device->device, image);
|
||||
goto vk_error;
|
||||
}
|
||||
|
||||
params.align = mem->requirements.alignment;
|
||||
_vk_image_mem_init (mem, allocator, parent, device, ¶ms,
|
||||
mem->requirements.size, user_data, notify);
|
||||
mem->create_info = image_info;
|
||||
mem->image = image;
|
||||
|
||||
err = vkGetPhysicalDeviceImageFormatProperties (gpu, format, VK_IMAGE_TYPE_2D,
|
||||
tiling, usage, 0, &mem->format_properties);
|
||||
if (gst_vulkan_error_to_g_error (err, &error,
|
||||
"vkGetPhysicalDeviceImageFormatProperties") < 0)
|
||||
goto vk_error;
|
||||
|
||||
if (!_find_memory_type_index_with_type_properties (device,
|
||||
mem->requirements.memoryTypeBits, mem_prop_flags,
|
||||
&memory_type_index)) {
|
||||
GST_CAT_ERROR (GST_CAT_VULKAN_IMAGE_MEMORY,
|
||||
"Could not find suitable memory type");
|
||||
goto error;
|
||||
}
|
||||
|
||||
mem->vk_mem = (GstVulkanMemory *)
|
||||
gst_vulkan_memory_alloc (device, memory_type_index, ¶ms,
|
||||
mem->requirements.size, mem_prop_flags);
|
||||
if (!mem->vk_mem) {
|
||||
GST_CAT_ERROR (GST_CAT_VULKAN_IMAGE_MEMORY,
|
||||
"Failed to allocate device memory");
|
||||
goto error;
|
||||
}
|
||||
|
||||
err =
|
||||
vkBindImageMemory (device->device, mem->image, mem->vk_mem->mem_ptr,
|
||||
0 /* offset */ );
|
||||
if (gst_vulkan_error_to_g_error (err, &error, "vkBindImageMemory") < 0)
|
||||
goto vk_error;
|
||||
|
||||
if (usage & (VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT |
|
||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)) {
|
||||
_view_create_info (mem->image, format, &view_info);
|
||||
err = vkCreateImageView (device->device, &view_info, &mem->view);
|
||||
if (gst_vulkan_error_to_g_error (err, &error, "vkCreateImageView") < 0)
|
||||
goto vk_error;
|
||||
}
|
||||
|
||||
return mem;
|
||||
|
||||
vk_error:
|
||||
{
|
||||
GST_CAT_ERROR (GST_CAT_VULKAN_IMAGE_MEMORY,
|
||||
"Failed to allocate image memory %s", error->message);
|
||||
g_clear_error (&error);
|
||||
goto error;
|
||||
}
|
||||
|
||||
error:
|
||||
{
|
||||
gst_memory_unref ((GstMemory *) mem);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static GstVulkanImageMemory *
|
||||
_vk_image_mem_new_wrapped (GstAllocator * allocator, GstMemory * parent,
|
||||
GstVulkanDevice * device, VkImage image, VkFormat format, gsize width,
|
||||
gsize height, VkImageTiling tiling, VkImageUsageFlags usage,
|
||||
gpointer user_data, GDestroyNotify notify)
|
||||
{
|
||||
GstVulkanImageMemory *mem = g_new0 (GstVulkanImageMemory, 1);
|
||||
GstAllocationParams params = { 0, };
|
||||
VkImageViewCreateInfo view_info;
|
||||
VkPhysicalDevice gpu;
|
||||
GError *error = NULL;
|
||||
VkResult err;
|
||||
|
||||
gpu = gst_vulkan_device_get_physical_device (device);
|
||||
mem->image = image;
|
||||
|
||||
err =
|
||||
vkGetImageMemoryRequirements (device->device, mem->image,
|
||||
&mem->requirements);
|
||||
if (gst_vulkan_error_to_g_error (err, &error,
|
||||
"vkGetImageMemoryRequirements") < 0) {
|
||||
vkDestroyImage (device->device, image);
|
||||
goto vk_error;
|
||||
}
|
||||
|
||||
params.flags = GST_MEMORY_FLAG_NOT_MAPPABLE | GST_MEMORY_FLAG_READONLY;
|
||||
_vk_image_mem_init (mem, allocator, parent, device, ¶ms,
|
||||
mem->requirements.size, user_data, notify);
|
||||
mem->wrapped = TRUE;
|
||||
|
||||
if (!_create_info_from_args (&mem->create_info, format, width, height, tiling,
|
||||
usage)) {
|
||||
GST_CAT_ERROR (GST_CAT_VULKAN_IMAGE_MEMORY, "Incorrect image parameters");
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = vkGetPhysicalDeviceImageFormatProperties (gpu, format, VK_IMAGE_TYPE_2D,
|
||||
tiling, usage, 0, &mem->format_properties);
|
||||
if (gst_vulkan_error_to_g_error (err, &error,
|
||||
"vkGetPhysicalDeviceImageFormatProperties") < 0)
|
||||
goto vk_error;
|
||||
|
||||
if (usage & (VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT |
|
||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)) {
|
||||
_view_create_info (mem->image, format, &view_info);
|
||||
err = vkCreateImageView (device->device, &view_info, &mem->view);
|
||||
if (gst_vulkan_error_to_g_error (err, &error, "vkCreateImageView") < 0)
|
||||
goto vk_error;
|
||||
}
|
||||
|
||||
return mem;
|
||||
|
||||
vk_error:
|
||||
{
|
||||
GST_CAT_ERROR (GST_CAT_VULKAN_IMAGE_MEMORY,
|
||||
"Failed to allocate image memory %s", error->message);
|
||||
g_clear_error (&error);
|
||||
goto error;
|
||||
}
|
||||
|
||||
error:
|
||||
{
|
||||
gst_memory_unref ((GstMemory *) mem);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static gpointer
|
||||
_vk_image_mem_map_full (GstVulkanImageMemory * mem, GstMapInfo * info,
|
||||
gsize size)
|
||||
{
|
||||
GstMapInfo *vk_map_info = g_new0 (GstMapInfo, 1);
|
||||
info->user_data[0] = vk_map_info;
|
||||
|
||||
/* FIXME: possible layout transformation needed */
|
||||
|
||||
if (!mem->vk_mem)
|
||||
return NULL;
|
||||
|
||||
if (!gst_memory_map ((GstMemory *) mem->vk_mem, vk_map_info, info->flags))
|
||||
return NULL;
|
||||
|
||||
return vk_map_info->data;
|
||||
}
|
||||
|
||||
static void
|
||||
_vk_image_mem_unmap_full (GstVulkanImageMemory * mem, GstMapInfo * info)
|
||||
{
|
||||
gst_memory_unmap ((GstMemory *) mem->vk_mem, info->user_data[0]);
|
||||
|
||||
g_free (info->user_data[0]);
|
||||
}
|
||||
|
||||
static GstMemory *
|
||||
_vk_image_mem_copy (GstVulkanImageMemory * src, gssize offset, gssize size)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static GstMemory *
|
||||
_vk_image_mem_share (GstVulkanImageMemory * mem, gssize offset, gssize size)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_vk_image_mem_is_span (GstVulkanImageMemory * mem1, GstVulkanImageMemory * mem2,
|
||||
gsize * offset)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static GstMemory *
|
||||
_vk_image_mem_alloc (GstAllocator * allocator, gsize size,
|
||||
GstAllocationParams * params)
|
||||
{
|
||||
g_critical ("Subclass should override GstAllocatorClass::alloc() function");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
_vk_image_mem_free (GstAllocator * allocator, GstMemory * memory)
|
||||
{
|
||||
GstVulkanImageMemory *mem = (GstVulkanImageMemory *) memory;
|
||||
|
||||
GST_CAT_TRACE (GST_CAT_VULKAN_IMAGE_MEMORY, "freeing image memory:%p "
|
||||
"id:%" G_GUINT64_FORMAT, mem, mem->image.handle);
|
||||
|
||||
if (mem->image.handle && !mem->wrapped)
|
||||
vkDestroyImage (mem->device->device, mem->image);
|
||||
|
||||
if (mem->view.handle)
|
||||
vkDestroyImageView (mem->device->device, mem->view);
|
||||
|
||||
if (mem->vk_mem)
|
||||
gst_memory_unref ((GstMemory *) mem->vk_mem);
|
||||
|
||||
if (mem->notify)
|
||||
mem->notify (mem->user_data);
|
||||
|
||||
gst_object_unref (mem->device);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_vulkan_image_memory_set_layout (GstVulkanImageMemory * vk_mem,
|
||||
VkImageLayout image_layout, VkImageMemoryBarrier * barrier)
|
||||
{
|
||||
/* validate vk_mem->usage with image_layout */
|
||||
|
||||
barrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
barrier->pNext = NULL;
|
||||
barrier->outputMask = 0;
|
||||
barrier->inputMask = 0;
|
||||
barrier->oldLayout = vk_mem->image_layout;
|
||||
barrier->newLayout = image_layout;
|
||||
barrier->image = vk_mem->image;
|
||||
barrier->subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR;
|
||||
barrier->subresourceRange.baseMipLevel = 0;
|
||||
barrier->subresourceRange.mipLevels = 1;
|
||||
barrier->subresourceRange.baseArrayLayer = 0;
|
||||
barrier->subresourceRange.arraySize = 0;
|
||||
|
||||
if (image_layout == VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL) {
|
||||
/* Make sure anything that was copying from this image has completed */
|
||||
barrier->inputMask = VK_MEMORY_INPUT_TRANSFER_BIT;
|
||||
}
|
||||
|
||||
if (image_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
|
||||
/* Make sure any Copy or CPU writes to image are flushed */
|
||||
barrier->outputMask =
|
||||
VK_MEMORY_OUTPUT_HOST_WRITE_BIT | VK_MEMORY_OUTPUT_TRANSFER_BIT;
|
||||
}
|
||||
|
||||
/* FIXME: what if the barrier is never submitted or is submitted out of order? */
|
||||
vk_mem->image_layout = image_layout;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_vulkan_image_memory_alloc:
|
||||
* @device:a #GstVulkanDevice
|
||||
* @memory_type_index: the Vulkan memory type index
|
||||
* @params: a #GstAllocationParams
|
||||
* @size: the size to allocate
|
||||
*
|
||||
* Allocated a new #GstVulkanImageMemory.
|
||||
*
|
||||
* Returns: a #GstMemory object backed by a vulkan device memory
|
||||
*/
|
||||
GstMemory *
|
||||
gst_vulkan_image_memory_alloc (GstVulkanDevice * device, VkFormat format,
|
||||
gsize width, gsize height, VkImageTiling tiling, VkImageUsageFlags usage,
|
||||
VkMemoryPropertyFlags mem_prop_flags)
|
||||
{
|
||||
GstVulkanImageMemory *mem;
|
||||
|
||||
mem = _vk_image_mem_new_alloc (_vulkan_image_memory_allocator, NULL, device,
|
||||
format, width, height, tiling, usage, mem_prop_flags, NULL, NULL);
|
||||
|
||||
return (GstMemory *) mem;
|
||||
}
|
||||
|
||||
GstMemory *
|
||||
gst_vulkan_image_memory_wrapped (GstVulkanDevice * device, VkImage image,
|
||||
VkFormat format, gsize width, gsize height, VkImageTiling tiling,
|
||||
VkImageUsageFlags usage, gpointer user_data, GDestroyNotify notify)
|
||||
{
|
||||
GstVulkanImageMemory *mem;
|
||||
|
||||
mem = _vk_image_mem_new_wrapped (_vulkan_image_memory_allocator, NULL, device,
|
||||
image, format, width, height, tiling, usage, user_data, notify);
|
||||
|
||||
return (GstMemory *) mem;
|
||||
}
|
||||
|
||||
G_DEFINE_TYPE (GstVulkanImageMemoryAllocator, gst_vulkan_image_memory_allocator,
|
||||
GST_TYPE_ALLOCATOR);
|
||||
|
||||
static void
|
||||
gst_vulkan_image_memory_allocator_class_init (GstVulkanImageMemoryAllocatorClass
|
||||
* klass)
|
||||
{
|
||||
GstAllocatorClass *allocator_class = (GstAllocatorClass *) klass;
|
||||
|
||||
allocator_class->alloc = _vk_image_mem_alloc;
|
||||
allocator_class->free = _vk_image_mem_free;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vulkan_image_memory_allocator_init (GstVulkanImageMemoryAllocator *
|
||||
allocator)
|
||||
{
|
||||
GstAllocator *alloc = GST_ALLOCATOR_CAST (allocator);
|
||||
|
||||
alloc->mem_type = GST_VULKAN_IMAGE_MEMORY_ALLOCATOR_NAME;
|
||||
alloc->mem_map_full = (GstMemoryMapFullFunction) _vk_image_mem_map_full;
|
||||
alloc->mem_unmap_full = (GstMemoryUnmapFullFunction) _vk_image_mem_unmap_full;
|
||||
alloc->mem_copy = (GstMemoryCopyFunction) _vk_image_mem_copy;
|
||||
alloc->mem_share = (GstMemoryShareFunction) _vk_image_mem_share;
|
||||
alloc->mem_is_span = (GstMemoryIsSpanFunction) _vk_image_mem_is_span;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_vulkan_image_memory_init_once:
|
||||
*
|
||||
* Initializes the Vulkan memory allocator. It is safe to call this function
|
||||
* multiple times. This must be called before any other #GstVulkanImageMemory operation.
|
||||
*/
|
||||
void
|
||||
gst_vulkan_image_memory_init_once (void)
|
||||
{
|
||||
static volatile gsize _init = 0;
|
||||
|
||||
if (g_once_init_enter (&_init)) {
|
||||
GST_DEBUG_CATEGORY_INIT (GST_CAT_VULKAN_IMAGE_MEMORY, "vulkanimagememory",
|
||||
0, "Vulkan Image Memory");
|
||||
|
||||
_vulkan_image_memory_allocator =
|
||||
g_object_new (gst_vulkan_image_memory_allocator_get_type (), NULL);
|
||||
|
||||
gst_allocator_register (GST_VULKAN_IMAGE_MEMORY_ALLOCATOR_NAME,
|
||||
gst_object_ref (_vulkan_image_memory_allocator));
|
||||
g_once_init_leave (&_init, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_is_vulkan_image_memory:
|
||||
* @mem:a #GstMemory
|
||||
*
|
||||
* Returns: whether the memory at @mem is a #GstVulkanImageMemory
|
||||
*/
|
||||
gboolean
|
||||
gst_is_vulkan_image_memory (GstMemory * mem)
|
||||
{
|
||||
return mem != NULL && mem->allocator != NULL &&
|
||||
g_type_is_a (G_OBJECT_TYPE (mem->allocator),
|
||||
GST_TYPE_VULKAN_IMAGE_MEMORY_ALLOCATOR);
|
||||
}
|
116
ext/vulkan/vkimagememory.h
Normal file
116
ext/vulkan/vkimagememory.h
Normal file
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
|
||||
*
|
||||
* 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 _VK_IMAGE_MEMORY_H_
|
||||
#define _VK_IMAGE_MEMORY_H_
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/gstallocator.h>
|
||||
#include <gst/gstmemory.h>
|
||||
|
||||
#include <gst/video/video.h>
|
||||
|
||||
#include <vk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_VULKAN_IMAGE_MEMORY_ALLOCATOR (gst_vulkan_image_memory_allocator_get_type())
|
||||
GType gst_vulkan_image_memory_allocator_get_type(void);
|
||||
|
||||
#define GST_IS_VULKAN_IMAGE_MEMORY_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VULKAN_IMAGE_MEMORY_ALLOCATOR))
|
||||
#define GST_IS_VULKAN_IMAGE_MEMORY_ALLOCATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VULKAN_IMAGE_MEMORY_ALLOCATOR))
|
||||
#define GST_VULKAN_IMAGE_MEMORY_ALLOCATOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VULKAN_MEMORY_ALLOCATOR, GstVulkanImageMemoryAllocatorClass))
|
||||
#define GST_VULKAN_IMAGE_MEMORY_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VULKAN_MEMORY_ALLOCATOR, GstVulkanImageMemoryAllocator))
|
||||
#define GST_VULKAN_IMAGE_MEMORY_ALLOCATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VULKAN_MEMORY_ALLOCATOR, GstVulkanImageMemoryAllocatorClass))
|
||||
#define GST_VULKAN_IMAGE_MEMORY_ALLOCATOR_CAST(obj) ((GstVulkanImageMemoryAllocator *)(obj))
|
||||
|
||||
#define GST_VULKAN_IMAGE_MEMORY_ALLOCATOR_NAME "VulkanImage"
|
||||
|
||||
struct _GstVulkanImageMemory
|
||||
{
|
||||
GstMemory parent;
|
||||
|
||||
GstVulkanDevice * device;
|
||||
|
||||
VkImage image;
|
||||
VkImageLayout image_layout;
|
||||
VkImageView view;
|
||||
GstVulkanMemory *vk_mem;
|
||||
|
||||
VkImageCreateInfo create_info;
|
||||
VkMemoryRequirements requirements;
|
||||
VkImageFormatProperties format_properties;
|
||||
|
||||
GMutex lock;
|
||||
gboolean wrapped;
|
||||
GDestroyNotify notify;
|
||||
gpointer user_data;
|
||||
};
|
||||
|
||||
/**
|
||||
* GstVulkanImageMemoryAllocator
|
||||
*
|
||||
* Opaque #GstVulkanImageMemoryAllocator struct
|
||||
*/
|
||||
struct _GstVulkanImageMemoryAllocator
|
||||
{
|
||||
GstAllocator parent;
|
||||
};
|
||||
|
||||
/**
|
||||
* GstVulkanImageMemoryAllocatorClass:
|
||||
*
|
||||
* The #GstVulkanImageMemoryAllocatorClass only contains private data
|
||||
*/
|
||||
struct _GstVulkanImageMemoryAllocatorClass
|
||||
{
|
||||
GstAllocatorClass parent_class;
|
||||
};
|
||||
|
||||
void gst_vulkan_image_memory_init_once (void);
|
||||
gboolean gst_is_vulkan_image_memory (GstMemory * mem);
|
||||
|
||||
GstMemory * gst_vulkan_image_memory_alloc (GstVulkanDevice * device,
|
||||
VkFormat format,
|
||||
gsize width,
|
||||
gsize height,
|
||||
VkImageTiling tiling,
|
||||
VkImageUsageFlags usage,
|
||||
VkMemoryPropertyFlags mem_prop_flags);
|
||||
|
||||
GstMemory * gst_vulkan_image_memory_wrapped (GstVulkanDevice * device,
|
||||
VkImage image,
|
||||
VkFormat format,
|
||||
gsize width,
|
||||
gsize height,
|
||||
VkImageTiling tiling,
|
||||
VkImageUsageFlags usage,
|
||||
gpointer user_data,
|
||||
GDestroyNotify notify);
|
||||
gboolean gst_vulkan_image_memory_set_layout (GstVulkanImageMemory * vk_mem,
|
||||
VkImageLayout,
|
||||
VkImageMemoryBarrier * barrier);
|
||||
|
||||
VkFormat gst_vulkan_format_from_video_format (GstVideoFormat v_format,
|
||||
guint plane);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* _VK_IMAGE_MEMORY_H_ */
|
315
ext/vulkan/vkinstance.c
Normal file
315
ext/vulkan/vkinstance.c
Normal file
|
@ -0,0 +1,315 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
|
||||
*
|
||||
* 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 "vkinstance.h"
|
||||
#include "vkutils.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define APP_SHORT_NAME "GStreamer"
|
||||
|
||||
static const char *instance_validation_layers[] = {
|
||||
/* FIXME: until the loader stops segfaulting/hanging we don't have any
|
||||
* validation layers for the instance */
|
||||
"Threading",
|
||||
"MemTracker",
|
||||
"ObjectTracker",
|
||||
"DrawState",
|
||||
"ParamChecker",
|
||||
"ShaderChecker",
|
||||
"Swapchain",
|
||||
"DeviceLimits",
|
||||
"Image",
|
||||
};
|
||||
|
||||
#define GST_CAT_DEFAULT gst_vulkan_instance_debug
|
||||
GST_DEBUG_CATEGORY (GST_CAT_DEFAULT);
|
||||
GST_DEBUG_CATEGORY (GST_VULKAN_DEBUG_CAT);
|
||||
|
||||
#define gst_vulkan_instance_parent_class parent_class
|
||||
G_DEFINE_TYPE_WITH_CODE (GstVulkanInstance, gst_vulkan_instance,
|
||||
GST_TYPE_OBJECT, GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT,
|
||||
"vulkaninstance", 0, "Vulkan Instance");
|
||||
GST_DEBUG_CATEGORY_INIT (GST_VULKAN_DEBUG_CAT,
|
||||
"vulkandebug", 0, "Vulkan Debug"));
|
||||
|
||||
static void gst_vulkan_instance_finalize (GObject * object);
|
||||
|
||||
GstVulkanInstance *
|
||||
gst_vulkan_instance_new (void)
|
||||
{
|
||||
return g_object_new (GST_TYPE_VULKAN_INSTANCE, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vulkan_instance_init (GstVulkanInstance * instance)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vulkan_instance_class_init (GstVulkanInstanceClass * instance_class)
|
||||
{
|
||||
gst_vulkan_memory_init_once ();
|
||||
gst_vulkan_image_memory_init_once ();
|
||||
|
||||
G_OBJECT_CLASS (instance_class)->finalize = gst_vulkan_instance_finalize;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vulkan_instance_finalize (GObject * object)
|
||||
{
|
||||
GstVulkanInstance *instance = GST_VULKAN_INSTANCE (object);
|
||||
|
||||
if (instance->instance)
|
||||
vkDestroyInstance (instance->instance);
|
||||
instance->instance = NULL;
|
||||
}
|
||||
|
||||
static VkBool32
|
||||
_gst_vk_debug_callback (VkFlags msgFlags, VkDbgObjectType objType,
|
||||
uint64_t srcObject, size_t location, int32_t msgCode,
|
||||
const char *pLayerPrefix, const char *pMsg, void *pUserData)
|
||||
{
|
||||
if (msgFlags & VK_DBG_REPORT_ERROR_BIT) {
|
||||
GST_CAT_ERROR (GST_VULKAN_DEBUG_CAT, "[%s] Code %d : %s", pLayerPrefix,
|
||||
msgCode, pMsg);
|
||||
} else if (msgFlags & VK_DBG_REPORT_WARN_BIT) {
|
||||
GST_CAT_WARNING (GST_VULKAN_DEBUG_CAT, "[%s] Code %d : %s", pLayerPrefix,
|
||||
msgCode, pMsg);
|
||||
} else if (msgFlags & VK_DBG_REPORT_INFO_BIT) {
|
||||
GST_CAT_LOG (GST_VULKAN_DEBUG_CAT, "[%s] Code %d : %s", pLayerPrefix,
|
||||
msgCode, pMsg);
|
||||
} else if (msgFlags & VK_DBG_REPORT_PERF_WARN_BIT) {
|
||||
GST_CAT_FIXME (GST_VULKAN_DEBUG_CAT, "[%s] Code %d : %s", pLayerPrefix,
|
||||
msgCode, pMsg);
|
||||
} else if (msgFlags & VK_DBG_REPORT_DEBUG_BIT) {
|
||||
GST_CAT_TRACE (GST_VULKAN_DEBUG_CAT, "[%s] Code %d : %s", pLayerPrefix,
|
||||
msgCode, pMsg);
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* false indicates that layer should not bail-out of an
|
||||
* API call that had validation failures. This may mean that the
|
||||
* app dies inside the driver due to invalid parameter(s).
|
||||
* That's what would happen without validation layers, so we'll
|
||||
* keep that behavior here.
|
||||
*/
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_vulkan_instance_open (GstVulkanInstance * instance, GError ** error)
|
||||
{
|
||||
VkExtensionProperties *instance_extensions;
|
||||
char *extension_names[64]; /* FIXME: make dynamic */
|
||||
VkLayerProperties *instance_layers;
|
||||
uint32_t instance_extension_count = 0;
|
||||
uint32_t enabled_extension_count = 0;
|
||||
uint32_t instance_layer_count = 0;
|
||||
uint32_t enabled_layer_count = 0;
|
||||
gboolean validation_found;
|
||||
gboolean have_swapchain_ext = FALSE;
|
||||
VkResult err;
|
||||
|
||||
/* Look for validation layers */
|
||||
err = vkEnumerateInstanceLayerProperties (&instance_layer_count, NULL);
|
||||
if (gst_vulkan_error_to_g_error (err, error,
|
||||
"vKEnumerateInstanceLayerProperties") < 0)
|
||||
return FALSE;
|
||||
|
||||
instance_layers = g_new0 (VkLayerProperties, instance_layer_count);
|
||||
err =
|
||||
vkEnumerateInstanceLayerProperties (&instance_layer_count,
|
||||
instance_layers);
|
||||
if (gst_vulkan_error_to_g_error (err, error,
|
||||
"vKEnumerateInstanceLayerProperties") < 0) {
|
||||
g_free (instance_layers);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* TODO: allow outside selection */
|
||||
validation_found =
|
||||
_check_for_all_layers (G_N_ELEMENTS (instance_validation_layers),
|
||||
instance_validation_layers, instance_layer_count, instance_layers);
|
||||
if (!validation_found) {
|
||||
g_error ("vkEnumerateInstanceLayerProperties failed to find"
|
||||
"required validation layer.\n\n"
|
||||
"Please look at the Getting Started guide for additional "
|
||||
"information.\nvkCreateInstance Failure");
|
||||
}
|
||||
enabled_layer_count = G_N_ELEMENTS (instance_validation_layers);
|
||||
|
||||
err =
|
||||
vkEnumerateInstanceExtensionProperties (NULL, &instance_extension_count,
|
||||
NULL);
|
||||
if (gst_vulkan_error_to_g_error (err, error,
|
||||
"vkEnumerateInstanceExtensionProperties") < 0) {
|
||||
g_free (instance_layers);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
memset (extension_names, 0, sizeof (extension_names));
|
||||
instance_extensions =
|
||||
g_new0 (VkExtensionProperties, instance_extension_count);
|
||||
err =
|
||||
vkEnumerateInstanceExtensionProperties (NULL, &instance_extension_count,
|
||||
instance_extensions);
|
||||
if (gst_vulkan_error_to_g_error (err, error,
|
||||
"vkEnumerateInstanceExtensionProperties") < 0) {
|
||||
g_free (instance_layers);
|
||||
g_free (instance_extensions);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* TODO: allow outside selection */
|
||||
for (uint32_t i = 0; i < instance_extension_count; i++) {
|
||||
if (!g_strcmp0 ("VK_EXT_KHR_swapchain", instance_extensions[i].extName)) {
|
||||
have_swapchain_ext = TRUE;
|
||||
extension_names[enabled_extension_count++] =
|
||||
(gchar *) "VK_EXT_KHR_swapchain";
|
||||
}
|
||||
if (!g_strcmp0 (VK_DEBUG_REPORT_EXTENSION_NAME,
|
||||
instance_extensions[i].extName)) {
|
||||
extension_names[enabled_extension_count++] =
|
||||
(gchar *) VK_DEBUG_REPORT_EXTENSION_NAME;
|
||||
}
|
||||
g_assert (enabled_extension_count < 64);
|
||||
}
|
||||
if (!have_swapchain_ext) {
|
||||
g_error ("vkEnumerateInstanceExtensionProperties failed to find the "
|
||||
"\"VK_EXT_KHR_swapchain\" extension.\n\nDo you have a compatible "
|
||||
"Vulkan installable client driver (ICD) installed?\nPlease "
|
||||
"look at the Getting Started guide for additional "
|
||||
"information.\nvkCreateInstance Failure");
|
||||
}
|
||||
|
||||
{
|
||||
const VkApplicationInfo app = {
|
||||
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
|
||||
.pNext = NULL,
|
||||
.pAppName = APP_SHORT_NAME,
|
||||
.appVersion = 0,
|
||||
.pEngineName = APP_SHORT_NAME,
|
||||
.engineVersion = 0,
|
||||
.apiVersion = VK_API_VERSION,
|
||||
};
|
||||
VkInstanceCreateInfo inst_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
|
||||
.pNext = NULL,
|
||||
.pAppInfo = &app,
|
||||
.pAllocCb = NULL,
|
||||
.layerCount = enabled_layer_count,
|
||||
.ppEnabledLayerNames = (const char *const *) instance_validation_layers,
|
||||
.extensionCount = enabled_extension_count,
|
||||
.ppEnabledExtensionNames = (const char *const *) extension_names,
|
||||
};
|
||||
|
||||
err = vkCreateInstance (&inst_info, &instance->instance);
|
||||
if (gst_vulkan_error_to_g_error (err, error, "vkCreateInstance") < 0) {
|
||||
g_free (instance_layers);
|
||||
g_free (instance_extensions);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
g_free (instance_layers);
|
||||
g_free (instance_extensions);
|
||||
|
||||
err =
|
||||
vkEnumeratePhysicalDevices (instance->instance,
|
||||
&instance->n_physical_devices, NULL);
|
||||
if (gst_vulkan_error_to_g_error (err, error,
|
||||
"vkEnumeratePhysicalDevices") < 0)
|
||||
return FALSE;
|
||||
g_assert (instance->n_physical_devices > 0);
|
||||
instance->physical_devices =
|
||||
g_new0 (VkPhysicalDevice, instance->n_physical_devices);
|
||||
err =
|
||||
vkEnumeratePhysicalDevices (instance->instance,
|
||||
&instance->n_physical_devices, instance->physical_devices);
|
||||
if (gst_vulkan_error_to_g_error (err, error,
|
||||
"vkEnumeratePhysicalDevices") < 0)
|
||||
return FALSE;
|
||||
|
||||
instance->dbgCreateMsgCallback = (PFN_vkDbgCreateMsgCallback)
|
||||
gst_vulkan_instance_get_proc_address (instance, "vkDbgCreateMsgCallback");
|
||||
if (!instance->dbgCreateMsgCallback) {
|
||||
g_set_error (error, GST_VULKAN_ERROR, GST_VULKAN_ERROR_FAILED,
|
||||
"Failed to retreive vkDbgCreateMsgCallback");
|
||||
return FALSE;
|
||||
}
|
||||
instance->dbgDestroyMsgCallback = (PFN_vkDbgDestroyMsgCallback)
|
||||
gst_vulkan_instance_get_proc_address (instance,
|
||||
"vkDbgDestroyMsgCallback");
|
||||
if (!instance->dbgDestroyMsgCallback) {
|
||||
g_set_error (error, GST_VULKAN_ERROR, GST_VULKAN_ERROR_FAILED,
|
||||
"Failed to retreive vkDbgDestroyMsgCallback");
|
||||
return FALSE;
|
||||
}
|
||||
instance->dbgBreakCallback =
|
||||
(PFN_vkDbgMsgCallback) gst_vulkan_instance_get_proc_address (instance,
|
||||
"vkDbgBreakCallback");
|
||||
if (!instance->dbgBreakCallback) {
|
||||
g_set_error (error, GST_VULKAN_ERROR, GST_VULKAN_ERROR_FAILED,
|
||||
"Failed to retreive vkDbgBreakCallback");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
err = instance->dbgCreateMsgCallback (instance->instance,
|
||||
VK_DBG_REPORT_ERROR_BIT | VK_DBG_REPORT_WARN_BIT | VK_DBG_REPORT_INFO_BIT
|
||||
| VK_DBG_REPORT_DEBUG_BIT | VK_DBG_REPORT_PERF_WARN_BIT,
|
||||
_gst_vk_debug_callback, NULL, &instance->msg_callback);
|
||||
if (gst_vulkan_error_to_g_error (err, error, "vkDbgCreateMsgCallback") < 0)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gpointer
|
||||
gst_vulkan_instance_get_proc_address (GstVulkanInstance * instance,
|
||||
const gchar * name)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_VULKAN_INSTANCE (instance), NULL);
|
||||
g_return_val_if_fail (instance->instance != NULL, NULL);
|
||||
g_return_val_if_fail (name != NULL, NULL);
|
||||
|
||||
GST_TRACE_OBJECT (instance, "%s", name);
|
||||
|
||||
return vkGetInstanceProcAddr (instance->instance, name);
|
||||
}
|
||||
|
||||
void
|
||||
gst_vulkan_instance_close (GstVulkanInstance * instance)
|
||||
{
|
||||
g_return_if_fail (GST_IS_VULKAN_INSTANCE (instance));
|
||||
g_return_if_fail (instance->instance != NULL);
|
||||
|
||||
if (instance->dbgDestroyMsgCallback)
|
||||
instance->dbgDestroyMsgCallback (instance->instance,
|
||||
instance->msg_callback);
|
||||
|
||||
g_free (instance->physical_devices);
|
||||
}
|
65
ext/vulkan/vkinstance.h
Normal file
65
ext/vulkan/vkinstance.h
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
|
||||
*
|
||||
* 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 _VK_INSTANCE_H_
|
||||
#define _VK_INSTANCE_H_
|
||||
|
||||
#include "vk.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_VULKAN_INSTANCE (gst_vulkan_instance_get_type())
|
||||
#define GST_VULKAN_INSTANCE(o) (G_TYPE_CHECK_INSTANCE_CAST((o), GST_TYPE_VULKAN_INSTANCE, GstVulkanInstance))
|
||||
#define GST_VULKAN_INSTANCE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GST_TYPE_VULKAN_INSTANCE, GstVulkanInstanceClass))
|
||||
#define GST_IS_VULKAN_INSTANCE(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), GST_TYPE_VULKAN_INSTANCE))
|
||||
#define GST_IS_VULKAN_INSTANCE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), GST_TYPE_VULKAN_INSTANCE))
|
||||
#define GST_VULKAN_INSTANCE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GST_TYPE_VULKAN_INSTANCE, GstVulkanInstanceClass))
|
||||
GType gst_vulkan_instance_get_type (void);
|
||||
|
||||
struct _GstVulkanInstance
|
||||
{
|
||||
GstObject parent;
|
||||
|
||||
VkInstance instance; /* hides a pointer */
|
||||
VkPhysicalDevice *physical_devices; /* hides a pointer */
|
||||
guint32 n_physical_devices;
|
||||
|
||||
VkDbgMsgCallback msg_callback;
|
||||
PFN_vkDbgCreateMsgCallback dbgCreateMsgCallback;
|
||||
PFN_vkDbgDestroyMsgCallback dbgDestroyMsgCallback;
|
||||
PFN_vkDbgMsgCallback dbgBreakCallback;
|
||||
};
|
||||
|
||||
struct _GstVulkanInstanceClass
|
||||
{
|
||||
GstObjectClass parent_class;
|
||||
};
|
||||
|
||||
GstVulkanInstance * gst_vulkan_instance_new (void);
|
||||
gboolean gst_vulkan_instance_open (GstVulkanInstance * instance,
|
||||
GError ** error);
|
||||
void gst_vulkan_instance_close (GstVulkanInstance * instance);
|
||||
|
||||
gpointer gst_vulkan_instance_get_proc_address (GstVulkanInstance * instance,
|
||||
const gchar * name);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* _VK_INSTANCE_H_ */
|
264
ext/vulkan/vkmemory.c
Normal file
264
ext/vulkan/vkmemory.c
Normal file
|
@ -0,0 +1,264 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
|
||||
*
|
||||
* 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 <string.h>
|
||||
|
||||
#include "vkmemory.h"
|
||||
|
||||
/**
|
||||
* SECTION:vkmemory
|
||||
* @short_description: memory subclass for Vulkan device memory
|
||||
* @see_also: #GstMemory, #GstAllocator
|
||||
*
|
||||
* GstVulkanMemory is a #GstMemory subclass providing support for the mapping of
|
||||
* Vulkan device memory.
|
||||
*/
|
||||
|
||||
#define GST_CAT_DEFUALT GST_CAT_VULKAN_MEMORY
|
||||
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFUALT);
|
||||
|
||||
static GstAllocator *_vulkan_memory_allocator;
|
||||
|
||||
static void
|
||||
_vk_mem_init (GstVulkanMemory * mem, GstAllocator * allocator,
|
||||
GstMemory * parent, GstVulkanDevice * device, guint32 memory_type_index,
|
||||
GstAllocationParams * params, gsize size,
|
||||
VkMemoryPropertyFlags mem_prop_flags, gpointer user_data,
|
||||
GDestroyNotify notify)
|
||||
{
|
||||
gsize align = gst_memory_alignment, offset = 0, maxsize = size;
|
||||
GstMemoryFlags flags = 0;
|
||||
|
||||
if (params) {
|
||||
flags = params->flags;
|
||||
align |= params->align;
|
||||
offset = params->prefix;
|
||||
maxsize += params->prefix + params->padding;
|
||||
if ((maxsize & align) != 0)
|
||||
maxsize += ~(maxsize & align) + 1;
|
||||
}
|
||||
|
||||
gst_memory_init (GST_MEMORY_CAST (mem), flags, allocator, parent, maxsize,
|
||||
align, offset, size);
|
||||
|
||||
mem->device = gst_object_ref (device);
|
||||
mem->alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO;
|
||||
mem->alloc_info.pNext = NULL;
|
||||
mem->alloc_info.allocationSize = (VkDeviceSize) mem->mem.maxsize;
|
||||
mem->alloc_info.memoryTypeIndex = memory_type_index;
|
||||
mem->properties = mem_prop_flags;
|
||||
mem->notify = notify;
|
||||
mem->user_data = user_data;
|
||||
|
||||
g_mutex_init (&mem->lock);
|
||||
|
||||
GST_CAT_DEBUG (GST_CAT_VULKAN_MEMORY, "new GL buffer memory:%p size:%"
|
||||
G_GSIZE_FORMAT, mem, maxsize);
|
||||
}
|
||||
|
||||
static GstVulkanMemory *
|
||||
_vk_mem_new (GstAllocator * allocator, GstMemory * parent,
|
||||
GstVulkanDevice * device, guint32 memory_type_index,
|
||||
GstAllocationParams * params, gsize size,
|
||||
VkMemoryPropertyFlags mem_props_flags, gpointer user_data,
|
||||
GDestroyNotify notify)
|
||||
{
|
||||
GstVulkanMemory *mem = g_slice_new0 (GstVulkanMemory);
|
||||
GError *error = NULL;
|
||||
VkResult err;
|
||||
|
||||
_vk_mem_init (mem, allocator, parent, device, memory_type_index, params,
|
||||
size, mem_props_flags, user_data, notify);
|
||||
|
||||
err = vkAllocMemory (device->device, &mem->alloc_info, &mem->mem_ptr);
|
||||
if (gst_vulkan_error_to_g_error (err, &error, "vkAllocMemory") < 0) {
|
||||
GST_CAT_ERROR (GST_CAT_VULKAN_MEMORY, "Failed to allocate device memory %s",
|
||||
error->message);
|
||||
gst_memory_unref ((GstMemory *) mem);
|
||||
g_clear_error (&error);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
static gpointer
|
||||
_vk_mem_map_full (GstVulkanMemory * mem, GstMapInfo * info, gsize size)
|
||||
{
|
||||
gpointer data;
|
||||
VkResult err;
|
||||
GError *error = NULL;
|
||||
|
||||
if ((mem->properties & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) {
|
||||
GST_CAT_ERROR (GST_CAT_VULKAN_MEMORY, "Cannot map host-invisible memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
err = vkMapMemory (mem->device->device, mem->mem_ptr, 0, size, 0, &data);
|
||||
if (gst_vulkan_error_to_g_error (err, &error, "vkMapMemory") < 0) {
|
||||
GST_CAT_ERROR (GST_CAT_VULKAN_MEMORY, "Failed to map device memory %s",
|
||||
error->message);
|
||||
g_clear_error (&error);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static void
|
||||
_vk_mem_unmap_full (GstVulkanMemory * mem, GstMapInfo * info)
|
||||
{
|
||||
vkUnmapMemory (mem->device->device, mem->mem_ptr);
|
||||
}
|
||||
|
||||
static GstMemory *
|
||||
_vk_mem_copy (GstVulkanMemory * src, gssize offset, gssize size)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static GstMemory *
|
||||
_vk_mem_share (GstVulkanMemory * mem, gssize offset, gssize size)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_vk_mem_is_span (GstVulkanMemory * mem1, GstVulkanMemory * mem2, gsize * offset)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static GstMemory *
|
||||
_vk_mem_alloc (GstAllocator * allocator, gsize size,
|
||||
GstAllocationParams * params)
|
||||
{
|
||||
g_critical ("Subclass should override GstAllocatorClass::alloc() function");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
_vk_mem_free (GstAllocator * allocator, GstMemory * memory)
|
||||
{
|
||||
GstVulkanMemory *mem = (GstVulkanMemory *) memory;
|
||||
|
||||
GST_CAT_TRACE (GST_CAT_VULKAN_MEMORY, "freeing buffer memory:%p "
|
||||
"id:%" G_GUINT64_FORMAT, mem, mem->mem_ptr.handle);
|
||||
|
||||
g_mutex_clear (&mem->lock);
|
||||
|
||||
if (mem->notify)
|
||||
mem->notify (mem->user_data);
|
||||
|
||||
vkFreeMemory (mem->device->device, mem->mem_ptr);
|
||||
|
||||
gst_object_unref (mem->device);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_vulkan_memory_alloc:
|
||||
* @device:a #GstVulkanDevice
|
||||
* @memory_type_index: the Vulkan memory type index
|
||||
* @params: a #GstAllocationParams
|
||||
* @size: the size to allocate
|
||||
*
|
||||
* Allocated a new #GstVulkanMemory.
|
||||
*
|
||||
* Returns: a #GstMemory object backed by a vulkan device memory
|
||||
*/
|
||||
GstMemory *
|
||||
gst_vulkan_memory_alloc (GstVulkanDevice * device, guint32 memory_type_index,
|
||||
GstAllocationParams * params, gsize size, VkMemoryPropertyFlags mem_flags)
|
||||
{
|
||||
GstVulkanMemory *mem;
|
||||
|
||||
mem = _vk_mem_new (_vulkan_memory_allocator, NULL, device, memory_type_index,
|
||||
params, size, mem_flags, NULL, NULL);
|
||||
|
||||
return (GstMemory *) mem;
|
||||
}
|
||||
|
||||
G_DEFINE_TYPE (GstVulkanMemoryAllocator, gst_vulkan_memory_allocator,
|
||||
GST_TYPE_ALLOCATOR);
|
||||
|
||||
static void
|
||||
gst_vulkan_memory_allocator_class_init (GstVulkanMemoryAllocatorClass * klass)
|
||||
{
|
||||
GstAllocatorClass *allocator_class = (GstAllocatorClass *) klass;
|
||||
|
||||
allocator_class->alloc = _vk_mem_alloc;
|
||||
allocator_class->free = _vk_mem_free;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vulkan_memory_allocator_init (GstVulkanMemoryAllocator * allocator)
|
||||
{
|
||||
GstAllocator *alloc = GST_ALLOCATOR_CAST (allocator);
|
||||
|
||||
alloc->mem_type = GST_VULKAN_MEMORY_ALLOCATOR_NAME;
|
||||
alloc->mem_map_full = (GstMemoryMapFullFunction) _vk_mem_map_full;
|
||||
alloc->mem_unmap_full = (GstMemoryUnmapFullFunction) _vk_mem_unmap_full;
|
||||
alloc->mem_copy = (GstMemoryCopyFunction) _vk_mem_copy;
|
||||
alloc->mem_share = (GstMemoryShareFunction) _vk_mem_share;
|
||||
alloc->mem_is_span = (GstMemoryIsSpanFunction) _vk_mem_is_span;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_vulkan_memory_init_once:
|
||||
*
|
||||
* Initializes the Vulkan memory allocator. It is safe to call this function
|
||||
* multiple times. This must be called before any other #GstVulkanMemory operation.
|
||||
*/
|
||||
void
|
||||
gst_vulkan_memory_init_once (void)
|
||||
{
|
||||
static volatile gsize _init = 0;
|
||||
|
||||
if (g_once_init_enter (&_init)) {
|
||||
GST_DEBUG_CATEGORY_INIT (GST_CAT_VULKAN_MEMORY, "vulkanmemory", 0,
|
||||
"Vulkan Memory");
|
||||
|
||||
_vulkan_memory_allocator =
|
||||
g_object_new (gst_vulkan_memory_allocator_get_type (), NULL);
|
||||
|
||||
gst_allocator_register (GST_VULKAN_MEMORY_ALLOCATOR_NAME,
|
||||
gst_object_ref (_vulkan_memory_allocator));
|
||||
g_once_init_leave (&_init, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_is_vulkan_memory:
|
||||
* @mem:a #GstMemory
|
||||
*
|
||||
* Returns: whether the memory at @mem is a #GstVulkanMemory
|
||||
*/
|
||||
gboolean
|
||||
gst_is_vulkan_memory (GstMemory * mem)
|
||||
{
|
||||
return mem != NULL && mem->allocator != NULL &&
|
||||
g_type_is_a (G_OBJECT_TYPE (mem->allocator),
|
||||
GST_TYPE_VULKAN_MEMORY_ALLOCATOR);
|
||||
}
|
94
ext/vulkan/vkmemory.h
Normal file
94
ext/vulkan/vkmemory.h
Normal file
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
|
||||
*
|
||||
* 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_VULKAN_BASE_BUFFER_H_
|
||||
#define _GST_VULKAN_BASE_BUFFER_H_
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/gstallocator.h>
|
||||
#include <gst/gstmemory.h>
|
||||
|
||||
#include <vk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_VULKAN_MEMORY_ALLOCATOR (gst_vulkan_memory_allocator_get_type())
|
||||
GType gst_vulkan_memory_allocator_get_type(void);
|
||||
|
||||
#define GST_IS_VULKAN_MEMORY_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VULKAN_MEMORY_ALLOCATOR))
|
||||
#define GST_IS_VULKAN_MEMORY_ALLOCATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VULKAN_MEMORY_ALLOCATOR))
|
||||
#define GST_VULKAN_MEMORY_ALLOCATOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VULKAN_MEMORY_ALLOCATOR, GstVulkanMemoryAllocatorClass))
|
||||
#define GST_VULKAN_MEMORY_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VULKAN_MEMORY_ALLOCATOR, GstVulkanMemoryAllocator))
|
||||
#define GST_VULKAN_MEMORY_ALLOCATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VULKAN_MEMORY_ALLOCATOR, GstVulkanMemoryAllocatorClass))
|
||||
#define GST_VULKAN_MEMORY_ALLOCATOR_CAST(obj) ((GstVulkanMemoryAllocator *)(obj))
|
||||
|
||||
#define GST_VULKAN_MEMORY_ALLOCATOR_NAME "Vulkan"
|
||||
|
||||
struct _GstVulkanMemory
|
||||
{
|
||||
GstMemory mem;
|
||||
|
||||
GstVulkanDevice *device;
|
||||
|
||||
VkDeviceMemory mem_ptr;
|
||||
|
||||
/* <protected> */
|
||||
GMutex lock;
|
||||
|
||||
/* <private> */
|
||||
GDestroyNotify notify;
|
||||
gpointer user_data;
|
||||
|
||||
VkMemoryAllocInfo alloc_info;
|
||||
VkMemoryPropertyFlags properties;
|
||||
};
|
||||
|
||||
/**
|
||||
* GstVulkanMemoryAllocator
|
||||
*
|
||||
* Opaque #GstVulkanMemoryAllocator struct
|
||||
*/
|
||||
struct _GstVulkanMemoryAllocator
|
||||
{
|
||||
GstAllocator parent;
|
||||
};
|
||||
|
||||
/**
|
||||
* GstVulkanMemoryAllocatorClass:
|
||||
*
|
||||
* The #GstVulkanMemoryAllocatorClass only contains private data
|
||||
*/
|
||||
struct _GstVulkanMemoryAllocatorClass
|
||||
{
|
||||
GstAllocatorClass parent_class;
|
||||
};
|
||||
|
||||
void gst_vulkan_memory_init_once (void);
|
||||
gboolean gst_is_vulkan_memory (GstMemory * mem);
|
||||
|
||||
GstMemory * gst_vulkan_memory_alloc (GstVulkanDevice * device,
|
||||
guint32 memory_type_index,
|
||||
GstAllocationParams * params,
|
||||
gsize size,
|
||||
VkMemoryPropertyFlags mem_prop_flags);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* _GST_VULKAN_BASE_BUFFER_H_ */
|
65
ext/vulkan/vkqueue.c
Normal file
65
ext/vulkan/vkqueue.c
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
|
||||
*
|
||||
* 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 "vkqueue.h"
|
||||
|
||||
#define GST_CAT_DEFAULT gst_vulkan_queue_debug
|
||||
GST_DEBUG_CATEGORY (GST_CAT_DEFAULT);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GstVulkanQueue, gst_vulkan_queue, GST_TYPE_OBJECT,
|
||||
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "vulkanqueue", 0,
|
||||
"Vulkan Queue"));
|
||||
|
||||
static void gst_vulkan_queue_dispose (GObject * object);
|
||||
|
||||
static void
|
||||
gst_vulkan_queue_init (GstVulkanQueue * device)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vulkan_queue_class_init (GstVulkanQueueClass * device_class)
|
||||
{
|
||||
GObjectClass *gobject_class = (GObjectClass *) device_class;
|
||||
|
||||
gobject_class->dispose = gst_vulkan_queue_dispose;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vulkan_queue_dispose (GObject * object)
|
||||
{
|
||||
GstVulkanQueue *queue = GST_VULKAN_QUEUE (object);
|
||||
|
||||
if (queue->device)
|
||||
gst_object_unref (queue->device);
|
||||
queue->device = NULL;
|
||||
}
|
||||
|
||||
GstVulkanDevice *
|
||||
gst_vulkan_queue_get_device (GstVulkanQueue * queue)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_VULKAN_QUEUE (queue), NULL);
|
||||
|
||||
return queue->device ? gst_object_ref (queue->device) : NULL;
|
||||
}
|
52
ext/vulkan/vkqueue.h
Normal file
52
ext/vulkan/vkqueue.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
|
||||
*
|
||||
* 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 _VK_QUEUE_H_
|
||||
#define _VK_QUEUE_H_
|
||||
|
||||
#include "vk.h"
|
||||
|
||||
#define GST_TYPE_VULKAN_QUEUE (gst_vulkan_queue_get_type())
|
||||
#define GST_VULKAN_QUEUE(o) (G_TYPE_CHECK_INSTANCE_CAST((o), GST_TYPE_VULKAN_QUEUE, GstVulkanQueue))
|
||||
#define GST_VULKAN_QUEUE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GST_TYPE_VULKAN_QUEUE, GstVulkanQueueClass))
|
||||
#define GST_IS_VULKAN_QUEUE(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), GST_TYPE_VULKAN_QUEUE))
|
||||
#define GST_IS_VULKAN_QUEUE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), GST_TYPE_VULKAN_QUEUE))
|
||||
#define GST_VULKAN_QUEUE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GST_TYPE_VULKAN_QUEUE, GstVulkanQueueClass))
|
||||
GType gst_vulkan_queue_get_type (void);
|
||||
|
||||
struct _GstVulkanQueue
|
||||
{
|
||||
GstObject parent;
|
||||
|
||||
GstVulkanDevice *device;
|
||||
|
||||
VkQueue queue; /* hides a pointer */
|
||||
guint32 family;
|
||||
guint32 index;
|
||||
};
|
||||
|
||||
struct _GstVulkanQueueClass
|
||||
{
|
||||
GstObjectClass parent_class;
|
||||
};
|
||||
|
||||
GstVulkanDevice * gst_vulkan_queue_get_device (GstVulkanQueue * queue);
|
||||
|
||||
#endif /* _VK_QUEUE_H_ */
|
491
ext/vulkan/vksink.c
Normal file
491
ext/vulkan/vksink.c
Normal file
|
@ -0,0 +1,491 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:element-vulkansink
|
||||
*
|
||||
* vulkansink renders video frames to a drawable on a local or remote
|
||||
* display using Vulkan.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
//#include <gst/video/videooverlay.h>
|
||||
|
||||
#include "vksink.h"
|
||||
#include "vkdevice.h"
|
||||
|
||||
GST_DEBUG_CATEGORY (gst_debug_vulkan_sink);
|
||||
#define GST_CAT_DEFAULT gst_debug_vulkan_sink
|
||||
|
||||
#define DEFAULT_FORCE_ASPECT_RATIO TRUE
|
||||
#define DEFAULT_PIXEL_ASPECT_RATIO_N 0
|
||||
#define DEFAULT_PIXEL_ASPECT_RATIO_D 1
|
||||
|
||||
static void gst_vulkan_sink_finalize (GObject * object);
|
||||
static void gst_vulkan_sink_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * param_spec);
|
||||
static void gst_vulkan_sink_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * param_spec);
|
||||
|
||||
static gboolean gst_vulkan_sink_query (GstBaseSink * bsink, GstQuery * query);
|
||||
static void gst_vulkan_sink_set_context (GstElement * element,
|
||||
GstContext * context);
|
||||
|
||||
static GstStateChangeReturn
|
||||
gst_vulkan_sink_change_state (GstElement * element, GstStateChange transition);
|
||||
|
||||
static void gst_vulkan_sink_get_times (GstBaseSink * bsink, GstBuffer * buf,
|
||||
GstClockTime * start, GstClockTime * end);
|
||||
static gboolean gst_vulkan_sink_set_caps (GstBaseSink * bsink, GstCaps * caps);
|
||||
static GstCaps *gst_vulkan_sink_get_caps (GstBaseSink * bsink,
|
||||
GstCaps * filter);
|
||||
static GstFlowReturn gst_vulkan_sink_prepare (GstBaseSink * bsink,
|
||||
GstBuffer * buf);
|
||||
static GstFlowReturn gst_vulkan_sink_show_frame (GstVideoSink * bsink,
|
||||
GstBuffer * buf);
|
||||
|
||||
static GstStaticPadTemplate gst_vulkan_sink_template =
|
||||
GST_STATIC_PAD_TEMPLATE ("sink",
|
||||
GST_PAD_SINK,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("RGBA")));
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_FORCE_ASPECT_RATIO,
|
||||
PROP_PIXEL_ASPECT_RATIO,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
SIGNAL_0,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
/* static guint gst_vulkan_sink_signals[LAST_SIGNAL] = { 0 }; */
|
||||
|
||||
#define gst_vulkan_sink_parent_class parent_class
|
||||
G_DEFINE_TYPE_WITH_CODE (GstVulkanSink, gst_vulkan_sink,
|
||||
GST_TYPE_VIDEO_SINK, GST_DEBUG_CATEGORY_INIT (gst_debug_vulkan_sink,
|
||||
"vulkansink", 0, "Vulkan Video Sink"));
|
||||
|
||||
static void
|
||||
gst_vulkan_sink_class_init (GstVulkanSinkClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
GstElementClass *gstelement_class;
|
||||
GstBaseSinkClass *gstbasesink_class;
|
||||
GstVideoSinkClass *gstvideosink_class;
|
||||
GstElementClass *element_class;
|
||||
|
||||
gobject_class = (GObjectClass *) klass;
|
||||
gstelement_class = (GstElementClass *) klass;
|
||||
gstbasesink_class = (GstBaseSinkClass *) klass;
|
||||
gstvideosink_class = (GstVideoSinkClass *) klass;
|
||||
element_class = GST_ELEMENT_CLASS (klass);
|
||||
|
||||
gobject_class->set_property = gst_vulkan_sink_set_property;
|
||||
gobject_class->get_property = gst_vulkan_sink_get_property;
|
||||
|
||||
g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO,
|
||||
g_param_spec_boolean ("force-aspect-ratio", "Force aspect ratio",
|
||||
"When enabled, scaling will respect original aspect ratio",
|
||||
DEFAULT_FORCE_ASPECT_RATIO,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (gobject_class, PROP_PIXEL_ASPECT_RATIO,
|
||||
gst_param_spec_fraction ("pixel-aspect-ratio", "Pixel Aspect Ratio",
|
||||
"The pixel aspect ratio of the device", 0, 1, G_MAXINT, 1, 1, 1,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
gst_element_class_set_metadata (element_class, "Vulkan video sink",
|
||||
"Sink/Video", "A videosink based on OpenGL",
|
||||
"Matthew Waters <matthew@centricular.com>");
|
||||
|
||||
gst_element_class_add_pad_template (element_class,
|
||||
gst_static_pad_template_get (&gst_vulkan_sink_template));
|
||||
|
||||
gobject_class->finalize = gst_vulkan_sink_finalize;
|
||||
|
||||
gstelement_class->change_state = gst_vulkan_sink_change_state;
|
||||
gstelement_class->set_context = gst_vulkan_sink_set_context;
|
||||
gstbasesink_class->query = GST_DEBUG_FUNCPTR (gst_vulkan_sink_query);
|
||||
gstbasesink_class->set_caps = gst_vulkan_sink_set_caps;
|
||||
gstbasesink_class->get_caps = gst_vulkan_sink_get_caps;
|
||||
gstbasesink_class->get_times = gst_vulkan_sink_get_times;
|
||||
gstbasesink_class->prepare = gst_vulkan_sink_prepare;
|
||||
|
||||
gstvideosink_class->show_frame =
|
||||
GST_DEBUG_FUNCPTR (gst_vulkan_sink_show_frame);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vulkan_sink_init (GstVulkanSink * vk_sink)
|
||||
{
|
||||
vk_sink->force_aspect_ratio = DEFAULT_FORCE_ASPECT_RATIO;
|
||||
vk_sink->par_n = DEFAULT_PIXEL_ASPECT_RATIO_N;
|
||||
vk_sink->par_d = DEFAULT_PIXEL_ASPECT_RATIO_D;
|
||||
|
||||
// g_mutex_init (&vk_sink->drawing_lock);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vulkan_sink_finalize (GObject * object)
|
||||
{
|
||||
// GstVulkanSink *vk_sink = GST_VULKAN_SINK (object);
|
||||
// g_mutex_clear (&vk_sink->drawing_lock);
|
||||
|
||||
// GST_DEBUG ("finalized");
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vulkan_sink_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstVulkanSink *vk_sink = GST_VULKAN_SINK (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_FORCE_ASPECT_RATIO:
|
||||
vk_sink->force_aspect_ratio = g_value_get_boolean (value);
|
||||
break;
|
||||
case PROP_PIXEL_ASPECT_RATIO:
|
||||
vk_sink->par_n = gst_value_get_fraction_numerator (value);
|
||||
vk_sink->par_d = gst_value_get_fraction_denominator (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vulkan_sink_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstVulkanSink *vk_sink = GST_VULKAN_SINK (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_FORCE_ASPECT_RATIO:
|
||||
g_value_set_boolean (value, vk_sink->force_aspect_ratio);
|
||||
break;
|
||||
case PROP_PIXEL_ASPECT_RATIO:
|
||||
gst_value_set_fraction (value, vk_sink->par_n, vk_sink->par_d);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_vulkan_sink_query (GstBaseSink * bsink, GstQuery * query)
|
||||
{
|
||||
// GstVulkanSink *vk_sink = GST_VULKAN_SINK (bsink);
|
||||
gboolean res = FALSE;
|
||||
|
||||
switch (GST_QUERY_TYPE (query)) {
|
||||
default:
|
||||
res = GST_BASE_SINK_CLASS (parent_class)->query (bsink, query);
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vulkan_sink_set_context (GstElement * element, GstContext * context)
|
||||
{
|
||||
// GstVulkanSink *vk_sink = GST_VULKAN_SINK (element);
|
||||
|
||||
GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
|
||||
}
|
||||
|
||||
static GstStateChangeReturn
|
||||
gst_vulkan_sink_change_state (GstElement * element, GstStateChange transition)
|
||||
{
|
||||
GstVulkanSink *vk_sink = GST_VULKAN_SINK (element);
|
||||
GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
|
||||
GError *error = NULL;
|
||||
|
||||
GST_DEBUG ("changing state: %s => %s",
|
||||
gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
|
||||
gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
|
||||
|
||||
switch (transition) {
|
||||
case GST_STATE_CHANGE_NULL_TO_READY:
|
||||
vk_sink->instance = gst_vulkan_instance_new ();
|
||||
if (!gst_vulkan_instance_open (vk_sink->instance, &error)) {
|
||||
GST_ELEMENT_ERROR (vk_sink, RESOURCE, NOT_FOUND,
|
||||
("Failed to create vulkan instance"), ("%s", error->message));
|
||||
return GST_STATE_CHANGE_FAILURE;
|
||||
}
|
||||
vk_sink->device = gst_vulkan_device_new (vk_sink->instance);
|
||||
if (!gst_vulkan_device_open (vk_sink->device, &error)) {
|
||||
GST_ELEMENT_ERROR (vk_sink, RESOURCE, NOT_FOUND,
|
||||
("Failed to create vulkan device"), ("%s", error->message));
|
||||
return GST_STATE_CHANGE_FAILURE;
|
||||
}
|
||||
|
||||
if (!(vk_sink->display = gst_vulkan_display_new ())) {
|
||||
GST_ELEMENT_ERROR (vk_sink, RESOURCE, NOT_FOUND,
|
||||
("Failed to connect to the window sysytem"), (NULL));
|
||||
return GST_STATE_CHANGE_FAILURE;
|
||||
}
|
||||
|
||||
if (!(vk_sink->window =
|
||||
gst_vulkan_display_create_window (vk_sink->display))) {
|
||||
GST_ELEMENT_ERROR (vk_sink, RESOURCE, NOT_FOUND,
|
||||
("Failed to create a window"), (NULL));
|
||||
return GST_STATE_CHANGE_FAILURE;
|
||||
}
|
||||
|
||||
if (!gst_vulkan_window_open (vk_sink->window, &error)) {
|
||||
GST_ELEMENT_ERROR (vk_sink, RESOURCE, NOT_FOUND,
|
||||
("Failed to open window"), ("%s", error->message));
|
||||
return GST_STATE_CHANGE_FAILURE;
|
||||
}
|
||||
|
||||
if (!(vk_sink->swapper =
|
||||
gst_vulkan_swapper_new (vk_sink->device, vk_sink->window))) {
|
||||
GST_ELEMENT_ERROR (vk_sink, RESOURCE, NOT_FOUND,
|
||||
("Failed to create a swapper"), (NULL));
|
||||
return GST_STATE_CHANGE_FAILURE;
|
||||
}
|
||||
break;
|
||||
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
||||
break;
|
||||
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
||||
if (ret == GST_STATE_CHANGE_FAILURE)
|
||||
return ret;
|
||||
|
||||
switch (transition) {
|
||||
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
|
||||
break;
|
||||
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
||||
break;
|
||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
||||
gst_object_unref (vk_sink->swapper);
|
||||
vk_sink->swapper = NULL;
|
||||
gst_object_unref (vk_sink->display);
|
||||
vk_sink->display = NULL;
|
||||
gst_vulkan_window_close (vk_sink->window);
|
||||
gst_object_unref (vk_sink->window);
|
||||
vk_sink->window = NULL;
|
||||
gst_vulkan_device_close (vk_sink->device);
|
||||
gst_object_unref (vk_sink->device);
|
||||
vk_sink->device = NULL;
|
||||
gst_vulkan_instance_close (vk_sink->instance);
|
||||
gst_object_unref (vk_sink->instance);
|
||||
vk_sink->instance = NULL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vulkan_sink_get_times (GstBaseSink * bsink, GstBuffer * buf,
|
||||
GstClockTime * start, GstClockTime * end)
|
||||
{
|
||||
GstVulkanSink *vk_sink = GST_VULKAN_SINK (bsink);
|
||||
|
||||
if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
|
||||
*start = GST_BUFFER_TIMESTAMP (buf);
|
||||
if (GST_BUFFER_DURATION_IS_VALID (buf))
|
||||
*end = *start + GST_BUFFER_DURATION (buf);
|
||||
else {
|
||||
if (GST_VIDEO_INFO_FPS_N (&vk_sink->v_info) > 0) {
|
||||
*end = *start +
|
||||
gst_util_uint64_scale_int (GST_SECOND,
|
||||
GST_VIDEO_INFO_FPS_D (&vk_sink->v_info),
|
||||
GST_VIDEO_INFO_FPS_N (&vk_sink->v_info));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static GstCaps *
|
||||
gst_vulkan_sink_get_caps (GstBaseSink * bsink, GstCaps * filter)
|
||||
{
|
||||
GstVulkanSink *vk_sink = GST_VULKAN_SINK (bsink);
|
||||
GstCaps *tmp = NULL;
|
||||
GstCaps *result = NULL;
|
||||
GError *error = NULL;
|
||||
|
||||
if (vk_sink->swapper) {
|
||||
if (!(result =
|
||||
gst_vulkan_swapper_get_supported_caps (vk_sink->swapper, &error))) {
|
||||
GST_ELEMENT_ERROR (bsink, RESOURCE, NOT_FOUND, ("%s", error->message),
|
||||
(NULL));
|
||||
g_clear_error (&error);
|
||||
return NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
tmp = gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD (bsink));
|
||||
|
||||
if (filter) {
|
||||
GST_DEBUG_OBJECT (bsink, "intersecting with filter caps %" GST_PTR_FORMAT,
|
||||
filter);
|
||||
|
||||
result = gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST);
|
||||
gst_caps_unref (tmp);
|
||||
} else {
|
||||
result = tmp;
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (bsink, "returning caps: %" GST_PTR_FORMAT, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_configure_display_from_info (GstVulkanSink * vk_sink, GstVideoInfo * vinfo)
|
||||
{
|
||||
guint display_ratio_num, display_ratio_den;
|
||||
gint display_par_n, display_par_d;
|
||||
gint par_n, par_d;
|
||||
gint width, height;
|
||||
gboolean ok;
|
||||
|
||||
width = GST_VIDEO_INFO_WIDTH (vinfo);
|
||||
height = GST_VIDEO_INFO_HEIGHT (vinfo);
|
||||
|
||||
par_n = GST_VIDEO_INFO_PAR_N (vinfo);
|
||||
par_d = GST_VIDEO_INFO_PAR_D (vinfo);
|
||||
|
||||
if (!par_n)
|
||||
par_n = 1;
|
||||
|
||||
/* get display's PAR */
|
||||
if (vk_sink->par_n != 0 && vk_sink->par_d != 0) {
|
||||
display_par_n = vk_sink->par_n;
|
||||
display_par_d = vk_sink->par_d;
|
||||
} else {
|
||||
display_par_n = 1;
|
||||
display_par_d = 1;
|
||||
}
|
||||
|
||||
ok = gst_video_calculate_display_ratio (&display_ratio_num,
|
||||
&display_ratio_den, width, height, par_n, par_d, display_par_n,
|
||||
display_par_d);
|
||||
|
||||
if (!ok)
|
||||
return FALSE;
|
||||
|
||||
GST_TRACE ("PAR: %u/%u DAR:%u/%u", par_n, par_d, display_par_n,
|
||||
display_par_d);
|
||||
|
||||
if (height % display_ratio_den == 0) {
|
||||
GST_DEBUG ("keeping video height");
|
||||
GST_VIDEO_SINK_WIDTH (vk_sink) = (guint)
|
||||
gst_util_uint64_scale_int (height, display_ratio_num,
|
||||
display_ratio_den);
|
||||
GST_VIDEO_SINK_HEIGHT (vk_sink) = height;
|
||||
} else if (width % display_ratio_num == 0) {
|
||||
GST_DEBUG ("keeping video width");
|
||||
GST_VIDEO_SINK_WIDTH (vk_sink) = width;
|
||||
GST_VIDEO_SINK_HEIGHT (vk_sink) = (guint)
|
||||
gst_util_uint64_scale_int (width, display_ratio_den, display_ratio_num);
|
||||
} else {
|
||||
GST_DEBUG ("approximating while keeping video height");
|
||||
GST_VIDEO_SINK_WIDTH (vk_sink) = (guint)
|
||||
gst_util_uint64_scale_int (height, display_ratio_num,
|
||||
display_ratio_den);
|
||||
GST_VIDEO_SINK_HEIGHT (vk_sink) = height;
|
||||
}
|
||||
GST_DEBUG ("scaling to %dx%d", GST_VIDEO_SINK_WIDTH (vk_sink),
|
||||
GST_VIDEO_SINK_HEIGHT (vk_sink));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_vulkan_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
|
||||
{
|
||||
GstVulkanSink *vk_sink = GST_VULKAN_SINK (bsink);
|
||||
GError *error = NULL;
|
||||
GstVideoInfo v_info;
|
||||
|
||||
GST_DEBUG_OBJECT (bsink, "set caps with %" GST_PTR_FORMAT, caps);
|
||||
|
||||
if (!gst_video_info_from_caps (&v_info, caps))
|
||||
return FALSE;
|
||||
|
||||
if (!_configure_display_from_info (vk_sink, &v_info))
|
||||
return FALSE;
|
||||
|
||||
if (!gst_vulkan_swapper_set_caps (vk_sink->swapper, caps, &error)) {
|
||||
GST_ELEMENT_ERROR (vk_sink, RESOURCE, NOT_FOUND,
|
||||
("Failed to configure caps"), ("%s", error->message));
|
||||
g_clear_error (&error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
vk_sink->v_info = v_info;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_vulkan_sink_prepare (GstBaseSink * bsink, GstBuffer * buf)
|
||||
{
|
||||
GstVulkanSink *vk_sink = GST_VULKAN_SINK (bsink);
|
||||
|
||||
GST_TRACE_OBJECT (vk_sink, "preparing buffer %" GST_PTR_FORMAT, buf);
|
||||
|
||||
if (GST_VIDEO_SINK_WIDTH (vk_sink) < 1 || GST_VIDEO_SINK_HEIGHT (vk_sink) < 1) {
|
||||
return GST_FLOW_NOT_NEGOTIATED;
|
||||
}
|
||||
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_vulkan_sink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
|
||||
{
|
||||
GstVulkanSink *vk_sink = GST_VULKAN_SINK (vsink);
|
||||
GError *error = NULL;
|
||||
|
||||
GST_TRACE_OBJECT (vk_sink, "rendering buffer %" GST_PTR_FORMAT, buf);
|
||||
|
||||
if (!gst_vulkan_swapper_render_buffer (vk_sink->swapper, buf, &error)) {
|
||||
GST_ELEMENT_ERROR (vk_sink, RESOURCE, NOT_FOUND,
|
||||
("Failed to render buffer"), ("%s", error->message));
|
||||
g_clear_error (&error);
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
|
||||
return GST_FLOW_OK;
|
||||
}
|
73
ext/vulkan/vksink.h
Normal file
73
ext/vulkan/vksink.h
Normal file
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
|
||||
*
|
||||
* 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 _VK_SINK_H_
|
||||
#define _VK_SINK_H_
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/video/gstvideosink.h>
|
||||
#include <gst/video/video.h>
|
||||
#include "vk.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_VULKAN_SINK (gst_vulkan_sink_get_type())
|
||||
#define GST_VULKAN_SINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VULKAN_SINK,GstVulkanSink))
|
||||
#define GST_VULKAN_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VULKAN_SINK,GstVulkanSinkClass))
|
||||
#define GST_IS_VULKAN_SINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VULKAN_SINK))
|
||||
#define GST_IS_VULKAN_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VULKAN_SINK))
|
||||
|
||||
typedef struct _GstVulkanSink GstVulkanSink;
|
||||
typedef struct _GstVulkanSinkClass GstVulkanSinkClass;
|
||||
|
||||
struct _GstVulkanSink
|
||||
{
|
||||
GstVideoSink video_sink;
|
||||
|
||||
GstVulkanInstance *instance;
|
||||
GstVulkanDevice *device;
|
||||
|
||||
GstVulkanDisplay *display;
|
||||
GstVulkanWindow *window;
|
||||
|
||||
GstVulkanSwapper *swapper;
|
||||
|
||||
/* properties */
|
||||
gboolean force_aspect_ratio;
|
||||
gint par_n;
|
||||
gint par_d;
|
||||
|
||||
/* stream configuration */
|
||||
GstVideoInfo v_info;
|
||||
|
||||
/* runtime variables */
|
||||
gint to_quit;
|
||||
};
|
||||
|
||||
struct _GstVulkanSinkClass
|
||||
{
|
||||
GstVideoSinkClass video_sink_class;
|
||||
};
|
||||
|
||||
GType gst_vulkan_sink_get_type(void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
957
ext/vulkan/vkswapper.c
Normal file
957
ext/vulkan/vkswapper.c
Normal file
|
@ -0,0 +1,957 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
|
||||
*
|
||||
* 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 <string.h>
|
||||
|
||||
#include "vkswapper.h"
|
||||
|
||||
#define GST_CAT_DEFAULT gst_vulkan_swapper_debug
|
||||
GST_DEBUG_CATEGORY (GST_CAT_DEFAULT);
|
||||
|
||||
#define gst_vulkan_swapper_parent_class parent_class
|
||||
G_DEFINE_TYPE_WITH_CODE (GstVulkanSwapper, gst_vulkan_swapper,
|
||||
GST_TYPE_OBJECT, GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT,
|
||||
"vulkanswapper", 0, "Vulkan Swapper"));
|
||||
|
||||
static gboolean
|
||||
_get_function_table (GstVulkanSwapper * swapper)
|
||||
{
|
||||
GstVulkanDevice *device = swapper->device;
|
||||
GstVulkanInstance *instance = gst_vulkan_device_get_instance (device);
|
||||
|
||||
#define GET_PROC_ADDRESS_REQUIRED(obj, type, name) \
|
||||
G_STMT_START { \
|
||||
obj->G_PASTE (, name) = G_PASTE(G_PASTE(gst_vulkan_, type), _get_proc_address) (type, "vk" G_STRINGIFY(name)); \
|
||||
if (!obj->G_PASTE(, name)) { \
|
||||
GST_ERROR_OBJECT (obj, "Failed to find required function vk" G_STRINGIFY(name)); \
|
||||
return FALSE; \
|
||||
} \
|
||||
} G_STMT_END
|
||||
|
||||
GET_PROC_ADDRESS_REQUIRED (swapper, instance,
|
||||
GetPhysicalDeviceSurfaceSupportKHR);
|
||||
GET_PROC_ADDRESS_REQUIRED (swapper, device, GetSurfacePropertiesKHR);
|
||||
GET_PROC_ADDRESS_REQUIRED (swapper, device, GetSurfaceFormatsKHR);
|
||||
GET_PROC_ADDRESS_REQUIRED (swapper, device, GetSurfacePresentModesKHR);
|
||||
GET_PROC_ADDRESS_REQUIRED (swapper, device, CreateSwapchainKHR);
|
||||
GET_PROC_ADDRESS_REQUIRED (swapper, device, DestroySwapchainKHR);
|
||||
GET_PROC_ADDRESS_REQUIRED (swapper, device, GetSwapchainImagesKHR);
|
||||
GET_PROC_ADDRESS_REQUIRED (swapper, device, AcquireNextImageKHR);
|
||||
GET_PROC_ADDRESS_REQUIRED (swapper, device, QueuePresentKHR);
|
||||
|
||||
return TRUE;
|
||||
|
||||
#undef GET_PROC_ADDRESS_REQUIRED
|
||||
}
|
||||
|
||||
static VkPlatformKHR
|
||||
_gst_display_type_to_vk_platform (GstVulkanDisplayType dtype)
|
||||
{
|
||||
VkPlatformKHR ret = -1;
|
||||
|
||||
if (dtype == GST_VULKAN_DISPLAY_TYPE_ANY)
|
||||
return -1;
|
||||
if (dtype == GST_VULKAN_DISPLAY_TYPE_NONE)
|
||||
return -1;
|
||||
|
||||
#if GST_VULKAN_HAVE_WINDOW_X11
|
||||
if ((dtype & GST_VULKAN_DISPLAY_TYPE_X11) == dtype)
|
||||
ret = VK_PLATFORM_X11_KHR;
|
||||
#endif
|
||||
|
||||
#if GST_VULKAN_HAVE_WINDOW_XCB
|
||||
if ((dtype & GST_VULKAN_DISPLAY_TYPE_XCB) == dtype)
|
||||
ret = VK_PLATFORM_XCB_KHR;
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_get_window_surface_description (GstVulkanSwapper * swapper,
|
||||
VkSurfaceDescriptionWindowKHR * desc)
|
||||
{
|
||||
GstVulkanDisplay *display = gst_vulkan_window_get_display (swapper->window);
|
||||
GstVulkanDisplayType dtype = gst_vulkan_display_get_handle_type (display);
|
||||
|
||||
g_return_val_if_fail (desc != NULL, FALSE);
|
||||
|
||||
desc->sType = VK_STRUCTURE_TYPE_SURFACE_DESCRIPTION_WINDOW_KHR;
|
||||
desc->pNext = NULL;
|
||||
desc->platform = _gst_display_type_to_vk_platform (dtype);
|
||||
if (desc->platform == -1) {
|
||||
GST_ERROR_OBJECT (swapper, "Failed to retrieve platform from display");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
desc->pPlatformHandle = gst_vulkan_display_get_platform_handle (display);
|
||||
desc->pPlatformWindow =
|
||||
gst_vulkan_window_get_platform_handle (swapper->window);
|
||||
|
||||
gst_object_unref (display);
|
||||
|
||||
/* XXX: might be a little too strict */
|
||||
return desc->pPlatformHandle != NULL && desc->pPlatformWindow != NULL;
|
||||
}
|
||||
|
||||
static GstVideoFormat
|
||||
_vk_format_to_video_format (VkFormat format)
|
||||
{
|
||||
switch (format) {
|
||||
/* double check endianess */
|
||||
case VK_FORMAT_R8G8B8A8_UNORM:
|
||||
return GST_VIDEO_FORMAT_RGBA;
|
||||
case VK_FORMAT_R8G8B8_UNORM:
|
||||
return GST_VIDEO_FORMAT_RGB;
|
||||
case VK_FORMAT_B8G8R8A8_UNORM:
|
||||
return GST_VIDEO_FORMAT_BGRA;
|
||||
case VK_FORMAT_B8G8R8_UNORM:
|
||||
return GST_VIDEO_FORMAT_BGR;
|
||||
default:
|
||||
return GST_VIDEO_FORMAT_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static VkFormat
|
||||
_vk_format_from_video_format (GstVideoFormat v_format)
|
||||
{
|
||||
switch (v_format) {
|
||||
case GST_VIDEO_FORMAT_RGBA:
|
||||
return VK_FORMAT_R8G8B8A8_UNORM;
|
||||
case GST_VIDEO_FORMAT_RGB:
|
||||
return VK_FORMAT_R8G8B8_UNORM;
|
||||
case GST_VIDEO_FORMAT_BGRA:
|
||||
return VK_FORMAT_B8G8R8A8_UNORM;
|
||||
case GST_VIDEO_FORMAT_BGR:
|
||||
return VK_FORMAT_B8G8R8_UNORM;
|
||||
default:
|
||||
return VK_FORMAT_UNDEFINED;
|
||||
}
|
||||
}
|
||||
|
||||
static VkColorSpaceKHR
|
||||
_vk_color_space_from_video_info (GstVideoInfo * v_info)
|
||||
{
|
||||
return VK_COLORSPACE_SRGB_NONLINEAR_KHR;
|
||||
}
|
||||
|
||||
static void
|
||||
_add_vk_format_to_list (GValue * list, VkFormat format)
|
||||
{
|
||||
GstVideoFormat v_format;
|
||||
const gchar *format_str;
|
||||
|
||||
v_format = _vk_format_to_video_format (format);
|
||||
if (v_format) {
|
||||
GValue item = G_VALUE_INIT;
|
||||
|
||||
g_value_init (&item, G_TYPE_STRING);
|
||||
format_str = gst_video_format_to_string (v_format);
|
||||
g_value_set_string (&item, format_str);
|
||||
gst_value_list_append_value (list, &item);
|
||||
g_value_unset (&item);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_vulkan_swapper_retrieve_surface_properties (GstVulkanSwapper * swapper,
|
||||
GError ** error)
|
||||
{
|
||||
VkSurfaceDescriptionWindowKHR surface_desc;
|
||||
VkDevice device = swapper->device->device;
|
||||
guint32 i, present_queue = -1, graphics_queue = -1;
|
||||
VkPhysicalDevice gpu;
|
||||
VkResult err;
|
||||
|
||||
if (swapper->surf_formats)
|
||||
return TRUE;
|
||||
|
||||
gpu = gst_vulkan_device_get_physical_device (swapper->device);
|
||||
|
||||
if (!_get_window_surface_description (swapper,
|
||||
(VkSurfaceDescriptionWindowKHR *) & surface_desc)) {
|
||||
g_set_error (error, GST_VULKAN_ERROR,
|
||||
GST_VULKAN_ERROR_INITIALIZATION_FAILED,
|
||||
"Failed to retrieve platform description");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for (i = 0; i < swapper->device->n_queues; i++) {
|
||||
VkBool32 supports_present;
|
||||
|
||||
swapper->GetPhysicalDeviceSurfaceSupportKHR (gpu, i,
|
||||
(VkSurfaceDescriptionKHR *) & surface_desc, &supports_present);
|
||||
if ((swapper->device->
|
||||
queue_family_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) {
|
||||
if (supports_present) {
|
||||
/* found one that supports both */
|
||||
graphics_queue = present_queue = i;
|
||||
break;
|
||||
}
|
||||
if (graphics_queue != -1)
|
||||
graphics_queue = i;
|
||||
} else if (supports_present) {
|
||||
if (present_queue != -1)
|
||||
present_queue = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (graphics_queue != present_queue) {
|
||||
g_set_error (error, GST_VULKAN_ERROR,
|
||||
GST_VULKAN_ERROR_INITIALIZATION_FAILED,
|
||||
"Failed to find a compatible present/graphics queue");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!(swapper->queue = gst_vulkan_device_get_queue (swapper->device,
|
||||
swapper->device->queue_family_id, graphics_queue, error)))
|
||||
return FALSE;
|
||||
|
||||
err =
|
||||
swapper->GetSurfacePropertiesKHR (device,
|
||||
(VkSurfaceDescriptionKHR *) & surface_desc, &swapper->surf_props);
|
||||
if (gst_vulkan_error_to_g_error (err, error, "vkGetSurfacePropertiesKHR") < 0)
|
||||
return FALSE;
|
||||
|
||||
err =
|
||||
swapper->GetSurfaceFormatsKHR (device,
|
||||
(VkSurfaceDescriptionKHR *) & surface_desc, &swapper->n_surf_formats,
|
||||
NULL);
|
||||
if (gst_vulkan_error_to_g_error (err, error, "vkGetSurfaceFormatsKHR") < 0)
|
||||
return FALSE;
|
||||
|
||||
swapper->surf_formats = g_new0 (VkSurfaceFormatKHR, swapper->n_surf_formats);
|
||||
err =
|
||||
swapper->GetSurfaceFormatsKHR (device,
|
||||
(VkSurfaceDescriptionKHR *) & surface_desc, &swapper->n_surf_formats,
|
||||
swapper->surf_formats);
|
||||
if (gst_vulkan_error_to_g_error (err, error, "vkGetSurfaceFormatsKHR") < 0)
|
||||
return FALSE;
|
||||
|
||||
err =
|
||||
swapper->GetSurfacePresentModesKHR (device,
|
||||
(VkSurfaceDescriptionKHR *) & surface_desc,
|
||||
&swapper->n_surf_present_modes, NULL);
|
||||
if (gst_vulkan_error_to_g_error (err, error,
|
||||
"vkGetSurfacePresentModesKHR") < 0)
|
||||
return FALSE;
|
||||
|
||||
swapper->surf_present_modes =
|
||||
g_new0 (VkPresentModeKHR, swapper->n_surf_present_modes);
|
||||
err =
|
||||
swapper->GetSurfacePresentModesKHR (device,
|
||||
(VkSurfaceDescriptionKHR *) & surface_desc,
|
||||
&swapper->n_surf_present_modes, swapper->surf_present_modes);
|
||||
if (gst_vulkan_error_to_g_error (err, error,
|
||||
"vkGetSurfacePresentModesKHR") < 0)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vulkan_swapper_finalize (GObject * object)
|
||||
{
|
||||
GstVulkanSwapper *swapper = GST_VULKAN_SWAPPER (object);
|
||||
int i;
|
||||
|
||||
if (swapper->swap_chain_images) {
|
||||
for (i = 0; i < swapper->n_swap_chain_images; i++) {
|
||||
gst_memory_unref ((GstMemory *) swapper->swap_chain_images[i]);
|
||||
swapper->swap_chain_images[i] = NULL;
|
||||
}
|
||||
g_free (swapper->swap_chain_images);
|
||||
}
|
||||
swapper->swap_chain_images = NULL;
|
||||
|
||||
if (swapper->swap_chain.handle)
|
||||
swapper->DestroySwapchainKHR (swapper->device->device, swapper->swap_chain);
|
||||
swapper->swap_chain.handle = 0;
|
||||
|
||||
if (swapper->queue)
|
||||
gst_object_unref (swapper->queue);
|
||||
swapper->queue = NULL;
|
||||
|
||||
if (swapper->device)
|
||||
gst_object_unref (swapper->device);
|
||||
swapper->device = NULL;
|
||||
|
||||
if (swapper->window)
|
||||
gst_object_unref (swapper->window);
|
||||
swapper->window = NULL;
|
||||
|
||||
g_free (swapper->surf_present_modes);
|
||||
swapper->surf_present_modes = NULL;
|
||||
|
||||
g_free (swapper->surf_formats);
|
||||
swapper->surf_formats = NULL;
|
||||
|
||||
gst_caps_replace (&swapper->caps, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vulkan_swapper_init (GstVulkanSwapper * swapper)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vulkan_swapper_class_init (GstVulkanSwapperClass * klass)
|
||||
{
|
||||
G_OBJECT_CLASS (klass)->finalize = gst_vulkan_swapper_finalize;
|
||||
}
|
||||
|
||||
GstVulkanSwapper *
|
||||
gst_vulkan_swapper_new (GstVulkanDevice * device, GstVulkanWindow * window)
|
||||
{
|
||||
GstVulkanSwapper *swapper;
|
||||
|
||||
swapper = g_object_new (GST_TYPE_VULKAN_SWAPPER, NULL);
|
||||
swapper->device = gst_object_ref (device);
|
||||
swapper->window = gst_object_ref (window);
|
||||
|
||||
if (!_get_function_table (swapper)) {
|
||||
gst_object_unref (swapper);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return swapper;
|
||||
}
|
||||
|
||||
GstCaps *
|
||||
gst_vulkan_swapper_get_supported_caps (GstVulkanSwapper * swapper,
|
||||
GError ** error)
|
||||
{
|
||||
GstStructure *s;
|
||||
GstCaps *caps;
|
||||
|
||||
g_return_val_if_fail (GST_IS_VULKAN_SWAPPER (swapper), NULL);
|
||||
|
||||
if (!_vulkan_swapper_retrieve_surface_properties (swapper, error))
|
||||
return NULL;
|
||||
|
||||
caps = gst_caps_new_empty_simple ("video/x-raw");
|
||||
s = gst_caps_get_structure (caps, 0);
|
||||
|
||||
{
|
||||
int i;
|
||||
GValue list = G_VALUE_INIT;
|
||||
|
||||
g_value_init (&list, GST_TYPE_LIST);
|
||||
|
||||
if (swapper->n_surf_formats
|
||||
&& swapper->surf_formats[0].format == VK_FORMAT_UNDEFINED) {
|
||||
_add_vk_format_to_list (&list, VK_FORMAT_B8G8R8A8_UNORM);
|
||||
} else {
|
||||
for (i = 0; i < swapper->n_surf_formats; i++) {
|
||||
_add_vk_format_to_list (&list, swapper->surf_formats[i].format);
|
||||
}
|
||||
}
|
||||
|
||||
gst_structure_set_value (s, "format", &list);
|
||||
g_value_unset (&list);
|
||||
}
|
||||
{
|
||||
guint32 max_dim = swapper->device->gpu_props.limits.maxImageDimension2D;
|
||||
|
||||
gst_structure_set (s, "width", GST_TYPE_INT_RANGE, 1, (gint) max_dim,
|
||||
"height", GST_TYPE_INT_RANGE, 1, (gint) max_dim, "pixel-aspect-ratio",
|
||||
GST_TYPE_FRACTION, 1, 1, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1,
|
||||
G_MAXINT, 1, NULL);
|
||||
}
|
||||
|
||||
GST_INFO_OBJECT (swapper, "Probed the following caps %" GST_PTR_FORMAT, caps);
|
||||
|
||||
return caps;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_swapper_set_image_layout_with_cmd (GstVulkanSwapper * swapper, VkCmdBuffer cmd,
|
||||
GstVulkanImageMemory * image, VkImageLayout new_image_layout,
|
||||
GError ** error)
|
||||
{
|
||||
VkPipelineStageFlags src_stages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
VkPipelineStageFlags dest_stages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
VkImageMemoryBarrier image_memory_barrier;
|
||||
VkImageMemoryBarrier *pmemory_barrier = &image_memory_barrier;
|
||||
|
||||
gst_vulkan_image_memory_set_layout (image, new_image_layout,
|
||||
&image_memory_barrier);
|
||||
|
||||
vkCmdPipelineBarrier (cmd, src_stages, dest_stages, FALSE, 1,
|
||||
(const void *const *) &pmemory_barrier);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_new_fence (GstVulkanDevice * device, VkFence * fence, GError ** error)
|
||||
{
|
||||
VkFenceCreateInfo fence_info;
|
||||
VkResult err;
|
||||
|
||||
fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||
fence_info.pNext = NULL;
|
||||
fence_info.flags = 0;
|
||||
|
||||
err = vkCreateFence (device->device, &fence_info, fence);
|
||||
if (gst_vulkan_error_to_g_error (err, error, "vkCreateFence") < 0)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_swapper_set_image_layout (GstVulkanSwapper * swapper,
|
||||
GstVulkanImageMemory * image, VkImageLayout new_image_layout,
|
||||
GError ** error)
|
||||
{
|
||||
VkCmdBuffer cmd;
|
||||
VkFence fence;
|
||||
VkResult err;
|
||||
|
||||
if (!gst_vulkan_device_create_cmd_buffer (swapper->device, &cmd, error))
|
||||
return FALSE;
|
||||
|
||||
if (!_new_fence (swapper->device, &fence, error))
|
||||
return FALSE;
|
||||
|
||||
{
|
||||
VkCmdBufferBeginInfo cmd_buf_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO,
|
||||
.pNext = NULL,
|
||||
.flags = VK_CMD_BUFFER_OPTIMIZE_SMALL_BATCH_BIT |
|
||||
VK_CMD_BUFFER_OPTIMIZE_ONE_TIME_SUBMIT_BIT,
|
||||
.renderPass = {VK_NULL_HANDLE}
|
||||
,
|
||||
.subpass = 0,
|
||||
.framebuffer = {VK_NULL_HANDLE}
|
||||
,
|
||||
};
|
||||
err = vkBeginCommandBuffer (cmd, &cmd_buf_info);
|
||||
if (gst_vulkan_error_to_g_error (err, error, "vkBeginCommandBuffer") < 0)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!_swapper_set_image_layout_with_cmd (swapper, cmd, image,
|
||||
new_image_layout, error))
|
||||
return FALSE;
|
||||
|
||||
err = vkEndCommandBuffer (cmd);
|
||||
if (gst_vulkan_error_to_g_error (err, error, "vkEndCommandBuffer") < 0)
|
||||
return FALSE;
|
||||
|
||||
err = vkQueueSubmit (swapper->queue->queue, 1, &cmd, fence);
|
||||
if (gst_vulkan_error_to_g_error (err, error, "vkQueueSubmit") < 0)
|
||||
return FALSE;
|
||||
|
||||
err = vkWaitForFences (swapper->device->device, 1, &fence, TRUE, -1);
|
||||
if (gst_vulkan_error_to_g_error (err, error, "vkWaitForFences") < 0)
|
||||
return FALSE;
|
||||
vkDestroyCommandBuffer (swapper->device->device, cmd);
|
||||
|
||||
vkDestroyFence (swapper->device->device, fence);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_allocate_swapchain (GstVulkanSwapper * swapper, GstCaps * caps,
|
||||
GError ** error)
|
||||
{
|
||||
VkSurfaceTransformFlagsKHR preTransform;
|
||||
VkSurfaceDescriptionWindowKHR surface_desc;
|
||||
VkPresentModeKHR present_mode;
|
||||
VkImageUsageFlags usage = 0;
|
||||
VkColorSpaceKHR color_space;
|
||||
VkImage *swap_chain_images;
|
||||
VkExtent2D swapchain_dims;
|
||||
guint32 n_images_wanted;
|
||||
VkFormat format;
|
||||
VkResult err;
|
||||
guint32 i;
|
||||
|
||||
/* width and height are either both -1, or both not -1. */
|
||||
if (swapper->surf_props.currentExtent.width == -1) {
|
||||
/* If the surface size is undefined, the size is set to
|
||||
* the size of the images requested. */
|
||||
swapchain_dims.width = 320;
|
||||
swapchain_dims.height = 240;
|
||||
} else {
|
||||
/* If the surface size is defined, the swap chain size must match */
|
||||
swapchain_dims = swapper->surf_props.currentExtent;
|
||||
}
|
||||
|
||||
/* If mailbox mode is available, use it, as is the lowest-latency non-
|
||||
* tearing mode. If not, try IMMEDIATE which will usually be available,
|
||||
* and is fastest (though it tears). If not, fall back to FIFO which is
|
||||
* always available. */
|
||||
present_mode = VK_PRESENT_MODE_FIFO_KHR;
|
||||
for (size_t i = 0; i < swapper->n_surf_present_modes; i++) {
|
||||
if (swapper->surf_present_modes[i] == VK_PRESENT_MODE_MAILBOX_KHR) {
|
||||
present_mode = VK_PRESENT_MODE_MAILBOX_KHR;
|
||||
break;
|
||||
}
|
||||
if ((present_mode != VK_PRESENT_MODE_MAILBOX_KHR) &&
|
||||
(swapper->surf_present_modes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR)) {
|
||||
present_mode = VK_PRESENT_MODE_IMMEDIATE_KHR;
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine the number of VkImage's to use in the swap chain (we desire to
|
||||
* own only 1 image at a time, besides the images being displayed and
|
||||
* queued for display): */
|
||||
n_images_wanted = swapper->surf_props.minImageCount + 1;
|
||||
if ((swapper->surf_props.maxImageCount > 0) &&
|
||||
(n_images_wanted > swapper->surf_props.maxImageCount)) {
|
||||
/* Application must settle for fewer images than desired: */
|
||||
n_images_wanted = swapper->surf_props.maxImageCount;
|
||||
}
|
||||
|
||||
if (swapper->surf_props.
|
||||
supportedTransforms & VK_SURFACE_TRANSFORM_NONE_BIT_KHR) {
|
||||
preTransform = VK_SURFACE_TRANSFORM_NONE_KHR;
|
||||
} else {
|
||||
preTransform = swapper->surf_props.currentTransform;
|
||||
}
|
||||
|
||||
if (!_get_window_surface_description (swapper, &surface_desc)) {
|
||||
g_set_error (error, GST_VULKAN_ERROR,
|
||||
GST_VULKAN_ERROR_INITIALIZATION_FAILED,
|
||||
"Failed to retrieve platform description");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
format =
|
||||
_vk_format_from_video_format (GST_VIDEO_INFO_FORMAT (&swapper->v_info));
|
||||
color_space = _vk_color_space_from_video_info (&swapper->v_info);
|
||||
|
||||
if ((swapper->surf_props.supportedUsageFlags &
|
||||
VK_IMAGE_USAGE_TRANSFER_DESTINATION_BIT) != 0) {
|
||||
usage |= VK_IMAGE_USAGE_TRANSFER_DESTINATION_BIT;
|
||||
} else {
|
||||
g_set_error (error, GST_VULKAN_ERROR,
|
||||
GST_VULKAN_ERROR_INITIALIZATION_FAILED,
|
||||
"Incorrect usage flags available for the swap images");
|
||||
return FALSE;
|
||||
}
|
||||
if ((swapper->
|
||||
surf_props.supportedUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)
|
||||
!= 0) {
|
||||
usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
} else {
|
||||
g_set_error (error, GST_VULKAN_ERROR,
|
||||
GST_VULKAN_ERROR_INITIALIZATION_FAILED,
|
||||
"Incorrect usage flags available for the swap images");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
{
|
||||
const VkSwapchainCreateInfoKHR swap_chain_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
|
||||
.pNext = NULL,
|
||||
.pSurfaceDescription = (const VkSurfaceDescriptionKHR *) &surface_desc,
|
||||
.minImageCount = n_images_wanted,
|
||||
.imageFormat = format,
|
||||
.imageColorSpace = color_space,
|
||||
.imageExtent = {
|
||||
.width = swapchain_dims.width,
|
||||
.height = swapchain_dims.height,
|
||||
},
|
||||
.imageUsageFlags = usage,
|
||||
.preTransform = preTransform,
|
||||
.imageArraySize = 1,
|
||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||
.queueFamilyCount = 0,
|
||||
.pQueueFamilyIndices = NULL,
|
||||
.presentMode = present_mode,
|
||||
.oldSwapchain = swapper->swap_chain,
|
||||
.clipped = TRUE,
|
||||
};
|
||||
|
||||
err =
|
||||
swapper->CreateSwapchainKHR (swapper->device->device, &swap_chain_info,
|
||||
&swapper->swap_chain);
|
||||
if (gst_vulkan_error_to_g_error (err, error, "vkCreateSwapchainKHR") < 0)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
err =
|
||||
swapper->GetSwapchainImagesKHR (swapper->device->device,
|
||||
swapper->swap_chain, &swapper->n_swap_chain_images, NULL);
|
||||
if (gst_vulkan_error_to_g_error (err, error, "vkGetSwapchainImagesKHR") < 0)
|
||||
return FALSE;
|
||||
|
||||
swap_chain_images = g_new0 (VkImage, swapper->n_swap_chain_images);
|
||||
err =
|
||||
swapper->GetSwapchainImagesKHR (swapper->device->device,
|
||||
swapper->swap_chain, &swapper->n_swap_chain_images, swap_chain_images);
|
||||
if (gst_vulkan_error_to_g_error (err, error, "vkGetSwapchainImagesKHR") < 0) {
|
||||
g_free (swap_chain_images);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
swapper->swap_chain_images =
|
||||
g_new0 (GstVulkanImageMemory *, swapper->n_swap_chain_images);
|
||||
for (i = 0; i < swapper->n_swap_chain_images; i++) {
|
||||
swapper->swap_chain_images[i] = (GstVulkanImageMemory *)
|
||||
gst_vulkan_image_memory_wrapped (swapper->device, swap_chain_images[i],
|
||||
format, swapchain_dims.width, swapchain_dims.height,
|
||||
VK_IMAGE_TILING_OPTIMAL, usage, NULL, NULL);
|
||||
|
||||
if (!_swapper_set_image_layout (swapper, swapper->swap_chain_images[i],
|
||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, error)) {
|
||||
g_free (swap_chain_images);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
g_free (swap_chain_images);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_swapchain_resize (GstVulkanSwapper * swapper, GError ** error)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!swapper->queue) {
|
||||
if (!_vulkan_swapper_retrieve_surface_properties (swapper, error)) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (swapper->swap_chain_images) {
|
||||
for (i = 0; i < swapper->n_swap_chain_images; i++) {
|
||||
if (swapper->swap_chain_images[i])
|
||||
gst_memory_unref ((GstMemory *) swapper->swap_chain_images[i]);
|
||||
}
|
||||
g_free (swapper->swap_chain_images);
|
||||
}
|
||||
|
||||
return _allocate_swapchain (swapper, swapper->caps, error);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_vulkan_swapper_set_caps (GstVulkanSwapper * swapper, GstCaps * caps,
|
||||
GError ** error)
|
||||
{
|
||||
if (!gst_video_info_from_caps (&swapper->v_info, caps)) {
|
||||
g_set_error (error, GST_VULKAN_ERROR,
|
||||
GST_VULKAN_ERROR_INITIALIZATION_FAILED,
|
||||
"Failed to geto GstVideoInfo from caps");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gst_caps_replace (&swapper->caps, caps);
|
||||
|
||||
return _swapchain_resize (swapper, error);
|
||||
}
|
||||
|
||||
struct cmd_data
|
||||
{
|
||||
VkCmdBuffer cmd;
|
||||
VkFence fence;
|
||||
GDestroyNotify notify;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
static gboolean
|
||||
_build_render_buffer_cmd (GstVulkanSwapper * swapper, guint32 swap_idx,
|
||||
GstBuffer * buffer, struct cmd_data *cmd_data, GError ** error)
|
||||
{
|
||||
const VkImageSubresource subres = {
|
||||
.aspect = VK_IMAGE_ASPECT_COLOR,
|
||||
.mipLevel = 0,
|
||||
.arrayLayer = 0,
|
||||
};
|
||||
GstVulkanImageMemory *swap_mem, *staging;
|
||||
GstMapInfo staging_map_info;
|
||||
VkSubresourceLayout layout;
|
||||
GstVideoFrame vframe;
|
||||
guint8 *src, *dest;
|
||||
VkCmdBuffer cmd;
|
||||
guint32 wt, ht;
|
||||
VkResult err;
|
||||
gsize h;
|
||||
|
||||
g_return_val_if_fail (swap_idx < swapper->n_swap_chain_images, FALSE);
|
||||
swap_mem = swapper->swap_chain_images[swap_idx];
|
||||
|
||||
if (!gst_vulkan_device_create_cmd_buffer (swapper->device, &cmd, error))
|
||||
return FALSE;
|
||||
|
||||
if (!gst_video_frame_map (&vframe, &swapper->v_info, buffer, GST_MAP_READ)) {
|
||||
g_set_error (error, GST_VULKAN_ERROR, GST_VULKAN_ERROR_MEMORY_MAP_FAILED,
|
||||
"Failed to map buffer");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
staging =
|
||||
(GstVulkanImageMemory *) gst_vulkan_image_memory_alloc (swapper->device,
|
||||
swap_mem->create_info.format, GST_VIDEO_FRAME_COMP_WIDTH (&vframe, 0),
|
||||
GST_VIDEO_FRAME_COMP_HEIGHT (&vframe, 0), VK_IMAGE_TILING_LINEAR,
|
||||
VK_IMAGE_USAGE_TRANSFER_SOURCE_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
|
||||
|
||||
if (!staging) {
|
||||
g_set_error (error, GST_VULKAN_ERROR, GST_VULKAN_ERROR_MEMORY_MAP_FAILED,
|
||||
"Failed to create staging memory");
|
||||
gst_video_frame_unmap (&vframe);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!gst_memory_map ((GstMemory *) staging, &staging_map_info, GST_MAP_WRITE)) {
|
||||
g_set_error (error, GST_VULKAN_ERROR, GST_VULKAN_ERROR_MEMORY_MAP_FAILED,
|
||||
"Failed to map swap image");
|
||||
gst_video_frame_unmap (&vframe);
|
||||
gst_memory_unref ((GstMemory *) staging);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
err = vkGetImageSubresourceLayout (swapper->device->device, staging->image,
|
||||
&subres, &layout);
|
||||
if (gst_vulkan_error_to_g_error (err, error,
|
||||
"vkGetImageSubresourceLayout") < 0) {
|
||||
gst_video_frame_unmap (&vframe);
|
||||
gst_memory_unmap ((GstMemory *) staging, &staging_map_info);
|
||||
gst_memory_unref ((GstMemory *) staging);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* FIXME: multi-planar formats */
|
||||
dest = staging_map_info.data;
|
||||
dest += layout.offset;
|
||||
src = vframe.data[0];
|
||||
for (h = 0; h < GST_VIDEO_FRAME_COMP_HEIGHT (&vframe, 0); h++) {
|
||||
/* FIXME: memcpy */
|
||||
memcpy (dest, src, GST_VIDEO_FRAME_PLANE_STRIDE (&vframe, 0));
|
||||
dest += layout.rowPitch;
|
||||
src += GST_VIDEO_FRAME_PLANE_STRIDE (&vframe, 0);
|
||||
g_assert (dest - staging_map_info.data - layout.offset <= layout.size);
|
||||
}
|
||||
gst_video_frame_unmap (&vframe);
|
||||
gst_memory_unmap ((GstMemory *) staging, &staging_map_info);
|
||||
|
||||
{
|
||||
VkCmdBufferBeginInfo cmd_buf_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO,
|
||||
.pNext = NULL,
|
||||
.flags = VK_CMD_BUFFER_OPTIMIZE_SMALL_BATCH_BIT |
|
||||
VK_CMD_BUFFER_OPTIMIZE_ONE_TIME_SUBMIT_BIT,
|
||||
.renderPass = {VK_NULL_HANDLE}
|
||||
,
|
||||
.subpass = 0,
|
||||
.framebuffer = {VK_NULL_HANDLE}
|
||||
,
|
||||
};
|
||||
err = vkBeginCommandBuffer (cmd, &cmd_buf_info);
|
||||
if (gst_vulkan_error_to_g_error (err, error, "vkBeginCommandBuffer") < 0)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!_swapper_set_image_layout_with_cmd (swapper, cmd, swap_mem,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL, error)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!_swapper_set_image_layout_with_cmd (swapper, cmd, staging,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_SOURCE_OPTIMAL, error)) {
|
||||
return FALSE;
|
||||
}
|
||||
#define SUBRESOURCE_COPY(res,aspect_,mip,layer,size) \
|
||||
G_STMT_START { \
|
||||
res.aspect = aspect_; \
|
||||
res.mipLevel = mip; \
|
||||
res.arrayLayer = layer; \
|
||||
res.arraySize = size; \
|
||||
} G_STMT_END
|
||||
#define OFFSET3D(offset,x_,y_,z_) \
|
||||
G_STMT_START { \
|
||||
offset.x = x_; \
|
||||
offset.y = y_; \
|
||||
offset.z = z_; \
|
||||
} G_STMT_END
|
||||
#define EXTENT3D(extent,w,h,d) \
|
||||
G_STMT_START { \
|
||||
extent.width = w; \
|
||||
extent.height = h; \
|
||||
extent.depth = d; \
|
||||
} G_STMT_END
|
||||
|
||||
/* FIXME: center rect */
|
||||
#if 0
|
||||
/* XXX: doesn't work with LunarG's example driver. According to LunarG,
|
||||
* it's not implemented */
|
||||
{
|
||||
VkImageBlit blit_image = { 0, };
|
||||
|
||||
SUBRESOURCE_COPY (blit_image.srcSubresource, VK_IMAGE_ASPECT_COLOR, 0, 0,
|
||||
1);
|
||||
OFFSET3D (blit_image.srcOffset, 0, 0, 0);
|
||||
EXTENT3D (blit_image.extent, GST_VIDEO_INFO_WIDTH (&swapper->v_info),
|
||||
GST_VIDEO_INFO_HEIGHT (&swapper->v_info), 1);
|
||||
SUBRESOURCE_COPY (blit_image.destSubresource, VK_IMAGE_ASPECT_COLOR, 0, 0,
|
||||
1);
|
||||
OFFSET3D (blit_image.destOffset, 0, 0, 0);
|
||||
EXTENT3D (blit_image.extent, swap_mem->create_info.extent.width,
|
||||
swap_mem->create_info.extent.height, 1);
|
||||
|
||||
/* FIXME: copy */
|
||||
vkCmdBlitImage (cmd, staging->image,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_SOURCE_OPTIMAL, swap_mem->image,
|
||||
VK_IMAGE_LAYOUT_GENERAL, 1, &blit_image, VK_TEX_FILTER_LINEAR);
|
||||
}
|
||||
#else
|
||||
wt = MIN (swap_mem->create_info.extent.width,
|
||||
GST_VIDEO_INFO_WIDTH (&swapper->v_info));
|
||||
ht = MIN (swap_mem->create_info.extent.height,
|
||||
GST_VIDEO_INFO_HEIGHT (&swapper->v_info));
|
||||
|
||||
{
|
||||
VkImageCopy copy_image = { 0, };
|
||||
|
||||
SUBRESOURCE_COPY (copy_image.srcSubresource, VK_IMAGE_ASPECT_COLOR, 0, 0,
|
||||
1);
|
||||
OFFSET3D (copy_image.srcOffset, 0, 0, 0);
|
||||
SUBRESOURCE_COPY (copy_image.destSubresource, VK_IMAGE_ASPECT_COLOR, 0, 0,
|
||||
1);
|
||||
OFFSET3D (copy_image.destOffset, 0, 0, 0);
|
||||
EXTENT3D (copy_image.extent, wt, ht, 1);
|
||||
|
||||
/* FIXME: copy */
|
||||
vkCmdCopyImage (cmd, staging->image,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_SOURCE_OPTIMAL, swap_mem->image,
|
||||
VK_IMAGE_LAYOUT_GENERAL, 1, ©_image);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!_swapper_set_image_layout_with_cmd (swapper, cmd, staging,
|
||||
VK_IMAGE_LAYOUT_PRESENT_SOURCE_KHR, error)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
err = vkEndCommandBuffer (cmd);
|
||||
if (gst_vulkan_error_to_g_error (err, error, "vkEndCommandBuffer") < 0)
|
||||
return FALSE;
|
||||
|
||||
cmd_data->cmd = cmd;
|
||||
cmd_data->notify = (GDestroyNotify) gst_memory_unref;
|
||||
cmd_data->data = staging;
|
||||
|
||||
if (!_new_fence (swapper->device, &cmd_data->fence, error)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* FIXME: staging frame is leaked */
|
||||
err =
|
||||
vkQueueSubmit (swapper->queue->queue, 1, &cmd_data->cmd, cmd_data->fence);
|
||||
if (gst_vulkan_error_to_g_error (err, error, "vkQueueSubmit") < 0) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_vulkan_swapper_render_buffer (GstVulkanSwapper * swapper,
|
||||
GstBuffer * buffer, GError ** error)
|
||||
{
|
||||
VkSemaphore semaphore = { 0, };
|
||||
VkSemaphoreCreateInfo semaphore_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
|
||||
.pNext = NULL,
|
||||
.flags = VK_FENCE_CREATE_SIGNALED_BIT,
|
||||
};
|
||||
VkPresentInfoKHR present;
|
||||
struct cmd_data cmd_data = { 0, };
|
||||
guint32 swap_idx;
|
||||
VkResult err;
|
||||
|
||||
reacquire:
|
||||
err = vkCreateSemaphore (swapper->device->device, &semaphore_info,
|
||||
&semaphore);
|
||||
if (gst_vulkan_error_to_g_error (err, error, "vkCreateSemaphore") < 0)
|
||||
goto error;
|
||||
|
||||
err =
|
||||
swapper->AcquireNextImageKHR (swapper->device->device,
|
||||
swapper->swap_chain, -1, semaphore, &swap_idx);
|
||||
/* TODO: Deal with the VK_SUBOPTIMAL_KHR and VK_ERROR_OUT_OF_DATE_KHR */
|
||||
if (err == VK_ERROR_OUT_OF_DATE_KHR) {
|
||||
vkDestroySemaphore (swapper->device->device, semaphore);
|
||||
if (!_swapchain_resize (swapper, error))
|
||||
return FALSE;
|
||||
goto reacquire;
|
||||
} else if (gst_vulkan_error_to_g_error (err, error,
|
||||
"vkAcquireNextImageKHR") < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!_build_render_buffer_cmd (swapper, swap_idx, buffer, &cmd_data, error))
|
||||
goto error;
|
||||
|
||||
vkQueueWaitSemaphore (swapper->queue->queue, semaphore);
|
||||
|
||||
present.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
||||
present.pNext = NULL;
|
||||
present.swapchainCount = 1;
|
||||
present.swapchains = &swapper->swap_chain;
|
||||
present.imageIndices = &swap_idx;
|
||||
|
||||
err = swapper->QueuePresentKHR (swapper->queue->queue, &present);
|
||||
if (err == VK_ERROR_OUT_OF_DATE_KHR) {
|
||||
vkDestroySemaphore (swapper->device->device, semaphore);
|
||||
if (!_swapchain_resize (swapper, error))
|
||||
return FALSE;
|
||||
/* FIXME: correct? */
|
||||
return TRUE;
|
||||
} else if (gst_vulkan_error_to_g_error (err, error, "vkQueuePresentKHR") < 0)
|
||||
goto error;
|
||||
|
||||
err = vkWaitForFences (swapper->device->device, 1, &cmd_data.fence, TRUE, -1);
|
||||
if (gst_vulkan_error_to_g_error (err, error, "vkWaitForFences") < 0)
|
||||
goto error;
|
||||
|
||||
if (semaphore.handle)
|
||||
vkDestroySemaphore (swapper->device->device, semaphore);
|
||||
if (cmd_data.cmd)
|
||||
vkDestroyCommandBuffer (swapper->device->device, cmd_data.cmd);
|
||||
if (cmd_data.fence.handle)
|
||||
vkDestroyFence (swapper->device->device, cmd_data.fence);
|
||||
if (cmd_data.notify)
|
||||
cmd_data.notify (cmd_data.data);
|
||||
return TRUE;
|
||||
|
||||
error:
|
||||
{
|
||||
if (semaphore.handle)
|
||||
vkDestroySemaphore (swapper->device->device, semaphore);
|
||||
if (cmd_data.cmd)
|
||||
vkDestroyCommandBuffer (swapper->device->device, cmd_data.cmd);
|
||||
if (cmd_data.fence.handle)
|
||||
vkDestroyFence (swapper->device->device, cmd_data.fence);
|
||||
if (cmd_data.notify)
|
||||
cmd_data.notify (cmd_data.data);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
91
ext/vulkan/vkswapper.h
Normal file
91
ext/vulkan/vkswapper.h
Normal file
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
|
||||
*
|
||||
* 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 _VK_SWAPPER_H_
|
||||
#define _VK_SWAPPER_H_
|
||||
|
||||
#include <gst/video/video.h>
|
||||
|
||||
#include <vk.h>
|
||||
#include <vulkan/vk_ext_khr_swapchain.h>
|
||||
#include <vulkan/vk_ext_khr_device_swapchain.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_VULKAN_SWAPPER (gst_vulkan_swapper_get_type())
|
||||
#define GST_VULKAN_SWAPPER(o) (G_TYPE_CHECK_INSTANCE_CAST((o), GST_TYPE_VULKAN_SWAPPER, GstVulkanSwapper))
|
||||
#define GST_VULKAN_SWAPPER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GST_TYPE_VULKAN_SWAPPER, GstVulkanSwapperClass))
|
||||
#define GST_IS_VULKAN_SWAPPER(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), GST_TYPE_VULKAN_SWAPPER))
|
||||
#define GST_IS_VULKAN_SWAPPER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), GST_TYPE_VULKAN_SWAPPER))
|
||||
#define GST_VULKAN_SWAPPER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GST_TYPE_VULKAN_SWAPPER, GstVulkanSwapperClass))
|
||||
GType gst_vulkan_swapper_get_type (void);
|
||||
|
||||
struct _GstVulkanSwapper
|
||||
{
|
||||
GstObject parent;
|
||||
|
||||
GstVulkanDevice *device;
|
||||
GstVulkanWindow *window;
|
||||
GstVulkanQueue *queue;
|
||||
|
||||
VkSurfacePropertiesKHR surf_props;
|
||||
VkSurfaceFormatKHR *surf_formats;
|
||||
guint32 n_surf_formats;
|
||||
VkPresentModeKHR *surf_present_modes;
|
||||
guint32 n_surf_present_modes;
|
||||
|
||||
VkSwapchainKHR swap_chain;
|
||||
GstVulkanImageMemory **swap_chain_images;
|
||||
guint32 n_swap_chain_images;
|
||||
|
||||
GstCaps *caps;
|
||||
GstVideoInfo v_info;
|
||||
|
||||
PFN_vkGetPhysicalDeviceSurfaceSupportKHR GetPhysicalDeviceSurfaceSupportKHR;
|
||||
PFN_vkGetSurfacePropertiesKHR GetSurfacePropertiesKHR;
|
||||
PFN_vkGetSurfaceFormatsKHR GetSurfaceFormatsKHR;
|
||||
PFN_vkGetSurfacePresentModesKHR GetSurfacePresentModesKHR;
|
||||
PFN_vkCreateSwapchainKHR CreateSwapchainKHR;
|
||||
PFN_vkDestroySwapchainKHR DestroySwapchainKHR;
|
||||
PFN_vkGetSwapchainImagesKHR GetSwapchainImagesKHR;
|
||||
PFN_vkAcquireNextImageKHR AcquireNextImageKHR;
|
||||
PFN_vkQueuePresentKHR QueuePresentKHR;
|
||||
};
|
||||
|
||||
struct _GstVulkanSwapperClass
|
||||
{
|
||||
GstObjectClass parent_class;
|
||||
};
|
||||
|
||||
GstVulkanSwapper * gst_vulkan_swapper_new (GstVulkanDevice * device,
|
||||
GstVulkanWindow * window);
|
||||
|
||||
GstCaps * gst_vulkan_swapper_get_supported_caps (GstVulkanSwapper * swapper,
|
||||
GError ** error);
|
||||
gboolean gst_vulkan_swapper_set_caps (GstVulkanSwapper * swapper,
|
||||
GstCaps * caps,
|
||||
GError ** error);
|
||||
gboolean gst_vulkan_swapper_render_buffer (GstVulkanSwapper * swapper,
|
||||
GstBuffer * buffer,
|
||||
GError ** error);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* _VK_INSTANCE_H_ */
|
46
ext/vulkan/vkutils.c
Normal file
46
ext/vulkan/vkutils.c
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
|
||||
*
|
||||
* 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 "vkutils.h"
|
||||
|
||||
gboolean
|
||||
_check_for_all_layers (uint32_t check_count, const char **check_names,
|
||||
uint32_t layer_count, VkLayerProperties * layers)
|
||||
{
|
||||
uint32_t i, j;
|
||||
|
||||
for (i = 0; i < check_count; i++) {
|
||||
gboolean found = FALSE;
|
||||
for (j = 0; j < layer_count; j++) {
|
||||
if (g_strcmp0 (check_names[i], layers[j].layerName) == 0) {
|
||||
found = TRUE;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
GST_ERROR ("Cannot find layer: %s", check_names[i]);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
33
ext/vulkan/vkutils.h
Normal file
33
ext/vulkan/vkutils.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
|
||||
*
|
||||
* 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 _VK_UTILS_H_
|
||||
#define _VK_UTILS_H_
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include "vk.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
gboolean _check_for_all_layers (uint32_t check_count, const char ** check_names,
|
||||
uint32_t layer_count, VkLayerProperties * layers);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /*_VK_UTILS_H_ */
|
247
ext/vulkan/vkwindow.c
Normal file
247
ext/vulkan/vkwindow.c
Normal file
|
@ -0,0 +1,247 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2012 Matthew Waters <ystreet00@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:gstglwindow
|
||||
* @short_description: window/surface abstraction
|
||||
* @title: GstVulkanWindow
|
||||
* @see_also: #GstGLContext, #GstGLDisplay
|
||||
*
|
||||
* GstVulkanWindow represents a window that elements can render into. A window can
|
||||
* either be a user visible window (onscreen) or hidden (offscreen).
|
||||
*/
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <gmodule.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "vkwindow.h"
|
||||
|
||||
#if GST_VULKAN_HAVE_WINDOW_X11
|
||||
#include "x11/vkwindow_x11.h"
|
||||
#endif
|
||||
#if GST_VULKAN_HAVE_WINDOW_XCB
|
||||
#include "xcb/vkwindow_xcb.h"
|
||||
#endif
|
||||
|
||||
#define GST_CAT_DEFAULT gst_vulkan_window_debug
|
||||
GST_DEBUG_CATEGORY (GST_CAT_DEFAULT);
|
||||
|
||||
#define gst_vulkan_window_parent_class parent_class
|
||||
G_DEFINE_ABSTRACT_TYPE (GstVulkanWindow, gst_vulkan_window, GST_TYPE_OBJECT);
|
||||
|
||||
#define GST_VULKAN_WINDOW_GET_PRIVATE(o) \
|
||||
(G_TYPE_INSTANCE_GET_PRIVATE((o), GST_TYPE_VULKAN_WINDOW, GstVulkanWindowPrivate))
|
||||
|
||||
struct _GstVulkanWindowPrivate
|
||||
{
|
||||
guint surface_width;
|
||||
guint surface_height;
|
||||
};
|
||||
|
||||
static void gst_vulkan_window_finalize (GObject * object);
|
||||
|
||||
typedef struct _GstVulkanDummyWindow
|
||||
{
|
||||
GstVulkanWindow parent;
|
||||
|
||||
guintptr handle;
|
||||
} GstVulkanDummyWindow;
|
||||
|
||||
typedef struct _GstVulkanDummyWindowCass
|
||||
{
|
||||
GstVulkanWindowClass parent;
|
||||
} GstVulkanDummyWindowClass;
|
||||
|
||||
GstVulkanDummyWindow *gst_vulkan_dummy_window_new (void);
|
||||
|
||||
enum
|
||||
{
|
||||
SIGNAL_0,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
/* static guint gst_vulkan_window_signals[LAST_SIGNAL] = { 0 }; */
|
||||
|
||||
GQuark
|
||||
gst_vulkan_window_error_quark (void)
|
||||
{
|
||||
return g_quark_from_static_string ("gst-gl-window-error-quark");
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_vulkan_window_default_open (GstVulkanWindow * window, GError ** error)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vulkan_window_default_close (GstVulkanWindow * window)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
_init_debug (void)
|
||||
{
|
||||
static volatile gsize _init = 0;
|
||||
|
||||
if (g_once_init_enter (&_init)) {
|
||||
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "vulkanwindow", 0,
|
||||
"Vulkan Window");
|
||||
g_once_init_leave (&_init, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vulkan_window_init (GstVulkanWindow * window)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vulkan_window_class_init (GstVulkanWindowClass * klass)
|
||||
{
|
||||
g_type_class_add_private (klass, sizeof (GstVulkanWindowPrivate));
|
||||
|
||||
klass->open = GST_DEBUG_FUNCPTR (gst_vulkan_window_default_open);
|
||||
klass->close = GST_DEBUG_FUNCPTR (gst_vulkan_window_default_close);
|
||||
|
||||
G_OBJECT_CLASS (klass)->finalize = gst_vulkan_window_finalize;
|
||||
|
||||
_init_debug ();
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_vulkan_window_new:
|
||||
* @display: a #GstGLDisplay
|
||||
*
|
||||
* Returns: (transfer full): a new #GstVulkanWindow using @display's connection
|
||||
*
|
||||
* Since: 1.4
|
||||
*/
|
||||
GstVulkanWindow *
|
||||
gst_vulkan_window_new (GstVulkanDisplay * display)
|
||||
{
|
||||
GstVulkanWindow *window = NULL;
|
||||
const gchar *user_choice;
|
||||
|
||||
g_return_val_if_fail (display != NULL, NULL);
|
||||
|
||||
_init_debug ();
|
||||
|
||||
user_choice = g_getenv ("GST_VULKAN_WINDOW");
|
||||
GST_INFO ("creating a window, user choice:%s", user_choice);
|
||||
#if GST_VULKAN_HAVE_WINDOW_X11
|
||||
if (!window && (!user_choice || g_strstr_len (user_choice, 3, "x11")))
|
||||
window = GST_VULKAN_WINDOW (gst_vulkan_window_x11_new (display));
|
||||
#endif
|
||||
#if GST_VULKAN_HAVE_WINDOW_XCB
|
||||
if (!window && (!user_choice || g_strstr_len (user_choice, 3, "xcb")))
|
||||
window = GST_VULKAN_WINDOW (gst_vulkan_window_xcb_new (display));
|
||||
#endif
|
||||
if (!window) {
|
||||
/* subclass returned a NULL window */
|
||||
GST_WARNING ("Could not create window. user specified %s, creating dummy"
|
||||
" window", user_choice ? user_choice : "(null)");
|
||||
|
||||
window = GST_VULKAN_WINDOW (gst_vulkan_dummy_window_new ());
|
||||
}
|
||||
|
||||
window->display = gst_object_ref (display);
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vulkan_window_finalize (GObject * object)
|
||||
{
|
||||
GstVulkanWindow *window = GST_VULKAN_WINDOW (object);
|
||||
|
||||
gst_object_unref (window->display);
|
||||
|
||||
G_OBJECT_CLASS (gst_vulkan_window_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
GstVulkanDisplay *
|
||||
gst_vulkan_window_get_display (GstVulkanWindow * window)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_VULKAN_WINDOW (window), NULL);
|
||||
|
||||
return gst_object_ref (window->display);
|
||||
}
|
||||
|
||||
gpointer
|
||||
gst_vulkan_window_get_platform_handle (GstVulkanWindow * window)
|
||||
{
|
||||
GstVulkanWindowClass *klass;
|
||||
|
||||
g_return_val_if_fail (GST_IS_VULKAN_WINDOW (window), NULL);
|
||||
klass = GST_VULKAN_WINDOW_GET_CLASS (window);
|
||||
g_return_val_if_fail (klass->get_platform_handle != NULL, NULL);
|
||||
|
||||
return klass->get_platform_handle (window);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_vulkan_window_open (GstVulkanWindow * window, GError ** error)
|
||||
{
|
||||
GstVulkanWindowClass *klass;
|
||||
|
||||
g_return_val_if_fail (GST_IS_VULKAN_WINDOW (window), FALSE);
|
||||
klass = GST_VULKAN_WINDOW_GET_CLASS (window);
|
||||
g_return_val_if_fail (klass->open != NULL, FALSE);
|
||||
|
||||
return klass->open (window, error);
|
||||
}
|
||||
|
||||
void
|
||||
gst_vulkan_window_close (GstVulkanWindow * window)
|
||||
{
|
||||
GstVulkanWindowClass *klass;
|
||||
|
||||
g_return_if_fail (GST_IS_VULKAN_WINDOW (window));
|
||||
klass = GST_VULKAN_WINDOW_GET_CLASS (window);
|
||||
g_return_if_fail (klass->close != NULL);
|
||||
|
||||
return klass->close (window);
|
||||
}
|
||||
|
||||
GType gst_vulkan_dummy_window_get_type (void);
|
||||
G_DEFINE_TYPE (GstVulkanDummyWindow, gst_vulkan_dummy_window,
|
||||
GST_TYPE_VULKAN_WINDOW);
|
||||
|
||||
static void
|
||||
gst_vulkan_dummy_window_class_init (GstVulkanDummyWindowClass * klass)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vulkan_dummy_window_init (GstVulkanDummyWindow * dummy)
|
||||
{
|
||||
dummy->handle = 0;
|
||||
}
|
||||
|
||||
GstVulkanDummyWindow *
|
||||
gst_vulkan_dummy_window_new (void)
|
||||
{
|
||||
return g_object_new (gst_vulkan_dummy_window_get_type (), NULL);
|
||||
}
|
100
ext/vulkan/vkwindow.h
Normal file
100
ext/vulkan/vkwindow.h
Normal file
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2008 Julien Isorce <julien.isorce@gmail.com>
|
||||
* Copyright (C) 2012 Matthew Waters <ystreet00@gmail.com>
|
||||
*
|
||||
* 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_VULKAN_WINDOW_H__
|
||||
#define __GST_VULKAN_WINDOW_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
#include <vk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_VULKAN_WINDOW (gst_vulkan_window_get_type())
|
||||
#define GST_VULKAN_WINDOW(o) (G_TYPE_CHECK_INSTANCE_CAST((o), GST_TYPE_VULKAN_WINDOW, GstVulkanWindow))
|
||||
#define GST_VULKAN_WINDOW_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GST_TYPE_VULKAN_WINDOW, GstVulkanWindowClass))
|
||||
#define GST_IS_VULKAN_WINDOW(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), GST_TYPE_VULKAN_WINDOW))
|
||||
#define GST_IS_VULKAN_WINDOW_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), GST_TYPE_VULKAN_WINDOW))
|
||||
#define GST_VULKAN_WINDOW_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GST_TYPE_VULKAN_WINDOW, GstVulkanWindowClass))
|
||||
GType gst_vulkan_window_get_type (void);
|
||||
|
||||
#define GST_VULKAN_WINDOW_LOCK(w) g_mutex_lock(&GST_VULKAN_WINDOW(w)->lock)
|
||||
#define GST_VULKAN_WINDOW_UNLOCK(w) g_mutex_unlock(&GST_VULKAN_WINDOW(w)->lock)
|
||||
#define GST_VULKAN_WINDOW_GET_LOCK(w) (&GST_VULKAN_WINDOW(w)->lock)
|
||||
|
||||
#define GST_VULKAN_WINDOW_ERROR (gst_vulkan_window_error_quark ())
|
||||
GQuark gst_vulkan_window_error_quark (void);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GST_VULKAN_WINDOW_ERROR_FAILED,
|
||||
GST_VULKAN_WINDOW_ERROR_OLD_LIBS,
|
||||
GST_VULKAN_WINDOW_ERROR_RESOURCE_UNAVAILABLE,
|
||||
} GstVulkanWindowError;
|
||||
|
||||
/**
|
||||
* GstVulkanWindow:
|
||||
*
|
||||
* #GstVulkanWindow is an opaque struct and should only be accessed through the
|
||||
* provided api.
|
||||
*/
|
||||
struct _GstVulkanWindow {
|
||||
/*< private >*/
|
||||
GstObject parent;
|
||||
|
||||
GstVulkanDisplay *display;
|
||||
|
||||
GMutex lock;
|
||||
|
||||
GstVulkanWindowPrivate *priv;
|
||||
|
||||
gpointer _reserved[GST_PADDING];
|
||||
};
|
||||
|
||||
/**
|
||||
* GstVulkanWindowClass:
|
||||
* @parent_class: Parent class
|
||||
* @open: open the connection to the display
|
||||
* @close: close the connection to the display
|
||||
*/
|
||||
struct _GstVulkanWindowClass {
|
||||
GstObjectClass parent_class;
|
||||
|
||||
gboolean (*open) (GstVulkanWindow *window, GError **error);
|
||||
void (*close) (GstVulkanWindow *window);
|
||||
|
||||
gpointer (*get_platform_handle) (GstVulkanWindow *window);
|
||||
|
||||
/*< private >*/
|
||||
gpointer _reserved[GST_PADDING];
|
||||
};
|
||||
|
||||
GstVulkanWindow * gst_vulkan_window_new (GstVulkanDisplay *display);
|
||||
|
||||
GstVulkanDisplay * gst_vulkan_window_get_display (GstVulkanWindow *window);
|
||||
gpointer gst_vulkan_window_get_platform_handle (GstVulkanWindow *window);
|
||||
|
||||
gboolean gst_vulkan_window_open (GstVulkanWindow * window, GError ** error);
|
||||
void gst_vulkan_window_close (GstVulkanWindow * window);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_VULKAN_WINDOW_H__ */
|
29
ext/vulkan/xcb/Makefile.am
Normal file
29
ext/vulkan/xcb/Makefile.am
Normal file
|
@ -0,0 +1,29 @@
|
|||
## Process this file with automake to produce Makefile.in
|
||||
|
||||
noinst_LTLIBRARIES = libgstvulkan-xcb.la
|
||||
|
||||
libgstvulkan_xcb_la_SOURCES = \
|
||||
vkdisplay_xcb.c \
|
||||
vkwindow_xcb.c \
|
||||
xcb_event_source.c
|
||||
|
||||
noinst_HEADERS = \
|
||||
vkdisplay_xcb.h \
|
||||
vkwindow_xcb.h \
|
||||
xcb_event_source.h
|
||||
|
||||
libgstvulkan_xcb_la_CFLAGS = \
|
||||
-I$(top_srcdir)/gst-libs \
|
||||
-I$(top_srcdir)/ext/vulkan \
|
||||
-I$(top_builddir)/gst-libs \
|
||||
$(GST_PLUGINS_BASE_CFLAGS) \
|
||||
$(GST_BASE_CFLAGS) \
|
||||
$(GST_CFLAGS) \
|
||||
$(XCB_CFLAGS)
|
||||
|
||||
libgstvulkan_xcb_la_LIBADD = \
|
||||
$(XCB_LIBS)
|
||||
|
||||
libgstvulkan_xcb_la_LDFLAGS = \
|
||||
$(GST_LIB_LDFLAGS) \
|
||||
$(GST_ALL_LDFLAGS)
|
165
ext/vulkan/xcb/vkdisplay_xcb.c
Normal file
165
ext/vulkan/xcb/vkdisplay_xcb.c
Normal file
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
|
||||
*
|
||||
* 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 "vkdisplay_xcb.h"
|
||||
#include "xcb_event_source.h"
|
||||
|
||||
#define GST_CAT_DEFAULT gst_vulkan_display_debug
|
||||
GST_DEBUG_CATEGORY_STATIC (gst_vulkan_display_debug);
|
||||
|
||||
G_DEFINE_TYPE (GstVulkanDisplayXCB, gst_vulkan_display_xcb,
|
||||
GST_TYPE_VULKAN_DISPLAY);
|
||||
|
||||
static void gst_vulkan_display_xcb_finalize (GObject * object);
|
||||
static gpointer gst_vulkan_display_xcb_get_handle (GstVulkanDisplay * display);
|
||||
static gpointer gst_vulkan_display_xcb_get_platform_handle (GstVulkanDisplay *
|
||||
display);
|
||||
|
||||
static void
|
||||
gst_vulkan_display_xcb_class_init (GstVulkanDisplayXCBClass * klass)
|
||||
{
|
||||
GST_VULKAN_DISPLAY_CLASS (klass)->get_handle =
|
||||
GST_DEBUG_FUNCPTR (gst_vulkan_display_xcb_get_handle);
|
||||
GST_VULKAN_DISPLAY_CLASS (klass)->get_platform_handle =
|
||||
GST_DEBUG_FUNCPTR (gst_vulkan_display_xcb_get_platform_handle);
|
||||
|
||||
G_OBJECT_CLASS (klass)->finalize = gst_vulkan_display_xcb_finalize;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vulkan_display_xcb_init (GstVulkanDisplayXCB * display_xcb)
|
||||
{
|
||||
GstVulkanDisplay *display = (GstVulkanDisplay *) display_xcb;
|
||||
|
||||
display->type = GST_VULKAN_DISPLAY_TYPE_XCB;
|
||||
display_xcb->foreign_display = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vulkan_display_xcb_finalize (GObject * object)
|
||||
{
|
||||
GstVulkanDisplayXCB *display_xcb = GST_VULKAN_DISPLAY_XCB (object);
|
||||
|
||||
if (!display_xcb->foreign_display && display_xcb->platform_handle.connection)
|
||||
xcb_disconnect (display_xcb->platform_handle.connection);
|
||||
display_xcb->platform_handle.connection = NULL;
|
||||
|
||||
if (display_xcb->event_source) {
|
||||
g_source_destroy (display_xcb->event_source);
|
||||
g_source_unref (display_xcb->event_source);
|
||||
}
|
||||
display_xcb->event_source = NULL;
|
||||
|
||||
G_OBJECT_CLASS (gst_vulkan_display_xcb_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static xcb_screen_t *
|
||||
_get_screen_from_connection (xcb_connection_t * connection, int screen_no)
|
||||
{
|
||||
const xcb_setup_t *setup;
|
||||
xcb_screen_iterator_t iter;
|
||||
|
||||
setup = xcb_get_setup (connection);
|
||||
iter = xcb_setup_roots_iterator (setup);
|
||||
while (screen_no-- > 0)
|
||||
xcb_screen_next (&iter);
|
||||
|
||||
return iter.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_vulkan_display_xcb_new:
|
||||
* @name: (allow-none): a display name
|
||||
*
|
||||
* Create a new #GstVulkanDisplayXCB from the xcb display name. See XOpenDisplay()
|
||||
* for details on what is a valid name.
|
||||
*
|
||||
* Returns: (transfer full): a new #GstVulkanDisplayXCB or %NULL
|
||||
*/
|
||||
GstVulkanDisplayXCB *
|
||||
gst_vulkan_display_xcb_new (const gchar * name)
|
||||
{
|
||||
xcb_connection_t *connection;
|
||||
GstVulkanDisplayXCB *ret;
|
||||
int screen_no = 0;
|
||||
|
||||
GST_DEBUG_CATEGORY_GET (gst_vulkan_display_debug, "gldisplay");
|
||||
|
||||
ret = g_object_new (GST_TYPE_VULKAN_DISPLAY_XCB, NULL);
|
||||
|
||||
ret->platform_handle.connection = connection = xcb_connect (NULL, &screen_no);
|
||||
if (connection == NULL || xcb_connection_has_error (connection)) {
|
||||
GST_ERROR_OBJECT (ret,
|
||||
"Failed to open XCB display connection with name, \'%s\'", name);
|
||||
gst_object_unref (ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret->screen = _get_screen_from_connection (connection, screen_no);
|
||||
ret->platform_handle.root = ret->screen->root;
|
||||
ret->event_source = xcb_event_source_new (ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_vulkan_display_xcb_new_with_display:
|
||||
* @display: an existing, xcb display
|
||||
*
|
||||
* Creates a new display connection from a XCB Display.
|
||||
*
|
||||
* Returns: (transfer full): a new #GstVulkanDisplayXCB
|
||||
*/
|
||||
GstVulkanDisplayXCB *
|
||||
gst_vulkan_display_xcb_new_with_connection (xcb_connection_t * connection,
|
||||
int screen_no)
|
||||
{
|
||||
GstVulkanDisplayXCB *ret;
|
||||
|
||||
g_return_val_if_fail (connection != NULL, NULL);
|
||||
|
||||
GST_DEBUG_CATEGORY_GET (gst_vulkan_display_debug, "gldisplay");
|
||||
|
||||
ret = g_object_new (GST_TYPE_VULKAN_DISPLAY_XCB, NULL);
|
||||
|
||||
ret->platform_handle.connection = connection;
|
||||
ret->screen = _get_screen_from_connection (connection, screen_no);
|
||||
ret->platform_handle.root = ret->screen->root;
|
||||
ret->foreign_display = TRUE;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gpointer
|
||||
gst_vulkan_display_xcb_get_handle (GstVulkanDisplay * display)
|
||||
{
|
||||
return (gpointer) GST_VULKAN_DISPLAY_XCB (display)->platform_handle.
|
||||
connection;
|
||||
}
|
||||
|
||||
static gpointer
|
||||
gst_vulkan_display_xcb_get_platform_handle (GstVulkanDisplay * display)
|
||||
{
|
||||
return &GST_VULKAN_DISPLAY_XCB (display)->platform_handle;
|
||||
}
|
84
ext/vulkan/xcb/vkdisplay_xcb.h
Normal file
84
ext/vulkan/xcb/vkdisplay_xcb.h
Normal file
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2013 Matthew Waters <ystreet00@gmail.com>
|
||||
*
|
||||
* 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_VULKAN_DISPLAY_XCB_H__
|
||||
#define __GST_VULKAN_DISPLAY_XCB_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
#include <xcb/xcb.h>
|
||||
|
||||
#include <vk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
GType gst_vulkan_display_xcb_get_type (void);
|
||||
|
||||
#define GST_TYPE_VULKAN_DISPLAY_XCB (gst_vulkan_display_xcb_get_type())
|
||||
#define GST_VULKAN_DISPLAY_XCB(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VULKAN_DISPLAY_XCB,GstVulkanDisplayXCB))
|
||||
#define GST_VULKAN_DISPLAY_XCB_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_VULKAN_DISPLAY_XCB,GstVulkanDisplayXCBClass))
|
||||
#define GST_IS_VULKAN_DISPLAY_XCB(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VULKAN_DISPLAY_XCB))
|
||||
#define GST_IS_VULKAN_DISPLAY_XCB_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_VULKAN_DISPLAY_XCB))
|
||||
#define GST_VULKAN_DISPLAY_XCB_CAST(obj) ((GstVulkanDisplayXCB*)(obj))
|
||||
|
||||
typedef struct _GstVulkanDisplayXCB GstVulkanDisplayXCB;
|
||||
typedef struct _GstVulkanDisplayXCBClass GstVulkanDisplayXCBClass;
|
||||
|
||||
#define GST_VULKAN_DISPLAY_XCB_CONNECTION(d) (GST_VULKAN_DISPLAY_XCB(d)->platform_handle.connection)
|
||||
#define GST_VULKAN_DISPLAY_XCB_ROOT_WINDOW(d) (GST_VULKAN_DISPLAY_XCB(d)->platform_handle.root)
|
||||
#define GST_VULKAN_DISPLAY_XCB_SCREEN(d) (GST_VULKAN_DISPLAY_XCB(d)->screen)
|
||||
|
||||
struct _GstVkPlatformHandleXCBKHR
|
||||
{
|
||||
xcb_connection_t* connection;
|
||||
xcb_window_t root;
|
||||
};
|
||||
|
||||
/**
|
||||
* GstVulkanDisplayXCB:
|
||||
*
|
||||
* the contents of a #GstVulkanDisplayXCB are private and should only be accessed
|
||||
* through the provided API
|
||||
*/
|
||||
struct _GstVulkanDisplayXCB
|
||||
{
|
||||
GstVulkanDisplay parent;
|
||||
|
||||
/* <private> */
|
||||
gboolean foreign_display;
|
||||
|
||||
struct _GstVkPlatformHandleXCBKHR platform_handle;
|
||||
xcb_screen_t *screen;
|
||||
|
||||
GSource *event_source;
|
||||
};
|
||||
|
||||
struct _GstVulkanDisplayXCBClass
|
||||
{
|
||||
GstVulkanDisplayClass object_class;
|
||||
};
|
||||
|
||||
GstVulkanDisplayXCB * gst_vulkan_display_xcb_new (const gchar * name);
|
||||
GstVulkanDisplayXCB * gst_vulkan_display_xcb_new_with_connection (xcb_connection_t * connection,
|
||||
int screen_no);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_VULKAN_DISPLAY_XCB_H__ */
|
243
ext/vulkan/xcb/vkwindow_xcb.c
Normal file
243
ext/vulkan/xcb/vkwindow_xcb.c
Normal file
|
@ -0,0 +1,243 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
|
||||
*
|
||||
* 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 <gst/gst.h>
|
||||
#include <locale.h>
|
||||
|
||||
#include "vkwindow_xcb.h"
|
||||
#include "vkdisplay_xcb.h"
|
||||
|
||||
#define GST_VULKAN_WINDOW_XCB_GET_PRIVATE(o) \
|
||||
(G_TYPE_INSTANCE_GET_PRIVATE((o), GST_TYPE_VULKAN_WINDOW_XCB, GstVulkanWindowXCBPrivate))
|
||||
|
||||
#define GST_CAT_DEFAULT gst_vulkan_window_xcb_debug
|
||||
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
|
||||
|
||||
static void
|
||||
_init_debug (void)
|
||||
{
|
||||
static volatile gsize _init = 0;
|
||||
|
||||
if (g_once_init_enter (&_init)) {
|
||||
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "vulkanwindowxcb", 0,
|
||||
"Vulkan XCB Window");
|
||||
g_once_init_leave (&_init, 1);
|
||||
}
|
||||
}
|
||||
|
||||
#define gst_vulkan_window_xcb_parent_class parent_class
|
||||
G_DEFINE_TYPE_WITH_CODE (GstVulkanWindowXCB, gst_vulkan_window_xcb,
|
||||
GST_TYPE_VULKAN_WINDOW, _init_debug ());
|
||||
|
||||
gboolean gst_vulkan_window_xcb_handle_event (GstVulkanWindowXCB * window_xcb);
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
};
|
||||
|
||||
struct _GstVulkanWindowXCBPrivate
|
||||
{
|
||||
gboolean activate;
|
||||
gboolean activate_result;
|
||||
|
||||
gint preferred_width;
|
||||
gint preferred_height;
|
||||
|
||||
xcb_intern_atom_reply_t *atom_wm_delete_window;
|
||||
};
|
||||
|
||||
static gpointer gst_vulkan_window_xcb_get_platform_window (GstVulkanWindow *
|
||||
window);
|
||||
gboolean gst_vulkan_window_xcb_open (GstVulkanWindow * window, GError ** error);
|
||||
void gst_vulkan_window_xcb_close (GstVulkanWindow * window);
|
||||
|
||||
static void
|
||||
gst_vulkan_window_xcb_finalize (GObject * object)
|
||||
{
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vulkan_window_xcb_class_init (GstVulkanWindowXCBClass * klass)
|
||||
{
|
||||
GObjectClass *obj_class = G_OBJECT_CLASS (klass);
|
||||
GstVulkanWindowClass *window_class = (GstVulkanWindowClass *) klass;
|
||||
|
||||
g_type_class_add_private (klass, sizeof (GstVulkanWindowXCBPrivate));
|
||||
|
||||
obj_class->finalize = gst_vulkan_window_xcb_finalize;
|
||||
|
||||
window_class->open = GST_DEBUG_FUNCPTR (gst_vulkan_window_xcb_open);
|
||||
window_class->close = GST_DEBUG_FUNCPTR (gst_vulkan_window_xcb_close);
|
||||
window_class->get_platform_handle = gst_vulkan_window_xcb_get_platform_window;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vulkan_window_xcb_init (GstVulkanWindowXCB * window)
|
||||
{
|
||||
window->priv = GST_VULKAN_WINDOW_XCB_GET_PRIVATE (window);
|
||||
}
|
||||
|
||||
/* Must be called in the gl thread */
|
||||
GstVulkanWindowXCB *
|
||||
gst_vulkan_window_xcb_new (GstVulkanDisplay * display)
|
||||
{
|
||||
_init_debug ();
|
||||
|
||||
if ((gst_vulkan_display_get_handle_type (display) &
|
||||
GST_VULKAN_DISPLAY_TYPE_XCB)
|
||||
== GST_VULKAN_DISPLAY_TYPE_NONE) {
|
||||
GST_INFO ("Wrong display type %u for this window type %u", display->type,
|
||||
GST_VULKAN_DISPLAY_TYPE_XCB);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return g_object_new (GST_TYPE_VULKAN_WINDOW_XCB, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vulkan_window_xcb_show (GstVulkanWindow * window)
|
||||
{
|
||||
GstVulkanWindowXCB *window_xcb = GST_VULKAN_WINDOW_XCB (window);
|
||||
GstVulkanDisplayXCB *display_xcb = GST_VULKAN_DISPLAY_XCB (window->display);
|
||||
xcb_connection_t *connection = display_xcb->platform_handle.connection;
|
||||
|
||||
if (!window_xcb->visible) {
|
||||
xcb_map_window (connection, window_xcb->win_id);
|
||||
window_xcb->visible = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vulkan_window_xcb_hide (GstVulkanWindow * window)
|
||||
{
|
||||
GstVulkanWindowXCB *window_xcb = GST_VULKAN_WINDOW_XCB (window);
|
||||
GstVulkanDisplayXCB *display_xcb = GST_VULKAN_DISPLAY_XCB (window->display);
|
||||
xcb_connection_t *connection = display_xcb->platform_handle.connection;
|
||||
|
||||
if (window_xcb->visible) {
|
||||
xcb_unmap_window (connection, window_xcb->win_id);
|
||||
window_xcb->visible = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_vulkan_window_xcb_create_window (GstVulkanWindowXCB * window_xcb)
|
||||
{
|
||||
GstVulkanDisplayXCB *display_xcb;
|
||||
xcb_connection_t *connection;
|
||||
xcb_screen_t *screen;
|
||||
xcb_window_t root_window;
|
||||
uint32_t value_mask, value_list[32];
|
||||
xcb_intern_atom_cookie_t cookie, cookie2;
|
||||
xcb_intern_atom_reply_t *reply, *reply2;
|
||||
// const gchar *title = "OpenGL renderer";
|
||||
gint x = 0, y = 0, width = 320, height = 240;
|
||||
|
||||
display_xcb =
|
||||
GST_VULKAN_DISPLAY_XCB (GST_VULKAN_WINDOW (window_xcb)->display);
|
||||
connection = GST_VULKAN_DISPLAY_XCB_CONNECTION (display_xcb);
|
||||
root_window = GST_VULKAN_DISPLAY_XCB_ROOT_WINDOW (display_xcb);
|
||||
screen = GST_VULKAN_DISPLAY_XCB_SCREEN (display_xcb);
|
||||
|
||||
window_xcb->win_id = xcb_generate_id (connection);
|
||||
|
||||
value_mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
|
||||
value_list[0] = screen->black_pixel;
|
||||
value_list[1] = XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_EXPOSURE;
|
||||
|
||||
xcb_create_window (connection, XCB_COPY_FROM_PARENT, window_xcb->win_id,
|
||||
root_window, x, y, width, height, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT,
|
||||
screen->root_visual, value_mask, value_list);
|
||||
|
||||
GST_LOG_OBJECT (window_xcb, "gl window id: %p",
|
||||
(gpointer) (guintptr) window_xcb->win_id);
|
||||
GST_LOG_OBJECT (window_xcb, "gl window props: x:%d y:%d", x, y);
|
||||
|
||||
/* Magic code that will send notification when window is destroyed */
|
||||
cookie = xcb_intern_atom (connection, 1, 12, "WM_PROTOCOLS");
|
||||
reply = xcb_intern_atom_reply (connection, cookie, 0);
|
||||
|
||||
cookie2 = xcb_intern_atom (connection, 0, 16, "WM_DELETE_WINDOW");
|
||||
reply2 = xcb_intern_atom_reply (connection, cookie2, 0);
|
||||
|
||||
xcb_change_property (connection, XCB_PROP_MODE_REPLACE, window_xcb->win_id,
|
||||
reply->atom, 4, 32, 1, &reply2->atom);
|
||||
g_free (reply);
|
||||
g_free (reply2);
|
||||
|
||||
gst_vulkan_window_xcb_show (GST_VULKAN_WINDOW (window_xcb));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gpointer
|
||||
gst_vulkan_window_xcb_get_platform_window (GstVulkanWindow * window)
|
||||
{
|
||||
return &GST_VULKAN_WINDOW_XCB (window)->win_id;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_vulkan_window_xcb_open (GstVulkanWindow * window, GError ** error)
|
||||
{
|
||||
GstVulkanWindowXCB *window_xcb = GST_VULKAN_WINDOW_XCB (window);
|
||||
GstVulkanDisplayXCB *display_xcb = (GstVulkanDisplayXCB *) window->display;
|
||||
xcb_connection_t *connection;
|
||||
|
||||
connection = display_xcb->platform_handle.connection;
|
||||
if (connection == NULL) {
|
||||
g_set_error (error, GST_VULKAN_WINDOW_ERROR,
|
||||
GST_VULKAN_WINDOW_ERROR_RESOURCE_UNAVAILABLE,
|
||||
"Failed to connect to X display server with XCB");
|
||||
goto failure;
|
||||
}
|
||||
|
||||
if (!GST_VULKAN_WINDOW_CLASS (parent_class)->open (window, error))
|
||||
return FALSE;
|
||||
|
||||
return gst_vulkan_window_xcb_create_window (window_xcb);
|
||||
|
||||
failure:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
gst_vulkan_window_xcb_close (GstVulkanWindow * window)
|
||||
{
|
||||
GstVulkanWindowXCB *window_xcb = GST_VULKAN_WINDOW_XCB (window);
|
||||
GstVulkanDisplayXCB *display_xcb = (GstVulkanDisplayXCB *) window->display;
|
||||
xcb_connection_t *connection =
|
||||
GST_VULKAN_DISPLAY_XCB_CONNECTION (display_xcb);
|
||||
|
||||
if (connection) {
|
||||
gst_vulkan_window_xcb_hide (window);
|
||||
|
||||
g_free (window_xcb->priv->atom_wm_delete_window);
|
||||
window_xcb->priv->atom_wm_delete_window = NULL;
|
||||
GST_DEBUG ("display receiver closed");
|
||||
}
|
||||
|
||||
GST_VULKAN_WINDOW_CLASS (parent_class)->close (window);
|
||||
}
|
86
ext/vulkan/xcb/vkwindow_xcb.h
Normal file
86
ext/vulkan/xcb/vkwindow_xcb.h
Normal file
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2012 Matthew Waters <ystreet00@gmail.com>
|
||||
*
|
||||
* 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_VULKAN_WINDOW_XCB_H__
|
||||
#define __GST_VULKAN_WINDOW_XCB_H__
|
||||
|
||||
#include <xcb/xcb.h>
|
||||
|
||||
#include <vk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_VULKAN_WINDOW_XCB (gst_vulkan_window_xcb_get_type())
|
||||
#define GST_VULKAN_WINDOW_XCB(o) (G_TYPE_CHECK_INSTANCE_CAST((o), GST_TYPE_VULKAN_WINDOW_XCB, GstVulkanWindowXCB))
|
||||
#define GST_VULKAN_WINDOW_XCB_CLASS(k) (G_TYPE_CHECK_CLASS((k), GST_TYPE_VULKAN_WINDOW_XCB, GstVulkanWindowXCBClass))
|
||||
#define GST_IS_VULKAN_WINDOW_XCB(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), GST_TYPE_VULKAN_WINDOW_XCB))
|
||||
#define GST_IS_VULKAN_WINDOW_XCB_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), GST_TYPE_VULKAN_WINDOW_XCB))
|
||||
#define GST_VULKAN_WINDOW_XCB_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GST_TYPE_VULKAN_WINDOW_XCB, GstVulkanWindowXCBClass))
|
||||
|
||||
typedef struct _GstVulkanWindowXCB GstVulkanWindowXCB;
|
||||
typedef struct _GstVulkanWindowXCBPrivate GstVulkanWindowXCBPrivate;
|
||||
typedef struct _GstVulkanWindowXCBClass GstVulkanWindowXCBClass;
|
||||
|
||||
/**
|
||||
* GstVulkanWindowXCB:
|
||||
*
|
||||
* Opaque #GstVulkanWindowXCB object
|
||||
*/
|
||||
struct _GstVulkanWindowXCB
|
||||
{
|
||||
/*< private >*/
|
||||
GstVulkanWindow parent;
|
||||
|
||||
/* X window */
|
||||
xcb_window_t win_id;
|
||||
|
||||
gint visible :1;
|
||||
|
||||
/*< private >*/
|
||||
GstVulkanWindowXCBPrivate *priv;
|
||||
|
||||
gpointer _reserved[GST_PADDING];
|
||||
};
|
||||
|
||||
/**
|
||||
* GstVulkanWindowXCBClass:
|
||||
*
|
||||
* Opaque #GstVulkanWindowXCBClass object
|
||||
*/
|
||||
struct _GstVulkanWindowXCBClass {
|
||||
/*< private >*/
|
||||
GstVulkanWindowClass parent_class;
|
||||
|
||||
/*< private >*/
|
||||
gpointer _reserved[GST_PADDING_LARGE];
|
||||
};
|
||||
|
||||
GType gst_vulkan_window_xcb_get_type (void);
|
||||
|
||||
GstVulkanWindowXCB * gst_vulkan_window_xcb_new (GstVulkanDisplay * display);
|
||||
|
||||
void gst_vulkan_window_xcb_trap_x_errors (void);
|
||||
gint gst_vulkan_window_xcb_untrap_x_errors (void);
|
||||
|
||||
gboolean gst_vulkan_window_xcb_create_window (GstVulkanWindowXCB * window_xcb);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_VULKAN_WINDOW_XCB_H__ */
|
251
ext/vulkan/xcb/xcb_event_source.c
Normal file
251
ext/vulkan/xcb/xcb_event_source.c
Normal file
|
@ -0,0 +1,251 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2012 Matthew Waters <ystreet00@gmail.com>
|
||||
*
|
||||
* 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 <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "xcb_event_source.h"
|
||||
#include "vkdisplay_xcb.h"
|
||||
#include "vkwindow_xcb.h"
|
||||
|
||||
static gint
|
||||
_compare_xcb_window (GstVulkanWindowXCB * window_xcb, xcb_window_t * window_id)
|
||||
{
|
||||
return window_xcb->win_id - *window_id;
|
||||
}
|
||||
|
||||
static GstVulkanWindowXCB *
|
||||
_find_window_from_xcb_window (GstVulkanDisplayXCB * display_xcb,
|
||||
xcb_window_t window_id)
|
||||
{
|
||||
GstVulkanDisplay *display = GST_VULKAN_DISPLAY (display_xcb);
|
||||
GstVulkanWindowXCB *ret = NULL;
|
||||
GList *l;
|
||||
|
||||
if (!window_id)
|
||||
return NULL;
|
||||
|
||||
GST_OBJECT_LOCK (display);
|
||||
l = g_list_find_custom (display->windows, &window_id,
|
||||
(GCompareFunc) _compare_xcb_window);
|
||||
if (l)
|
||||
ret = gst_object_ref (l->data);
|
||||
GST_OBJECT_UNLOCK (display);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_xcb_handle_event (GstVulkanDisplayXCB * display_xcb)
|
||||
{
|
||||
xcb_connection_t *connection =
|
||||
GST_VULKAN_DISPLAY_XCB_CONNECTION (display_xcb);
|
||||
xcb_generic_event_t *event;
|
||||
gboolean ret = TRUE;
|
||||
|
||||
while ((event = xcb_poll_for_event (connection))) {
|
||||
uint8_t event_code = event->response_type & 0x7f;
|
||||
|
||||
switch (event_code) {
|
||||
case XCB_CLIENT_MESSAGE:{
|
||||
xcb_client_message_event_t *client_event;
|
||||
xcb_intern_atom_cookie_t cookie;
|
||||
xcb_intern_atom_reply_t *reply;
|
||||
|
||||
client_event = (xcb_client_message_event_t *) event;
|
||||
cookie = xcb_intern_atom (connection, 0, 16, "WM_DELETE_WINDOW");
|
||||
reply = xcb_intern_atom_reply (connection, cookie, 0);
|
||||
|
||||
if (client_event->data.data32[0] == reply->atom) {
|
||||
GstVulkanWindowXCB *window_xcb;
|
||||
|
||||
window_xcb =
|
||||
_find_window_from_xcb_window (display_xcb, client_event->window);
|
||||
/* TODO: actually quit */
|
||||
ret = FALSE;
|
||||
#if 0
|
||||
if (display->close)
|
||||
display->close (display->close_data);
|
||||
#endif
|
||||
gst_object_unref (window_xcb);
|
||||
}
|
||||
|
||||
g_free (reply);
|
||||
break;
|
||||
}
|
||||
#if 0
|
||||
case CreateNotify:
|
||||
case ConfigureNotify:
|
||||
#if 0
|
||||
gst_vulkan_window_resize (window, event.xconfigure.width,
|
||||
event.xconfigure.height);
|
||||
#endif
|
||||
break;
|
||||
case DestroyNotify:
|
||||
break;
|
||||
|
||||
case Expose:
|
||||
/* non-zero means that other Expose follows
|
||||
* so just wait for the last one
|
||||
* in theory we should not receive non-zero because
|
||||
* we have no sub areas here but just in case */
|
||||
if (event.xexpose.count != 0) {
|
||||
break;
|
||||
}
|
||||
#if 0
|
||||
/* We need to redraw on expose */
|
||||
if (window->draw) {
|
||||
context = gst_vulkan_window_get_context (window);
|
||||
context_class = GST_VULKAN_CONTEXT_GET_CLASS (context);
|
||||
|
||||
window->draw (window->draw_data);
|
||||
context_class->swap_buffers (context);
|
||||
|
||||
gst_object_unref (context);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case VisibilityNotify:
|
||||
/* actually nothing to do here */
|
||||
break;
|
||||
#if 0
|
||||
case KeyPress:
|
||||
case KeyRelease:
|
||||
keysym = XkbKeycodeToKeysym (window_xcb->device,
|
||||
event.xkey.keycode, 0, 0);
|
||||
key_str = XKeysymToString (keysym);
|
||||
key_data = g_slice_new (struct key_event);
|
||||
key_data->window = window;
|
||||
key_data->key_str = XKeysymToString (keysym);
|
||||
key_data->event_type =
|
||||
event.type == KeyPress ? "key-press" : "key-release";
|
||||
GST_DEBUG ("input event key %d pressed over window at %d,%d (%s)",
|
||||
event.xkey.keycode, event.xkey.x, event.xkey.y, key_str);
|
||||
g_main_context_invoke (window->navigation_context,
|
||||
(GSourceFunc) gst_vulkan_window_key_event_cb, key_data);
|
||||
break;
|
||||
case ButtonPress:
|
||||
case ButtonRelease:
|
||||
GST_DEBUG ("input event mouse button %d pressed over window at %d,%d",
|
||||
event.xbutton.button, event.xbutton.x, event.xbutton.y);
|
||||
mouse_data = g_slice_new (struct mouse_event);
|
||||
mouse_data->window = window;
|
||||
mouse_data->event_type =
|
||||
event.type ==
|
||||
ButtonPress ? "mouse-button-press" : "mouse-button-release";
|
||||
mouse_data->button = event.xbutton.button;
|
||||
mouse_data->posx = (double) event.xbutton.x;
|
||||
mouse_data->posy = (double) event.xbutton.y;
|
||||
|
||||
g_main_context_invoke (window->navigation_context,
|
||||
(GSourceFunc) gst_vulkan_window_mouse_event_cb, mouse_data);
|
||||
break;
|
||||
case MotionNotify:
|
||||
GST_DEBUG ("input event pointer moved over window at %d,%d",
|
||||
event.xmotion.x, event.xmotion.y);
|
||||
mouse_data = g_slice_new (struct mouse_event);
|
||||
mouse_data->window = window;
|
||||
mouse_data->event_type = "mouse-move";
|
||||
mouse_data->button = 0;
|
||||
mouse_data->posx = (double) event.xbutton.x;
|
||||
mouse_data->posy = (double) event.xbutton.y;
|
||||
|
||||
g_main_context_invoke (window->navigation_context, (GSourceFunc)
|
||||
gst_vulkan_window_mouse_event_cb, mouse_data);
|
||||
break;
|
||||
#endif
|
||||
#endif
|
||||
default:
|
||||
GST_DEBUG ("unhandled XCB type: %u", event_code);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
typedef struct _XCBEventSource
|
||||
{
|
||||
GSource source;
|
||||
GPollFD pfd;
|
||||
uint32_t mask;
|
||||
GstVulkanDisplayXCB *display_xcb;
|
||||
} XCBEventSource;
|
||||
|
||||
static gboolean
|
||||
xcb_event_source_prepare (GSource * base, gint * timeout)
|
||||
{
|
||||
*timeout = -1;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
xcb_event_source_check (GSource * base)
|
||||
{
|
||||
XCBEventSource *source = (XCBEventSource *) base;
|
||||
gboolean retval;
|
||||
|
||||
retval = source->pfd.revents;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
xcb_event_source_dispatch (GSource * base, GSourceFunc callback, gpointer data)
|
||||
{
|
||||
XCBEventSource *source = (XCBEventSource *) base;
|
||||
|
||||
gboolean ret = _xcb_handle_event (source->display_xcb);
|
||||
|
||||
if (callback)
|
||||
callback (data);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static GSourceFuncs xcb_event_source_funcs = {
|
||||
xcb_event_source_prepare,
|
||||
xcb_event_source_check,
|
||||
xcb_event_source_dispatch,
|
||||
NULL
|
||||
};
|
||||
|
||||
GSource *
|
||||
xcb_event_source_new (GstVulkanDisplayXCB * display_xcb)
|
||||
{
|
||||
xcb_connection_t *connection;
|
||||
XCBEventSource *source;
|
||||
|
||||
connection = GST_VULKAN_DISPLAY_XCB_CONNECTION (display_xcb);
|
||||
g_return_val_if_fail (connection != NULL, NULL);
|
||||
|
||||
source = (XCBEventSource *)
|
||||
g_source_new (&xcb_event_source_funcs, sizeof (XCBEventSource));
|
||||
source->display_xcb = display_xcb;
|
||||
source->pfd.fd = xcb_get_file_descriptor (connection);
|
||||
source->pfd.events = G_IO_IN | G_IO_ERR;
|
||||
g_source_add_poll (&source->source, &source->pfd);
|
||||
|
||||
return &source->source;
|
||||
}
|
30
ext/vulkan/xcb/xcb_event_source.h
Normal file
30
ext/vulkan/xcb/xcb_event_source.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2012 Matthew Waters <ystreet00@gmail.com>
|
||||
*
|
||||
* 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 __VULKAN_XCB_EVENT_SOURCE_H__
|
||||
#define __VULKAN_XCB_EVENT_SOURCE_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
#include "vkdisplay_xcb.h"
|
||||
|
||||
GSource *
|
||||
xcb_event_source_new (GstVulkanDisplayXCB *display_xcb);
|
||||
|
||||
#endif /* __VULKAN_XCB_EVENT_SOURCE_H__ */
|
Loading…
Reference in a new issue