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.
This commit is contained in:
Alexander Orzechowski 2023-06-16 20:10:01 -04:00
parent 7c5a3afd60
commit 3ee0f52e09
4 changed files with 62 additions and 33 deletions

View file

@ -295,12 +295,24 @@ struct wlr_vk_vert_pcr_data {
float uv_size[2]; 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_pipeline *setup_get_or_create_pipeline(
struct wlr_vk_render_format_setup *setup, struct wlr_vk_render_format_setup *setup,
const struct wlr_vk_pipeline_key *key); const struct wlr_vk_pipeline_key *key);
struct wlr_vk_pipeline_layout *get_or_create_pipeline_layout( struct wlr_vk_pipeline_layout *get_or_create_pipeline_layout(
struct wlr_vk_renderer *renderer, struct wlr_vk_renderer *renderer,
const struct wlr_vk_pipeline_layout_key *key); 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. // Creates a vulkan renderer for the given device.
struct wlr_renderer *vulkan_renderer_create_for_device(struct wlr_vk_device *dev); 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; uint32_t mem_count;
VkDeviceMemory memories[WLR_DMABUF_MAX_PLANES]; VkDeviceMemory memories[WLR_DMABUF_MAX_PLANES];
VkImage image; VkImage image;
VkImageView image_view;
const struct wlr_vk_format *format; const struct wlr_vk_format *format;
enum wlr_vk_texture_transform transform; 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 struct wlr_vk_command_buffer *last_used_cb; // to track when it can be destroyed
bool dmabuf_imported; bool dmabuf_imported;
bool owned; // if dmabuf_imported: whether we have ownership of the image 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; struct wlr_addon buffer_addon;
// For DMA-BUF implicit sync interop // For DMA-BUF implicit sync interop
VkSemaphore foreign_semaphores[WLR_DMABUF_MAX_PLANES]; 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); struct wlr_vk_texture *vulkan_get_texture(struct wlr_texture *wlr_texture);

View file

@ -555,10 +555,17 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass,
return; 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); bind_pipeline(pass, pipe->vk);
vkCmdBindDescriptorSets(cb, VK_PIPELINE_BIND_POINT_GRAPHICS, 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, vkCmdPushConstants(cb, pipe->layout->vk,
VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(vert_pcr_data), &vert_pcr_data); VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(vert_pcr_data), &vert_pcr_data);

View file

@ -1419,13 +1419,19 @@ static bool vulkan_render_subtexture_with_matrix(struct wlr_renderer *wlr_render
return false; 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) { if (pipe->vk != renderer->bound_pipe) {
vkCmdBindPipeline(cb, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe->vk); vkCmdBindPipeline(cb, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe->vk);
renderer->bound_pipe = pipe->vk; renderer->bound_pipe = pipe->vk;
} }
vkCmdBindDescriptorSets(cb, VK_PIPELINE_BIND_POINT_GRAPHICS, 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]; float final_matrix[9];
wlr_matrix_multiply(final_matrix, renderer->projection, matrix); wlr_matrix_multiply(final_matrix, renderer->projection, matrix);

View file

@ -214,8 +214,12 @@ void vulkan_texture_destroy(struct wlr_vk_texture *texture) {
wl_list_remove(&texture->link); wl_list_remove(&texture->link);
VkDevice dev = texture->renderer->dev->dev; 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++) { 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); vkDestroyImage(dev, texture->image, NULL);
for (unsigned i = 0u; i < texture->mem_count; ++i) { 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_impl, width, height);
texture->renderer = renderer; texture->renderer = renderer;
wl_list_insert(&renderer->textures, &texture->link); wl_list_insert(&renderer->textures, &texture->link);
wl_list_init(&texture->views);
return texture; return texture;
} }
static bool vulkan_texture_init_view(struct wlr_vk_texture *texture) { struct wlr_vk_texture_view *vulkan_texture_get_or_create_view(struct wlr_vk_texture *texture,
VkResult res; const struct wlr_vk_pipeline_layout *pipeline_layout) {
VkDevice dev = texture->renderer->dev->dev; 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( view = calloc(1, sizeof(*view));
texture->renderer, &(struct wlr_vk_pipeline_layout_key) { if (!view) {
.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");
return NULL; return NULL;
} }
view->layout = pipeline_layout;
VkResult res;
VkDevice dev = texture->renderer->dev->dev;
const struct wlr_pixel_format_info *format_info = const struct wlr_pixel_format_info *format_info =
drm_get_pixel_format_info(texture->format->drm); drm_get_pixel_format_info(texture->format->drm);
if (format_info != NULL) { 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; 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) { if (res != VK_SUCCESS) {
free(view);
wlr_vk_error("vkCreateImageView failed", res); wlr_vk_error("vkCreateImageView failed", res);
return false; return NULL;
} }
texture->ds_pool = vulkan_alloc_texture_ds(texture->renderer, pipeline_layout->ds, &texture->ds); view->ds_pool = vulkan_alloc_texture_ds(texture->renderer, pipeline_layout->ds, &view->ds);
if (!texture->ds_pool) { if (!view->ds_pool) {
free(view);
wlr_log(WLR_ERROR, "failed to allocate descriptor"); wlr_log(WLR_ERROR, "failed to allocate descriptor");
return false; return NULL;
} }
VkDescriptorImageInfo ds_img_info = { VkDescriptorImageInfo ds_img_info = {
.imageView = texture->image_view, .imageView = view->image_view,
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, .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, .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.descriptorCount = 1, .descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.dstSet = texture->ds, .dstSet = view->ds,
.pImageInfo = &ds_img_info, .pImageInfo = &ds_img_info,
}; };
vkUpdateDescriptorSets(dev, 1, &ds_write, 0, NULL); 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( static struct wlr_texture *vulkan_texture_from_pixels(
@ -419,10 +432,6 @@ static struct wlr_texture *vulkan_texture_from_pixels(
goto error; goto error;
} }
if (!vulkan_texture_init_view(texture)) {
goto error;
}
pixman_region32_t region; pixman_region32_t region;
pixman_region32_init_rect(&region, 0, 0, width, height); pixman_region32_init_rect(&region, 0, 0, width, height);
if (!write_pixels(texture, stride, &region, data, VK_IMAGE_LAYOUT_UNDEFINED, if (!write_pixels(texture, stride, &region, data, VK_IMAGE_LAYOUT_UNDEFINED,
@ -706,10 +715,6 @@ static struct wlr_vk_texture *vulkan_texture_from_dmabuf(
goto error; goto error;
} }
if (!vulkan_texture_init_view(texture)) {
goto error;
}
texture->dmabuf_imported = true; texture->dmabuf_imported = true;
return texture; return texture;