Browse Source

glgsg: Fix binding assignment for image2D et al in OpenGL ES

For some reason my driver assigns the same binding index (0) even when the images have differing locations.

May need to be revisited to support structs with mixed images and samplers, may need to apply hoisting pass
rdb 1 year ago
parent
commit
f2cc31a9a7

+ 3 - 0
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -2155,6 +2155,8 @@ reset() {
        get_extension_func("glGetShaderInfoLog");
        get_extension_func("glGetShaderInfoLog");
     _glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)
     _glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)
        get_extension_func("glGetUniformLocation");
        get_extension_func("glGetUniformLocation");
+    _glGetUniformiv = (PFNGLGETUNIFORMIVPROC)
+       get_extension_func("glGetUniformiv");
     _glLinkProgram = (PFNGLLINKPROGRAMPROC)
     _glLinkProgram = (PFNGLLINKPROGRAMPROC)
        get_extension_func("glLinkProgram");
        get_extension_func("glLinkProgram");
     _glShaderSource = (PFNGLSHADERSOURCEPROC_P)
     _glShaderSource = (PFNGLSHADERSOURCEPROC_P)
@@ -2311,6 +2313,7 @@ reset() {
   _glGetShaderiv = glGetShaderiv;
   _glGetShaderiv = glGetShaderiv;
   _glGetShaderInfoLog = glGetShaderInfoLog;
   _glGetShaderInfoLog = glGetShaderInfoLog;
   _glGetUniformLocation = glGetUniformLocation;
   _glGetUniformLocation = glGetUniformLocation;
+  _glGetUniformiv = glGetUniformiv;
   _glLinkProgram = glLinkProgram;
   _glLinkProgram = glLinkProgram;
   _glShaderSource = (PFNGLSHADERSOURCEPROC_P) glShaderSource;
   _glShaderSource = (PFNGLSHADERSOURCEPROC_P) glShaderSource;
   _glUseProgram = glUseProgram;
   _glUseProgram = glUseProgram;

+ 2 - 0
panda/src/glstuff/glGraphicsStateGuardian_src.h

@@ -166,6 +166,7 @@ typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei buf
 typedef void (APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params);
 typedef void (APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params);
 typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
 typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
 typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name);
 typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name);
+typedef void (APIENTRYP PFNGLGETUNIFORMIVPROC) (GLuint program, GLint location, GLint *params);
 typedef void (APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program);
 typedef void (APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program);
 typedef void (APIENTRYP PFNGLSHADERSOURCEPROC_P) (GLuint shader, GLsizei count, const GLchar* const *string, const GLint *length);
 typedef void (APIENTRYP PFNGLSHADERSOURCEPROC_P) (GLuint shader, GLsizei count, const GLchar* const *string, const GLint *length);
 typedef void (APIENTRYP PFNGLSPECIALIZESHADERARBPROC) (GLuint shader, const GLchar *, GLuint, const GLuint *, const GLuint *);
 typedef void (APIENTRYP PFNGLSPECIALIZESHADERARBPROC) (GLuint shader, const GLchar *, GLuint, const GLuint *, const GLuint *);
@@ -1051,6 +1052,7 @@ public:
   PFNGLGETSHADERIVPROC _glGetShaderiv;
   PFNGLGETSHADERIVPROC _glGetShaderiv;
   PFNGLGETSHADERINFOLOGPROC _glGetShaderInfoLog;
   PFNGLGETSHADERINFOLOGPROC _glGetShaderInfoLog;
   PFNGLGETUNIFORMLOCATIONPROC _glGetUniformLocation;
   PFNGLGETUNIFORMLOCATIONPROC _glGetUniformLocation;
