528 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			528 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  * 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)
 | |
|  */
 | |
| 
 | |
| #include "BLI_bitmap.h"
 | |
| 
 | |
| #include "gl_backend.hh"
 | |
| #include "gl_batch.hh"
 | |
| #include "gl_context.hh"
 | |
| 
 | |
| #include "gl_shader_interface.hh"
 | |
| 
 | |
| #include "GPU_capabilities.h"
 | |
| 
 | |
| namespace blender::gpu {
 | |
| 
 | |
| /* -------------------------------------------------------------------- */
 | |
| /** \name Binding assignment
 | |
|  *
 | |
|  * To mimic vulkan, we assign binding at shader creation to avoid shader recompilation.
 | |
|  * In the future, we should set it in the shader using layout(binding = i) and query its value.
 | |
|  * \{ */
 | |
| 
 | |
| static inline int block_binding(int32_t program, uint32_t block_index)
 | |
| {
 | |
|   /* For now just assign a consecutive index. In the future, we should set it in
 | |
|    * the shader using layout(binding = i) and query its value. */
 | |
|   glUniformBlockBinding(program, block_index, block_index);
 | |
|   return block_index;
 | |
| }
 | |
| 
 | |
| static inline int sampler_binding(int32_t program,
 | |
|                                   uint32_t uniform_index,
 | |
|                                   int32_t uniform_location,
 | |
|                                   int *sampler_len)
 | |
| {
 | |
|   /* Identify sampler uniforms and assign sampler units to them. */
 | |
|   GLint type;
 | |
|   glGetActiveUniformsiv(program, 1, &uniform_index, GL_UNIFORM_TYPE, &type);
 | |
| 
 | |
|   switch (type) {
 | |
|     case GL_SAMPLER_1D:
 | |
|     case GL_SAMPLER_2D:
 | |
|     case GL_SAMPLER_3D:
 | |
|     case GL_SAMPLER_CUBE:
 | |
|     case GL_SAMPLER_CUBE_MAP_ARRAY_ARB: /* OpenGL 4.0 */
 | |
|     case GL_SAMPLER_1D_SHADOW:
 | |
|     case GL_SAMPLER_2D_SHADOW:
 | |
|     case GL_SAMPLER_1D_ARRAY:
 | |
|     case GL_SAMPLER_2D_ARRAY:
 | |
|     case GL_SAMPLER_1D_ARRAY_SHADOW:
 | |
|     case GL_SAMPLER_2D_ARRAY_SHADOW:
 | |
|     case GL_SAMPLER_2D_MULTISAMPLE:
 | |
|     case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
 | |
|     case GL_SAMPLER_CUBE_SHADOW:
 | |
|     case GL_SAMPLER_BUFFER:
 | |
|     case GL_INT_SAMPLER_1D:
 | |
|     case GL_INT_SAMPLER_2D:
 | |
|     case GL_INT_SAMPLER_3D:
 | |
|     case GL_INT_SAMPLER_CUBE:
 | |
|     case GL_INT_SAMPLER_1D_ARRAY:
 | |
|     case GL_INT_SAMPLER_2D_ARRAY:
 | |
|     case GL_INT_SAMPLER_2D_MULTISAMPLE:
 | |
|     case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
 | |
|     case GL_INT_SAMPLER_BUFFER:
 | |
|     case GL_UNSIGNED_INT_SAMPLER_1D:
 | |
|     case GL_UNSIGNED_INT_SAMPLER_2D:
 | |
|     case GL_UNSIGNED_INT_SAMPLER_3D:
 | |
|     case GL_UNSIGNED_INT_SAMPLER_CUBE:
 | |
|     case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
 | |
|     case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
 | |
|     case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
 | |
|     case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
 | |
|     case GL_UNSIGNED_INT_SAMPLER_BUFFER: {
 | |
|       /* For now just assign a consecutive index. In the future, we should set it in
 | |
|        * the shader using layout(binding = i) and query its value. */
 | |
|       int binding = *sampler_len;
 | |
|       glUniform1i(uniform_location, binding);
 | |
|       (*sampler_len)++;
 | |
|       return binding;
 | |
|     }
 | |
|     default:
 | |
|       return -1;
 | |
|   }
 | |
| }
 | |
| 
 | |
| static inline int image_binding(int32_t program,
 | |
|                                 uint32_t uniform_index,
 | |
|                                 int32_t uniform_location,
 | |
|                                 int *image_len)
 | |
| {
 | |
|   /* Identify image uniforms and assign image units to them. */
 | |
|   GLint type;
 | |
|   glGetActiveUniformsiv(program, 1, &uniform_index, GL_UNIFORM_TYPE, &type);
 | |
| 
 | |
|   switch (type) {
 | |
|     case GL_IMAGE_1D:
 | |
|     case GL_IMAGE_2D:
 | |
|     case GL_IMAGE_3D: {
 | |
|       /* For now just assign a consecutive index. In the future, we should set it in
 | |
|        * the shader using layout(binding = i) and query its value. */
 | |
|       int binding = *image_len;
 | |
|       glUniform1i(uniform_location, binding);
 | |
|       (*image_len)++;
 | |
|       return binding;
 | |
|     }
 | |
|     default:
 | |
|       return -1;
 | |
|   }
 | |
| }
 | |
| 
 | |
| static inline int ssbo_binding(int32_t program, uint32_t ssbo_index)
 | |
| {
 | |
|   GLint binding = -1;
 | |
|   GLenum property = GL_BUFFER_BINDING;
 | |
|   GLint values_written = 0;
 | |
|   glGetProgramResourceiv(
 | |
|       program, GL_SHADER_STORAGE_BLOCK, ssbo_index, 1, &property, 1, &values_written, &binding);
 | |
| 
 | |
|   return binding;
 | |
| }
 | |
| 
 | |
| /** \} */
 | |
| 
 | |
| /* -------------------------------------------------------------------- */
 | |
| /** \name Creation / Destruction
 | |
|  * \{ */
 | |
| 
 | |
| GLShaderInterface::GLShaderInterface(GLuint program)
 | |
| {
 | |
|   /* Necessary to make #glUniform works. */
 | |
|   glUseProgram(program);
 | |
| 
 | |
|   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);
 | |
| 
 | |
|   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);
 | |
