Blender V4.3
vk_push_constants.hh
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
20#pragma once
21
22#include "BLI_utility_mixins.hh"
23#include "BLI_vector.hh"
24
26
27#include "vk_common.hh"
28#include "vk_descriptor_set.hh"
29
30namespace blender::gpu {
31class VKShaderInterface;
32class VKUniformBuffer;
33class VKContext;
34class VKDevice;
35
48class VKPushConstants : VKResourceTracker<VKUniformBuffer> {
49 friend class VKContext;
50
51 public:
53 enum class StorageType {
55 NONE,
56
59
64 };
65
69 struct Layout {
72
73 struct PushConstant {
74 /* Used as lookup based on ShaderInput. */
76
82 };
83
84 private:
85 Vector<PushConstant> push_constants;
86 uint32_t size_in_bytes_ = 0;
87 StorageType storage_type_ = StorageType::NONE;
91 VKDescriptorSet::Location descriptor_set_location_;
92
93 public:
105 const VKDevice &device);
106
117 void init(const shader::ShaderCreateInfo &info,
118 const VKShaderInterface &interface,
119 StorageType storage_type,
121
126 {
127 return storage_type_;
128 }
129
136 {
137 return descriptor_set_location_;
138 }
139
144 {
145 return size_in_bytes_;
146 }
147
152 const PushConstant *find(int32_t location) const;
153
154 void debug_print() const;
155 };
156
157 private:
158 const Layout *layout_ = nullptr;
159 void *data_ = nullptr;
160 bool is_dirty_ = false;
161
162 public:
164 VKPushConstants(const Layout *layout);
166 virtual ~VKPushConstants();
167
169
170 size_t offset() const
171 {
172 return 0;
173 }
174
175 const Layout &layout_get() const
176 {
177 return *layout_;
178 }
179
183 std::unique_ptr<VKUniformBuffer> create_resource(VKContext &context) override;
184
192 const void *data() const
193 {
194 return data_;
195 }
196
205 template<typename T>
207 int32_t comp_len,
208 int32_t array_size,
209 const T *input_data)
210 {
211 const Layout::PushConstant *push_constant_layout = layout_->find(location);
212 if (push_constant_layout == nullptr) {
213 /* Legacy code can still try to update push constants when they don't exist. For example
214 * `immDrawPixelsTexSetup` will bind an image slot manually. This works in OpenGL, but in
215 * vulkan images aren't stored as push constants. */
216 return;
217 }
218
219 uint8_t *bytes = static_cast<uint8_t *>(data_);
220 T *dst = static_cast<T *>(static_cast<void *>(&bytes[push_constant_layout->offset]));
221 const int inner_row_padding = push_constant_layout->inner_row_padding;
222 const bool is_tightly_std140_packed = (comp_len % 4) == 0;
223 if (inner_row_padding == 0 &&
224 (layout_->storage_type_get() == StorageType::PUSH_CONSTANTS || array_size == 0 ||
225 push_constant_layout->array_size == 0 || is_tightly_std140_packed))
226 {
227 const size_t copy_size_in_bytes = comp_len * max_ii(array_size, 1) * sizeof(T);
228 BLI_assert_msg(push_constant_layout->offset + copy_size_in_bytes <= layout_->size_in_bytes(),
229 "Tried to write outside the push constant allocated memory.");
230 memcpy(dst, input_data, copy_size_in_bytes);
231 is_dirty_ = true;
232 return;
233 }
234
235 /* Store elements in uniform buffer as array. In Std140 arrays have an element stride of 16
236 * bytes. */
237 BLI_assert(sizeof(T) == 4);
238 const T *src = input_data;
239 if (inner_row_padding == 0) {
240 for (const int i : IndexRange(array_size)) {
241 UNUSED_VARS(i);
242 memcpy(dst, src, comp_len * sizeof(T));
243 src += comp_len;
244 dst += 4;
245 }
246 }
247 else {
248 BLI_assert_msg(array_size == 1, "No support for MAT3 arrays, but can be added when needed");
249 for (const int component_index : IndexRange(comp_len)) {
250 *dst = *src;
251 dst += 1;
252 src += 1;
253 if ((component_index % inner_row_padding) == (inner_row_padding - 1)) {
254 dst += 1;
255 }
256 }
257 }
258
259 is_dirty_ = true;
260 }
261
269
275 std::unique_ptr<VKUniformBuffer> &uniform_buffer_get();
276};
277
278} // namespace blender::gpu
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
MINLINE int max_ii(int a, int b)
unsigned int uint
#define UNUSED_VARS(...)
void init()
VKPushConstants & operator=(VKPushConstants &&other)
std::unique_ptr< VKUniformBuffer > create_resource(VKContext &context) override
const Layout & layout_get() const
std::unique_ptr< VKUniformBuffer > & uniform_buffer_get()
void push_constant_set(int32_t location, int32_t comp_len, int32_t array_size, const T *input_data)
#define T
unsigned int uint32_t
Definition stdint.h:80
signed int int32_t
Definition stdint.h:77
unsigned char uint8_t
Definition stdint.h:78
static constexpr StorageType STORAGE_TYPE_DEFAULT
static constexpr StorageType STORAGE_TYPE_FALLBACK
static StorageType determine_storage_type(const shader::ShaderCreateInfo &info, const VKDevice &device)
VKDescriptorSet::Location descriptor_set_location_get() const
const PushConstant * find(int32_t location) const
Describe inputs & outputs, stage interfaces, resources and sources of a shader. If all data is correc...