diff --git a/ext/vulkan/Makefile.am b/ext/vulkan/Makefile.am index 6c87b8c432..57b1af0081 100644 --- a/ext/vulkan/Makefile.am +++ b/ext/vulkan/Makefile.am @@ -31,6 +31,7 @@ noinst_HEADERS = \ vksink.h \ vkswapper.h \ vkutils.h \ + vkutils_private.h \ vkwindow.h libgstvulkan_la_CFLAGS = \ diff --git a/ext/vulkan/vk.h b/ext/vulkan/vk.h index 9e98fe17c1..556de5cd30 100644 --- a/ext/vulkan/vk.h +++ b/ext/vulkan/vk.h @@ -41,5 +41,6 @@ #include "vkswapper.h" #include "vkmemory.h" #include "vkimagememory.h" +#include "vkutils.h" #endif /* _VK_H_ */ diff --git a/ext/vulkan/vkdevice.c b/ext/vulkan/vkdevice.c index 251f39dfdd..0eeb4621c7 100644 --- a/ext/vulkan/vkdevice.c +++ b/ext/vulkan/vkdevice.c @@ -23,7 +23,7 @@ #endif #include "vkdevice.h" -#include "vkutils.h" +#include "vkutils_private.h" #include diff --git a/ext/vulkan/vkdisplay.c b/ext/vulkan/vkdisplay.c index ad9f1d0360..dcf3b55a94 100644 --- a/ext/vulkan/vkdisplay.c +++ b/ext/vulkan/vkdisplay.c @@ -34,6 +34,7 @@ #include "xcb/vkdisplay_xcb.h" #endif +GST_DEBUG_CATEGORY_STATIC (GST_CAT_CONTEXT); #define GST_CAT_DEFAULT gst_vulkan_display_debug GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); @@ -45,6 +46,7 @@ _init_debug (void) if (g_once_init_enter (&_init)) { GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "vulkandisplay", 0, "Vulkan display"); + GST_DEBUG_CATEGORY_GET (GST_CAT_CONTEXT, "GST_CONTEXT"); g_once_init_leave (&_init, 1); } } @@ -323,3 +325,60 @@ gst_vulkan_display_remove_window (GstVulkanDisplay * display, return ret; } + +/** + * gst_context_set_vulkan_display: + * @context: a #GstContext + * @display: a #GstVulkanDisplay + * + * Sets @display on @context + * + * Since: 1.10 + */ +void +gst_context_set_vulkan_display (GstContext * context, + GstVulkanDisplay * display) +{ + GstStructure *s; + + g_return_if_fail (context != NULL); + g_return_if_fail (gst_context_is_writable (context)); + + if (display) + GST_CAT_LOG (GST_CAT_CONTEXT, + "setting GstVulkanDisplay(%" GST_PTR_FORMAT ") on context(%" + GST_PTR_FORMAT ")", display, context); + + s = gst_context_writable_structure (context); + gst_structure_set (s, GST_VULKAN_DISPLAY_CONTEXT_TYPE_STR, + GST_TYPE_VULKAN_DISPLAY, display, NULL); +} + +/** + * gst_context_get_vulkan_display: + * @context: a #GstContext + * @display: resulting #GstVulkanDisplay + * + * Returns: Whether @display was in @context + * + * Since: 1.10 + */ +gboolean +gst_context_get_vulkan_display (GstContext * context, + GstVulkanDisplay ** display) +{ + const GstStructure *s; + gboolean ret; + + g_return_val_if_fail (display != NULL, FALSE); + g_return_val_if_fail (context != NULL, FALSE); + + s = gst_context_get_structure (context); + ret = gst_structure_get (s, GST_VULKAN_DISPLAY_CONTEXT_TYPE_STR, + GST_TYPE_VULKAN_DISPLAY, display, NULL); + + GST_CAT_LOG (GST_CAT_CONTEXT, "got GstVulkanDisplay(%" GST_PTR_FORMAT + ") from context(%" GST_PTR_FORMAT ")", *display, context); + + return ret; +} diff --git a/ext/vulkan/vkdisplay.h b/ext/vulkan/vkdisplay.h index d48eeccde2..9a1f65a87b 100644 --- a/ext/vulkan/vkdisplay.h +++ b/ext/vulkan/vkdisplay.h @@ -39,6 +39,8 @@ G_BEGIN_DECLS #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); +#define GST_VULKAN_DISPLAY_CONTEXT_TYPE_STR "gst.vulkan.display" + typedef enum { GST_VULKAN_DISPLAY_TYPE_NONE = 0, @@ -83,15 +85,21 @@ struct _GstVulkanDisplayClass GstVulkanWindow * (*create_window) (GstVulkanDisplay * display); }; -GstVulkanDisplay *gst_vulkan_display_new (void); +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); +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); + +gboolean gst_context_get_vulkan_display (GstContext * context, + GstVulkanDisplay ** display); +void gst_context_set_vulkan_display (GstContext * context, + GstVulkanDisplay * display); /* GstVulkanWindow usage only */ -gboolean gst_vulkan_display_remove_window (GstVulkanDisplay * display, GstVulkanWindow * window); +gboolean gst_vulkan_display_remove_window (GstVulkanDisplay * display, GstVulkanWindow * window); + G_END_DECLS diff --git a/ext/vulkan/vkinstance.c b/ext/vulkan/vkinstance.c index e9fb559a1b..7ded8f91d0 100644 --- a/ext/vulkan/vkinstance.c +++ b/ext/vulkan/vkinstance.c @@ -23,7 +23,7 @@ #endif #include "vkinstance.h" -#include "vkutils.h" +#include "vkutils_private.h" #include @@ -44,13 +44,15 @@ static const char *instance_validation_layers[] = { #define GST_CAT_DEFAULT gst_vulkan_instance_debug GST_DEBUG_CATEGORY (GST_CAT_DEFAULT); GST_DEBUG_CATEGORY (GST_VULKAN_DEBUG_CAT); +GST_DEBUG_CATEGORY (GST_CAT_CONTEXT); #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")); + "vulkandebug", 0, "Vulkan Debug"); + GST_DEBUG_CATEGORY_GET (GST_CAT_CONTEXT, "GST_CONTEXT")); static void gst_vulkan_instance_finalize (GObject * object); @@ -332,3 +334,60 @@ gst_vulkan_instance_get_proc_address (GstVulkanInstance * instance, return vkGetInstanceProcAddr (instance->instance, name); } + +/** + * gst_context_set_vulkan_instance: + * @context: a #GstContext + * @instance: a #GstVulkanInstance + * + * Sets @instance on @context + * + * Since: 1.10 + */ +void +gst_context_set_vulkan_instance (GstContext * context, + GstVulkanInstance * instance) +{ + GstStructure *s; + + g_return_if_fail (context != NULL); + g_return_if_fail (gst_context_is_writable (context)); + + if (instance) + GST_CAT_LOG (GST_CAT_CONTEXT, + "setting GstVulkanInstance(%" GST_PTR_FORMAT ") on context(%" + GST_PTR_FORMAT ")", instance, context); + + s = gst_context_writable_structure (context); + gst_structure_set (s, GST_VULKAN_INSTANCE_CONTEXT_TYPE_STR, + GST_TYPE_VULKAN_INSTANCE, instance, NULL); +} + +/** + * gst_context_get_vulkan_instance: + * @context: a #GstContext + * @instance: resulting #GstVulkanInstance + * + * Returns: Whether @instance was in @context + * + * Since: 1.10 + */ +gboolean +gst_context_get_vulkan_instance (GstContext * context, + GstVulkanInstance ** instance) +{ + const GstStructure *s; + gboolean ret; + + g_return_val_if_fail (instance != NULL, FALSE); + g_return_val_if_fail (context != NULL, FALSE); + + s = gst_context_get_structure (context); + ret = gst_structure_get (s, GST_VULKAN_INSTANCE_CONTEXT_TYPE_STR, + GST_TYPE_VULKAN_INSTANCE, instance, NULL); + + GST_CAT_LOG (GST_CAT_CONTEXT, "got GstVulkanInstance(%" GST_PTR_FORMAT + ") from context(%" GST_PTR_FORMAT ")", *instance, context); + + return ret; +} diff --git a/ext/vulkan/vkinstance.h b/ext/vulkan/vkinstance.h index d8e7438e9d..07022851a0 100644 --- a/ext/vulkan/vkinstance.h +++ b/ext/vulkan/vkinstance.h @@ -33,6 +33,8 @@ G_BEGIN_DECLS #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); +#define GST_VULKAN_INSTANCE_CONTEXT_TYPE_STR "gst.vulkan.instance" + struct _GstVulkanInstance { GstObject parent; @@ -61,6 +63,11 @@ gboolean gst_vulkan_instance_open (GstVulkanInstance * gpointer gst_vulkan_instance_get_proc_address (GstVulkanInstance * instance, const gchar * name); +void gst_context_set_vulkan_instance (GstContext * context, + GstVulkanInstance * instance); +gboolean gst_context_get_vulkan_instance (GstContext * context, + GstVulkanInstance ** instance); + G_END_DECLS #endif /* _VK_INSTANCE_H_ */ diff --git a/ext/vulkan/vksink.c b/ext/vulkan/vksink.c index f969f8bb17..81a77c23af 100644 --- a/ext/vulkan/vksink.c +++ b/ext/vulkan/vksink.c @@ -202,22 +202,32 @@ gst_vulkan_sink_get_property (GObject * object, guint prop_id, static gboolean gst_vulkan_sink_query (GstBaseSink * bsink, GstQuery * query) { -// GstVulkanSink *vk_sink = GST_VULKAN_SINK (bsink); + GstVulkanSink *vk_sink = GST_VULKAN_SINK (bsink); gboolean res = FALSE; switch (GST_QUERY_TYPE (query)) { + case GST_QUERY_CONTEXT:{ + res = gst_vulkan_handle_context_query (GST_ELEMENT (vk_sink), query, + &vk_sink->display, &vk_sink->instance); + + if (res) + return res; + break; + } default: - res = GST_BASE_SINK_CLASS (parent_class)->query (bsink, query); break; } - return res; + return GST_BASE_SINK_CLASS (parent_class)->query (bsink, query); } static void gst_vulkan_sink_set_context (GstElement * element, GstContext * context) { -// GstVulkanSink *vk_sink = GST_VULKAN_SINK (element); + GstVulkanSink *vk_sink = GST_VULKAN_SINK (element); + + gst_vulkan_handle_set_context (element, context, &vk_sink->display, + &vk_sink->instance); GST_ELEMENT_CLASS (parent_class)->set_context (element, context); } @@ -235,12 +245,19 @@ gst_vulkan_sink_change_state (GstElement * element, GstStateChange transition) switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: - vk_sink->instance = gst_vulkan_instance_new (); + if (!gst_vulkan_ensure_element_data (element, &vk_sink->display, + &vk_sink->instance)) { + GST_ELEMENT_ERROR (vk_sink, RESOURCE, NOT_FOUND, + ("Failed to retreive vulkan instance/display"), (NULL)); + return GST_STATE_CHANGE_FAILURE; + } + 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, @@ -248,12 +265,6 @@ gst_vulkan_sink_change_state (GstElement * element, GstStateChange transition) 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, diff --git a/ext/vulkan/vkutils.c b/ext/vulkan/vkutils.c index 602b643c37..e83a91e236 100644 --- a/ext/vulkan/vkutils.c +++ b/ext/vulkan/vkutils.c @@ -23,6 +23,9 @@ #endif #include "vkutils.h" +#include "vkutils_private.h" + +GST_DEBUG_CATEGORY_STATIC (GST_CAT_CONTEXT); gboolean _check_for_all_layers (uint32_t check_count, const char **check_names, @@ -44,3 +47,282 @@ _check_for_all_layers (uint32_t check_count, const char **check_names, } return TRUE; } + +static void +_init_context_debug (void) +{ +#ifndef GST_DISABLE_GST_DEBUG + static volatile gsize _init = 0; + + if (g_once_init_enter (&_init)) { + GST_DEBUG_CATEGORY_GET (GST_CAT_CONTEXT, "GST_CONTEXT"); + g_once_init_leave (&_init, 1); + } +#endif +} + +static gboolean +_vk_pad_query (const GValue * item, GValue * value, gpointer user_data) +{ + GstPad *pad = g_value_get_object (item); + GstQuery *query = user_data; + gboolean res; + + _init_context_debug (); + + res = gst_pad_peer_query (pad, query); + + if (res) { + g_value_set_boolean (value, TRUE); + return FALSE; + } + + GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, pad, "pad peer query failed"); + return TRUE; +} + +gboolean +gst_vulkan_run_query (GstElement * element, GstQuery * query, + GstPadDirection direction) +{ + GstIterator *it; + GstIteratorFoldFunction func = _vk_pad_query; + GValue res = { 0 }; + + g_value_init (&res, G_TYPE_BOOLEAN); + g_value_set_boolean (&res, FALSE); + + /* Ask neighbor */ + if (direction == GST_PAD_SRC) + it = gst_element_iterate_src_pads (element); + else + it = gst_element_iterate_sink_pads (element); + + while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC) + gst_iterator_resync (it); + + gst_iterator_free (it); + + return g_value_get_boolean (&res); +} + +static void +_vk_gst_context_query (GstElement * element, const gchar * display_type) +{ + GstQuery *query; + GstContext *ctxt; + + _init_context_debug (); + + /* 2a) Query downstream with GST_QUERY_CONTEXT for the context and + * check if downstream already has a context of the specific type + * 2b) Query upstream as above. + */ + query = gst_query_new_context (display_type); + if (gst_vulkan_run_query (element, query, GST_PAD_SRC)) { + gst_query_parse_context (query, &ctxt); + GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element, + "found context (%p) in downstream query", ctxt); + gst_element_set_context (element, ctxt); + } else if (gst_vulkan_run_query (element, query, GST_PAD_SINK)) { + gst_query_parse_context (query, &ctxt); + GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element, + "found context (%p) in upstream query", ctxt); + gst_element_set_context (element, ctxt); + } else { + /* 3) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with + * the required context type and afterwards check if a + * usable context was set now as in 1). The message could + * be handled by the parent bins of the element and the + * application. + */ + GstMessage *msg; + + GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element, + "posting need context message"); + msg = gst_message_new_need_context (GST_OBJECT_CAST (element), + display_type); + gst_element_post_message (element, msg); + } + + /* + * Whomever responds to the need-context message performs a + * GstElement::set_context() with the required context in which the element + * is required to update the display_ptr or call gst_vulkan_handle_set_context(). + */ + + gst_query_unref (query); +} + +static void +_vk_display_context_query (GstElement * element, + GstVulkanDisplay ** display_ptr) +{ + _vk_gst_context_query (element, GST_VULKAN_DISPLAY_CONTEXT_TYPE_STR); +} + +/* 4) Create a context by itself and post a GST_MESSAGE_HAVE_CONTEXT + * message. + */ +/* + * @element: (transfer none): + * @context: (transfer full): + */ +static void +_vk_context_propagate (GstElement * element, GstContext * context) +{ + GstMessage *msg; + + _init_context_debug (); + + gst_element_set_context (element, context); + + GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element, + "posting have context (%" GST_PTR_FORMAT ") message", context); + msg = gst_message_new_have_context (GST_OBJECT_CAST (element), context); + gst_element_post_message (GST_ELEMENT_CAST (element), msg); +} + +gboolean +gst_vulkan_ensure_element_data (gpointer element, + GstVulkanDisplay ** display_ptr, GstVulkanInstance ** instance_ptr) +{ + g_return_val_if_fail (element != NULL, FALSE); + g_return_val_if_fail (display_ptr != NULL, FALSE); + g_return_val_if_fail (instance_ptr != NULL, FALSE); + + /* 1) Check if the element already has a context of the specific + * type. + */ + if (!*display_ptr) { + _vk_display_context_query (element, display_ptr); + + /* Neighbour found and it updated the display */ + if (!*display_ptr) { + GstContext *context; + + /* If no neighboor, or application not interested, use system default */ + *display_ptr = gst_vulkan_display_new (); + + context = gst_context_new (GST_VULKAN_DISPLAY_CONTEXT_TYPE_STR, TRUE); + gst_context_set_vulkan_display (context, *display_ptr); + + _vk_context_propagate (element, context); + } + } + + if (!*instance_ptr) { + _vk_gst_context_query (element, GST_VULKAN_INSTANCE_CONTEXT_TYPE_STR); + + /* Neighbour found and it updated the display */ + if (!*instance_ptr) { + GstContext *context; + + /* If no neighboor, or application not interested, use system default */ + *instance_ptr = gst_vulkan_instance_new (); + + context = gst_context_new (GST_VULKAN_INSTANCE_CONTEXT_TYPE_STR, TRUE); + gst_context_set_vulkan_instance (context, *instance_ptr); + + _vk_context_propagate (element, context); + } + } + + return *display_ptr != NULL && *instance_ptr != NULL; +} + +gboolean +gst_vulkan_handle_set_context (GstElement * element, GstContext * context, + GstVulkanDisplay ** display, GstVulkanInstance ** instance) +{ + GstVulkanDisplay *display_replacement = NULL; + GstVulkanInstance *instance_replacement = NULL; + const gchar *context_type; + + g_return_val_if_fail (display != NULL, FALSE); + g_return_val_if_fail (instance != NULL, FALSE); + + if (!context) + return FALSE; + + context_type = gst_context_get_context_type (context); + + if (g_strcmp0 (context_type, GST_VULKAN_DISPLAY_CONTEXT_TYPE_STR) == 0) { + if (!gst_context_get_vulkan_display (context, &display_replacement)) { + GST_WARNING_OBJECT (element, "Failed to get display from context"); + return FALSE; + } + } else if (g_strcmp0 (context_type, + GST_VULKAN_INSTANCE_CONTEXT_TYPE_STR) == 0) { + if (!gst_context_get_vulkan_instance (context, &instance_replacement)) { + GST_WARNING_OBJECT (element, "Failed to get instance from context"); + return FALSE; + } + } + + if (display_replacement) { + GstVulkanDisplay *old = *display; + *display = display_replacement; + + if (old) + gst_object_unref (old); + } + + if (instance_replacement) { + GstVulkanInstance *old = *instance; + *instance = instance_replacement; + + if (old) + gst_object_unref (old); + } + + return TRUE; +} + +gboolean +gst_vulkan_handle_context_query (GstElement * element, GstQuery * query, + GstVulkanDisplay ** display, GstVulkanInstance ** instance) +{ + gboolean res = FALSE; + const gchar *context_type; + GstContext *context, *old_context; + + g_return_val_if_fail (element != NULL, FALSE); + g_return_val_if_fail (query != NULL, FALSE); + g_return_val_if_fail (GST_QUERY_TYPE (query) != GST_QUERY_CONTEXT, FALSE); + g_return_val_if_fail (display != NULL, FALSE); + g_return_val_if_fail (instance != NULL, FALSE); + + gst_query_parse_context_type (query, &context_type); + + if (g_strcmp0 (context_type, GST_VULKAN_DISPLAY_CONTEXT_TYPE_STR) == 0) { + gst_query_parse_context (query, &old_context); + + if (old_context) + context = gst_context_copy (old_context); + else + context = gst_context_new (GST_VULKAN_DISPLAY_CONTEXT_TYPE_STR, TRUE); + + gst_context_set_vulkan_display (context, *display); + gst_query_set_context (query, context); + gst_context_unref (context); + + res = *display != NULL; + } else if (g_strcmp0 (context_type, + GST_VULKAN_INSTANCE_CONTEXT_TYPE_STR) == 0) { + gst_query_parse_context (query, &old_context); + + if (old_context) + context = gst_context_copy (old_context); + else + context = gst_context_new (GST_VULKAN_INSTANCE_CONTEXT_TYPE_STR, TRUE); + + gst_context_set_vulkan_instance (context, *instance); + gst_query_set_context (query, context); + gst_context_unref (context); + + res = *instance != NULL; + } + + return res; +} diff --git a/ext/vulkan/vkutils.h b/ext/vulkan/vkutils.h index c07abb8f62..4b9eaa3344 100644 --- a/ext/vulkan/vkutils.h +++ b/ext/vulkan/vkutils.h @@ -21,12 +21,19 @@ #define _VK_UTILS_H_ #include -#include "vk.h" +#include G_BEGIN_DECLS -gboolean _check_for_all_layers (uint32_t check_count, const char ** check_names, - uint32_t layer_count, VkLayerProperties * layers); +gboolean gst_vulkan_ensure_element_data (gpointer element, + GstVulkanDisplay **display_ptr, GstVulkanInstance ** instance_ptr); +gboolean gst_vulkan_handle_set_context (GstElement * element, GstContext * context, + GstVulkanDisplay ** display, GstVulkanInstance ** instance); +gboolean gst_vulkan_handle_context_query (GstElement * element, GstQuery * query, + GstVulkanDisplay ** display, GstVulkanInstance ** instance); + +gboolean gst_vulkan_run_query (GstElement * element, + GstQuery * query, GstPadDirection direction); G_END_DECLS diff --git a/ext/vulkan/vkutils_private.h b/ext/vulkan/vkutils_private.h new file mode 100644 index 0000000000..aebf44b7d3 --- /dev/null +++ b/ext/vulkan/vkutils_private.h @@ -0,0 +1,33 @@ +/* + * GStreamer + * Copyright (C) 2015 Matthew Waters + * + * 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_PRIVATE_H_ +#define _VK_UTILS_PRIVATE_H_ + +#include +#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_ */