Blender  V2.93
gpu_uniform_buffer.cc
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2020 Blender Foundation.
17  * All rights reserved.
18  */
19 
24 #include "MEM_guardedalloc.h"
25 #include <cstring>
26 
27 #include "BLI_blenlib.h"
28 #include "BLI_math_base.h"
29 
30 #include "gpu_backend.hh"
31 #include "gpu_node_graph.h"
32 
33 #include "GPU_material.h"
34 
35 #include "GPU_uniform_buffer.h"
37 
38 /* -------------------------------------------------------------------- */
42 namespace blender::gpu {
43 
44 UniformBuf::UniformBuf(size_t size, const char *name)
45 {
46  /* Make sure that UBO is padded to size of vec4 */
47  BLI_assert((size % 16) == 0);
48 
50 
51  BLI_strncpy(name_, name, sizeof(name_));
52 }
53 
55 {
57 }
58 
59 } // namespace blender::gpu
60 
63 /* -------------------------------------------------------------------- */
72 {
73  GPUInput *input = (GPUInput *)link->data;
74  eGPUType gputype = input->type;
75  /* Unless the vec3 is followed by a float we need to treat it as a vec4. */
76  if (gputype == GPU_VEC3 && (link->next != nullptr) &&
77  (((GPUInput *)link->next->data)->type != GPU_FLOAT)) {
78  gputype = GPU_VEC4;
79  }
80  return gputype;
81 }
82 
87 static int inputs_cmp(const void *a, const void *b)
88 {
89  const LinkData *link_a = (const LinkData *)a, *link_b = (const LinkData *)b;
90  const GPUInput *input_a = (const GPUInput *)link_a->data;
91  const GPUInput *input_b = (const GPUInput *)link_b->data;
92  return input_a->type < input_b->type ? 1 : 0;
93 }
94 
100 {
101 /* Only support up to this type, if you want to extend it, make sure static void
102  * inputs_sobuffer_size_compute *inputs) padding logic is correct for the new types. */
103 #define MAX_UBO_GPU_TYPE GPU_MAT4
104 
105  /* Order them as mat4, vec4, vec3, vec2, float. */
107 
108  /* Creates a lookup table for the different types; */
109  LinkData *inputs_lookup[MAX_UBO_GPU_TYPE + 1] = {nullptr};
110  eGPUType cur_type = static_cast<eGPUType>(MAX_UBO_GPU_TYPE + 1);
111 
112  LISTBASE_FOREACH (LinkData *, link, inputs) {
113  GPUInput *input = (GPUInput *)link->data;
114 
115  if (input->type == GPU_MAT3) {
116  /* Alignment for mat3 is not handled currently, so not supported */
117  BLI_assert(!"mat3 not supported in UBO");
118  continue;
119  }
120  if (input->type > MAX_UBO_GPU_TYPE) {
121  BLI_assert(!"GPU type not supported in UBO");
122  continue;
123  }
124 
125  if (input->type == cur_type) {
126  continue;
127  }
128 
129  inputs_lookup[input->type] = link;
130  cur_type = input->type;
131  }
132 
133  /* If there is no GPU_VEC3 there is no need for alignment. */
134  if (inputs_lookup[GPU_VEC3] == nullptr) {
135  return;
136  }
137 
138  LinkData *link = inputs_lookup[GPU_VEC3];
139  while (link != nullptr && ((GPUInput *)link->data)->type == GPU_VEC3) {
140  LinkData *link_next = link->next;
141 
142  /* If GPU_VEC3 is followed by nothing or a GPU_FLOAT, no need for alignment. */
143  if ((link_next == nullptr) || ((GPUInput *)link_next->data)->type == GPU_FLOAT) {
144  break;
145  }
146 
147  /* If there is a float, move it next to current vec3. */
148  if (inputs_lookup[GPU_FLOAT] != nullptr) {
149  LinkData *float_input = inputs_lookup[GPU_FLOAT];
150  inputs_lookup[GPU_FLOAT] = float_input->next;
151 
152  BLI_remlink(inputs, float_input);
153  BLI_insertlinkafter(inputs, link, float_input);
154  }
155 
156  link = link_next;
157  }
158 #undef MAX_UBO_GPU_TYPE
159 }
160 
161 static inline size_t buffer_size_from_list(ListBase *inputs)
162 {
163  size_t buffer_size = 0;
164  LISTBASE_FOREACH (LinkData *, link, inputs) {
165  const eGPUType gputype = get_padded_gpu_type(link);
166  buffer_size += gputype * sizeof(float);
167  }
168  /* Round up to size of vec4. (Opengl Requirement) */
169  size_t alignment = sizeof(float[4]);
170  buffer_size = divide_ceil_u(buffer_size, alignment) * alignment;
171 
172  return buffer_size;
173 }
174 
175 static inline void buffer_fill_from_list(void *data, ListBase *inputs)
176 {
177  /* Now that we know the total ubo size we can start populating it. */
178  float *offset = (float *)data;
179  LISTBASE_FOREACH (LinkData *, link, inputs) {
180  GPUInput *input = (GPUInput *)link->data;
181  memcpy(offset, input->vec, input->type * sizeof(float));
182  offset += get_padded_gpu_type(link);
183  }
184 }
185 
188 /* -------------------------------------------------------------------- */
192 using namespace blender::gpu;
193 
194 GPUUniformBuf *GPU_uniformbuf_create_ex(size_t size, const void *data, const char *name)
195 {
197  /* Direct init. */
198  if (data != nullptr) {
199  ubo->update(data);
200  }
201  return wrap(ubo);
202 }
203 
211 {
212  /* There is no point on creating an UBO if there is no arguments. */
214  return nullptr;
215  }
216 
218  size_t buffer_size = buffer_size_from_list(inputs);
219  void *data = MEM_mallocN(buffer_size, __func__);
221 
222  UniformBuf *ubo = GPUBackend::get()->uniformbuf_alloc(buffer_size, name);
223  /* Defer data upload. */
224  ubo->attach_data(data);
225  return wrap(ubo);
226 }
227 
229 {
230  delete unwrap(ubo);
231 }
232 
233 void GPU_uniformbuf_update(GPUUniformBuf *ubo, const void *data)
234 {
235  unwrap(ubo)->update(data);
236 }
237 
238 void GPU_uniformbuf_bind(GPUUniformBuf *ubo, int slot)
239 {
240  unwrap(ubo)->bind(slot);
241 }
242 
244 {
245  unwrap(ubo)->unbind();
246 }
247 
249 {
250  /* FIXME */
251 }
252 
typedef float(TangentPoint)[2]
#define BLI_assert(a)
Definition: BLI_assert.h:58
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:124
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1)
Definition: listbase.c:352
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.c:133
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy) ATTR_NONNULL()
Definition: string.c:108
eGPUType
Definition: GPU_material.h:59
@ GPU_VEC4
Definition: GPU_material.h:66
@ GPU_VEC3
Definition: GPU_material.h:65
@ GPU_MAT3
Definition: GPU_material.h:67
@ GPU_FLOAT
Definition: GPU_material.h:63
struct GPUUniformBuf GPUUniformBuf
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
virtual UniformBuf * uniformbuf_alloc(int size, const char *name)=0
static GPUBackend * get(void)
Definition: gpu_context.cc:191
virtual void update(const void *data)=0
UniformBuf(size_t size, const char *name)
static void buffer_from_list_inputs_sort(ListBase *inputs)
static void buffer_fill_from_list(void *data, ListBase *inputs)
void GPU_uniformbuf_unbind_all(void)
static int inputs_cmp(const void *a, const void *b)
void GPU_uniformbuf_unbind(GPUUniformBuf *ubo)
GPUUniformBuf * GPU_uniformbuf_create_from_list(ListBase *inputs, const char *name)
GPUUniformBuf * GPU_uniformbuf_create_ex(size_t size, const void *data, const char *name)
void GPU_uniformbuf_update(GPUUniformBuf *ubo, const void *data)
void GPU_uniformbuf_free(GPUUniformBuf *ubo)
static size_t buffer_size_from_list(ListBase *inputs)
#define MAX_UBO_GPU_TYPE
void GPU_uniformbuf_bind(GPUUniformBuf *ubo, int slot)
static eGPUType get_padded_gpu_type(LinkData *link)
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
MINLINE uint divide_ceil_u(uint a, uint b)
static unsigned a[3]
Definition: RandGen.cpp:92
static GPUContext * wrap(Context *ctx)
static Context * unwrap(GPUContext *ctx)
static bNodeSocketTemplate inputs[]
float vec[16]
eGPUType type
void * data
Definition: DNA_listBase.h:42
struct LinkData * next
Definition: DNA_listBase.h:41