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.
This commit is contained in:
Benjamin Otte 2016-11-28 16:34:01 +01:00
parent cca547e5bc
commit 6d1d6e6792
10 changed files with 223 additions and 24 deletions

View File

@ -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);

View File

@ -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.

View File

@ -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;
}

View File

@ -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__ */

View File

@ -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;
}

View File

@ -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)

View File

@ -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

View File

@ -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;

View File

@ -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 "gdkconfig.h"
#ifdef GDK_WINDOWING_VULKAN
#include "gdkvulkancontext-x11.h"
#include <vulkan/vulkan.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 */

View File

@ -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 */