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