c/main: Refactor out mirror_to_debug_gui code

This commit is contained in:
Jakob Bornecrantz 2023-05-16 15:06:13 +01:00
parent f359826363
commit 44c81b6ddb
4 changed files with 456 additions and 295 deletions

View file

@ -185,6 +185,8 @@ if(XRT_MODULE_COMPOSITOR_MAIN)
main/comp_layer.c
main/comp_layer_renderer.h
main/comp_layer_renderer.c
main/comp_mirror_to_debug_gui.c
main/comp_mirror_to_debug_gui.h
)
target_link_libraries(
comp_main

View file

@ -0,0 +1,321 @@
// Copyright 2019-2023, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Compositor mirroring code.
* @author Moses Turner <moses@collabora.com>
* @author Jakob Bornecrantz <jakob@collabora.com>
* @ingroup comp_main
*/
#include "math/m_mathinclude.h"
#include "main/comp_mirror_to_debug_gui.h"
/*
*
* Helper functions.
*
*/
static bool
ensure_scratch(struct comp_mirror_to_debug_gui *m, struct vk_bundle *vk)
{
VkResult ret;
if (m->bounce.image != VK_NULL_HANDLE) {
return true;
}
VkFormat format = VK_FORMAT_R8G8B8A8_SRGB;
VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
VkExtent2D extent = m->image_extent;
ret = vk_create_image_simple( //
vk, // vk_bundle
extent, // extent
format, // format
usage, // usage
&m->bounce.mem, // out_mem
&m->bounce.image); // out_image
if (ret != VK_SUCCESS) {
VK_ERROR(vk, "vk_create_image_simple: %s", vk_result_string(ret));
return false;
}
return true;
}
/*
*
* 'Exported' functions.
*
*/
VkResult
comp_mirror_init(struct comp_mirror_to_debug_gui *m, struct vk_bundle *vk, VkExtent2D extent)
{
VkResult ret;
// Do this init as early as possible.
u_sink_debug_init(&m->debug_sink);
double orig_width = extent.width;
double orig_height = extent.height;
double target_height = 1080;
double mul = target_height / orig_height;
// Casts seem to always round down; we don't want that here.
m->image_extent.width = (uint32_t)(round(orig_width * mul));
m->image_extent.height = (uint32_t)target_height;
// We want the images to have even widths/heights so that libx264 can encode them properly; no other reason.
if (m->image_extent.width % 2 == 1) {
m->image_extent.width += 1;
}
vk_image_readback_to_xf_pool_create( //
vk, // vk_bundle
m->image_extent, // extent
&m->pool, // out_pool
XRT_FORMAT_R8G8B8X8, // xrt_format
VK_FORMAT_R8G8B8A8_SRGB); // vk_format
ret = vk_cmd_pool_init(vk, &m->cmd_pool, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT);
if (ret != VK_SUCCESS) {
VK_ERROR(vk, "vk_cmd_pool_init: %s", vk_result_string(ret));
return ret;
}
return VK_SUCCESS;
}
void
comp_mirror_add_debug_vars(struct comp_mirror_to_debug_gui *m, struct comp_compositor *c)
{
// Reset state.
m->push_every_frame_out_of_X = 2;
// Init widigts.
u_frame_times_widget_init(&m->push_frame_times, 0.f, 0.f);
comp_mirror_fixup_ui_state(m, c);
// Do the adding now.
u_var_add_root(m, "Readback", true);
u_var_add_bool(m, &c->mirroring_to_debug_gui, "Readback left eye to debug GUI");
u_var_add_i32(m, &m->push_every_frame_out_of_X, "Push 1 frame out of every X frames");
u_var_add_ro_f32(m, &m->push_frame_times.fps, "FPS (Readback)");
u_var_add_f32_timing(m, m->push_frame_times.debug_var, "Frame Times (Readback)");
u_var_add_sink_debug(m, &m->debug_sink, "Left view!");
}
void
comp_mirror_fixup_ui_state(struct comp_mirror_to_debug_gui *m, struct comp_compositor *c)
{
// One out of every zero frames is not what we want!
// Also one out of every negative two frames, etc. is nonsensical
if (m->push_every_frame_out_of_X < 1) {
m->push_every_frame_out_of_X = 1;
}
float nominal_frame_interval_ms = (float)time_ns_to_ms_f(c->settings.nominal_frame_interval_ns);
m->target_frame_time_ms = (float)m->push_every_frame_out_of_X * nominal_frame_interval_ms;
m->push_frame_times.debug_var->reference_timing = m->target_frame_time_ms;
m->push_frame_times.debug_var->range = m->target_frame_time_ms;
}
bool
comp_mirror_is_ready_and_active(struct comp_mirror_to_debug_gui *m,
struct comp_compositor *c,
uint64_t predicted_display_time_ns)
{
if (!c->mirroring_to_debug_gui || !u_sink_debug_is_active(&m->debug_sink)) {
return false;
}
double diff_ms = time_ns_to_ms_f(predicted_display_time_ns - m->last_push_ts_ns);
// Completely unscientific - lower values probably works fine too.
// I figure we don't have very many 500Hz displays and this woorks great for 120-144hz
double slop_ms = 2;
if (diff_ms < m->target_frame_time_ms - slop_ms) {
return false;
}
// Set the last time to the frame that is being displayed.
m->last_push_ts_ns = predicted_display_time_ns;
return true;
}
void
comp_mirror_do_blit(struct comp_mirror_to_debug_gui *m,
struct vk_bundle *vk,
uint64_t predicted_display_time_ns,
VkImage from_image,
VkExtent2D from_extent)
{
VkResult ret;
struct vk_image_readback_to_xf *wrap = NULL;
if (!vk_image_readback_to_xf_pool_get_unused_frame(vk, m->pool, &wrap)) {
return;
}
if (!ensure_scratch(m, vk)) {
return;
}
struct vk_cmd_pool *pool = &m->cmd_pool;
// For writing and submitting commands.
vk_cmd_pool_lock(pool);
VkCommandBuffer cmd;
ret = vk_cmd_pool_create_and_begin_cmd_buffer_locked(vk, pool, 0, &cmd);
if (ret != VK_SUCCESS) {
vk_cmd_pool_unlock(pool);
return;
}
// First mip view into the copy from image.
struct vk_cmd_first_mip_image copy_from_fm_image = {
.aspect_mask = VK_IMAGE_ASPECT_COLOR_BIT,
.base_array_layer = 0,
.image = from_image,
};
// First mip view into the bounce image.
struct vk_cmd_first_mip_image bounce_fm_image = {
.aspect_mask = VK_IMAGE_ASPECT_COLOR_BIT,
.base_array_layer = 0,
.image = m->bounce.image,
};
// First mip view into the target image.
struct vk_cmd_first_mip_image target_fm_image = {
.aspect_mask = VK_IMAGE_ASPECT_COLOR_BIT,
.base_array_layer = 0,
.image = wrap->image,
};
// Blit arguments.
struct vk_cmd_blit_image_info blit_info = {
.src.old_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
.src.src_access_mask = VK_ACCESS_SHADER_READ_BIT,
.src.src_stage_mask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
.src.fm_image = copy_from_fm_image,
.src.rect.offset = {0, 0},
.src.rect.extent = {from_extent.width, from_extent.height},
.dst.old_layout = VK_IMAGE_LAYOUT_UNDEFINED,
.dst.src_access_mask = VK_ACCESS_TRANSFER_READ_BIT,
.dst.src_stage_mask = VK_PIPELINE_STAGE_TRANSFER_BIT,
.dst.fm_image = bounce_fm_image,
.dst.rect.offset = {0, 0},
.dst.rect.extent = {m->image_extent.width, m->image_extent.height},
};
vk_cmd_blit_image_locked(vk, cmd, &blit_info);
// Copy arguments.
struct vk_cmd_copy_image_info copy_info = {
.src.old_layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
.src.src_access_mask = VK_ACCESS_TRANSFER_WRITE_BIT,
.src.src_stage_mask = VK_PIPELINE_STAGE_TRANSFER_BIT,
.src.fm_image = bounce_fm_image,
.dst.old_layout = wrap->layout,
.dst.src_access_mask = VK_ACCESS_HOST_READ_BIT,
.dst.src_stage_mask = VK_PIPELINE_STAGE_HOST_BIT,
.dst.fm_image = target_fm_image,
.size.w = m->image_extent.width,
.size.h = m->image_extent.height,
};
vk_cmd_copy_image_locked(vk, cmd, &copy_info);
// Barrier arguments.
VkImageSubresourceRange first_color_level_subresource_range = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
};
// Barrier readback image to host so we can safely read
vk_cmd_image_barrier_locked( //
vk, // vk_bundle
cmd, // cmdbuffer
wrap->image, // image
VK_ACCESS_TRANSFER_WRITE_BIT, // srcAccessMask
VK_ACCESS_HOST_READ_BIT, // dstAccessMask
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // oldImageLayout
VK_IMAGE_LAYOUT_GENERAL, // newImageLayout
VK_PIPELINE_STAGE_TRANSFER_BIT, // srcStageMask
VK_PIPELINE_STAGE_HOST_BIT, // dstStageMask
first_color_level_subresource_range); // subresourceRange
// Done writing commands, submit to queue, waits for command to finish.
ret = vk_cmd_pool_end_submit_wait_and_free_cmd_buffer_locked(vk, pool, cmd);
// Done submitting commands.
vk_cmd_pool_unlock(pool);
// Check results from submit.
if (ret != VK_SUCCESS) {
//! @todo Better handling of error?
VK_ERROR(vk, "vk_cmd_pool_end_submit_wait_and_free_cmd_buffer_locked: %s", vk_result_string(ret));
}
wrap->base_frame.source_timestamp = wrap->base_frame.timestamp = predicted_display_time_ns;
wrap->base_frame.source_id = m->sequence++;
struct xrt_frame *frame = &wrap->base_frame;
wrap = NULL;
u_sink_debug_push_frame(&m->debug_sink, frame);
u_frame_times_widget_push_sample(&m->push_frame_times, predicted_display_time_ns);
xrt_frame_reference(&frame, NULL);
}
void
comp_mirror_fini(struct comp_mirror_to_debug_gui *m, struct vk_bundle *vk)
{
// Remove u_var root as early as possible.
u_var_remove_root(m);
// Left eye readback
vk_image_readback_to_xf_pool_destroy(vk, &m->pool);
if (m->bounce.image != VK_NULL_HANDLE) {
vk->vkFreeMemory(vk->device, m->bounce.mem, NULL);
vk->vkDestroyImage(vk->device, m->bounce.image, NULL);
}
// Command pool for readback code.
vk_cmd_pool_destroy(vk, &m->cmd_pool);
// The frame timing widigt.
u_frame_times_widget_teardown(&m->push_frame_times);
// Destroy as late as possible.
u_sink_debug_destroy(&m->debug_sink);
}

