From 3ee0f52e09d422b497434f724b9c2e1606c02bea Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Fri, 16 Jun 2023 20:10:01 -0400 Subject: [PATCH] render/vulkan: Dynamically create texture views Now that we are dynamically creating pipeline layouts, we need separate texture views for each pipeline layout we choose to use with a texture. --- include/render/vulkan.h | 17 +++++++++-- render/vulkan/pass.c | 9 +++++- render/vulkan/renderer.c | 8 +++++- render/vulkan/texture.c | 61 ++++++++++++++++++++++------------------ 4 files changed, 62 insertions(+), 33 deletions(-) diff --git a/include/render/vulkan.h b/include/render/vulkan.h index f25d7cd5..f901f5f1 100644 --- a/include/render/vulkan.h +++ b/include/render/vulkan.h @@ -295,12 +295,24 @@ struct wlr_vk_vert_pcr_data { float uv_size[2]; }; +struct wlr_vk_texture_view { + struct wl_list link; // struct wlr_vk_texture.views + const struct wlr_vk_pipeline_layout *layout; + + VkDescriptorSet ds; + VkImageView image_view; + struct wlr_vk_descriptor_pool *ds_pool; +}; + struct wlr_vk_pipeline *setup_get_or_create_pipeline( struct wlr_vk_render_format_setup *setup, const struct wlr_vk_pipeline_key *key); struct wlr_vk_pipeline_layout *get_or_create_pipeline_layout( struct wlr_vk_renderer *renderer, const struct wlr_vk_pipeline_layout_key *key); +struct wlr_vk_texture_view *vulkan_texture_get_or_create_view( + struct wlr_vk_texture *texture, + const struct wlr_vk_pipeline_layout *layout); // Creates a vulkan renderer for the given device. struct wlr_renderer *vulkan_renderer_create_for_device(struct wlr_vk_device *dev); @@ -373,11 +385,8 @@ struct wlr_vk_texture { uint32_t mem_count; VkDeviceMemory memories[WLR_DMABUF_MAX_PLANES]; VkImage image; - VkImageView image_view; const struct wlr_vk_format *format; enum wlr_vk_texture_transform transform; - VkDescriptorSet ds; - struct wlr_vk_descriptor_pool *ds_pool; struct wlr_vk_command_buffer *last_used_cb; // to track when it can be destroyed bool dmabuf_imported; bool owned; // if dmabuf_imported: whether we have ownership of the image @@ -392,6 +401,8 @@ struct wlr_vk_texture { struct wlr_addon buffer_addon; // For DMA-BUF implicit sync interop VkSemaphore foreign_semaphores[WLR_DMABUF_MAX_PLANES]; + + struct wl_list views; // struct wlr_vk_texture_ds.link }; struct wlr_vk_texture *vulkan_get_texture(struct wlr_texture *wlr_texture); diff --git a/render/vulkan/pass.c b/render/vulkan/pass.c index 419f92e0..acc2a5ae 100644 --- a/render/vulkan/pass.c +++ b/render/vulkan/pass.c @@ -555,10 +555,17 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass, return; } + struct wlr_vk_texture_view *view = + vulkan_texture_get_or_create_view(texture, pipe->layout); + if (!view) { + pass->failed = true; + return; + } + bind_pipeline(pass, pipe->vk); vkCmdBindDescriptorSets(cb, VK_PIPELINE_BIND_POINT_GRAPHICS, - pipe->layout->vk, 0, 1, &texture->ds, 0, NULL); + pipe->layout->vk, 0, 1, &view->ds, 0, NULL); vkCmdPushConstants(cb, pipe->layout->vk, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(vert_pcr_data), &vert_pcr_data); diff --git a/render/vulkan/renderer.c b/render/vulkan/renderer.c index 8917f540..205f40ad 100644 --- a/render/vulkan/renderer.c +++ b/render/vulkan/renderer.c @@ -1419,13 +1419,19 @@ static bool vulkan_render_subtexture_with_matrix(struct wlr_renderer *wlr_render return false; } + struct wlr_vk_texture_view *view = + vulkan_texture_get_or_create_view(texture, pipe->layout); + if (!view) { + return false; + } + if (pipe->vk != renderer->bound_pipe) { vkCmdBindPipeline(cb, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe->vk); renderer->bound_pipe = pipe->vk; } vkCmdBindDescriptorSets(cb, VK_PIPELINE_BIND_POINT_GRAPHICS, - pipe->layout->vk, 0, 1, &texture->ds, 0, NULL); + pipe->layout->vk, 0, 1, &view->ds, 0, NULL); float final_matrix[9]; wlr_matrix_multiply(final_matrix, renderer->projection, matrix); diff --git a/render/vulkan/texture.c b/render/vulkan/texture.c index f6252c2b..15e6f601 100644 --- a/render/vulkan/texture.c +++ b/render/vulkan/texture.c @@ -214,8 +214,12 @@ void vulkan_texture_destroy(struct wlr_vk_texture *texture) { wl_list_remove(&texture->link); VkDevice dev = texture->renderer->dev->dev; - if (texture->ds && texture->ds_pool) { - vulkan_free_ds(texture->renderer, texture->ds_pool, texture->ds); + + struct wlr_vk_texture_view *view, *tmp_view; + wl_list_for_each_safe(view, tmp_view, &texture->views, link) { + vulkan_free_ds(texture->renderer, view->ds_pool, view->ds); + vkDestroyImageView(dev, view->image_view, NULL); + free(view); } for (size_t i = 0; i < WLR_DMABUF_MAX_PLANES; i++) { @@ -224,7 +228,6 @@ void vulkan_texture_destroy(struct wlr_vk_texture *texture) { } } - vkDestroyImageView(dev, texture->image_view, NULL); vkDestroyImage(dev, texture->image, NULL); for (unsigned i = 0u; i < texture->mem_count; ++i) { @@ -262,22 +265,29 @@ static struct wlr_vk_texture *vulkan_texture_create( &texture_impl, width, height); texture->renderer = renderer; wl_list_insert(&renderer->textures, &texture->link); + wl_list_init(&texture->views); return texture; } -static bool vulkan_texture_init_view(struct wlr_vk_texture *texture) { - VkResult res; - VkDevice dev = texture->renderer->dev->dev; +struct wlr_vk_texture_view *vulkan_texture_get_or_create_view(struct wlr_vk_texture *texture, + const struct wlr_vk_pipeline_layout *pipeline_layout) { + struct wlr_vk_texture_view *view; + wl_list_for_each(view, &texture->views, link) { + if (view->layout == pipeline_layout) { + return view; + } + } - struct wlr_vk_pipeline_layout *pipeline_layout = get_or_create_pipeline_layout( - texture->renderer, &(struct wlr_vk_pipeline_layout_key) { - .ycbcr_format = texture->format->is_ycbcr ? texture->format : NULL, - }); - if (!pipeline_layout) { - wlr_log(WLR_ERROR, "Failed to create a pipeline layout for a texture"); + view = calloc(1, sizeof(*view)); + if (!view) { return NULL; } + view->layout = pipeline_layout; + + VkResult res; + VkDevice dev = texture->renderer->dev->dev; + const struct wlr_pixel_format_info *format_info = drm_get_pixel_format_info(texture->format->drm); if (format_info != NULL) { @@ -317,20 +327,22 @@ static bool vulkan_texture_init_view(struct wlr_vk_texture *texture) { view_info.pNext = &ycbcr_conversion_info; } - res = vkCreateImageView(dev, &view_info, NULL, &texture->image_view); + res = vkCreateImageView(dev, &view_info, NULL, &view->image_view); if (res != VK_SUCCESS) { + free(view); wlr_vk_error("vkCreateImageView failed", res); - return false; + return NULL; } - texture->ds_pool = vulkan_alloc_texture_ds(texture->renderer, pipeline_layout->ds, &texture->ds); - if (!texture->ds_pool) { + view->ds_pool = vulkan_alloc_texture_ds(texture->renderer, pipeline_layout->ds, &view->ds); + if (!view->ds_pool) { + free(view); wlr_log(WLR_ERROR, "failed to allocate descriptor"); - return false; + return NULL; } VkDescriptorImageInfo ds_img_info = { - .imageView = texture->image_view, + .imageView = view->image_view, .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, }; @@ -338,13 +350,14 @@ static bool vulkan_texture_init_view(struct wlr_vk_texture *texture) { .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, .descriptorCount = 1, .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - .dstSet = texture->ds, + .dstSet = view->ds, .pImageInfo = &ds_img_info, }; vkUpdateDescriptorSets(dev, 1, &ds_write, 0, NULL); - return true; + wl_list_insert(&texture->views, &view->link); + return view; } static struct wlr_texture *vulkan_texture_from_pixels( @@ -419,10 +432,6 @@ static struct wlr_texture *vulkan_texture_from_pixels( goto error; } - if (!vulkan_texture_init_view(texture)) { - goto error; - } - pixman_region32_t region; pixman_region32_init_rect(®ion, 0, 0, width, height); if (!write_pixels(texture, stride, ®ion, data, VK_IMAGE_LAYOUT_UNDEFINED, @@ -706,10 +715,6 @@ static struct wlr_vk_texture *vulkan_texture_from_dmabuf( goto error; } - if (!vulkan_texture_init_view(texture)) { - goto error; - } - texture->dmabuf_imported = true; return texture;