| 
 | |
|   GLint max_uniform_name_len = 0, active_uniform_len = 0, uniform_len = 0;
 | |
|   glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_uniform_name_len);
 | |
|   glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &active_uniform_len);
 | |
|   uniform_len = active_uniform_len;
 | |
| 
 | |
|   GLint max_ssbo_name_len = 0, ssbo_len = 0;
 | |
|   if (GPU_shader_storage_buffer_objects_support()) {
 | |
|     glGetProgramInterfaceiv(program, GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_RESOURCES, &ssbo_len);
 | |
|     glGetProgramInterfaceiv(
 | |
|         program, GL_SHADER_STORAGE_BLOCK, GL_MAX_NAME_LENGTH, &max_ssbo_name_len);
 | |
|   }
 | |
| 
 | |
|   BLI_assert_msg(ubo_len <= 16, "enabled_ubo_mask_ is uint16_t");
 | |
| 
 | |
|   /* 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;
 | |
|   }
 | |
|   if (uniform_len > 0 && max_uniform_name_len == 0) {
 | |
|     max_uniform_name_len = 256;
 | |
|   }
 | |
|   if (ssbo_len > 0 && max_ssbo_name_len == 0) {
 | |
|     max_ssbo_name_len = 256;
 | |
|   }
 | |
| 
 | |
|   /* GL_ACTIVE_UNIFORMS lied to us! Remove the UBO uniforms from the total before
 | |
|    * allocating the uniform array. */
 | |
|   GLint max_ubo_uni_len = 0;
 | |
|   for (int i = 0; i < ubo_len; i++) {
 | |
|     GLint ubo_uni_len;
 | |
|     glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &ubo_uni_len);
 | |
|     max_ubo_uni_len = max_ii(max_ubo_uni_len, ubo_uni_len);
 | |
|     uniform_len -= ubo_uni_len;
 | |
|   }
 | |
|   /* Bit set to true if uniform comes from a uniform block. */
 | |
