[gtk+] vulkan: Implement gsk_renderer_render_texture()



commit 786d3a013e0ec7f19999f05f32df1110585d6443
Author: Benjamin Otte <otte redhat com>
Date:   Thu Dec 22 19:01:07 2016 +0100

    vulkan: Implement gsk_renderer_render_texture()

 gsk/gskvulkanbuffer.c        |    6 +++
 gsk/gskvulkanbufferprivate.h |    2 +
 gsk/gskvulkancommandpool.c   |    4 ++
 gsk/gskvulkanimage.c         |   85 ++++++++++++++++++++++++++++++++++++++++++
 gsk/gskvulkanimageprivate.h  |    7 +++
 gsk/gskvulkanrender.c        |   68 ++++++++++++++++++++++-----------
 gsk/gskvulkanrenderer.c      |   51 ++++++++++++++++++++++++-
 gsk/gskvulkanrenderprivate.h |    5 ++-
 8 files changed, 204 insertions(+), 24 deletions(-)
---
diff --git a/gsk/gskvulkanbuffer.c b/gsk/gskvulkanbuffer.c
index 3c1d76d..ec5905b 100644
--- a/gsk/gskvulkanbuffer.c
+++ b/gsk/gskvulkanbuffer.c
@@ -71,6 +71,12 @@ gsk_vulkan_buffer_new_staging (GdkVulkanContext  *context,
   return gsk_vulkan_buffer_new_internal (context, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
 }
 
+GskVulkanBuffer *
+gsk_vulkan_buffer_new_download (GdkVulkanContext  *context,
+                                gsize              size)
+{
+  return gsk_vulkan_buffer_new_internal (context, size, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
+}
 void
 gsk_vulkan_buffer_free (GskVulkanBuffer *self)
 {
diff --git a/gsk/gskvulkanbufferprivate.h b/gsk/gskvulkanbufferprivate.h
index 30e327e..700e400 100644
--- a/gsk/gskvulkanbufferprivate.h
+++ b/gsk/gskvulkanbufferprivate.h
@@ -11,6 +11,8 @@ GskVulkanBuffer *       gsk_vulkan_buffer_new                           (GdkVulk
                                                                          gsize                   size);
 GskVulkanBuffer *       gsk_vulkan_buffer_new_staging                   (GdkVulkanContext       *context,
                                                                          gsize                   size);
+GskVulkanBuffer *       gsk_vulkan_buffer_new_download                  (GdkVulkanContext       *context,
+                                                                         gsize                   size);
 void                    gsk_vulkan_buffer_free                          (GskVulkanBuffer        *buffer);
 
 VkBuffer                gsk_vulkan_buffer_get_buffer                    (GskVulkanBuffer        *self);
diff --git a/gsk/gskvulkancommandpool.c b/gsk/gskvulkancommandpool.c
index 218a8c9..09dd333 100644
--- a/gsk/gskvulkancommandpool.c
+++ b/gsk/gskvulkancommandpool.c
@@ -83,10 +83,12 @@ gsk_vulkan_command_pool_submit_buffer (GskVulkanCommandPool *self,
                                1,
                                &(VkSubmitInfo) {
                                   .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
+#if 0
                                   .waitSemaphoreCount = 1,
                                   .pWaitSemaphores = (VkSemaphore[1]) {
                                       gdk_vulkan_context_get_draw_semaphore (self->vulkan)
                                   },
+#endif
                                   .pWaitDstStageMask = (VkPipelineStageFlags []) {
                                       VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
                                   },
@@ -94,10 +96,12 @@ gsk_vulkan_command_pool_submit_buffer (GskVulkanCommandPool *self,
                                   .pCommandBuffers = (VkCommandBuffer[1]) {
                                       command_buffer
                                   },
+#if 0
                                   .signalSemaphoreCount = 1,
                                   .pSignalSemaphores = (VkSemaphore[1]) {
                                       gdk_vulkan_context_get_draw_semaphore (self->vulkan)
                                   }
+#endif
                                },
                                fence);
 }
diff --git a/gsk/gskvulkanimage.c b/gsk/gskvulkanimage.c
index b403768..9ef2c51 100644
--- a/gsk/gskvulkanimage.c
+++ b/gsk/gskvulkanimage.c
@@ -562,6 +562,91 @@ gsk_vulkan_image_new_for_swapchain (GdkVulkanContext *context,
   return self;
 }
 
+GskVulkanImage *
+gsk_vulkan_image_new_for_framebuffer (GdkVulkanContext *context,
+                                      gsize             width,
+                                      gsize             height)
+{
+  GskVulkanImage *self;
+
+
+  self = gsk_vulkan_image_new (context,
+                               width,
+                               height, 
+                               VK_IMAGE_TILING_OPTIMAL,
+                               VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
+                               VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+
+  gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_SRGB);
+
+  return self;
+}
+
+GskTexture *
+gsk_vulkan_image_download (GskVulkanImage    *self,
+                           GskVulkanUploader *uploader)
+{
+  GskVulkanBuffer *buffer;
+  GskTexture *texture;
+  guchar *mem;
+
+  gsk_vulkan_uploader_add_image_barrier (uploader,
+                                         FALSE,
+                                         &(VkImageMemoryBarrier) {
+                                             .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
+                                             .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
+                                             .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
+                                             .oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
+                                             .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+                                             .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+                                             .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+                                             .image = self->vk_image,
+                                             .subresourceRange = {
+                                                 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+                                                 .baseMipLevel = 0,
+                                                 .levelCount = 1,
+                                                 .baseArrayLayer = 0,
+                                                 .layerCount = 1
+                                             }
+                                         });
+
+  buffer = gsk_vulkan_buffer_new_download (self->vulkan, self->width * self->height * 4);
+
+  vkCmdCopyImageToBuffer (gsk_vulkan_uploader_get_copy_buffer (uploader),
+                          self->vk_image,
+                          VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+                          gsk_vulkan_buffer_get_buffer (buffer),
+                          1,
+                          (VkBufferImageCopy[1]) {
+                               {
+                                   .bufferOffset = 0,
+                                   .imageSubresource = {
+                                       .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+                                       .mipLevel = 0,
+                                       .baseArrayLayer = 0,
+                                       .layerCount = 1
+                                   },
+                                   .imageOffset = { 0, 0, 0 },
+                                   .imageExtent = {
+                                       .width = self->width,
+                                       .height = self->height,
+                                       .depth = 1
+                                   }
+                               }
+                          });
+
+  gsk_vulkan_uploader_upload (uploader);
+
+  GSK_VK_CHECK (vkQueueWaitIdle, gdk_vulkan_context_get_queue (self->vulkan));
+
+  mem = gsk_vulkan_buffer_map (buffer);
+  texture = gsk_texture_new_for_data (mem, self->width, self->height, self->width * 4);
+  gsk_vulkan_buffer_unmap (buffer);
+  gsk_vulkan_buffer_free (buffer);
+
+  return texture;
+}
+
 void
 gsk_vulkan_image_finalize (GObject *object)
 {
diff --git a/gsk/gskvulkanimageprivate.h b/gsk/gskvulkanimageprivate.h
index 45d8ca2..feade29 100644
--- a/gsk/gskvulkanimageprivate.h
+++ b/gsk/gskvulkanimageprivate.h
@@ -3,6 +3,7 @@
 
 #include <gdk/gdk.h>
 
+#include "gsk/gsktexture.h"
 #include "gsk/gskvulkancommandpoolprivate.h"
 
 G_BEGIN_DECLS
@@ -30,6 +31,12 @@ GskVulkanImage *        gsk_vulkan_image_new_from_data                  (GskVulk
                                                                          gsize                   width,
                                                                          gsize                   height,
                                                                          gsize                   stride);
+GskVulkanImage *        gsk_vulkan_image_new_for_framebuffer            (GdkVulkanContext       *context,
+                                                                         gsize                   width,
+                                                                         gsize                   height);
+
+GskTexture *            gsk_vulkan_image_download                       (GskVulkanImage         *self,
+                                                                         GskVulkanUploader      *uploader);
 
 gsize                   gsk_vulkan_image_get_width                      (GskVulkanImage         *self);
 gsize                   gsk_vulkan_image_get_height                     (GskVulkanImage         *self);
diff --git a/gsk/gskvulkanrender.c b/gsk/gskvulkanrender.c
index 05ca19c..eabdd6f 100644
--- a/gsk/gskvulkanrender.c
+++ b/gsk/gskvulkanrender.c
@@ -24,7 +24,7 @@ struct _GskVulkanRender
 
   graphene_matrix_t mvp;
   int scale_factor;
-  VkExtent2D size;
+  VkRect2D viewport;
   VkRect2D scissor;
 
   GHashTable *framebuffers;
@@ -48,29 +48,41 @@ struct _GskVulkanRender
 };
 
 static void
-gsk_vulkan_render_compute_mvp (GskVulkanRender *self)
+gsk_vulkan_render_compute_mvp (GskVulkanRender       *self,
+                               const graphene_rect_t *rect)
 {
   GdkWindow *window = gsk_renderer_get_window (self->renderer);
   graphene_matrix_t modelview, projection;
   cairo_rectangle_int_t extents;
 
-  cairo_region_get_extents (gdk_drawing_context_get_clip (gsk_renderer_get_drawing_context (self->renderer)),
-                            &extents);
-
-  self->scale_factor = gsk_renderer_get_scale_factor (self->renderer);
-  self->size.width = gdk_window_get_width (window) * self->scale_factor;
-  self->size.height = gdk_window_get_height (window) * self->scale_factor;
-  self->scissor.offset.x = extents.x * self->scale_factor;
-  self->scissor.offset.y = extents.y * self->scale_factor;
-  self->scissor.extent.width = extents.width * self->scale_factor;
-  self->scissor.extent.height = extents.height * self->scale_factor;
+  if (rect)
+    {
+      self->scissor = (VkRect2D) { { rect->origin.x, rect->origin.y }, { rect->size.width, rect->size.height 
} };
+      self->viewport = self->scissor;
+      self->scale_factor = 1;
+    }
+  else
+    {
+      cairo_region_get_extents (gdk_drawing_context_get_clip (gsk_renderer_get_drawing_context 
(self->renderer)),
+                                &extents);
+
+      self->scale_factor = gsk_renderer_get_scale_factor (self->renderer);
+      self->viewport.offset = (VkOffset2D) { 0, 0 };
+      self->viewport.extent.width = gdk_window_get_width (window) * self->scale_factor;
+      self->viewport.extent.height = gdk_window_get_height (window) * self->scale_factor;
+      self->scissor.offset.x = extents.x * self->scale_factor;
+      self->scissor.offset.y = extents.y * self->scale_factor;
+      self->scissor.extent.width = extents.width * self->scale_factor;
+      self->scissor.extent.height = extents.height * self->scale_factor;
+    }
 
   graphene_matrix_init_scale (&modelview, self->scale_factor, self->scale_factor, 1.0);
   graphene_matrix_init_ortho (&projection,
-                              0, self->size.width,
-                              0, self->size.height,
+                              self->viewport.offset.x, self->viewport.extent.width,
+                              self->viewport.offset.y, self->viewport.extent.height,
                               ORTHO_NEAR_PLANE,
                               ORTHO_FAR_PLANE);
+
   graphene_matrix_multiply (&modelview, &projection, &self->mvp);
 }
 
@@ -450,10 +462,10 @@ gsk_vulkan_render_draw (GskVulkanRender   *self,
                     0,
                     1,
                     &(VkViewport) {
-                      .x = 0,
-                      .y = 0,
-                      .width = self->size.width,
-                      .height = self->size.height,
+                      .x = self->viewport.offset.x,
+                      .y = self->viewport.offset.x,
+                      .width = self->viewport.extent.width,
+                      .height = self->viewport.extent.height,
                       .minDepth = 0,
                       .maxDepth = 1
                     });
@@ -470,7 +482,10 @@ gsk_vulkan_render_draw (GskVulkanRender   *self,
                             .framebuffer = gsk_vulkan_render_get_framebuffer (self, self->target),
                             .renderArea = { 
                                 { 0, 0 },
-                                { self->size.width, self->size.height }
+                                {
+                                    gsk_vulkan_image_get_width (self->target),
+                                    gsk_vulkan_image_get_height (self->target)
+                                }
                             },
                             .clearValueCount = 1,
                             .pClearValues = (VkClearValue [1]) {
@@ -500,6 +515,14 @@ gsk_vulkan_render_draw (GskVulkanRender   *self,
     }
 }
 
+GskTexture *
+gsk_vulkan_render_download_target (GskVulkanRender *self)
+{
+  gsk_vulkan_uploader_reset (self->uploader);
+
+  return gsk_vulkan_image_download (self->target, self->uploader);
+}
+
 static void
 gsk_vulkan_render_cleanup (GskVulkanRender *self)
 {
@@ -589,14 +612,15 @@ gsk_vulkan_render_is_busy (GskVulkanRender *self)
 }
 
 void
-gsk_vulkan_render_reset (GskVulkanRender *self,
-                         GskVulkanImage  *target)
+gsk_vulkan_render_reset (GskVulkanRender       *self,
+                         GskVulkanImage        *target,
+                         const graphene_rect_t *rect)
 {
   gsk_vulkan_render_cleanup (self);
 
   self->target = g_object_ref (target);
 
-  gsk_vulkan_render_compute_mvp (self);
+  gsk_vulkan_render_compute_mvp (self, rect);
 }
 
 GskRenderer *
diff --git a/gsk/gskvulkanrenderer.c b/gsk/gskvulkanrenderer.c
index bb3d79b..747ed09 100644
--- a/gsk/gskvulkanrenderer.c
+++ b/gsk/gskvulkanrenderer.c
@@ -170,6 +170,54 @@ gsk_vulkan_renderer_unrealize (GskRenderer *renderer)
   g_clear_object (&self->vulkan);
 }
 
+static GskTexture *
+gsk_vulkan_renderer_render_texture (GskRenderer           *renderer,
+                                    GskRenderNode         *root,
+                                    const graphene_rect_t *viewport)
+{
+  GskVulkanRenderer *self = GSK_VULKAN_RENDERER (renderer);
+  GskVulkanRender *render;
+  GskVulkanImage *image;
+  GskTexture *texture;
+#ifdef G_ENABLE_DEBUG
+  GskProfiler *profiler;
+  gint64 cpu_time;
+#endif
+
+#ifdef G_ENABLE_DEBUG
+  profiler = gsk_renderer_get_profiler (renderer);
+  gsk_profiler_timer_begin (profiler, self->profile_timers.cpu_time);
+#endif
+
+  render = gsk_vulkan_render_new (renderer, self->vulkan);
+
+  image = gsk_vulkan_image_new_for_framebuffer (self->vulkan,
+                                                ceil (viewport->size.width),
+                                                ceil (viewport->size.height));
+
+  gsk_vulkan_render_reset (render, image, viewport);
+
+  gsk_vulkan_render_add_node (render, root);
+
+  gsk_vulkan_render_upload (render);
+
+  gsk_vulkan_render_draw (render, self->sampler);
+
+  texture = gsk_vulkan_render_download_target (render);
+
+  g_object_unref (image);
+  gsk_vulkan_render_free (render);
+
+#ifdef G_ENABLE_DEBUG
+  cpu_time = gsk_profiler_timer_end (profiler, self->profile_timers.cpu_time);
+  gsk_profiler_timer_set (profiler, self->profile_timers.cpu_time, cpu_time);
+
+  gsk_profiler_push_samples (profiler);
+#endif
+
+  return texture;
+}
+
 static void
 gsk_vulkan_renderer_render (GskRenderer   *renderer,
                             GskRenderNode *root)
@@ -188,7 +236,7 @@ gsk_vulkan_renderer_render (GskRenderer   *renderer,
 
   render = self->render;
 
-  gsk_vulkan_render_reset (render, self->targets[gdk_vulkan_context_get_draw_index (self->vulkan)]);
+  gsk_vulkan_render_reset (render, self->targets[gdk_vulkan_context_get_draw_index (self->vulkan)], NULL);
 
   gsk_vulkan_render_add_node (render, root);
 
@@ -238,6 +286,7 @@ gsk_vulkan_renderer_class_init (GskVulkanRendererClass *klass)
   renderer_class->realize = gsk_vulkan_renderer_realize;
   renderer_class->unrealize = gsk_vulkan_renderer_unrealize;
   renderer_class->render = gsk_vulkan_renderer_render;
+  renderer_class->render_texture = gsk_vulkan_renderer_render_texture;
   renderer_class->begin_draw_frame = gsk_vulkan_renderer_begin_draw_frame;
 }
 
diff --git a/gsk/gskvulkanrenderprivate.h b/gsk/gskvulkanrenderprivate.h
index 5696dd3..e44f263 100644
--- a/gsk/gskvulkanrenderprivate.h
+++ b/gsk/gskvulkanrenderprivate.h
@@ -24,7 +24,8 @@ void                    gsk_vulkan_render_free                          (GskVulk
 
 gboolean                gsk_vulkan_render_is_busy                       (GskVulkanRender        *self);
 void                    gsk_vulkan_render_reset                         (GskVulkanRender        *self,
-                                                                         GskVulkanImage         *target);
+                                                                         GskVulkanImage         *target,
+                                                                         const graphene_rect_t  *rect);
 
 GskRenderer *           gsk_vulkan_render_get_renderer                  (GskVulkanRender        *self);
 
@@ -47,6 +48,8 @@ void                    gsk_vulkan_render_draw                          (GskVulk
 
 void                    gsk_vulkan_render_submit                        (GskVulkanRender        *self);
 
+GskTexture *            gsk_vulkan_render_download_target               (GskVulkanRender        *self);
+
 G_END_DECLS
 
 #endif /* __GSK_VULKAN_RENDER_PRIVATE_H__ */


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