The open source OpenXR runtime
1// Copyright 2019-2024, Collabora, Ltd.
2// Copyright 2024-2025, NVIDIA CORPORATION.
3// SPDX-License-Identifier: BSL-1.0
4/*!
5 * @file
6 * @brief Higher level interface for scratch images.
7 * @author Jakob Bornecrantz <tbornecrantz@nvidia.com>
8 * @author Andrei Aristarkhov <aaristarkhov@nvidia.com>
9 * @author Gareth Morgan <gmorgan@nvidia.com>
10 * @author Rylie Pavlik <rylie.pavlik@collabora.com>
11 * @ingroup comp_main
12 */
13
14
15#include "comp_high_level_scratch.h"
16
17
18void
19chl_scratch_init(struct chl_scratch *scratch)
20{
21 for (uint32_t i = 0; i < ARRAY_SIZE(scratch->views); i++) {
22 comp_scratch_single_images_init(&scratch->views[i].cssi);
23 }
24}
25
26void
27chl_scratch_fini(struct chl_scratch *scratch)
28{
29 for (uint32_t i = 0; i < ARRAY_SIZE(scratch->views); i++) {
30 comp_scratch_single_images_destroy(&scratch->views[i].cssi);
31 }
32}
33
34bool
35chl_scratch_ensure(struct chl_scratch *scratch,
36 struct render_resources *rr,
37 uint32_t view_count,
38 VkExtent2D extent,
39 const VkFormat format)
40{
41 struct vk_bundle *vk = rr->vk;
42 bool bret = false;
43
44 // Is everything already correct?
45 if (scratch->view_count == view_count && //
46 scratch->extent.width == extent.width && //
47 scratch->extent.height == extent.height && //
48 scratch->format == format) {
49 return true;
50 }
51
52 // Free all old resources.
53 chl_scratch_free_resources(scratch, rr);
54
55 // Shared render pass between all scratch images.
56 bret = render_gfx_render_pass_init( //
57 &scratch->render_pass, // rgrp
58 rr, // struct render_resources
59 format, // format
60 VK_ATTACHMENT_LOAD_OP_CLEAR, // load_op
61 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); // final_layout
62 if (!bret) {
63 VK_ERROR(vk, "render_gfx_render_pass_init: false");
64 return false;
65 }
66
67 // Need to track if the render pass has been initialized.
68 scratch->render_pass_initialized = true;
69
70 for (uint32_t i = 0; i < view_count; i++) {
71 // Helper.
72 struct comp_scratch_single_images *cssi = &scratch->views[i].cssi;
73
74 if (format == VK_FORMAT_R8G8B8A8_SRGB) {
75 // Special creation function for the mutable format.
76 bret = comp_scratch_single_images_ensure_mutable(cssi, vk, extent);
77 } else {
78 bret = comp_scratch_single_images_ensure(cssi, vk, extent, format);
79 }
80
81 if (!bret) {
82 VK_ERROR(vk, "comp_scratch_single_images_ensure[_mutable]: false");
83 // Free any that has already been allocated.
84 chl_scratch_free_resources(scratch, rr);
85 return false;
86 }
87
88 for (uint32_t k = 0; k < COMP_SCRATCH_NUM_IMAGES; k++) {
89
90 /*
91 * For graphics parts we use the same image view as the
92 * source. In other words the sRGB image view for the
93 * non-linear formats.
94 */
95 VkImageView target_image_view = chl_scratch_get_sample_view(scratch, i, k);
96
97 render_gfx_target_resources_init( //
98 &scratch->views[i].targets[k], // rtr
99 rr, // struct render_resources
100 &scratch->render_pass, // struct render_gfx_render_pass
101 target_image_view, // target
102 extent); // extent
103 }
104
105 /*
106 * Update the count, doing it this way means free_resources
107 * will free the allocated images correctly. The count is one
108 * more then the index.
109 */
110 scratch->view_count = i + 1;
111 }
112
113 // Update the cached values.
114 scratch->extent = extent;
115 scratch->format = format;
116
117 return true;
118}
119
120void
121chl_scratch_free_resources(struct chl_scratch *scratch, struct render_resources *rr)
122{
123 struct vk_bundle *vk = rr->vk;
124
125 for (uint32_t i = 0; i < scratch->view_count; i++) {
126 for (uint32_t k = 0; k < COMP_SCRATCH_NUM_IMAGES; k++) {
127 render_gfx_target_resources_fini(&scratch->views[i].targets[k]);
128 }
129
130 comp_scratch_single_images_free(&scratch->views[i].cssi, vk);
131 }
132
133 // Nothing allocated.
134 scratch->view_count = 0;
135 scratch->extent.width = 0;
136 scratch->extent.height = 0;
137 scratch->format = VK_FORMAT_UNDEFINED;
138
139 // Do this after the image targets as they reference the render pass.
140 if (scratch->render_pass_initialized) {
141 render_gfx_render_pass_fini(&scratch->render_pass);
142 scratch->render_pass_initialized = false;
143 }
144}