[gtk+/wip/matthiasc/renderpasses: 4/6] Implement multiple render passes
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/wip/matthiasc/renderpasses: 4/6] Implement multiple render passes
- Date: Thu, 28 Sep 2017 03:24:35 +0000 (UTC)
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]