From a91d0ac156fe385da23e6a4b76c2e1450615b8af Mon Sep 17 00:00:00 2001 From: Georges Basile Stavracas Neto Date: Sat, 5 Oct 2019 11:38:29 -0300 Subject: [PATCH 1/4] wayland: Allow binding to wl_compositor v4 This is a requirement for using VK_KHR_incremental_present. Vulkan Wayland drivers translate the VkPresentRegionsKHR to wl_surface.damage_buffer(), which a v4-only request. --- gdk/wayland/gdkdisplay-wayland.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gdk/wayland/gdkdisplay-wayland.c b/gdk/wayland/gdkdisplay-wayland.c index d1377888dc..9f1fa5b380 100644 --- a/gdk/wayland/gdkdisplay-wayland.c +++ b/gdk/wayland/gdkdisplay-wayland.c @@ -416,8 +416,8 @@ gdk_registry_handle_global (void *data, if (strcmp (interface, "wl_compositor") == 0) { display_wayland->compositor = - wl_registry_bind (display_wayland->wl_registry, id, &wl_compositor_interface, MIN (version, 3)); - display_wayland->compositor_version = MIN (version, 3); + wl_registry_bind (display_wayland->wl_registry, id, &wl_compositor_interface, MIN (version, 4)); + display_wayland->compositor_version = MIN (version, 4); } else if (strcmp (interface, "wl_shm") == 0) { From 0b2006b74f0cc659625986059e172086a3b6d548 Mon Sep 17 00:00:00 2001 From: Georges Basile Stavracas Neto Date: Fri, 4 Oct 2019 11:52:43 -0300 Subject: [PATCH 2/4] vulkan/image: Set HOST and TRANSFER bits for before barriers Multiple images in the before barrier array are defined with VK_ACCESS_TRANSFER_WRITE_BIT and VK_ACCESS_TRANSFER_READ_BIT, which requires passing VK_PIPELINE_STAGE_TRANSFER_BIT and VK_PIPELINE_STAGE_HOST_BIT to vkCmdPipelineBarrier(). Pass these flags correctly. --- gsk/vulkan/gskvulkanimage.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/gsk/vulkan/gskvulkanimage.c b/gsk/vulkan/gskvulkanimage.c index 03d76c2d05..64e780bb7f 100644 --- a/gsk/vulkan/gskvulkanimage.c +++ b/gsk/vulkan/gskvulkanimage.c @@ -142,13 +142,15 @@ gsk_vulkan_uploader_get_copy_buffer (GskVulkanUploader *self) void gsk_vulkan_uploader_upload (GskVulkanUploader *self) { + VkPipelineStageFlagBits host_and_transfer_bits = VK_PIPELINE_STAGE_HOST_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT; + if (self->before_buffer_barriers->len > 0 || self->before_image_barriers->len > 0) { VkCommandBuffer command_buffer; command_buffer = gsk_vulkan_command_pool_get_buffer (self->command_pool); vkCmdPipelineBarrier (command_buffer, - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | host_and_transfer_bits, VK_PIPELINE_STAGE_HOST_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, @@ -164,7 +166,7 @@ gsk_vulkan_uploader_upload (GskVulkanUploader *self) { VkCommandBuffer command_buffer = gsk_vulkan_uploader_get_copy_buffer (self); vkCmdPipelineBarrier (command_buffer, - VK_PIPELINE_STAGE_HOST_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT, + host_and_transfer_bits, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, From a2b49322fb86f22a4f851e1b2b6d06467df2de4a Mon Sep 17 00:00:00 2001 From: Georges Basile Stavracas Neto Date: Fri, 4 Oct 2019 17:55:25 -0300 Subject: [PATCH 3/4] vulkan/renderpass: Use GENERAL for initial layout UNDEFINED initial layouts may not preserve the contents of the attachment after transitioning the layout. We want them to be preserved because we do partial rendering. Use GENERAL as the initial layout for render passes. --- gsk/vulkan/gskvulkanrenderpass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gsk/vulkan/gskvulkanrenderpass.c b/gsk/vulkan/gskvulkanrenderpass.c index 00fd658d8b..414d8b55d4 100644 --- a/gsk/vulkan/gskvulkanrenderpass.c +++ b/gsk/vulkan/gskvulkanrenderpass.c @@ -172,7 +172,7 @@ gsk_vulkan_render_pass_new (GdkVulkanContext *context, .samples = VK_SAMPLE_COUNT_1_BIT, .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, .storeOp = VK_ATTACHMENT_STORE_OP_STORE, - .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .initialLayout = VK_IMAGE_LAYOUT_GENERAL, .finalLayout = final_layout } }, From a795d6635b63c6d1dad9acbb3a78fc3eef8d7670 Mon Sep 17 00:00:00 2001 From: Georges Basile Stavracas Neto Date: Fri, 4 Oct 2019 18:53:10 -0300 Subject: [PATCH 4/4] vulkan/context: Implement VK_KHR_incremental_present This is the Vulkan version of eglSwapBuffersWithDamage(), and it's always a good idea to limit the number of pixels we're pushing to the GPU and/or swapping into the display. --- gdk/gdkvulkancontext.c | 75 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 68 insertions(+), 7 deletions(-) diff --git a/gdk/gdkvulkancontext.c b/gdk/gdkvulkancontext.c index a47808cc3b..7234421e1b 100644 --- a/gdk/gdkvulkancontext.c +++ b/gdk/gdkvulkancontext.c @@ -64,6 +64,9 @@ struct _GdkVulkanContextPrivate { guint n_images; VkImage *images; cairo_region_t **regions; + + gboolean has_present_region; + #endif guint32 draw_index; @@ -385,6 +388,26 @@ gdk_vulkan_context_check_swapchain (GdkVulkanContext *context, return res == VK_SUCCESS; } +static gboolean +device_supports_incremental_present (VkPhysicalDevice device) +{ + VkExtensionProperties *extensions; + uint32_t n_device_extensions; + + vkEnumerateDeviceExtensionProperties (device, NULL, &n_device_extensions, NULL); + + extensions = g_newa (VkExtensionProperties, n_device_extensions); + vkEnumerateDeviceExtensionProperties (device, NULL, &n_device_extensions, extensions); + + for (uint32_t i = 0; i < n_device_extensions; i++) + { + if (g_str_equal (extensions[i].extensionName, VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME)) + return TRUE; + } + + return FALSE; +} + static void gdk_vulkan_context_begin_frame (GdkDrawContext *draw_context, cairo_region_t *region) @@ -414,6 +437,29 @@ gdk_vulkan_context_end_frame (GdkDrawContext *draw_context, { GdkVulkanContext *context = GDK_VULKAN_CONTEXT (draw_context); GdkVulkanContextPrivate *priv = gdk_vulkan_context_get_instance_private (context); + VkPresentRegionsKHR *regionsptr = VK_NULL_HANDLE; + VkPresentRegionsKHR regions; + cairo_rectangle_int_t extents; + + cairo_region_get_extents (painted, &extents); + + regions = (VkPresentRegionsKHR) { + .sType = VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR, + .swapchainCount = 1, + .pRegions = &(VkPresentRegionKHR) { + .rectangleCount = 1, + .pRectangles = &(VkRectLayerKHR) { + .layer = 0, + .offset.x = extents.x, + .offset.y = extents.y, + .extent.width = extents.width, + .extent.height = extents.height, + } + }, + }; + + if (priv->has_present_region) + regionsptr = ®ions; GDK_VK_CHECK (vkQueuePresentKHR, gdk_vulkan_context_get_queue (context), &(VkPresentInfoKHR) { @@ -429,6 +475,7 @@ gdk_vulkan_context_end_frame (GdkDrawContext *draw_context, .pImageIndices = (uint32_t[]) { priv->draw_index }, + .pNext = regionsptr, }); cairo_region_destroy (priv->regions[priv->draw_index]); @@ -491,11 +538,12 @@ gdk_vulkan_context_real_init (GInitable *initable, { GdkVulkanContext *context = GDK_VULKAN_CONTEXT (initable); GdkVulkanContextPrivate *priv = gdk_vulkan_context_get_instance_private (context); + GdkDisplay *display = gdk_draw_context_get_display (GDK_DRAW_CONTEXT (context)); VkResult res; VkBool32 supported; uint32_t i; - priv->vulkan_ref = gdk_display_ref_vulkan (gdk_draw_context_get_display (GDK_DRAW_CONTEXT (context)), error); + priv->vulkan_ref = gdk_display_ref_vulkan (display, error); if (!priv->vulkan_ref) return FALSE; @@ -543,6 +591,7 @@ gdk_vulkan_context_real_init (GInitable *initable, goto out_surface; } priv->image_format = formats[i]; + priv->has_present_region = device_supports_incremental_present (display->vk_physical_device); if (!gdk_vulkan_context_check_swapchain (context, error)) goto out_surface; @@ -866,11 +915,20 @@ gdk_display_create_vulkan_device (GdkDisplay *display, vkGetPhysicalDeviceQueueFamilyProperties (devices[i], &n_queue_props, NULL); VkQueueFamilyProperties *queue_props = g_newa (VkQueueFamilyProperties, n_queue_props); vkGetPhysicalDeviceQueueFamilyProperties (devices[i], &n_queue_props, queue_props); - for (j = 0; j < n_queue_props; j++) { if (queue_props[j].queueFlags & VK_QUEUE_GRAPHICS_BIT) { + GPtrArray *device_extensions; + gboolean has_incremental_present; + + has_incremental_present = device_supports_incremental_present (devices[i]); + + device_extensions = g_ptr_array_new (); + g_ptr_array_add (device_extensions, (gpointer) VK_KHR_SWAPCHAIN_EXTENSION_NAME); + if (has_incremental_present) + g_ptr_array_add (device_extensions, (gpointer) VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME); + GDK_DISPLAY_NOTE (display, VULKAN, g_print ("Using Vulkan device %u, queue %u\n", i, j)); if (GDK_VK_CHECK (vkCreateDevice, devices[i], &(VkDeviceCreateInfo) { @@ -886,14 +944,17 @@ gdk_display_create_vulkan_device (GdkDisplay *display, }, 0, NULL, - 1, - (const char * const []) { - VK_KHR_SWAPCHAIN_EXTENSION_NAME, - }, + device_extensions->len, + (const gchar * const *) device_extensions->pdata }, NULL, &display->vk_device) != VK_SUCCESS) - continue; + { + g_ptr_array_unref (device_extensions); + continue; + } + + g_ptr_array_unref (device_extensions); display->vk_physical_device = devices[i]; vkGetDeviceQueue(display->vk_device, j, 0, &display->vk_queue);