Fix build errors
[blender.git] / source / blender / gpu / intern / gpu_vertex_buffer.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 vertex buffer
24  */
25
26 #include "MEM_guardedalloc.h"
27
28 #include "GPU_vertex_buffer.h"
29
30 #include "gpu_context_private.h"
31 #include "gpu_vertex_format_private.h"
32
33 #include <stdlib.h>
34 #include <string.h>
35
36 #define KEEP_SINGLE_COPY 1
37
38 static uint vbo_memory_usage;
39
40 static GLenum convert_usage_type_to_gl(GPUUsageType type)
41 {
42         static const GLenum table[] = {
43                 [GPU_USAGE_STREAM] = GL_STREAM_DRAW,
44                 [GPU_USAGE_STATIC] = GL_STATIC_DRAW,
45                 [GPU_USAGE_DYNAMIC] = GL_DYNAMIC_DRAW,
46         };
47         return table[type];
48 }
49
50 GPUVertBuf *GPU_vertbuf_create(GPUUsageType usage)
51 {
52         GPUVertBuf *verts = MEM_mallocN(sizeof(GPUVertBuf), "GPUVertBuf");
53         GPU_vertbuf_init(verts, usage);
54         return verts;
55 }
56
57 GPUVertBuf *GPU_vertbuf_create_with_format_ex(const GPUVertFormat *format, GPUUsageType usage)
58 {
59         GPUVertBuf *verts = GPU_vertbuf_create(usage);
60         GPU_vertformat_copy(&verts->format, format);
61         if (!format->packed) {
62                 VertexFormat_pack(&verts->format);
63         }
64         return verts;
65
66         /* this function might seem redundant, but there is potential for memory savings here... */
67         /* TODO: implement those memory savings */
68 }
69
70 void GPU_vertbuf_init(GPUVertBuf *verts, GPUUsageType usage)
71 {
72         memset(verts, 0, sizeof(GPUVertBuf));
73         verts->usage = usage;
74         verts->dirty = true;
75 }
76
77 void GPU_vertbuf_init_with_format_ex(GPUVertBuf *verts, const GPUVertFormat *format, GPUUsageType usage)
78 {
79         GPU_vertbuf_init(verts, usage);
80         GPU_vertformat_copy(&verts->format, format);
81         if (!format->packed) {
82                 VertexFormat_pack(&verts->format);
83         }
84 }
85
86 void GPU_vertbuf_discard(GPUVertBuf *verts)
87 {
88         if (verts->vbo_id) {
89                 GPU_buf_free(verts->vbo_id);
90 #if VRAM_USAGE
91                 vbo_memory_usage -= GPU_vertbuf_size_get(verts);
92 #endif
93         }
94         if (verts->data) {
95                 MEM_freeN(verts->data);
96         }
97         MEM_freeN(verts);
98 }
99
100 uint GPU_vertbuf_size_get(const GPUVertBuf *verts)
101 {
102         return vertex_buffer_size(&verts->format, verts->vertex_len);
103 }
104
105 /* create a new allocation, discarding any existing data */
106 void GPU_vertbuf_data_alloc(GPUVertBuf *verts, uint v_len)
107 {
108         GPUVertFormat *format = &verts->format;
109         if (!format->packed) {
110                 VertexFormat_pack(format);
111         }
112 #if TRUST_NO_ONE
113         /* catch any unnecessary use */
114         assert(verts->vertex_alloc != v_len || verts->data == NULL);
115 #endif
116         /* discard previous data if any */
117         if (verts->data) {
118                 MEM_freeN(verts->data);
119         }
120 #if VRAM_USAGE
121         uint new_size = vertex_buffer_size(&verts->format, v_len);
122         vbo_memory_usage += new_size - GPU_vertbuf_size_get(verts);
123 #endif
124         verts->dirty = true;
125         verts->vertex_len = verts->vertex_alloc = v_len;
126         verts->data = MEM_mallocN(sizeof(GLubyte) * GPU_vertbuf_size_get(verts), "GPUVertBuf data");
127 }
128
129 /* resize buffer keeping existing data */
130 void GPU_vertbuf_data_resize(GPUVertBuf *verts, uint v_len)
131 {
132 #if TRUST_NO_ONE
133         assert(verts->data != NULL);
134         assert(verts->vertex_alloc != v_len);
135 #endif
136
137 #if VRAM_USAGE
138         uint new_size = vertex_buffer_size(&verts->format, v_len);
139         vbo_memory_usage += new_size - GPU_vertbuf_size_get(verts);
140 #endif
141         verts->dirty = true;
142         verts->vertex_len = verts->vertex_alloc = v_len;
143         verts->data = MEM_reallocN(verts->data, sizeof(GLubyte) * GPU_vertbuf_size_get(verts));
144 }
145
146 /* Set vertex count but does not change allocation.
147  * Only this many verts will be uploaded to the GPU and rendered.
148  * This is useful for streaming data. */
149 void GPU_vertbuf_data_len_set(GPUVertBuf *verts, uint v_len)
150 {
151 #if TRUST_NO_ONE
152         assert(verts->data != NULL); /* only for dynamic data */
153         assert(v_len <= verts->vertex_alloc);
154 #endif
155
156 #if VRAM_USAGE
157         uint new_size = vertex_buffer_size(&verts->format, v_len);
158         vbo_memory_usage += new_size - GPU_vertbuf_size_get(verts);
159 #endif
160         verts->vertex_len = v_len;
161 }
162
163 void GPU_vertbuf_attr_set(GPUVertBuf *verts, uint a_idx, uint v_idx, const void *data)
164 {
165         const GPUVertFormat *format = &verts->format;
166         const GPUVertAttr *a = &format->attrs[a_idx];
167
168 #if TRUST_NO_ONE
169         assert(a_idx < format->attr_len);
170         assert(v_idx < verts->vertex_alloc);
171         assert(verts->data != NULL);
172 #endif
173         verts->dirty = true;
174         memcpy((GLubyte *)verts->data + a->offset + v_idx * format->stride, data, a->sz);
175 }
176
177 void GPU_vertbuf_attr_fill(GPUVertBuf *verts, uint a_idx, const void *data)
178 {
179         const GPUVertFormat *format = &verts->format;
180         const GPUVertAttr *a = &format->attrs[a_idx];
181
182 #if TRUST_NO_ONE
183         assert(a_idx < format->attr_len);
184 #endif
185         const uint stride = a->sz; /* tightly packed input data */
186
187         GPU_vertbuf_attr_fill_stride(verts, a_idx, stride, data);
188 }
189
190 void GPU_vertbuf_attr_fill_stride(GPUVertBuf *verts, uint a_idx, uint stride, const void *data)
191 {
192         const GPUVertFormat *format = &verts->format;
193         const GPUVertAttr *a = &format->attrs[a_idx];
194
195 #if TRUST_NO_ONE
196         assert(a_idx < format->attr_len);
197         assert(verts->data != NULL);
198 #endif
199         verts->dirty = true;
200         const uint vertex_len = verts->vertex_len;
201
202         if (format->attr_len == 1 && stride == format->stride) {
203                 /* we can copy it all at once */
204                 memcpy(verts->data, data, vertex_len * a->sz);
205         }
206         else {
207                 /* we must copy it per vertex */
208                 for (uint v = 0; v < vertex_len; ++v) {
209                         memcpy((GLubyte *)verts->data + a->offset + v * format->stride, (const GLubyte *)data + v * stride, a->sz);
210                 }
211         }
212 }
213
214 void GPU_vertbuf_attr_get_raw_data(GPUVertBuf *verts, uint a_idx, GPUVertBufRaw *access)
215 {
216         const GPUVertFormat *format = &verts->format;
217         const GPUVertAttr *a = &format->attrs[a_idx];
218
219 #if TRUST_NO_ONE
220         assert(a_idx < format->attr_len);
221         assert(verts->data != NULL);
222 #endif
223
224         verts->dirty = true;
225
226         access->size = a->sz;
227         access->stride = format->stride;
228         access->data = (GLubyte *)verts->data + a->offset;
229         access->data_init = access->data;
230 #if TRUST_NO_ONE
231         access->_data_end = access->data_init + (size_t)(verts->vertex_alloc * format->stride);
232 #endif
233 }
234
235 static void VertBuffer_upload_data(GPUVertBuf *verts)
236 {
237         uint buffer_sz = GPU_vertbuf_size_get(verts);
238
239         /* orphan the vbo to avoid sync */
240         glBufferData(GL_ARRAY_BUFFER, buffer_sz, NULL, convert_usage_type_to_gl(verts->usage));
241         /* upload data */
242         glBufferSubData(GL_ARRAY_BUFFER, 0, buffer_sz, verts->data);
243
244         if (verts->usage == GPU_USAGE_STATIC) {
245                 MEM_freeN(verts->data);
246                 verts->data = NULL;
247         }
248         verts->dirty = false;
249 }
250
251 void GPU_vertbuf_use(GPUVertBuf *verts)
252 {
253         /* only create the buffer the 1st time */
254         if (verts->vbo_id == 0) {
255                 verts->vbo_id = GPU_buf_alloc();
256         }
257         glBindBuffer(GL_ARRAY_BUFFER, verts->vbo_id);
258         if (verts->dirty) {
259                 VertBuffer_upload_data(verts);
260         }
261 }
262
263 uint GPU_vertbuf_get_memory_usage(void)
264 {
265         return vbo_memory_usage;
266 }