vulkan: implement quitting and resizing the window

As before, only xcb has been implemented.
This commit is contained in:
Matthew Waters 2015-12-01 16:28:28 +11:00
parent 5de6dd9f40
commit 216a321319
10 changed files with 240 additions and 59 deletions

View file

@ -74,9 +74,39 @@ static GstVulkanWindow
struct _GstVulkanDisplayPrivate
{
gint dummy;
GThread *event_thread;
GMutex thread_lock;
GCond thread_cond;
};
static gpointer
_event_thread_main (GstVulkanDisplay * display)
{
g_mutex_lock (&display->priv->thread_lock);
display->main_context = g_main_context_new ();
display->main_loop = g_main_loop_new (display->main_context, FALSE);
g_cond_broadcast (&display->priv->thread_cond);
g_mutex_unlock (&display->priv->thread_lock);
g_main_loop_run (display->main_loop);
g_mutex_lock (&display->priv->thread_lock);
g_main_loop_unref (display->main_loop);
g_main_context_unref (display->main_context);
display->main_loop = NULL;
display->main_context = NULL;
g_cond_broadcast (&display->priv->thread_cond);
g_mutex_unlock (&display->priv->thread_lock);
return NULL;
}
static void
gst_vulkan_display_class_init (GstVulkanDisplayClass * klass)
{
@ -94,11 +124,42 @@ gst_vulkan_display_init (GstVulkanDisplay * display)
{
display->priv = GST_VULKAN_DISPLAY_GET_PRIVATE (display);
display->type = GST_VULKAN_DISPLAY_TYPE_ANY;
g_mutex_init (&display->priv->thread_lock);
g_cond_init (&display->priv->thread_cond);
display->priv->event_thread = g_thread_new ("vkdisplay-event",
(GThreadFunc) _event_thread_main, display);
g_mutex_lock (&display->priv->thread_lock);
while (!display->main_loop)
g_cond_wait (&display->priv->thread_cond, &display->priv->thread_lock);
g_mutex_unlock (&display->priv->thread_lock);
}
static void
gst_vulkan_display_finalize (GObject * object)
{
GstVulkanDisplay *display = GST_VULKAN_DISPLAY (object);
g_mutex_lock (&display->priv->thread_lock);
if (display->main_context && display->event_source) {
g_source_destroy (display->event_source);
g_source_unref (display->event_source);
}
display->event_source = NULL;
if (display->main_loop)
g_main_loop_quit (display->main_loop);
while (display->main_loop)
g_cond_wait (&display->priv->thread_cond, &display->priv->thread_lock);
if (display->priv->event_thread)
g_thread_unref (display->priv->event_thread);
display->priv->event_thread = NULL;
g_mutex_unlock (&display->priv->thread_lock);
G_OBJECT_CLASS (gst_vulkan_display_parent_class)->finalize (object);
}
@ -136,7 +197,7 @@ gst_vulkan_display_new (void)
"(platform: %s), creating dummy",
GST_STR_NULL (user_choice), GST_STR_NULL (platform_choice));
return g_object_new (GST_TYPE_VULKAN_DISPLAY, NULL);
display = g_object_new (GST_TYPE_VULKAN_DISPLAY, NULL);
}
return display;
@ -244,3 +305,21 @@ gst_vulkan_display_default_create_window (GstVulkanDisplay * display)
{
return gst_vulkan_window_new (display);
}
gboolean
gst_vulkan_display_remove_window (GstVulkanDisplay * display,
GstVulkanWindow * window)
{
gboolean ret = FALSE;
GList *l;
GST_OBJECT_LOCK (display);
l = g_list_find (display->windows, window);
if (l) {
display->windows = g_list_delete_link (display->windows, l);
ret = TRUE;
}
GST_OBJECT_UNLOCK (display);
return ret;
}

View file

