title: GLSL - unable to access second index of a SSBO array for multiple lights
body: <p>In my application I add two lights. One at (0,0,2) and the second one at (2,0,0). Here's what I get (the x,y,z axes are represented respectively by the red, green &amp; blue lines):</p>
  
  <p><a href="https://i.stack.imgur.com/vhYTD.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/vhYTD.png" alt="cube with only one light working"></a></p>
  
  <p>Notice how only the first light is working and the second is not. I made my application core-profile compliant to inspect the buffers with various tools like RenderDoc and NSight and both show me that the second light's data is present in the buffer (picture taken while running Nsight):</p>
  
  <p><a href="https://i.stack.imgur.com/bQfSY.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/bQfSY.png" alt="nsight capture"></a></p>
  
  <p>The positions seem to be correctly transfered to the gpu memory buffer. Here's the implementation of my fragment shader that uses a SSBO to handle multiple lights in my application:</p>
  
  <pre><code>#version 430
  
  struct Light {
    vec3  position;
    vec3  color;
    float intensity;
    float attenuation;
    float radius;
  };
  
  layout (std140, binding = 0) uniform CameraInfo {
    mat4  ProjectionView; 
    vec3  eye;
  };
  
  layout (std430, binding = 1) readonly buffer LightsData {
      Light lights[];
  };
  
  uniform vec3  ambient_light_color;
  uniform float ambient_light_intensity;
  
  in  vec3 ex_FragPos;
  in  vec4 ex_Color;
  in  vec3 ex_Normal;
  out vec4 out_Color;
  
  void main(void)
  {
      // Basic ambient light
      vec3 ambient_light = ambient_light_color * ambient_light_intensity;
  
      int i;
      vec3 diffuse = vec3(0.0,0.0,0.0);
      vec3 specular = vec3(0.0,0.0,0.0);
      for (i = 0; i &lt; lights.length(); ++i) {
          Light wLight = lights[i];
          // Basic diffuse light
          vec3 norm = normalize(ex_Normal); // in this project the normals are all normalized anyway...
          vec3 lightDir = normalize(wLight.position - ex_FragPos);
          float diff = max(dot(norm, lightDir), 0.0);
          diffuse += diff * wLight.color;
  
          // Basic specular light
          vec3 viewDir = normalize(eye - ex_FragPos);
          vec3 reflectDir = reflect(-lightDir, norm);  
          float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);
          specular += wLight.intensity * spec * wLight.color;  
      }
  
      out_Color = ex_Color * vec4(specular + diffuse + ambient_light,1.0); 
  }
  </code></pre>
  
  <p>Note that I've read the section 7.6.2.2 of the <a href="https://www.khronos.org/registry/OpenGL/specs/gl/glspec45.core.pdf" rel="nofollow noreferrer">OpenGL 4.5 spec</a> and that, if I understood correctly, my alignment should follow the size of the biggest member of my struct, which is a vec3 and my struct size is 36 bytes so everything should be fine here. I also tried different std version (e.g. std140) and adding some padding, but nothing fixes the issue with the second light. In my C++ code, I have those definitions to add the lights in my application:</p>
  
  <p>light_module.h/.cc:</p>
  
  <pre><code>struct Light {
    glm::f32vec3  position;
    glm::f32vec3  color;
    float         intensity;
    float         attenuation;
    float         radius;
  };
  ...
  constexpr GLuint        LIGHTS_SSBO_BINDING_POINT = 1U;
  std::vector&lt;Light&gt;      _Lights;
  ...
  void AddLight(const Light &amp;light) {
    // Add to _Lights
    _Lights.push_back(light);
  UpdateSSBOBlockData(
    LIGHTS_SSBO_BINDING_POINT, _Lights.size()* sizeof(Light),
    static_cast&lt;void*&gt;(_Lights.data()), GL_DYNAMIC_DRAW);
  }
  </code></pre>
  
  <p>shader_module.h/.cc:</p>
  
  <pre><code>using SSBOCapacity = GLuint;
  using BindingPoint = GLuint;
  using ID = GLuint;
  std::map&lt;BindingPoint, std::pair&lt;ID, SSBOCapacity&gt; &gt;  SSBO_list;
  ...
  void UpdateSSBOBlockData(GLuint a_unBindingPoint,
    GLuint a_unSSBOSize, void* a_pData, GLenum a_eUsage) {
    auto SSBO = SSBO_list.find(a_unBindingPoint);
    if (SSBO != SSBO_list.end()) {
      GLuint unSSBOID = SSBO-&gt;second.first;
      glBindBuffer(GL_SHADER_STORAGE_BUFFER, unSSBOID);
      glBufferData(GL_SHADER_STORAGE_BUFFER, a_unSSBOSize, a_pData, a_eUsage);
      glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); //unbind
    }
    else 
      // error handling...
  }
  </code></pre>
  
  <p>Basically, I'm trying to update/reallocate the SSBO size with glBufferData each time a light is added in my app.</p>
  
  <p>Now, since I'm having issues processing the second light data, I changed my fragment shader code to only execute the second light in my SSBO array by forcing <code>i = 1</code> and looping until <code>i &lt; 2</code>, but I get the following errors:</p>
  
  <pre><code>(50) : error C1068: ... or possible array index out of bounds
  (50) : error C5025: lvalue in field access too complex
  (56) : error C1068: ... or possible array index out of bounds
  (56) : error C5025: lvalue in field access too complex
  </code></pre>
  
  <p>Lines 50 and 56 refer to <code>diffuse += diff * wLight.color;</code> and <code>specular += wLight.intensity * spec * wLight.color;</code> respectively. Is there really an out of bounds access even if I add my lights before the first draw call? Why is the shader compiling correctly when I'm using <code>lights.length()</code> instead of 2?</p>
  
  <p>Finally, I've added a simple <code>if (i == 1)</code> in my for-loop to see if lights.length() is equal to 2, but it doesn't go in it. <strong>Yet the initial size of my buffer is 0 and then I add a light that sets the buffer size to 36 bytes and we can see that the first light works fine. Why is the update/reallocate not working the second time?</strong></p>