// Copyright 2019-2024, Collabora, Ltd. // Copyright 2024-2025, NVIDIA CORPORATION. // SPDX-License-Identifier: BSL-1.0 /*! * @file * @brief Helper implementation for native compositors. * @author Jakob Bornecrantz * @author Lubosz Sarnecki * @ingroup comp_util */ #pragma once #include "util/u_native_images_debug.h" #include "vk/vk_helpers.h" #include "render/render_interface.h" #ifdef __cplusplus extern "C" { #endif /* * * Defines. * */ //! The number of images for each view, works like a swapchain. #define COMP_SCRATCH_NUM_IMAGES (4) /* * * Common for handling indices. * */ /*! * Small helper struct to deal with indices. * * @ingroup comp_util */ struct comp_scratch_indices { uint32_t current; uint32_t last; }; /* * * Single view images. * */ /*! * Holds scratch images for a single view, designed to work with render code. * Also manages @ref xrt_image_native and @ref u_native_images_debug to * facilitate easy debugging. * * @ingroup comp_util */ struct comp_scratch_single_images { //! Images used when rendering. struct render_scratch_color_image images[COMP_SCRATCH_NUM_IMAGES]; //! To connect to the debug UI. struct u_native_images_debug unid; //! Exposed via @ref unid. struct xrt_swapchain_create_info info; //! Exposed via @ref unid. struct xrt_image_native native_images[COMP_SCRATCH_NUM_IMAGES]; //! Keeping track of indices. struct comp_scratch_indices indices; //! Process unique id, used for caching. xrt_limited_unique_id_t limited_unique_id; }; /*! * Init the struct, this function must be called before calling any other * function on this struct, or variable tracking setup on @p unid. Zero init is * not enough as it has a mutex in it and has native handles which on some * platforms zero is a valid handle. * * @public @memberof comp_scratch_single_images * * @ingroup comp_util */ void comp_scratch_single_images_init(struct comp_scratch_single_images *cssi); /*! * Ensure that the scratch images are allocated and match @p extent size, and * @p format. * * @public @memberof comp_scratch_single_images * * @ingroup comp_util */ bool comp_scratch_single_images_ensure(struct comp_scratch_single_images *cssi, struct vk_bundle *vk, VkExtent2D extent, const VkFormat format); /*! * Ensure that the scratch images are allocated and match @p extent size, * the formats it will get is 8bit SRGB formats. * * @public @memberof comp_scratch_single_images * * @ingroup comp_util */ bool comp_scratch_single_images_ensure_mutable(struct comp_scratch_single_images *cssi, struct vk_bundle *vk, VkExtent2D extent); /*! * Free all images allocated, @p init must be called before calling this * function, is safe to call without any image allocated. * * @public @memberof comp_scratch_single_images * * @ingroup comp_util */ void comp_scratch_single_images_free(struct comp_scratch_single_images *cssi, struct vk_bundle *vk); /*! * Get the next free image, after this function has been called you must call * either @p done or @p discard before calling any other function. * * @public @memberof comp_scratch_single_images * * @ingroup comp_util */ void comp_scratch_single_images_get(struct comp_scratch_single_images *cssi, uint32_t *out_index); /*! * Get the image for the given index. * * @public @memberof comp_scratch_single_images * * @ingroup comp_util */ static inline VkImage comp_scratch_single_images_get_image(struct comp_scratch_single_images *cssi, uint32_t index) { return cssi->images[index].image; } /*! * Get the image view for sampling, it will apply any automatic linearization, * aka sRGB gamma curve correction. * * @public @memberof comp_scratch_single_images * * @ingroup comp_util */ static inline VkImageView comp_scratch_single_images_get_sample_view(struct comp_scratch_single_images *cssi, uint32_t index) { struct render_scratch_color_image *rsci = &cssi->images[index]; VkImageView view = rsci->srgb_view; if (view != VK_NULL_HANDLE) { return view; } // Fallback to unorm view. return rsci->unorm_view; } /*! * Get the image view for storage or direct value, no linearization will be * done. * * @public @memberof comp_scratch_single_images * * @ingroup comp_util */ static inline VkImageView comp_scratch_single_images_get_storage_view(struct comp_scratch_single_images *cssi, uint32_t index) { struct render_scratch_color_image *rsci = &cssi->images[index]; // Always the storage view. return rsci->unorm_view; } /*! * After calling @p get and rendering to the image you call this function to * signal that you are done with this function, the GPU work needs to be fully * completed before calling done. * * @public @memberof comp_scratch_single_images * * @ingroup comp_util */ void comp_scratch_single_images_done(struct comp_scratch_single_images *cssi); /*! * Discard a @p get call, this clears the image debug part causing no image to * be shown in the debug UI. * * @public @memberof comp_scratch_single_images * * @ingroup comp_util */ void comp_scratch_single_images_discard(struct comp_scratch_single_images *cssi); /*! * Clears the debug output, this causes nothing to be shown in the debug UI. * * @public @memberof comp_scratch_single_images * * @ingroup comp_util */ void comp_scratch_single_images_clear_debug(struct comp_scratch_single_images *cssi); /*! * Destroys scratch image struct, if any images has been allocated must call * @p free before as this function only destroys the mutex, and the @p unid must * no longer be tracked. * * @public @memberof comp_scratch_single_images * * @ingroup comp_util */ void comp_scratch_single_images_destroy(struct comp_scratch_single_images *cssi); /* * * Stereo. * */ /*! * Holds scartch images for a stereo views, designed to work with render code. * Also manages @ref xrt_image_native and @ref u_native_images_debug to * facilitate easy debugging. * * @ingroup comp_util */ struct comp_scratch_stereo_images { struct render_scratch_images rsis[COMP_SCRATCH_NUM_IMAGES]; struct xrt_swapchain_create_info info; //! Keeping track of indices. struct comp_scratch_indices indices; struct { //! Debug output for each view. struct u_native_images_debug unid; //! Count always equals to the number of rsis. struct xrt_image_native native_images[COMP_SCRATCH_NUM_IMAGES]; } views[2]; //! Process unique id, used for caching. xrt_limited_unique_id_t limited_unique_id; }; void comp_scratch_stereo_images_init(struct comp_scratch_stereo_images *cssi); bool comp_scratch_stereo_images_ensure(struct comp_scratch_stereo_images *cssi, struct vk_bundle *vk, VkExtent2D extent); void comp_scratch_stereo_images_free(struct comp_scratch_stereo_images *cssi, struct vk_bundle *vk); void comp_scratch_stereo_images_get(struct comp_scratch_stereo_images *cssi, uint32_t *out_index); void comp_scratch_stereo_images_done(struct comp_scratch_stereo_images *cssi); void comp_scratch_stereo_images_discard(struct comp_scratch_stereo_images *cssi); void comp_scratch_stereo_images_clear_debug(struct comp_scratch_stereo_images *cssi); void comp_scratch_stereo_images_destroy(struct comp_scratch_stereo_images *cssi); #ifdef __cplusplus } #endif