Blender  V2.93
gpu_index_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) 2016 by Mike Erwin.
17  * All rights reserved.
18  */
19 
26 #include "MEM_guardedalloc.h"
27 
28 #include "BLI_utildefines.h"
29 
30 #include "gpu_backend.hh"
31 
33 
34 #define KEEP_SINGLE_COPY 1
35 
36 #define RESTART_INDEX 0xFFFFFFFF
37 
38 /* -------------------------------------------------------------------- */
42 using namespace blender;
43 using namespace blender::gpu;
44 
46  GPUPrimType prim_type,
47  uint index_len,
48  uint vertex_len)
49 {
50  builder->max_allowed_index = vertex_len - 1;
51  builder->max_index_len = index_len;
52  builder->index_len = 0; // start empty
53  builder->prim_type = prim_type;
54  builder->data = (uint *)MEM_callocN(builder->max_index_len * sizeof(uint), "GPUIndexBuf data");
55 }
56 
58  GPUPrimType prim_type,
59  uint prim_len,
60  uint vertex_len)
61 {
62  int verts_per_prim = GPU_indexbuf_primitive_len(prim_type);
63 #if TRUST_NO_ONE
64  assert(verts_per_prim != -1);
65 #endif
66  GPU_indexbuf_init_ex(builder, prim_type, prim_len * (uint)verts_per_prim, vertex_len);
67 }
68 
70 {
71 #if TRUST_NO_ONE
72  assert(builder->data != nullptr);
73  assert(builder->index_len < builder->max_index_len);
74  assert(v <= builder->max_allowed_index);
75 #endif
76  builder->data[builder->index_len++] = v;
77 }
78 
80 {
81 #if TRUST_NO_ONE
82  assert(builder->data != nullptr);
83  assert(builder->index_len < builder->max_index_len);
84 #endif
85  builder->data[builder->index_len++] = RESTART_INDEX;
86 }
87 
89 {
90 #if TRUST_NO_ONE
91  assert(builder->prim_type == GPU_PRIM_POINTS);
92 #endif
94 }
95 
97 {
98 #if TRUST_NO_ONE
99  assert(builder->prim_type == GPU_PRIM_LINES);
100  assert(v1 != v2);
101 #endif
104 }
105 
107 {
108 #if TRUST_NO_ONE
109  assert(builder->prim_type == GPU_PRIM_TRIS);
110  assert(v1 != v2 && v2 != v3 && v3 != v1);
111 #endif
114  GPU_indexbuf_add_generic_vert(builder, v3);
115 }
116 
118  GPUIndexBufBuilder *builder, uint v1, uint v2, uint v3, uint v4)
119 {
120 #if TRUST_NO_ONE
121  assert(builder->prim_type == GPU_PRIM_LINES_ADJ);
122  assert(v2 != v3); /* only the line need diff indices */
123 #endif
126  GPU_indexbuf_add_generic_vert(builder, v3);
127  GPU_indexbuf_add_generic_vert(builder, v4);
128 }
129 
131 {
132  BLI_assert(builder->prim_type == GPU_PRIM_POINTS);
133  BLI_assert(elem < builder->max_index_len);
134  builder->data[elem++] = v1;
135  if (builder->index_len < elem) {
136  builder->index_len = elem;
137  }
138 }
139 
141 {
142  BLI_assert(builder->prim_type == GPU_PRIM_LINES);
143  BLI_assert(v1 != v2);
144  BLI_assert(v1 <= builder->max_allowed_index);
145  BLI_assert(v2 <= builder->max_allowed_index);
146  BLI_assert((elem + 1) * 2 <= builder->max_index_len);
147  uint idx = elem * 2;
148  builder->data[idx++] = v1;
149  builder->data[idx++] = v2;
150  if (builder->index_len < idx) {
151  builder->index_len = idx;
152  }
153 }
154 
156 {
157  BLI_assert(builder->prim_type == GPU_PRIM_TRIS);
158  BLI_assert(v1 != v2 && v2 != v3 && v3 != v1);
159  BLI_assert(v1 <= builder->max_allowed_index);
160  BLI_assert(v2 <= builder->max_allowed_index);
161  BLI_assert(v3 <= builder->max_allowed_index);
162  BLI_assert((elem + 1) * 3 <= builder->max_index_len);
163  uint idx = elem * 3;
164  builder->data[idx++] = v1;
165  builder->data[idx++] = v2;
166  builder->data[idx++] = v3;
167  if (builder->index_len < idx) {
168  builder->index_len = idx;
169  }
170 }
171 
173 {
174  BLI_assert(builder->prim_type == GPU_PRIM_POINTS);
175  BLI_assert(elem < builder->max_index_len);
176  builder->data[elem++] = RESTART_INDEX;
177  if (builder->index_len < elem) {
178  builder->index_len = elem;
179  }
180 }
181 
183 {
184  BLI_assert(builder->prim_type == GPU_PRIM_LINES);
185  BLI_assert((elem + 1) * 2 <= builder->max_index_len);
186  uint idx = elem * 2;
187  builder->data[idx++] = RESTART_INDEX;
188  builder->data[idx++] = RESTART_INDEX;
189  if (builder->index_len < idx) {
190  builder->index_len = idx;
191  }
192 }
193 
195 {
196  BLI_assert(builder->prim_type == GPU_PRIM_TRIS);
197  BLI_assert((elem + 1) * 3 <= builder->max_index_len);
198  uint idx = elem * 3;
199  builder->data[idx++] = RESTART_INDEX;
200  builder->data[idx++] = RESTART_INDEX;
201  builder->data[idx++] = RESTART_INDEX;
202  if (builder->index_len < idx) {
203  builder->index_len = idx;
204  }
205 }
206 
209 /* -------------------------------------------------------------------- */
213 namespace blender::gpu {
214 
216 {
217  if (!is_subrange_) {
219  }
220 }
221 
222 void IndexBuf::init(uint indices_len, uint32_t *indices)
223 {
224  is_init_ = true;
225  data_ = indices;
226  index_start_ = 0;
227  index_len_ = indices_len;
228 
229 #if GPU_TRACK_INDEX_RANGE
230  /* Everything remains 32 bit while building to keep things simple.
231  * Find min/max after, then convert to smallest index type possible. */
232  uint min_index, max_index;
233  uint range = this->index_range(&min_index, &max_index);
234  /* count the primitive restart index. */
235  range += 1;
236 
237  if (range <= 0xFFFF) {
239  this->squeeze_indices_short(min_index, max_index);
240  }
241 #endif
242 }
243 
245 {
246  /* We don't support nested subranges. */
247  BLI_assert(elem_src && elem_src->is_subrange_ == false);
248  BLI_assert((length == 0) || (start + length <= elem_src->index_len_));
249 
250  is_init_ = true;
251  is_subrange_ = true;
252  src_ = elem_src;
253  index_start_ = start;
254  index_len_ = length;
255  index_base_ = elem_src->index_base_;
256  index_type_ = elem_src->index_type_;
257 }
258 
259 uint IndexBuf::index_range(uint *r_min, uint *r_max)
260 {
261  if (index_len_ == 0) {
262  *r_min = *r_max = 0;
263  return 0;
264  }
265  const uint32_t *uint_idx = (uint32_t *)data_;
266  uint min_value = RESTART_INDEX;
267  uint max_value = 0;
268  for (uint i = 0; i < index_len_; i++) {
269  const uint value = uint_idx[i];
270  if (value == RESTART_INDEX) {
271  continue;
272  }
273  if (value < min_value) {
274  min_value = value;
275  }
276  else if (value > max_value) {
277  max_value = value;
278  }
279  }
280  if (min_value == RESTART_INDEX) {
281  *r_min = *r_max = 0;
282  return 0;
283  }
284  *r_min = min_value;
285  *r_max = max_value;
286  return max_value - min_value;
287 }
288 
289 void IndexBuf::squeeze_indices_short(uint min_idx, uint max_idx)
290 {
291  /* data will never be *larger* than builder->data...
292  * converting in place to avoid extra allocation */
293  uint16_t *ushort_idx = (uint16_t *)data_;
294  const uint32_t *uint_idx = (uint32_t *)data_;
295 
296  if (max_idx >= 0xFFFF) {
297  index_base_ = min_idx;
298  for (uint i = 0; i < index_len_; i++) {
299  ushort_idx[i] = (uint16_t)MIN2(0xFFFF, uint_idx[i] - min_idx);
300  }
301  }
302  else {
303  index_base_ = 0;
304  for (uint i = 0; i < index_len_; i++) {
305  ushort_idx[i] = (uint16_t)(uint_idx[i]);
306  }
307  }
308 }
309 
310 } // namespace blender::gpu
311 
314 /* -------------------------------------------------------------------- */
319 {
320  return wrap(GPUBackend::get()->indexbuf_alloc());
321 }
322 
324 {
326  GPU_indexbuf_build_in_place(builder, elem);
327  return elem;
328 }
329 
331 {
333  GPU_indexbuf_create_subrange_in_place(elem, elem_src, start, length);
334  return elem;
335 }
336 
338 {
339  BLI_assert(builder->data != nullptr);
340  /* Transfer data ownership to GPUIndexBuf.
341  * It will be uploaded upon first use. */
342  unwrap(elem)->init(builder->index_len, builder->data);
343  builder->data = nullptr;
344 }
345 
347  GPUIndexBuf *elem_src,
348  uint start,
349  uint length)
350 {
351  unwrap(elem)->init_subrange(unwrap(elem_src), start, length);
352 }
353 
355 {
356  delete unwrap(elem);
357 }
358 
360 {
361  return unwrap(elem)->is_init();
362 }
363 
365 {
366  return indices_per_primitive(prim_type);
367 }
368 
#define BLI_assert(a)
Definition: BLI_assert.h:58
unsigned int uint
Definition: BLI_sys_types.h:83
#define MIN2(a, b)
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:34
@ GPU_PRIM_LINES
Definition: GPU_primitive.h:36
@ GPU_PRIM_POINTS
Definition: GPU_primitive.h:35
@ GPU_PRIM_LINES_ADJ
Definition: GPU_primitive.h:43
@ GPU_PRIM_TRIS
Definition: GPU_primitive.h:37
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert * v
SIMD_FORCE_INLINE btScalar length(const btQuaternion &q)
Return the length of a quaternion.
Definition: btQuaternion.h:895
void init(uint indices_len, uint32_t *indices)
void init_subrange(IndexBuf *elem_src, uint start, uint length)
static ushort indices[]
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)
void GPU_indexbuf_set_point_restart(GPUIndexBufBuilder *builder, uint elem)
GPUIndexBuf * GPU_indexbuf_build(GPUIndexBufBuilder *builder)
GPUIndexBuf * GPU_indexbuf_create_subrange(GPUIndexBuf *elem_src, uint start, uint length)
void GPU_indexbuf_set_line_verts(GPUIndexBufBuilder *builder, uint elem, uint v1, uint v2)
void GPU_indexbuf_set_tri_verts(GPUIndexBufBuilder *builder, uint elem, uint v1, uint v2, uint v3)
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_add_primitive_restart(GPUIndexBufBuilder *builder)
GPUIndexBuf * GPU_indexbuf_calloc(void)
void GPU_indexbuf_build_in_place(GPUIndexBufBuilder *builder, GPUIndexBuf *elem)
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)
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)
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
static GPUContext * wrap(Context *ctx)
static Context * unwrap(GPUContext *ctx)
static int indices_per_primitive(GPUPrimType prim_type)
unsigned short uint16_t
Definition: stdint.h:82
unsigned int uint32_t
Definition: stdint.h:83