+  PFNGLGETUNIFORMIVPROC _glGetUniformiv;
   PFNGLLINKPROGRAMPROC _glLinkProgram;
   PFNGLLINKPROGRAMPROC _glLinkProgram;
   PFNGLSPECIALIZESHADERARBPROC _glSpecializeShader;
   PFNGLSPECIALIZESHADERARBPROC _glSpecializeShader;
   PFNGLSHADERBINARYPROC _glShaderBinary;
   PFNGLSHADERBINARYPROC _glShaderBinary;

+ 79 - 43
panda/src/glstuff/glShaderContext_src.cxx

@@ -58,28 +58,42 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
   // Ignoring any locations that may have already been set, we assign a new
   // Ignoring any locations that may have already been set, we assign a new
   // unique location to each parameter.
   // unique location to each parameter.
   LocationMap locations;
   LocationMap locations;
-  LocationMap ssbo_bindings;
+  LocationMap bindings;
   GLint next_location = 0;
   GLint next_location = 0;
   GLint next_ssbo_binding = 0;
   GLint next_ssbo_binding = 0;
+#ifdef OPENGLES
+  GLint next_image_binding = 0;
+#endif
   for (const Shader::Parameter &param : _shader->_parameters) {
   for (const Shader::Parameter &param : _shader->_parameters) {
     GLint num_locations = 0;
     GLint num_locations = 0;
     GLint num_ssbo_bindings = 0;
     GLint num_ssbo_bindings = 0;
-    r_count_locations_bindings(param._type, num_locations, num_ssbo_bindings);
+    GLint num_image_bindings = 0;
+    r_count_locations_bindings(param._type, num_locations, num_ssbo_bindings,
+                               num_image_bindings);
 
 
     if (num_locations > 0) {
     if (num_locations > 0) {
       locations[param._name] = next_location;
       locations[param._name] = next_location;
       next_location += num_locations;
       next_location += num_locations;
     }
     }
     if (num_ssbo_bindings > 0) {
     if (num_ssbo_bindings > 0) {
-      ssbo_bindings[param._name] = next_ssbo_binding;
+      bindings[param._name] = next_ssbo_binding;
       next_ssbo_binding += num_ssbo_bindings;
       next_ssbo_binding += num_ssbo_bindings;
     }
     }
+#ifdef OPENGLES
+    // For OpenGL ES, we can't specify the binding after the fact, so we
+    // have to specify the bindings up front.
+    if (num_image_bindings > 0) {
+      //TODO: what if there is a struct with mixed samplers and images?
+      bindings[param._name] = next_image_binding;
+      next_image_binding += num_image_bindings;
+    }
+#endif
   }
   }
 
 
   // We compile and analyze the shader here, instead of in shader.cxx, to
   // We compile and analyze the shader here, instead of in shader.cxx, to
   // avoid gobj getting a dependency on GL stuff.
   // avoid gobj getting a dependency on GL stuff.
   bool remap_locations = false;
   bool remap_locations = false;
-  if (!compile_and_link(locations, remap_locations, ssbo_bindings)) {
+  if (!compile_and_link(locations, remap_locations, bindings)) {
     release_resources();
     release_resources();
     s->_error_flag = true;
     s->_error_flag = true;
     return;
     return;
@@ -93,9 +107,9 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
   SparseArray active_locations;
   SparseArray active_locations;
   if (_is_legacy) {
   if (_is_legacy) {
     locations.clear();
     locations.clear();
-    ssbo_bindings.clear();
+    bindings.clear();
 
 
-    reflect_program(active_locations, locations, ssbo_bindings);
+    reflect_program(active_locations, locations, bindings);
   }
   }
   else if (!remap_locations) {
   else if (!remap_locations) {
     // We still need to query which uniform locations are actually in use,
     // We still need to query which uniform locations are actually in use,
@@ -142,11 +156,11 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
       }
       }
     }
     }
 
 
