Merge branch 'blender2.7'
[blender.git] / source / blender / gpu / intern / gpu_shader_interface.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) 2016 by Mike Erwin.
19  * All rights reserved.
20  *
21  * Contributor(s): Blender Foundation
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/gpu/intern/gpu_shader_interface.c
27  *  \ingroup gpu
28  *
29  * GPU shader interface (C --> GLSL)
30  */
31
32 #include "MEM_guardedalloc.h"
33
34 #include "GPU_shader_interface.h"
35
36 #include "gpu_batch_private.h"
37 #include "gpu_context_private.h"
38
39 #include <stdlib.h>
40 #include <stddef.h>
41 #include <string.h>
42
43 #define DEBUG_SHADER_INTERFACE 0
44
45 #if DEBUG_SHADER_INTERFACE
46 #  include <stdio.h>
47 #endif
48
49 static const char *BuiltinUniform_name(GPUUniformBuiltin u)
50 {
51         static const char *names[] = {
52                 [GPU_UNIFORM_NONE] = NULL,
53
54                 [GPU_UNIFORM_MODEL] = "ModelMatrix",
55                 [GPU_UNIFORM_VIEW] = "ViewMatrix",
56                 [GPU_UNIFORM_MODELVIEW] = "ModelViewMatrix",
57                 [GPU_UNIFORM_PROJECTION] = "ProjectionMatrix",
58                 [GPU_UNIFORM_VIEWPROJECTION] = "ViewProjectionMatrix",
59                 [GPU_UNIFORM_MVP] = "ModelViewProjectionMatrix",
60
61                 [GPU_UNIFORM_MODEL_INV] = "ModelMatrixInverse",
62                 [GPU_UNIFORM_VIEW_INV] = "ViewMatrixInverse",
63                 [GPU_UNIFORM_MODELVIEW_INV] = "ModelViewMatrixInverse",
64                 [GPU_UNIFORM_PROJECTION_INV] = "ProjectionMatrixInverse",
65                 [GPU_UNIFORM_VIEWPROJECTION_INV] = "ViewProjectionMatrixInverse",
66
67                 [GPU_UNIFORM_NORMAL] = "NormalMatrix",
68                 [GPU_UNIFORM_WORLDNORMAL] = "WorldNormalMatrix",
69                 [GPU_UNIFORM_CAMERATEXCO] = "CameraTexCoFactors",
70                 [GPU_UNIFORM_ORCO] = "OrcoTexCoFactors",
71
72                 [GPU_UNIFORM_COLOR] = "color",
73                 [GPU_UNIFORM_EYE] = "eye",
74                 [GPU_UNIFORM_CALLID] = "callId",
75                 [GPU_UNIFORM_OBJECT_INFO] = "unfobjectinfo",
76
77                 [GPU_UNIFORM_CUSTOM] = NULL,
78                 [GPU_NUM_UNIFORMS] = NULL,
79         };
80
81         return names[u];
82 }
83
84 GPU_INLINE bool match(const char *a, const char *b)
85 {
86         return strcmp(a, b) == 0;
87 }
88
89 GPU_INLINE uint hash_string(const char *str)
90 {
91         uint i = 0, c;
92         while ((c = *str++)) {
93                 i = i * 37 + c;
94         }
95         return i;
96 }
97
98 GPU_INLINE void set_input_name(
99         GPUShaderInterface *shaderface, GPUShaderInput *input,
100         const char *name, uint32_t name_len)
101 {
102         input->name_offset = shaderface->name_buffer_offset;
103         input->name_hash = hash_string(name);
104         shaderface->name_buffer_offset += name_len + 1; /* include NULL terminator */
105 }
106
107 GPU_INLINE void shader_input_to_bucket(
108         GPUShaderInput *input,
109         GPUShaderInput *buckets[GPU_NUM_SHADERINTERFACE_BUCKETS])
110 {
111         const uint bucket_index = input->name_hash % GPU_NUM_SHADERINTERFACE_BUCKETS;
112         input->next = buckets[bucket_index];
113         buckets[bucket_index] = input;
114 }
115
116 GPU_INLINE const GPUShaderInput *buckets_lookup(
117         GPUShaderInput *const buckets[GPU_NUM_SHADERINTERFACE_BUCKETS],
118         const char *name_buffer, const char *name)
119 {
120         const uint name_hash = hash_string(name);
121         const uint bucket_index = name_hash % GPU_NUM_SHADERINTERFACE_BUCKETS;
122         const GPUShaderInput *input = buckets[bucket_index];
123         if (input == NULL) {
124                 /* Requested uniform is not found at all. */
125                 return NULL;
126         }
127         /* Optimization bit: if there is no hash collision detected when constructing shader interface
128          * it means we can only request the single possible uniform. Surely, it's possible we request
129          * uniform which causes hash collision, but that will be detected in debug builds. */
130         if (input->next == NULL) {
131                 if (name_hash == input->name_hash) {
132 #if TRUST_NO_ONE
133                         assert(match(name_buffer + input->name_offset, name));
134 #endif
135                         return input;
136                 }
137                 return NULL;
138         }
139         /* Work through possible collisions. */
140         const GPUShaderInput *next = input;
141         while (next != NULL) {
142                 input = next;
143                 next = input->next;
144                 if (input->name_hash != name_hash) {
145                         continue;
146                 }
147                 if (match(name_buffer + input->name_offset, name)) {
148                         return input;
149                 }
150         }
151         return NULL; /* not found */
152 }
153
154 GPU_INLINE void buckets_free(GPUShaderInput *buckets[GPU_NUM_SHADERINTERFACE_BUCKETS])
155 {
156         for (uint bucket_index = 0; bucket_index < GPU_NUM_SHADERINTERFACE_BUCKETS; ++bucket_index) {
157                 GPUShaderInput *input = buckets[bucket_index];
158                 while (input != NULL) {
159                         GPUShaderInput *input_next = input->next;
160                         MEM_freeN(input);
161                         input = input_next;
162                 }
163         }
164 }
165
166 static bool setup_builtin_uniform(GPUShaderInput *input, const char *name)
167 {
168         /* TODO: reject DOUBLE, IMAGE, ATOMIC_COUNTER gl_types */
169
170         /* detect built-in uniforms (name must match) */
171         for (GPUUniformBuiltin u = GPU_UNIFORM_NONE + 1; u < GPU_UNIFORM_CUSTOM; ++u) {
172                 const char *builtin_name = BuiltinUniform_name(u);
173                 if (match(name, builtin_name)) {
174                         input->builtin_type = u;
175                         return true;
176                 }
177         }
178         input->builtin_type = GPU_UNIFORM_CUSTOM;
179         return false;
180 }
181
182 static const GPUShaderInput *add_uniform(GPUShaderInterface *shaderface, const char *name)
183 {
184         GPUShaderInput *input = MEM_mallocN(sizeof(GPUShaderInput), "GPUShaderInput Unif");
185
186         input->location = glGetUniformLocation(shaderface->program, name);
187
188         uint name_len = strlen(name);
189         shaderface->name_buffer = MEM_reallocN(shaderface->name_buffer, shaderface->name_buffer_offset + name_len + 1); /* include NULL terminator */
190         char *name_buffer = shaderface->name_buffer + shaderface->name_buffer_offset;
191         strcpy(name_buffer, name);
192
193         set_input_name(shaderface, input, name, name_len);
194         setup_builtin_uniform(input, name);
195
196         shader_input_to_bucket(input, shaderface->uniform_buckets);
197         if (input->builtin_type != GPU_UNIFORM_NONE &&
198             input->builtin_type != GPU_UNIFORM_CUSTOM)
199         {
200                 shaderface->builtin_uniforms[input->builtin_type] = input;
201         }
202 #if DEBUG_SHADER_INTERFACE
203         printf("GPUShaderInterface %p, program %d, uniform[] '%s' at location %d\n",
204                shaderface,
205                shaderface->program,
206                name,
207                input->location);
208 #endif
209         return input;
210 }
211
212 GPUShaderInterface *GPU_shaderinterface_create(int32_t program)
213 {
214         GPUShaderInterface *shaderface = MEM_callocN(sizeof(GPUShaderInterface), "GPUShaderInterface");
215         shaderface->program = program;
216
217 #if DEBUG_SHADER_INTERFACE
218         printf("%s {\n", __func__); /* enter function */
219         printf("GPUShaderInterface %p, program %d\n", shaderface, program);
220 #endif
221
222         GLint max_attrib_name_len, attr_len;
223         glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_attrib_name_len);
224         glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &attr_len);
225
226         GLint max_ubo_name_len, ubo_len;
227         glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &max_ubo_name_len);
228         glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &ubo_len);
229
230         const uint32_t name_buffer_len = attr_len * max_attrib_name_len + ubo_len * max_ubo_name_len;
231         shaderface->name_buffer = MEM_mallocN(name_buffer_len, "name_buffer");
232
233         /* Attributes */
234         for (uint32_t i = 0; i < attr_len; ++i) {
235                 GPUShaderInput *input = MEM_mallocN(sizeof(GPUShaderInput), "GPUShaderInput Attr");
236                 GLsizei remaining_buffer = name_buffer_len - shaderface->name_buffer_offset;
237                 char *name = shaderface->name_buffer + shaderface->name_buffer_offset;
238                 GLsizei name_len = 0;
239
240                 glGetActiveAttrib(program, i, remaining_buffer, &name_len, &input->size, &input->gl_type, name);
241
242                 /* remove "[0]" from array name */
243                 if (name[name_len - 1] == ']') {
244                         name[name_len - 3] = '\0';
245                         name_len -= 3;
246                 }
247
248                 /* TODO: reject DOUBLE gl_types */
249
250                 input->location = glGetAttribLocation(program, name);
251
252                 set_input_name(shaderface, input, name, name_len);
253
254                 shader_input_to_bucket(input, shaderface->attrib_buckets);
255
256 #if DEBUG_SHADER_INTERFACE
257                 printf("attrib[%u] '%s' at location %d\n", i, name, input->location);
258 #endif
259         }
260         /* Uniform Blocks */
261         for (uint32_t i = 0; i < ubo_len; ++i) {
262                 GPUShaderInput *input = MEM_mallocN(sizeof(GPUShaderInput), "GPUShaderInput UBO");
263                 GLsizei remaining_buffer = name_buffer_len - shaderface->name_buffer_offset;
264                 char *name = shaderface->name_buffer + shaderface->name_buffer_offset;
265                 GLsizei name_len = 0;
266
267                 glGetActiveUniformBlockName(program, i, remaining_buffer, &name_len, name);
268
269                 input->location = i;
270
271                 set_input_name(shaderface, input, name, name_len);
272
273                 shader_input_to_bucket(input, shaderface->ubo_buckets);
274
275 #if DEBUG_SHADER_INTERFACE
276                 printf("ubo '%s' at location %d\n", name, input->location);
277 #endif
278         }
279         /* Builtin Uniforms */
280         for (GPUUniformBuiltin u = GPU_UNIFORM_NONE + 1; u < GPU_UNIFORM_CUSTOM; ++u) {
281                 const char *builtin_name = BuiltinUniform_name(u);
282                 if (glGetUniformLocation(program, builtin_name) != -1) {
283                         add_uniform((GPUShaderInterface *)shaderface, builtin_name);
284                 }
285         }
286         /* Batches ref buffer */
287         shaderface->batches_len = GPU_SHADERINTERFACE_REF_ALLOC_COUNT;
288         shaderface->batches = MEM_callocN(shaderface->batches_len * sizeof(GPUBatch *), "GPUShaderInterface batches");
289
290         return shaderface;
291 }
292
293 void GPU_shaderinterface_discard(GPUShaderInterface *shaderface)
294 {
295         /* Free memory used by buckets and has entries. */
296         buckets_free(shaderface->uniform_buckets);
297         buckets_free(shaderface->attrib_buckets);
298         buckets_free(shaderface->ubo_buckets);
299         /* Free memory used by name_buffer. */
300         MEM_freeN(shaderface->name_buffer);
301         /* Remove this interface from all linked Batches vao cache. */
302         for (int i = 0; i < shaderface->batches_len; ++i) {
303                 if (shaderface->batches[i] != NULL) {
304                         gpu_batch_remove_interface_ref(shaderface->batches[i], shaderface);
305                 }
306         }
307         MEM_freeN(shaderface->batches);
308         /* Free memory used by shader interface by its self. */
309         MEM_freeN(shaderface);
310 }
311
312 const GPUShaderInput *GPU_shaderinterface_uniform(const GPUShaderInterface *shaderface, const char *name)
313 {
314         /* TODO: Warn if we find a matching builtin, since these can be looked up much quicker. */
315         const GPUShaderInput *input = buckets_lookup(shaderface->uniform_buckets, shaderface->name_buffer, name);
316         /* If input is not found add it so it's found next time. */
317         if (input == NULL) {
318                 input = add_uniform((GPUShaderInterface *)shaderface, name);
319         }
320         return (input->location != -1) ? input : NULL;
321 }
322
323 const GPUShaderInput *GPU_shaderinterface_uniform_builtin(
324             const GPUShaderInterface *shaderface, GPUUniformBuiltin builtin)
325 {
326 #if TRUST_NO_ONE
327         assert(builtin != GPU_UNIFORM_NONE);
328         assert(builtin != GPU_UNIFORM_CUSTOM);
329         assert(builtin != GPU_NUM_UNIFORMS);
330 #endif
331         return shaderface->builtin_uniforms[builtin];
332 }
333
334 const GPUShaderInput *GPU_shaderinterface_ubo(const GPUShaderInterface *shaderface, const char *name)
335 {
336         return buckets_lookup(shaderface->ubo_buckets, shaderface->name_buffer, name);
337 }
338
339 const GPUShaderInput *GPU_shaderinterface_attr(const GPUShaderInterface *shaderface, const char *name)
340 {
341         return buckets_lookup(shaderface->attrib_buckets, shaderface->name_buffer, name);
342 }
343
344 void GPU_shaderinterface_add_batch_ref(GPUShaderInterface *shaderface, GPUBatch *batch)
345 {
346         int i; /* find first unused slot */
347         for (i = 0; i < shaderface->batches_len; ++i) {
348                 if (shaderface->batches[i] == NULL) {
349                         break;
350                 }
351         }
352         if (i == shaderface->batches_len) {
353                 /* Not enough place, realloc the array. */
354                 i = shaderface->batches_len;
355                 shaderface->batches_len += GPU_SHADERINTERFACE_REF_ALLOC_COUNT;
356                 shaderface->batches = MEM_recallocN(shaderface->batches, sizeof(GPUBatch *) * shaderface->batches_len);
357         }
358         shaderface->batches[i] = batch;
359 }
360
361 void GPU_shaderinterface_remove_batch_ref(GPUShaderInterface *shaderface, GPUBatch *batch)
362 {
363         for (int i = 0; i < shaderface->batches_len; ++i) {
364                 if (shaderface->batches[i] == batch) {
365                         shaderface->batches[i] = NULL;
366                         break; /* cannot have duplicates */
367                 }
368         }
369 }