Merge branch 'blender2.7'
[blender.git] / source / blender / gpu / intern / gpu_uniformbuffer.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) 2005 Blender Foundation.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): Clement Foucault.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file gpu_uniformbuffer.c
29  *  \ingroup gpu
30  */
31
32 #include <string.h>
33 #include "MEM_guardedalloc.h"
34
35 #include "BLI_blenlib.h"
36
37 #include "gpu_codegen.h"
38 #include "gpu_context_private.h"
39
40 #include "GPU_extensions.h"
41 #include "GPU_glew.h"
42 #include "GPU_material.h"
43 #include "GPU_uniformbuffer.h"
44
45 typedef enum GPUUniformBufferFlag {
46         GPU_UBO_FLAG_INITIALIZED = (1 << 0),
47         GPU_UBO_FLAG_DIRTY = (1 << 1),
48 } GPUUniformBufferFlag;
49
50 typedef enum GPUUniformBufferType {
51         GPU_UBO_STATIC = 0,
52         GPU_UBO_DYNAMIC = 1,
53 } GPUUniformBufferType;
54
55 struct GPUUniformBuffer {
56         int size;           /* in bytes */
57         GLuint bindcode;    /* opengl identifier for UBO */
58         int bindpoint;      /* current binding point */
59         GPUUniformBufferType type;
60 };
61
62 #define GPUUniformBufferStatic GPUUniformBuffer
63
64 typedef struct GPUUniformBufferDynamic {
65         GPUUniformBuffer buffer;
66         void *data;                  /* Continuous memory block to copy to GPU. */
67         char flag;
68 } GPUUniformBufferDynamic;
69
70 /* Prototypes */
71 static GPUType get_padded_gpu_type(struct LinkData *link);
72 static void gpu_uniformbuffer_inputs_sort(struct ListBase *inputs);
73
74 /* Only support up to this type, if you want to extend it, make sure the
75  * padding logic is correct for the new types. */
76 #define MAX_UBO_GPU_TYPE GPU_VEC4
77
78 static void gpu_uniformbuffer_initialize(GPUUniformBuffer *ubo, const void *data)
79 {
80         glBindBuffer(GL_UNIFORM_BUFFER, ubo->bindcode);
81         glBufferData(GL_UNIFORM_BUFFER, ubo->size, data, GL_DYNAMIC_DRAW);
82         glBindBuffer(GL_UNIFORM_BUFFER, 0);
83 }
84
85 GPUUniformBuffer *GPU_uniformbuffer_create(int size, const void *data, char err_out[256])
86 {
87         GPUUniformBuffer *ubo = MEM_callocN(sizeof(GPUUniformBufferStatic), "GPUUniformBufferStatic");
88         ubo->size = size;
89         ubo->bindpoint = -1;
90
91         /* Generate Buffer object */
92         ubo->bindcode = GPU_buf_alloc();
93
94         if (!ubo->bindcode) {
95                 if (err_out)
96                         BLI_snprintf(err_out, 256, "GPUUniformBuffer: UBO create failed");
97                 GPU_uniformbuffer_free(ubo);
98                 return NULL;
99         }
100
101         if (ubo->size > GPU_max_ubo_size()) {
102                 if (err_out)
103                         BLI_snprintf(err_out, 256, "GPUUniformBuffer: UBO too big");
104                 GPU_uniformbuffer_free(ubo);
105                 return NULL;
106         }
107
108         gpu_uniformbuffer_initialize(ubo, data);
109         return ubo;
110 }
111
112 /**
113  * Create dynamic UBO from parameters
114  * Return NULL if failed to create or if \param inputs: is empty.
115  *
116  * \param inputs: ListBase of BLI_genericNodeN(GPUInput)
117  */
118 GPUUniformBuffer *GPU_uniformbuffer_dynamic_create(ListBase *inputs, char err_out[256])
119 {
120         /* There is no point on creating an UBO if there is no arguments. */
121         if (BLI_listbase_is_empty(inputs)) {
122                 return NULL;
123         }
124
125         GPUUniformBufferDynamic *ubo = MEM_callocN(sizeof(GPUUniformBufferDynamic), "GPUUniformBufferDynamic");
126         ubo->buffer.type = GPU_UBO_DYNAMIC;
127         ubo->buffer.bindpoint = -1;
128         ubo->flag = GPU_UBO_FLAG_DIRTY;
129
130         /* Generate Buffer object. */
131         ubo->buffer.bindcode = GPU_buf_alloc();
132
133         if (!ubo->buffer.bindcode) {
134                 if (err_out)
135                         BLI_snprintf(err_out, 256, "GPUUniformBuffer: UBO create failed");
136                 GPU_uniformbuffer_free(&ubo->buffer);
137                 return NULL;
138         }
139
140         if (ubo->buffer.size > GPU_max_ubo_size()) {
141                 if (err_out)
142                         BLI_snprintf(err_out, 256, "GPUUniformBuffer: UBO too big");
143                 GPU_uniformbuffer_free(&ubo->buffer);
144                 return NULL;
145         }
146
147         /* Make sure we comply to the ubo alignment requirements. */
148         gpu_uniformbuffer_inputs_sort(inputs);
149
150         for (LinkData *link = inputs->first; link; link = link->next) {
151                 const GPUType gputype = get_padded_gpu_type(link);
152                 ubo->buffer.size += gputype * sizeof(float);
153         }
154
155         /* Allocate the data. */
156         ubo->data = MEM_mallocN(ubo->buffer.size, __func__);
157
158         /* Now that we know the total ubo size we can start populating it. */
159         float *offset = ubo->data;
160         for (LinkData *link = inputs->first; link; link = link->next) {
161                 GPUInput *input = link->data;
162                 memcpy(offset, input->vec, input->type * sizeof(float));
163                 offset += get_padded_gpu_type(link);
164         }
165
166         /* Note since we may create the UBOs in the CPU in a different thread than the main drawing one,
167          * we don't create the UBO in the GPU here. This will happen when we first bind the UBO.
168          */
169
170         return &ubo->buffer;
171 }
172
173 /**
174  * Free the data
175  */
176 static void gpu_uniformbuffer_dynamic_free(GPUUniformBuffer *ubo_)
177 {
178         BLI_assert(ubo_->type == GPU_UBO_DYNAMIC);
179         GPUUniformBufferDynamic *ubo = (GPUUniformBufferDynamic *)ubo_;
180
181         ubo->buffer.size = 0;
182         if (ubo->data) {
183                 MEM_freeN(ubo->data);
184         }
185 }
186
187 void GPU_uniformbuffer_free(GPUUniformBuffer *ubo)
188 {
189         if (ubo->type == GPU_UBO_DYNAMIC) {
190                 gpu_uniformbuffer_dynamic_free(ubo);
191         }
192
193         GPU_buf_free(ubo->bindcode);
194         MEM_freeN(ubo);
195 }
196
197 static void gpu_uniformbuffer_update(GPUUniformBuffer *ubo, const void *data)
198 {
199         glBindBuffer(GL_UNIFORM_BUFFER, ubo->bindcode);
200         glBufferSubData(GL_UNIFORM_BUFFER, 0, ubo->size, data);
201         glBindBuffer(GL_UNIFORM_BUFFER, 0);
202 }
203
204 void GPU_uniformbuffer_update(GPUUniformBuffer *ubo, const void *data)
205 {
206         BLI_assert(ubo->type == GPU_UBO_STATIC);
207         gpu_uniformbuffer_update(ubo, data);
208 }
209
210 /**
211  * We need to recalculate the internal data, and re-generate it
212  * from its populated items.
213  */
214 void GPU_uniformbuffer_dynamic_update(GPUUniformBuffer *ubo_)
215 {
216         BLI_assert(ubo_->type == GPU_UBO_DYNAMIC);
217         GPUUniformBufferDynamic *ubo = (GPUUniformBufferDynamic *)ubo_;
218
219         if (ubo->flag & GPU_UBO_FLAG_INITIALIZED) {
220                 gpu_uniformbuffer_update(ubo_, ubo->data);
221         }
222         else {
223                 ubo->flag |= GPU_UBO_FLAG_INITIALIZED;
224                 gpu_uniformbuffer_initialize(ubo_, ubo->data);
225         }
226
227         ubo->flag &= ~GPU_UBO_FLAG_DIRTY;
228 }
229
230 /**
231  * We need to pad some data types (vec3) on the C side
232  * To match the GPU expected memory block alignment.
233  */
234 static GPUType get_padded_gpu_type(LinkData *link)
235 {
236         GPUInput *input = link->data;
237         GPUType gputype = input->type;
238
239         /* Unless the vec3 is followed by a float we need to treat it as a vec4. */
240         if (gputype == GPU_VEC3 &&
241             (link->next != NULL) &&
242             (((GPUInput *)link->next->data)->type != GPU_FLOAT))
243         {
244                 gputype = GPU_VEC4;
245         }
246
247         return gputype;
248 }
249
250 /**
251  * Returns 1 if the first item shold be after second item.
252  * We make sure the vec4 uniforms come first.
253  */
254 static int inputs_cmp(const void *a, const void *b)
255 {
256         const LinkData *link_a = a, *link_b = b;
257         const GPUInput *input_a = link_a->data, *input_b = link_b->data;
258         return input_a->type < input_b->type ? 1 : 0;
259 }
260
261 /**
262  * Make sure we respect the expected alignment of UBOs.
263  * vec4, pad vec3 as vec4, then vec2, then floats.
264  */
265 static void gpu_uniformbuffer_inputs_sort(ListBase *inputs)
266 {
267         /* Order them as vec4, vec3, vec2, float. */
268         BLI_listbase_sort(inputs, inputs_cmp);
269
270         /* Creates a lookup table for the different types; */
271         LinkData *inputs_lookup[MAX_UBO_GPU_TYPE + 1] = {NULL};
272         GPUType cur_type = MAX_UBO_GPU_TYPE + 1;
273
274         for (LinkData *link = inputs->first; link; link = link->next) {
275                 GPUInput *input = link->data;
276                 if (input->type == cur_type) {
277                         continue;
278                 }
279                 else {
280                         inputs_lookup[input->type] = link;
281                         cur_type = input->type;
282                 }
283         }
284
285         /* If there is no GPU_VEC3 there is no need for alignment. */
286         if (inputs_lookup[GPU_VEC3] == NULL) {
287                 return;
288         }
289
290         LinkData *link = inputs_lookup[GPU_VEC3];
291         while (link != NULL && ((GPUInput *)link->data)->type == GPU_VEC3) {
292                 LinkData *link_next = link->next;
293
294                 /* If GPU_VEC3 is followed by nothing or a GPU_FLOAT, no need for alignment. */
295                 if ((link_next == NULL) ||
296                     ((GPUInput *)link_next->data)->type == GPU_FLOAT)
297                 {
298                         break;
299                 }
300
301                 /* If there is a float, move it next to current vec3. */
302                 if (inputs_lookup[GPU_FLOAT] != NULL) {
303                         LinkData *float_input = inputs_lookup[GPU_FLOAT];
304                         inputs_lookup[GPU_FLOAT] = float_input->next;
305
306                         BLI_remlink(inputs, float_input);
307                         BLI_insertlinkafter(inputs, link, float_input);
308                 }
309
310                 link = link_next;
311         }
312 }
313
314 void GPU_uniformbuffer_bind(GPUUniformBuffer *ubo, int number)
315 {
316         if (number >= GPU_max_ubo_binds()) {
317                 fprintf(stderr, "Not enough UBO slots.\n");
318                 return;
319         }
320
321         if (ubo->type == GPU_UBO_DYNAMIC) {
322                 GPUUniformBufferDynamic *ubo_dynamic = (GPUUniformBufferDynamic *)ubo;
323                 if (ubo_dynamic->flag & GPU_UBO_FLAG_DIRTY) {
324                         GPU_uniformbuffer_dynamic_update(ubo);
325                 }
326         }
327
328         if (ubo->bindcode != 0) {
329                 glBindBufferBase(GL_UNIFORM_BUFFER, number, ubo->bindcode);
330         }
331
332         ubo->bindpoint = number;
333 }
334
335 void GPU_uniformbuffer_unbind(GPUUniformBuffer *ubo)
336 {
337         ubo->bindpoint = -1;
338 }
339
340 int GPU_uniformbuffer_bindpoint(GPUUniformBuffer *ubo)
341 {
342         return ubo->bindpoint;
343 }
344
345 #undef MAX_UBO_GPU_TYPE