message: Check top-level stride of buffers to know if we need to pad. Refs
diff: @@ -757,6 +757,13 @@ void ReconstructVarTree(const GLHookSet &gl, GLenum query, GLuint sepProg, GLuin
  else
  var.type.descriptor.elements = 0;
  + GLint topLevelStride = 0;
  + if(query == eGL_BUFFER_VARIABLE)
  + {
  + GLenum propName = eGL_TOP_LEVEL_ARRAY_STRIDE;
  + gl.glGetProgramResourceiv(sepProg, query, varIdx, 1, &propName, 1, NULL, &topLevelStride);
  + }
  +
  vector<DynShaderConstant> *parentmembers = defaultBlock;
  if(values[3] != -1 && values[3] < numParentBlocks)
  @@ -833,6 +840,7 @@ void ReconstructVarTree(const GLHookSet &gl, GLenum query, GLuint sepProg, GLuin
  parentVar.type.descriptor.rowMajorStorage = false;
  parentVar.type.descriptor.type = var.type.descriptor.type;
  parentVar.type.descriptor.elements = isarray ? RDCMAX(1U, uint32_t(arrayIdx + 1)) : 0;
  + parentVar.type.descriptor.arrayStride = topLevelStride;
  bool found = false;
  @@ -1534,6 +1542,54 @@ void MakeShaderReflection(const GLHookSet &gl, GLenum shadType, GLuint sepProg,
  for(size_t ssbo = 0; ssbo < ssbos.size(); ssbo++)
  {
  sort(members[ssbo]);
  +
  + // account for padding for std430 layout, if we have a root array of
  + // structs, we need to pad the struct up to have the correct alignment
  + if(members[ssbo].size() == 1 && !members[ssbo][0].type.members.empty() &&
  + members[ssbo][0].type.descriptor.arrayStride != 0)
  + {
  + // now that we're sorted, see what the tightly packed stride would be by looking at the last
  + // member
  + uint32_t desiredStride = members[ssbo][0].type.descriptor.arrayStride;
  +
  + DynShaderConstant *last = &members[ssbo][0].type.members.back();
  + while(!last->type.members.empty())
  + last = &last->type.members.back();
  +
  + // start from the offset
  + uint32_t stride = last->reg.vec * 16 + last->reg.comp * 4;
  +
  + // add its size
  + uint32_t size = last->type.descriptor.rows * last->type.descriptor.cols * 4;
  + if(last->type.descriptor.type == eVar_Double)
  + size *= 2;
  +
  + stride += size;
  +
  + if(stride < desiredStride)
  + {
  + uint32_t padding = desiredStride - stride;
  +
  + RDCASSERT((padding % 4) == 0 && padding <= 16, padding);
  +
  + padding /= 4;
  +
  + DynShaderConstant paddingVar;
  + paddingVar.name = "__padding";
  + paddingVar.reg.vec = last->reg.vec + (size / 16);
  + paddingVar.reg.comp = (last->reg.comp + size / 4) % 16;
  + paddingVar.type.descriptor.type = eVar_UInt;
  + paddingVar.type.descriptor.rows = 1;
  + paddingVar.type.descriptor.cols = padding;
  + paddingVar.type.descriptor.elements = 1;
  + paddingVar.type.descriptor.rowMajorStorage = false;
  + paddingVar.type.descriptor.arrayStride = 0;
  + paddingVar.type.descriptor.name = StringFormat::Fmt("uint%u", padding);
  +
  + members[ssbo][0].type.members.push_back(paddingVar);
  + }
  + }
  +
  copy(rwresources[ssbos[ssbo]].variableType.members, members[ssbo]);
  }
  