|   BLI_bitmap *uniforms_from_blocks = BLI_BITMAP_NEW(active_uniform_len, __func__);
 | |
|   /* Set uniforms from block for exclusion. */
 | |
|   GLint *ubo_uni_ids = (GLint *)MEM_mallocN(sizeof(GLint) * max_ubo_uni_len, __func__);
 | |
|   for (int i = 0; i < ubo_len; i++) {
 | |
|     GLint ubo_uni_len;
 | |
|     glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &ubo_uni_len);
 | |
|     glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, ubo_uni_ids);
 | |
|     for (int u = 0; u < ubo_uni_len; u++) {
 | |
|       BLI_BITMAP_ENABLE(uniforms_from_blocks, ubo_uni_ids[u]);
 | |
|     }
 | |
|   }
 | |
|   MEM_freeN(ubo_uni_ids);
 | |
| 
 | |
|   int input_tot_len = attr_len + ubo_len + uniform_len + ssbo_len;
 | |
|   inputs_ = (ShaderInput *)MEM_callocN(sizeof(ShaderInput) * input_tot_len, __func__);
 | |
| 
 | |
|   const uint32_t name_buffer_len = attr_len * max_attr_name_len + ubo_len * max_ubo_name_len +
 | |
|                                    uniform_len * max_uniform_name_len +
 | |
|                                    ssbo_len * max_ssbo_name_len;
 | |
|   name_buffer_ = (char *)MEM_mallocN(name_buffer_len, "name_buffer");
 | |
|   uint32_t name_buffer_offset = 0;
 | |
| 
 | |
|   /* Attributes */
 | |
|   enabled_attr_mask_ = 0;
 | |
|   for (int i = 0; i < attr_len; i++) {
 | |
|     char *name = name_buffer_ + name_buffer_offset;
 | |
|     GLsizei remaining_buffer = name_buffer_len - name_buffer_offset;
 | |
|     GLsizei name_len = 0;
 | |
|     GLenum type;
 | |
|     GLint size;
 | |
| 
 | |
|     glGetActiveAttrib(program, i, remaining_buffer, &name_len, &size, &type, name);
 | |
|     GLint location = glGetAttribLocation(program, name);
 | |
|     /* Ignore OpenGL names like `gl_BaseInstanceARB`, `gl_InstanceID` and `gl_VertexID`. */
 | |
|     if (location == -1) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     ShaderInput *input = &inputs_[attr_len_++];
 | |
|     input->location = input->binding = location;
 | |
| 
 | |
|     name_buffer_offset += set_input_name(input, name, name_len);
 | |
|     enabled_attr_mask_ |= (1 << input->location);
 | |
|   }
 | |
| 
 | |
|   /* Uniform Blocks */
 | |
|   for (int i = 0; i < ubo_len; i++) {
 | |
|     char *name = name_buffer_ + name_buffer_offset;
 | |
|     GLsizei remaining_buffer = name_buffer_len - name_buffer_offset;
 | |
|     GLsizei name_len = 0;
 | |
| 
 | |
|     glGetActiveUniformBlockName(program, i, remaining_buffer, &name_len, name);
 | |
| 
 | |
|     ShaderInput *input = &inputs_[attr_len_ + ubo_len_++];
 | |
|     input->binding = input->location = block_binding(program, i);
 | |
| 
 | |
|     name_buffer_offset += this->set_input_name(input, name, name_len);
 | |
|     enabled_ubo_mask_ |= (1 << input->binding);
 | |
|   }
 | |
| 
 | |
|   /* Uniforms & samplers & images */
 | |
