Drop vulkan refcounting

Change things to have a gdk_display_prepare_vulkan call which sets
up Vulkan support for the display. The Vulkan resources will be
dropped when the display is disposed. This matches what we do
for GL, and seems better than a refcounting approach where everybody
leaks the references.

Fixes: #7150
This commit is contained in:
Matthias Clasen
2024-11-11 07:41:59 -05:00
parent 9d8679e211
commit 58036ece96
7 changed files with 70 additions and 84 deletions

View File

@@ -438,11 +438,10 @@ gdk_display_dispose (GObject *object)
g_clear_pointer (&display->egl_dmabuf_formats, gdk_dmabuf_formats_unref);
g_clear_pointer (&display->egl_internal_formats, gdk_dmabuf_formats_unref);
#ifdef GDK_RENDERING_VULKAN
if (display->vk_dmabuf_formats)
{
gdk_display_unref_vulkan (display);
g_assert (display->vk_dmabuf_formats == NULL);
}
if (display->vk_instance)
gdk_display_destroy_vulkan_instance (display);
g_assert (display->vk_dmabuf_formats == NULL);
g_clear_error (&display->vulkan_error);
#endif
g_clear_object (&priv->gl_context);
@@ -1286,6 +1285,53 @@ gdk_display_get_keymap (GdkDisplay *display)
return GDK_DISPLAY_GET_CLASS (display)->get_keymap (display);
}
/*< private >
* gdk_display_prepare_vulkan:
* @self: a `GdkDisplay`
* @error: return location for a `GError`
*
* Checks that Vulkan is available for @self and ensures that it is
* properly initialized.
*
* When this fails, an @error will be set describing the error and this
* function returns %FALSE.
*
* Note that even if this function succeeds, creating a `GdkVulkanContext`
* may still fail.
*
* This function is idempotent. Calling it multiple times will just
* return the same value or error.
*
* You never need to call this function, GDK will call it automatically
* as needed.
*
* Returns: %TRUE if the display supports Vulkan
*/
gboolean
gdk_display_prepare_vulkan (GdkDisplay *self,
GError **error)
{
g_return_val_if_fail (GDK_IS_DISPLAY (self), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
#ifdef GDK_RENDERING_VULKAN
if (!self->vk_instance && !self->vulkan_error)
gdk_display_create_vulkan_instance (self, &self->vulkan_error);
if (self->vk_instance == NULL)
{
if (error)
*error = g_error_copy (self->vulkan_error);
}
return self->vk_instance != NULL;
#else
g_set_error (error, GDK_VULKAN_ERROR, GDK_VULKAN_ERROR_UNSUPPORTED,
"GTK was built without Vulkan support");
return FALSE;
#endif
}
/*<private>
* gdk_display_create_vulkan_context:
* @self: a `GdkDisplay`

View File

@@ -126,7 +126,7 @@ struct _GdkDisplay
GdkDmabufFormats *vk_dmabuf_formats;
GdkVulkanFeatures vulkan_features;
guint vulkan_refcount;
GError *vulkan_error;
#endif /* GDK_RENDERING_VULKAN */
/* egl info */
@@ -239,6 +239,8 @@ void _gdk_display_unpause_events (GdkDisplay *display
void gdk_display_init_dmabuf (GdkDisplay *self);
gboolean gdk_display_prepare_vulkan (GdkDisplay *self,
GError **error);
gboolean gdk_display_has_vulkan_feature (GdkDisplay *self,
GdkVulkanFeatures feature);
GdkVulkanContext * gdk_display_create_vulkan_context (GdkDisplay *self,

View File

@@ -367,7 +367,6 @@ 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;
guint i;
@@ -397,11 +396,6 @@ gdk_vulkan_context_dispose (GObject *gobject)
priv->surface = VK_NULL_HANDLE;
}
/* display will be unset in gdk_draw_context_dispose() */
display = gdk_draw_context_get_display (GDK_DRAW_CONTEXT (context));
if (display && priv->vulkan_ref)
gdk_display_unref_vulkan (display);
G_OBJECT_CLASS (gdk_vulkan_context_parent_class)->dispose (gobject);
}
@@ -887,8 +881,7 @@ gdk_vulkan_context_real_init (GInitable *initable,
VkBool32 supported;
uint32_t i;
priv->vulkan_ref = gdk_display_init_vulkan (display, error);
if (!priv->vulkan_ref)
if (!gdk_display_prepare_vulkan (display, error))
return FALSE;
if (surface == NULL)
@@ -1668,7 +1661,7 @@ gdk_vulkan_debug_report (VkDebugReportFlagsEXT flags,
return VK_FALSE;
}
static gboolean
gboolean
gdk_display_create_vulkan_instance (GdkDisplay *display,
GError **error)
{
@@ -1678,6 +1671,8 @@ gdk_display_create_vulkan_instance (GdkDisplay *display,
gboolean have_debug_report = FALSE;
VkResult res;
g_assert (display->vk_instance == NULL);
if (!gdk_has_feature (GDK_FEATURE_VULKAN))
{
g_set_error_literal (error, GDK_VULKAN_ERROR, GDK_VULKAN_ERROR_NOT_AVAILABLE,
@@ -1804,66 +1799,16 @@ gdk_display_create_vulkan_instance (GdkDisplay *display,
return TRUE;
}
/*
* gdk_display_init_vulkan:
* @display: a display
* @error: A potential error message
*
* Initializes Vulkan and returns an error on failure.
*
* If Vulkan is already initialized, this function returns
* %TRUE and increases the refcount of the existing instance.
*
* You need to gdk_display_unref_vulkan() to close it again.
*
* Returns: %TRUE if Vulkan is initialized.
**/
gboolean
gdk_display_init_vulkan (GdkDisplay *display,
GError **error)
{
if (display->vulkan_refcount == 0)
{
if (!gdk_display_create_vulkan_instance (display, error))
return FALSE;
}
display->vulkan_refcount++;
return TRUE;
}
/*
* gdk_display_ref_vulkan:
* @display: a GdkDisplay
*
* Increases the refcount of an existing Vulkan instance.
*
* This function must not be called if Vulkan may not be initialized
* yet, call gdk_display_init_vulkan() in that case.
**/
void
gdk_display_ref_vulkan (GdkDisplay *display)
{
g_assert (display->vulkan_refcount > 0);
display->vulkan_refcount++;
}
void
gdk_display_unref_vulkan (GdkDisplay *display)
gdk_display_destroy_vulkan_instance (GdkDisplay *display)
{
GHashTableIter iter;
gpointer key, value;
g_return_if_fail (GDK_IS_DISPLAY (display));
g_return_if_fail (display->vulkan_refcount > 0);
g_assert (GDK_IS_DISPLAY (display));
g_assert (display->vk_instance != NULL);
display->vulkan_refcount--;
if (display->vulkan_refcount > 0)
return;
GDK_DEBUG (VULKAN, "Closing Vulkan instance");
GDK_DEBUG (VULKAN, "Destroy Vulkan instance");
display->vulkan_features = 0;
g_clear_pointer (&display->vk_dmabuf_formats, gdk_dmabuf_formats_unref);
g_hash_table_iter_init (&iter, display->vk_shader_modules);
@@ -1941,11 +1886,9 @@ gdk_vulkan_init_dmabuf (GdkDisplay *display)
return;
if (!gdk_has_feature (GDK_FEATURE_DMABUF) ||
!gdk_display_init_vulkan (display, NULL) ||
((display->vulkan_features & GDK_VULKAN_FEATURE_DMABUF) == 0))
{
return;
}
!gdk_display_prepare_vulkan (display, NULL) ||
(display->vulkan_features & GDK_VULKAN_FEATURE_DMABUF) == 0)
return;
vulkan_builder = gdk_dmabuf_formats_builder_new ();

View File

@@ -73,10 +73,9 @@ gdk_vulkan_handle_result (VkResult res,
#define GDK_VK_CHECK(func, ...) gdk_vulkan_handle_result (func (__VA_ARGS__), G_STRINGIFY (func))
gboolean gdk_display_init_vulkan (GdkDisplay *display,
gboolean gdk_display_create_vulkan_instance (GdkDisplay *display,
GError **error);
void gdk_display_ref_vulkan (GdkDisplay *display);
void gdk_display_unref_vulkan (GdkDisplay *display);
void gdk_display_destroy_vulkan_instance (GdkDisplay *display);
void gdk_vulkan_init_dmabuf (GdkDisplay *display);

View File

@@ -343,8 +343,6 @@ gsk_vulkan_device_finalize (GObject *object)
g_clear_pointer (&self->allocators[i], gsk_vulkan_allocator_unref);
g_clear_pointer (&self->external_allocator, gsk_vulkan_allocator_unref);
gdk_display_unref_vulkan (display);
G_OBJECT_CLASS (gsk_vulkan_device_parent_class)->finalize (object);
}
@@ -422,7 +420,7 @@ gsk_vulkan_device_get_for_display (GdkDisplay *display,
if (self)
return GSK_GPU_DEVICE (g_object_ref (self));
if (!gdk_display_init_vulkan (display, error))
if (!gdk_display_prepare_vulkan (display, error))
return NULL;
self = g_object_new (GSK_TYPE_VULKAN_DEVICE, NULL);

View File

@@ -653,7 +653,7 @@ vulkan_supported_platform (GdkSurface *surface,
VkPhysicalDeviceProperties props;
GError *error = NULL;
if (!gdk_display_init_vulkan (display, &error))
if (!gdk_display_prepare_vulkan (display, &error))
{
GSK_DEBUG (RENDERER, "Not using Vulkan%s: %s",
as_fallback ? " as fallback" : "",

View File

@@ -577,7 +577,7 @@ init_vulkan (GtkInspectorGeneral *gen)
const char *types[] = { "other", "integrated GPU", "discrete GPU", "virtual GPU", "CPU" };
GError *error = NULL;
if (!gdk_display_init_vulkan (gen->display, &error))
if (!gdk_display_prepare_vulkan (gen->display, &error))
{
gtk_label_set_text (GTK_LABEL (gen->vk_device), C_("Vulkan device", "None"));
gtk_widget_set_visible (gen->vk_error_row, TRUE);
@@ -617,8 +617,6 @@ init_vulkan (GtkInspectorGeneral *gen)
add_instance_extensions (gen->vulkan_extensions_list);
add_device_extensions (gen->display->vk_physical_device, gen->vulkan_extensions_list);
add_layers (gen->vulkan_layers_list);
gdk_display_unref_vulkan (gen->display);
#else
gtk_label_set_text (GTK_LABEL (gen->vk_device), C_("Vulkan device", "None"));
gtk_widget_set_visible (gen->vk_api_version_row, FALSE);