vulkan: acquire/present images when drawing

Another step towards the final goal of actually showing something.
This commit is contained in:
Benjamin Otte 2016-12-01 04:07:20 +01:00
parent 06657fa23b
commit 8ba2898e08
3 changed files with 157 additions and 35 deletions

View File

@ -36,9 +36,12 @@ struct _GdkVulkanContextPrivate {
int swapchain_width, swapchain_height;
VkSwapchainKHR swapchain;
VkSemaphore draw_semaphore;
guint n_images;
VkImage *images;
uint32_t draw_index;
};
enum {
@ -121,13 +124,24 @@ gdk_vulkan_context_dispose (GObject *gobject)
GdkVulkanContext *context = GDK_VULKAN_CONTEXT (gobject);
GdkVulkanContextPrivate *priv = gdk_vulkan_context_get_instance_private (context);
GdkDisplay *display;
VkDevice device;
g_clear_pointer (&priv->images, g_free);
priv->n_images = 0;
device = gdk_vulkan_context_get_device (context);
if (priv->draw_semaphore != VK_NULL_HANDLE)
{
vkDestroySemaphore (device,
priv->draw_semaphore,
NULL);
priv->draw_semaphore = VK_NULL_HANDLE;
}
if (priv->swapchain != VK_NULL_HANDLE)
{
vkDestroySwapchainKHR (gdk_vulkan_context_get_device (context),
vkDestroySwapchainKHR (device,
priv->swapchain,
NULL);
priv->swapchain = VK_NULL_HANDLE;
@ -149,36 +163,6 @@ gdk_vulkan_context_dispose (GObject *gobject)
G_OBJECT_CLASS (gdk_vulkan_context_parent_class)->dispose (gobject);
}
static void
gdk_vulkan_context_class_init (GdkVulkanContextClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->dispose = gdk_vulkan_context_dispose;
/**
* GdkVulkanContext::images-updated:
* @context: the object on which the signal is emitted
*
* This signal is emitted when the images managed by this context have
* changed. Usually this means that the swapchain had to be recreated,
* for example in response to a change of the window size.
*/
signals[IMAGES_UPDATED] =
g_signal_new (g_intern_static_string ("images-updated"),
G_OBJECT_CLASS_TYPE (gobject_class),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
}
static void
gdk_vulkan_context_init (GdkVulkanContext *self)
{
}
static gboolean
gdk_vulkan_context_check_swapchain (GdkVulkanContext *context,
GError **error)
@ -259,8 +243,8 @@ gdk_vulkan_context_check_swapchain (GdkVulkanContext *context,
if (res == VK_SUCCESS)
{
priv->swapchain_width = gdk_window_get_width (window);
priv->swapchain_height = gdk_window_get_height (window);
priv->swapchain_width = capabilities.currentExtent.width;
priv->swapchain_height = capabilities.currentExtent.height;
priv->swapchain = new_swapchain;
GDK_VK_CHECK (vkGetSwapchainImagesKHR, device,
@ -288,6 +272,84 @@ gdk_vulkan_context_check_swapchain (GdkVulkanContext *context,
return res == VK_SUCCESS;
}
static void
gdk_vulkan_context_begin_frame (GdkDrawContext *draw_context,
cairo_region_t *region)
{
GdkVulkanContext *context = GDK_VULKAN_CONTEXT (draw_context);
GdkVulkanContextPrivate *priv = gdk_vulkan_context_get_instance_private (context);
GError *error = NULL;
if (!gdk_vulkan_context_check_swapchain (context, &error))
{
g_warning ("%s", error->message);
g_error_free (error);
return;
}
GDK_VK_CHECK (vkAcquireNextImageKHR, gdk_vulkan_context_get_device (context),
priv->swapchain,
UINT64_MAX,
priv->draw_semaphore,
VK_NULL_HANDLE,
&priv->draw_index);
}
static void
gdk_vulkan_context_end_frame (GdkDrawContext *draw_context,
cairo_region_t *painted,
cairo_region_t *damage)
{
GdkVulkanContext *context = GDK_VULKAN_CONTEXT (draw_context);
GdkVulkanContextPrivate *priv = gdk_vulkan_context_get_instance_private (context);
GDK_VK_CHECK (vkQueuePresentKHR, gdk_vulkan_context_get_queue (context),
&(VkPresentInfoKHR) {
.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
.swapchainCount = 1,
.pSwapchains = (VkSwapchainKHR[]) {
priv->swapchain
},
.pImageIndices = (uint32_t[]) {
priv->draw_index
},
});
}
static void
gdk_vulkan_context_class_init (GdkVulkanContextClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GdkDrawContextClass *draw_context_class = GDK_DRAW_CONTEXT_CLASS (klass);
gobject_class->dispose = gdk_vulkan_context_dispose;
draw_context_class->begin_frame = gdk_vulkan_context_begin_frame;
draw_context_class->end_frame = gdk_vulkan_context_end_frame;
/**
* GdkVulkanContext::images-updated:
* @context: the object on which the signal is emitted
*
* This signal is emitted when the images managed by this context have
* changed. Usually this means that the swapchain had to be recreated,
* for example in response to a change of the window size.
*/
signals[IMAGES_UPDATED] =
g_signal_new (g_intern_static_string ("images-updated"),
G_OBJECT_CLASS_TYPE (gobject_class),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
}
static void
gdk_vulkan_context_init (GdkVulkanContext *self)
{
}
static gboolean
gdk_vulkan_context_real_init (GInitable *initable,
GCancellable *cancellable,
@ -350,6 +412,13 @@ gdk_vulkan_context_real_init (GInitable *initable,
if (!gdk_vulkan_context_check_swapchain (context, error))
goto out_surface;
GDK_VK_CHECK (vkCreateSemaphore, gdk_vulkan_context_get_device (context),
&(VkSemaphoreCreateInfo) {
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
},
NULL,
&priv->draw_semaphore);
return TRUE;
}
@ -417,7 +486,7 @@ gdk_vulkan_context_get_image_format (GdkVulkanContext *context)
return priv->image_format.format;
}
guint
uint32_t
gdk_vulkan_context_get_n_images (GdkVulkanContext *context)
{
GdkVulkanContextPrivate *priv = gdk_vulkan_context_get_instance_private (context);
@ -439,6 +508,28 @@ gdk_vulkan_context_get_image (GdkVulkanContext *context,
return priv->images[id];
}
uint32_t
gdk_vulkan_context_get_draw_index (GdkVulkanContext *context)
{
GdkVulkanContextPrivate *priv = gdk_vulkan_context_get_instance_private (context);
g_return_val_if_fail (GDK_IS_VULKAN_CONTEXT (context), 0);
g_return_val_if_fail (gdk_draw_context_is_drawing (GDK_DRAW_CONTEXT (context)), 0);
return priv->draw_index;
}
VkSemaphore
gdk_vulkan_context_get_draw_semaphore (GdkVulkanContext *context)
{
GdkVulkanContextPrivate *priv = gdk_vulkan_context_get_instance_private (context);
g_return_val_if_fail (GDK_IS_VULKAN_CONTEXT (context), VK_NULL_HANDLE);
g_return_val_if_fail (gdk_draw_context_is_drawing (GDK_DRAW_CONTEXT (context)), VK_NULL_HANDLE);
return priv->draw_semaphore;
}
static gboolean
gdk_display_create_vulkan_device (GdkDisplay *display,
GError **error)

View File

@ -64,10 +64,14 @@ uint32_t gdk_vulkan_context_get_queue_family_index (GdkVulkanCo
GDK_AVAILABLE_IN_3_90
VkFormat gdk_vulkan_context_get_image_format (GdkVulkanContext *context);
GDK_AVAILABLE_IN_3_90
guint gdk_vulkan_context_get_n_images (GdkVulkanContext *context);
uint32_t gdk_vulkan_context_get_n_images (GdkVulkanContext *context);
GDK_AVAILABLE_IN_3_90
VkImage gdk_vulkan_context_get_image (GdkVulkanContext *context,
guint id);
GDK_AVAILABLE_IN_3_90
uint32_t gdk_vulkan_context_get_draw_index (GdkVulkanContext *context);
GDK_AVAILABLE_IN_3_90
VkSemaphore gdk_vulkan_context_get_draw_semaphore (GdkVulkanContext *context);
#endif /* GDK_WINDOWING_VULKAN */

View File

@ -285,6 +285,32 @@ gsk_vulkan_renderer_render (GskRenderer *renderer,
#endif
}
static GdkDrawingContext *
gsk_vulkan_renderer_begin_draw_frame (GskRenderer *renderer,
const cairo_region_t *region)
{
GskVulkanRenderer *self = GSK_VULKAN_RENDERER (renderer);
cairo_region_t *whole_window;
GdkDrawingContext *result;
GdkWindow *window;
window = gsk_renderer_get_window (renderer);
whole_window = cairo_region_create_rectangle (&(GdkRectangle) {
0, 0,
gdk_window_get_width (window),
gdk_window_get_height (window)
});
result = gdk_window_begin_draw_frame (window,
GDK_DRAW_CONTEXT (self->vulkan),
region);
cairo_region_destroy (whole_window);
return result;
}
static void
gsk_vulkan_renderer_class_init (GskVulkanRendererClass *klass)
{
@ -293,6 +319,7 @@ gsk_vulkan_renderer_class_init (GskVulkanRendererClass *klass)
renderer_class->realize = gsk_vulkan_renderer_realize;
renderer_class->unrealize = gsk_vulkan_renderer_unrealize;
renderer_class->render = gsk_vulkan_renderer_render;
renderer_class->begin_draw_frame = gsk_vulkan_renderer_begin_draw_frame;
}
static void