Blender  V3.3
gpu_uniform_buffer.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2020 Blender Foundation. All rights reserved. */
3 
8 #include "MEM_guardedalloc.h"
9 #include <cstring>
10 
11 #include "BLI_blenlib.h"
12 #include "BLI_math_base.h"
13 
14 #include "gpu_backend.hh"
15 #include "gpu_node_graph.h"
16 
17 #include "GPU_material.h"
18 
19 #include "GPU_uniform_buffer.h"
21 
22 /* -------------------------------------------------------------------- */
26 namespace blender::gpu {
27 
28 UniformBuf::UniformBuf(size_t size, const char *name)
29 {
30  /* Make sure that UBO is padded to size of vec4 */
31  BLI_assert((size % 16) == 0);
32 
34 
35  BLI_strncpy(name_, name, sizeof(name_));
36 }
37 
39 {
41 }
42 
43 } // namespace blender::gpu
44 
47 /* -------------------------------------------------------------------- */
56 {
57  GPUInput *input = (GPUInput *)link->data;
58  eGPUType gputype = input->type;
59  /* Unless the vec3 is followed by a float we need to treat it as a vec4. */
60  if (gputype == GPU_VEC3 && (link->next != nullptr) &&
61  (((GPUInput *)link->next->data)->type != GPU_FLOAT)) {
62  gputype = GPU_VEC4;
63  }
64  return gputype;
65 }
66 
71 static int inputs_cmp(const void *a, const void *b)
72 {
73  const LinkData *link_a = (const LinkData *)a, *link_b = (const LinkData *)b;
74  const GPUInput *input_a = (const GPUInput *)link_a->data;
75  const GPUInput *input_b = (const GPUInput *)link_b->data;
76  return input_a->type < input_b->type ? 1 : 0;
77 }
78 
84 {
85 /* Only support up to this type, if you want to extend it, make sure static void
86  * inputs_sobuffer_size_compute *inputs) padding logic is correct for the new types. */
87 #define MAX_UBO_GPU_TYPE GPU_MAT4
88 
89  /* Order them as mat4, vec4, vec3, vec2, float. */
91 
92  /* Creates a lookup table for the different types; */
93  LinkData *inputs_lookup[MAX_UBO_GPU_TYPE + 1] = {nullptr};
94  eGPUType cur_type = static_cast<eGPUType>(MAX_UBO_GPU_TYPE + 1);
95 
96  LISTBASE_FOREACH (LinkData *, link, inputs) {
97  GPUInput *input = (GPUInput *)link->data;
98 
99  if (input->type == GPU_MAT3) {
100  /* Alignment for mat3 is not handled currently, so not supported */
101  BLI_assert_msg(0, "mat3 not supported in UBO");
102  continue;
103  }
104  if (input->type > MAX_UBO_GPU_TYPE) {
105  BLI_assert_msg(0, "GPU type not supported in UBO");
106  continue;
107  }
108 
109  if (input->type == cur_type) {
110  continue;
111  }
112 
113  inputs_lookup[input->type] = link;
114  cur_type = input->type;
115  }
116 
117  /* If there is no GPU_VEC3 there is no need for alignment. */
118  if (inputs_lookup[GPU_VEC3] == nullptr) {
119  return;
120  }
121 
122  LinkData *link = inputs_lookup[GPU_VEC3];
123  while (link != nullptr && ((GPUInput *)link->data)->type == GPU_VEC3) {
124  LinkData *link_next = link->next;
125 
126  /* If GPU_VEC3 is followed by nothing or a GPU_FLOAT, no need for alignment. */
127  if ((link_next == nullptr) || ((GPUInput *)link_next->data)->type == GPU_FLOAT) {
128  break;
129  }
130 
131  /* If there is a float, move it next to current vec3. */
132  if (inputs_lookup[GPU_FLOAT] != nullptr) {
133  LinkData *float_input = inputs_lookup[GPU_FLOAT];
134  inputs_lookup[GPU_FLOAT] = float_input->next;
135 
136  BLI_remlink(inputs, float_input);
137  BLI_insertlinkafter(inputs, link, float_input);
138  }
139 
140  link = link_next;
141  }
142 #undef MAX_UBO_GPU_TYPE
143 }
144 
145 static inline size_t buffer_size_from_list(ListBase *inputs)
146 {
147  size_t buffer_size = 0;
148  LISTBASE_FOREACH (LinkData *, link, inputs) {
149  const eGPUType gputype = get_padded_gpu_type(link);
150  buffer_size += gputype * sizeof(float);
151  }
152  /* Round up to size of vec4. (Opengl Requirement) */
153  size_t alignment = sizeof(float[4]);
154  buffer_size = divide_ceil_u(buffer_size, alignment) * alignment;
155 
156  return buffer_size;
157 }
158 
159 static inline void buffer_fill_from_list(void *data, ListBase *inputs)
160 {
161  /* Now that we know the total ubo size we can start populating it. */
162  float *offset = (float *)data;
163  LISTBASE_FOREACH (LinkData *, link, inputs) {
164  GPUInput *input = (GPUInput *)link->data;
165  memcpy(offset, input->vec, input->type * sizeof(float));
166  offset += get_padded_gpu_type(link);
167  }
168 }
169 
172 /* -------------------------------------------------------------------- */
176 using namespace blender::gpu;
177 
178 GPUUniformBuf *GPU_uniformbuf_create_ex(size_t size, const void *data, const char *name)
179 {
181  /* Direct init. */
182  if (data != nullptr) {
183  ubo->update(data);
184  }
185  return wrap(ubo);
186 }
187 
189 {
190  /* There is no point on creating an UBO if there is no arguments. */
192  return nullptr;
193  }
194 
196  size_t buffer_size = buffer_size_from_list(inputs);
197  void *data = MEM_mallocN(buffer_size, __func__);
199 
200  UniformBuf *ubo = GPUBackend::get()->uniformbuf_alloc(buffer_size, name);
201  /* Defer data upload. */
202  ubo->attach_data(data);
203  return wrap(ubo);
204 }
205 
207 {
208  delete unwrap(ubo);
209 }
210 
211 void GPU_uniformbuf_update(GPUUniformBuf *ubo, const void *data)
212 {
213  unwrap(ubo)->update(data);
214 }
215 
216 void GPU_uniformbuf_bind(GPUUniformBuf *ubo, int slot)
217 {
218  unwrap(ubo)->bind(slot);
219 }
220 
222 {
223  unwrap(ubo)->unbind();
224 }
225 
227 {
228  /* FIXME */
229 }
230 
typedef float(TangentPoint)[2]
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition: BLI_assert.h:53
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:269
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1)
Definition: listbase.c:301
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:100
MINLINE uint divide_ceil_u(uint a, uint b)
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL()
Definition: string.c:64
eGPUType
Definition: GPU_material.h:45
@ GPU_VEC4
Definition: GPU_material.h:52
@ GPU_VEC3
Definition: GPU_material.h:51
@ GPU_MAT3
Definition: GPU_material.h:53
@ GPU_FLOAT
Definition: GPU_material.h:49
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
static GPUBackend * get()
Definition: gpu_context.cc:292
virtual UniformBuf * uniformbuf_alloc(int size, const char *name)=0
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)
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_unbind_all()
void GPU_uniformbuf_bind(GPUUniformBuf *ubo, int slot)
static eGPUType get_padded_gpu_type(LinkData *link)
ccl_gpu_kernel_postfix ccl_global float int int int int float bool int offset
ccl_global KernelShaderEvalInput * input
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
static unsigned a[3]
Definition: RandGen.cpp:78
static GPUContext * wrap(Context *ctx)
static Context * unwrap(GPUContext *ctx)
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
static bNodeSocketTemplate inputs[]
eGPUType type
void * data
Definition: DNA_listBase.h:26
struct LinkData * next
Definition: DNA_listBase.h:25