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