-    int ssbo_binding = -1;
+    int binding = -1;
     {
     {
-      auto it = ssbo_bindings.find(param._name);
-      if (it != ssbo_bindings.end()) {
-        ssbo_binding = it->second;
+      auto it = bindings.find(param._name);
+      if (it != bindings.end()) {
+        binding = it->second;
       }
       }
     }
     }
 
 
@@ -162,7 +176,7 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
     }
     }
     r_collect_uniforms(param, block, param._type, name.c_str(), sym_buffer,
     r_collect_uniforms(param, block, param._type, name.c_str(), sym_buffer,
                        actual_location, active_locations, resource_index,
                        actual_location, active_locations, resource_index,
-                       ssbo_binding);
+                       binding);
 
 
     if (!block._matrices.empty() || !block._vectors.empty()) {
     if (!block._matrices.empty() || !block._vectors.empty()) {
       _uniform_data_deps |= block._dep;
       _uniform_data_deps |= block._dep;
@@ -219,20 +233,22 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
  */
  */
 void CLP(ShaderContext)::
 void CLP(ShaderContext)::
 r_count_locations_bindings(const ShaderType *type,
 r_count_locations_bindings(const ShaderType *type,
-                           GLint &num_locations, GLint &num_ssbo_bindings) {
+                           GLint &num_locations, GLint &num_ssbo_bindings,
+                           GLint &num_image_bindings) {
 
 
   if (const ShaderType::Array *array_type = type->as_array()) {
   if (const ShaderType::Array *array_type = type->as_array()) {
-    GLint element_locs = 0, element_binds = 0;
-    r_count_locations_bindings(array_type->get_element_type(), element_locs, element_binds);
+    GLint element_locs = 0, element_ssbo_binds = 0, element_img_binds = 0;
+    r_count_locations_bindings(array_type->get_element_type(), element_locs, element_ssbo_binds, element_img_binds);
     num_locations += element_locs * array_type->get_num_elements();
     num_locations += element_locs * array_type->get_num_elements();
-    num_ssbo_bindings += element_binds * array_type->get_num_elements();
+    num_ssbo_bindings += element_ssbo_binds * array_type->get_num_elements();
+    num_image_bindings += element_img_binds * array_type->get_num_elements();
     return;
     return;
   }
   }
   if (const ShaderType::Struct *struct_type = type->as_struct()) {
   if (const ShaderType::Struct *struct_type = type->as_struct()) {
     for (uint32_t i = 0; i < struct_type->get_num_members(); ++i) {
     for (uint32_t i = 0; i < struct_type->get_num_members(); ++i) {
       const ShaderType::Struct::Member &member = struct_type->get_member(i);
       const ShaderType::Struct::Member &member = struct_type->get_member(i);
 
 
-      r_count_locations_bindings(member.type, num_locations, num_ssbo_bindings);
+      r_count_locations_bindings(member.type, num_locations, num_ssbo_bindings, num_image_bindings);
     }
     }
     return;
     return;
   }
   }
@@ -246,9 +262,13 @@ r_count_locations_bindings(const ShaderType *type,
     return;
     return;
   }
   }
 
 
-  if (type->as_sampled_image() != nullptr ||
-      type->as_image() != nullptr ||
-      type == ShaderType::void_type) {
+  if (type->as_image() != nullptr) {
+    ++num_locations;
+    ++num_image_bindings;
+    return;
+  }
+
+  if (type->as_sampled_image() != nullptr || type == ShaderType::void_type) {
     ++num_locations;
     ++num_locations;
     return;
     return;
   }
   }
@@ -269,7 +289,7 @@ void CLP(ShaderContext)::
 r_collect_uniforms(const Shader::Parameter &param, UniformBlock &block,
 r_collect_uniforms(const Shader::Parameter &param, UniformBlock &block,
                    const ShaderType *type, const char *name, const char *sym,
                    const ShaderType *type, const char *name, const char *sym,
                    int &cur_location, const SparseArray &active_locations,
                    int &cur_location, const SparseArray &active_locations,
-                   int &resource_index, int &ssbo_binding, size_t offset) {
+                   int &resource_index, int &cur_binding, size_t offset) {
 
 
   ShaderType::ScalarType scalar_type;
   ShaderType::ScalarType scalar_type;
   uint32_t num_elements;
   uint32_t num_elements;
@@ -393,7 +413,7 @@ r_collect_uniforms(const Shader::Parameter &param, UniformBlock &block,
       sprintf(name_buffer, "%s[%u]", name, i);
       sprintf(name_buffer, "%s[%u]", name, i);
       sprintf(sym_buffer, "%s[%u]", sym, i);
       sprintf(sym_buffer, "%s[%u]", sym, i);
       r_collect_uniforms(param, block, element_type, name_buffer, sym_buffer,
       r_collect_uniforms(param, block, element_type, name_buffer, sym_buffer,
-                         cur_location, active_locations, resource_index, ssbo_binding,
+                         cur_location, active_locations, resource_index, cur_binding,
                          offset);
                          offset);
       offset += stride;
       offset += stride;
     }
     }
@@ -411,7 +431,7 @@ r_collect_uniforms(const Shader::Parameter &param, UniformBlock &block,
       // SPIRV-Cross names struct members _m0, _m1, etc. in declaration order.
       // SPIRV-Cross names struct members _m0, _m1, etc. in declaration order.
       sprintf(sym_buffer, "%s._m%u", sym, i);
       sprintf(sym_buffer, "%s._m%u", sym, i);
       r_collect_uniforms(param, block, member.type, qualname.c_str(), sym_buffer,
       r_collect_uniforms(param, block, member.type, qualname.c_str(), sym_buffer,
-                         cur_location, active_locations, resource_index, ssbo_binding,
+                         cur_location, active_locations, resource_index, cur_binding,
                          offset + member.offset);
                          offset + member.offset);
     }
     }
     return;
     return;
@@ -423,14 +443,14 @@ r_collect_uniforms(const Shader::Parameter &param, UniformBlock &block,
 
 
   if (type->as_storage_buffer() != nullptr) {
   if (type->as_storage_buffer() != nullptr) {
     // These are an exception, they do not have locations but bindings.
     // These are an exception, they do not have locations but bindings.
-    GLint binding = ssbo_binding;
+    GLint binding = cur_binding;
     if (binding < 0) {
     if (binding < 0) {
       // We have to look this one up.
       // We have to look this one up.
       GLuint index = _glgsg->_glGetProgramResourceIndex(_glsl_program, GL_SHADER_STORAGE_BLOCK, name);
       GLuint index = _glgsg->_glGetProgramResourceIndex(_glsl_program, GL_SHADER_STORAGE_BLOCK, name);
       const GLenum props[] = {GL_BUFFER_BINDING};
       const GLenum props[] = {GL_BUFFER_BINDING};
       _glgsg->_glGetProgramResourceiv(_glsl_program, GL_SHADER_STORAGE_BLOCK, index, 1, props, 1, nullptr, &binding);
       _glgsg->_glGetProgramResourceiv(_glsl_program, GL_SHADER_STORAGE_BLOCK, index, 1, props, 1, nullptr, &binding);
     } else {
     } else {
-      ++ssbo_binding;
+      ++cur_binding;
     }
     }
 
 
     if (GLCAT.is_debug()) {
     if (GLCAT.is_debug()) {
@@ -442,7 +462,7 @@ r_collect_uniforms(const Shader::Parameter &param, UniformBlock &block,
     StorageBlock block;
     StorageBlock block;
     block._binding = param._binding;
     block._binding = param._binding;
     block._resource_id = param._binding->get_resource_id(resource_index++, type);
     block._resource_id = param._binding->get_resource_id(resource_index++, type);
-    block._binding_index = binding++;
+    block._binding_index = binding;
     _storage_blocks.push_back(std::move(block));
     _storage_blocks.push_back(std::move(block));
     return;
     return;
   }
   }
@@ -482,7 +502,12 @@ r_collect_uniforms(const Shader::Parameter &param, UniformBlock &block,
     unit._access = image->get_access();
     unit._access = image->get_access();
     unit._written = false;
     unit._written = false;
 
 
+    // In OpenGL ES, we can't specify a binding index after the fact.
+#ifdef OPENGLES
+    _glgsg->_glGetUniformiv(_glsl_program, location, &unit._binding_index);
+#else
     _glgsg->_glUniform1i(location, (GLint)_image_units.size());
     _glgsg->_glUniform1i(location, (GLint)_image_units.size());
+#endif
     _image_units.push_back(std::move(unit));
     _image_units.push_back(std::move(unit));
   }
   }
   else if (type->as_resource()) {
   else if (type->as_resource()) {
@@ -1936,7 +1961,12 @@ disable_shader_texture_bindings() {
 #endif
 #endif
     {
     {
       for (int i = 0; i < num_image_units; ++i) {
       for (int i = 0; i < num_image_units; ++i) {
-        _glgsg->_glBindImageTexture(i, 0, 0, GL_FALSE, 0, GL_READ_ONLY, GL_R8);
+#ifdef OPENGLES
+        GLint binding_index = _image_units[i]._binding_index;
+#else
+        GLint binding_index = i;
+#endif
+        _glgsg->_glBindImageTexture(binding_index, 0, 0, GL_FALSE, 0, GL_READ_ONLY, GL_R8);
       }
       }
     }
     }
 
 
@@ -1986,6 +2016,12 @@ update_shader_texture_bindings(ShaderContext *prev) {
     for (int i = 0; i < num_image_units; ++i) {
     for (int i = 0; i < num_image_units; ++i) {
       ImageUnit &unit = _image_units[i];
       ImageUnit &unit = _image_units[i];
 
 
+#ifdef OPENGLES
+      GLint binding_index = unit._binding_index;
+#else
+      GLint binding_index = i;
+#endif
+
       ShaderType::Access access = ShaderType::Access::READ_WRITE;
       ShaderType::Access access = ShaderType::Access::READ_WRITE;
       int z = -1;
       int z = -1;
       int n = 0;
       int n = 0;
@@ -2014,7 +2050,7 @@ update_shader_texture_bindings(ShaderContext *prev) {
       }
       }
 
 
       if (gl_tex == 0) {
       if (gl_tex == 0) {
-        _glgsg->_glBindImageTexture(i, 0, 0, GL_FALSE, 0, GL_READ_ONLY, GL_R8);
+        _glgsg->_glBindImageTexture(binding_index, 0, 0, GL_FALSE, 0, GL_READ_ONLY, GL_R8);
 
 
       } else {
       } else {
         // TODO: automatically convert to sized type instead of plain GL_RGBA
         // TODO: automatically convert to sized type instead of plain GL_RGBA
@@ -2066,8 +2102,8 @@ update_shader_texture_bindings(ShaderContext *prev) {
           break;
           break;
         }
         }
 
 
-        _glgsg->_glBindImageTexture(i, gl_tex, bind_level, layered, bind_layer,
-                                    gl_access, gtc->_internal_format);
+        _glgsg->_glBindImageTexture(binding_index, gl_tex, bind_level, layered,
+                                    bind_layer, gl_access, gtc->_internal_format);
       }
       }
     }
     }
   }
   }
@@ -2336,7 +2372,7 @@ report_program_errors(GLuint program, bool fatal) {
 bool CLP(ShaderContext)::
 bool CLP(ShaderContext)::
 attach_shader(const ShaderModule *module, Shader::ModuleSpecConstants &consts,
 attach_shader(const ShaderModule *module, Shader::ModuleSpecConstants &consts,
               const LocationMap &locations, bool &remap_locations,
               const LocationMap &locations, bool &remap_locations,
-              const LocationMap &ssbo_bindings) {
+              const LocationMap &bindings) {
   ShaderModule::Stage stage = module->get_stage();
   ShaderModule::Stage stage = module->get_stage();
 
 
   GLuint handle = 0;
   GLuint handle = 0;
@@ -2389,7 +2425,7 @@ attach_shader(const ShaderModule *module, Shader::ModuleSpecConstants &consts,
     ShaderModuleSpirV *spv = (ShaderModuleSpirV *)module;
     ShaderModuleSpirV *spv = (ShaderModuleSpirV *)module;
 
 
     pmap<uint32_t, int> id_to_location;
     pmap<uint32_t, int> id_to_location;
-    pvector<uint32_t> ssbo_binding_ids;
+    pvector<uint32_t> binding_ids;
     for (size_t pi = 0; pi < module->get_num_parameters(); ++pi) {
     for (size_t pi = 0; pi < module->get_num_parameters(); ++pi) {
       const ShaderModule::Variable &var = module->get_parameter(pi);
       const ShaderModule::Variable &var = module->get_parameter(pi);
       {
       {
@@ -2399,12 +2435,12 @@ attach_shader(const ShaderModule *module, Shader::ModuleSpecConstants &consts,
         }
         }
       }
       }
       {
       {
-        auto it = ssbo_bindings.find(var.name);
-        if (it != ssbo_bindings.end()) {
-          if (it->second >= (int)ssbo_binding_ids.size()) {
-            ssbo_binding_ids.resize(it->second + 1, 0);
+        auto it = bindings.find(var.name);
+        if (it != bindings.end()) {
+          if (it->second >= (int)binding_ids.size()) {
+            binding_ids.resize(it->second + 1, 0);
           }
           }
-          ssbo_binding_ids[it->second] = var.id;
+          binding_ids[it->second] = var.id;
         }
         }
       }
       }
     }
     }
@@ -2434,8 +2470,8 @@ attach_shader(const ShaderModule *module, Shader::ModuleSpecConstants &consts,
           transformer.assign_procedural_names("p", id_to_location);
           transformer.assign_procedural_names("p", id_to_location);
         }
         }
       }
       }
-      if (!ssbo_binding_ids.empty()) {
-        transformer.bind_descriptor_set(0, ssbo_binding_ids);
+      if (!binding_ids.empty()) {
+        transformer.bind_descriptor_set(0, binding_ids);
       }
       }
 
 
       ShaderModuleSpirV::InstructionStream stream = transformer.get_result();
       ShaderModuleSpirV::InstructionStream stream = transformer.get_result();
@@ -2472,7 +2508,7 @@ attach_shader(const ShaderModule *module, Shader::ModuleSpecConstants &consts,
 
 
       // We want to use explicit bindings for SSBOs, which requires 420 or
       // We want to use explicit bindings for SSBOs, which requires 420 or
       // the 420pack extension.  Presumably we have it if we support SSBOs.
       // the 420pack extension.  Presumably we have it if we support SSBOs.
-      if (!ssbo_binding_ids.empty() && !options.es && options.version < 420) {
+      if (!binding_ids.empty() && !options.es && options.version < 420) {
         options.enable_420pack_extension = true;
         options.enable_420pack_extension = true;
       }
       }
 
 
@@ -2596,8 +2632,8 @@ attach_shader(const ShaderModule *module, Shader::ModuleSpecConstants &consts,
       }
       }
 
 
       // Add bindings for the shader storage buffers.
       // Add bindings for the shader storage buffers.
-      for (size_t binding = 0; binding < ssbo_binding_ids.size(); ++binding) {
-        uint32_t id = ssbo_binding_ids[binding];
+      for (size_t binding = 0; binding < binding_ids.size(); ++binding) {
+        uint32_t id = binding_ids[binding];
         if (id > 0) {
         if (id > 0) {
           compiler.set_decoration(id, spv::DecorationBinding, binding);
           compiler.set_decoration(id, spv::DecorationBinding, binding);
         }
         }
@@ -2658,7 +2694,7 @@ attach_shader(const ShaderModule *module, Shader::ModuleSpecConstants &consts,
  */
  */
 bool CLP(ShaderContext)::
 bool CLP(ShaderContext)::
 compile_and_link(const LocationMap &locations, bool &remap_locations,
 compile_and_link(const LocationMap &locations, bool &remap_locations,
-                 const LocationMap &ssbo_bindings) {
+                 const LocationMap &bindings) {
   _modules.clear();
   _modules.clear();
   _glsl_program = _glgsg->_glCreateProgram();
   _glsl_program = _glgsg->_glCreateProgram();
   if (!_glsl_program) {
   if (!_glsl_program) {
@@ -2697,7 +2733,7 @@ compile_and_link(const LocationMap &locations, bool &remap_locations,
   bool valid = true;
   bool valid = true;
   for (Shader::LinkedModule &linked_module : _shader->_modules) {
   for (Shader::LinkedModule &linked_module : _shader->_modules) {
     valid &= attach_shader(linked_module._module.get_read_pointer(), linked_module._consts,
     valid &= attach_shader(linked_module._module.get_read_pointer(), linked_module._consts,
-                           locations, remap_locations, ssbo_bindings);
+                           locations, remap_locations, bindings);
   }
   }
 
 
   if (!valid) {
   if (!valid) {

+ 7 - 3
panda/src/glstuff/glShaderContext_src.h

@@ -42,13 +42,14 @@ public:
 
 
   static void r_count_locations_bindings(const ShaderType *type,
   static void r_count_locations_bindings(const ShaderType *type,
                                          GLint &num_locations,
                                          GLint &num_locations,
-                                         GLint &num_ssbo_bindings);
+                                         GLint &num_ssbo_bindings,
+                                         GLint &num_image_bindings);
 
 
   void r_collect_uniforms(const Shader::Parameter &param, UniformBlock &block,
   void r_collect_uniforms(const Shader::Parameter &param, UniformBlock &block,
                           const ShaderType *type, const char *name,
                           const ShaderType *type, const char *name,
                           const char *sym, int &location,
                           const char *sym, int &location,
                           const SparseArray &active_locations,
                           const SparseArray &active_locations,
-                          int &resource_index, int &ssbo_binding,
+                          int &resource_index, int &binding,
                           size_t offset = 0);
                           size_t offset = 0);
 
 
   void reflect_program(SparseArray &active_locations, LocationMap &locations, LocationMap &ssbo_bindings);
   void reflect_program(SparseArray &active_locations, LocationMap &locations, LocationMap &ssbo_bindings);
@@ -144,6 +145,9 @@ private:
     PT(ShaderInputBinding) _binding;
     PT(ShaderInputBinding) _binding;
     ShaderInputBinding::ResourceId _resource_id;
     ShaderInputBinding::ResourceId _resource_id;
     CLP(TextureContext) *_gtc = nullptr;
     CLP(TextureContext) *_gtc = nullptr;
+#ifdef OPENGLES
+    GLint _binding_index;
+#endif
     ShaderType::Access _access;
     ShaderType::Access _access;
     bool _written = false;
     bool _written = false;
   };
   };
@@ -171,7 +175,7 @@ private:
                      const LocationMap &locations, bool &remap_locations,
                      const LocationMap &locations, bool &remap_locations,
                      const LocationMap &ssbo_bindings);
                      const LocationMap &ssbo_bindings);
   bool compile_and_link(const LocationMap &locations, bool &remap_locations,
   bool compile_and_link(const LocationMap &locations, bool &remap_locations,
-                        const LocationMap &ssbo_bindings);
+                        const LocationMap &bindings);
   void release_resources();
   void release_resources();
 
 
 public:
 public: