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_backend.hh"
29 #include "gpu_vertex_format_private.h"
30
31 #include "gl_vertex_buffer.hh" /* TODO remove */
32 #include "gpu_context_private.hh" /* TODO remove */
33
34 #include "gpu_vertex_buffer_private.hh"
35
36 #include <cstring>
37
38 /* -------------------------------------------------------------------- */
39 /** \name VertBuf
40 * \{ */
41
42 namespace blender::gpu {
43
44 size_t VertBuf::memory_usage = 0;
45
VertBuf()46 VertBuf::VertBuf()
47 {
48 /* Needed by some code check. */
49 format.attr_len = 0;
50 }
51
~VertBuf()52 VertBuf::~VertBuf()
53 {
54 /* Should already have been cleared. */
55 BLI_assert(flag == GPU_VERTBUF_INVALID);
56 }
57
init(const GPUVertFormat * format,GPUUsageType usage)58 void VertBuf::init(const GPUVertFormat *format, GPUUsageType usage)
59 {
60 usage_ = usage;
61 flag = GPU_VERTBUF_DATA_DIRTY;
62 GPU_vertformat_copy(&this->format, format);
63 if (!format->packed) {
64 VertexFormat_pack(&this->format);
65 }
66 flag |= GPU_VERTBUF_INIT;
67 }
68
clear(void)69 void VertBuf::clear(void)
70 {
71 this->release_data();
72 flag = GPU_VERTBUF_INVALID;
73 }
74
duplicate(void)75 VertBuf *VertBuf::duplicate(void)
76 {
77 VertBuf *dst = GPUBackend::get()->vertbuf_alloc();
78 /* Full copy. */
79 *dst = *this;
80 /* Almost full copy... */
81 dst->handle_refcount_ = 1;
82 /* Duplicate all needed implementation specifics data. */
83 this->duplicate_data(dst);
84 return dst;
85 }
86
allocate(uint vert_len)87 void VertBuf::allocate(uint vert_len)
88 {
89 BLI_assert(format.packed);
90 /* Catch any unnecessary usage. */
91 BLI_assert(vertex_alloc != vert_len || data == nullptr);
92 vertex_len = vertex_alloc = vert_len;
93
94 this->acquire_data();
95
96 flag |= GPU_VERTBUF_DATA_DIRTY;
97 }
98
resize(uint vert_len)99 void VertBuf::resize(uint vert_len)
100 {
101 /* Catch any unnecessary usage. */
102 BLI_assert(vertex_alloc != vert_len);
103 vertex_len = vertex_alloc = vert_len;
104
105 this->resize_data();
106
107 flag |= GPU_VERTBUF_DATA_DIRTY;
108 }
109
upload(void)110 void VertBuf::upload(void)
111 {
112 this->upload_data();
113 }
114
115 } // namespace blender::gpu
116
117 /** \} */
118
119 /* -------------------------------------------------------------------- */
120 /** \name C-API
121 * \{ */
122
123 using namespace blender;
124 using namespace blender::gpu;
125
126 /* -------- Creation & deletion -------- */
127
GPU_vertbuf_calloc(void)128 GPUVertBuf *GPU_vertbuf_calloc(void)
129 {
130 return wrap(GPUBackend::get()->vertbuf_alloc());
131 }
132
GPU_vertbuf_create_with_format_ex(const GPUVertFormat * format,GPUUsageType usage)133 GPUVertBuf *GPU_vertbuf_create_with_format_ex(const GPUVertFormat *format, GPUUsageType usage)
134 {
135 GPUVertBuf *verts = GPU_vertbuf_calloc();
136 unwrap(verts)->init(format, usage);
137 return verts;
138 }
139
GPU_vertbuf_init_with_format_ex(GPUVertBuf * verts_,const GPUVertFormat * format,GPUUsageType usage)140 void GPU_vertbuf_init_with_format_ex(GPUVertBuf *verts_,
141 const GPUVertFormat *format,
142 GPUUsageType usage)
143 {
144 unwrap(verts_)->init(format, usage);
145 }
146
GPU_vertbuf_duplicate(GPUVertBuf * verts_)147 GPUVertBuf *GPU_vertbuf_duplicate(GPUVertBuf *verts_)
148 {
149 return wrap(unwrap(verts_)->duplicate());
150 }
151
152 /** Same as discard but does not free. */
GPU_vertbuf_clear(GPUVertBuf * verts)153 void GPU_vertbuf_clear(GPUVertBuf *verts)
154 {
155 unwrap(verts)->clear();
156 }
157
GPU_vertbuf_discard(GPUVertBuf * verts)158 void GPU_vertbuf_discard(GPUVertBuf *verts)
159 {
160 unwrap(verts)->clear();
161 unwrap(verts)->reference_remove();
162 }
163
GPU_vertbuf_handle_ref_add(GPUVertBuf * verts)164 void GPU_vertbuf_handle_ref_add(GPUVertBuf *verts)
165 {
166 unwrap(verts)->reference_add();
167 }
168
GPU_vertbuf_handle_ref_remove(GPUVertBuf * verts)169 void GPU_vertbuf_handle_ref_remove(GPUVertBuf *verts)
170 {
171 unwrap(verts)->reference_remove();
172 }
173
174 /* -------- Data update -------- */
175
176 /* create a new allocation, discarding any existing data */
GPU_vertbuf_data_alloc(GPUVertBuf * verts,uint v_len)177 void GPU_vertbuf_data_alloc(GPUVertBuf *verts, uint v_len)
178 {
179 unwrap(verts)->allocate(v_len);
180 }
181
182 /* resize buffer keeping existing data */
GPU_vertbuf_data_resize(GPUVertBuf * verts,uint v_len)183 void GPU_vertbuf_data_resize(GPUVertBuf *verts, uint v_len)
184 {
185 unwrap(verts)->resize(v_len);
186 }
187
188 /* Set vertex count but does not change allocation.
189 * Only this many verts will be uploaded to the GPU and rendered.
190 * This is useful for streaming data. */
GPU_vertbuf_data_len_set(GPUVertBuf * verts_,uint v_len)191 void GPU_vertbuf_data_len_set(GPUVertBuf *verts_, uint v_len)
192 {
193 VertBuf *verts = unwrap(verts_);
194 BLI_assert(verts->data != NULL); /* Only for dynamic data. */
195 BLI_assert(v_len <= verts->vertex_alloc);
196 verts->vertex_len = v_len;
197 }
198
GPU_vertbuf_attr_set(GPUVertBuf * verts_,uint a_idx,uint v_idx,const void * data)199 void GPU_vertbuf_attr_set(GPUVertBuf *verts_, uint a_idx, uint v_idx, const void *data)
200 {
201 VertBuf *verts = unwrap(verts_);
202 const GPUVertFormat *format = &verts->format;
203 const GPUVertAttr *a = &format->attrs[a_idx];
204 BLI_assert(v_idx < verts->vertex_alloc);
205 BLI_assert(a_idx < format->attr_len);
206 BLI_assert(verts->data != NULL);
207 verts->flag |= GPU_VERTBUF_DATA_DIRTY;
208 memcpy(verts->data + a->offset + v_idx * format->stride, data, a->sz);
209 }
210
GPU_vertbuf_attr_fill(GPUVertBuf * verts_,uint a_idx,const void * data)211 void GPU_vertbuf_attr_fill(GPUVertBuf *verts_, uint a_idx, const void *data)
212 {
213 VertBuf *verts = unwrap(verts_);
214 const GPUVertFormat *format = &verts->format;
215 BLI_assert(a_idx < format->attr_len);
216 const GPUVertAttr *a = &format->attrs[a_idx];
217 const uint stride = a->sz; /* tightly packed input data */
218 verts->flag |= GPU_VERTBUF_DATA_DIRTY;
219 GPU_vertbuf_attr_fill_stride(verts_, a_idx, stride, data);
220 }
221
222 /** Fills a whole vertex (all attributes). Data must match packed layout. */
GPU_vertbuf_vert_set(GPUVertBuf * verts_,uint v_idx,const void * data)223 void GPU_vertbuf_vert_set(GPUVertBuf *verts_, uint v_idx, const void *data)
224 {
225 VertBuf *verts = unwrap(verts_);
226 const GPUVertFormat *format = &verts->format;
227 BLI_assert(v_idx < verts->vertex_alloc);
228 BLI_assert(verts->data != NULL);
229 verts->flag |= GPU_VERTBUF_DATA_DIRTY;
230 memcpy(verts->data + v_idx * format->stride, data, format->stride);
231 }
232
GPU_vertbuf_attr_fill_stride(GPUVertBuf * verts_,uint a_idx,uint stride,const void * data)233 void GPU_vertbuf_attr_fill_stride(GPUVertBuf *verts_, uint a_idx, uint stride, const void *data)
234 {
235 VertBuf *verts = unwrap(verts_);
236 const GPUVertFormat *format = &verts->format;
237 const GPUVertAttr *a = &format->attrs[a_idx];
238 BLI_assert(a_idx < format->attr_len);
239 BLI_assert(verts->data != NULL);
240 verts->flag |= GPU_VERTBUF_DATA_DIRTY;
241 const uint vertex_len = verts->vertex_len;
242
243 if (format->attr_len == 1 && stride == format->stride) {
244 /* we can copy it all at once */
245 memcpy(verts->data, data, vertex_len * a->sz);
246 }
247 else {
248 /* we must copy it per vertex */
249 for (uint v = 0; v < vertex_len; v++) {
250 memcpy(
251 verts->data + a->offset + v * format->stride, (const uchar *)data + v * stride, a->sz);
252 }
253 }
254 }
255
GPU_vertbuf_attr_get_raw_data(GPUVertBuf * verts_,uint a_idx,GPUVertBufRaw * access)256 void GPU_vertbuf_attr_get_raw_data(GPUVertBuf *verts_, uint a_idx, GPUVertBufRaw *access)
257 {
258 VertBuf *verts = unwrap(verts_);
259 const GPUVertFormat *format = &verts->format;
260 const GPUVertAttr *a = &format->attrs[a_idx];
261 BLI_assert(a_idx < format->attr_len);
262 BLI_assert(verts->data != NULL);
263
264 verts->flag |= GPU_VERTBUF_DATA_DIRTY;
265 verts->flag &= ~GPU_VERTBUF_DATA_UPLOADED;
266 access->size = a->sz;
267 access->stride = format->stride;
268 access->data = (uchar *)verts->data + a->offset;
269 access->data_init = access->data;
270 #ifdef DEBUG
271 access->_data_end = access->data_init + (size_t)(verts->vertex_alloc * format->stride);
272 #endif
273 }
274
275 /* -------- Getters -------- */
276
277 /* NOTE: Be careful when using this. The data needs to match the expected format. */
GPU_vertbuf_get_data(const GPUVertBuf * verts)278 void *GPU_vertbuf_get_data(const GPUVertBuf *verts)
279 {
280 /* TODO Assert that the format has no padding. */
281 return unwrap(verts)->data;
282 }
283
284 /* Returns the data buffer and set it to null internally to avoid freeing.
285 * NOTE: Be careful when using this. The data needs to match the expected format. */
GPU_vertbuf_steal_data(GPUVertBuf * verts_)286 void *GPU_vertbuf_steal_data(GPUVertBuf *verts_)
287 {
288 VertBuf *verts = unwrap(verts_);
289 /* TODO Assert that the format has no padding. */
290 BLI_assert(verts->data);
291 void *data = verts->data;
292 verts->data = nullptr;
293 return data;
294 }
295
GPU_vertbuf_get_format(const GPUVertBuf * verts)296 const GPUVertFormat *GPU_vertbuf_get_format(const GPUVertBuf *verts)
297 {
298 return &unwrap(verts)->format;
299 }
300
GPU_vertbuf_get_vertex_alloc(const GPUVertBuf * verts)301 uint GPU_vertbuf_get_vertex_alloc(const GPUVertBuf *verts)
302 {
303 return unwrap(verts)->vertex_alloc;
304 }
305
GPU_vertbuf_get_vertex_len(const GPUVertBuf * verts)306 uint GPU_vertbuf_get_vertex_len(const GPUVertBuf *verts)
307 {
308 return unwrap(verts)->vertex_len;
309 }
310
GPU_vertbuf_get_status(const GPUVertBuf * verts)311 GPUVertBufStatus GPU_vertbuf_get_status(const GPUVertBuf *verts)
312 {
313 return unwrap(verts)->flag;
314 }
315
GPU_vertbuf_get_memory_usage(void)316 uint GPU_vertbuf_get_memory_usage(void)
317 {
318 return VertBuf::memory_usage;
319 }
320
321 /* Should be rename to GPU_vertbuf_data_upload */
GPU_vertbuf_use(GPUVertBuf * verts)322 void GPU_vertbuf_use(GPUVertBuf *verts)
323 {
324 unwrap(verts)->upload();
325 }
326
327 /* XXX this is just a wrapper for the use of the Hair refine workaround.
328 * To be used with GPU_vertbuf_use(). */
GPU_vertbuf_update_sub(GPUVertBuf * verts,uint start,uint len,void * data)329 void GPU_vertbuf_update_sub(GPUVertBuf *verts, uint start, uint len, void *data)
330 {
331 unwrap(verts)->update_sub(start, len, data);
332 }
333
334 /** \} */
335