Blender  V3.3
gpu_index_buffer.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2016 by Mike Erwin. All rights reserved. */
3 
10 #include "MEM_guardedalloc.h"
11 
12 #include "BLI_math_base.h"
13 #include "BLI_utildefines.h"
14 
15 #include "gpu_backend.hh"
16 
18 
19 #include <cstring>
20 
21 #define KEEP_SINGLE_COPY 1
22 
23 #define RESTART_INDEX 0xFFFFFFFF
24 
25 /* -------------------------------------------------------------------- */
29 using namespace blender;
30 using namespace blender::gpu;
31 
33  GPUPrimType prim_type,
34  uint index_len,
35  uint vertex_len)
36 {
37  builder->max_allowed_index = vertex_len - 1;
38  builder->max_index_len = index_len;
39  builder->index_len = 0; // start empty
40  builder->index_min = UINT32_MAX;
41  builder->index_max = 0;
42  builder->prim_type = prim_type;
43  builder->data = (uint *)MEM_callocN(builder->max_index_len * sizeof(uint), "GPUIndexBuf data");
44 }
45 
47  GPUPrimType prim_type,
48  uint prim_len,
49  uint vertex_len)
50 {
51  int verts_per_prim = GPU_indexbuf_primitive_len(prim_type);
52 #if TRUST_NO_ONE
53  assert(verts_per_prim != -1);
54 #endif
55  GPU_indexbuf_init_ex(builder, prim_type, prim_len * (uint)verts_per_prim, vertex_len);
56 }
57 
59 {
61  GPU_indexbuf_init_build_on_device(elem_, index_len);
62  return elem_;
63 }
64 
66 {
67  IndexBuf *elem_ = unwrap(elem);
68  elem_->init_build_on_device(index_len);
69 }
70 
71 void GPU_indexbuf_join(GPUIndexBufBuilder *builder_to, const GPUIndexBufBuilder *builder_from)
72 {
73  BLI_assert(builder_to->data == builder_from->data);
74  builder_to->index_len = max_uu(builder_to->index_len, builder_from->index_len);
75  builder_to->index_min = min_uu(builder_to->index_min, builder_from->index_min);
76  builder_to->index_max = max_uu(builder_to->index_max, builder_from->index_max);
77 }
78 
80 {
81 #if TRUST_NO_ONE
82  assert(builder->data != nullptr);
83  assert(builder->index_len < builder->max_index_len);
84  assert(v <= builder->max_allowed_index);
85 #endif
86  builder->data[builder->index_len++] = v;
87  builder->index_min = MIN2(builder->index_min, v);
88  builder->index_max = MAX2(builder->index_max, v);
89 }
90 
92 {
93 #if TRUST_NO_ONE
94  assert(builder->data != nullptr);
95  assert(builder->index_len < builder->max_index_len);
96 #endif
97  builder->data[builder->index_len++] = RESTART_INDEX;
98 }
99 
101 {
102 #if TRUST_NO_ONE
103  assert(builder->prim_type == GPU_PRIM_POINTS);
104 #endif
106 }
107 
109 {
110 #if TRUST_NO_ONE
111  assert(builder->prim_type == GPU_PRIM_LINES);
112  assert(v1 != v2);
113 #endif
116 }
117 
119 {
120 #if TRUST_NO_ONE
121  assert(builder->prim_type == GPU_PRIM_TRIS);
122  assert(v1 != v2 && v2 != v3 && v3 != v1);
123 #endif
126  GPU_indexbuf_add_generic_vert(builder, v3);
127 }
128 
130  GPUIndexBufBuilder *builder, uint v1, uint v2, uint v3, uint v4)
131 {
132 #if TRUST_NO_ONE
133  assert(builder->prim_type == GPU_PRIM_LINES_ADJ);
134  assert(v2 != v3); /* only the line need diff indices */
135 #endif
138  GPU_indexbuf_add_generic_vert(builder, v3);
139  GPU_indexbuf_add_generic_vert(builder, v4);
140 }
141 
143 {
144  BLI_assert(builder->prim_type == GPU_PRIM_POINTS);
145  BLI_assert(elem < builder->max_index_len);
146  builder->data[elem++] = v1;
147  builder->index_min = MIN2(builder->index_min, v1);
148  builder->index_max = MAX2(builder->index_max, v1);
149  builder->index_len = MAX2(builder->index_len, elem);
150 }
151 
153 {
154  BLI_assert(builder->prim_type == GPU_PRIM_LINES);
155  BLI_assert(v1 != v2);
156  BLI_assert(v1 <= builder->max_allowed_index);
157  BLI_assert(v2 <= builder->max_allowed_index);
158  BLI_assert((elem + 1) * 2 <= builder->max_index_len);
159  uint idx = elem * 2;
160  builder->data[idx++] = v1;
161  builder->data[idx++] = v2;
162  builder->index_min = MIN3(builder->index_min, v1, v2);
163  builder->index_max = MAX3(builder->index_max, v1, v2);
164  builder->index_len = MAX2(builder->index_len, idx);
165 }
166 
168 {
169  BLI_assert(builder->prim_type == GPU_PRIM_TRIS);
170  BLI_assert(v1 != v2 && v2 != v3 && v3 != v1);
171  BLI_assert(v1 <= builder->max_allowed_index);
172  BLI_assert(v2 <= builder->max_allowed_index);
173  BLI_assert(v3 <= builder->max_allowed_index);
174  BLI_assert((elem + 1) * 3 <= builder->max_index_len);
175  uint idx = elem * 3;
176  builder->data[idx++] = v1;
177  builder->data[idx++] = v2;
178  builder->data[idx++] = v3;
179 
180  builder->index_min = MIN4(builder->index_min, v1, v2, v3);
181  builder->index_max = MAX4(builder->index_max, v1, v2, v3);
182  builder->index_len = MAX2(builder->index_len, idx);
183 }
184 
186 {
187  BLI_assert(builder->prim_type == GPU_PRIM_POINTS);
188  BLI_assert(elem < builder->max_index_len);
189  builder->data[elem++] = RESTART_INDEX;
190  builder->index_len = MAX2(builder->index_len, elem);
191 }
192 
194 {
195  BLI_assert(builder->prim_type == GPU_PRIM_LINES);
196  BLI_assert((elem + 1) * 2 <= builder->max_index_len);
197  uint idx = elem * 2;
198  builder->data[idx++] = RESTART_INDEX;
199  builder->data[idx++] = RESTART_INDEX;
200  builder->index_len = MAX2(builder->index_len, idx);
201 }
202 
204 {
205  BLI_assert(builder->prim_type == GPU_PRIM_TRIS);
206  BLI_assert((elem + 1) * 3 <= builder->max_index_len);
207  uint idx = elem * 3;
208  builder->data[idx++] = RESTART_INDEX;
209  builder->data[idx++] = RESTART_INDEX;
210  builder->data[idx++] = RESTART_INDEX;
211  builder->index_len = MAX2(builder->index_len, idx);
212 }
213 
216 /* -------------------------------------------------------------------- */
220 namespace blender::gpu {
221 
223 {
224  if (!is_subrange_) {
226  }
227 }
228 
229 void IndexBuf::init(uint indices_len, uint32_t *indices, uint min_index, uint max_index)
230 {
231  is_init_ = true;
232  data_ = indices;
233  index_start_ = 0;
234  index_len_ = indices_len;
235  is_empty_ = min_index > max_index;
236 
237 #if GPU_TRACK_INDEX_RANGE
238  /* Everything remains 32 bit while building to keep things simple.
239  * Find min/max after, then convert to smallest index type possible. */
240  uint range = min_index < max_index ? max_index - min_index : 0;
241  /* count the primitive restart index. */
242  range += 1;
243 
244  if (range <= 0xFFFF) {
246  this->squeeze_indices_short(min_index, max_index);
247  }
248 #endif
249 }
250 
252 {
253  is_init_ = true;
254  index_start_ = 0;
255  index_len_ = index_len;
257  data_ = nullptr;
258 }
259 
261 {
262  /* We don't support nested subranges. */
263  BLI_assert(elem_src && elem_src->is_subrange_ == false);
264  BLI_assert((length == 0) || (start + length <= elem_src->index_len_));
265 
266  is_init_ = true;
267  is_subrange_ = true;
268  src_ = elem_src;
269  index_start_ = start;
270  index_len_ = length;
271  index_base_ = elem_src->index_base_;
272  index_type_ = elem_src->index_type_;
273 }
274 
275 uint IndexBuf::index_range(uint *r_min, uint *r_max)
276 {
277  if (index_len_ == 0) {
278  *r_min = *r_max = 0;
279  return 0;
280  }
281  const uint32_t *uint_idx = (uint32_t *)data_;
282  uint min_value = RESTART_INDEX;
283  uint max_value = 0;
284  for (uint i = 0; i < index_len_; i++) {
285  const uint value = uint_idx[i];
286  if (value == RESTART_INDEX) {
287  continue;
288  }
289  if (value < min_value) {
290  min_value = value;
291  }
292  else if (value > max_value) {
293  max_value = value;
294  }
295  }
296  if (min_value == RESTART_INDEX) {
297  *r_min = *r_max = 0;
298  return 0;
299  }
300  *r_min = min_value;
301  *r_max = max_value;
302  return max_value - min_value;
303 }
304 
305 void IndexBuf::squeeze_indices_short(uint min_idx, uint max_idx)
306 {
307  /* data will never be *larger* than builder->data...
308  * converting in place to avoid extra allocation */
309  uint16_t *ushort_idx = (uint16_t *)data_;
310  const uint32_t *uint_idx = (uint32_t *)data_;
311 
312  if (max_idx >= 0xFFFF) {
313  index_base_ = min_idx;
314  for (uint i = 0; i < index_len_; i++) {
315  ushort_idx[i] = (uint16_t)MIN2(0xFFFF, uint_idx[i] - min_idx);
316  }
317  }
318  else {
319  index_base_ = 0;
320  for (uint i = 0; i < index_len_; i++) {
321  ushort_idx[i] = (uint16_t)(uint_idx[i]);
322  }
323  }
324 }
325 
326 uint32_t *IndexBuf::unmap(const uint32_t *mapped_memory) const
327 {
328  size_t size = size_get();
329  uint32_t *result = static_cast<uint32_t *>(MEM_mallocN(size, __func__));
330  memcpy(result, mapped_memory, size);
331  return result;
332 }
333 
334 } // namespace blender::gpu
335 
338 /* -------------------------------------------------------------------- */
343 {
344  return wrap(GPUBackend::get()->indexbuf_alloc());
345 }
346 
348 {
350  GPU_indexbuf_build_in_place(builder, elem);
351  return elem;
352 }
353 
355 {
357  GPU_indexbuf_create_subrange_in_place(elem, elem_src, start, length);
358  return elem;
359 }
360 
362 {
363  BLI_assert(builder->data != nullptr);
364  /* Transfer data ownership to GPUIndexBuf.
365  * It will be uploaded upon first use. */
366  unwrap(elem)->init(builder->index_len, builder->data, builder->index_min, builder->index_max);
367  builder->data = nullptr;
368 }
369 
371  GPUIndexBuf *elem_src,
372  uint start,
373  uint length)
374 {
375  unwrap(elem)->init_subrange(unwrap(elem_src), start, length);
376 }
377 
379 {
380  return unwrap(elem)->read();
381 }
382 
383 uint32_t *GPU_indexbuf_unmap(const GPUIndexBuf *elem, const uint32_t *mapped_buffer)
384 {
385  return unwrap(elem)->unmap(mapped_buffer);
386 }
387 
389 {
390  delete unwrap(elem);
391 }
392 
394 {
395  return unwrap(elem)->is_init();
396 }
397 
399 {
400  return indices_per_primitive(prim_type);
401 }
402 
404 {
405  unwrap(elem)->upload_data();
406 }
407 
408 void GPU_indexbuf_bind_as_ssbo(GPUIndexBuf *elem, int binding)
409 {
410  unwrap(elem)->bind_as_ssbo(binding);
411 }
412 
413 void GPU_indexbuf_update_sub(GPUIndexBuf *elem, uint start, uint len, const void *data)
414 {
415  unwrap(elem)->update_sub(start, len, data);
416 }
417 
#define BLI_assert(a)
Definition: BLI_assert.h:46
MINLINE uint min_uu(uint a, uint b)
MINLINE uint max_uu(uint a, uint b)
unsigned int uint
Definition: BLI_sys_types.h:67
#define MIN4(a, b, c, d)
#define MAX3(a, b, c)
#define MIN3(a, b, c)
#define MAX2(a, b)
#define MIN2(a, b)
#define MAX4(a, b, c, d)
struct GPUIndexBuf GPUIndexBuf
_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 const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble v1
GPUPrimType
Definition: GPU_primitive.h:18
@ GPU_PRIM_LINES
Definition: GPU_primitive.h:20
@ GPU_PRIM_POINTS
Definition: GPU_primitive.h:19
@ GPU_PRIM_LINES_ADJ
Definition: GPU_primitive.h:29
@ GPU_PRIM_TRIS
Definition: GPU_primitive.h:21
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert * v
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
void init(uint indices_len, uint32_t *indices, uint min_index, uint max_index)
uint32_t * unmap(const uint32_t *mapped_memory) const
void init_build_on_device(uint index_len)
void init_subrange(IndexBuf *elem_src, uint start, uint length)
int len
Definition: draw_manager.c:108
void GPU_indexbuf_set_point_vert(GPUIndexBufBuilder *builder, uint elem, uint v1)
int GPU_indexbuf_primitive_len(GPUPrimType prim_type)
void GPU_indexbuf_add_generic_vert(GPUIndexBufBuilder *builder, uint v)
GPUIndexBuf * GPU_indexbuf_build_on_device(uint index_len)
void GPU_indexbuf_set_point_restart(GPUIndexBufBuilder *builder, uint elem)
GPUIndexBuf * GPU_indexbuf_build(GPUIndexBufBuilder *builder)
void GPU_indexbuf_bind_as_ssbo(GPUIndexBuf *elem, int binding)
GPUIndexBuf * GPU_indexbuf_create_subrange(GPUIndexBuf *elem_src, uint start, uint length)
void GPU_indexbuf_init_build_on_device(GPUIndexBuf *elem, uint index_len)
void GPU_indexbuf_set_line_verts(GPUIndexBufBuilder *builder, uint elem, uint v1, uint v2)
void GPU_indexbuf_update_sub(GPUIndexBuf *elem, uint start, uint len, const void *data)
const uint32_t * GPU_indexbuf_read(GPUIndexBuf *elem)
void GPU_indexbuf_set_tri_verts(GPUIndexBufBuilder *builder, uint elem, uint v1, uint v2, uint v3)
void GPU_indexbuf_use(GPUIndexBuf *elem)
void GPU_indexbuf_set_line_restart(GPUIndexBufBuilder *builder, uint elem)
void GPU_indexbuf_add_line_adj_verts(GPUIndexBufBuilder *builder, uint v1, uint v2, uint v3, uint v4)
void GPU_indexbuf_set_tri_restart(GPUIndexBufBuilder *builder, uint elem)
void GPU_indexbuf_join(GPUIndexBufBuilder *builder_to, const GPUIndexBufBuilder *builder_from)
void GPU_indexbuf_add_primitive_restart(GPUIndexBufBuilder *builder)
void GPU_indexbuf_build_in_place(GPUIndexBufBuilder *builder, GPUIndexBuf *elem)
GPUIndexBuf * GPU_indexbuf_calloc()
void GPU_indexbuf_create_subrange_in_place(GPUIndexBuf *elem, GPUIndexBuf *elem_src, uint start, uint length)
void GPU_indexbuf_discard(GPUIndexBuf *elem)
void GPU_indexbuf_add_point_vert(GPUIndexBufBuilder *builder, uint v)
void GPU_indexbuf_init_ex(GPUIndexBufBuilder *builder, GPUPrimType prim_type, uint index_len, uint vertex_len)
uint32_t * GPU_indexbuf_unmap(const GPUIndexBuf *elem, const uint32_t *mapped_buffer)
bool GPU_indexbuf_is_init(GPUIndexBuf *elem)
void GPU_indexbuf_add_tri_verts(GPUIndexBufBuilder *builder, uint v1, uint v2, uint v3)
#define RESTART_INDEX
void GPU_indexbuf_init(GPUIndexBufBuilder *builder, GPUPrimType prim_type, uint prim_len, uint vertex_len)
void GPU_indexbuf_add_line_verts(GPUIndexBufBuilder *builder, uint v1, uint v2)
ccl_gpu_kernel_postfix int ccl_global int * indices
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
static PartialUpdateUserImpl * unwrap(struct PartialUpdateUser *user)
static struct PartialUpdateUser * wrap(PartialUpdateUserImpl *user)
static Context * unwrap(GPUContext *ctx)
static int indices_per_primitive(GPUPrimType prim_type)
T length(const vec_base< T, Size > &a)
unsigned short uint16_t
Definition: stdint.h:79
unsigned int uint32_t
Definition: stdint.h:80
#define UINT32_MAX
Definition: stdint.h:142