c/util: Add high level scratch helper

Part-of: <https://gitlab.freedesktop.org/monado/monado/-/merge_requests/2493>
This commit is contained in:
Jakob Bornecrantz committed 2025-07-07 20:03:00 +01:00
1 parent ea9fff0517
commit fe2d906e8b
3 files changed
+346

No files matched your search

+2
View File
@@ -146,6 +146,8 @@ if(XRT_HAVE_VULKAN)
comp_util STATIC
util/comp_base.h
util/comp_base.c
util/comp_high_level_scratch.c
util/comp_high_level_scratch.h
util/comp_layer_accum.h
util/comp_layer_accum.c
util/comp_render.h
@@ -0,0 +1,144 @@
// Copyright 2019-2024, Collabora, Ltd.
// Copyright 2024-2025, NVIDIA CORPORATION.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Higher level interface for scratch images.
* @author Jakob Bornecrantz <tbornecrantz@nvidia.com>
* @author Andrei Aristarkhov <aaristarkhov@nvidia.com>
* @author Gareth Morgan <gmorgan@nvidia.com>
* @author Rylie Pavlik <rylie.pavlik@collabora.com>
* @ingroup comp_main
*/
#include "comp_high_level_scratch.h"
void
chl_scratch_init(struct chl_scratch *scratch)
{
for (uint32_t i = 0; i < ARRAY_SIZE(scratch->views); i++) {
comp_scratch_single_images_init(&scratch->views[i].cssi);
}
}
void
chl_scratch_fini(struct chl_scratch *scratch)
{
for (uint32_t i = 0; i < ARRAY_SIZE(scratch->views); i++) {
comp_scratch_single_images_destroy(&scratch->views[i].cssi);
}
}
bool
chl_scratch_ensure(struct chl_scratch *scratch,
struct render_resources *rr,
uint32_t view_count,
VkExtent2D extent,
const VkFormat format)
{
struct vk_bundle *vk = rr->vk;
bool bret = false;
// Is everything already correct?
if (scratch->view_count == view_count && //
scratch->extent.width == extent.width && //
scratch->extent.height == extent.height && //
scratch->format == format) {
return true;
}
// Free all old resources.
chl_scratch_free_resources(scratch, rr);
// Shared render pass between all scratch images.
bret = render_gfx_render_pass_init( //
&scratch->render_pass, // rgrp
rr, // struct render_resources
format, // format
VK_ATTACHMENT_LOAD_OP_CLEAR, // load_op
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); // final_layout
if (!bret) {
VK_ERROR(vk, "render_gfx_render_pass_init: false");
return false;
}
// Need to track if the render pass has been initialized.
scratch->render_pass_initialized = true;
for (uint32_t i = 0; i < view_count; i++) {
// Helper.
struct comp_scratch_single_images *cssi = &scratch->views[i].cssi;
if (format == VK_FORMAT_R8G8B8A8_SRGB) {
// Special creation function for the mutable format.
bret = comp_scratch_single_images_ensure_mutable(cssi, vk, extent);
} else {
bret = comp_scratch_single_images_ensure(cssi, vk, extent, format);
}
if (!bret) {
VK_ERROR(vk, "comp_scratch_single_images_ensure[_mutable]: false");
// Free any that has already been allocated.
chl_scratch_free_resources(scratch, rr);
return false;
}
for (uint32_t k = 0; k < COMP_SCRATCH_NUM_IMAGES; k++) {
/*
* For graphics parts we use the same image view as the
* source. In other words the sRGB image view for the
* non-linear formats.
*/
VkImageView target_image_view = chl_scratch_get_sample_view(scratch, i, k);
render_gfx_target_resources_init( //
&scratch->views[i].targets[k], // rtr
rr, // struct render_resources
&scratch->render_pass, // struct render_gfx_render_pass
target_image_view, // target
extent); // extent
}
/*
* Update the count, doing it this way means free_resources
* will free the allocated images correctly. The count is one
* more then the index.
*/
scratch->view_count = i + 1;
}
// Update the cached values.
scratch->extent = extent;
scratch->format = format;
return true;
}
void
chl_scratch_free_resources(struct chl_scratch *scratch, struct render_resources *rr)
{
struct vk_bundle *vk = rr->vk;
for (uint32_t i = 0; i < scratch->view_count; i++) {
for (uint32_t k = 0; k < COMP_SCRATCH_NUM_IMAGES; k++) {
render_gfx_target_resources_fini(&scratch->views[i].targets[k]);
}
comp_scratch_single_images_free(&scratch->views[i].cssi, vk);
}
// Nothing allocated.
scratch->view_count = 0;
scratch->extent.width = 0;
scratch->extent.height = 0;
scratch->format = VK_FORMAT_UNDEFINED;
// Do this after the image targets as they reference the render pass.
if (scratch->render_pass_initialized) {
render_gfx_render_pass_fini(&scratch->render_pass);
scratch->render_pass_initialized = false;
}
}
@@ -0,0 +1,200 @@
// Copyright 2019-2024, Collabora, Ltd.
// Copyright 2024-2025, NVIDIA CORPORATION.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Higher level interface for scratch images.
* @author Jakob Bornecrantz <tbornecrantz@nvidia.com>
* @ingroup comp_util
*/
#pragma once
#include "render/render_interface.h"
#include "comp_scratch.h"
#ifdef __cplusplus
extern "C" {
#endif
/*!
* Scratch images that can be used for staging buffers.
*
* @ingroup comp_util
*/
struct chl_scratch
{
//! Shared render passed for the views.
struct render_gfx_render_pass render_pass;
struct
{
//! Per-view scratch images.
struct comp_scratch_single_images cssi;
//! Targets for rendering to the scratch buffer.
struct render_gfx_target_resources targets[COMP_SCRATCH_NUM_IMAGES];
} views[XRT_MAX_VIEWS];
/*!
* Number of views that has been ensured and have Vulkan resources,
* all comp_scratch_single_images are always inited.
*/
uint32_t view_count;
//! The extent used to create the images.
VkExtent2D extent;
//! Format requested.
VkFormat format;
//! Has the render pass been initialized.
bool render_pass_initialized;
};
/*!
* Must becalled before used and before the scratch images are registered with
* the u_var system.
*
* @memberof chl_scratch
*/
void
chl_scratch_init(struct chl_scratch *scratch);
/*!
* Resources must be manually called before calling this functions, and the
* scratch images unregistered from the u_var system.
*
* @memberof chl_scratch
*/
void
chl_scratch_fini(struct chl_scratch *scratch);
/*!
* Ensure the scratch images and the render target resources are created.
*
* @memberof chl_scratch
*/
bool
chl_scratch_ensure(struct chl_scratch *scratch,
struct render_resources *rr,
uint32_t view_count,
VkExtent2D extent,
const VkFormat format);
/*!
* Free all Vulkan resources that this scratch has created.
*
* @memberof chl_scratch
*/
void
chl_scratch_free_resources(struct chl_scratch *scratch, struct render_resources *rr);
/*!
* Get the image, see @ref comp_scratch_single_images_get_image.
*
* @memberof chl_scratch
*/
static inline VkImage
chl_scratch_get_image(struct chl_scratch *scratch, uint32_t view_index, uint32_t image_index)
{
return comp_scratch_single_images_get_image(&scratch->views[view_index].cssi, image_index);
}
/*!
* Get the sample view, see @ref comp_scratch_single_images_get_sample_view.
*
* @memberof chl_scratch
*/
static inline VkImageView
chl_scratch_get_sample_view(struct chl_scratch *scratch, uint32_t view_index, uint32_t image_index)
{
return comp_scratch_single_images_get_sample_view(&scratch->views[view_index].cssi, image_index);
}
/*!
* Get the storage view, see @ref comp_scratch_single_images_get_storage_view.
*
* @memberof chl_scratch
*/
static inline VkImageView
chl_scratch_get_storage_view(struct chl_scratch *scratch, uint32_t view_index, uint32_t image_index)
{
return comp_scratch_single_images_get_storage_view(&scratch->views[view_index].cssi, image_index);
}
/*
*
* State
*
*/
/*!
* Per view frame state tracking which index was gotten and if it was used.
*
* @ingroup comp_util
*/
struct chl_scratch_state_view
{
uint32_t index;
bool used;
};
/*!
* Used to track the index of images gotten for the images, and if it has been
* used. The user will need to mark images as used.
*
* @ingroup comp_util
*/
struct chl_scratch_state
{
struct chl_scratch_state_view views[XRT_MAX_VIEWS];
};
/*!
* Zeros out the struct and calls get on all the images, setting the @p index
* field on the state for each view.
*
* @memberof chl_scratch_state
*/
static inline void
chl_scratch_state_init_and_get(struct chl_scratch_state *scratch_state, struct chl_scratch *scratch)
{
U_ZERO(scratch_state);
// Loop over all the of the images in the scratch view.
for (uint32_t i = 0; i < scratch->view_count; i++) {
comp_scratch_single_images_get(&scratch->views[i].cssi, &scratch_state->views[i].index);
}
}
/*!
* Calls discard or done on all the scratch images, it calls done if the @p used
* field is set to true.
*
* @memberof chl_scratch_state
*/
static inline void
chl_scratch_state_discard_or_done(struct chl_scratch_state *scratch_state, struct chl_scratch *scratch)
{
// Loop over all the of the images in the scratch view.
for (uint32_t i = 0; i < scratch->view_count; i++) {
if (scratch_state->views[i].used) {
comp_scratch_single_images_done(&scratch->views[i].cssi);
} else {
comp_scratch_single_images_discard(&scratch->views[i].cssi);
}
}
U_ZERO(scratch_state);
}
#ifdef __cplusplus
}
#endif