| 
									
										
										
										
											2020-08-20 13:05:22 +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. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** \file
 | 
					
						
							|  |  |  |  * \ingroup gpu | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * GPU shader interface (C --> GLSL) | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2020-08-22 00:09:17 +10:00
										 |  |  |  * Structure detailing needed vertex inputs and resources for a specific shader. | 
					
						
							| 
									
										
										
										
											2020-08-20 13:05:22 +02:00
										 |  |  |  * A shader interface can be shared between two similar shaders. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #pragma once
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <cstring> /* required for STREQ later on. */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "BLI_hash.h"
 | 
					
						
							|  |  |  | #include "BLI_utildefines.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "GPU_shader.h"
 | 
					
						
							| 
									
										
										
										
											2022-01-17 14:45:22 +01:00
										 |  |  | #include "gpu_shader_create_info.hh"
 | 
					
						
							| 
									
										
										
										
											2020-08-20 13:05:22 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace blender::gpu { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct ShaderInput { | 
					
						
							|  |  |  |   uint32_t name_offset; | 
					
						
							|  |  |  |   uint32_t name_hash; | 
					
						
							|  |  |  |   int32_t location; | 
					
						
							| 
									
										
										
										
											2021-02-05 16:23:34 +11:00
										 |  |  |   /** Defined at interface creation or in shader. Only for Samplers, UBOs and Vertex Attributes. */ | 
					
						
							| 
									
										
										
										
											2020-08-20 13:05:22 +02:00
										 |  |  |   int32_t binding; | 
					
						
							|  |  |  | } ShaderInput; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-21 14:14:56 +02:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * Implementation of Shader interface. | 
					
						
							|  |  |  |  * Base class which is then specialized for each implementation (GL, VK, ...). | 
					
						
							| 
									
										
										
										
											2021-01-04 12:00:18 +11:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2020-08-20 13:05:22 +02:00
										 |  |  | class ShaderInterface { | 
					
						
							| 
									
										
										
										
											2022-01-17 14:45:22 +01:00
										 |  |  |   friend shader::ShaderCreateInfo; | 
					
						
							| 
									
										
										
										
											2020-09-19 14:32:41 +10:00
										 |  |  |   /* TODO(fclem): should be protected. */ | 
					
						
							| 
									
										
										
										
											2020-08-20 13:05:22 +02:00
										 |  |  |  public: | 
					
						
							|  |  |  |   /** Flat array. In this order: Attributes, Ubos, Uniforms. */ | 
					
						
							|  |  |  |   ShaderInput *inputs_ = NULL; | 
					
						
							|  |  |  |   /** Buffer containing all inputs names separated by '\0'. */ | 
					
						
							|  |  |  |   char *name_buffer_ = NULL; | 
					
						
							|  |  |  |   /** Input counts inside input array. */ | 
					
						
							|  |  |  |   uint attr_len_ = 0; | 
					
						
							|  |  |  |   uint ubo_len_ = 0; | 
					
						
							|  |  |  |   uint uniform_len_ = 0; | 
					
						
							| 
									
										
										
										
											2021-05-26 16:49:17 +02:00
										 |  |  |   uint ssbo_len_ = 0; | 
					
						
							| 
									
										
										
										
											2021-02-17 15:04:29 +11:00
										 |  |  |   /** Enabled bind-points that needs to be fed with data. */ | 
					
						
							| 
									
										
										
										
											2020-08-20 13:05:22 +02:00
										 |  |  |   uint16_t enabled_attr_mask_ = 0; | 
					
						
							|  |  |  |   uint16_t enabled_ubo_mask_ = 0; | 
					
						
							| 
									
										
										
										
											2020-09-12 06:10:11 +02:00
										 |  |  |   uint8_t enabled_ima_mask_ = 0; | 
					
						
							| 
									
										
										
										
											2020-08-20 13:05:22 +02:00
										 |  |  |   uint64_t enabled_tex_mask_ = 0; | 
					
						
							|  |  |  |   /** Location of builtin uniforms. Fast access, no lookup needed. */ | 
					
						
							|  |  |  |   int32_t builtins_[GPU_NUM_UNIFORMS]; | 
					
						
							|  |  |  |   int32_t builtin_blocks_[GPU_NUM_UNIFORM_BLOCKS]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  public: | 
					
						
							|  |  |  |   ShaderInterface(); | 
					
						
							| 
									
										
										
										
											2022-01-17 14:45:22 +01:00
										 |  |  |   ShaderInterface(const shader::ShaderCreateInfo &info); | 
					
						
							| 
									
										
										
										
											2020-08-20 13:05:22 +02:00
										 |  |  |   virtual ~ShaderInterface(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-05 21:44:03 -05:00
										 |  |  |   void debug_print(); | 
					
						
							| 
									
										
										
										
											2020-08-20 13:05:22 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   inline const ShaderInput *attr_get(const char *name) const | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     return input_lookup(inputs_, attr_len_, name); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   inline const ShaderInput *ubo_get(const char *name) const | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     return input_lookup(inputs_ + attr_len_, ubo_len_, name); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-09-01 02:41:29 +02:00
										 |  |  |   inline const ShaderInput *ubo_get(const int binding) const | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     return input_lookup(inputs_ + attr_len_, ubo_len_, binding); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-08-20 13:05:22 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   inline const ShaderInput *uniform_get(const char *name) const | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     return input_lookup(inputs_ + attr_len_ + ubo_len_, uniform_len_, name); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-04 22:19:36 +02:00
										 |  |  |   inline const ShaderInput *texture_get(const int binding) const | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     return input_lookup(inputs_ + attr_len_ + ubo_len_, uniform_len_, binding); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-26 16:49:17 +02:00
										 |  |  |   inline const ShaderInput *ssbo_get(const char *name) const | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     return input_lookup(inputs_ + attr_len_ + ubo_len_ + uniform_len_, ssbo_len_, name); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-01 02:41:29 +02:00
										 |  |  |   inline const char *input_name_get(const ShaderInput *input) const | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     return name_buffer_ + input->name_offset; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-20 13:05:22 +02:00
										 |  |  |   /* Returns uniform location. */ | 
					
						
							|  |  |  |   inline int32_t uniform_builtin(const GPUUniformBuiltin builtin) const | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     BLI_assert(builtin >= 0 && builtin < GPU_NUM_UNIFORMS); | 
					
						
							|  |  |  |     return builtins_[builtin]; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Returns binding position. */ | 
					
						
							|  |  |  |   inline int32_t ubo_builtin(const GPUUniformBlockBuiltin builtin) const | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     BLI_assert(builtin >= 0 && builtin < GPU_NUM_UNIFORM_BLOCKS); | 
					
						
							|  |  |  |     return builtin_blocks_[builtin]; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  protected: | 
					
						
							|  |  |  |   static inline const char *builtin_uniform_name(GPUUniformBuiltin u); | 
					
						
							|  |  |  |   static inline const char *builtin_uniform_block_name(GPUUniformBlockBuiltin u); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   inline uint32_t set_input_name(ShaderInput *input, char *name, uint32_t name_len) const; | 
					
						
							| 
									
										
										
										
											2022-01-17 14:45:22 +01:00
										 |  |  |   inline void copy_input_name(ShaderInput *input, | 
					
						
							|  |  |  |                               const StringRefNull &name, | 
					
						
							|  |  |  |                               char *name_buffer, | 
					
						
							|  |  |  |                               uint32_t &name_buffer_offset) const; | 
					
						
							| 
									
										
										
										
											2020-08-20 13:05:22 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-09 20:01:47 +11:00
										 |  |  |   /**
 | 
					
						
							|  |  |  |    * Finalize interface construction by sorting the #ShaderInputs for faster lookups. | 
					
						
							|  |  |  |    */ | 
					
						
							| 
									
										
										
										
											2022-01-05 21:44:03 -05:00
										 |  |  |   void sort_inputs(); | 
					
						
							| 
									
										
										
										
											2020-08-20 13:05:22 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |  private: | 
					
						
							|  |  |  |   inline const ShaderInput *input_lookup(const ShaderInput *const inputs, | 
					
						
							| 
									
										
										
										
											2022-01-07 11:38:08 +11:00
										 |  |  |                                          uint inputs_len, | 
					
						
							| 
									
										
										
										
											2020-08-20 13:05:22 +02:00
										 |  |  |                                          const char *name) const; | 
					
						
							| 
									
										
										
										
											2020-09-01 02:41:29 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   inline const ShaderInput *input_lookup(const ShaderInput *const inputs, | 
					
						
							| 
									
										
										
										
											2022-01-07 11:38:08 +11:00
										 |  |  |                                          uint inputs_len, | 
					
						
							|  |  |  |                                          int binding) const; | 
					
						
							| 
									
										
										
										
											2020-08-20 13:05:22 +02:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | inline const char *ShaderInterface::builtin_uniform_name(GPUUniformBuiltin u) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   switch (u) { | 
					
						
							|  |  |  |     case GPU_UNIFORM_MODEL: | 
					
						
							|  |  |  |       return "ModelMatrix"; | 
					
						
							|  |  |  |     case GPU_UNIFORM_VIEW: | 
					
						
							|  |  |  |       return "ViewMatrix"; | 
					
						
							|  |  |  |     case GPU_UNIFORM_MODELVIEW: | 
					
						
							|  |  |  |       return "ModelViewMatrix"; | 
					
						
							|  |  |  |     case GPU_UNIFORM_PROJECTION: | 
					
						
							|  |  |  |       return "ProjectionMatrix"; | 
					
						
							|  |  |  |     case GPU_UNIFORM_VIEWPROJECTION: | 
					
						
							|  |  |  |       return "ViewProjectionMatrix"; | 
					
						
							|  |  |  |     case GPU_UNIFORM_MVP: | 
					
						
							|  |  |  |       return "ModelViewProjectionMatrix"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case GPU_UNIFORM_MODEL_INV: | 
					
						
							|  |  |  |       return "ModelMatrixInverse"; | 
					
						
							|  |  |  |     case GPU_UNIFORM_VIEW_INV: | 
					
						
							|  |  |  |       return "ViewMatrixInverse"; | 
					
						
							|  |  |  |     case GPU_UNIFORM_MODELVIEW_INV: | 
					
						
							|  |  |  |       return "ModelViewMatrixInverse"; | 
					
						
							|  |  |  |     case GPU_UNIFORM_PROJECTION_INV: | 
					
						
							|  |  |  |       return "ProjectionMatrixInverse"; | 
					
						
							|  |  |  |     case GPU_UNIFORM_VIEWPROJECTION_INV: | 
					
						
							|  |  |  |       return "ViewProjectionMatrixInverse"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case GPU_UNIFORM_NORMAL: | 
					
						
							|  |  |  |       return "NormalMatrix"; | 
					
						
							|  |  |  |     case GPU_UNIFORM_ORCO: | 
					
						
							|  |  |  |       return "OrcoTexCoFactors"; | 
					
						
							|  |  |  |     case GPU_UNIFORM_CLIPPLANES: | 
					
						
							|  |  |  |       return "WorldClipPlanes"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case GPU_UNIFORM_COLOR: | 
					
						
							|  |  |  |       return "color"; | 
					
						
							|  |  |  |     case GPU_UNIFORM_BASE_INSTANCE: | 
					
						
							|  |  |  |       return "baseInstance"; | 
					
						
							|  |  |  |     case GPU_UNIFORM_RESOURCE_CHUNK: | 
					
						
							|  |  |  |       return "resourceChunk"; | 
					
						
							|  |  |  |     case GPU_UNIFORM_RESOURCE_ID: | 
					
						
							|  |  |  |       return "resourceId"; | 
					
						
							|  |  |  |     case GPU_UNIFORM_SRGB_TRANSFORM: | 
					
						
							|  |  |  |       return "srgbTarget"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |       return NULL; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | inline const char *ShaderInterface::builtin_uniform_block_name(GPUUniformBlockBuiltin u) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   switch (u) { | 
					
						
							|  |  |  |     case GPU_UNIFORM_BLOCK_VIEW: | 
					
						
							|  |  |  |       return "viewBlock"; | 
					
						
							|  |  |  |     case GPU_UNIFORM_BLOCK_MODEL: | 
					
						
							|  |  |  |       return "modelBlock"; | 
					
						
							|  |  |  |     case GPU_UNIFORM_BLOCK_INFO: | 
					
						
							|  |  |  |       return "infoBlock"; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |       return NULL; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Returns string length including '\0' terminator. */ | 
					
						
							|  |  |  | inline uint32_t ShaderInterface::set_input_name(ShaderInput *input, | 
					
						
							|  |  |  |                                                 char *name, | 
					
						
							|  |  |  |                                                 uint32_t name_len) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   /* remove "[0]" from array name */ | 
					
						
							|  |  |  |   if (name[name_len - 1] == ']') { | 
					
						
							| 
									
										
										
										
											2022-01-17 14:45:22 +01:00
										 |  |  |     for (; name_len > 1; name_len--) { | 
					
						
							|  |  |  |       if (name[name_len] == '[') { | 
					
						
							|  |  |  |         name[name_len] = '\0'; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-08-20 13:05:22 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   input->name_offset = (uint32_t)(name - name_buffer_); | 
					
						
							|  |  |  |   input->name_hash = BLI_hash_string(name); | 
					
						
							|  |  |  |   return name_len + 1; /* include NULL terminator */ | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-17 14:45:22 +01:00
										 |  |  | inline void ShaderInterface::copy_input_name(ShaderInput *input, | 
					
						
							|  |  |  |                                              const StringRefNull &name, | 
					
						
							|  |  |  |                                              char *name_buffer, | 
					
						
							|  |  |  |                                              uint32_t &name_buffer_offset) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   uint32_t name_len = name.size(); | 
					
						
							|  |  |  |   /* Copy include NULL terminator. */ | 
					
						
							|  |  |  |   memcpy(name_buffer + name_buffer_offset, name.c_str(), name_len + 1); | 
					
						
							|  |  |  |   name_buffer_offset += set_input_name(input, name_buffer + name_buffer_offset, name_len); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-20 13:05:22 +02:00
										 |  |  | inline const ShaderInput *ShaderInterface::input_lookup(const ShaderInput *const inputs, | 
					
						
							|  |  |  |                                                         const uint inputs_len, | 
					
						
							|  |  |  |                                                         const char *name) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   const uint name_hash = BLI_hash_string(name); | 
					
						
							|  |  |  |   /* Simple linear search for now. */ | 
					
						
							|  |  |  |   for (int i = inputs_len - 1; i >= 0; i--) { | 
					
						
							|  |  |  |     if (inputs[i].name_hash == name_hash) { | 
					
						
							|  |  |  |       if ((i > 0) && UNLIKELY(inputs[i - 1].name_hash == name_hash)) { | 
					
						
							| 
									
										
										
										
											2021-02-05 16:23:34 +11:00
										 |  |  |         /* Hash collision resolve. */ | 
					
						
							| 
									
										
										
										
											2020-08-20 13:05:22 +02:00
										 |  |  |         for (; i >= 0 && inputs[i].name_hash == name_hash; i--) { | 
					
						
							|  |  |  |           if (STREQ(name, name_buffer_ + inputs[i].name_offset)) { | 
					
						
							|  |  |  |             return inputs + i; /* not found */ | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return NULL; /* not found */ | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       /* This is a bit dangerous since we could have a hash collision.
 | 
					
						
							|  |  |  |        * where the asked uniform that does not exist has the same hash | 
					
						
							|  |  |  |        * as a real uniform. */ | 
					
						
							|  |  |  |       BLI_assert(STREQ(name, name_buffer_ + inputs[i].name_offset)); | 
					
						
							|  |  |  |       return inputs + i; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return NULL; /* not found */ | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-01 02:41:29 +02:00
										 |  |  | inline const ShaderInput *ShaderInterface::input_lookup(const ShaderInput *const inputs, | 
					
						
							|  |  |  |                                                         const uint inputs_len, | 
					
						
							|  |  |  |                                                         const int binding) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   /* Simple linear search for now. */ | 
					
						
							|  |  |  |   for (int i = inputs_len - 1; i >= 0; i--) { | 
					
						
							|  |  |  |     if (inputs[i].binding == binding) { | 
					
						
							|  |  |  |       return inputs + i; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return NULL; /* not found */ | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-20 13:05:22 +02:00
										 |  |  | }  // namespace blender::gpu
 |