mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-03-30 11:11:21 -04:00
render: explicit sync for wlr_texture_read_pixels()
This commit is contained in:
parent
413664e0b0
commit
f295d0322a
6 changed files with 110 additions and 55 deletions
|
|
@ -410,7 +410,7 @@ VkCommandBuffer vulkan_record_stage_cb(struct wlr_vk_renderer *renderer);
|
||||||
|
|
||||||
// Submits the current stage command buffer and waits until it has
|
// Submits the current stage command buffer and waits until it has
|
||||||
// finished execution.
|
// finished execution.
|
||||||
bool vulkan_submit_stage_wait(struct wlr_vk_renderer *renderer);
|
bool vulkan_submit_stage_wait(struct wlr_vk_renderer *renderer, int wait_sync_file_fd);
|
||||||
|
|
||||||
struct wlr_vk_render_pass_texture {
|
struct wlr_vk_render_pass_texture {
|
||||||
struct wlr_vk_texture *texture;
|
struct wlr_vk_texture *texture;
|
||||||
|
|
@ -476,6 +476,8 @@ uint64_t vulkan_end_command_buffer(struct wlr_vk_command_buffer *cb,
|
||||||
void vulkan_reset_command_buffer(struct wlr_vk_command_buffer *cb);
|
void vulkan_reset_command_buffer(struct wlr_vk_command_buffer *cb);
|
||||||
bool vulkan_wait_command_buffer(struct wlr_vk_command_buffer *cb,
|
bool vulkan_wait_command_buffer(struct wlr_vk_command_buffer *cb,
|
||||||
struct wlr_vk_renderer *renderer);
|
struct wlr_vk_renderer *renderer);
|
||||||
|
VkSemaphore vulkan_command_buffer_wait_sync_file(struct wlr_vk_renderer *renderer,
|
||||||
|
struct wlr_vk_command_buffer *render_cb, size_t sem_index, int sync_file_fd);
|
||||||
|
|
||||||
bool vulkan_sync_render_pass_release(struct wlr_vk_renderer *renderer,
|
bool vulkan_sync_render_pass_release(struct wlr_vk_renderer *renderer,
|
||||||
struct wlr_vk_render_pass *pass);
|
struct wlr_vk_render_pass *pass);
|
||||||
|
|
@ -488,7 +490,8 @@ bool vulkan_read_pixels(struct wlr_vk_renderer *vk_renderer,
|
||||||
VkFormat src_format, VkImage src_image,
|
VkFormat src_format, VkImage src_image,
|
||||||
uint32_t drm_format, uint32_t stride,
|
uint32_t drm_format, uint32_t stride,
|
||||||
uint32_t width, uint32_t height, uint32_t src_x, uint32_t src_y,
|
uint32_t width, uint32_t height, uint32_t src_x, uint32_t src_y,
|
||||||
uint32_t dst_x, uint32_t dst_y, void *data);
|
uint32_t dst_x, uint32_t dst_y, void *data,
|
||||||
|
struct wlr_drm_syncobj_timeline *wait_timeline, uint64_t wait_point);
|
||||||
|
|
||||||
// State (e.g. image texture) associated with a surface.
|
// State (e.g. image texture) associated with a surface.
|
||||||
struct wlr_vk_texture {
|
struct wlr_vk_texture {
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,8 @@ struct wlr_texture_read_pixels_options {
|
||||||
uint32_t dst_x, dst_y;
|
uint32_t dst_x, dst_y;
|
||||||
/** Source box of the texture to read from. If empty, the full texture is assumed. */
|
/** Source box of the texture to read from. If empty, the full texture is assumed. */
|
||||||
const struct wlr_box src_box;
|
const struct wlr_box src_box;
|
||||||
|
struct wlr_drm_syncobj_timeline *wait_timeline;
|
||||||
|
uint64_t wait_point;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool wlr_texture_read_pixels(struct wlr_texture *texture,
|
bool wlr_texture_read_pixels(struct wlr_texture *texture,
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,10 @@
|
||||||
#include <GLES2/gl2ext.h>
|
#include <GLES2/gl2ext.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
#include <wayland-server-protocol.h>
|
#include <wayland-server-protocol.h>
|
||||||
#include <wayland-util.h>
|
#include <wayland-util.h>
|
||||||
|
#include <wlr/render/drm_syncobj.h>
|
||||||
#include <wlr/render/egl.h>
|
#include <wlr/render/egl.h>
|
||||||
#include <wlr/render/interface.h>
|
#include <wlr/render/interface.h>
|
||||||
#include <wlr/render/wlr_texture.h>
|
#include <wlr/render/wlr_texture.h>
|
||||||
|
|
@ -201,6 +203,27 @@ static bool gles2_texture_read_pixels(struct wlr_texture *wlr_texture,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options->wait_timeline != NULL) {
|
||||||
|
int sync_file_fd =
|
||||||
|
wlr_drm_syncobj_timeline_export_sync_file(options->wait_timeline, options->wait_point);
|
||||||
|
if (sync_file_fd < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_gles2_renderer *renderer = texture->renderer;
|
||||||
|
EGLSyncKHR sync = wlr_egl_create_sync(renderer->egl, sync_file_fd);
|
||||||
|
close(sync_file_fd);
|
||||||
|
if (sync == EGL_NO_SYNC_KHR) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ok = wlr_egl_wait_sync(renderer->egl, sync);
|
||||||
|
wlr_egl_destroy_sync(renderer->egl, sync);
|
||||||
|
if (!ok) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure any pending drawing is finished before we try to read it
|
// Make sure any pending drawing is finished before we try to read it
|
||||||
glFinish();
|
glFinish();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -99,53 +99,6 @@ static void render_pass_destroy(struct wlr_vk_render_pass *pass) {
|
||||||
free(pass);
|
free(pass);
|
||||||
}
|
}
|
||||||
|
|
||||||
static VkSemaphore render_pass_wait_sync_file(struct wlr_vk_render_pass *pass,
|
|
||||||
size_t sem_index, int sync_file_fd) {
|
|
||||||
struct wlr_vk_renderer *renderer = pass->renderer;
|
|
||||||
struct wlr_vk_command_buffer *render_cb = pass->command_buffer;
|
|
||||||
VkResult res;
|
|
||||||
|
|
||||||
VkSemaphore *wait_semaphores = render_cb->wait_semaphores.data;
|
|
||||||
size_t wait_semaphores_len = render_cb->wait_semaphores.size / sizeof(wait_semaphores[0]);
|
|
||||||
|
|
||||||
VkSemaphore *sem_ptr;
|
|
||||||
if (sem_index >= wait_semaphores_len) {
|
|
||||||
sem_ptr = wl_array_add(&render_cb->wait_semaphores, sizeof(*sem_ptr));
|
|
||||||
if (sem_ptr == NULL) {
|
|
||||||
return VK_NULL_HANDLE;
|
|
||||||
}
|
|
||||||
*sem_ptr = VK_NULL_HANDLE;
|
|
||||||
} else {
|
|
||||||
sem_ptr = &wait_semaphores[sem_index];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*sem_ptr == VK_NULL_HANDLE) {
|
|
||||||
VkSemaphoreCreateInfo semaphore_info = {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
|
|
||||||
};
|
|
||||||
res = vkCreateSemaphore(renderer->dev->dev, &semaphore_info, NULL, sem_ptr);
|
|
||||||
if (res != VK_SUCCESS) {
|
|
||||||
wlr_vk_error("vkCreateSemaphore", res);
|
|
||||||
return VK_NULL_HANDLE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VkImportSemaphoreFdInfoKHR import_info = {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR,
|
|
||||||
.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
|
|
||||||
.flags = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT,
|
|
||||||
.semaphore = *sem_ptr,
|
|
||||||
.fd = sync_file_fd,
|
|
||||||
};
|
|
||||||
res = renderer->dev->api.vkImportSemaphoreFdKHR(renderer->dev->dev, &import_info);
|
|
||||||
if (res != VK_SUCCESS) {
|
|
||||||
wlr_vk_error("vkImportSemaphoreFdKHR", res);
|
|
||||||
return VK_NULL_HANDLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return *sem_ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool render_pass_wait_render_buffer(struct wlr_vk_render_pass *pass,
|
static bool render_pass_wait_render_buffer(struct wlr_vk_render_pass *pass,
|
||||||
VkSemaphoreSubmitInfoKHR *render_wait, uint32_t *render_wait_len_ptr) {
|
VkSemaphoreSubmitInfoKHR *render_wait, uint32_t *render_wait_len_ptr) {
|
||||||
int sync_file_fds[WLR_DMABUF_MAX_PLANES];
|
int sync_file_fds[WLR_DMABUF_MAX_PLANES];
|
||||||
|
|
@ -162,7 +115,8 @@ static bool render_pass_wait_render_buffer(struct wlr_vk_render_pass *pass,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkSemaphore sem = render_pass_wait_sync_file(pass, *render_wait_len_ptr, sync_file_fds[i]);
|
VkSemaphore sem = vulkan_command_buffer_wait_sync_file(pass->renderer,
|
||||||
|
pass->command_buffer, *render_wait_len_ptr, sync_file_fds[i]);
|
||||||
if (sem == VK_NULL_HANDLE) {
|
if (sem == VK_NULL_HANDLE) {
|
||||||
close(sync_file_fds[i]);
|
close(sync_file_fds[i]);
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -431,7 +385,8 @@ static bool render_pass_submit(struct wlr_render_pass *wlr_pass) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkSemaphore sem = render_pass_wait_sync_file(pass, render_wait_len, sync_file_fds[i]);
|
VkSemaphore sem = vulkan_command_buffer_wait_sync_file(renderer, render_cb,
|
||||||
|
render_wait_len, sync_file_fds[i]);
|
||||||
if (sem == VK_NULL_HANDLE) {
|
if (sem == VK_NULL_HANDLE) {
|
||||||
close(sync_file_fds[i]);
|
close(sync_file_fds[i]);
|
||||||
continue;
|
continue;
|
||||||
|
|
|
||||||
|
|
@ -379,7 +379,52 @@ VkCommandBuffer vulkan_record_stage_cb(struct wlr_vk_renderer *renderer) {
|
||||||
return renderer->stage.cb->vk;
|
return renderer->stage.cb->vk;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool vulkan_submit_stage_wait(struct wlr_vk_renderer *renderer) {
|
VkSemaphore vulkan_command_buffer_wait_sync_file(struct wlr_vk_renderer *renderer,
|
||||||
|
struct wlr_vk_command_buffer *render_cb, size_t sem_index, int sync_file_fd) {
|
||||||
|
VkResult res;
|
||||||
|
|
||||||
|
VkSemaphore *wait_semaphores = render_cb->wait_semaphores.data;
|
||||||
|
size_t wait_semaphores_len = render_cb->wait_semaphores.size / sizeof(wait_semaphores[0]);
|
||||||
|
|
||||||
|
VkSemaphore *sem_ptr;
|
||||||
|
if (sem_index >= wait_semaphores_len) {
|
||||||
|
sem_ptr = wl_array_add(&render_cb->wait_semaphores, sizeof(*sem_ptr));
|
||||||
|
if (sem_ptr == NULL) {
|
||||||
|
return VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
*sem_ptr = VK_NULL_HANDLE;
|
||||||
|
} else {
|
||||||
|
sem_ptr = &wait_semaphores[sem_index];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*sem_ptr == VK_NULL_HANDLE) {
|
||||||
|
VkSemaphoreCreateInfo semaphore_info = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
|
||||||
|
};
|
||||||
|
res = vkCreateSemaphore(renderer->dev->dev, &semaphore_info, NULL, sem_ptr);
|
||||||
|
if (res != VK_SUCCESS) {
|
||||||
|
wlr_vk_error("vkCreateSemaphore", res);
|
||||||
|
return VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VkImportSemaphoreFdInfoKHR import_info = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR,
|
||||||
|
.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
|
||||||
|
.flags = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT,
|
||||||
|
.semaphore = *sem_ptr,
|
||||||
|
.fd = sync_file_fd,
|
||||||
|
};
|
||||||
|
res = renderer->dev->api.vkImportSemaphoreFdKHR(renderer->dev->dev, &import_info);
|
||||||
|
if (res != VK_SUCCESS) {
|
||||||
|
wlr_vk_error("vkImportSemaphoreFdKHR", res);
|
||||||
|
return VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *sem_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool vulkan_submit_stage_wait(struct wlr_vk_renderer *renderer, int wait_sync_file_fd) {
|
||||||
if (renderer->stage.cb == NULL) {
|
if (renderer->stage.cb == NULL) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -389,9 +434,12 @@ bool vulkan_submit_stage_wait(struct wlr_vk_renderer *renderer) {
|
||||||
|
|
||||||
uint64_t timeline_point = vulkan_end_command_buffer(cb, renderer);
|
uint64_t timeline_point = vulkan_end_command_buffer(cb, renderer);
|
||||||
if (timeline_point == 0) {
|
if (timeline_point == 0) {
|
||||||
|
close(wait_sync_file_fd);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VkSemaphore wait_semaphore;
|
||||||
|
VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
|
||||||
VkTimelineSemaphoreSubmitInfoKHR timeline_submit_info = {
|
VkTimelineSemaphoreSubmitInfoKHR timeline_submit_info = {
|
||||||
.sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO_KHR,
|
.sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO_KHR,
|
||||||
.signalSemaphoreValueCount = 1,
|
.signalSemaphoreValueCount = 1,
|
||||||
|
|
@ -405,6 +453,18 @@ bool vulkan_submit_stage_wait(struct wlr_vk_renderer *renderer) {
|
||||||
.signalSemaphoreCount = 1,
|
.signalSemaphoreCount = 1,
|
||||||
.pSignalSemaphores = &renderer->timeline_semaphore,
|
.pSignalSemaphores = &renderer->timeline_semaphore,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (wait_sync_file_fd != -1) {
|
||||||
|
wait_semaphore = vulkan_command_buffer_wait_sync_file(renderer, cb, 0, wait_sync_file_fd);
|
||||||
|
if (wait_semaphore == VK_NULL_HANDLE) {
|
||||||
|
close(wait_sync_file_fd);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
submit_info.waitSemaphoreCount = 1;
|
||||||
|
submit_info.pWaitSemaphores = &wait_semaphore;
|
||||||
|
submit_info.pWaitDstStageMask = &wait_stage;
|
||||||
|
}
|
||||||
|
|
||||||
VkResult res = vkQueueSubmit(renderer->dev->queue, 1, &submit_info, VK_NULL_HANDLE);
|
VkResult res = vkQueueSubmit(renderer->dev->queue, 1, &submit_info, VK_NULL_HANDLE);
|
||||||
if (res != VK_SUCCESS) {
|
if (res != VK_SUCCESS) {
|
||||||
wlr_vk_error("vkQueueSubmit", res);
|
wlr_vk_error("vkQueueSubmit", res);
|
||||||
|
|
@ -1218,7 +1278,8 @@ bool vulkan_read_pixels(struct wlr_vk_renderer *vk_renderer,
|
||||||
VkFormat src_format, VkImage src_image,
|
VkFormat src_format, VkImage src_image,
|
||||||
uint32_t drm_format, uint32_t stride,
|
uint32_t drm_format, uint32_t stride,
|
||||||
uint32_t width, uint32_t height, uint32_t src_x, uint32_t src_y,
|
uint32_t width, uint32_t height, uint32_t src_x, uint32_t src_y,
|
||||||
uint32_t dst_x, uint32_t dst_y, void *data) {
|
uint32_t dst_x, uint32_t dst_y, void *data,
|
||||||
|
struct wlr_drm_syncobj_timeline *wait_timeline, uint64_t wait_point) {
|
||||||
VkDevice dev = vk_renderer->dev->dev;
|
VkDevice dev = vk_renderer->dev->dev;
|
||||||
|
|
||||||
const struct wlr_pixel_format_info *pixel_format_info = drm_get_pixel_format_info(drm_format);
|
const struct wlr_pixel_format_info *pixel_format_info = drm_get_pixel_format_info(drm_format);
|
||||||
|
|
@ -1404,7 +1465,17 @@ bool vulkan_read_pixels(struct wlr_vk_renderer *vk_renderer,
|
||||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||||
VK_ACCESS_MEMORY_READ_BIT);
|
VK_ACCESS_MEMORY_READ_BIT);
|
||||||
|
|
||||||
if (!vulkan_submit_stage_wait(vk_renderer)) {
|
int wait_sync_file_fd = -1;
|
||||||
|
if (wait_timeline != NULL) {
|
||||||
|
wait_sync_file_fd = wlr_drm_syncobj_timeline_export_sync_file(wait_timeline, wait_point);
|
||||||
|
if (wait_sync_file_fd < 0) {
|
||||||
|
wlr_log(WLR_ERROR, "Failed to export wait timeline point as sync_file");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!vulkan_submit_stage_wait(vk_renderer, wait_sync_file_fd)) {
|
||||||
|
close(wait_sync_file_fd);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -238,7 +238,8 @@ static bool vulkan_texture_read_pixels(struct wlr_texture *wlr_texture,
|
||||||
void *p = wlr_texture_read_pixel_options_get_data(options);
|
void *p = wlr_texture_read_pixel_options_get_data(options);
|
||||||
|
|
||||||
return vulkan_read_pixels(texture->renderer, texture->format->vk, texture->image,
|
return vulkan_read_pixels(texture->renderer, texture->format->vk, texture->image,
|
||||||
options->format, options->stride, src.width, src.height, src.x, src.y, 0, 0, p);
|
options->format, options->stride, src.width, src.height, src.x, src.y, 0, 0, p,
|
||||||
|
options->wait_timeline, options->wait_point);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t vulkan_texture_preferred_read_format(struct wlr_texture *wlr_texture) {
|
static uint32_t vulkan_texture_preferred_read_format(struct wlr_texture *wlr_texture) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue