render/vulkan: destroy textures after command buffer completes

We need to wait for any pending command buffer to complete before
we're able to fully destroy a struct wlr_vk_texture: the Vulkan
spec requires the VkDescriptorSet to be kept alive.

So far we've done this in vulkan_end(), after blocking until the
command buffer completes. We'll soon stop blocking, so move this
logic in get_command_buffer(), where we check which commands buffers
have completed in a non-blocking fashion.
This commit is contained in:
Simon Ser 2022-11-07 15:11:10 +01:00
parent 0730552e85
commit 2a414c896e
3 changed files with 39 additions and 20 deletions

View file

@ -425,6 +425,7 @@ static bool init_command_buffer(struct wlr_vk_command_buffer *cb,
*cb = (struct wlr_vk_command_buffer){
.vk = vk_cb,
};
wl_list_init(&cb->destroy_textures);
return true;
}
@ -449,6 +450,15 @@ static bool wait_command_buffer(struct wlr_vk_command_buffer *cb,
return true;
}
static void release_command_buffer_resources(struct wlr_vk_command_buffer *cb) {
struct wlr_vk_texture *texture, *texture_tmp;
wl_list_for_each_safe(texture, texture_tmp, &cb->destroy_textures, destroy_link) {
wl_list_remove(&texture->destroy_link);
texture->last_used_cb = NULL;
wlr_texture_destroy(&texture->wlr_texture);
}
}
static struct wlr_vk_command_buffer *get_command_buffer(
struct wlr_vk_renderer *renderer) {
VkResult res;
@ -461,6 +471,15 @@ static struct wlr_vk_command_buffer *get_command_buffer(
return NULL;
}
// Destroy textures for completed command buffers
for (size_t i = 0; i < VULKAN_COMMAND_BUFFERS_CAP; i++) {
struct wlr_vk_command_buffer *cb = &renderer->command_buffers[i];
if (cb->vk != VK_NULL_HANDLE && !cb->recording &&
cb->timeline_point <= current_point) {
release_command_buffer_resources(cb);
}
}
// First try to find an existing command buffer which isn't busy
struct wlr_vk_command_buffer *unused = NULL;
struct wlr_vk_command_buffer *wait = NULL;
@ -943,15 +962,7 @@ static void vulkan_end(struct wlr_renderer *wlr_renderer) {
return;
}
++renderer->frame;
release_stage_allocations(renderer);
// destroy pending textures
wl_list_for_each_safe(texture, tmp_tex, &renderer->destroy_textures, destroy_link) {
wlr_texture_destroy(&texture->wlr_texture);
}
wl_list_init(&renderer->destroy_textures); // reset the list
}
static bool vulkan_render_subtexture_with_matrix(struct wlr_renderer *wlr_renderer,
@ -1007,7 +1018,7 @@ static bool vulkan_render_subtexture_with_matrix(struct wlr_renderer *wlr_render
VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(vert_pcr_data), sizeof(float),
&alpha);
vkCmdDraw(cb, 4, 1, 0, 0);
texture->last_used = renderer->frame;
texture->last_used_cb = renderer->current_command_buffer;
return true;
}
@ -1146,6 +1157,14 @@ static void vulkan_destroy(struct wlr_renderer *wlr_renderer) {
wlr_vk_error("vkDeviceWaitIdle", res);
}
for (size_t i = 0; i < VULKAN_COMMAND_BUFFERS_CAP; i++) {
struct wlr_vk_command_buffer *cb = &renderer->command_buffers[i];
if (cb->vk == VK_NULL_HANDLE) {
continue;
}
release_command_buffer_resources(cb);
}
// stage.cb automatically freed with command pool
struct wlr_vk_shared_buffer *buf, *tmp_buf;
wl_list_for_each_safe(buf, tmp_buf, &renderer->stage.buffers, link) {
@ -1931,7 +1950,6 @@ struct wlr_renderer *vulkan_renderer_create_for_device(struct wlr_vk_device *dev
renderer->dev = dev;
wlr_renderer_init(&renderer->wlr_renderer, &renderer_impl);
wl_list_init(&renderer->stage.buffers);
wl_list_init(&renderer->destroy_textures);
wl_list_init(&renderer->foreign_textures);
wl_list_init(&renderer->textures);
wl_list_init(&renderer->descriptor_pools);