View file

@ -0,0 +1,115 @@
// Copyright 2019-2023, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Compositor mirroring code.
* @author Moses Turner <moses@collabora.com>
* @author Jakob Bornecrantz <jakob@collabora.com>
* @ingroup comp_main
*/
#pragma once
#include "util/u_sink.h"
#include "vk/vk_image_readback_to_xf_pool.h"
#include "main/comp_compositor.h"
#ifdef __cplusplus
extern "C" {
#endif
/*!
* Helper struct for mirroring the compositors rendering to the debug ui,
* which also enables recording. Currently embedded in @ref comp_renderer.
*
* @ingroup comp_main
*/
struct comp_mirror_to_debug_gui
{
/*
* Hint: enable/disable is in c->mirroring_to_debug_gui. It is there
* because the ccomp_renderer struct is just a forward decl in the
* header and then defined properly in the comp_renderer.c file.
*/
struct u_frame_times_widget push_frame_times;
float target_frame_time_ms;
uint64_t last_push_ts_ns;
int push_every_frame_out_of_X;
struct u_sink_debug debug_sink;
VkExtent2D image_extent;
uint64_t sequence;
struct vk_image_readback_to_xf_pool *pool;
struct
{
VkImage image;
VkDeviceMemory mem;
} bounce;
struct vk_cmd_pool cmd_pool;
};
/*!
* Initialise the struct.
*
* @public @memberof comp_mirror_to_debug_gui
*/
VkResult
comp_mirror_init(struct comp_mirror_to_debug_gui *m, struct vk_bundle *vk, VkExtent2D extent);
/*!
* One time adding of the debug variables.
*
* @public @memberof comp_mirror_to_debug_gui
*/
void
comp_mirror_add_debug_vars(struct comp_mirror_to_debug_gui *m, struct comp_compositor *c);
/*!
* Fixup various timing state.
*
* @public @memberof comp_mirror_to_debug_gui
*/
void
comp_mirror_fixup_ui_state(struct comp_mirror_to_debug_gui *m, struct comp_compositor *c);
/*!
* Is this struct ready and capable of mirroring the image, can only
* call @ref comp_mirror_do_blit if this function has returned true.
*
* @public @memberof comp_mirror_to_debug_gui
*/
bool
comp_mirror_is_ready_and_active(struct comp_mirror_to_debug_gui *m,
struct comp_compositor *c,
uint64_t predicted_display_time_ns);
/*!
* Do the blit.
*
* @public @memberof comp_mirror_to_debug_gui
*/
void
comp_mirror_do_blit(struct comp_mirror_to_debug_gui *m,
struct vk_bundle *vk,
uint64_t predicted_display_time_ns,
VkImage from_image,
VkExtent2D from_extent);
/*!
* Finalise the struct, frees and resources.
*
* @public @memberof comp_mirror_to_debug_gui
*/
void
comp_mirror_fini(struct comp_mirror_to_debug_gui *m, struct vk_bundle *vk);
#ifdef __cplusplus
}
#endif

