GHOST: Only spam about X11 errors when using --debug-ghost
[blender.git] / source / blender / gpu / intern / gpu_element.c
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
20 /** \file
21  * \ingroup gpu
22  *
23  * GPU element list (AKA index buffer)
24  */
25
26 #include "MEM_guardedalloc.h"
27
28 #include "GPU_element.h"
29
30 #include "gpu_context_private.h"
31
32 #include <stdlib.h>
33
34 #define KEEP_SINGLE_COPY 1
35
36 #define RESTART_INDEX 0xFFFFFFFF
37
38 static GLenum convert_index_type_to_gl(GPUIndexBufType type)
39 {
40   static const GLenum table[] = {
41       [GPU_INDEX_U16] = GL_UNSIGNED_SHORT,
42       [GPU_INDEX_U32] = GL_UNSIGNED_INT,
43   };
44   return table[type];
45 }
46
47 uint GPU_indexbuf_size_get(const GPUIndexBuf *elem)
48 {
49 #if GPU_TRACK_INDEX_RANGE
50   static const uint table[] = {
51       [GPU_INDEX_U16] = sizeof(GLushort),
52       [GPU_INDEX_U32] = sizeof(GLuint),
53   };
54   return elem->index_len * table[elem->index_type];
55 #else
56   return elem->index_len * sizeof(GLuint);
57 #endif
58 }
59
60 int GPU_indexbuf_primitive_len(GPUPrimType prim_type)
61 {
62   switch (prim_type) {
63     case GPU_PRIM_POINTS:
64       return 1;
65     case GPU_PRIM_LINES:
66       return 2;
67     case GPU_PRIM_TRIS:
68       return 3;
69     case GPU_PRIM_LINES_ADJ:
70       return 4;
71     default:
72       break;
73   }
74 #if TRUST_NO_ONE
75   assert(false);
76 #endif
77   return -1;
78 }
79
80 void GPU_indexbuf_init_ex(GPUIndexBufBuilder *builder,
81                           GPUPrimType prim_type,
82                           uint index_len,
83                           uint vertex_len)
84 {
85   builder->max_allowed_index = vertex_len - 1;
86   builder->max_index_len = index_len;
87   builder->index_len = 0;  // start empty
88   builder->prim_type = prim_type;
89   builder->data = MEM_callocN(builder->max_index_len * sizeof(uint), "GPUIndexBuf data");
90 }
91
92 void GPU_indexbuf_init(GPUIndexBufBuilder *builder,
93                        GPUPrimType prim_type,
94                        uint prim_len,
95                        uint vertex_len)
96 {
97   int verts_per_prim = GPU_indexbuf_primitive_len(prim_type);
98 #if TRUST_NO_ONE
99   assert(verts_per_prim != -1);
100 #endif
101   GPU_indexbuf_init_ex(builder, prim_type, prim_len * (uint)verts_per_prim, vertex_len);
102 }
103
104 void GPU_indexbuf_add_generic_vert(GPUIndexBufBuilder *builder, uint v)
105 {
106 #if TRUST_NO_ONE
107   assert(builder->data != NULL);
108   assert(builder->index_len < builder->max_index_len);
109   assert(v <= builder->max_allowed_index);
110 #endif
111   builder->data[builder->index_len++] = v;
112 }
113
114 void GPU_indexbuf_add_primitive_restart(GPUIndexBufBuilder *builder)
115 {
116 #if TRUST_NO_ONE
117   assert(builder->data != NULL);
118   assert(builder->index_len < builder->max_index_len);
119 #endif
120   builder->data[builder->index_len++] = RESTART_INDEX;
121 }
122
123 void GPU_indexbuf_add_point_vert(GPUIndexBufBuilder *builder, uint v)
124 {
125 #if TRUST_NO_ONE
126   assert(builder->prim_type == GPU_PRIM_POINTS);
127 #endif
128   GPU_indexbuf_add_generic_vert(builder, v);
129 }
130
131 void GPU_indexbuf_add_line_verts(GPUIndexBufBuilder *builder, uint v1, uint v2)
132 {
133 #if TRUST_NO_ONE
134   assert(builder->prim_type == GPU_PRIM_LINES);
135   assert(v1 != v2);
136 #endif
137   GPU_indexbuf_add_generic_vert(builder, v1);
138   GPU_indexbuf_add_generic_vert(builder, v2);
139 }
140
141 void GPU_indexbuf_add_tri_verts(GPUIndexBufBuilder *builder, uint v1, uint v2, uint v3)
142 {
143 #if TRUST_NO_ONE
144   assert(builder->prim_type == GPU_PRIM_TRIS);
145   assert(v1 != v2 && v2 != v3 && v3 != v1);
146 #endif
147   GPU_indexbuf_add_generic_vert(builder, v1);
148   GPU_indexbuf_add_generic_vert(builder, v2);
149   GPU_indexbuf_add_generic_vert(builder, v3);
150 }
151
152 void GPU_indexbuf_add_line_adj_verts(
153     GPUIndexBufBuilder *builder, uint v1, uint v2, uint v3, uint v4)
154 {
155 #if TRUST_NO_ONE
156   assert(builder->prim_type == GPU_PRIM_LINES_ADJ);
157   assert(v2 != v3); /* only the line need diff indices */
158 #endif
159   GPU_indexbuf_add_generic_vert(builder, v1);
160   GPU_indexbuf_add_generic_vert(builder, v2);
161   GPU_indexbuf_add_generic_vert(builder, v3);
162   GPU_indexbuf_add_generic_vert(builder, v4);
163 }
164
165 void GPU_indexbuf_set_point_vert(GPUIndexBufBuilder *builder, uint elem, uint v1)
166 {
167   BLI_assert(builder->prim_type == GPU_PRIM_POINTS);
168   BLI_assert(elem < builder->max_index_len);
169   builder->data[elem++] = v1;
170   if (builder->index_len < elem) {
171     builder->index_len = elem;
172   }
173 }
174
175 void GPU_indexbuf_set_line_verts(GPUIndexBufBuilder *builder, uint elem, uint v1, uint v2)
176 {
177   BLI_assert(builder->prim_type == GPU_PRIM_LINES);
178   BLI_assert(v1 != v2);
179   BLI_assert(v1 <= builder->max_allowed_index);
180   BLI_assert(v2 <= builder->max_allowed_index);
181   BLI_assert((elem + 1) * 2 <= builder->max_index_len);
182   uint idx = elem * 2;
183   builder->data[idx++] = v1;
184   builder->data[idx++] = v2;
185   if (builder->index_len < idx) {
186     builder->index_len = idx;
187   }
188 }
189
190 void GPU_indexbuf_set_tri_verts(GPUIndexBufBuilder *builder, uint elem, uint v1, uint v2, uint v3)
191 {
192   BLI_assert(builder->prim_type == GPU_PRIM_TRIS);
193   BLI_assert(v1 != v2 && v2 != v3 && v3 != v1);
194   BLI_assert(v1 <= builder->max_allowed_index);
195   BLI_assert(v2 <= builder->max_allowed_index);
196   BLI_assert(v3 <= builder->max_allowed_index);
197   BLI_assert((elem + 1) * 3 <= builder->max_index_len);
198   uint idx = elem * 3;
199   builder->data[idx++] = v1;
200   builder->data[idx++] = v2;
201   builder->data[idx++] = v3;
202   if (builder->index_len < idx) {
203     builder->index_len = idx;
204   }
205 }
206
207 void GPU_indexbuf_set_point_restart(GPUIndexBufBuilder *builder, uint elem)
208 {
209   BLI_assert(builder->prim_type == GPU_PRIM_POINTS);
210   BLI_assert(elem < builder->max_index_len);
211   builder->data[elem++] = RESTART_INDEX;
212   if (builder->index_len < elem) {
213     builder->index_len = elem;
214   }
215 }
216
217 void GPU_indexbuf_set_line_restart(GPUIndexBufBuilder *builder, uint elem)
218 {
219   BLI_assert(builder->prim_type == GPU_PRIM_LINES);
220   BLI_assert((elem + 1) * 2 <= builder->max_index_len);
221   uint idx = elem * 2;
222   builder->data[idx++] = RESTART_INDEX;
223   builder->data[idx++] = RESTART_INDEX;
224   if (builder->index_len < idx) {
225     builder->index_len = idx;
226   }
227 }
228
229 void GPU_indexbuf_set_tri_restart(GPUIndexBufBuilder *builder, uint elem)
230 {
231   BLI_assert(builder->prim_type == GPU_PRIM_TRIS);
232   BLI_assert((elem + 1) * 3 <= builder->max_index_len);
233   uint idx = elem * 3;
234   builder->data[idx++] = RESTART_INDEX;
235   builder->data[idx++] = RESTART_INDEX;
236   builder->data[idx++] = RESTART_INDEX;
237   if (builder->index_len < idx) {
238     builder->index_len = idx;
239   }
240 }
241
242 GPUIndexBuf *GPU_indexbuf_create_subrange(GPUIndexBuf *elem_src, uint start, uint length)
243 {
244   GPUIndexBuf *elem = MEM_callocN(sizeof(GPUIndexBuf), "GPUIndexBuf");
245   BLI_assert(elem_src && !elem_src->is_subrange);
246   BLI_assert((length == 0) || (start + length <= elem_src->index_len));
247 #if GPU_TRACK_INDEX_RANGE
248   elem->index_type = elem_src->index_type;
249   elem->gl_index_type = elem_src->gl_index_type;
250   elem->base_index = elem_src->base_index;
251 #endif
252   elem->is_subrange = true;
253   elem->src = elem_src;
254   elem->index_start = start;
255   elem->index_len = length;
256   return elem;
257 }
258
259 #if GPU_TRACK_INDEX_RANGE
260 /* Everything remains 32 bit while building to keep things simple.
261  * Find min/max after, then convert to smallest index type possible. */
262
263 static uint index_range(const uint values[], uint value_len, uint *min_out, uint *max_out)
264 {
265   if (value_len == 0) {
266     *min_out = 0;
267     *max_out = 0;
268     return 0;
269   }
270   uint min_value = RESTART_INDEX;
271   uint max_value = 0;
272   for (uint i = 0; i < value_len; i++) {
273     const uint value = values[i];
274     if (value == RESTART_INDEX) {
275       continue;
276     }
277     else if (value < min_value) {
278       min_value = value;
279     }
280     else if (value > max_value) {
281       max_value = value;
282     }
283   }
284   if (min_value == RESTART_INDEX) {
285     *min_out = 0;
286     *max_out = 0;
287     return 0;
288   }
289   else {
290     *min_out = min_value;
291     *max_out = max_value;
292     return max_value - min_value;
293   }
294 }
295
296 static void squeeze_indices_short(GPUIndexBufBuilder *builder,
297                                   GPUIndexBuf *elem,
298                                   uint min_index,
299                                   uint max_index)
300 {
301   const uint *values = builder->data;
302   const uint index_len = elem->index_len;
303
304   /* data will never be *larger* than builder->data...
305    * converting in place to avoid extra allocation */
306   GLushort *data = (GLushort *)builder->data;
307
308   if (max_index >= 0xFFFF) {
309     elem->base_index = min_index;
310     for (uint i = 0; i < index_len; i++) {
311       data[i] = (values[i] == RESTART_INDEX) ? 0xFFFF : (GLushort)(values[i] - min_index);
312     }
313   }
314   else {
315     elem->base_index = 0;
316     for (uint i = 0; i < index_len; i++) {
317       data[i] = (GLushort)(values[i]);
318     }
319   }
320 }
321
322 #endif /* GPU_TRACK_INDEX_RANGE */
323
324 GPUIndexBuf *GPU_indexbuf_build(GPUIndexBufBuilder *builder)
325 {
326   GPUIndexBuf *elem = MEM_callocN(sizeof(GPUIndexBuf), "GPUIndexBuf");
327   GPU_indexbuf_build_in_place(builder, elem);
328   return elem;
329 }
330
331 void GPU_indexbuf_build_in_place(GPUIndexBufBuilder *builder, GPUIndexBuf *elem)
332 {
333 #if TRUST_NO_ONE
334   assert(builder->data != NULL);
335 #endif
336   elem->index_len = builder->index_len;
337   elem->ibo_id = 0; /* Created at first use. */
338
339 #if GPU_TRACK_INDEX_RANGE
340   uint min_index, max_index;
341   uint range = index_range(builder->data, builder->index_len, &min_index, &max_index);
342
343   /* count the primitive restart index. */
344   range += 1;
345
346   if (range <= 0xFFFF) {
347     elem->index_type = GPU_INDEX_U16;
348     squeeze_indices_short(builder, elem, min_index, max_index);
349   }
350   else {
351     elem->index_type = GPU_INDEX_U32;
352     elem->base_index = 0;
353   }
354   elem->gl_index_type = convert_index_type_to_gl(elem->index_type);
355 #endif
356
357   /* Transfer data ownership to GPUIndexBuf.
358    * It will be uploaded upon first use. */
359   elem->data = builder->data;
360   builder->data = NULL;
361   /* other fields are safe to leave */
362 }
363
364 static void indexbuf_upload_data(GPUIndexBuf *elem)
365 {
366   /* send data to GPU */
367   glBufferData(GL_ELEMENT_ARRAY_BUFFER, GPU_indexbuf_size_get(elem), elem->data, GL_STATIC_DRAW);
368   /* No need to keep copy of data in system memory. */
369   MEM_freeN(elem->data);
370   elem->data = NULL;
371 }
372
373 void GPU_indexbuf_use(GPUIndexBuf *elem)
374 {
375   if (elem->is_subrange) {
376     GPU_indexbuf_use(elem->src);
377     return;
378   }
379   if (elem->ibo_id == 0) {
380     elem->ibo_id = GPU_buf_alloc();
381   }
382   glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elem->ibo_id);
383   if (elem->data != NULL) {
384     indexbuf_upload_data(elem);
385   }
386 }
387
388 void GPU_indexbuf_discard(GPUIndexBuf *elem)
389 {
390   if (elem->ibo_id) {
391     GPU_buf_free(elem->ibo_id);
392   }
393   if (!elem->is_subrange && elem->data) {
394     MEM_freeN(elem->data);
395   }
396   MEM_freeN(elem);
397 }