[gtk+/wip/otte/vulkan: 19/36] gdk: Add more infrastructure



commit d56e4cb1692f3af747cd1f577d3993f3cc108613
Author: Benjamin Otte <otte redhat com>
Date:   Mon Nov 28 16:34:01 2016 +0100

    gdk: 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 c90c611..4164b9c 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 2faa907..e2ad6f7 100644
--- a/gdk/gdktypes.h
+++ b/gdk/gdktypes.h
@@ -489,6 +489,21 @@ typedef enum {
 } 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.
  * @GDK_WINDOW_TYPE_HINT_DIALOG: Dialog window.
diff --git a/gdk/gdkvulkancontext.c b/gdk/gdkvulkancontext.c
index c392d21..df6a30f 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 7a042f0..ce85903 100644
--- a/gdk/gdkvulkancontext.h
+++ b/gdk/gdkvulkancontext.h
@@ -28,6 +28,10 @@
 #include <gdk/gdkversionmacros.h>
 #include <gdk/gdktypes.h>
 
+#ifdef GDK_WINDOWING_VULKAN
+#include <vulkan/vulkan.h>
+#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 7bed0d9..de4ba2f 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 fd74eb8..22307a2 100644
--- a/gdk/gdkwindow.c
+++ b/gdk/gdkwindow.c
@@ -2681,6 +2681,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 96d326c..e6c60c7 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 843cdc8..9efe829 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 <glib.h>
@@ -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 cb0bda2..dc42306 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 <http://www.gnu.org/licenses/>.
  */
 
-#ifdef GDK_WINDOWING_VULKAN
-
 #include "config.h"
 
-#include "gdkvulkancontext-x11.h"
+#include "gdkconfig.h"
 
-#include <vulkan/vulkan.h>
+#ifdef GDK_WINDOWING_VULKAN
+
+#include "gdkvulkancontext-x11.h"
 
 #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 d4268df..8c3dab1 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 */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]