Fix build errors
[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 static GLenum convert_index_type_to_gl(GPUIndexBufType type)
37 {
38         static const GLenum table[] = {
39                 [GPU_INDEX_U8] = GL_UNSIGNED_BYTE, /* GL has this, Vulkan does not */
40                 [GPU_INDEX_U16] = GL_UNSIGNED_SHORT,
41                 [GPU_INDEX_U32] = GL_UNSIGNED_INT,
42         };
43         return table[type];
44 }
45
46 uint GPU_indexbuf_size_get(const GPUIndexBuf *elem)
47 {
48 #if GPU_TRACK_INDEX_RANGE
49         static const uint table[] = {
50                 [GPU_INDEX_U8] = sizeof(GLubyte), /* GL has this, Vulkan does not */
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(
81         GPUIndexBufBuilder *builder, GPUPrimType prim_type,
82         uint index_len, uint vertex_len, bool use_prim_restart)
83 {
84         builder->use_prim_restart = use_prim_restart;
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, GPUPrimType prim_type, uint prim_len, uint vertex_len)
93 {
94         int verts_per_prim = GPU_indexbuf_primitive_len(prim_type);
95 #if TRUST_NO_ONE
96         assert(verts_per_prim != -1);
97 #endif
98         GPU_indexbuf_init_ex(builder, prim_type, prim_len * (uint)verts_per_prim, vertex_len, false);
99 }
100
101 void GPU_indexbuf_add_generic_vert(GPUIndexBufBuilder *builder, uint v)
102 {
103 #if TRUST_NO_ONE
104         assert(builder->data != NULL);
105         assert(builder->index_len < builder->max_index_len);
106         assert(v <= builder->max_allowed_index);
107 #endif
108         builder->data[builder->index_len++] = v;
109 }
110
111 void GPU_indexbuf_add_primitive_restart(GPUIndexBufBuilder *builder)
112 {
113 #if TRUST_NO_ONE
114         assert(builder->data != NULL);
115         assert(builder->index_len < builder->max_index_len);
116         assert(builder->use_prim_restart);
117 #endif
118         builder->data[builder->index_len++] = GPU_PRIM_RESTART;
119 }
120
121 void GPU_indexbuf_add_point_vert(GPUIndexBufBuilder *builder, uint v)
122 {
123 #if TRUST_NO_ONE
124         assert(builder->prim_type == GPU_PRIM_POINTS);
125 #endif
126         GPU_indexbuf_add_generic_vert(builder, v);
127 }
128
129 void GPU_indexbuf_add_line_verts(GPUIndexBufBuilder *builder, uint v1, uint v2)
130 {
131 #if TRUST_NO_ONE
132         assert(builder->prim_type == GPU_PRIM_LINES);
133         assert(v1 != v2);
134 #endif
135         GPU_indexbuf_add_generic_vert(builder, v1);
136         GPU_indexbuf_add_generic_vert(builder, v2);
137 }
138
139 void GPU_indexbuf_add_tri_verts(GPUIndexBufBuilder *builder, uint v1, uint v2, uint v3)
140 {
141 #if TRUST_NO_ONE
142         assert(builder->prim_type == GPU_PRIM_TRIS);
143         assert(v1 != v2 && v2 != v3 && v3 != v1);
144 #endif
145         GPU_indexbuf_add_generic_vert(builder, v1);
146         GPU_indexbuf_add_generic_vert(builder, v2);
147         GPU_indexbuf_add_generic_vert(builder, v3);
148 }
149
150 void GPU_indexbuf_add_line_adj_verts(GPUIndexBufBuilder *builder, uint v1, uint v2, uint v3, uint v4)
151 {
152 #if TRUST_NO_ONE
153         assert(builder->prim_type == GPU_PRIM_LINES_ADJ);
154         assert(v2 != v3); /* only the line need diff indices */
155 #endif
156         GPU_indexbuf_add_generic_vert(builder, v1);
157         GPU_indexbuf_add_generic_vert(builder, v2);
158         GPU_indexbuf_add_generic_vert(builder, v3);
159         GPU_indexbuf_add_generic_vert(builder, v4);
160 }
161
162 #if GPU_TRACK_INDEX_RANGE
163 /* Everything remains 32 bit while building to keep things simple.
164  * Find min/max after, then convert to smallest index type possible. */
165
166 static uint index_range(const uint values[], uint value_len, uint *min_out, uint *max_out)
167 {
168         if (value_len == 0) {
169                 *min_out = 0;
170                 *max_out = 0;
171                 return 0;
172         }
173         uint min_value = values[0];
174         uint max_value = values[0];
175         for (uint i = 1; i < value_len; ++i) {
176                 const uint value = values[i];
177                 if (value == GPU_PRIM_RESTART)
178                         continue;
179                 else if (value < min_value)
180                         min_value = value;
181                 else if (value > max_value)
182                         max_value = value;
183         }
184         *min_out = min_value;
185         *max_out = max_value;
186         return max_value - min_value;
187 }
188
189 static void squeeze_indices_byte(GPUIndexBufBuilder *builder, GPUIndexBuf *elem)
190 {
191         const uint *values = builder->data;
192         const uint index_len = elem->index_len;
193
194         /* data will never be *larger* than builder->data...
195          * converting in place to avoid extra allocation */
196         GLubyte *data = (GLubyte *)builder->data;
197
198         if (elem->max_index > 0xFF) {
199                 const uint base = elem->min_index;
200                 elem->base_index = base;
201                 elem->min_index = 0;
202                 elem->max_index -= base;
203                 for (uint i = 0; i < index_len; ++i) {
204                         data[i] = (values[i] == GPU_PRIM_RESTART) ? 0xFF : (GLubyte)(values[i] - base);
205                 }
206         }
207         else {
208                 elem->base_index = 0;
209                 for (uint i = 0; i < index_len; ++i) {
210                         data[i] = (GLubyte)(values[i]);
211                 }
212         }
213 }
214
215 static void squeeze_indices_short(GPUIndexBufBuilder *builder, GPUIndexBuf *elem)
216 {
217         const uint *values = builder->data;
218         const uint index_len = elem->index_len;
219
220         /* data will never be *larger* than builder->data...
221          * converting in place to avoid extra allocation */
222         GLushort *data = (GLushort *)builder->data;
223
224         if (elem->max_index > 0xFFFF) {
225                 const uint base = elem->min_index;
226                 elem->base_index = base;
227                 elem->min_index = 0;
228                 elem->max_index -= base;
229                 for (uint i = 0; i < index_len; ++i) {
230                         data[i] = (values[i] == GPU_PRIM_RESTART) ? 0xFFFF : (GLushort)(values[i] - base);
231                 }
232         }
233         else {
234                 elem->base_index = 0;
235                 for (uint i = 0; i < index_len; ++i) {
236                         data[i] = (GLushort)(values[i]);
237                 }
238         }
239 }
240
241 #endif /* GPU_TRACK_INDEX_RANGE */
242
243 GPUIndexBuf *GPU_indexbuf_build(GPUIndexBufBuilder *builder)
244 {
245         GPUIndexBuf *elem = MEM_callocN(sizeof(GPUIndexBuf), "GPUIndexBuf");
246         GPU_indexbuf_build_in_place(builder, elem);
247         return elem;
248 }
249
250 void GPU_indexbuf_build_in_place(GPUIndexBufBuilder *builder, GPUIndexBuf *elem)
251 {
252 #if TRUST_NO_ONE
253         assert(builder->data != NULL);
254 #endif
255         elem->index_len = builder->index_len;
256         elem->use_prim_restart = builder->use_prim_restart;
257         elem->ibo_id = 0; /* Created at first use. */
258
259 #if GPU_TRACK_INDEX_RANGE
260         uint range = index_range(builder->data, builder->index_len, &elem->min_index, &elem->max_index);
261
262         /* count the primitive restart index. */
263         if (elem->use_prim_restart) {
264                 range += 1;
265         }
266
267         if (range <= 0xFF) {
268                 elem->index_type = GPU_INDEX_U8;
269                 squeeze_indices_byte(builder, elem);
270         }
271         else if (range <= 0xFFFF) {
272                 elem->index_type = GPU_INDEX_U16;
273                 squeeze_indices_short(builder, elem);
274         }
275         else {
276                 elem->index_type = GPU_INDEX_U32;
277                 elem->base_index = 0;
278         }
279         elem->gl_index_type = convert_index_type_to_gl(elem->index_type);
280 #endif
281
282         /* Transfer data ownership to GPUIndexBuf.
283          * It will be uploaded upon first use. */
284         elem->data = builder->data;
285         builder->data = NULL;
286         /* other fields are safe to leave */
287 }
288
289 static void indexbuf_upload_data(GPUIndexBuf *elem)
290 {
291         /* send data to GPU */
292         glBufferData(GL_ELEMENT_ARRAY_BUFFER, GPU_indexbuf_size_get(elem), elem->data, GL_STATIC_DRAW);
293         /* No need to keep copy of data in system memory. */
294         MEM_freeN(elem->data);
295         elem->data = NULL;
296 }
297
298 void GPU_indexbuf_use(GPUIndexBuf *elem)
299 {
300         if (elem->ibo_id == 0) {
301                 elem->ibo_id = GPU_buf_alloc();
302         }
303         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elem->ibo_id);
304         if (elem->data != NULL) {
305                 indexbuf_upload_data(elem);
306         }
307 }
308
309 void GPU_indexbuf_discard(GPUIndexBuf *elem)
310 {
311         if (elem->ibo_id) {
312                 GPU_buf_free(elem->ibo_id);
313         }
314         if (elem->data) {
315                 MEM_freeN(elem->data);
316         }
317         MEM_freeN(elem);
318 }