[gtk+/wip/matthiasc/renderpasses: 4/6] Implement multiple render passes



commit 59b4dec216602aa65dcb209a0f41af28e496f9fc
Author: Matthias Clasen <mclasen redhat com>
Date:   Wed Sep 27 20:56:01 2017 -0400

    Implement multiple render passes

 gsk/gskvulkanrender.c        |  343 +++++++++++++++++++++++++++++------------
 gsk/gskvulkanrenderpass.c    |   13 ++-
 gsk/gskvulkanrenderprivate.h |    7 +
 3 files changed, 259 insertions(+), 104 deletions(-)
---
diff --git a/gsk/gskvulkanrender.c b/gsk/gskvulkanrender.c
index 5888866..81792e1 100644
--- a/gsk/gskvulkanrender.c
+++ b/gsk/gskvulkanrender.c
@@ -46,7 +46,6 @@ struct _GskVulkanRender
   VkDescriptorSetLayout descriptor_set_layout;
   VkPipelineLayout pipeline_layout[3]; /* indexed by number of textures */
   GskVulkanUploader *uploader;
-  GskVulkanBuffer *vertex_buffer;
 
   GHashTable *descriptor_set_indexes;
   VkDescriptorPool descriptor_pool;
@@ -57,10 +56,49 @@ struct _GskVulkanRender
 
   GskVulkanImage *target;
 
-  GSList *render_passes;
+  GList *render_passes;
   GSList *cleanup_images;
 };
 
