diff --git a/glslang/MachineIndependent/iomapper.cpp b/glslang/MachineIndependent/iomapper.cpp index 297c1237129f38fff651f1306db3600f372b7099..9ab9deaa352a6b0281cca03bd80081b158e3ab42 100644 --- a/glslang/MachineIndependent/iomapper.cpp +++ b/glslang/MachineIndependent/iomapper.cpp @@ -383,29 +383,34 @@ struct TDefaultIoResolverBase : public glslang::TIoMapResolver return !(at != slots[set].end() && *at == slot); } - int reserveSlot(int set, int slot) + int reserveSlot(int set, int slot, int size = 1) { TSlotSet::iterator at = findSlot(set, slot); // tolerate aliasing, by not double-recording aliases // (policy about appropriateness of the alias is higher up) - if (at == slots[set].end() || *at != slot) - slots[set].insert(at, slot); + for (int i = 0; i < size; i++) { + if (at == slots[set].end() || *at != slot + i) + at = slots[set].insert(at, slot + i); + ++at; + } return slot; } - int getFreeSlot(int set, int base) + int getFreeSlot(int set, int base, int size = 1) { TSlotSet::iterator at = findSlot(set, base); if (at == slots[set].end()) - return reserveSlot(set, base); + return reserveSlot(set, base, size); - // look in locksteps, if they not match, then there is a free slot - for (; at != slots[set].end(); ++at, ++base) - if (*at != base) + // look for a big enough gap + for (; at != slots[set].end(); ++at) { + if (*at - base >= size) break; - return reserveSlot(set, base); + base = *at + 1; + } + return reserveSlot(set, base, size); } virtual bool validateBinding(EShLanguage /*stage*/, const char* /*name*/, const glslang::TType& type, bool /*is_live*/) override = 0; @@ -561,40 +566,42 @@ struct TDefaultIoResolver : public TDefaultIoResolverBase int resolveBinding(EShLanguage /*stage*/, const char* /*name*/, const glslang::TType& type, bool is_live) override { const int set = getLayoutSet(type); + // On OpenGL arrays of opaque types take a seperate binding for each element + int numBindings = intermediate.getSpv().openGl != 0 && type.isSizedArray() ? type.getCumulativeArraySize() : 1; if (type.getQualifier().hasBinding()) { if (isImageType(type)) - return reserveSlot(set, getBaseBinding(EResImage, set) + type.getQualifier().layoutBinding); + return reserveSlot(set, getBaseBinding(EResImage, set) + type.getQualifier().layoutBinding, numBindings); if (isTextureType(type)) - return reserveSlot(set, getBaseBinding(EResTexture, set) + type.getQualifier().layoutBinding); + return reserveSlot(set, getBaseBinding(EResTexture, set) + type.getQualifier().layoutBinding, numBindings); if (isSsboType(type)) - return reserveSlot(set, getBaseBinding(EResSsbo, set) + type.getQualifier().layoutBinding); + return reserveSlot(set, getBaseBinding(EResSsbo, set) + type.getQualifier().layoutBinding, numBindings); if (isSamplerType(type)) - return reserveSlot(set, getBaseBinding(EResSampler, set) + type.getQualifier().layoutBinding); + return reserveSlot(set, getBaseBinding(EResSampler, set) + type.getQualifier().layoutBinding, numBindings); if (isUboType(type)) - return reserveSlot(set, getBaseBinding(EResUbo, set) + type.getQualifier().layoutBinding); + return reserveSlot(set, getBaseBinding(EResUbo, set) + type.getQualifier().layoutBinding, numBindings); } else if (is_live && doAutoBindingMapping()) { // find free slot, the caller did make sure it passes all vars with binding // first and now all are passed that do not have a binding and needs one if (isImageType(type)) - return getFreeSlot(set, getBaseBinding(EResImage, set)); + return getFreeSlot(set, getBaseBinding(EResImage, set), numBindings); if (isTextureType(type)) - return getFreeSlot(set, getBaseBinding(EResTexture, set)); + return getFreeSlot(set, getBaseBinding(EResTexture, set), numBindings); if (isSsboType(type)) - return getFreeSlot(set, getBaseBinding(EResSsbo, set)); + return getFreeSlot(set, getBaseBinding(EResSsbo, set), numBindings); if (isSamplerType(type)) - return getFreeSlot(set, getBaseBinding(EResSampler, set)); + return getFreeSlot(set, getBaseBinding(EResSampler, set), numBindings); if (isUboType(type)) - return getFreeSlot(set, getBaseBinding(EResUbo, set)); + return getFreeSlot(set, getBaseBinding(EResUbo, set), numBindings); } return -1;