diff --git a/src/xrt/compositor/CMakeLists.txt b/src/xrt/compositor/CMakeLists.txt index 1bfae24c3..1ba5ec438 100644 --- a/src/xrt/compositor/CMakeLists.txt +++ b/src/xrt/compositor/CMakeLists.txt @@ -146,6 +146,8 @@ if(XRT_HAVE_VULKAN) comp_util STATIC util/comp_base.h util/comp_base.c + util/comp_high_level_render.c + util/comp_high_level_render.h util/comp_high_level_scratch.c util/comp_high_level_scratch.h util/comp_layer_accum.h diff --git a/src/xrt/compositor/util/comp_high_level_render.c b/src/xrt/compositor/util/comp_high_level_render.c new file mode 100644 index 000000000..f1c9aa145 --- /dev/null +++ b/src/xrt/compositor/util/comp_high_level_render.c @@ -0,0 +1,222 @@ +// Copyright 2019-2024, Collabora, Ltd. +// Copyright 2024-2025, NVIDIA CORPORATION. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Higher level interface for rendering a frame. + * @author Jakob Bornecrantz + * @author Christoph Haag + * @author Fernando Velazquez Innella + * @author Rylie Pavlik + * @ingroup comp_util + */ + +#include "comp_high_level_render.h" + + +/* + * + * Common + * + */ + +void +chl_frame_state_init(struct chl_frame_state *frame_state, + struct render_resources *rr, + uint32_t view_count, + bool do_timewarp, + bool fast_path, + struct chl_scratch *scratch) +{ + assert(rr != NULL); + assert(rr->vk != NULL); + assert(view_count <= rr->view_count); + + U_ZERO(frame_state); + frame_state->view_count = view_count; + frame_state->scratch = scratch; + + comp_render_initial_init( // + &frame_state->data, // data + fast_path, // fast_path + do_timewarp); // do_timewarp + + chl_scratch_state_init_and_get(&frame_state->scratch_state, scratch); +} + +void +chl_frame_state_fini(struct chl_frame_state *frame_state) +{ + if (frame_state->scratch == NULL) { + return; + } + + chl_scratch_state_discard_or_done(&frame_state->scratch_state, frame_state->scratch); + + U_ZERO(frame_state); +} + + +/* + * + * Graphics + * + */ + +void +chl_frame_state_gfx_set_views(struct chl_frame_state *frame_state, + const struct xrt_pose world_poses[XRT_MAX_VIEWS], + const struct xrt_pose eye_poses[XRT_MAX_VIEWS], + const struct xrt_fov fovs[XRT_MAX_VIEWS], + uint32_t layer_count) +{ + for (uint32_t i = 0; i < frame_state->view_count; i++) { + // Which image of the scratch images for this view are we using. + uint32_t scratch_index = frame_state->scratch_state.views[i].index; + + // The set of scratch images we are using for this view. + struct comp_scratch_single_images *scratch_view = &frame_state->scratch->views[i].cssi; + + // The render target resources for the scratch images. + struct render_gfx_target_resources *rsci_rtr = &frame_state->scratch->views[i].targets[scratch_index]; + + // Scratch color image. + struct render_scratch_color_image *rsci = &scratch_view->images[scratch_index]; + + // Use the whole scratch image. + struct render_viewport_data layer_viewport_data = { + .x = 0, + .y = 0, + .w = scratch_view->info.width, + .h = scratch_view->info.height, + }; + + comp_render_gfx_add_squash_view( // + &frame_state->data, // + &world_poses[i], // + &eye_poses[i], // + &fovs[i], // + rsci->image, // squash_image + rsci_rtr, // squash_rtr + &layer_viewport_data); // squash_viewport_data + + if (layer_count == 0) { + frame_state->scratch_state.views[i].used = false; + } else { + frame_state->scratch_state.views[i].used = !frame_state->data.fast_path; + } + } +} + +void +chl_frame_state_gfx_set_target(struct chl_frame_state *frame_state, + struct render_gfx_target_resources *target_rtr, + const struct render_viewport_data target_viewport_datas[XRT_MAX_VIEWS], + const struct xrt_matrix_2x2 vertex_rots[XRT_MAX_VIEWS]) +{ + // Add the target info. + comp_render_gfx_add_target(&frame_state->data, target_rtr); + + for (uint32_t i = 0; i < frame_state->view_count; i++) { + // Which image of the scratch images for this view are we using. + uint32_t scratch_index = frame_state->scratch_state.views[i].index; + + // The set of scratch images we are using for this view. + struct comp_scratch_single_images *scratch_view = &frame_state->scratch->views[i].cssi; + + // Scratch image covers the whole image. + struct xrt_normalized_rect layer_norm_rect = {.x = 0.0f, .y = 0.0f, .w = 1.0f, .h = 1.0f}; + + VkImageView sample_view = comp_scratch_single_images_get_sample_view(scratch_view, scratch_index); + + comp_render_gfx_add_target_view( // + &frame_state->data, // + sample_view, // squash_as_src_sample_view + &layer_norm_rect, // squash_as_src_norm_rect + &vertex_rots[i], // target_vertex_rot + &target_viewport_datas[i]); // target_viewport_data + } +} + + +/* + * + * Compute + * + */ + +void +chl_frame_state_cs_set_views(struct chl_frame_state *frame_state, + const struct xrt_pose world_poses[XRT_MAX_VIEWS], + const struct xrt_pose eye_poses[XRT_MAX_VIEWS], + const struct xrt_fov fovs[XRT_MAX_VIEWS], + uint32_t layer_count) +{ + for (uint32_t i = 0; i < frame_state->view_count; i++) { + // Which image of the scratch images for this view are we using. + uint32_t scratch_index = frame_state->scratch_state.views[i].index; + + // The set of scratch images we are using for this view. + struct comp_scratch_single_images *scratch_view = &frame_state->scratch->views[i].cssi; + + // Scratch color image. + struct render_scratch_color_image *rsci = &scratch_view->images[scratch_index]; + + // Use the whole scratch image. + struct render_viewport_data layer_viewport_data = { + .x = 0, + .y = 0, + .w = scratch_view->info.width, + .h = scratch_view->info.height, + }; + + VkImageView storage_view = comp_scratch_single_images_get_storage_view(scratch_view, scratch_index); + + comp_render_cs_add_squash_view( // + &frame_state->data, // + &world_poses[i], // + &eye_poses[i], // + &fovs[i], // + rsci->image, // squash_image + storage_view, // squash_storage_view + &layer_viewport_data); // squash_viewport_data + + if (layer_count == 0) { + frame_state->scratch_state.views[i].used = false; + } else { + frame_state->scratch_state.views[i].used = !frame_state->data.fast_path; + } + } +} + +void +chl_frame_state_cs_set_target(struct chl_frame_state *frame_state, + VkImage target_image, + VkImageView target_storage_view, + const struct render_viewport_data views[XRT_MAX_VIEWS]) +{ + // Add the target info. + comp_render_cs_add_target( // + &frame_state->data, // data + target_image, // target_image + target_storage_view); // target_unorm_view + + for (uint32_t i = 0; i < frame_state->view_count; i++) { + // Which image of the scratch images for this view are we using. + uint32_t scratch_index = frame_state->scratch_state.views[i].index; + + // The set of scratch images we are using for this view. + struct comp_scratch_single_images *scratch_view = &frame_state->scratch->views[i].cssi; + + // Scratch image covers the whole image. + struct xrt_normalized_rect layer_norm_rect = {.x = 0.0f, .y = 0.0f, .w = 1.0f, .h = 1.0f}; + + VkImageView sample_view = comp_scratch_single_images_get_sample_view(scratch_view, scratch_index); + + comp_render_cs_add_target_view( // + &frame_state->data, // + sample_view, // squash_as_src_sample_view + &layer_norm_rect, // squash_as_src_norm_rect + &views[i]); // target_viewport_data + } +} diff --git a/src/xrt/compositor/util/comp_high_level_render.h b/src/xrt/compositor/util/comp_high_level_render.h new file mode 100644 index 000000000..46edfd669 --- /dev/null +++ b/src/xrt/compositor/util/comp_high_level_render.h @@ -0,0 +1,239 @@ +// Copyright 2019-2024, Collabora, Ltd. +// Copyright 2024-2025, NVIDIA CORPORATION. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Higher level interface for rendering a frame. + * @author Jakob Bornecrantz + * @author Christoph Haag + * @author Fernando Velazquez Innella + * @author Rylie Pavlik + * @ingroup comp_util + */ + +#pragma once + + +#include "render/render_interface.h" + +#include "comp_render.h" +#include "comp_high_level_scratch.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/*! + * Encapsulates all the needed state to run the layer squasher and distortion + * passes, state object needs to be kept alive until the GPU work finishes. + * None of the functions are thread safe so make sure to synchronize access. + * + * The lifetime of this struct is one frame, but as stated above it needs to + * live for long enough that the GPU work has been finished. + * + * @comp_util + */ +struct chl_frame_state +{ + struct chl_scratch *scratch; + + uint32_t view_count; + + struct chl_scratch_state scratch_state; + + struct comp_render_dispatch_data data; + + struct render_compute cs; +}; + + +/* + * + * Shared functions. + * + */ + +/*! + * Create the Vulkan resources using the given @p render_resources and the + * @p vk_bundle it refers to. Is used for both graphics and compute paths, + * also manages the scratch state. + * + * @memberof chl_frame_state + */ +void +chl_frame_state_init(struct chl_frame_state *frame_state, + struct render_resources *rr, + uint32_t view_count, + bool do_timewarp, + bool fast_path, + struct chl_scratch *scratch); + +/*! + * Frees all resources that this frame state tracks and manages the scratch + * images state. Must be called after the GPU work has finished and has been + * waited on (or the validation layer gets upset). + * + * @memberof chl_frame_state + */ +void +chl_frame_state_fini(struct chl_frame_state *state); + + +/* + * + * Graphics. + * + */ + +/*! + * Sets all the needed state to run the layer squasher to the scratch images, + * this is the graphics version. + * + * @memberof chl_frame_state + */ +void +chl_frame_state_gfx_set_views(struct chl_frame_state *frame_state, + const struct xrt_pose world_pose[XRT_MAX_VIEWS], + const struct xrt_pose eye_pose[XRT_MAX_VIEWS], + const struct xrt_fov fov[XRT_MAX_VIEWS], + uint32_t layer_count); + +/*! + * Adds the needed information to also perform a distortion step, reuses some + * information from the _set_views call and as such this needs to be called + * before calling this function. This is the graphics version. + * + * @memberof chl_frame_state + */ +void +chl_frame_state_gfx_set_target(struct chl_frame_state *frame_state, + struct render_gfx_target_resources *target_rtr, + const struct render_viewport_data target_viewport_datas[XRT_MAX_VIEWS], + const struct xrt_matrix_2x2 vertex_rots[XRT_MAX_VIEWS]); + +/*! + * A single do all function, runs the default graphics pipeline. + * + * @memberof chl_frame_state + */ +static inline void +chl_frame_state_gfx_default_pipeline(struct chl_frame_state *frame_state, + struct render_gfx *render, + const struct comp_layer *layers, + uint32_t layer_count, + const struct xrt_pose world_poses[XRT_MAX_VIEWS], + const struct xrt_pose eye_poses[XRT_MAX_VIEWS], + const struct xrt_fov fovs[XRT_MAX_VIEWS], + struct render_gfx_target_resources *target_rtr, + const struct render_viewport_data target_viewport_datas[XRT_MAX_VIEWS], + const struct xrt_matrix_2x2 vertex_rots[XRT_MAX_VIEWS]) +{ + chl_frame_state_gfx_set_views( // + frame_state, // + world_poses, // + eye_poses, // + fovs, // + layer_count); // + + chl_frame_state_gfx_set_target( // + frame_state, // + target_rtr, // + target_viewport_datas, // + vertex_rots); // + + // Start the compute pipeline. + render_gfx_begin(render); + + // Build the command buffer. + comp_render_gfx_dispatch( // + render, // + layers, // + layer_count, // + &frame_state->data); // + + // Make the command buffer submittable. + render_gfx_end(render); +} + + +/* + * + * Compute + * + */ + +/*! + * Sets all the needed state to run the layer squasher to the scratch images, + * this is the compute version. + * + * @memberof chl_frame_state + */ +void +chl_frame_state_cs_set_views(struct chl_frame_state *frame_state, + const struct xrt_pose world_pose[XRT_MAX_VIEWS], + const struct xrt_pose eye_pose[XRT_MAX_VIEWS], + const struct xrt_fov fov[XRT_MAX_VIEWS], + uint32_t layer_count); + +/*! + * Adds the needed information to also perform a distortion step, reuses some + * information from the _set_views call and as such this needs to be called + * before calling this function. This is the compute version. + * + * @memberof chl_frame_state + */ +void +chl_frame_state_cs_set_target(struct chl_frame_state *frame_state, + VkImage target_image, + VkImageView target_storage_view, + const struct render_viewport_data views[XRT_MAX_VIEWS]); + +/*! + * A single do all function, runs the default compute pipeline. + * + * @memberof chl_frame_state + */ +static inline void +chl_frame_state_cs_default_pipeline(struct chl_frame_state *frame_state, + struct render_compute *render, + const struct comp_layer *layers, + uint32_t layer_count, + const struct xrt_pose world_poses[XRT_MAX_VIEWS], + const struct xrt_pose eye_poses[XRT_MAX_VIEWS], + const struct xrt_fov fovs[XRT_MAX_VIEWS], + VkImage target_image, + VkImageView target_storage_view, + const struct render_viewport_data target_viewport_datas[XRT_MAX_VIEWS]) +{ + chl_frame_state_cs_set_views( // + frame_state, // + world_poses, // + eye_poses, // + fovs, // + layer_count); // + + chl_frame_state_cs_set_target( // + frame_state, // + target_image, // + target_storage_view, // + target_viewport_datas); // + + // Start the compute pipeline. + render_compute_begin(render); + + // Build the command buffer. + comp_render_cs_dispatch( // + render, // + layers, // + layer_count, // + &frame_state->data); // + + // Make the command buffer submittable. + render_compute_end(render); +} + +#ifdef __cplusplus +} +#endif