| 
									
										
										
										
											2018-07-17 14:46:44 +02:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * This program is free software; you can redistribute it and/or | 
					
						
							|  |  |  |  * modify it under the terms of the GNU General Public License | 
					
						
							|  |  |  |  * as published by the Free Software Foundation; either version 2 | 
					
						
							|  |  |  |  * of the License, or (at your option) any later version. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |  * GNU General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  |  * along with this program; if not, write to the Free Software Foundation, | 
					
						
							|  |  |  |  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * The Original Code is Copyright (C) 2016 by Mike Erwin. | 
					
						
							|  |  |  |  * All rights reserved. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-18 08:08:12 +11:00
										 |  |  | /** \file
 | 
					
						
							|  |  |  |  * \ingroup gpu | 
					
						
							| 
									
										
										
										
											2018-07-17 14:46:44 +02:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2018-07-18 00:12:21 +02:00
										 |  |  |  * GPU shader interface (C --> GLSL) | 
					
						
							| 
									
										
										
										
											2018-07-17 14:46:44 +02:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2017-03-02 21:27:51 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-31 16:54:58 +02:00
										 |  |  | #include "MEM_guardedalloc.h"
 | 
					
						
							| 
									
										
										
										
											2019-01-17 19:39:27 +01:00
										 |  |  | #include "BKE_global.h"
 | 
					
						
							| 
									
										
										
										
											2018-07-31 16:54:58 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-17 21:11:23 +02:00
										 |  |  | #include "GPU_shader_interface.h"
 | 
					
						
							| 
									
										
										
										
											2018-07-19 15:48:13 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "gpu_batch_private.h"
 | 
					
						
							|  |  |  | #include "gpu_context_private.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-02 21:27:51 -05:00
										 |  |  | #include <stdlib.h>
 | 
					
						
							| 
									
										
										
										
											2017-03-03 14:50:35 -05:00
										 |  |  | #include <stddef.h>
 | 
					
						
							| 
									
										
										
										
											2017-04-12 17:56:26 -04:00
										 |  |  | #include <string.h>
 | 
					
						
							| 
									
										
										
										
											2017-03-02 21:27:51 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | #define DEBUG_SHADER_INTERFACE 0
 | 
					
						
							| 
									
										
										
										
											2019-01-17 19:42:17 +01:00
										 |  |  | #define DEBUG_SHADER_UNIFORMS 0
 | 
					
						
							| 
									
										
										
										
											2017-03-02 21:27:51 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | #if DEBUG_SHADER_INTERFACE
 | 
					
						
							| 
									
										
										
										
											2018-07-19 16:06:37 +10:00
										 |  |  | #  include <stdio.h>
 | 
					
						
							| 
									
										
										
										
											2017-03-02 21:27:51 -05:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-18 23:09:31 +10:00
										 |  |  | static const char *BuiltinUniform_name(GPUUniformBuiltin u) | 
					
						
							| 
									
										
										
										
											2018-07-17 14:46:44 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   static const char *names[] = { | 
					
						
							|  |  |  |       [GPU_UNIFORM_NONE] = NULL, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       [GPU_UNIFORM_MODEL] = "ModelMatrix", | 
					
						
							|  |  |  |       [GPU_UNIFORM_VIEW] = "ViewMatrix", | 
					
						
							|  |  |  |       [GPU_UNIFORM_MODELVIEW] = "ModelViewMatrix", | 
					
						
							|  |  |  |       [GPU_UNIFORM_PROJECTION] = "ProjectionMatrix", | 
					
						
							|  |  |  |       [GPU_UNIFORM_VIEWPROJECTION] = "ViewProjectionMatrix", | 
					
						
							|  |  |  |       [GPU_UNIFORM_MVP] = "ModelViewProjectionMatrix", | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       [GPU_UNIFORM_MODEL_INV] = "ModelMatrixInverse", | 
					
						
							|  |  |  |       [GPU_UNIFORM_VIEW_INV] = "ViewMatrixInverse", | 
					
						
							|  |  |  |       [GPU_UNIFORM_MODELVIEW_INV] = "ModelViewMatrixInverse", | 
					
						
							|  |  |  |       [GPU_UNIFORM_PROJECTION_INV] = "ProjectionMatrixInverse", | 
					
						
							|  |  |  |       [GPU_UNIFORM_VIEWPROJECTION_INV] = "ViewProjectionMatrixInverse", | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       [GPU_UNIFORM_NORMAL] = "NormalMatrix", | 
					
						
							|  |  |  |       [GPU_UNIFORM_CAMERATEXCO] = "CameraTexCoFactors", | 
					
						
							|  |  |  |       [GPU_UNIFORM_ORCO] = "OrcoTexCoFactors", | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       [GPU_UNIFORM_COLOR] = "color", | 
					
						
							|  |  |  |       [GPU_UNIFORM_CALLID] = "callId", | 
					
						
							|  |  |  |       [GPU_UNIFORM_OBJECT_INFO] = "unfobjectinfo", | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       [GPU_UNIFORM_CUSTOM] = NULL, | 
					
						
							|  |  |  |       [GPU_NUM_UNIFORMS] = NULL, | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return names[u]; | 
					
						
							| 
									
										
										
										
											2018-07-17 14:46:44 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2017-03-02 21:27:51 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-18 23:09:31 +10:00
										 |  |  | GPU_INLINE bool match(const char *a, const char *b) | 
					
						
							| 
									
										
										
										
											2018-07-17 14:46:44 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   return strcmp(a, b) == 0; | 
					
						
							| 
									
										
										
										
											2018-07-17 14:46:44 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2017-04-15 19:19:00 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-18 00:12:21 +02:00
										 |  |  | GPU_INLINE uint hash_string(const char *str) | 
					
						
							| 
									
										
										
										
											2018-07-17 14:46:44 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   uint i = 0, c; | 
					
						
							|  |  |  |   while ((c = *str++)) { | 
					
						
							|  |  |  |     i = i * 37 + c; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return i; | 
					
						
							| 
									
										
										
										
											2018-07-17 14:46:44 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2017-06-01 12:26:27 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | GPU_INLINE void set_input_name(GPUShaderInterface *shaderface, | 
					
						
							|  |  |  |                                GPUShaderInput *input, | 
					
						
							|  |  |  |                                const char *name, | 
					
						
							|  |  |  |                                uint32_t name_len) | 
					
						
							| 
									
										
										
										
											2018-07-17 14:46:44 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   input->name_offset = shaderface->name_buffer_offset; | 
					
						
							|  |  |  |   input->name_hash = hash_string(name); | 
					
						
							|  |  |  |   shaderface->name_buffer_offset += name_len + 1; /* include NULL terminator */ | 
					
						
							| 
									
										
										
										
											2018-07-17 14:46:44 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2017-06-01 12:26:27 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | GPU_INLINE void shader_input_to_bucket(GPUShaderInput *input, | 
					
						
							|  |  |  |                                        GPUShaderInput *buckets[GPU_NUM_SHADERINTERFACE_BUCKETS]) | 
					
						
							| 
									
										
										
										
											2018-07-17 14:46:44 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   const uint bucket_index = input->name_hash % GPU_NUM_SHADERINTERFACE_BUCKETS; | 
					
						
							|  |  |  |   input->next = buckets[bucket_index]; | 
					
						
							|  |  |  |   buckets[bucket_index] = input; | 
					
						
							| 
									
										
										
										
											2018-07-17 14:46:44 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2017-10-04 17:36:52 +05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-18 23:09:31 +10:00
										 |  |  | GPU_INLINE const GPUShaderInput *buckets_lookup( | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     GPUShaderInput *const buckets[GPU_NUM_SHADERINTERFACE_BUCKETS], | 
					
						
							|  |  |  |     const char *name_buffer, | 
					
						
							|  |  |  |     const char *name) | 
					
						
							| 
									
										
										
										
											2018-07-17 14:46:44 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   const uint name_hash = hash_string(name); | 
					
						
							|  |  |  |   const uint bucket_index = name_hash % GPU_NUM_SHADERINTERFACE_BUCKETS; | 
					
						
							|  |  |  |   const GPUShaderInput *input = buckets[bucket_index]; | 
					
						
							|  |  |  |   if (input == NULL) { | 
					
						
							|  |  |  |     /* Requested uniform is not found at all. */ | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   /* Optimization bit: if there is no hash collision detected when constructing shader interface
 | 
					
						
							|  |  |  |    * it means we can only request the single possible uniform. Surely, it's possible we request | 
					
						
							|  |  |  |    * uniform which causes hash collision, but that will be detected in debug builds. */ | 
					
						
							|  |  |  |   if (input->next == NULL) { | 
					
						
							|  |  |  |     if (name_hash == input->name_hash) { | 
					
						
							| 
									
										
										
										
											2017-10-04 17:36:52 +05:00
										 |  |  | #if TRUST_NO_ONE
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       assert(match(name_buffer + input->name_offset, name)); | 
					
						
							| 
									
										
										
										
											2017-10-04 17:36:52 +05:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       return input; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   /* Work through possible collisions. */ | 
					
						
							|  |  |  |   const GPUShaderInput *next = input; | 
					
						
							|  |  |  |   while (next != NULL) { | 
					
						
							|  |  |  |     input = next; | 
					
						
							|  |  |  |     next = input->next; | 
					
						
							|  |  |  |     if (input->name_hash != name_hash) { | 
					
						
							|  |  |  |       continue; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (match(name_buffer + input->name_offset, name)) { | 
					
						
							|  |  |  |       return input; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return NULL; /* not found */ | 
					
						
							| 
									
										
										
										
											2018-07-17 14:46:44 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2017-10-04 17:36:52 +05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-18 23:09:31 +10:00
										 |  |  | GPU_INLINE void buckets_free(GPUShaderInput *buckets[GPU_NUM_SHADERINTERFACE_BUCKETS]) | 
					
						
							| 
									
										
										
										
											2018-07-17 14:46:44 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   for (uint bucket_index = 0; bucket_index < GPU_NUM_SHADERINTERFACE_BUCKETS; ++bucket_index) { | 
					
						
							|  |  |  |     GPUShaderInput *input = buckets[bucket_index]; | 
					
						
							|  |  |  |     while (input != NULL) { | 
					
						
							|  |  |  |       GPUShaderInput *input_next = input->next; | 
					
						
							|  |  |  |       MEM_freeN(input); | 
					
						
							|  |  |  |       input = input_next; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-07-17 14:46:44 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2017-10-06 01:50:16 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-18 23:09:31 +10:00
										 |  |  | static bool setup_builtin_uniform(GPUShaderInput *input, const char *name) | 
					
						
							| 
									
										
										
										
											2018-07-17 14:46:44 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   /* TODO: reject DOUBLE, IMAGE, ATOMIC_COUNTER gl_types */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* detect built-in uniforms (name must match) */ | 
					
						
							|  |  |  |   for (GPUUniformBuiltin u = GPU_UNIFORM_NONE + 1; u < GPU_UNIFORM_CUSTOM; ++u) { | 
					
						
							|  |  |  |     const char *builtin_name = BuiltinUniform_name(u); | 
					
						
							|  |  |  |     if (match(name, builtin_name)) { | 
					
						
							|  |  |  |       input->builtin_type = u; | 
					
						
							|  |  |  |       return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   input->builtin_type = GPU_UNIFORM_CUSTOM; | 
					
						
							|  |  |  |   return false; | 
					
						
							| 
									
										
										
										
											2018-07-17 14:46:44 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2017-03-02 21:27:51 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-18 23:09:31 +10:00
										 |  |  | static const GPUShaderInput *add_uniform(GPUShaderInterface *shaderface, const char *name) | 
					
						
							| 
									
										
										
										
											2018-07-17 14:46:44 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   GPUShaderInput *input = MEM_mallocN(sizeof(GPUShaderInput), "GPUShaderInput Unif"); | 
					
						
							| 
									
										
										
										
											2017-03-02 21:27:51 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   input->location = glGetUniformLocation(shaderface->program, name); | 
					
						
							| 
									
										
										
										
											2017-03-02 21:27:51 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   uint name_len = strlen(name); | 
					
						
							|  |  |  |   shaderface->name_buffer = MEM_reallocN(shaderface->name_buffer, | 
					
						
							|  |  |  |                                          shaderface->name_buffer_offset + name_len + | 
					
						
							|  |  |  |                                              1); /* include NULL terminator */ | 
					
						
							|  |  |  |   char *name_buffer = shaderface->name_buffer + shaderface->name_buffer_offset; | 
					
						
							|  |  |  |   strcpy(name_buffer, name); | 
					
						
							| 
									
										
										
										
											2017-03-02 21:27:51 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   set_input_name(shaderface, input, name, name_len); | 
					
						
							|  |  |  |   setup_builtin_uniform(input, name); | 
					
						
							| 
									
										
										
										
											2018-07-17 14:46:44 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   shader_input_to_bucket(input, shaderface->uniform_buckets); | 
					
						
							|  |  |  |   if (input->builtin_type != GPU_UNIFORM_NONE && input->builtin_type != GPU_UNIFORM_CUSTOM) { | 
					
						
							|  |  |  |     shaderface->builtin_uniforms[input->builtin_type] = input; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-10-05 18:26:50 +02:00
										 |  |  | #if DEBUG_SHADER_INTERFACE
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   printf("GPUShaderInterface %p, program %d, uniform[] '%s' at location %d\n", | 
					
						
							|  |  |  |          shaderface, | 
					
						
							|  |  |  |          shaderface->program, | 
					
						
							|  |  |  |          name, | 
					
						
							|  |  |  |          input->location); | 
					
						
							| 
									
										
										
										
											2017-04-12 18:03:18 -04:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   return input; | 
					
						
							| 
									
										
										
										
											2018-07-17 14:46:44 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2017-10-05 18:26:50 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-18 23:09:31 +10:00
										 |  |  | GPUShaderInterface *GPU_shaderinterface_create(int32_t program) | 
					
						
							| 
									
										
										
										
											2018-07-17 14:46:44 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   GPUShaderInterface *shaderface = MEM_callocN(sizeof(GPUShaderInterface), "GPUShaderInterface"); | 
					
						
							|  |  |  |   shaderface->program = program; | 
					
						
							| 
									
										
										
										
											2017-03-02 21:27:51 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | #if DEBUG_SHADER_INTERFACE
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   printf("%s {\n", __func__); /* enter function */ | 
					
						
							|  |  |  |   printf("GPUShaderInterface %p, program %d\n", shaderface, program); | 
					
						
							| 
									
										
										
										
											2017-03-02 21:27:51 -05:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2017-10-05 18:26:50 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   GLint max_attr_name_len = 0, attr_len = 0; | 
					
						
							|  |  |  |   glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_attr_name_len); | 
					
						
							|  |  |  |   glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &attr_len); | 
					
						
							| 
									
										
										
										
											2017-10-05 18:26:50 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   GLint max_ubo_name_len = 0, ubo_len = 0; | 
					
						
							|  |  |  |   glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &max_ubo_name_len); | 
					
						
							|  |  |  |   glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &ubo_len); | 
					
						
							| 
									
										
										
										
											2017-10-06 14:57:21 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   /* Work around driver bug with Intel HD 4600 on Windows 7/8, where
 | 
					
						
							|  |  |  |    * GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH does not work. */ | 
					
						
							|  |  |  |   if (attr_len > 0 && max_attr_name_len == 0) { | 
					
						
							|  |  |  |     max_attr_name_len = 256; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (ubo_len > 0 && max_ubo_name_len == 0) { | 
					
						
							|  |  |  |     max_ubo_name_len = 256; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-04-06 14:23:25 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   const uint32_t name_buffer_len = attr_len * max_attr_name_len + ubo_len * max_ubo_name_len; | 
					
						
							|  |  |  |   shaderface->name_buffer = MEM_mallocN(name_buffer_len, "name_buffer"); | 
					
						
							| 
									
										
										
										
											2017-03-02 21:27:51 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   /* Attributes */ | 
					
						
							|  |  |  |   for (uint32_t i = 0; i < attr_len; ++i) { | 
					
						
							|  |  |  |     GPUShaderInput *input = MEM_mallocN(sizeof(GPUShaderInput), "GPUShaderInput Attr"); | 
					
						
							|  |  |  |     GLsizei remaining_buffer = name_buffer_len - shaderface->name_buffer_offset; | 
					
						
							|  |  |  |     char *name = shaderface->name_buffer + shaderface->name_buffer_offset; | 
					
						
							|  |  |  |     GLsizei name_len = 0; | 
					
						
							| 
									
										
										
										
											2017-03-02 21:27:51 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     glGetActiveAttrib( | 
					
						
							|  |  |  |         program, i, remaining_buffer, &name_len, &input->size, &input->gl_type, name); | 
					
						
							| 
									
										
										
										
											2017-03-02 21:27:51 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     /* remove "[0]" from array name */ | 
					
						
							|  |  |  |     if (name[name_len - 1] == ']') { | 
					
						
							|  |  |  |       name[name_len - 3] = '\0'; | 
					
						
							|  |  |  |       name_len -= 3; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-02-15 19:14:46 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     /* TODO: reject DOUBLE gl_types */ | 
					
						
							| 
									
										
										
										
											2017-03-02 21:27:51 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     input->location = glGetAttribLocation(program, name); | 
					
						
							| 
									
										
										
										
											2017-04-12 17:56:26 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     set_input_name(shaderface, input, name, name_len); | 
					
						
							| 
									
										
										
										
											2017-04-12 17:56:26 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     shader_input_to_bucket(input, shaderface->attr_buckets); | 
					
						
							| 
									
										
										
										
											2017-03-02 21:27:51 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-06 14:57:21 +02:00
										 |  |  | #if DEBUG_SHADER_INTERFACE
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     printf("attr[%u] '%s' at location %d\n", i, name, input->location); | 
					
						
							| 
									
										
										
										
											2017-10-06 14:57:21 +02:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							|  |  |  |   /* Uniform Blocks */ | 
					
						
							|  |  |  |   for (uint32_t i = 0; i < ubo_len; ++i) { | 
					
						
							|  |  |  |     GPUShaderInput *input = MEM_mallocN(sizeof(GPUShaderInput), "GPUShaderInput UBO"); | 
					
						
							|  |  |  |     GLsizei remaining_buffer = name_buffer_len - shaderface->name_buffer_offset; | 
					
						
							|  |  |  |     char *name = shaderface->name_buffer + shaderface->name_buffer_offset; | 
					
						
							|  |  |  |     GLsizei name_len = 0; | 
					
						
							| 
									
										
										
										
											2017-10-06 14:57:21 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     glGetActiveUniformBlockName(program, i, remaining_buffer, &name_len, name); | 
					
						
							| 
									
										
										
										
											2017-10-06 14:57:21 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     input->location = i; | 
					
						
							| 
									
										
										
										
											2017-10-06 14:57:21 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     set_input_name(shaderface, input, name, name_len); | 
					
						
							| 
									
										
										
										
											2017-10-06 14:57:21 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     shader_input_to_bucket(input, shaderface->ubo_buckets); | 
					
						
							| 
									
										
										
										
											2017-10-06 14:57:21 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-02 21:27:51 -05:00
										 |  |  | #if DEBUG_SHADER_INTERFACE
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     printf("ubo '%s' at location %d\n", name, input->location); | 
					
						
							| 
									
										
										
										
											2017-03-02 21:27:51 -05:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							|  |  |  |   /* Builtin Uniforms */ | 
					
						
							|  |  |  |   for (GPUUniformBuiltin u = GPU_UNIFORM_NONE + 1; u < GPU_UNIFORM_CUSTOM; ++u) { | 
					
						
							|  |  |  |     const char *builtin_name = BuiltinUniform_name(u); | 
					
						
							|  |  |  |     if (glGetUniformLocation(program, builtin_name) != -1) { | 
					
						
							|  |  |  |       add_uniform((GPUShaderInterface *)shaderface, builtin_name); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   /* Batches ref buffer */ | 
					
						
							|  |  |  |   shaderface->batches_len = GPU_SHADERINTERFACE_REF_ALLOC_COUNT; | 
					
						
							|  |  |  |   shaderface->batches = MEM_callocN(shaderface->batches_len * sizeof(GPUBatch *), | 
					
						
							|  |  |  |                                     "GPUShaderInterface batches"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return shaderface; | 
					
						
							| 
									
										
										
										
											2018-07-17 14:46:44 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2017-03-02 21:27:51 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-18 23:09:31 +10:00
										 |  |  | void GPU_shaderinterface_discard(GPUShaderInterface *shaderface) | 
					
						
							| 
									
										
										
										
											2018-07-17 14:46:44 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   /* Free memory used by buckets and has entries. */ | 
					
						
							|  |  |  |   buckets_free(shaderface->uniform_buckets); | 
					
						
							|  |  |  |   buckets_free(shaderface->attr_buckets); | 
					
						
							|  |  |  |   buckets_free(shaderface->ubo_buckets); | 
					
						
							|  |  |  |   /* Free memory used by name_buffer. */ | 
					
						
							|  |  |  |   MEM_freeN(shaderface->name_buffer); | 
					
						
							|  |  |  |   /* Remove this interface from all linked Batches vao cache. */ | 
					
						
							|  |  |  |   for (int i = 0; i < shaderface->batches_len; ++i) { | 
					
						
							|  |  |  |     if (shaderface->batches[i] != NULL) { | 
					
						
							|  |  |  |       gpu_batch_remove_interface_ref(shaderface->batches[i], shaderface); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   MEM_freeN(shaderface->batches); | 
					
						
							|  |  |  |   /* Free memory used by shader interface by its self. */ | 
					
						
							|  |  |  |   MEM_freeN(shaderface); | 
					
						
							| 
									
										
										
										
											2018-07-17 14:46:44 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2017-04-12 17:56:26 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | const GPUShaderInput *GPU_shaderinterface_uniform(const GPUShaderInterface *shaderface, | 
					
						
							|  |  |  |                                                   const char *name) | 
					
						
							| 
									
										
										
										
											2019-01-16 04:41:27 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   return buckets_lookup(shaderface->uniform_buckets, shaderface->name_buffer, name); | 
					
						
							| 
									
										
										
										
											2019-01-16 04:41:27 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | const GPUShaderInput *GPU_shaderinterface_uniform_ensure(const GPUShaderInterface *shaderface, | 
					
						
							|  |  |  |                                                          const char *name) | 
					
						
							| 
									
										
										
										
											2018-07-17 14:46:44 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   const GPUShaderInput *input = GPU_shaderinterface_uniform(shaderface, name); | 
					
						
							|  |  |  |   /* If input is not found add it so it's found next time. */ | 
					
						
							|  |  |  |   if (input == NULL) { | 
					
						
							|  |  |  |     input = add_uniform((GPUShaderInterface *)shaderface, name); | 
					
						
							| 
									
										
										
										
											2019-01-17 19:39:27 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     if ((G.debug & G_DEBUG_GPU) && (input->location == -1)) { | 
					
						
							|  |  |  |       fprintf(stderr, "GPUShaderInterface: Warning: Uniform '%s' not found!\n", name); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-01-17 19:42:17 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | #if DEBUG_SHADER_UNIFORMS
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if ((G.debug & G_DEBUG_GPU) && input->builtin_type != GPU_UNIFORM_NONE && | 
					
						
							|  |  |  |       input->builtin_type != GPU_UNIFORM_CUSTOM) { | 
					
						
							|  |  |  |     /* Warn if we find a matching builtin, since these can be looked up much quicker. */ | 
					
						
							|  |  |  |     fprintf(stderr, | 
					
						
							|  |  |  |             "GPUShaderInterface: Warning: Uniform '%s' is a builtin uniform but not queried as " | 
					
						
							|  |  |  |             "such!\n", | 
					
						
							|  |  |  |             name); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-01-17 19:42:17 +01:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   return (input->location != -1) ? input : NULL; | 
					
						
							| 
									
										
										
										
											2018-07-17 14:46:44 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2017-04-12 17:56:26 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | const GPUShaderInput *GPU_shaderinterface_uniform_builtin(const GPUShaderInterface *shaderface, | 
					
						
							|  |  |  |                                                           GPUUniformBuiltin builtin) | 
					
						
							| 
									
										
										
										
											2018-07-17 14:46:44 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2017-06-04 22:09:39 -04:00
										 |  |  | #if TRUST_NO_ONE
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   assert(builtin != GPU_UNIFORM_NONE); | 
					
						
							|  |  |  |   assert(builtin != GPU_UNIFORM_CUSTOM); | 
					
						
							|  |  |  |   assert(builtin != GPU_NUM_UNIFORMS); | 
					
						
							| 
									
										
										
										
											2017-06-04 22:09:39 -04:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   return shaderface->builtin_uniforms[builtin]; | 
					
						
							| 
									
										
										
										
											2018-07-17 14:46:44 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2017-04-15 18:06:54 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | const GPUShaderInput *GPU_shaderinterface_ubo(const GPUShaderInterface *shaderface, | 
					
						
							|  |  |  |                                               const char *name) | 
					
						
							| 
									
										
										
										
											2018-07-17 14:46:44 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   return buckets_lookup(shaderface->ubo_buckets, shaderface->name_buffer, name); | 
					
						
							| 
									
										
										
										
											2018-07-17 14:46:44 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2017-10-06 14:57:21 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | const GPUShaderInput *GPU_shaderinterface_attr(const GPUShaderInterface *shaderface, | 
					
						
							|  |  |  |                                                const char *name) | 
					
						
							| 
									
										
										
										
											2018-07-17 14:46:44 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   return buckets_lookup(shaderface->attr_buckets, shaderface->name_buffer, name); | 
					
						
							| 
									
										
										
										
											2018-07-17 14:46:44 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2018-02-20 01:55:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-18 23:09:31 +10:00
										 |  |  | void GPU_shaderinterface_add_batch_ref(GPUShaderInterface *shaderface, GPUBatch *batch) | 
					
						
							| 
									
										
										
										
											2018-07-17 14:46:44 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   int i; /* find first unused slot */ | 
					
						
							|  |  |  |   for (i = 0; i < shaderface->batches_len; ++i) { | 
					
						
							|  |  |  |     if (shaderface->batches[i] == NULL) { | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (i == shaderface->batches_len) { | 
					
						
							|  |  |  |     /* Not enough place, realloc the array. */ | 
					
						
							|  |  |  |     i = shaderface->batches_len; | 
					
						
							|  |  |  |     shaderface->batches_len += GPU_SHADERINTERFACE_REF_ALLOC_COUNT; | 
					
						
							|  |  |  |     shaderface->batches = MEM_recallocN(shaderface->batches, | 
					
						
							|  |  |  |                                         sizeof(GPUBatch *) * shaderface->batches_len); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   shaderface->batches[i] = batch; | 
					
						
							| 
									
										
										
										
											2018-07-17 14:46:44 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2018-02-20 01:55:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-18 23:09:31 +10:00
										 |  |  | void GPU_shaderinterface_remove_batch_ref(GPUShaderInterface *shaderface, GPUBatch *batch) | 
					
						
							| 
									
										
										
										
											2018-07-17 14:46:44 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   for (int i = 0; i < shaderface->batches_len; ++i) { | 
					
						
							|  |  |  |     if (shaderface->batches[i] == batch) { | 
					
						
							|  |  |  |       shaderface->batches[i] = NULL; | 
					
						
							|  |  |  |       break; /* cannot have duplicates */ | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-07-17 14:46:44 +02:00
										 |  |  | } |