From 6d1d6e67925035742f70b9d167ab41dfe7075ff3 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Mon, 28 Nov 2016 16:34:01 +0100 Subject: [PATCH] vulkan: Add more infrastructure gdk_window_create_vulkan_context() now exists and will return a Vulkan context for the given window. It even initializes the surface. But it doesn't do anything useful yet. --- gdk/gdkdisplayprivate.h | 2 + gdk/gdktypes.h | 15 +++++ gdk/gdkvulkancontext.c | 103 +++++++++++++++++++++++++++------ gdk/gdkvulkancontext.h | 11 ++++ gdk/gdkvulkancontextprivate.h | 12 +++- gdk/gdkwindow.c | 39 +++++++++++++ gdk/gdkwindow.h | 4 ++ gdk/x11/gdkdisplay-x11.c | 7 +++ gdk/x11/gdkvulkancontext-x11.c | 44 ++++++++++++-- gdk/x11/gdkvulkancontext-x11.h | 10 ++++ 10 files changed, 223 insertions(+), 24 deletions(-) diff --git a/gdk/gdkdisplayprivate.h b/gdk/gdkdisplayprivate.h index c90c611647..4164b9ce88 100644 --- a/gdk/gdkdisplayprivate.h +++ b/gdk/gdkdisplayprivate.h @@ -145,6 +145,8 @@ struct _GdkDisplayClass GObjectClass parent_class; GType window_type; /* type for native windows for this display, set in class_init */ + GType vk_context_type; /* type for GdkVulkanContext, must be set if vk_extension_name != NULL */ + const char *vk_extension_name; /* Name of required windowing vulkan extension or %NULL (default) if Vulkan isn't supported */ const gchar * (*get_name) (GdkDisplay *display); GdkScreen * (*get_default_screen) (GdkDisplay *display); diff --git a/gdk/gdktypes.h b/gdk/gdktypes.h index 2172304223..73bf2feccd 100644 --- a/gdk/gdktypes.h +++ b/gdk/gdktypes.h @@ -489,6 +489,21 @@ typedef enum { GDK_GL_ERROR_LINK_FAILED } GdkGLError; +/** + * GdkVulkanError: + * @GDK_VULKAN_ERROR_UNSUPPORTED: Vulkan is not supported on this backend or has not been + * compiled in. + * @GDK_VULKAN_ERROR_NOT_AVAILABLE: Vulkan support is not available on this Window + * + * Error enumeration for #GdkVulkanContext. + * + * Since: 3.90 + */ +typedef enum { + GDK_VULKAN_ERROR_UNSUPPORTED, + GDK_VULKAN_ERROR_NOT_AVAILABLE, +} GdkVulkanError; + /** * GdkWindowTypeHint: * @GDK_WINDOW_TYPE_HINT_NORMAL: Normal toplevel window. diff --git a/gdk/gdkvulkancontext.c b/gdk/gdkvulkancontext.c index 462ca460ed..04cad65c5c 100644 --- a/gdk/gdkvulkancontext.c +++ b/gdk/gdkvulkancontext.c @@ -32,6 +32,8 @@ typedef struct _GdkVulkanContextPrivate GdkVulkanContextPrivate; struct _GdkVulkanContextPrivate { GdkWindow *window; + + VkSurfaceKHR surface; }; enum { @@ -47,7 +49,11 @@ static GParamSpec *pspecs[LAST_PROP] = { NULL, }; G_DEFINE_QUARK (gdk-vulkan-error-quark, gdk_vulkan_error) -G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GdkVulkanContext, gdk_vulkan_context, G_TYPE_OBJECT) +static void gdk_vulkan_context_initable_init (GInitableIface *iface); + +G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GdkVulkanContext, gdk_vulkan_context, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, gdk_vulkan_context_initable_init) + G_ADD_PRIVATE (GdkVulkanContext)) static void gdk_vulkan_context_dispose (GObject *gobject) @@ -55,6 +61,8 @@ gdk_vulkan_context_dispose (GObject *gobject) GdkVulkanContext *context = GDK_VULKAN_CONTEXT (gobject); GdkVulkanContextPrivate *priv = gdk_vulkan_context_get_instance_private (context); + gdk_display_unref_vulkan (gdk_vulkan_context_get_display (context)); + g_clear_object (&priv->window); G_OBJECT_CLASS (gdk_vulkan_context_parent_class)->dispose (gobject); @@ -153,6 +161,33 @@ gdk_vulkan_context_init (GdkVulkanContext *self) { } +static gboolean +gdk_vulkan_context_real_init (GInitable *initable, + GCancellable *cancellable, + GError **error) +{ + GdkVulkanContext *context = GDK_VULKAN_CONTEXT (initable); + GdkVulkanContextPrivate *priv = gdk_vulkan_context_get_instance_private (context); + + if (!gdk_display_ref_vulkan (gdk_vulkan_context_get_display (context), error)) + return FALSE; + + if (GDK_VULKAN_CONTEXT_GET_CLASS (context)->create_surface (context, &priv->surface) != VK_SUCCESS) + { + g_set_error_literal (error, GDK_VULKAN_ERROR, GDK_VULKAN_ERROR_NOT_AVAILABLE, + "Vulkan support not available for this window."); + return FALSE; + } + + return TRUE; +} + +static void +gdk_vulkan_context_initable_init (GInitableIface *iface) +{ + iface->init = gdk_vulkan_context_real_init; +} + /** * gdk_vulkan_context_get_display: * @context: a #GdkVulkanContext @@ -195,8 +230,17 @@ gdk_vulkan_context_get_window (GdkVulkanContext *context) #ifdef GDK_WINDOWING_VULKAN +VkInstance +gdk_vulkan_context_get_instance (GdkVulkanContext *context) +{ + g_return_val_if_fail (GDK_IS_VULKAN_CONTEXT (context), NULL); + + return gdk_vulkan_context_get_display (context)->vk_instance; +} + static gboolean -gdk_display_create_vulkan_device (GdkDisplay *display) +gdk_display_create_vulkan_device (GdkDisplay *display, + GError **error) { uint32_t i, j; @@ -205,6 +249,14 @@ gdk_display_create_vulkan_device (GdkDisplay *display) VkPhysicalDevice devices[n_devices]; GDK_VK_CHECK(vkEnumeratePhysicalDevices, display->vk_instance, &n_devices, devices); + if (n_devices == 0) + { + /* Give a different error for 0 devices so people know their drivers suck. */ + g_set_error_literal (error, GDK_VULKAN_ERROR, GDK_VULKAN_ERROR_NOT_AVAILABLE, + "No Vulkan devices available."); + return FALSE; + } + for (i = 0; i < n_devices; i++) { VkPhysicalDeviceProperties props; @@ -265,15 +317,24 @@ gdk_display_create_vulkan_device (GdkDisplay *display) } } + g_set_error_literal (error, GDK_VULKAN_ERROR, GDK_VULKAN_ERROR_NOT_AVAILABLE, + "Could not find a Vulkan device with the required features."); return FALSE; } static gboolean -gdk_display_create_vulkan_instance (GdkDisplay *display, - const char *wsi_extension_name) +gdk_display_create_vulkan_instance (GdkDisplay *display, + GError **error) { uint32_t i; + if (GDK_DISPLAY_GET_CLASS (display)->vk_extension_name == NULL) + { + g_set_error (error, GDK_VULKAN_ERROR, GDK_VULKAN_ERROR_UNSUPPORTED, + "The %s backend has no Vulkan support.", G_OBJECT_TYPE_NAME (display)); + return FALSE; + } + uint32_t n_extensions; GDK_VK_CHECK (vkEnumerateInstanceExtensionProperties, NULL, &n_extensions, NULL); VkExtensionProperties extensions[n_extensions]; @@ -308,31 +369,39 @@ gdk_display_create_vulkan_instance (GdkDisplay *display, NULL, 0, &(VkApplicationInfo) { - VK_STRUCTURE_TYPE_APPLICATION_INFO, - NULL, - g_get_application_name (), - 0, - "GTK+", - VK_MAKE_VERSION (GDK_MAJOR_VERSION, GDK_MINOR_VERSION, GDK_MICRO_VERSION), - VK_API_VERSION_1_0 }, + VK_STRUCTURE_TYPE_APPLICATION_INFO, + NULL, + g_get_application_name (), + 0, + "GTK+", + VK_MAKE_VERSION (GDK_MAJOR_VERSION, GDK_MINOR_VERSION, GDK_MICRO_VERSION), + VK_API_VERSION_1_0 }, 0, NULL, - 1, - &wsi_extension_name }, + 2, + (const char *const *) &(const char *[2]) { + VK_KHR_SURFACE_EXTENSION_NAME, + GDK_DISPLAY_GET_CLASS (display)->vk_extension_name + }, + }, NULL, &display->vk_instance) != VK_SUCCESS) - return FALSE; + { + g_set_error_literal (error, GDK_VULKAN_ERROR, GDK_VULKAN_ERROR_UNSUPPORTED, + "Could not create a Vulkan instance."); + return FALSE; + } - return gdk_display_create_vulkan_device (display); + return gdk_display_create_vulkan_device (display, error); } gboolean gdk_display_ref_vulkan (GdkDisplay *display, - const char *wsi_extension_name) + GError **error) { if (display->vulkan_refcount == 0) { - if (!gdk_display_create_vulkan_instance (display, wsi_extension_name)) + if (!gdk_display_create_vulkan_instance (display, error)) return FALSE; } diff --git a/gdk/gdkvulkancontext.h b/gdk/gdkvulkancontext.h index 7a042f0a9b..ce85903dbd 100644 --- a/gdk/gdkvulkancontext.h +++ b/gdk/gdkvulkancontext.h @@ -28,6 +28,10 @@ #include #include +#ifdef GDK_WINDOWING_VULKAN +#include +#endif + G_BEGIN_DECLS #define GDK_TYPE_VULKAN_CONTEXT (gdk_vulkan_context_get_type ()) @@ -47,6 +51,13 @@ GdkDisplay * gdk_vulkan_context_get_display (GdkVulkanCo GDK_AVAILABLE_IN_3_90 GdkWindow * gdk_vulkan_context_get_window (GdkVulkanContext *context); +#ifdef GDK_WINDOWING_VULKAN + +GDK_AVAILABLE_IN_3_90 +VkInstance gdk_vulkan_context_get_instance (GdkVulkanContext *context); + +#endif /* GDK_WINDOWING_VULKAN */ + G_END_DECLS #endif /* __GDK_VULKAN_CONTEXT__ */ diff --git a/gdk/gdkvulkancontextprivate.h b/gdk/gdkvulkancontextprivate.h index 7bed0d92fe..de4ba2ff2c 100644 --- a/gdk/gdkvulkancontextprivate.h +++ b/gdk/gdkvulkancontextprivate.h @@ -43,6 +43,9 @@ struct _GdkVulkanContext struct _GdkVulkanContextClass { GObjectClass parent_class; + + VkResult (* create_surface) (GdkVulkanContext *context, + VkSurfaceKHR *surface); }; #ifdef GDK_WINDOWING_VULKAN @@ -61,17 +64,20 @@ gdk_vulkan_handle_result (VkResult res, #define GDK_VK_CHECK(func, ...) gdk_vulkan_handle_result (func (__VA_ARGS__), G_STRINGIFY (func)) gboolean gdk_display_ref_vulkan (GdkDisplay *display, - const char *wsi_extension_name); + GError **error); void gdk_display_unref_vulkan (GdkDisplay *display); #else /* !GDK_WINDOWING_VULKAN */ static inline gboolean -gdk_display_init_vulkan (GdkDisplay *display, - const char *wsi_extension_name) +gdk_display_ref_vulkan (GdkDisplay *display, + GError **error) { GDK_NOTE (VULKAN, g_print ("Support for Vulkan disabled at compile-time")); + g_set_error_literal (error, GDK_VULKAN_ERROR, GDK_VULKAN_ERROR_UNSUPPORTED, + "Vulkan support was not enabled at compie time."); + return FALSE; } diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c index 60ac09a8ba..4c9fe05328 100644 --- a/gdk/gdkwindow.c +++ b/gdk/gdkwindow.c @@ -2682,6 +2682,45 @@ gdk_window_create_gl_context (GdkWindow *window, error); } +/** + * gdk_window_create_vulkan_context: + * @window: a #GdkWindow + * @error: return location for an error + * + * Creates a new #GdkVulkanContext for rendering on @window. + * + * If the creation of the #GdkVulkanContext failed, @error will be set. + * + * Returns: (transfer full): the newly created #GdkVulkanContext, or + * %NULL on error + * + * Since: 3.90 + **/ +GdkVulkanContext * +gdk_window_create_vulkan_context (GdkWindow *window, + GError **error) +{ + GdkDisplay *display; + + g_return_val_if_fail (GDK_IS_WINDOW (window), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + display = gdk_window_get_display (window); + + if (GDK_DISPLAY_GET_CLASS (display)->vk_extension_name == NULL) + { + g_set_error (error, GDK_VULKAN_ERROR, GDK_VULKAN_ERROR_UNSUPPORTED, + "The %s backend has no Vulkan support.", G_OBJECT_TYPE_NAME (display)); + return FALSE; + } + + return g_initable_new (GDK_DISPLAY_GET_CLASS (display)->vk_context_type, + NULL, + error, + "window", window, + NULL); +} + static void gdk_window_begin_paint_internal (GdkWindow *window, const cairo_region_t *region) diff --git a/gdk/gdkwindow.h b/gdk/gdkwindow.h index d99dccce02..0ddc53178a 100644 --- a/gdk/gdkwindow.h +++ b/gdk/gdkwindow.h @@ -946,6 +946,10 @@ gboolean gdk_window_show_window_menu (GdkWindow *window, GDK_AVAILABLE_IN_3_16 GdkGLContext * gdk_window_create_gl_context (GdkWindow *window, GError **error); +GDK_AVAILABLE_IN_3_90 +GdkVulkanContext * + gdk_window_create_vulkan_context(GdkWindow *window, + GError **error); G_END_DECLS diff --git a/gdk/x11/gdkdisplay-x11.c b/gdk/x11/gdkdisplay-x11.c index 843cdc8de8..9efe829229 100644 --- a/gdk/x11/gdkdisplay-x11.c +++ b/gdk/x11/gdkdisplay-x11.c @@ -22,6 +22,8 @@ #include "config.h" +#define VK_USE_PLATFORM_XLIB_KHR + #include "gdkasync.h" #include "gdkdisplay.h" #include "gdkeventsource.h" @@ -38,6 +40,7 @@ #include "gdkprivate-x11.h" #include "gdkscreen-x11.h" #include "gdkglcontext-x11.h" +#include "gdkvulkancontext-x11.h" #include "gdk-private.h" #include @@ -2951,6 +2954,10 @@ gdk_x11_display_class_init (GdkX11DisplayClass * class) object_class->finalize = gdk_x11_display_finalize; display_class->window_type = GDK_TYPE_X11_WINDOW; +#ifdef GDK_WINDOWING_VULKAN + display_class->vk_context_type = GDK_TYPE_X11_VULKAN_CONTEXT; + display_class->vk_extension_name = VK_KHR_XLIB_SURFACE_EXTENSION_NAME; +#endif display_class->get_name = gdk_x11_display_get_name; display_class->get_default_screen = gdk_x11_display_get_default_screen; diff --git a/gdk/x11/gdkvulkancontext-x11.c b/gdk/x11/gdkvulkancontext-x11.c index cb0bda2ebb..dc423064b2 100644 --- a/gdk/x11/gdkvulkancontext-x11.c +++ b/gdk/x11/gdkvulkancontext-x11.c @@ -18,15 +18,51 @@ * License along with this library. If not, see . */ -#ifdef GDK_WINDOWING_VULKAN - #include "config.h" +#include "gdkconfig.h" + +#ifdef GDK_WINDOWING_VULKAN + #include "gdkvulkancontext-x11.h" -#include - #include "gdkinternals.h" +#include "gdkdisplay-x11.h" +#include "gdkwindow-x11.h" + +G_DEFINE_TYPE (GdkX11VulkanContext, gdk_x11_vulkan_context, GDK_TYPE_VULKAN_CONTEXT) + +static VkResult +gdk_x11_vulkan_context_create_surface (GdkVulkanContext *context, + VkSurfaceKHR *surface) +{ + GdkWindow *window = gdk_vulkan_context_get_window (context); + GdkDisplay *display = gdk_vulkan_context_get_display (context); + + return GDK_VK_CHECK (vkCreateXlibSurfaceKHR, gdk_vulkan_context_get_instance (context), + &(VkXlibSurfaceCreateInfoKHR) { + VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, + NULL, + 0, + gdk_x11_display_get_xdisplay (display), + gdk_x11_window_get_xid (window) + }, + NULL, + surface); +} + +static void +gdk_x11_vulkan_context_class_init (GdkX11VulkanContextClass *klass) +{ + GdkVulkanContextClass *context_class = GDK_VULKAN_CONTEXT_CLASS (klass); + + context_class->create_surface = gdk_x11_vulkan_context_create_surface; +} + +static void +gdk_x11_vulkan_context_init (GdkX11VulkanContext *self) +{ +} #endif /* GDK_WINDOWING_VULKAN */ diff --git a/gdk/x11/gdkvulkancontext-x11.h b/gdk/x11/gdkvulkancontext-x11.h index d4268df350..8c3dab1e6d 100644 --- a/gdk/x11/gdkvulkancontext-x11.h +++ b/gdk/x11/gdkvulkancontext-x11.h @@ -21,8 +21,12 @@ #ifndef __GDK_X11_VULKAN_CONTEXT__ #define __GDK_X11_VULKAN_CONTEXT__ +#include "gdkconfig.h" + #ifdef GDK_WINDOWING_VULKAN +#define VK_USE_PLATFORM_XLIB_KHR + #include "gdkvulkancontextprivate.h" G_BEGIN_DECLS @@ -34,6 +38,9 @@ G_BEGIN_DECLS #define GDK_IS_X11_VULKAN_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_X11_VULKAN_CONTEXT)) #define GDK_X11_VULKAN_CONTEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_X11_VULKAN_CONTEXT, GdkX11VulkanContextClass)) +typedef struct _GdkX11VulkanContext GdkX11VulkanContext; +typedef struct _GdkX11VulkanContextClass GdkX11VulkanContextClass; + struct _GdkX11VulkanContext { GdkVulkanContext parent_instance; @@ -44,6 +51,9 @@ struct _GdkX11VulkanContextClass GdkVulkanContextClass parent_class; }; +GDK_AVAILABLE_IN_3_90 +GType gdk_x11_vulkan_context_get_type (void) G_GNUC_CONST; + G_END_DECLS #endif /* !GDK_WINDOWING_VULKAN */