vulkan: Add support for render timer using timestamp queries

This commit is contained in:
Kenny Levinsen 2026-04-06 15:30:40 +00:00
parent 8a9e3a84b5
commit 35c35530a3
4 changed files with 105 additions and 0 deletions

View file

@ -1556,6 +1556,80 @@ static struct wlr_render_pass *vulkan_begin_buffer_pass(struct wlr_renderer *wlr
return &render_pass->base;
}
static const struct wlr_render_timer_impl render_timer_impl;
static struct wlr_render_timer *vulkan_render_timer_create(
struct wlr_renderer *wlr_renderer) {
struct wlr_vk_renderer *renderer = vulkan_get_renderer(wlr_renderer);
if (renderer->dev->timestamp_valid_bits == 0) {
wlr_log(WLR_ERROR, "Failed to create render timer: "
"timestamp queries not supported by queue family");
return NULL;
}
struct wlr_vk_render_timer *timer = calloc(1, sizeof(*timer));
if (!timer) {
wlr_log_errno(WLR_ERROR, "Allocation failed");
return NULL;
}
VkQueryPoolCreateInfo pool_info = {
.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO,
.queryType = VK_QUERY_TYPE_TIMESTAMP,
.queryCount = 2,
};
VkResult res = vkCreateQueryPool(renderer->dev->dev, &pool_info,
NULL, &timer->query_pool);
if (res != VK_SUCCESS) {
wlr_vk_error("vkCreateQueryPool", res);
free(timer);
return NULL;
}
timer->base.impl = &render_timer_impl;
timer->renderer = renderer;
return &timer->base;
}
static int vulkan_render_timer_get_duration_ns(
struct wlr_render_timer *wlr_timer) {
struct wlr_vk_render_timer *timer =
wl_container_of(wlr_timer, timer, base);
struct wlr_vk_renderer *renderer = timer->renderer;
// Layout: [ timestamp1, avail1, timestamp2, avail2 ]
uint64_t data[4] = {0};
VkResult res = vkGetQueryPoolResults(renderer->dev->dev,
timer->query_pool, 0, 2, sizeof(data), data,
2 * sizeof(uint64_t),
VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WITH_AVAILABILITY_BIT);
if (res == VK_NOT_READY || data[1] == 0 || data[3] == 0) {
wlr_log(WLR_ERROR, "Failed to get render duration: "
"timestamp query results not yet ready");
return -1;
}
if (res != VK_SUCCESS) {
wlr_vk_error("vkGetQueryPoolResults", res);
return -1;
}
uint64_t ticks = data[2] - data[0];
return (int)(ticks * renderer->dev->timestamp_period);
}
static void vulkan_render_timer_destroy(
struct wlr_render_timer *wlr_timer) {
struct wlr_vk_render_timer *timer =
wl_container_of(wlr_timer, timer, base);
vkDestroyQueryPool(timer->renderer->dev->dev, timer->query_pool, NULL);
free(timer);
}
static const struct wlr_render_timer_impl render_timer_impl = {
.get_duration_ns = vulkan_render_timer_get_duration_ns,
.destroy = vulkan_render_timer_destroy,
};
static const struct wlr_renderer_impl renderer_impl = {
.get_texture_formats = vulkan_get_texture_formats,
.get_render_formats = vulkan_get_render_formats,
@ -1563,6 +1637,7 @@ static const struct wlr_renderer_impl renderer_impl = {
.get_drm_fd = vulkan_get_drm_fd,
.texture_from_buffer = vulkan_texture_from_buffer,
.begin_buffer_pass = vulkan_begin_buffer_pass,
.render_timer_create = vulkan_render_timer_create,
};
// Initializes the VkDescriptorSetLayout and VkPipelineLayout needed