+typedef struct {
+  GskVulkanRender *render;
+  GskVulkanRenderPass *pass;
+  GskVulkanImage *target;
+
+  graphene_matrix_t mvp;
+  int scale_factor;
+  VkRect2D viewport;
+  cairo_region_t *clip;
+
+  VkRenderPass render_pass;
+  GskVulkanBuffer *vertex_data;
+  GArray *wait_semaphores;
+  VkSemaphore signal_semaphore;
+} RenderPassData;
+
+static void
+render_pass_data_free (gpointer v)
+{
+  RenderPassData *data = v;
+
+  gsk_vulkan_render_pass_free (data->pass);
+  g_object_unref (data->target);
+  cairo_region_destroy (data->clip);
+  if (data->render_pass != data->render->render_pass)
+    vkDestroyRenderPass (gdk_vulkan_context_get_device (data->render->vulkan),
+                         data->render_pass,
+                         NULL);
+  if (data->vertex_data)
+    gsk_vulkan_buffer_free (data->vertex_data);
+  if (data->signal_semaphore != VK_NULL_HANDLE)
+    vkDestroySemaphore (gdk_vulkan_context_get_device (data->render->vulkan),
+                        data->signal_semaphore,
+                        NULL);
+  if (data->wait_semaphores)
+    g_array_unref (data->wait_semaphores);
+  g_free (data);
+}
+
 static void
 gsk_vulkan_render_setup (GskVulkanRender       *self,
                          GskVulkanImage        *target,
@@ -285,70 +323,164 @@ void
 gsk_vulkan_render_add_node (GskVulkanRender *self,
                             GskRenderNode   *node)
 {
-  GskVulkanRenderPass *pass = gsk_vulkan_render_pass_new (self->vulkan);
-
-  self->render_passes = g_slist_prepend (self->render_passes, pass);
-
-  gsk_vulkan_render_pass_add (pass,
+  RenderPassData *data;
+
+  data = g_new0 (RenderPassData, 1);
+  data->pass = gsk_vulkan_render_pass_new (self->vulkan);
+  data->target = g_object_ref (self->target);
+  data->render = self;
+  data->scale_factor = self->scale_factor;
+  data->clip = cairo_region_copy (self->clip);
+  data->render_pass = self->render_pass;
+  data->signal_semaphore = VK_NULL_HANDLE;
+  data->wait_semaphores = NULL;
+  data->viewport = self->viewport;
+  data->mvp = self->mvp;
+
+  self->render_passes = g_list_prepend (self->render_passes, data);
+
+  gsk_vulkan_render_pass_add (data->pass,
                               self,
-                              &self->mvp,
+                              &data->mvp,
                               &GRAPHENE_RECT_INIT (
-                                  self->viewport.offset.x, self->viewport.offset.y,
-                                  self->viewport.extent.width, self->viewport.extent.height
+                                  data->viewport.offset.x, data->viewport.offset.y,
+                                  data->viewport.extent.width, data->viewport.extent.height
                               ),
                               node);
 }
 
-void
-gsk_vulkan_render_upload (GskVulkanRender *self)
+static void
+add_wait_semaphore (GskVulkanRender     *self,
+                    GskVulkanRenderPass *pass,
+                    VkSemaphore          semaphore)
 {
-  GSList *l;
+  GList *l;
+
+  if (semaphore == VK_NULL_HANDLE)
+    return;
 
   for (l = self->render_passes; l; l = l->next)
     {
-      gsk_vulkan_render_pass_upload (l->data, self, self->uploader);
-    }
+      RenderPassData *data = l->data;
+      if (data->pass == pass)
+        {
+          if (data->wait_semaphores == NULL)
+            data->wait_semaphores = g_array_new (FALSE, FALSE, sizeof (VkSemaphore));
 
-  gsk_vulkan_uploader_upload (self->uploader);
+          g_array_append_val (data->wait_semaphores, semaphore);
+          return;
+        }
+    }
 }
 
-static gsize
-gsk_vulkan_renderer_count_vertex_data (GskVulkanRender *self)
+void
+gsk_vulkan_render_add_node_for_texture (GskVulkanRender     *self,
+                                        GskVulkanRenderPass *pass,
+                                        GskRenderNode       *node,
+                                        const graphene_rect_t *bounds,
+                                        GskVulkanImage      *target)
 {
-  gsize n_bytes;
-  GSList *l;
+  RenderPassData *data;
+
+  data = g_new0 (RenderPassData, 1);
+  data->pass = gsk_vulkan_render_pass_new (self->vulkan);
+  data->target = g_object_ref (target);
+  data->render = self;
+  data->scale_factor = 1;
+  data->clip = cairo_region_create_rectangle (&(cairo_rectangle_int_t) {
+                                                0, 0,
+                                                gsk_vulkan_image_get_width (target),
+                                                gsk_vulkan_image_get_height (target)
+                                                });
+  data->viewport.offset = (VkOffset2D) { 0, 0 };
+  data->viewport.extent.width = gsk_vulkan_image_get_width (target);
+  data->viewport.extent.height = gsk_vulkan_image_get_height (target);
+
+  graphene_matrix_init_ortho (&data->mvp,
+                              bounds->origin.x, bounds->origin.x + bounds->size.width,
+                              bounds->origin.y, bounds->origin.y + bounds->size.height,
+                              ORTHO_NEAR_PLANE,
+                              ORTHO_FAR_PLANE);
 
-  n_bytes = 0;
-  for (l = self->render_passes; l; l = l->next)
-    {
-      n_bytes += gsk_vulkan_render_pass_count_vertex_data (l->data);
-    }
+  vkCreateSemaphore (gdk_vulkan_context_get_device (self->vulkan),
+                     &(VkSemaphoreCreateInfo) {
+                        VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
+                        NULL,
+                        0
+                     },
+                     NULL,
+                     &data->signal_semaphore);
+  add_wait_semaphore (self, pass, data->signal_semaphore);
+
+  GSK_VK_CHECK (vkCreateRenderPass, gdk_vulkan_context_get_device (self->vulkan),
+                                    &(VkRenderPassCreateInfo) {
+                                        .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
+                                        .attachmentCount = 1,
+                                        .pAttachments = (VkAttachmentDescription[]) {
+                                           {
+                                              .format = gdk_vulkan_context_get_image_format (self->vulkan),
+                                              .samples = VK_SAMPLE_COUNT_1_BIT,
+                                              .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
+                                              .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
+                                              .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
+                                              .finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
+                                           }
+                                        },
+                                        .subpassCount = 1,
+                                        .pSubpasses = (VkSubpassDescription []) {
+                                           {
+                                              .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
+                                              .inputAttachmentCount = 0,
+                                              .colorAttachmentCount = 1,
+                                              .pColorAttachments = (VkAttachmentReference []) {
+                                                 {
+                                                    .attachment = 0,
+                                                     .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
+                                                  }
+                                               },
+                                               .pResolveAttachments = (VkAttachmentReference []) {
+                                                  {
+                                                     .attachment = VK_ATTACHMENT_UNUSED,
+                                                     .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
+                                                  }
+                                               },
+                                               .pDepthStencilAttachment = NULL,
+                                            }
+                                         },
+                                         .dependencyCount = 0
+                                      },
+                                      NULL,
+                                      &data->render_pass);
+
+  self->render_passes = g_list_prepend (self->render_passes, data);
 
-  return n_bytes;
+  gsk_vulkan_render_pass_add (data->pass,
+                              self,
+                              &data->mvp,
+                              &GRAPHENE_RECT_INIT (
+                                  data->viewport.offset.x, data->viewport.offset.y,
+                                  data->viewport.extent.width, data->viewport.extent.height
+                              ),
+                              node);
 }
 
-static GskVulkanBuffer *
-gsk_vulkan_render_collect_vertex_data (GskVulkanRender *self)
+void
+gsk_vulkan_render_upload (GskVulkanRender *self)
 {
-  GskVulkanBuffer *buffer;
-  guchar *data;
-  GSList *l;
-  gsize offset, n_bytes;
-  
-  offset = 0;
-  n_bytes = gsk_vulkan_renderer_count_vertex_data (self);
-  buffer = gsk_vulkan_buffer_new (self->vulkan, n_bytes);
-  data = gsk_vulkan_buffer_map (buffer);
+  GList *l;
+
+  /* gsk_vulkan_render_pass_upload may call gsk_vulkan_render_add_node_for_texture,
+   * prepending new render passes to the list. Therefore, we walk the list from
+   * the end.
+   */
+  for (l = g_list_last (self->render_passes); l; l = l->prev)
 
-  for (l = self->render_passes; l; l = l->next)
     {
-      offset += gsk_vulkan_render_pass_collect_vertex_data (l->data, self, data, offset, n_bytes - offset);
-      g_assert (offset <= n_bytes);
+      RenderPassData *data = l->data;
+      gsk_vulkan_render_pass_upload (data->pass, self, self->uploader);
     }
 
-  gsk_vulkan_buffer_unmap (buffer);
-
-  return buffer;
+  gsk_vulkan_uploader_upload (self->uploader);
 }
 
 GskVulkanPipeline *
@@ -424,6 +556,8 @@ gsk_vulkan_render_reserve_descriptor_set (GskVulkanRender *self,
 {
   gpointer id_plus_one;
 
+  g_assert (source != NULL);
+
   id_plus_one = g_hash_table_lookup (self->descriptor_set_indexes, source);
   if (id_plus_one)
     return GPOINTER_TO_SIZE (id_plus_one) - 1;
@@ -441,14 +575,15 @@ gsk_vulkan_render_prepare_descriptor_sets (GskVulkanRender *self,
   GHashTableIter iter;
   gpointer key, value;
   VkDevice device;
-  GSList *l;
+  GList *l;
   guint i, needed_sets;
 
   device = gdk_vulkan_context_get_device (self->vulkan);
 
   for (l = self->render_passes; l; l = l->next)
     {
-      gsk_vulkan_render_pass_reserve_descriptor_sets (l->data, self);
+      RenderPassData *data = l->data;
+      gsk_vulkan_render_pass_reserve_descriptor_sets (data->pass, self);
     }
   
   needed_sets = g_hash_table_size (self->descriptor_set_indexes);
@@ -534,75 +669,83 @@ void
 gsk_vulkan_render_draw (GskVulkanRender   *self,
                         VkSampler          sampler)
 {
-  VkCommandBuffer command_buffer;
-  GSList *l;
-  guint i;
+  GList *l;
 
   gsk_vulkan_render_prepare_descriptor_sets (self, sampler);
 
-  command_buffer = gsk_vulkan_command_pool_get_buffer (self->command_pool);
-
-  self->vertex_buffer = gsk_vulkan_render_collect_vertex_data (self);
-
-  vkCmdSetViewport (command_buffer,
-                    0,
-                    1,
-                    &(VkViewport) {
-                      .x = 0,
-                      .y = 0,
-                      .width = self->viewport.extent.width,
-                      .height = self->viewport.extent.height,
-                      .minDepth = 0,
-                      .maxDepth = 1
-                    });
-
-  for (i = 0; i < cairo_region_num_rectangles (self->clip); i++)
+  for (l = self->render_passes; l; l = l->next)
     {
-      cairo_rectangle_int_t rect;
-
-      cairo_region_get_rectangle (self->clip, i, &rect);
-
-      vkCmdSetScissor (command_buffer,
-                       0,
-                       1,
-                       &(VkRect2D) {
-                           { rect.x * self->scale_factor, rect.y * self->scale_factor },
-                           { rect.width * self->scale_factor, rect.height * self->scale_factor }
+      RenderPassData *pass = l->data;
+      VkCommandBuffer command_buffer;
+      guint i;
+
+      pass->vertex_data = gsk_vulkan_render_pass_get_vertex_data (pass->pass, self);
+
+      command_buffer = gsk_vulkan_command_pool_get_buffer (self->command_pool);
+
+      vkCmdSetViewport (command_buffer,
+                        0,
+                        1,
+                        &(VkViewport) {
+                          .x = 0,
+                          .y = 0,
+                          .width = pass->viewport.extent.width,
+                          .height = pass->viewport.extent.height,
+                          .minDepth = 0,
+                           .maxDepth = 1
                        });
 
-      vkCmdBeginRenderPass (command_buffer,
-                            &(VkRenderPassBeginInfo) {
-                                .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
-                                .renderPass = self->render_pass,
-                                .framebuffer = gsk_vulkan_render_get_framebuffer (self, self->target),
-                                .renderArea = { 
-                                    { rect.x * self->scale_factor, rect.y * self->scale_factor },
-                                    { rect.width * self->scale_factor, rect.height * self->scale_factor }
-                                },
-                                .clearValueCount = 1,
-                                .pClearValues = (VkClearValue [1]) {
-                                    { .color = { .float32 = { 0.f, 0.f, 0.f, 0.f } } }
-                                }
-                            },
-                            VK_SUBPASS_CONTENTS_INLINE);
-
-      for (l = self->render_passes; l; l = l->next)
+      for (i = 0; i < cairo_region_num_rectangles (pass->clip); i++)
         {
-          gsk_vulkan_render_pass_draw (l->data, self, self->vertex_buffer, 3, self->pipeline_layout, 
command_buffer);
+          cairo_rectangle_int_t rect;
+
+          cairo_region_get_rectangle (pass->clip, i, &rect);
+
+          vkCmdSetScissor (command_buffer,
+                           0,
+                           1,
+                           &(VkRect2D) {
+                               { rect.x * pass->scale_factor, rect.y * pass->scale_factor },
+                               { rect.width * pass->scale_factor, rect.height * pass->scale_factor }
+                           });
+
+          vkCmdBeginRenderPass (command_buffer,
+                                &(VkRenderPassBeginInfo) {
+                                    .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
+                                    .renderPass = pass->render_pass,
+                                    .framebuffer = gsk_vulkan_render_get_framebuffer (self, pass->target),
+                                    .renderArea = { 
+                                      { rect.x * pass->scale_factor, rect.y * pass->scale_factor },
+                                      { rect.width * pass->scale_factor, rect.height * pass->scale_factor }
+                                    },
+                                    .clearValueCount = 1,
+                                    .pClearValues = (VkClearValue [1]) {
+                                        { .color = { .float32 = { 0.f, 0.f, 0.f, 0.f } } }
+                                    }
+                                },
+                                VK_SUBPASS_CONTENTS_INLINE);
+
+          gsk_vulkan_render_pass_draw (pass->pass, self, pass->vertex_data, 3, self->pipeline_layout, 
command_buffer);
+
+          vkCmdEndRenderPass (command_buffer);
         }
 
-      vkCmdEndRenderPass (command_buffer);
+      gsk_vulkan_command_pool_submit_buffer (self->command_pool,
+                                             command_buffer,
+                                             pass->wait_semaphores ? pass->wait_semaphores->len : 0,
+                                             (VkSemaphore*)(pass->wait_semaphores ? 
pass->wait_semaphores->data : NULL),
+                                             pass->signal_semaphore != VK_NULL_HANDLE ? 1 : 0,
+                                             (VkSemaphore*)&pass->signal_semaphore,
+                                             l->next != NULL ? VK_NULL_HANDLE : self->fence);
     }
 
-  gsk_vulkan_command_pool_submit_buffer (self->command_pool, command_buffer, 0, NULL, 0, NULL, self->fence);
-
   if (GSK_RENDER_MODE_CHECK (SYNC))
     {
       GSK_VK_CHECK (vkWaitForFences, gdk_vulkan_context_get_device (self->vulkan),
                                      1,
                                      &self->fence,
                                      VK_TRUE,
-                                     INT64_MAX);
+                                     1000000);
     }
 }
 
@@ -624,7 +767,7 @@ gsk_vulkan_render_cleanup (GskVulkanRender *self)
                                  1,
                                  &self->fence,
                                  VK_TRUE,
-                                 INT64_MAX);
+                                 1000000);
 
   GSK_VK_CHECK (vkResetFences, device,
                                1,
@@ -634,14 +777,12 @@ gsk_vulkan_render_cleanup (GskVulkanRender *self)
 
   gsk_vulkan_command_pool_reset (self->command_pool);
 
-  g_clear_pointer (&self->vertex_buffer, gsk_vulkan_buffer_free);
-
   g_hash_table_remove_all (self->descriptor_set_indexes);
   GSK_VK_CHECK (vkResetDescriptorPool, device,
                                        self->descriptor_pool,
                                        0);
 
-  g_slist_free_full (self->render_passes, (GDestroyNotify) gsk_vulkan_render_pass_free);
+  g_list_free_full (self->render_passes, (GDestroyNotify) render_pass_data_free);
   self->render_passes = NULL;
   g_slist_free_full (self->cleanup_images, g_object_unref);
   self->cleanup_images = NULL;
diff --git a/gsk/gskvulkanrenderpass.c b/gsk/gskvulkanrenderpass.c
index 022c08d..3500f12 100644
--- a/gsk/gskvulkanrenderpass.c
+++ b/gsk/gskvulkanrenderpass.c
@@ -118,6 +118,7 @@ gsk_vulkan_render_pass_new (GdkVulkanContext *context)
   self = g_slice_new0 (GskVulkanRenderPass);
   self->vulkan = g_object_ref (context);
   self->render_ops = g_array_new (FALSE, FALSE, sizeof (GskVulkanOp));
+
 #ifdef G_ENABLE_DEBUG
   self->fallback_pixels = g_quark_from_static_string ("fallback-pixels");
 #endif
@@ -566,8 +567,12 @@ gsk_vulkan_render_pass_get_node_as_texture (GskVulkanRenderPass   *self,
           surface = cairo_surface_reference (gsk_cairo_node_get_surface (node));
           goto got_surface;
 
-        default:
-          break;
+        default: ;
+          result = gsk_vulkan_image_new_for_texture (self->vulkan,
+                                                     ceil (bounds->size.width),
+                                                     ceil (bounds->size.height));
+          gsk_vulkan_render_add_node_for_texture (render, self, node, bounds, result);
+          return result;
         }
     }
 
@@ -756,7 +761,7 @@ gsk_vulkan_render_pass_upload (GskVulkanRenderPass  *self,
           {
             GskRenderNode *child = gsk_color_matrix_node_get_child (op->render.node);
 
-            op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self, 
+            op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
                                                                             render,
                                                                             uploader,
                                                                             child,
@@ -892,6 +897,7 @@ gsk_vulkan_render_pass_count_vertex_data (GskVulkanRenderPass *self)
 
         default:
           g_assert_not_reached ();
+
         case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
           continue;
         }
@@ -1180,6 +1186,7 @@ gsk_vulkan_render_pass_reserve_descriptor_sets (GskVulkanRenderPass *self,
 
         default:
           g_assert_not_reached ();
+
         case GSK_VULKAN_OP_COLOR:
         case GSK_VULKAN_OP_LINEAR_GRADIENT:
         case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
diff --git a/gsk/gskvulkanrenderprivate.h b/gsk/gskvulkanrenderprivate.h
index 4bd2484..2cce883 100644
--- a/gsk/gskvulkanrenderprivate.h
+++ b/gsk/gskvulkanrenderprivate.h
@@ -69,6 +69,13 @@ void                    gsk_vulkan_render_add_cleanup_image             (GskVulk
 void                    gsk_vulkan_render_add_node                      (GskVulkanRender        *self,
                                                                          GskRenderNode          *node);
 
+void                    gsk_vulkan_render_add_node_for_texture          (GskVulkanRender        *self,
+                                                                         GskVulkanRenderPass    *pass,
+                                                                         GskRenderNode          *node,
+                                                                         const graphene_rect_t *bounds,
+                                                                         GskVulkanImage         *target);
+
+
 void                    gsk_vulkan_render_upload                        (GskVulkanRender        *self);
 
 GskVulkanPipeline *     gsk_vulkan_render_get_pipeline                  (GskVulkanRender        *self,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]