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