diff --git a/gdk/gdkvulkancontext.c b/gdk/gdkvulkancontext.c index 9f536c6bfc2355e22a0cc9920d198a8ece58fc25..ec721d53a15ef3b18195adb8851ba00a747d0db4 100644 --- a/gdk/gdkvulkancontext.c +++ b/gdk/gdkvulkancontext.c @@ -80,6 +80,8 @@ struct _GdkVulkanContextPrivate { guint n_images; VkImage *images; cairo_region_t **regions; + + VkSemaphore draw_semaphore; #endif guint32 draw_index; @@ -638,6 +640,8 @@ gdk_vulkan_context_begin_frame (GdkDrawContext *draw_context, VkResult acquire_result; guint i; + g_assert (priv->draw_semaphore != NULL); + color_state = gdk_surface_get_color_state (surface); depth = gdk_memory_depth_merge (depth, gdk_color_state_get_depth (color_state)); @@ -670,7 +674,7 @@ gdk_vulkan_context_begin_frame (GdkDrawContext *draw_context, acquire_result = GDK_VK_CHECK (vkAcquireNextImageKHR, gdk_vulkan_context_get_device (context), priv->swapchain, UINT64_MAX, - VK_NULL_HANDLE, + priv->draw_semaphore, VK_NULL_HANDLE, &priv->draw_index); if ((acquire_result == VK_ERROR_OUT_OF_DATE_KHR) || @@ -690,6 +694,8 @@ gdk_vulkan_context_begin_frame (GdkDrawContext *draw_context, break; } + priv->draw_semaphore = NULL; + cairo_region_union (region, priv->regions[priv->draw_index]); if (priv->current_depth == GDK_MEMORY_U8_SRGB) @@ -1367,6 +1373,31 @@ gdk_vulkan_context_get_draw_index (GdkVulkanContext *context) return priv->draw_index; } +/** + * gdk_vulkan_context_set_draw_semaphore: + * @context: a `GdkVulkanContext` + * @semaphore: a `VkSemaphore` + * + * Sets the Vulkan semaphore that will be used in the immediately following + * gdk_draw_context_begin_frame() call. + * This is essentially an extra argument for that call, but without extending the + * arguments of that generic function with Vulkan-specific things. + * + * This function must be called or begin_frame() will abort. + */ +void +gdk_vulkan_context_set_draw_semaphore (GdkVulkanContext *context, + VkSemaphore semaphore) +{ + GdkVulkanContextPrivate *priv = gdk_vulkan_context_get_instance_private (context); + + g_return_if_fail (GDK_IS_VULKAN_CONTEXT (context)); + g_return_if_fail (!gdk_draw_context_is_in_frame (GDK_DRAW_CONTEXT (context))); + g_return_if_fail (priv->draw_semaphore == NULL); + + priv->draw_semaphore = semaphore; +} + static gboolean gdk_display_create_vulkan_device (GdkDisplay *display, GError **error) diff --git a/gdk/gdkvulkancontextprivate.h b/gdk/gdkvulkancontextprivate.h index c98771eb8f0f9db68c405bb3aff504a28ce5f3da..c0ad9578982eb666de3990a82a6d1100f88083ee 100644 --- a/gdk/gdkvulkancontextprivate.h +++ b/gdk/gdkvulkancontextprivate.h @@ -100,6 +100,9 @@ VkImage gdk_vulkan_context_get_image (GdkVulk guint id); uint32_t gdk_vulkan_context_get_draw_index (GdkVulkanContext *context); +void gdk_vulkan_context_set_draw_semaphore (GdkVulkanContext *context, + VkSemaphore semaphore); + #else /* !GDK_RENDERING_VULKAN */ diff --git a/gsk/gpu/gskglframe.c b/gsk/gpu/gskglframe.c index a9939785ddb25a61badcd9435fa8ff10036b0201..eb4d2ca38668a23c552f36589ce0b377907a108c 100644 --- a/gsk/gpu/gskglframe.c +++ b/gsk/gpu/gskglframe.c @@ -169,9 +169,10 @@ gsk_gl_frame_create_storage_buffer (GskGpuFrame *frame, } static void -gsk_gl_frame_submit (GskGpuFrame *frame, - GskGpuBuffer *vertex_buffer, - GskGpuOp *op) +gsk_gl_frame_submit (GskGpuFrame *frame, + GskRenderPassType pass_type, + GskGpuBuffer *vertex_buffer, + GskGpuOp *op) { GskGLFrame *self = GSK_GL_FRAME (frame); GskGLCommandState state = { 0, }; diff --git a/gsk/gpu/gskgpuframe.c b/gsk/gpu/gskgpuframe.c index fddfdeccbd579dd7c02f29db19cfd79bfe94b2f6..beb7a981e50d3212049f84acd8bd8f06e571689a 100644 --- a/gsk/gpu/gskgpuframe.c +++ b/gsk/gpu/gskgpuframe.c @@ -16,6 +16,7 @@ #include "gskrendererprivate.h" #include "gdk/gdkdmabufdownloaderprivate.h" +#include "gdk/gdkdrawcontextprivate.h" #include "gdk/gdktexturedownloaderprivate.h" #define DEFAULT_VERTEX_BUFFER_SIZE 128 * 1024 @@ -75,6 +76,22 @@ gsk_gpu_frame_default_cleanup (GskGpuFrame *self) priv->last_op = NULL; } +static void +gsk_gpu_frame_default_begin (GskGpuFrame *self, + GdkDrawContext *context, + GdkMemoryDepth depth, + const cairo_region_t *region) +{ + gdk_draw_context_begin_frame_full (context, depth, region); +} + +static void +gsk_gpu_frame_default_end (GskGpuFrame *self, + GdkDrawContext *context) +{ + gdk_draw_context_end_frame (context); +} + static void gsk_gpu_frame_cleanup (GskGpuFrame *self) { @@ -126,6 +143,8 @@ gsk_gpu_frame_class_init (GskGpuFrameClass *klass) klass->setup = gsk_gpu_frame_default_setup; klass->cleanup = gsk_gpu_frame_default_cleanup; + klass->begin = gsk_gpu_frame_default_begin; + klass->end = gsk_gpu_frame_default_end; klass->upload_texture = gsk_gpu_frame_default_upload_texture; object_class->dispose = gsk_gpu_frame_dispose; @@ -156,6 +175,22 @@ gsk_gpu_frame_setup (GskGpuFrame *self, GSK_GPU_FRAME_GET_CLASS (self)->setup (self); } +void +gsk_gpu_frame_begin (GskGpuFrame *self, + GdkDrawContext *context, + GdkMemoryDepth depth, + const cairo_region_t *region) +{ + GSK_GPU_FRAME_GET_CLASS (self)->begin (self, context, depth, region); +} + +void +gsk_gpu_frame_end (GskGpuFrame *self, + GdkDrawContext *context) +{ + GSK_GPU_FRAME_GET_CLASS (self)->end (self, context); +} + GskGpuDevice * gsk_gpu_frame_get_device (GskGpuFrame *self) { @@ -603,7 +638,8 @@ gsk_gpu_frame_record (GskGpuFrame *self, } static void -gsk_gpu_frame_submit (GskGpuFrame *self) +gsk_gpu_frame_submit (GskGpuFrame *self, + GskRenderPassType pass_type) { GskGpuFramePrivate *priv = gsk_gpu_frame_get_instance_private (self); @@ -627,6 +663,7 @@ gsk_gpu_frame_submit (GskGpuFrame *self) } GSK_GPU_FRAME_GET_CLASS (self)->submit (self, + pass_type, priv->vertex_buffer, priv->first_op); } @@ -641,11 +678,13 @@ gsk_gpu_frame_render (GskGpuFrame *self, const graphene_rect_t *viewport, GdkTexture **texture) { + GskRenderPassType pass_type = texture ? GSK_RENDER_PASS_EXPORT : GSK_RENDER_PASS_PRESENT; + gsk_gpu_frame_cleanup (self); gsk_gpu_frame_record (self, timestamp, target, target_color_state, region, node, viewport, texture); - gsk_gpu_frame_submit (self); + gsk_gpu_frame_submit (self, pass_type); } typedef struct _Download Download; @@ -710,6 +749,6 @@ gsk_gpu_frame_download_texture (GskGpuFrame *self, .stride = stride }, sizeof (Download))); - gsk_gpu_frame_submit (self); + gsk_gpu_frame_submit (self, GSK_RENDER_PASS_EXPORT); g_object_unref (image); } diff --git a/gsk/gpu/gskgpuframeprivate.h b/gsk/gpu/gskgpuframeprivate.h index 90a7eef2b628c6ddf8b42eedcfb6fe0c37ec74ea..9d120d68cf7749a95220a56b1a1a6f183fcda60f 100644 --- a/gsk/gpu/gskgpuframeprivate.h +++ b/gsk/gpu/gskgpuframeprivate.h @@ -27,6 +27,12 @@ struct _GskGpuFrameClass void (* wait) (GskGpuFrame *self); void (* setup) (GskGpuFrame *self); void (* cleanup) (GskGpuFrame *self); + void (* begin) (GskGpuFrame *self, + GdkDrawContext *context, + GdkMemoryDepth depth, + const cairo_region_t *region); + void (* end) (GskGpuFrame *self, + GdkDrawContext *context); GskGpuImage * (* upload_texture) (GskGpuFrame *self, gboolean with_mipmap, GdkTexture *texture); @@ -36,6 +42,7 @@ struct _GskGpuFrameClass GskGpuBuffer * (* create_storage_buffer) (GskGpuFrame *self, gsize size); void (* submit) (GskGpuFrame *self, + GskRenderPassType pass_type, GskGpuBuffer *vertex_buffer, GskGpuOp *op); }; @@ -48,6 +55,13 @@ void gsk_gpu_frame_setup (GskGpuF GskGpuDevice *device, GskGpuOptimizations optimizations); +void gsk_gpu_frame_begin (GskGpuFrame *self, + GdkDrawContext *context, + GdkMemoryDepth depth, + const cairo_region_t *region); +void gsk_gpu_frame_end (GskGpuFrame *self, + GdkDrawContext *context); + GdkDrawContext * gsk_gpu_frame_get_context (GskGpuFrame *self) G_GNUC_PURE; GskGpuDevice * gsk_gpu_frame_get_device (GskGpuFrame *self) G_GNUC_PURE; gint64 gsk_gpu_frame_get_timestamp (GskGpuFrame *self) G_GNUC_PURE; diff --git a/gsk/gpu/gskgpunodeprocessor.c b/gsk/gpu/gskgpunodeprocessor.c index 2ae86aa948d336da0673309c1d6ec7dafc52cc9a..17be0ef8c0907a732ec4184b27cf32938bad42eb 100644 --- a/gsk/gpu/gskgpunodeprocessor.c +++ b/gsk/gpu/gskgpunodeprocessor.c @@ -302,30 +302,20 @@ gsk_gpu_node_processor_add_image (GskGpuNodeProcessor *self, } static void -gsk_gpu_node_processor_add_images (GskGpuNodeProcessor *self, - gsize n_images, - GskGpuImage **images, - GskGpuSampler *samplers, - guint32 *out_descriptors) +gsk_gpu_node_processor_add_two_images (GskGpuNodeProcessor *self, + GskGpuImage *image1, + GskGpuSampler sampler1, + GskGpuImage *image2, + GskGpuSampler sampler2, + guint32 *out_descriptors) { GskGpuDescriptors *desc; - gsize i; - - g_assert (n_images > 0); - /* note: This will infloop if more images are requested than can fit into an empty descriptors, - * so don't do that. */ do { - out_descriptors[0] = gsk_gpu_node_processor_add_image (self, images[0], samplers[0]); + out_descriptors[0] = gsk_gpu_node_processor_add_image (self, image1, sampler1); desc = self->desc; - - for (i = 1; i < n_images; i++) - { - out_descriptors[i] = gsk_gpu_node_processor_add_image (self, images[i], samplers[i]); - if (desc != self->desc) - break; - } + out_descriptors[1] = gsk_gpu_node_processor_add_image (self, image2, sampler2); } while (desc != self->desc); } @@ -1079,11 +1069,12 @@ gsk_gpu_node_processor_add_rounded_clip_node_with_mask (GskGpuNodeProcessor *sel (float[4]) { 1, 1, 1, 1 }); gsk_gpu_node_processor_finish_draw (&other, mask_image); - gsk_gpu_node_processor_add_images (self, - 2, - (GskGpuImage *[2]) { child_image, mask_image }, - (GskGpuSampler[2]) { GSK_GPU_SAMPLER_DEFAULT, GSK_GPU_SAMPLER_DEFAULT }, - descriptors); + gsk_gpu_node_processor_add_two_images (self, + child_image, + GSK_GPU_SAMPLER_DEFAULT, + mask_image, + GSK_GPU_SAMPLER_DEFAULT, + descriptors); gsk_gpu_node_processor_sync_globals (self, 0); gsk_gpu_mask_op (self->frame, @@ -2609,11 +2600,12 @@ gsk_gpu_node_processor_add_blend_node (GskGpuNodeProcessor *self, top_rect = *graphene_rect_zero (); } - gsk_gpu_node_processor_add_images (self, - 2, - (GskGpuImage *[2]) { bottom_image, top_image }, - (GskGpuSampler[2]) { GSK_GPU_SAMPLER_DEFAULT, GSK_GPU_SAMPLER_DEFAULT }, - descriptors); + gsk_gpu_node_processor_add_two_images (self, + bottom_image, + GSK_GPU_SAMPLER_DEFAULT, + top_image, + GSK_GPU_SAMPLER_DEFAULT, + descriptors); gsk_gpu_blend_mode_op (self->frame, gsk_gpu_clip_get_shader_clip (&self->clip, &self->offset, &node->bounds), @@ -2686,11 +2678,12 @@ gsk_gpu_node_processor_add_cross_fade_node (GskGpuNodeProcessor *self, return; } - gsk_gpu_node_processor_add_images (self, - 2, - (GskGpuImage *[2]) { start_image, end_image }, - (GskGpuSampler[2]) { GSK_GPU_SAMPLER_DEFAULT, GSK_GPU_SAMPLER_DEFAULT }, - descriptors); + gsk_gpu_node_processor_add_two_images (self, + start_image, + GSK_GPU_SAMPLER_DEFAULT, + end_image, + GSK_GPU_SAMPLER_DEFAULT, + descriptors); gsk_gpu_cross_fade_op (self->frame, gsk_gpu_clip_get_shader_clip (&self->clip, &self->offset, &node->bounds), @@ -2766,11 +2759,12 @@ gsk_gpu_node_processor_add_mask_node (GskGpuNodeProcessor *self, g_object_unref (mask_image); return; } - gsk_gpu_node_processor_add_images (self, - 2, - (GskGpuImage *[2]) { source_image, mask_image }, - (GskGpuSampler[2]) { GSK_GPU_SAMPLER_DEFAULT, GSK_GPU_SAMPLER_DEFAULT }, - descriptors); + gsk_gpu_node_processor_add_two_images (self, + source_image, + GSK_GPU_SAMPLER_DEFAULT, + mask_image, + GSK_GPU_SAMPLER_DEFAULT, + descriptors); gsk_gpu_mask_op (self->frame, gsk_gpu_clip_get_shader_clip (&self->clip, &self->offset, &node->bounds), @@ -3215,11 +3209,12 @@ gsk_gpu_node_processor_add_fill_node (GskGpuNodeProcessor *self, if (source_image == NULL) return; - gsk_gpu_node_processor_add_images (self, - 2, - (GskGpuImage *[2]) { source_image, mask_image }, - (GskGpuSampler[2]) { GSK_GPU_SAMPLER_DEFAULT, GSK_GPU_SAMPLER_DEFAULT }, - descriptors); + gsk_gpu_node_processor_add_two_images (self, + source_image, + GSK_GPU_SAMPLER_DEFAULT, + mask_image, + GSK_GPU_SAMPLER_DEFAULT, + descriptors); gsk_gpu_mask_op (self->frame, gsk_gpu_clip_get_shader_clip (&self->clip, &self->offset, &clip_bounds), @@ -3312,11 +3307,12 @@ gsk_gpu_node_processor_add_stroke_node (GskGpuNodeProcessor *self, if (source_image == NULL) return; - gsk_gpu_node_processor_add_images (self, - 2, - (GskGpuImage *[2]) { source_image, mask_image }, - (GskGpuSampler[2]) { GSK_GPU_SAMPLER_DEFAULT, GSK_GPU_SAMPLER_DEFAULT }, - descriptors); + gsk_gpu_node_processor_add_two_images (self, + source_image, + GSK_GPU_SAMPLER_DEFAULT, + mask_image, + GSK_GPU_SAMPLER_DEFAULT, + descriptors); gsk_gpu_mask_op (self->frame, gsk_gpu_clip_get_shader_clip (&self->clip, &self->offset, &clip_bounds), diff --git a/gsk/gpu/gskgpurenderer.c b/gsk/gpu/gskgpurenderer.c index 1ec4bbd0dafead68e2feb11b68f55c46d939c75d..2e35bb5d2f0e4d81bb095880e282e359dff5d05a 100644 --- a/gsk/gpu/gskgpurenderer.c +++ b/gsk/gpu/gskgpurenderer.c @@ -416,19 +416,19 @@ gsk_gpu_renderer_render (GskRenderer *renderer, return; } - depth = gsk_render_node_get_preferred_depth (root); + gsk_gpu_device_maybe_gc (priv->device); - gdk_draw_context_begin_frame_full (priv->context, depth, region); + depth = gsk_render_node_get_preferred_depth (root); + frame = gsk_gpu_renderer_get_frame (self); + scale = gsk_gpu_renderer_get_scale (self); - gsk_gpu_device_maybe_gc (priv->device); + gsk_gpu_frame_begin (frame, priv->context, depth, region); gsk_gpu_renderer_make_current (self); backbuffer = GSK_GPU_RENDERER_GET_CLASS (self)->get_backbuffer (self); - frame = gsk_gpu_renderer_get_frame (self); render_region = get_render_region (self); - scale = gsk_gpu_renderer_get_scale (self); gsk_gpu_frame_render (frame, g_get_monotonic_time (), @@ -443,9 +443,9 @@ gsk_gpu_renderer_render (GskRenderer *renderer, ), NULL); - gsk_gpu_device_queue_gc (priv->device); + gsk_gpu_frame_end (frame, priv->context); - gdk_draw_context_end_frame (priv->context); + gsk_gpu_device_queue_gc (priv->device); g_clear_pointer (&render_region, cairo_region_destroy); } diff --git a/gsk/gpu/gskvulkanframe.c b/gsk/gpu/gskvulkanframe.c index 52a0cab80ec27380b43f9a3396d1fc66f8d93289..266d7845058358c50df242e4dce5e72246cd77ca 100644 --- a/gsk/gpu/gskvulkanframe.c +++ b/gsk/gpu/gskvulkanframe.c @@ -46,6 +46,7 @@ struct _GskVulkanFrame { GskGpuFrame parent_instance; + VkSemaphore vk_acquire_semaphore; VkFence vk_fence; VkCommandBuffer vk_command_buffer; VkDescriptorPool vk_descriptor_pool; @@ -111,6 +112,13 @@ gsk_vulkan_frame_setup (GskGpuFrame *frame) }, &self->vk_command_buffer); + GDK_VK_CHECK (vkCreateSemaphore, vk_device, + &(VkSemaphoreCreateInfo) { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, + }, + NULL, + &self->vk_acquire_semaphore); + GSK_VK_CHECK (vkCreateFence, vk_device, &(VkFenceCreateInfo) { .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, @@ -155,6 +163,18 @@ gsk_vulkan_frame_cleanup (GskGpuFrame *frame) GSK_GPU_FRAME_CLASS (gsk_vulkan_frame_parent_class)->cleanup (frame); } +static void +gsk_vulkan_frame_begin (GskGpuFrame *frame, + GdkDrawContext *context, + GdkMemoryDepth depth, + const cairo_region_t *region) +{ + GskVulkanFrame *self = GSK_VULKAN_FRAME (frame); + + gdk_vulkan_context_set_draw_semaphore (GDK_VULKAN_CONTEXT (context), self->vk_acquire_semaphore); + GSK_GPU_FRAME_CLASS (gsk_vulkan_frame_parent_class)->begin (frame, context, depth, region); +} + static GskGpuImage * gsk_vulkan_frame_upload_texture (GskGpuFrame *frame, gboolean with_mipmap, @@ -341,9 +361,10 @@ gsk_vulkan_frame_create_storage_buffer (GskGpuFrame *frame, } static void -gsk_vulkan_frame_submit (GskGpuFrame *frame, - GskGpuBuffer *vertex_buffer, - GskGpuOp *op) +gsk_vulkan_frame_submit (GskGpuFrame *frame, + GskRenderPassType pass_type, + GskGpuBuffer *vertex_buffer, + GskGpuOp *op) { GskVulkanFrame *self = GSK_VULKAN_FRAME (frame); GskVulkanSemaphores semaphores; @@ -373,6 +394,13 @@ gsk_vulkan_frame_submit (GskGpuFrame *frame, gsk_pipeline_stages_init (&semaphores.wait_stages); gsk_semaphores_init (&semaphores.signal_semaphores); + if (pass_type == GSK_RENDER_PASS_PRESENT) + { + gsk_vulkan_semaphores_add_wait (&semaphores, + self->vk_acquire_semaphore, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT); + } + state.vk_command_buffer = self->vk_command_buffer; state.vk_render_pass = VK_NULL_HANDLE; state.vk_format = VK_FORMAT_UNDEFINED; @@ -433,6 +461,9 @@ gsk_vulkan_frame_finalize (GObject *object) vkFreeCommandBuffers (vk_device, vk_command_pool, 1, &self->vk_command_buffer); + vkDestroySemaphore (vk_device, + self->vk_acquire_semaphore, + NULL); vkDestroyFence (vk_device, self->vk_fence, NULL); @@ -450,6 +481,7 @@ gsk_vulkan_frame_class_init (GskVulkanFrameClass *klass) gpu_frame_class->wait = gsk_vulkan_frame_wait; gpu_frame_class->setup = gsk_vulkan_frame_setup; gpu_frame_class->cleanup = gsk_vulkan_frame_cleanup; + gpu_frame_class->begin = gsk_vulkan_frame_begin; gpu_frame_class->upload_texture = gsk_vulkan_frame_upload_texture; gpu_frame_class->create_descriptors = gsk_vulkan_frame_create_descriptors; gpu_frame_class->create_vertex_buffer = gsk_vulkan_frame_create_vertex_buffer; diff --git a/gsk/gpu/gskvulkanimage.c b/gsk/gpu/gskvulkanimage.c index 5e28b8fa767af676c891751ffcb465d06f833eec..c11d326e31f0a3d839b49462fb3e4fb1864a918e 100644 --- a/gsk/gpu/gskvulkanimage.c +++ b/gsk/gpu/gskvulkanimage.c @@ -1440,7 +1440,7 @@ gsk_vulkan_image_transition (GskVulkanImage *self, self->vk_access == access) return; - if (self->vk_pipeline_stage == VK_IMAGE_LAYOUT_UNDEFINED && + if (self->vk_pipeline_stage == VK_IMAGE_LAYOUT_GENERAL && self->vk_semaphore) { gsk_vulkan_semaphores_add_wait (semaphores, self->vk_semaphore, stage);