|   for (int i = 0, sampler = 0, image = 0; i < active_uniform_len; i++) {
 | |
|     if (BLI_BITMAP_TEST(uniforms_from_blocks, i)) {
 | |
|       continue;
 | |
|     }
 | |
|     char *name = name_buffer_ + name_buffer_offset;
 | |
|     GLsizei remaining_buffer = name_buffer_len - name_buffer_offset;
 | |
|     GLsizei name_len = 0;
 | |
| 
 | |
|     glGetActiveUniformName(program, i, remaining_buffer, &name_len, name);
 | |
| 
 | |
|     ShaderInput *input = &inputs_[attr_len_ + ubo_len_ + uniform_len_++];
 | |
|     input->location = glGetUniformLocation(program, name);
 | |
|     input->binding = sampler_binding(program, i, input->location, &sampler);
 | |
| 
 | |
|     name_buffer_offset += this->set_input_name(input, name, name_len);
 | |
|     enabled_tex_mask_ |= (input->binding != -1) ? (1lu << input->binding) : 0lu;
 | |
| 
 | |
|     if (input->binding == -1) {
 | |
|       input->binding = image_binding(program, i, input->location, &image);
 | |
| 
 | |
|       enabled_ima_mask_ |= (input->binding != -1) ? (1lu << input->binding) : 0lu;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /* SSBOs */
 | |
|   for (int i = 0; i < ssbo_len; i++) {
 | |
|     char *name = name_buffer_ + name_buffer_offset;
 | |
|     GLsizei remaining_buffer = name_buffer_len - name_buffer_offset;
 | |
|     GLsizei name_len = 0;
 | |
|     glGetProgramResourceName(
 | |
|         program, GL_SHADER_STORAGE_BLOCK, i, remaining_buffer, &name_len, name);
 | |
| 
 | |
|     const GLint binding = ssbo_binding(program, i);
 | |
| 
 | |
|     ShaderInput *input = &inputs_[attr_len_ + ubo_len_ + uniform_len_ + ssbo_len_++];
 | |
|     input->binding = input->location = binding;
 | |
| 
 | |
|     name_buffer_offset += this->set_input_name(input, name, name_len);
 | |
|   }
 | |
| 
 | |
|   /* Builtin Uniforms */
 | |
|   for (int32_t u_int = 0; u_int < GPU_NUM_UNIFORMS; u_int++) {
 | |
|     GPUUniformBuiltin u = static_cast<GPUUniformBuiltin>(u_int);
 | |
|     builtins_[u] = glGetUniformLocation(program, builtin_uniform_name(u));
 | |
|   }
 | |
| 
 | |
|   /* Builtin Uniforms Blocks */
 | |
|   for (int32_t u_int = 0; u_int < GPU_NUM_UNIFORM_BLOCKS; u_int++) {
 | |
|     GPUUniformBlockBuiltin u = static_cast<GPUUniformBlockBuiltin>(u_int);
 | |
|     const ShaderInput *block = this->ubo_get(builtin_uniform_block_name(u));
 | |
|     builtin_blocks_[u] = (block != nullptr) ? block->binding : -1;
 | |
|   }
 | |
| 
 | |
|   MEM_freeN(uniforms_from_blocks);
 | |
| 
 | |
|   /* Resize name buffer to save some memory. */
 | |
|   if (name_buffer_offset < name_buffer_len) {
 | |
|     name_buffer_ = (char *)MEM_reallocN(name_buffer_, name_buffer_offset);
 | |
|   }
 | |
| 
 | |
|   // this->debug_print();
 | |
| 
 | |
|   this->sort_inputs();
 | |
| }
 | |
| 
 | |
| GLShaderInterface::GLShaderInterface(GLuint program, const shader::ShaderCreateInfo &info)
 | |
| {
 | |
|   using namespace blender::gpu::shader;
 | |
| 
 | |
|   attr_len_ = info.vertex_inputs_.size();
 | |
|   uniform_len_ = info.push_constants_.size();
 | |
|   ubo_len_ = 0;
 | |
|   ssbo_len_ = 0;
 | |
| 
 | |
|   Vector<ShaderCreateInfo::Resource> all_resources;
 | |
|   all_resources.extend(info.pass_resources_);
 | |
|   all_resources.extend(info.batch_resources_);
 | |
| 
 | |
|   for (ShaderCreateInfo::Resource &res : all_resources) {
 | |
|     switch (res.bind_type) {
 | |
|       case ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER:
 | |
|         ubo_len_++;
 | |
|         break;
 | |
|       case ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER:
 | |
|         ssbo_len_++;
 | |
|         break;
 | |
|       case ShaderCreateInfo::Resource::BindType::SAMPLER:
 | |
|         uniform_len_++;
 | |
|         break;
 | |
|       case ShaderCreateInfo::Resource::BindType::IMAGE:
 | |
|         uniform_len_++;
 | |
|         break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   size_t workaround_names_size = 0;
 | |
|   Vector<StringRefNull> workaround_uniform_names;
 | |
|   auto check_enabled_uniform = [&](const char *uniform_name) {
 | |
|     if (glGetUniformLocation(program, uniform_name) != -1) {
 | |
|       workaround_uniform_names.append(uniform_name);
 | |
|       workaround_names_size += StringRefNull(uniform_name).size() + 1;
 | |
|       uniform_len_++;
 | |
|     }
 | |
|   };
 | |
| 
 | |
|   if (!GLContext::shader_draw_parameters_support) {
 | |
|     check_enabled_uniform("gpu_BaseInstance");
 | |
|   }
 | |
| 
 | |
|   BLI_assert_msg(ubo_len_ <= 16, "enabled_ubo_mask_ is uint16_t");
 | |
| 
 | |
|   int input_tot_len = attr_len_ + ubo_len_ + uniform_len_ + ssbo_len_;
 | |
|   inputs_ = (ShaderInput *)MEM_callocN(sizeof(ShaderInput) * input_tot_len, __func__);
 | |
|   ShaderInput *input = inputs_;
 | |
| 
 | |
|   name_buffer_ = (char *)MEM_mallocN(info.interface_names_size_ + workaround_names_size,
 | |
|                                      "name_buffer");
 | |
|   uint32_t name_buffer_offset = 0;
 | |
| 
 | |
|   /* Necessary to make #glUniform works. TODO(fclem) Remove. */
 | |
|   glUseProgram(program);
 | |
| 
 | |
|   /* Attributes */
 | |
|   for (const ShaderCreateInfo::VertIn &attr : info.vertex_inputs_) {
 | |
|     copy_input_name(input, attr.name, name_buffer_, name_buffer_offset);
 | |
|     if (true || !GLContext::explicit_location_support) {
 | |
|       input->location = input->binding = glGetAttribLocation(program, attr.name.c_str());
 | |
|     }
 | |
|     else {
 | |
|       input->location = input->binding = attr.index;
 | |
|     }
 | |
|     enabled_attr_mask_ |= (1 << input->location);
 | |
|     input++;
 | |
|   }
 | |
| 
 | |
|   /* Uniform Blocks */
 | |
|   for (const ShaderCreateInfo::Resource &res : all_resources) {
 | |
|     if (res.bind_type == ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER) {
 | |
|       copy_input_name(input, res.uniformbuf.name, name_buffer_, name_buffer_offset);
 | |
|       if (true || !GLContext::explicit_location_support) {
 | |
|         input->location = glGetUniformBlockIndex(program, name_buffer_ + input->name_offset);
 | |
|         glUniformBlockBinding(program, input->location, res.slot);
 | |
|       }
 | |
|       input->binding = res.slot;
 | |
|       enabled_ubo_mask_ |= (1 << input->binding);
 | |
|       input++;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /* Uniforms & samplers & images */
 | |
|   for (const ShaderCreateInfo::Resource &res : all_resources) {
 | |
|     if (res.bind_type == ShaderCreateInfo::Resource::BindType::SAMPLER) {
 | |
|       copy_input_name(input, res.sampler.name, name_buffer_, name_buffer_offset);
 | |
|       /* Until we make use of explicit uniform location or eliminate all
 | |
|        * sampler manually changing. */
 | |
|       if (true || !GLContext::explicit_location_support) {
 | |
|         input->location = glGetUniformLocation(program, res.sampler.name.c_str());
 | |
|         glUniform1i(input->location, res.slot);
 | |
|       }
 | |
|       input->binding = res.slot;
 | |
|       enabled_tex_mask_ |= (1ull << input->binding);
 | |
|       input++;
 | |
|     }
 | |
|     else if (res.bind_type == ShaderCreateInfo::Resource::BindType::IMAGE) {
 | |
|       copy_input_name(input, res.image.name, name_buffer_, name_buffer_offset);
 | |
|       /* Until we make use of explicit uniform location. */
 | |
|       if (true || !GLContext::explicit_location_support) {
 | |
|         input->location = glGetUniformLocation(program, res.image.name.c_str());
 | |
|         glUniform1i(input->location, res.slot);
 | |
|       }
 | |
|       input->binding = res.slot;
 | |
|       enabled_ima_mask_ |= (1 << input->binding);
 | |
|       input++;
 | |
|     }
 | |
|   }
 | |
|   for (const ShaderCreateInfo::PushConst &uni : info.push_constants_) {
 | |
|     copy_input_name(input, uni.name, name_buffer_, name_buffer_offset);
 | |
|     input->location = glGetUniformLocation(program, name_buffer_ + input->name_offset);
 | |
|     input->binding = -1;
 | |
|     input++;
 | |
|   }
 | |
| 
 | |
|   /* Compatibility uniforms. */
 | |
|   for (auto &name : workaround_uniform_names) {
 | |
|     copy_input_name(input, name, name_buffer_, name_buffer_offset);
 | |
|     input->location = glGetUniformLocation(program, name_buffer_ + input->name_offset);
 | |
|     input->binding = -1;
 | |
|     input++;
 | |
|   }
 | |
| 
 | |
|   /* SSBOs */
 | |
|   for (const ShaderCreateInfo::Resource &res : all_resources) {
 | |
|     if (res.bind_type == ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER) {
 | |
|       copy_input_name(input, res.storagebuf.name, name_buffer_, name_buffer_offset);
 | |
|       input->location = input->binding = res.slot;
 | |
|       enabled_ubo_mask_ |= (1 << input->binding);
 | |
|       input++;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /* Builtin Uniforms */
 | |
|   for (int32_t u_int = 0; u_int < GPU_NUM_UNIFORMS; u_int++) {
 | |
|     GPUUniformBuiltin u = static_cast<GPUUniformBuiltin>(u_int);
 | |
|     const ShaderInput *uni = this->uniform_get(builtin_uniform_name(u));
 | |
|     builtins_[u] = (uni != nullptr) ? uni->location : -1;
 | |
|   }
 | |
| 
 | |
|   /* Builtin Uniforms Blocks */
 | |
|   for (int32_t u_int = 0; u_int < GPU_NUM_UNIFORM_BLOCKS; u_int++) {
 | |
|     GPUUniformBlockBuiltin u = static_cast<GPUUniformBlockBuiltin>(u_int);
 | |
|     const ShaderInput *block = this->ubo_get(builtin_uniform_block_name(u));
 | |
|     builtin_blocks_[u] = (block != nullptr) ? block->binding : -1;
 | |
|   }
 | |
| 
 | |
|   this->sort_inputs();
 | |
| 
 | |
|   // this->debug_print();
 | |
| }
 | |
| 
 | |
| GLShaderInterface::~GLShaderInterface()
 | |
| {
 | |
|   for (auto *ref : refs_) {
 | |
|     if (ref != nullptr) {
 | |
|       ref->remove(this);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| /** \} */
 | |
| 
 | |
| /* -------------------------------------------------------------------- */
 | |
| /** \name Batch Reference
 | |
|  * \{ */
 | |
| 
 | |
| void GLShaderInterface::ref_add(GLVaoCache *ref)
 | |
| {
 | |
|   for (int i = 0; i < refs_.size(); i++) {
 | |
|     if (refs_[i] == nullptr) {
 | |
|       refs_[i] = ref;
 | |
|       return;
 | |
|     }
 | |
|   }
 | |
|   refs_.append(ref);
 | |
| }
 | |
| 
 | |
| void GLShaderInterface::ref_remove(GLVaoCache *ref)
 | |
| {
 | |
|   for (int i = 0; i < refs_.size(); i++) {
 | |
|     if (refs_[i] == ref) {
 | |
|       refs_[i] = nullptr;
 | |
|       break; /* cannot have duplicates */
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| /** \} */
 | |
| 
 | |
| /* -------------------------------------------------------------------- */
 | |
| /** \name Validation
 | |
|  * TODO
 | |
|  * \{ */
 | |
| 
 | |
| /** \} */
 | |
| 
 | |
| }  // namespace blender::gpu
 |