Merge branch 'master' into blender2.8
[blender.git] / source / blender / gpu / intern / gpu_element.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2016 by Mike Erwin.
19  * All rights reserved.
20  *
21  * Contributor(s): Blender Foundation
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/gpu/intern/gpu_element.c
27  *  \ingroup gpu
28  *
29  * GPU element list (AKA index buffer)
30  */
31
32 #include "MEM_guardedalloc.h"
33
34 #include "GPU_element.h"
35
36 #include "gpu_context_private.h"
37
38 #include <stdlib.h>
39
40 #define KEEP_SINGLE_COPY 1
41
42 static GLenum convert_index_type_to_gl(GPUIndexBufType type)
43 {
44         static const GLenum table[] = {
45                 [GPU_INDEX_U8] = GL_UNSIGNED_BYTE, /* GL has this, Vulkan does not */
46                 [GPU_INDEX_U16] = GL_UNSIGNED_SHORT,
47                 [GPU_INDEX_U32] = GL_UNSIGNED_INT
48         };
49         return table[type];
50 }
51
52 uint GPU_indexbuf_size_get(const GPUIndexBuf *elem)
53 {
54 #if GPU_TRACK_INDEX_RANGE
55         static const uint table[] = {
56                 [GPU_INDEX_U8] = sizeof(GLubyte), /* GL has this, Vulkan does not */
57                 [GPU_INDEX_U16] = sizeof(GLushort),
58                 [GPU_INDEX_U32] = sizeof(GLuint)
59         };
60         return elem->index_len * table[elem->index_type];
61 #else
62         return elem->index_len * sizeof(GLuint);
63 #endif
64 }
65
66 int GPU_indexbuf_primitive_len(GPUPrimType prim_type)
67 {
68         switch (prim_type) {
69                 case GPU_PRIM_POINTS:
70                         return 1;
71                 case GPU_PRIM_LINES:
72                         return 2;
73                 case GPU_PRIM_TRIS:
74                         return 3;
75                 case GPU_PRIM_LINES_ADJ:
76                         return 4;
77                 default:
78                         break;
79         }
80 #if TRUST_NO_ONE
81         assert(false);
82 #endif
83         return -1;
84 }
85
86 void GPU_indexbuf_init_ex(
87         GPUIndexBufBuilder *builder, GPUPrimType prim_type,
88         uint index_len, uint vertex_len, bool use_prim_restart)
89 {
90         builder->use_prim_restart = use_prim_restart;
91         builder->max_allowed_index = vertex_len - 1;
92         builder->max_index_len = index_len;
93         builder->index_len = 0; // start empty
94         builder->prim_type = prim_type;
95         builder->data = MEM_callocN(builder->max_index_len * sizeof(uint), "GPUIndexBuf data");
96 }
97
98 void GPU_indexbuf_init(GPUIndexBufBuilder *builder, GPUPrimType prim_type, uint prim_len, uint vertex_len)
99 {
100         int verts_per_prim = GPU_indexbuf_primitive_len(prim_type);
101 #if TRUST_NO_ONE
102         assert(verts_per_prim != -1);
103 #endif
104         GPU_indexbuf_init_ex(builder, prim_type, prim_len * (uint)verts_per_prim, vertex_len, false);
105 }
106
107 void GPU_indexbuf_add_generic_vert(GPUIndexBufBuilder *builder, uint v)
108 {
109 #if TRUST_NO_ONE
110         assert(builder->data != NULL);
111         assert(builder->index_len < builder->max_index_len);
112         assert(v <= builder->max_allowed_index);
113 #endif
114         builder->data[builder->index_len++] = v;
115 }
116
117 void GPU_indexbuf_add_primitive_restart(GPUIndexBufBuilder *builder)
118 {
119 #if TRUST_NO_ONE
120         assert(builder->data != NULL);
121         assert(builder->index_len < builder->max_index_len);
122         assert(builder->use_prim_restart);
123 #endif
124         builder->data[builder->index_len++] = GPU_PRIM_RESTART;
125 }
126
127 void GPU_indexbuf_add_point_vert(GPUIndexBufBuilder *builder, uint v)
128 {
129 #if TRUST_NO_ONE
130         assert(builder->prim_type == GPU_PRIM_POINTS);
131 #endif
132         GPU_indexbuf_add_generic_vert(builder, v);
133 }
134
135 void GPU_indexbuf_add_line_verts(GPUIndexBufBuilder *builder, uint v1, uint v2)
136 {
137 #if TRUST_NO_ONE
138         assert(builder->prim_type == GPU_PRIM_LINES);
139         assert(v1 != v2);
140 #endif
141         GPU_indexbuf_add_generic_vert(builder, v1);
142         GPU_indexbuf_add_generic_vert(builder, v2);
143 }
144
145 void GPU_indexbuf_add_tri_verts(GPUIndexBufBuilder *builder, uint v1, uint v2, uint v3)
146 {
147 #if TRUST_NO_ONE
148         assert(builder->prim_type == GPU_PRIM_TRIS);
149         assert(v1 != v2 && v2 != v3 && v3 != v1);
150 #endif
151         GPU_indexbuf_add_generic_vert(builder, v1);
152         GPU_indexbuf_add_generic_vert(builder, v2);
153         GPU_indexbuf_add_generic_vert(builder, v3);
154 }
155
156 void GPU_indexbuf_add_line_adj_verts(GPUIndexBufBuilder *builder, uint v1, uint v2, uint v3, uint v4)
157 {
158 #if TRUST_NO_ONE
159         assert(builder->prim_type == GPU_PRIM_LINES_ADJ);
160         assert(v2 != v3); /* only the line need diff indices */
161 #endif
162         GPU_indexbuf_add_generic_vert(builder, v1);
163         GPU_indexbuf_add_generic_vert(builder, v2);
164         GPU_indexbuf_add_generic_vert(builder, v3);
165         GPU_indexbuf_add_generic_vert(builder, v4);
166 }
167
168 #if GPU_TRACK_INDEX_RANGE
169 /* Everything remains 32 bit while building to keep things simple.
170  * Find min/max after, then convert to smallest index type possible. */
171
172 static uint index_range(const uint values[], uint value_len, uint *min_out, uint *max_out)
173 {
174         if (value_len == 0) {
175                 *min_out = 0;
176                 *max_out = 0;
177                 return 0;
178         }
179         uint min_value = values[0];
180         uint max_value = values[0];
181         for (uint i = 1; i < value_len; ++i) {
182                 const uint value = values[i];
183                 if (value == GPU_PRIM_RESTART)
184                         continue;
185                 else if (value < min_value)
186                         min_value = value;
187                 else if (value > max_value)
188                         max_value = value;
189         }
190         *min_out = min_value;
191         *max_out = max_value;
192         return max_value - min_value;
193 }
194
195 static void squeeze_indices_byte(GPUIndexBufBuilder *builder, GPUIndexBuf *elem)
196 {
197         const uint *values = builder->data;
198         const uint index_len = elem->index_len;
199
200         /* data will never be *larger* than builder->data...
201          * converting in place to avoid extra allocation */
202         GLubyte *data = (GLubyte *)builder->data;
203
204         if (elem->max_index > 0xFF) {
205                 const uint base = elem->min_index;
206                 elem->base_index = base;
207                 elem->min_index = 0;
208                 elem->max_index -= base;
209                 for (uint i = 0; i < index_len; ++i) {
210                         data[i] = (values[i] == GPU_PRIM_RESTART) ? 0xFF : (GLubyte)(values[i] - base);
211                 }
212         }
213         else {
214                 elem->base_index = 0;
215                 for (uint i = 0; i < index_len; ++i) {
216                         data[i] = (GLubyte)(values[i]);
217                 }
218         }
219 }
220
221 static void squeeze_indices_short(GPUIndexBufBuilder *builder, GPUIndexBuf *elem)
222 {
223         const uint *values = builder->data;
224         const uint index_len = elem->index_len;
225
226         /* data will never be *larger* than builder->data...
227          * converting in place to avoid extra allocation */
228         GLushort *data = (GLushort *)builder->data;
229
230         if (elem->max_index > 0xFFFF) {
231                 const uint base = elem->min_index;
232                 elem->base_index = base;
233                 elem->min_index = 0;
234                 elem->max_index -= base;
235                 for (uint i = 0; i < index_len; ++i) {
236                         data[i] = (values[i] == GPU_PRIM_RESTART) ? 0xFFFF : (GLushort)(values[i] - base);
237                 }
238         }
239         else {
240                 elem->base_index = 0;
241                 for (uint i = 0; i < index_len; ++i) {
242                         data[i] = (GLushort)(values[i]);
243                 }
244         }
245 }
246
247 #endif /* GPU_TRACK_INDEX_RANGE */
248
249 GPUIndexBuf *GPU_indexbuf_build(GPUIndexBufBuilder *builder)
250 {
251         GPUIndexBuf *elem = MEM_callocN(sizeof(GPUIndexBuf), "GPUIndexBuf");
252         GPU_indexbuf_build_in_place(builder, elem);
253         return elem;
254 }
255
256 void GPU_indexbuf_build_in_place(GPUIndexBufBuilder *builder, GPUIndexBuf *elem)
257 {
258 #if TRUST_NO_ONE
259         assert(builder->data != NULL);
260 #endif
261         elem->index_len = builder->index_len;
262         elem->use_prim_restart = builder->use_prim_restart;
263         elem->ibo_id = 0; /* Created at first use. */
264
265 #if GPU_TRACK_INDEX_RANGE
266         uint range = index_range(builder->data, builder->index_len, &elem->min_index, &elem->max_index);
267
268         /* count the primitive restart index. */
269         if (elem->use_prim_restart) {
270                 range += 1;
271         }
272
273         if (range <= 0xFF) {
274                 elem->index_type = GPU_INDEX_U8;
275                 squeeze_indices_byte(builder, elem);
276         }
277         else if (range <= 0xFFFF) {
278                 elem->index_type = GPU_INDEX_U16;
279                 squeeze_indices_short(builder, elem);
280         }
281         else {
282                 elem->index_type = GPU_INDEX_U32;
283                 elem->base_index = 0;
284         }
285         elem->gl_index_type = convert_index_type_to_gl(elem->index_type);
286 #endif
287
288         /* Transfer data ownership to GPUIndexBuf.
289          * It will be uploaded upon first use. */
290         elem->data = builder->data;
291         builder->data = NULL;
292         /* other fields are safe to leave */
293 }
294
295 static void indexbuf_upload_data(GPUIndexBuf *elem)
296 {
297         /* send data to GPU */
298         glBufferData(GL_ELEMENT_ARRAY_BUFFER, GPU_indexbuf_size_get(elem), elem->data, GL_STATIC_DRAW);
299         /* No need to keep copy of data in system memory. */
300         MEM_freeN(elem->data);
301         elem->data = NULL;
302 }
303
304 void GPU_indexbuf_use(GPUIndexBuf *elem)
305 {
306         if (elem->ibo_id == 0) {
307                 elem->ibo_id = GPU_buf_alloc();
308         }
309         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elem->ibo_id);
310         if (elem->data != NULL) {
311                 indexbuf_upload_data(elem);
312         }
313 }
314
315 void GPU_indexbuf_discard(GPUIndexBuf *elem)
316 {
317         if (elem->ibo_id) {
318                 GPU_buf_free(elem->ibo_id);
319         }
320         if (elem->data) {
321                 MEM_freeN(elem->data);
322         }
323         MEM_freeN(elem);
324 }