From 786d3a013e0ec7f19999f05f32df1110585d6443 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Thu, 22 Dec 2016 19:01:07 +0100 Subject: [PATCH] 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 | 66 +++++++++++++++++++--------- gsk/gskvulkanrenderer.c | 51 +++++++++++++++++++++- gsk/gskvulkanrenderprivate.h | 5 ++- 8 files changed, 203 insertions(+), 23 deletions(-) diff --git a/gsk/gskvulkanbuffer.c b/gsk/gskvulkanbuffer.c index 3c1d76d37c..ec5905ba48 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 30e327e10e..700e400528 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 218a8c92fc..09dd333ad5 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 b4037680b6..9ef2c51bf5 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 45d8ca2e7e..feade292e8 100644 --- a/gsk/gskvulkanimageprivate.h +++ b/gsk/gskvulkanimageprivate.h @@ -3,6 +3,7 @@ #include +#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 05ca19c607..eabdd6f6ce 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); + 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->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; + 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 bb3d79b48e..747ed09c90 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 5696dd3001..e44f2639f2 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__ */