View file

@ -30,6 +30,7 @@
#include "main/comp_layer_renderer.h"
#include "main/comp_frame.h"
#include "main/comp_mirror_to_debug_gui.h"
#ifdef XRT_FEATURE_WINDOW_PEEK
#include "main/comp_window_peek.h"
@ -63,7 +64,7 @@
/*
*
* Private struct.
* Private struct(s).
*
*/
@ -82,31 +83,7 @@ struct comp_renderer
struct comp_compositor *c;
struct comp_settings *settings;
struct
{
// Hint: enable/disable is in c->mirroring_to_debug_gui. It's there because comp_renderer is just a
// forward decl to comp_compositor.c
struct u_frame_times_widget push_frame_times;
float target_frame_time_ms;
uint64_t last_push_ts_ns;
int push_every_frame_out_of_X;
struct u_sink_debug debug_sink;
VkExtent2D image_extent;
uint64_t sequence;
struct vk_image_readback_to_xf_pool *pool;
struct
{
VkImage image;
VkDeviceMemory mem;
} bounce;
struct vk_cmd_pool cmd_pool;
} mirror_to_debug_gui;
struct comp_mirror_to_debug_gui mirror_to_debug_gui;
//! @}
@ -566,41 +543,14 @@ renderer_init(struct comp_renderer *r, struct comp_compositor *c)
r->fenced_buffer = -1;
r->rtr_array = NULL;
// Do this init as early as possible.
u_sink_debug_init(&r->mirror_to_debug_gui.debug_sink);
// Try to early-allocate these, in case we can.
renderer_ensure_images_and_renderings(r, false);
double orig_width = r->lr->extent.width;
double orig_height = r->lr->extent.height;
double target_height = 1080;
double mul = target_height / orig_height;
// Casts seem to always round down; we don't want that here.
r->mirror_to_debug_gui.image_extent.width = (uint32_t)(round(orig_width * mul));
r->mirror_to_debug_gui.image_extent.height = (uint32_t)target_height;
// We want the images to have even widths/heights so that libx264 can encode them properly; no other reason.
if (r->mirror_to_debug_gui.image_extent.width % 2 == 1) {
r->mirror_to_debug_gui.image_extent.width += 1;
}
struct vk_bundle *vk = &r->c->base.vk;
vk_image_readback_to_xf_pool_create( //
vk, //
r->mirror_to_debug_gui.image_extent, //
&r->mirror_to_debug_gui.pool, //
XRT_FORMAT_R8G8B8X8, //
VK_FORMAT_R8G8B8A8_SRGB); //
VkResult ret = vk_cmd_pool_init(vk, &r->mirror_to_debug_gui.cmd_pool, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT);
VkResult ret = comp_mirror_init(&r->mirror_to_debug_gui, vk, r->lr->extent);
if (ret != VK_SUCCESS) {
COMP_ERROR(c, "vk_cmd_pool_init: %s", vk_result_string(ret));
COMP_ERROR(c, "comp_mirror_init: %s", vk_result_string(ret));
assert(false && "Whelp, can't return a error. But should never really fail.");
}
}
@ -846,29 +796,14 @@ renderer_fini(struct comp_renderer *r)
{
struct vk_bundle *vk = &r->c->base.vk;
// Remove u_var root as early as possible.
u_var_remove_root(r);
// Left eye readback
vk_image_readback_to_xf_pool_destroy(vk, &r->mirror_to_debug_gui.pool);
if (r->mirror_to_debug_gui.bounce.image != VK_NULL_HANDLE) {
vk->vkFreeMemory(vk->device, r->mirror_to_debug_gui.bounce.mem, NULL);
vk->vkDestroyImage(vk->device, r->mirror_to_debug_gui.bounce.image, NULL);
}
// Command pool for readback code.
vk_cmd_pool_destroy(vk, &r->mirror_to_debug_gui.cmd_pool);
// Command buffers
renderer_close_renderings_and_fences(r);
// Do before layer render just in case it holds any references.
comp_mirror_fini(&r->mirror_to_debug_gui, vk);
// Do this after the mirror struct.
comp_layer_renderer_destroy(&(r->lr));
u_frame_times_widget_teardown(&r->mirror_to_debug_gui.push_frame_times);
// Destroy as late as possible.
u_sink_debug_destroy(&r->mirror_to_debug_gui.debug_sink);
}
static VkImageView
@ -1755,210 +1690,6 @@ comp_renderer_set_cube_layer(struct comp_renderer *r,
}
#endif
static void
mirror_to_debug_gui_fixup_ui_state(struct comp_renderer *r)
{
// One out of every zero frames is not what we want!
// Also one out of every negative two frames, etc. is nonsensical
if (r->mirror_to_debug_gui.push_every_frame_out_of_X < 1) {
r->mirror_to_debug_gui.push_every_frame_out_of_X = 1;
}
r->mirror_to_debug_gui.target_frame_time_ms = (float)r->mirror_to_debug_gui.push_every_frame_out_of_X *
(float)time_ns_to_ms_f(r->c->settings.nominal_frame_interval_ns);
r->mirror_to_debug_gui.push_frame_times.debug_var->reference_timing =
r->mirror_to_debug_gui.target_frame_time_ms;
r->mirror_to_debug_gui.push_frame_times.debug_var->range = r->mirror_to_debug_gui.target_frame_time_ms;
}
static bool
can_mirror_to_debug_gui(struct comp_renderer *r, uint64_t predicted_display_time_ns)
{
if (!r->c->mirroring_to_debug_gui || !u_sink_debug_is_active(&r->mirror_to_debug_gui.debug_sink)) {
return false;
}
double diff_ms = time_ns_to_ms_f(predicted_display_time_ns - r->mirror_to_debug_gui.last_push_ts_ns);
// Completely unscientific - lower values probably works fine too.
// I figure we don't have very many 500Hz displays and this woorks great for 120-144hz
double slop_ms = 2;
if (diff_ms < r->mirror_to_debug_gui.target_frame_time_ms - slop_ms) {
return false;
}
// Set the last time to the frame that is being displayed.
r->mirror_to_debug_gui.last_push_ts_ns = predicted_display_time_ns;
return true;
}
static bool
mirror_to_debug_gui_ensure_scratch(struct comp_renderer *r)
{
if (r->mirror_to_debug_gui.bounce.image != VK_NULL_HANDLE) {
return true;
}
struct vk_bundle *vk = &r->c->base.vk;
VkFormat format = VK_FORMAT_R8G8B8A8_SRGB;
VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
VkExtent2D extent = r->mirror_to_debug_gui.image_extent;
if (vk_create_image_simple( //
vk, // vk_bundle
extent, // extent
format, // format
usage, // usage
&r->mirror_to_debug_gui.bounce.mem, // out_mem
&r->mirror_to_debug_gui.bounce.image // out_image
) != VK_SUCCESS) {
return false;
}
return true;
}
static void
mirror_to_debug_gui_do_blit(struct comp_renderer *r)
{
struct vk_bundle *vk = &r->c->base.vk;
VkResult ret;
struct vk_image_readback_to_xf *wrap = NULL;
if (!vk_image_readback_to_xf_pool_get_unused_frame(vk, r->mirror_to_debug_gui.pool, &wrap)) {
return;
}
if (!mirror_to_debug_gui_ensure_scratch(r)) {
return;
}
struct vk_cmd_pool *pool = &r->mirror_to_debug_gui.cmd_pool;
// For writing and submitting commands.
vk_cmd_pool_lock(pool);
VkCommandBuffer cmd;
ret = vk_cmd_pool_create_and_begin_cmd_buffer_locked(vk, pool, 0, &cmd);
if (ret != VK_SUCCESS) {
vk_cmd_pool_unlock(pool);
return;
}
// First mip view into the copy from image.
struct vk_cmd_first_mip_image copy_from_fm_image = {
.aspect_mask = VK_IMAGE_ASPECT_COLOR_BIT,
.base_array_layer = 0,
.image = r->lr->framebuffers[0].image,
};
// First mip view into the bounce image.
struct vk_cmd_first_mip_image bounce_fm_image = {
.aspect_mask = VK_IMAGE_ASPECT_COLOR_BIT,
.base_array_layer = 0,
.image = r->mirror_to_debug_gui.bounce.image,
};
// First mip view into the target image.
struct vk_cmd_first_mip_image target_fm_image = {
.aspect_mask = VK_IMAGE_ASPECT_COLOR_BIT,
.base_array_layer = 0,
.image = wrap->image,
};
// Blit arguments.
struct vk_cmd_blit_image_info blit_info = {
.src.old_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
.src.src_access_mask = VK_ACCESS_SHADER_READ_BIT,
.src.src_stage_mask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
.src.fm_image = copy_from_fm_image,
.src.rect.offset = {0, 0},
.src.rect.extent = {r->lr->extent.width, r->lr->extent.height},
.dst.old_layout = VK_IMAGE_LAYOUT_UNDEFINED,
.dst.src_access_mask = VK_ACCESS_TRANSFER_READ_BIT,
.dst.src_stage_mask = VK_PIPELINE_STAGE_TRANSFER_BIT,
.dst.fm_image = bounce_fm_image,
.dst.rect.offset = {0, 0},
.dst.rect.extent = {r->mirror_to_debug_gui.image_extent.width, r->mirror_to_debug_gui.image_extent.height},
};
vk_cmd_blit_image_locked(vk, cmd, &blit_info);
// Copy arguments.
struct vk_cmd_copy_image_info copy_info = {
.src.old_layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
.src.src_access_mask = VK_ACCESS_TRANSFER_WRITE_BIT,
.src.src_stage_mask = VK_PIPELINE_STAGE_TRANSFER_BIT,
.src.fm_image = bounce_fm_image,
.dst.old_layout = wrap->layout,
.dst.src_access_mask = VK_ACCESS_HOST_READ_BIT,
.dst.src_stage_mask = VK_PIPELINE_STAGE_HOST_BIT,
.dst.fm_image = target_fm_image,
.size.w = r->mirror_to_debug_gui.image_extent.width,
.size.h = r->mirror_to_debug_gui.image_extent.height,
};
vk_cmd_copy_image_locked(vk, cmd, &copy_info);
// Barrier arguments.
VkImageSubresourceRange first_color_level_subresource_range = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
};
// Barrier readback image to host so we can safely read
vk_cmd_image_barrier_locked( //
vk, // vk_bundle
cmd, // cmdbuffer
wrap->image, // image
VK_ACCESS_TRANSFER_WRITE_BIT, // srcAccessMask
VK_ACCESS_HOST_READ_BIT, // dstAccessMask
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // oldImageLayout
VK_IMAGE_LAYOUT_GENERAL, // newImageLayout
VK_PIPELINE_STAGE_TRANSFER_BIT, // srcStageMask
VK_PIPELINE_STAGE_HOST_BIT, // dstStageMask
first_color_level_subresource_range); // subresourceRange
// Done writing commands, submit to queue, waits for command to finish.
ret = vk_cmd_pool_end_submit_wait_and_free_cmd_buffer_locked(vk, pool, cmd);
// Done submitting commands.
vk_cmd_pool_unlock(pool);
// Check results from submit.
if (ret != VK_SUCCESS) {
//! @todo Better handling of error?
COMP_ERROR(r->c, "Failed to mirror image");
}
wrap->base_frame.source_timestamp = wrap->base_frame.timestamp =
r->c->frame.rendering.predicted_display_time_ns;
wrap->base_frame.source_id = r->mirror_to_debug_gui.sequence++;
struct xrt_frame *frame = &wrap->base_frame;
wrap = NULL;
u_sink_debug_push_frame(&r->mirror_to_debug_gui.debug_sink, frame);
u_frame_times_widget_push_sample(&r->mirror_to_debug_gui.push_frame_times,
r->c->frame.rendering.predicted_display_time_ns);
xrt_frame_reference(&frame, NULL);
}
void
comp_renderer_draw(struct comp_renderer *r)
{
@ -2039,9 +1770,14 @@ comp_renderer_draw(struct comp_renderer *r)
// Clear the rendered frame.
comp_frame_clear_locked(&c->frame.rendering);
mirror_to_debug_gui_fixup_ui_state(r);
if (can_mirror_to_debug_gui(r, predicted_display_time_ns)) {
mirror_to_debug_gui_do_blit(r);
comp_mirror_fixup_ui_state(&r->mirror_to_debug_gui, c);
if (comp_mirror_is_ready_and_active(&r->mirror_to_debug_gui, c, predicted_display_time_ns)) {
comp_mirror_do_blit( //
&r->mirror_to_debug_gui, //
&c->base.vk, //
predicted_display_time_ns, //
r->lr->framebuffers[0].image, //
r->lr->extent); //
}
/*
@ -2156,19 +1892,6 @@ void
comp_renderer_add_debug_vars(struct comp_renderer *self)
{
struct comp_renderer *r = self;
r->mirror_to_debug_gui.push_every_frame_out_of_X = 2;
u_frame_times_widget_init(&r->mirror_to_debug_gui.push_frame_times, 0.f, 0.f);
mirror_to_debug_gui_fixup_ui_state(r);
u_var_add_root(r, "Readback", true);
u_var_add_bool(r, &r->c->mirroring_to_debug_gui, "Readback left eye to debug GUI");
u_var_add_i32(r, &r->mirror_to_debug_gui.push_every_frame_out_of_X, "Push 1 frame out of every X frames");
u_var_add_ro_f32(r, &r->mirror_to_debug_gui.push_frame_times.fps, "FPS (Readback)");
u_var_add_f32_timing(r, r->mirror_to_debug_gui.push_frame_times.debug_var, "Frame Times (Readback)");
u_var_add_sink_debug(r, &r->mirror_to_debug_gui.debug_sink, "Left view!");
comp_mirror_add_debug_vars(&r->mirror_to_debug_gui, r->c);
}