Blender V4.3
gpu_uniform_buffer.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2020 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "MEM_guardedalloc.h"
10#include <cstring>
11
12#include "BLI_blenlib.h"
13#include "BLI_math_base.h"
14
15#include "gpu_backend.hh"
16#include "gpu_node_graph.hh"
17
18#include "GPU_context.hh"
19#include "GPU_material.hh"
20
21#include "GPU_uniform_buffer.hh"
24
25/* -------------------------------------------------------------------- */
29namespace blender::gpu {
30
31UniformBuf::UniformBuf(size_t size, const char *name)
32{
33 /* Make sure that UBO is padded to size of vec4 */
34 BLI_assert((size % 16) == 0);
35
37
38 STRNCPY(name_, name);
39}
40
45
46} // namespace blender::gpu
47
50/* -------------------------------------------------------------------- */
59{
60 GPUInput *input = (GPUInput *)link->data;
61 eGPUType gputype = input->type;
62 /* Metal cannot pack floats after vec3. */
64 return (gputype == GPU_VEC3) ? GPU_VEC4 : gputype;
65 }
66 /* Unless the vec3 is followed by a float we need to treat it as a vec4. */
67 if (gputype == GPU_VEC3 && (link->next != nullptr) &&
68 (((GPUInput *)link->next->data)->type != GPU_FLOAT))
69 {
70 gputype = GPU_VEC4;
71 }
72 return gputype;
73}
74
79static int inputs_cmp(const void *a, const void *b)
80{
81 const LinkData *link_a = (const LinkData *)a, *link_b = (const LinkData *)b;
82 const GPUInput *input_a = (const GPUInput *)link_a->data;
83 const GPUInput *input_b = (const GPUInput *)link_b->data;
84 return input_a->type < input_b->type ? 1 : 0;
85}
86
92{
93/* Only support up to this type, if you want to extend it, make sure static void
94 * inputs_sobuffer_size_compute *inputs) padding logic is correct for the new types. */
95#define MAX_UBO_GPU_TYPE GPU_MAT4
96
97 /* Order them as mat4, vec4, vec3, vec2, float. */
99
100 /* Metal cannot pack floats after vec3. */
102 return;
103 }
104
105 /* Creates a lookup table for the different types. */
106 LinkData *inputs_lookup[MAX_UBO_GPU_TYPE + 1] = {nullptr};
107 eGPUType cur_type = static_cast<eGPUType>(MAX_UBO_GPU_TYPE + 1);
108
109 LISTBASE_FOREACH (LinkData *, link, inputs) {
110 GPUInput *input = (GPUInput *)link->data;
111
112 if (input->type == GPU_MAT3) {
113 /* Alignment for mat3 is not handled currently, so not supported */
114 BLI_assert_msg(0, "mat3 not supported in UBO");
115 continue;
116 }
117 if (input->type > MAX_UBO_GPU_TYPE) {
118 BLI_assert_msg(0, "GPU type not supported in UBO");
119 continue;
120 }
121
122 if (input->type == cur_type) {
123 continue;
124 }
125
126 inputs_lookup[input->type] = link;
127 cur_type = input->type;
128 }
129
130 /* If there is no GPU_VEC3 there is no need for alignment. */
131 if (inputs_lookup[GPU_VEC3] == nullptr) {
132 return;
133 }
134
135 LinkData *link = inputs_lookup[GPU_VEC3];
136 while (link != nullptr && ((GPUInput *)link->data)->type == GPU_VEC3) {
137 LinkData *link_next = link->next;
138
139 /* If GPU_VEC3 is followed by nothing or a GPU_FLOAT, no need for alignment. */
140 if ((link_next == nullptr) || ((GPUInput *)link_next->data)->type == GPU_FLOAT) {
141 break;
142 }
143
144 /* If there is a float, move it next to current vec3. */
145 if (inputs_lookup[GPU_FLOAT] != nullptr) {
146 LinkData *float_input = inputs_lookup[GPU_FLOAT];
147 inputs_lookup[GPU_FLOAT] = float_input->next;
148
149 BLI_remlink(inputs, float_input);
150 BLI_insertlinkafter(inputs, link, float_input);
151 }
152
153 link = link_next;
154 }
155#undef MAX_UBO_GPU_TYPE
156}
157
158static inline size_t buffer_size_from_list(ListBase *inputs)
159{
160 size_t buffer_size = 0;
161 LISTBASE_FOREACH (LinkData *, link, inputs) {
162 const eGPUType gputype = get_padded_gpu_type(link);
163 buffer_size += gputype * sizeof(float);
164 }
165 /* Round up to size of vec4. (Opengl Requirement) */
166 size_t alignment = sizeof(float[4]);
167 buffer_size = divide_ceil_u(buffer_size, alignment) * alignment;
168
169 return buffer_size;
170}
171
172static inline void buffer_fill_from_list(void *data, ListBase *inputs)
173{
174 /* Now that we know the total ubo size we can start populating it. */
175 float *offset = (float *)data;
176 LISTBASE_FOREACH (LinkData *, link, inputs) {
177 GPUInput *input = (GPUInput *)link->data;
178 memcpy(offset, input->vec, input->type * sizeof(float));
179 offset += get_padded_gpu_type(link);
180 }
181}
182
185/* -------------------------------------------------------------------- */
189using namespace blender::gpu;
190
191GPUUniformBuf *GPU_uniformbuf_create_ex(size_t size, const void *data, const char *name)
192{
193 UniformBuf *ubo = GPUBackend::get()->uniformbuf_alloc(size, name);
194 /* Direct init. */
195 if (data != nullptr) {
196 ubo->update(data);
197 }
198 return wrap(ubo);
199}
200
201GPUUniformBuf *GPU_uniformbuf_create_from_list(ListBase *inputs, const char *name)
202{
203 /* There is no point on creating an UBO if there is no arguments. */
204 if (BLI_listbase_is_empty(inputs)) {
205 return nullptr;
206 }
207
209 size_t buffer_size = buffer_size_from_list(inputs);
210 void *data = MEM_mallocN(buffer_size, __func__);
211 buffer_fill_from_list(data, inputs);
212
213 UniformBuf *ubo = GPUBackend::get()->uniformbuf_alloc(buffer_size, name);
214 /* Defer data upload. */
215 ubo->attach_data(data);
216 return wrap(ubo);
217}
218
219void GPU_uniformbuf_free(GPUUniformBuf *ubo)
220{
221 delete unwrap(ubo);
222}
223
224void GPU_uniformbuf_update(GPUUniformBuf *ubo, const void *data)
225{
226 unwrap(ubo)->update(data);
227}
228
229void GPU_uniformbuf_bind(GPUUniformBuf *ubo, int slot)
230{
231 unwrap(ubo)->bind(slot);
232}
233
234void GPU_uniformbuf_bind_as_ssbo(GPUUniformBuf *ubo, int slot)
235{
236 unwrap(ubo)->bind_as_ssbo(slot);
237}
238
239void GPU_uniformbuf_unbind(GPUUniformBuf *ubo)
240{
241 unwrap(ubo)->unbind();
242}
243
248
249void GPU_uniformbuf_clear_to_zero(GPUUniformBuf *ubo)
250{
251 unwrap(ubo)->clear_to_zero();
252}
253
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
#define LISTBASE_FOREACH(type, var, list)
void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1)
Definition listbase.cc:331
void void BLI_listbase_sort(struct ListBase *listbase, int(*cmp)(const void *, const void *)) ATTR_NONNULL(1
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:130
MINLINE uint divide_ceil_u(uint a, uint b)
#define STRNCPY(dst, src)
Definition BLI_string.h:593
eGPUBackendType GPU_backend_get_type()
eGPUType
@ GPU_VEC4
@ GPU_VEC3
@ GPU_MAT3
@ GPU_FLOAT
GPUUniformBuf * GPU_uniformbuf_create_ex(size_t size, const void *data, const char *name)
void GPU_uniformbuf_unbind(GPUUniformBuf *ubo)
void GPU_uniformbuf_update(GPUUniformBuf *ubo, const void *data)
void GPU_uniformbuf_free(GPUUniformBuf *ubo)
GPUUniformBuf * GPU_uniformbuf_create_from_list(ListBase *inputs, const char *name)
void GPU_uniformbuf_clear_to_zero(GPUUniformBuf *ubo)
void GPU_uniformbuf_debug_unbind_all()
void GPU_uniformbuf_bind_as_ssbo(GPUUniformBuf *ubo, int slot)
void GPU_uniformbuf_bind(GPUUniformBuf *ubo, int slot)
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
static Context * get()
virtual void debug_unbind_all_ubo()=0
static GPUBackend * get()
virtual UniformBuf * uniformbuf_alloc(size_t size, const char *name)=0
virtual void update(const void *data)=0
UniformBuf(size_t size, const char *name)
local_group_size(16, 16) .push_constant(Type b
draw_view in_light_buf[] float
static void buffer_from_list_inputs_sort(ListBase *inputs)
static void buffer_fill_from_list(void *data, ListBase *inputs)
static int inputs_cmp(const void *a, const void *b)
static size_t buffer_size_from_list(ListBase *inputs)
#define MAX_UBO_GPU_TYPE
static eGPUType get_padded_gpu_type(LinkData *link)
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
static Context * unwrap(GPUContext *ctx)
static GPUContext * wrap(Context *ctx)
eGPUType type
void * data
struct LinkData * next