@ -66,7 +66,11 @@ struct _GstVulkanDisplay
/* <protected> */
GList *windows; /* OBJECT lock */
GMainContext *main_context;
GMainLoop *main_loop;
GSource *event_source;
/* <private> */
GstVulkanDisplayPrivate *priv;
};
@ -86,6 +90,9 @@ GstVulkanDisplayType gst_vulkan_display_get_handle_type (GstVulkanDisplay
gpointer gst_vulkan_display_get_platform_handle (GstVulkanDisplay * display);
GstVulkanWindow * gst_vulkan_display_create_window (GstVulkanDisplay * display);
/* GstVulkanWindow usage only */
gboolean gst_vulkan_display_remove_window (GstVulkanDisplay * display, GstVulkanWindow * window);
G_END_DECLS
#endif /* __GST_VULKAN_DISPLAY_H__ */

View file

@ -56,9 +56,6 @@ struct _GstVulkanSink
/* stream configuration */
GstVideoInfo v_info;
/* runtime variables */
gint to_quit;
};
struct _GstVulkanSinkClass

View file

@ -40,11 +40,16 @@ _get_function_table (GstVulkanSwapper * swapper)
GstVulkanDevice *device = swapper->device;
GstVulkanInstance *instance = gst_vulkan_device_get_instance (device);
if (!instance) {
GST_ERROR_OBJECT (swapper, "Failed to get instance from the device");
return FALSE;
}
#define GET_PROC_ADDRESS_REQUIRED(obj, type, name) \
G_STMT_START { \
obj->G_PASTE (, name) = G_PASTE(G_PASTE(gst_vulkan_, type), _get_proc_address) (type, "vk" G_STRINGIFY(name)); \
if (!obj->G_PASTE(, name)) { \
GST_ERROR_OBJECT (obj, "Failed to find required function vk" G_STRINGIFY(name)); \
gst_object_unref (instance); \
return FALSE; \
} \
} G_STMT_END
@ -60,6 +65,8 @@ _get_function_table (GstVulkanSwapper * swapper)
GET_PROC_ADDRESS_REQUIRED (swapper, device, AcquireNextImageKHR);
GET_PROC_ADDRESS_REQUIRED (swapper, device, QueuePresentKHR);
gst_object_unref (instance);
return TRUE;
#undef GET_PROC_ADDRESS_REQUIRED
@ -102,6 +109,7 @@ _get_window_surface_description (GstVulkanSwapper * swapper,
desc->platform = _gst_display_type_to_vk_platform (dtype);
if (desc->platform == -1) {
GST_ERROR_OBJECT (swapper, "Failed to retrieve platform from display");
gst_object_unref (display);
return FALSE;
}
@ -202,8 +210,8 @@ _vulkan_swapper_retrieve_surface_properties (GstVulkanSwapper * swapper,
swapper->GetPhysicalDeviceSurfaceSupportKHR (gpu, i,
(VkSurfaceDescriptionKHR *) & surface_desc, &supports_present);
if ((swapper->device->
queue_family_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) {
if ((swapper->device->queue_family_props[i].
queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) {
if (supports_present) {
/* found one that supports both */
graphics_queue = present_queue = i;
@ -270,6 +278,14 @@ _vulkan_swapper_retrieve_surface_properties (GstVulkanSwapper * swapper,
return TRUE;
}
static gboolean
_on_window_close (GstVulkanWindow * window, GstVulkanSwapper * swapper)
{
g_atomic_int_set (&swapper->to_quit, 1);
return TRUE;
}
static void
gst_vulkan_swapper_finalize (GObject * object)
{
@ -297,6 +313,9 @@ gst_vulkan_swapper_finalize (GObject * object)
gst_object_unref (swapper->device);
swapper->device = NULL;
g_signal_handler_disconnect (swapper->window, swapper->close_id);
swapper->close_id = 0;
if (swapper->window)
gst_object_unref (swapper->window);
swapper->window = NULL;
@ -335,6 +354,9 @@ gst_vulkan_swapper_new (GstVulkanDevice * device, GstVulkanWindow * window)
return NULL;
}
swapper->close_id = g_signal_connect (swapper->window, "close",
(GCallback) _on_window_close, swapper);
return swapper;
}
@ -491,6 +513,19 @@ _allocate_swapchain (GstVulkanSwapper * swapper, GstCaps * caps,
VkResult err;
guint32 i;
if (!_get_window_surface_description (swapper, &surface_desc)) {
g_set_error (error, GST_VULKAN_ERROR,
GST_VULKAN_ERROR_INITIALIZATION_FAILED,
"Failed to retrieve platform description");
return FALSE;
}
err =
swapper->GetSurfacePropertiesKHR (swapper->device->device,
(VkSurfaceDescriptionKHR *) & surface_desc, &swapper->surf_props);
if (gst_vulkan_error_to_g_error (err, error, "vkGetSurfacePropertiesKHR") < 0)
return FALSE;
/* width and height are either both -1, or both not -1. */
if (swapper->surf_props.currentExtent.width == -1) {
/* If the surface size is undefined, the size is set to
@ -528,20 +563,13 @@ _allocate_swapchain (GstVulkanSwapper * swapper, GstCaps * caps,
n_images_wanted = swapper->surf_props.maxImageCount;
}
if (swapper->surf_props.
supportedTransforms & VK_SURFACE_TRANSFORM_NONE_BIT_KHR) {
if (swapper->
surf_props.supportedTransforms & VK_SURFACE_TRANSFORM_NONE_BIT_KHR) {
preTransform = VK_SURFACE_TRANSFORM_NONE_KHR;
} else {
preTransform = swapper->surf_props.currentTransform;
}
if (!_get_window_surface_description (swapper, &surface_desc)) {
g_set_error (error, GST_VULKAN_ERROR,
GST_VULKAN_ERROR_INITIALIZATION_FAILED,
"Failed to retrieve platform description");
return FALSE;
}
format =
_vk_format_from_video_format (GST_VIDEO_INFO_FORMAT (&swapper->v_info));
color_space = _vk_color_space_from_video_info (&swapper->v_info);
@ -555,8 +583,8 @@ _allocate_swapchain (GstVulkanSwapper * swapper, GstCaps * caps,
"Incorrect usage flags available for the swap images");
return FALSE;
}
if ((swapper->
surf_props.supportedUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)
if ((swapper->surf_props.
supportedUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)
!= 0) {
usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
} else {
@ -887,6 +915,12 @@ gst_vulkan_swapper_render_buffer (GstVulkanSwapper * swapper,
guint32 swap_idx;
VkResult err;
if (g_atomic_int_get (&swapper->to_quit)) {
g_set_error (error, GST_VULKAN_ERROR, GST_VULKAN_ERROR_DEVICE_LOST,
"Output window was closed");
return FALSE;
}
reacquire:
err = vkCreateSemaphore (swapper->device->device, &semaphore_info,
&semaphore);
@ -898,6 +932,8 @@ reacquire:
swapper->swap_chain, -1, semaphore, &swap_idx);
/* TODO: Deal with the VK_SUBOPTIMAL_KHR and VK_ERROR_OUT_OF_DATE_KHR */
if (err == VK_ERROR_OUT_OF_DATE_KHR) {
GST_DEBUG_OBJECT (swapper, "out of date frame acquired");
vkDestroySemaphore (swapper->device->device, semaphore);
if (!_swapchain_resize (swapper, error))
return FALSE;
@ -920,11 +956,24 @@ reacquire:
err = swapper->QueuePresentKHR (swapper->queue->queue, &present);
if (err == VK_ERROR_OUT_OF_DATE_KHR) {
GST_DEBUG_OBJECT (swapper, "out of date frame submitted");
vkDestroySemaphore (swapper->device->device, semaphore);
if (!_swapchain_resize (swapper, error))
return FALSE;
/* FIXME: correct? */
return TRUE;
if (cmd_data.cmd)
vkDestroyCommandBuffer (swapper->device->device, cmd_data.cmd);
cmd_data.cmd = NULL;
if (cmd_data.fence.handle)
vkDestroyFence (swapper->device->device, cmd_data.fence);
cmd_data.fence.handle = 0;
if (cmd_data.notify)
cmd_data.notify (cmd_data.data);
cmd_data.notify = NULL;
goto reacquire;
} else if (gst_vulkan_error_to_g_error (err, error, "vkQueuePresentKHR") < 0)
goto error;

View file

@ -67,6 +67,13 @@ struct _GstVulkanSwapper
PFN_vkGetSwapchainImagesKHR GetSwapchainImagesKHR;
PFN_vkAcquireNextImageKHR AcquireNextImageKHR;
PFN_vkQueuePresentKHR QueuePresentKHR;
/* <private> */
/* runtime variables */
gint to_quit;
/* signal handlers */
gulong close_id;
};
struct _GstVulkanSwapperClass

View file

@ -78,10 +78,23 @@ GstVulkanDummyWindow *gst_vulkan_dummy_window_new (void);
enum
{
SIGNAL_0,
SIGNAL_CLOSE,
LAST_SIGNAL
};
/* static guint gst_vulkan_window_signals[LAST_SIGNAL] = { 0 }; */
static guint gst_vulkan_window_signals[LAST_SIGNAL] = { 0 };
static gboolean
_accum_logical_and (GSignalInvocationHint * ihint, GValue * return_accu,
const GValue * handler_return, gpointer data)
{
gboolean val = g_value_get_boolean (handler_return);
gboolean val2 = g_value_get_boolean (return_accu);
g_value_set_boolean (return_accu, val && val2);
return TRUE;
}
GQuark
gst_vulkan_window_error_quark (void)
@ -115,6 +128,9 @@ _init_debug (void)
static void
gst_vulkan_window_init (GstVulkanWindow * window)
{
window->priv =
G_TYPE_INSTANCE_GET_PRIVATE (window, GST_TYPE_VULKAN_WINDOW,
GstVulkanWindowPrivate);
}
static void
@ -125,6 +141,10 @@ gst_vulkan_window_class_init (GstVulkanWindowClass * klass)
klass->open = GST_DEBUG_FUNCPTR (gst_vulkan_window_default_open);
klass->close = GST_DEBUG_FUNCPTR (gst_vulkan_window_default_close);
gst_vulkan_window_signals[SIGNAL_CLOSE] =
g_signal_new ("close", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0,
(GSignalAccumulator) _accum_logical_and, NULL, NULL, G_TYPE_BOOLEAN, 0);
G_OBJECT_CLASS (klass)->finalize = gst_vulkan_window_finalize;
_init_debug ();
@ -136,7 +156,7 @@ gst_vulkan_window_class_init (GstVulkanWindowClass * klass)
*
* Returns: (transfer full): a new #GstVulkanWindow using @display's connection
*
* Since: 1.4
* Since: 1.10
*/
GstVulkanWindow *
gst_vulkan_window_new (GstVulkanDisplay * display)
@ -217,12 +237,27 @@ void
gst_vulkan_window_close (GstVulkanWindow * window)
{
GstVulkanWindowClass *klass;
gboolean to_close;
g_return_if_fail (GST_IS_VULKAN_WINDOW (window));
klass = GST_VULKAN_WINDOW_GET_CLASS (window);
g_return_if_fail (klass->close != NULL);
return klass->close (window);
g_signal_emit (window, gst_vulkan_window_signals[SIGNAL_CLOSE], 0, &to_close);
if (to_close)
klass->close (window);
}
void
gst_vulkan_window_resize (GstVulkanWindow * window, gint width, gint height)
{
g_return_if_fail (GST_IS_VULKAN_WINDOW (window));
window->priv->surface_width = width;
window->priv->surface_height = height;
/* XXX: possibly queue a resize/redraw */
}
GType gst_vulkan_dummy_window_get_type (void);

View file

@ -95,6 +95,8 @@ gpointer gst_vulkan_window_get_platform_handle (GstVulkanWindow *wi
gboolean gst_vulkan_window_open (GstVulkanWindow * window, GError ** error);
void gst_vulkan_window_close (GstVulkanWindow * window);
void gst_vulkan_window_resize (GstVulkanWindow * window, gint width, gint height);
G_END_DECLS
#endif /* __GST_VULKAN_WINDOW_H__ */

View file

@ -61,17 +61,11 @@ gst_vulkan_display_xcb_finalize (GObject * object)
{
GstVulkanDisplayXCB *display_xcb = GST_VULKAN_DISPLAY_XCB (object);
G_OBJECT_CLASS (gst_vulkan_display_xcb_parent_class)->finalize (object);
if (!display_xcb->foreign_display && display_xcb->platform_handle.connection)
xcb_disconnect (display_xcb->platform_handle.connection);
display_xcb->platform_handle.connection = NULL;
if (display_xcb->event_source) {
g_source_destroy (display_xcb->event_source);
g_source_unref (display_xcb->event_source);
}
display_xcb->event_source = NULL;
G_OBJECT_CLASS (gst_vulkan_display_xcb_parent_class)->finalize (object);
}
static xcb_screen_t *
@ -106,25 +100,23 @@ gst_vulkan_display_xcb_new (const gchar * name)
GST_DEBUG_CATEGORY_GET (gst_vulkan_display_debug, "gldisplay");
ret = g_object_new (GST_TYPE_VULKAN_DISPLAY_XCB, NULL);
ret->platform_handle.connection = connection = xcb_connect (NULL, &screen_no);
connection = xcb_connect (NULL, &screen_no);
if (connection == NULL || xcb_connection_has_error (connection)) {
GST_ERROR_OBJECT (ret,
"Failed to open XCB display connection with name, \'%s\'", name);
gst_object_unref (ret);
GST_ERROR ("Failed to open XCB display connection with name, \'%s\'", name);
return NULL;
}
ret->screen = _get_screen_from_connection (connection, screen_no);
ret->platform_handle.root = ret->screen->root;
ret->event_source = xcb_event_source_new (ret);
ret = gst_vulkan_display_xcb_new_with_connection (connection, screen_no);
GST_VULKAN_DISPLAY (ret)->event_source = xcb_event_source_new (ret);
g_source_attach (GST_VULKAN_DISPLAY (ret)->event_source,
GST_VULKAN_DISPLAY (ret)->main_context);
ret->foreign_display = FALSE;
return ret;
}
/**
* gst_vulkan_display_xcb_new_with_display:
* gst_vulkan_display_xcb_new_with_connection:
* @display: an existing, xcb display
*
* Creates a new display connection from a XCB Display.

View file

@ -166,7 +166,9 @@ gst_vulkan_window_xcb_create_window (GstVulkanWindowXCB * window_xcb)
value_mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
value_list[0] = screen->black_pixel;
value_list[1] = XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_EXPOSURE;
value_list[1] =
XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_EXPOSURE |
XCB_EVENT_MASK_STRUCTURE_NOTIFY;
xcb_create_window (connection, XCB_COPY_FROM_PARENT, window_xcb->win_id,
root_window, x, y, width, height, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT,

View file

@ -82,29 +82,38 @@ _xcb_handle_event (GstVulkanDisplayXCB * display_xcb)
window_xcb =
_find_window_from_xcb_window (display_xcb, client_event->window);
/* TODO: actually quit */
ret = FALSE;
#if 0
if (display->close)
display->close (display->close_data);
#endif
gst_object_unref (window_xcb);
if (window_xcb) {
GST_INFO_OBJECT (window_xcb, "Close requested");
gst_vulkan_window_close (GST_VULKAN_WINDOW (window_xcb));
gst_vulkan_display_remove_window (GST_VULKAN_DISPLAY (display_xcb),
GST_VULKAN_WINDOW (window_xcb));
gst_object_unref (window_xcb);
}
}
g_free (reply);
break;
}
#if 0
case CreateNotify:
case ConfigureNotify:
#if 0
gst_vulkan_window_resize (window, event.xconfigure.width,
event.xconfigure.height);
#endif
break;
case DestroyNotify:
break;
case XCB_CONFIGURE_NOTIFY:{
xcb_configure_notify_event_t *configure_event;
GstVulkanWindowXCB *window_xcb;
configure_event = (xcb_configure_notify_event_t *) event;
window_xcb =
_find_window_from_xcb_window (display_xcb, configure_event->window);
if (window_xcb) {
gst_vulkan_window_resize (GST_VULKAN_WINDOW (window_xcb),
configure_event->width, configure_event->height);
gst_object_unref (window_xcb);
}
break;
}
#if 0
case Expose:
/* non-zero means that other Expose follows
* so just wait for the last one
@ -180,6 +189,8 @@ _xcb_handle_event (GstVulkanDisplayXCB * display_xcb)
GST_DEBUG ("unhandled XCB type: %u", event_code);
break;
}
g_free (event);
}
return ret;