render/vulkan: add caching to vulkan_read_pixels

David96 2 years ago committed by Simon Ser
parent 05454618cd
commit 7a42392da2

@ -189,6 +189,14 @@ struct wlr_vk_renderer {
bool recording;
struct wl_list buffers; // type wlr_vk_shared_buffer
} stage;
struct {
bool initialized;
uint32_t drm_format;
uint32_t width, height;
VkImage dst_image;
VkDeviceMemory dst_img_memory;
} read_pixels_cache;
};
// Creates a vulkan renderer for the given device.

@ -968,6 +968,11 @@ static void vulkan_destroy(struct wlr_renderer *wlr_renderer) {
vkDestroySampler(dev->dev, renderer->sampler, NULL);
vkDestroyCommandPool(dev->dev, renderer->command_pool, NULL);
if (renderer->read_pixels_cache.initialized) {
vkFreeMemory(dev->dev, renderer->read_pixels_cache.dst_img_memory, NULL);
vkDestroyImage(dev->dev, renderer->read_pixels_cache.dst_image, NULL);
}
struct wlr_vk_instance *ini = dev->instance;
vulkan_device_destroy(dev);
vulkan_instance_destroy(ini);
@ -978,7 +983,6 @@ static bool vulkan_read_pixels(struct wlr_renderer *wlr_renderer,
uint32_t drm_format, uint32_t stride,
uint32_t width, uint32_t height, uint32_t src_x, uint32_t src_y,
uint32_t dst_x, uint32_t dst_y, void *data) {
bool success = false;
struct wlr_vk_renderer *vk_renderer = vulkan_get_renderer(wlr_renderer);
VkDevice dev = vk_renderer->dev->dev;
VkImage src_image = vk_renderer->current_render_buffer->image;
@ -1010,6 +1014,18 @@ static bool vulkan_read_pixels(struct wlr_renderer *wlr_renderer,
return false;
}
VkResult res;
VkImage dst_image;
VkDeviceMemory dst_img_memory;
bool use_cached = vk_renderer->read_pixels_cache.initialized &&
vk_renderer->read_pixels_cache.drm_format == drm_format &&
vk_renderer->read_pixels_cache.width == width &&
vk_renderer->read_pixels_cache.height == height;
if (use_cached) {
dst_image = vk_renderer->read_pixels_cache.dst_image;
dst_img_memory = vk_renderer->read_pixels_cache.dst_img_memory;
} else {
VkImageCreateInfo image_create_info = {
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.imageType = VK_IMAGE_TYPE_2D,
@ -1024,8 +1040,7 @@ static bool vulkan_read_pixels(struct wlr_renderer *wlr_renderer,
.tiling = VK_IMAGE_TILING_LINEAR,
.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT
};
VkImage dst_image;
VkResult res = vkCreateImage(dev, &image_create_info, NULL, &dst_image);
res = vkCreateImage(dev, &image_create_info, NULL, &dst_image);
if (res != VK_SUCCESS) {
wlr_vk_error("vkCreateImage", res);
return false;
@ -1050,7 +1065,6 @@ static bool vulkan_read_pixels(struct wlr_renderer *wlr_renderer,
mem_alloc_info.allocationSize = mem_reqs.size;
mem_alloc_info.memoryTypeIndex = mem_type;
VkDeviceMemory dst_img_memory;
res = vkAllocateMemory(dev, &mem_alloc_info, NULL, &dst_img_memory);
if (res != VK_SUCCESS) {
wlr_vk_error("vkAllocateMemory", res);
@ -1062,6 +1076,18 @@ static bool vulkan_read_pixels(struct wlr_renderer *wlr_renderer,
goto free_memory;
}
if (vk_renderer->read_pixels_cache.initialized) {
vkFreeMemory(dev, vk_renderer->read_pixels_cache.dst_img_memory, NULL);
vkDestroyImage(dev, vk_renderer->read_pixels_cache.dst_image, NULL);
}
vk_renderer->read_pixels_cache.initialized = true;
vk_renderer->read_pixels_cache.drm_format = drm_format;
vk_renderer->read_pixels_cache.dst_image = dst_image;
vk_renderer->read_pixels_cache.dst_img_memory = dst_img_memory;
vk_renderer->read_pixels_cache.width = width;
vk_renderer->read_pixels_cache.height = height;
}
VkCommandBuffer cb = vulkan_record_stage_cb(vk_renderer);
vulkan_change_layout(cb, dst_image,
@ -1137,7 +1163,7 @@ static bool vulkan_read_pixels(struct wlr_renderer *wlr_renderer,
VK_ACCESS_MEMORY_READ_BIT);
if (!vulkan_submit_stage_wait(vk_renderer)) {
goto free_memory;
return false;
}
VkImageSubresource img_sub_res = {
@ -1152,7 +1178,7 @@ static bool vulkan_read_pixels(struct wlr_renderer *wlr_renderer,
res = vkMapMemory(dev, dst_img_memory, 0, VK_WHOLE_SIZE, 0, &v);
if (res != VK_SUCCESS) {
wlr_vk_error("vkMapMemory", res);
goto free_memory;
return false;
}
const char *d = (const char *)v + img_sub_layout.offset;
@ -1167,14 +1193,15 @@ static bool vulkan_read_pixels(struct wlr_renderer *wlr_renderer,
}
}
success = true;
vkUnmapMemory(dev, dst_img_memory);
// Don't need to free anything else, since memory and image are cached
return true;
free_memory:
vkFreeMemory(dev, dst_img_memory, NULL);
destroy_image:
vkDestroyImage(dev, dst_image, NULL);
return success;
return false;
}
static int vulkan_get_drm_fd(struct wlr_renderer *wlr_renderer) {

Loading…
Cancel
Save