Blender  V2.93
gpu_vertex_format.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) 2016 by Mike Erwin.
17  * All rights reserved.
18  */
19 
26 #include "GPU_vertex_format.h"
27 #include "gpu_shader_private.hh"
29 
30 #include <cstddef>
31 #include <cstring>
32 
33 #include "BLI_ghash.h"
34 #include "BLI_string.h"
35 #include "BLI_utildefines.h"
36 
37 #define PACK_DEBUG 0
38 
39 #if PACK_DEBUG
40 # include <stdio.h>
41 #endif
42 
43 using namespace blender::gpu;
44 
46 {
47 #if TRUST_NO_ONE
48  memset(format, 0, sizeof(GPUVertFormat));
49 #else
50  format->attr_len = 0;
51  format->packed = false;
52  format->name_offset = 0;
53  format->name_len = 0;
54  format->deinterleaved = false;
55 
56  for (uint i = 0; i < GPU_VERT_ATTR_MAX_LEN; i++) {
57  format->attrs[i].name_len = 0;
58  }
59 #endif
60 }
61 
63 {
64  /* copy regular struct fields */
65  memcpy(dest, src, sizeof(GPUVertFormat));
66 }
67 
69 {
70 #if TRUST_NO_ONE
71  assert(type <= GPU_COMP_F32); /* other types have irregular sizes (not bytes) */
72 #endif
73  const uint sizes[] = {1, 1, 2, 2, 4, 4, 4};
74  return sizes[type];
75 }
76 
77 static uint attr_sz(const GPUVertAttr *a)
78 {
79  if (a->comp_type == GPU_COMP_I10) {
80  return 4; /* always packed as 10_10_10_2 */
81  }
82  return a->comp_len * comp_sz(static_cast<GPUVertCompType>(a->comp_type));
83 }
84 
85 static uint attr_align(const GPUVertAttr *a)
86 {
87  if (a->comp_type == GPU_COMP_I10) {
88  return 4; /* always packed as 10_10_10_2 */
89  }
90  uint c = comp_sz(static_cast<GPUVertCompType>(a->comp_type));
91  if (a->comp_len == 3 && c <= 2) {
92  return 4 * c; /* AMD HW can't fetch these well, so pad it out (other vendors too?) */
93  }
94 
95  return c; /* most fetches are ok if components are naturally aligned */
96 }
97 
99 {
100 #if TRUST_NO_ONE
101  assert(format->packed && format->stride > 0);
102 #endif
103  return format->stride * vertex_len;
104 }
105 
106 static uchar copy_attr_name(GPUVertFormat *format, const char *name)
107 {
108  /* `strncpy` does 110% of what we need; let's do exactly 100% */
109  uchar name_offset = format->name_offset;
110  char *name_copy = format->names + name_offset;
111  uint available = GPU_VERT_ATTR_NAMES_BUF_LEN - name_offset;
112  bool terminated = false;
113 
114  for (uint i = 0; i < available; i++) {
115  const char c = name[i];
116  name_copy[i] = c;
117  if (c == '\0') {
118  terminated = true;
119  format->name_offset += (i + 1);
120  break;
121  }
122  }
123 #if TRUST_NO_ONE
124  assert(terminated);
125  assert(format->name_offset <= GPU_VERT_ATTR_NAMES_BUF_LEN);
126 #else
127  (void)terminated;
128 #endif
129  return name_offset;
130 }
131 
133  const char *name,
134  GPUVertCompType comp_type,
135  uint comp_len,
136  GPUVertFetchMode fetch_mode)
137 {
138 #if TRUST_NO_ONE
139  assert(format->name_len < GPU_VERT_FORMAT_MAX_NAMES); /* there's room for more */
140  assert(format->attr_len < GPU_VERT_ATTR_MAX_LEN); /* there's room for more */
141  assert(!format->packed); /* packed means frozen/locked */
142  assert((comp_len >= 1 && comp_len <= 4) || comp_len == 8 || comp_len == 12 || comp_len == 16);
143 
144  switch (comp_type) {
145  case GPU_COMP_F32:
146  /* float type can only kept as float */
147  assert(fetch_mode == GPU_FETCH_FLOAT);
148  break;
149  case GPU_COMP_I10:
150  /* 10_10_10 format intended for normals (xyz) or colors (rgb)
151  * extra component packed.w can be manually set to { -2, -1, 0, 1 } */
152  assert(comp_len == 3 || comp_len == 4);
153 
154  /* Not strictly required, may relax later. */
155  assert(fetch_mode == GPU_FETCH_INT_TO_FLOAT_UNIT);
156 
157  break;
158  default:
159  /* integer types can be kept as int or converted/normalized to float */
160  assert(fetch_mode != GPU_FETCH_FLOAT);
161  /* only support float matrices (see Batch_update_program_bindings) */
162  assert(comp_len != 8 && comp_len != 12 && comp_len != 16);
163  }
164 #endif
165  format->name_len++; /* Multi-name support. */
166 
167  const uint attr_id = format->attr_len++;
168  GPUVertAttr *attr = &format->attrs[attr_id];
169 
170  attr->names[attr->name_len++] = copy_attr_name(format, name);
171  attr->comp_type = comp_type;
172  attr->comp_len = (comp_type == GPU_COMP_I10) ?
173  4 :
174  comp_len; /* system needs 10_10_10_2 to be 4 or BGRA */
175  attr->sz = attr_sz(attr);
176  attr->offset = 0; /* offsets & stride are calculated later (during pack) */
177  attr->fetch_mode = fetch_mode;
178 
179  return attr_id;
180 }
181 
183 {
184  GPUVertAttr *attr = &format->attrs[format->attr_len - 1];
185 #if TRUST_NO_ONE
186  assert(format->name_len < GPU_VERT_FORMAT_MAX_NAMES); /* there's room for more */
187  assert(attr->name_len < GPU_VERT_ATTR_MAX_NAMES);
188 #endif
189  format->name_len++; /* Multi-name support. */
190  attr->names[attr->name_len++] = copy_attr_name(format, alias);
191 }
192 
205 {
206  /* Sanity check. Maximum can be upgraded if needed. */
207  BLI_assert(load_count > 1 && load_count < 5);
208  /* We need a packed format because of format->stride. */
209  if (!format->packed) {
211  }
212 
213  BLI_assert((format->name_len + 1) * load_count < GPU_VERT_FORMAT_MAX_NAMES);
214  BLI_assert(format->attr_len * load_count <= GPU_VERT_ATTR_MAX_LEN);
215  BLI_assert(format->name_offset * load_count < GPU_VERT_ATTR_NAMES_BUF_LEN);
216 
217  const GPUVertAttr *attr = format->attrs;
218  int attr_len = format->attr_len;
219  for (int i = 0; i < attr_len; i++, attr++) {
220  const char *attr_name = GPU_vertformat_attr_name_get(format, attr, 0);
221  for (int j = 1; j < load_count; j++) {
222  char load_name[64];
223  BLI_snprintf(load_name, sizeof(load_name), "%s%d", attr_name, j);
224  GPUVertAttr *dst_attr = &format->attrs[format->attr_len++];
225  *dst_attr = *attr;
226 
227  dst_attr->names[0] = copy_attr_name(format, load_name);
228  dst_attr->name_len = 1;
229  dst_attr->offset += format->stride * j;
230  }
231  }
232 }
233 
234 int GPU_vertformat_attr_id_get(const GPUVertFormat *format, const char *name)
235 {
236  for (int i = 0; i < format->attr_len; i++) {
237  const GPUVertAttr *attr = &format->attrs[i];
238  for (int j = 0; j < attr->name_len; j++) {
239  const char *attr_name = GPU_vertformat_attr_name_get(format, attr, j);
240  if (STREQ(name, attr_name)) {
241  return i;
242  }
243  }
244  }
245  return -1;
246 }
247 
248 void GPU_vertformat_attr_rename(GPUVertFormat *format, int attr_id, const char *new_name)
249 {
250  BLI_assert(attr_id > -1 && attr_id < format->attr_len);
251  GPUVertAttr *attr = &format->attrs[attr_id];
252  char *attr_name = (char *)GPU_vertformat_attr_name_get(format, attr, 0);
253  BLI_assert(strlen(attr_name) == strlen(new_name));
254  int i = 0;
255  while (attr_name[i] != '\0') {
256  attr_name[i] = new_name[i];
257  i++;
258  }
259  attr->name_len = 1;
260 }
261 
262 /* Encode 8 original bytes into 11 safe bytes. */
263 static void safe_bytes(char out[11], const char data[8])
264 {
265  char safe_chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
266 
267  uint64_t in = *(uint64_t *)data;
268  for (int i = 0; i < 11; i++) {
269  out[i] = safe_chars[in % 62lu];
270  in /= 62lu;
271  }
272 }
273 
274 /* Warning: Always add a prefix to the result of this function as
275  * the generated string can start with a number and not be a valid attribute name. */
276 void GPU_vertformat_safe_attr_name(const char *attr_name, char *r_safe_name, uint UNUSED(max_len))
277 {
278  char data[8] = {0};
279  uint len = strlen(attr_name);
280 
281  if (len > 8) {
282  /* Start with the first 4 chars of the name; */
283  for (int i = 0; i < 4; i++) {
284  data[i] = attr_name[i];
285  }
286  /* We use a hash to identify each data layer based on its name.
287  * NOTE: This is still prone to hash collision but the risks are very low.*/
288  /* Start hashing after the first 2 chars. */
289  *(uint *)&data[4] = BLI_ghashutil_strhash_p_murmur(attr_name + 4);
290  }
291  else {
292  /* Copy the whole name. Collision is barely possible
293  * (hash would have to be equal to the last 4 bytes). */
294  for (int i = 0; i < 8 && attr_name[i] != '\0'; i++) {
295  data[i] = attr_name[i];
296  }
297  }
298  /* Convert to safe bytes characters. */
299  safe_bytes(r_safe_name, data);
300  /* End the string */
301  r_safe_name[11] = '\0';
302 
304 #if 0 /* For debugging */
305  printf("%s > %lx > %s\n", attr_name, *(uint64_t *)data, r_safe_name);
306 #endif
307 }
308 
309 /* Make attribute layout non-interleaved.
310  * Warning! This does not change data layout!
311  * Use direct buffer access to fill the data.
312  * This is for advanced usage.
313  *
314  * De-interleaved data means all attribute data for each attribute
315  * is stored continuously like this:
316  * 000011112222
317  * instead of :
318  * 012012012012
319  *
320  * Note this is per attribute de-interleaving, NOT per component.
321  * */
323 {
324  /* Ideally we should change the stride and offset here. This would allow
325  * us to use GPU_vertbuf_attr_set / GPU_vertbuf_attr_fill. But since
326  * we use only 11 bits for attr->offset this limits the size of the
327  * buffer considerably. So instead we do the conversion when creating
328  * bindings in create_bindings(). */
329  format->deinterleaved = true;
330 }
331 
332 uint padding(uint offset, uint alignment)
333 {
334  const uint mod = offset % alignment;
335  return (mod == 0) ? 0 : (alignment - mod);
336 }
337 
338 #if PACK_DEBUG
339 static void show_pack(uint a_idx, uint sz, uint pad)
340 {
341  const char c = 'A' + a_idx;
342  for (uint i = 0; i < pad; i++) {
343  putchar('-');
344  }
345  for (uint i = 0; i < sz; i++) {
346  putchar(c);
347  }
348 }
349 #endif
350 
352 {
353  GPUVertAttr *a0 = &format->attrs[0];
354  a0->offset = 0;
355  uint offset = a0->sz;
356 
357 #if PACK_DEBUG
358  show_pack(0, a0->sz, 0);
359 #endif
360 
361  for (uint a_idx = 1; a_idx < format->attr_len; a_idx++) {
362  GPUVertAttr *a = &format->attrs[a_idx];
363  uint mid_padding = padding(offset, attr_align(a));
364  offset += mid_padding;
365  a->offset = offset;
366  offset += a->sz;
367 
368 #if PACK_DEBUG
369  show_pack(a_idx, a->sz, mid_padding);
370 #endif
371  }
372 
373  uint end_padding = padding(offset, attr_align(a0));
374 
375 #if PACK_DEBUG
376  show_pack(0, 0, end_padding);
377  putchar('\n');
378 #endif
379  format->stride = offset + end_padding;
380  format->packed = true;
381 }
382 
384 {
385  const Shader *shader = reinterpret_cast<const Shader *>(gpushader);
386  shader->vertformat_from_shader(format);
387 }
#define BLI_assert(a)
Definition: BLI_assert.h:58
unsigned int BLI_ghashutil_strhash_p_murmur(const void *ptr)
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
unsigned char uchar
Definition: BLI_sys_types.h:86
unsigned int uint
Definition: BLI_sys_types.h:83
#define UNUSED(x)
#define STREQ(a, b)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
struct GPUShader GPUShader
Definition: GPU_shader.h:33
#define GPU_VERT_ATTR_MAX_NAMES
GPUVertFetchMode
@ GPU_FETCH_FLOAT
@ GPU_FETCH_INT_TO_FLOAT_UNIT
#define GPU_VERT_FORMAT_MAX_NAMES
#define GPU_VERT_ATTR_NAMES_BUF_LEN
BLI_INLINE const char * GPU_vertformat_attr_name_get(const GPUVertFormat *format, const GPUVertAttr *attr, uint n_idx)
#define GPU_MAX_SAFE_ATTR_NAME
#define GPU_VERT_ATTR_MAX_LEN
GPUVertCompType
@ GPU_COMP_I10
@ GPU_COMP_F32
struct @612::@615 attr_id
static uint attr_sz(const GPUVertAttr *a)
static void safe_bytes(char out[11], const char data[8])
void GPU_vertformat_alias_add(GPUVertFormat *format, const char *alias)
static uint attr_align(const GPUVertAttr *a)
void GPU_vertformat_from_shader(GPUVertFormat *format, const struct GPUShader *gpushader)
uint vertex_buffer_size(const GPUVertFormat *format, uint vertex_len)
void GPU_vertformat_attr_rename(GPUVertFormat *format, int attr_id, const char *new_name)
void GPU_vertformat_copy(GPUVertFormat *dest, const GPUVertFormat *src)
uint padding(uint offset, uint alignment)
static uint comp_sz(GPUVertCompType type)
void GPU_vertformat_multiload_enable(GPUVertFormat *format, int load_count)
void GPU_vertformat_safe_attr_name(const char *attr_name, char *r_safe_name, uint UNUSED(max_len))
int GPU_vertformat_attr_id_get(const GPUVertFormat *format, const char *name)
uint GPU_vertformat_attr_add(GPUVertFormat *format, const char *name, GPUVertCompType comp_type, uint comp_len, GPUVertFetchMode fetch_mode)
void GPU_vertformat_clear(GPUVertFormat *format)
static uchar copy_attr_name(GPUVertFormat *format, const char *name)
void GPU_vertformat_deinterleave(GPUVertFormat *format)
void VertexFormat_pack(GPUVertFormat *format)
void KERNEL_FUNCTION_FULL_NAME() shader(KernelGlobals *kg, uint4 *input, float4 *output, int type, int filter, int i, int offset, int sample)
format
Definition: logImageCore.h:47
static unsigned c
Definition: RandGen.cpp:97
static unsigned a[3]
Definition: RandGen.cpp:92
unsigned __int64 uint64_t
Definition: stdint.h:93
uchar names[GPU_VERT_ATTR_MAX_NAMES]
ccl_device_inline int mod(int x, int m)
Definition: util_math.h:405
uint len