diff --git a/Test/430.comp b/Test/430.comp index 13a812d6..f022f8f8 100644 --- a/Test/430.comp +++ b/Test/430.comp @@ -12,6 +12,18 @@ const int total = gl_MaxComputeWorkGroupCount.y + gl_MaxComputeAtomicCounters + gl_MaxComputeAtomicCounterBuffers; +buffer ShaderStorageBlock +{ + int value; + float values[]; +}; + +buffer InvalidShaderStorageBlock +{ + float values[]; // ERROR + int value; +} invalid; + void main() { barrier(); @@ -21,6 +33,7 @@ void main() memoryBarrierShared(); memoryBarrierImage(); groupMemoryBarrier(); + value = int(values[gl_LocalInvocationIndex]); } layout(location = 2) in vec3 v3; // ERROR @@ -36,3 +49,15 @@ layout(local_size_x = 2, local_size_y = 3, local_size_z = 4) out; // ERROR int arrX[gl_WorkGroupSize.x]; int arrY[gl_WorkGroupSize.y]; int arrZ[gl_WorkGroupSize.z]; + +readonly buffer roblock +{ + int value; + float values[]; +} ro; + +void foo() +{ + ro.values[2] = 4.7; // ERROR, readonly + ro.values.length(); +} diff --git a/Test/baseResults/300layout.vert.out b/Test/baseResults/300layout.vert.out index 52de07b8..b5b1e262 100644 --- a/Test/baseResults/300layout.vert.out +++ b/Test/baseResults/300layout.vert.out @@ -5,7 +5,7 @@ ERROR: 0:8: 'vertex input arrays' : not supported with this profile: es ERROR: 0:8: 'location' : overlapping use of location 10 ERROR: 0:12: 'layout' : cannot specify matrix layout on a variable declaration ERROR: 0:12: 'layout' : cannot specify packing on a variable declaration -ERROR: 0:19: 'badf' : member of uniform block cannot have an auxiliary or interpolation qualifier +ERROR: 0:19: 'badf' : member of uniform or buffer block cannot have an auxiliary or interpolation qualifier ERROR: 0:20: 'badg' : member storage qualifier cannot contradict block storage qualifier ERROR: 0:21: 'bad1' : member of block cannot have a packing layout qualifier ERROR: 0:22: 'bad2' : member of block cannot have a packing layout qualifier diff --git a/Test/baseResults/420.vert.out b/Test/baseResults/420.vert.out index 94f849b8..2d8bf8b1 100644 --- a/Test/baseResults/420.vert.out +++ b/Test/baseResults/420.vert.out @@ -38,8 +38,8 @@ ERROR: 0:107: '' : image variables not declared 'writeonly' must have a format l ERROR: 0:114: 'imageAtomicMin' : only supported on image with format r32i or r32ui ERROR: 0:115: 'imageAtomicMax' : no matching overloaded function found ERROR: 0:119: 'writeonly' : argument cannot drop memory qualifier when passed to formal parameter -ERROR: 0:122: '' : memory qualifiers can only be used on image types -ERROR: 0:123: '' : memory qualifiers can only be used on image types +ERROR: 0:122: '' : memory qualifiers cannot be used on this type +ERROR: 0:123: '' : memory qualifiers cannot be used on this type ERROR: 0:135: 'restrict' : argument cannot drop memory qualifier when passed to formal parameter ERROR: 0:139: 'rg8i' : does not apply to unsigned integer images ERROR: 0:140: 'rgba32i' : does not apply to floating point images diff --git a/Test/baseResults/430.comp.out b/Test/baseResults/430.comp.out index 4e3f8fd6..b1fed46f 100644 --- a/Test/baseResults/430.comp.out +++ b/Test/baseResults/430.comp.out @@ -2,32 +2,64 @@ Warning, version 430 is not yet complete; most version-specific features are present, but some are missing. ERROR: 0:4: 'local_size' : cannot change previously set size ERROR: 0:5: 'local_size' : too large; see gl_MaxComputeWorkGroupSize -ERROR: 0:26: 'in' : global storage input qualifier cannot be used in a compute shader -ERROR: 0:26: 'location qualifier on input' : not supported in this stage: compute -ERROR: 0:27: 'in' : global storage input qualifier cannot be used in a compute shader -ERROR: 0:28: 'out' : global storage output qualifier cannot be used in a compute shader -ERROR: 0:31: 'shared' : cannot apply layout qualifiers to a shared variable -ERROR: 0:31: 'location' : can only appy to uniform, buffer, in, or out storage qualifiers -ERROR: 0:32: 'shared' : cannot initialize this type of qualifier -ERROR: 0:34: 'local_size' : can only apply to 'in' -ERROR: 0:34: 'local_size' : can only apply to 'in' -ERROR: 0:34: 'local_size' : can only apply to 'in' -ERROR: 12 compilation errors. No code generated. +ERROR: 0:23: 'values' : only the last member of a buffer block can be run-time sized +ERROR: 0:39: 'in' : global storage input qualifier cannot be used in a compute shader +ERROR: 0:39: 'location qualifier on input' : not supported in this stage: compute +ERROR: 0:40: 'in' : global storage input qualifier cannot be used in a compute shader +ERROR: 0:41: 'out' : global storage output qualifier cannot be used in a compute shader +ERROR: 0:44: 'shared' : cannot apply layout qualifiers to a shared variable +ERROR: 0:44: 'location' : can only appy to uniform, buffer, in, or out storage qualifiers +ERROR: 0:45: 'shared' : cannot initialize this type of qualifier +ERROR: 0:47: 'local_size' : can only apply to 'in' +ERROR: 0:47: 'local_size' : can only apply to 'in' +ERROR: 0:47: 'local_size' : can only apply to 'in' +ERROR: 0:61: 'assign' : l-value required "ro" (can't modify a readonly buffer) +ERROR: 14 compilation errors. No code generated. Shader version: 430 local_size = (2, 1, 4096) ERROR: node is still EOpNull! -0:15 Function Definition: main( (void) -0:15 Function Parameters: -0:17 Sequence -0:17 Barrier (void) -0:18 MemoryBarrier (void) -0:19 MemoryBarrierAtomicCounter (void) -0:20 MemoryBarrierBuffer (void) -0:21 MemoryBarrierShared (void) -0:22 MemoryBarrierImage (void) -0:23 GroupMemoryBarrier (void) +0:27 Function Definition: main( (void) +0:27 Function Parameters: +0:29 Sequence +0:29 Barrier (void) +0:30 MemoryBarrier (void) +0:31 MemoryBarrierAtomicCounter (void) +0:32 MemoryBarrierBuffer (void) +0:33 MemoryBarrierShared (void) +0:34 MemoryBarrierImage (void) +0:35 GroupMemoryBarrier (void) +0:36 move second child to first child (int) +0:36 value: direct index for structure (layout(column_major shared ) buffer int) +0:36 'anon@0' (layout(column_major shared ) buffer block{layout(column_major shared ) buffer int value, layout(column_major shared ) buffer implicitly-sized array of float values}) +0:36 Constant: +0:36 0 (const uint) +0:36 Convert float to int (int) +0:36 indirect index (layout(column_major shared ) float) +0:36 values: direct index for structure (layout(column_major shared ) buffer implicitly-sized array of float) +0:36 'anon@0' (layout(column_major shared ) buffer block{layout(column_major shared ) buffer int value, layout(column_major shared ) buffer implicitly-sized array of float values}) +0:36 Constant: +0:36 1 (const uint) +0:36 'gl_LocalInvocationIndex' (in uint) +0:59 Function Definition: foo( (void) +0:59 Function Parameters: +0:61 Sequence +0:61 move second child to first child (float) +0:61 direct index (layout(column_major shared ) float) +0:61 values: direct index for structure (layout(column_major shared ) buffer implicitly-sized array of float) +0:61 'ro' (layout(column_major shared ) readonly buffer block{layout(column_major shared ) buffer int value, layout(column_major shared ) buffer implicitly-sized array of float values}) +0:61 Constant: +0:61 1 (const int) +0:61 Constant: +0:61 2 (const int) +0:61 Constant: +0:61 4.700000 +0:62 array length (int) +0:62 values: direct index for structure (layout(column_major shared ) buffer implicitly-sized array of float) +0:62 'ro' (layout(column_major shared ) readonly buffer block{layout(column_major shared ) buffer int value, layout(column_major shared ) buffer implicitly-sized array of float values}) +0:62 Constant: +0:62 1 (const int) 0:? Linker Objects 0:? 'gl_WorkGroupSize' (const 3-component vector of uint) 0:? 2 (const uint) @@ -35,6 +67,8 @@ ERROR: node is still EOpNull! 0:? 4096 (const uint) 0:? 'total' (const int) 0:? 66592 (const int) +0:? 'anon@0' (layout(column_major shared ) buffer block{layout(column_major shared ) buffer int value, layout(column_major shared ) buffer implicitly-sized array of float values}) +0:? 'invalid' (layout(column_major shared ) buffer block{layout(column_major shared ) buffer implicitly-sized array of float values, layout(column_major shared ) buffer int value}) 0:? 'v3' (layout(location=2 ) in 3-component vector of float) 0:? 'f' (in float) 0:? 'fo' (out float) @@ -44,6 +78,7 @@ ERROR: node is still EOpNull! 0:? 'arrX' (2-element array of int) 0:? 'arrY' (1-element array of int) 0:? 'arrZ' (4096-element array of int) +0:? 'ro' (layout(column_major shared ) readonly buffer block{layout(column_major shared ) buffer int value, layout(column_major shared ) buffer implicitly-sized array of float values}) Linked compute stage: @@ -52,16 +87,46 @@ Linked compute stage: Shader version: 430 local_size = (2, 1, 4096) ERROR: node is still EOpNull! -0:15 Function Definition: main( (void) -0:15 Function Parameters: -0:17 Sequence -0:17 Barrier (void) -0:18 MemoryBarrier (void) -0:19 MemoryBarrierAtomicCounter (void) -0:20 MemoryBarrierBuffer (void) -0:21 MemoryBarrierShared (void) -0:22 MemoryBarrierImage (void) -0:23 GroupMemoryBarrier (void) +0:27 Function Definition: main( (void) +0:27 Function Parameters: +0:29 Sequence +0:29 Barrier (void) +0:30 MemoryBarrier (void) +0:31 MemoryBarrierAtomicCounter (void) +0:32 MemoryBarrierBuffer (void) +0:33 MemoryBarrierShared (void) +0:34 MemoryBarrierImage (void) +0:35 GroupMemoryBarrier (void) +0:36 move second child to first child (int) +0:36 value: direct index for structure (layout(column_major shared ) buffer int) +0:36 'anon@0' (layout(column_major shared ) buffer block{layout(column_major shared ) buffer int value, layout(column_major shared ) buffer implicitly-sized array of float values}) +0:36 Constant: +0:36 0 (const uint) +0:36 Convert float to int (int) +0:36 indirect index (layout(column_major shared ) float) +0:36 values: direct index for structure (layout(column_major shared ) buffer implicitly-sized array of float) +0:36 'anon@0' (layout(column_major shared ) buffer block{layout(column_major shared ) buffer int value, layout(column_major shared ) buffer implicitly-sized array of float values}) +0:36 Constant: +0:36 1 (const uint) +0:36 'gl_LocalInvocationIndex' (in uint) +0:59 Function Definition: foo( (void) +0:59 Function Parameters: +0:61 Sequence +0:61 move second child to first child (float) +0:61 direct index (layout(column_major shared ) float) +0:61 values: direct index for structure (layout(column_major shared ) buffer implicitly-sized array of float) +0:61 'ro' (layout(column_major shared ) readonly buffer block{layout(column_major shared ) buffer int value, layout(column_major shared ) buffer implicitly-sized array of float values}) +0:61 Constant: +0:61 1 (const int) +0:61 Constant: +0:61 2 (const int) +0:61 Constant: +0:61 4.700000 +0:62 array length (int) +0:62 values: direct index for structure (layout(column_major shared ) buffer implicitly-sized array of float) +0:62 'ro' (layout(column_major shared ) readonly buffer block{layout(column_major shared ) buffer int value, layout(column_major shared ) buffer implicitly-sized array of float values}) +0:62 Constant: +0:62 1 (const int) 0:? Linker Objects 0:? 'gl_WorkGroupSize' (const 3-component vector of uint) 0:? 2 (const uint) @@ -69,6 +134,8 @@ ERROR: node is still EOpNull! 0:? 4096 (const uint) 0:? 'total' (const int) 0:? 66592 (const int) +0:? 'anon@0' (layout(column_major shared ) buffer block{layout(column_major shared ) buffer int value, layout(column_major shared ) buffer implicitly-sized array of float values}) +0:? 'invalid' (layout(column_major shared ) buffer block{layout(column_major shared ) buffer implicitly-sized array of float values, layout(column_major shared ) buffer int value}) 0:? 'v3' (layout(location=2 ) in 3-component vector of float) 0:? 'f' (in float) 0:? 'fo' (out float) @@ -78,4 +145,5 @@ ERROR: node is still EOpNull! 0:? 'arrX' (2-element array of int) 0:? 'arrY' (1-element array of int) 0:? 'arrZ' (4096-element array of int) +0:? 'ro' (layout(column_major shared ) readonly buffer block{layout(column_major shared ) buffer int value, layout(column_major shared ) buffer implicitly-sized array of float values}) diff --git a/Test/baseResults/specExamples.vert.out b/Test/baseResults/specExamples.vert.out index 9d02d020..b082a850 100644 --- a/Test/baseResults/specExamples.vert.out +++ b/Test/baseResults/specExamples.vert.out @@ -35,10 +35,6 @@ ERROR: 0:106: '' : vertex input cannot be further qualified ERROR: 0:106: 'redeclaration' : cannot change storage, memory, or auxiliary qualification of gl_FrontColor ERROR: 0:112: 'ColorIvn' : identifier not previously declared WARNING: 0:118: '' : unknown requalification -ERROR: 0:123: '' : memory qualifiers can only be used on image types -ERROR: 0:122: '' : memory qualifiers can only be used on image types -ERROR: 0:128: '' : memory qualifiers can only be used on image types -ERROR: 0:129: '' : memory qualifiers can only be used on image types ERROR: 0:132: 'shared' : not supported in this stage: vertex ERROR: 0:134: '' : function does not return a value: funcA ERROR: 0:136: '' : function does not return a value: funcB @@ -47,7 +43,7 @@ ERROR: 0:170: 'coherent' : argument cannot drop memory qualifier when passed to ERROR: 0:192: 'constructor' : constructing from a non-dereferenced array ERROR: 0:193: 'constructor' : constructing from a non-dereferenced array ERROR: 0:194: 'constructor' : constructing from a non-dereferenced array -ERROR: 45 compilation errors. No code generated. +ERROR: 41 compilation errors. No code generated. Shader version: 430 @@ -314,8 +310,8 @@ ERROR: node is still EOpNull! 0:? 'c' (in 4-component vector of float) 0:? 'd' (in 4-component vector of float) 0:? 'v' (smooth out 4-component vector of float) -0:? 'anon@6' (layout(row_major shared ) coherent uniform block{layout(row_major shared ) readonly uniform 4-component vector of float member1, layout(row_major shared ) uniform 4-component vector of float member2}) -0:? 'anon@7' (layout(row_major shared ) uniform block{layout(row_major shared ) coherent readonly uniform 4-component vector of float member1A, layout(row_major shared ) coherent uniform 4-component vector of float member2A}) +0:? 'anon@6' (layout(column_major shared ) coherent buffer block{layout(column_major shared ) readonly buffer 4-component vector of float member1, layout(column_major shared ) buffer 4-component vector of float member2}) +0:? 'anon@7' (layout(column_major shared ) buffer block{layout(column_major shared ) coherent readonly buffer 4-component vector of float member1A, layout(column_major shared ) coherent buffer 4-component vector of float member2A}) 0:? 'shv' (shared 4-component vector of float) 0:? 'img1' (layout(rgba32f ) uniform image2D) 0:? 'img2' (layout(rgba32f ) coherent uniform image2D) @@ -590,8 +586,8 @@ ERROR: node is still EOpNull! 0:? 'c' (in 4-component vector of float) 0:? 'd' (in 4-component vector of float) 0:? 'v' (smooth out 4-component vector of float) -0:? 'anon@6' (layout(row_major shared ) coherent uniform block{layout(row_major shared ) readonly uniform 4-component vector of float member1, layout(row_major shared ) uniform 4-component vector of float member2}) -0:? 'anon@7' (layout(row_major shared ) uniform block{layout(row_major shared ) coherent readonly uniform 4-component vector of float member1A, layout(row_major shared ) coherent uniform 4-component vector of float member2A}) +0:? 'anon@6' (layout(column_major shared ) coherent buffer block{layout(column_major shared ) readonly buffer 4-component vector of float member1, layout(column_major shared ) buffer 4-component vector of float member2}) +0:? 'anon@7' (layout(column_major shared ) buffer block{layout(column_major shared ) coherent readonly buffer 4-component vector of float member1A, layout(column_major shared ) coherent buffer 4-component vector of float member2A}) 0:? 'shv' (shared 4-component vector of float) 0:? 'img1' (layout(rgba32f ) uniform image2D) 0:? 'img2' (layout(rgba32f ) coherent uniform image2D) diff --git a/Todo.txt b/Todo.txt index 1a6095cf..ade92f59 100644 --- a/Todo.txt +++ b/Todo.txt @@ -197,9 +197,10 @@ Shader Functionality to Implement/Finish + Clarify that textureGatherOffset() can take non-constants for the offsets. GLSL 4.3 - Add shader storage buffer objects, as per the ARB_shader_storage_buffer_object extension. This includes - - allowing the last member of a storage buffer block to be an array that does not know its size until render time + + allowing the last member of a storage buffer block to be an array that does not know its size until render time - read/write memory shared with the application and other shader invocations - - adding the std430 layout qualifier for shader storage blocks + + adding the std430 layout qualifier for shader storage blocks + - add atomic built-ins - Allow .length() on all arrays; returning a compile-time constant or not, depending on how the array is sized, as per the ARB_shader_storage_buffer_object extension. - Be clear that implicit array sizing is only within a stage, not cross stage. diff --git a/glslang/Include/BaseTypes.h b/glslang/Include/BaseTypes.h index 5b9b2f5d..fd449512 100644 --- a/glslang/Include/BaseTypes.h +++ b/glslang/Include/BaseTypes.h @@ -67,8 +67,8 @@ enum TStorageQualifier { EvqConst, // User-defined constant values, will be semantically constant and constant folded EvqVaryingIn, // pipeline input, read only EvqVaryingOut, // pipeline ouput, read/write - EvqUniform, // read only, shader with app - EvqBuffer, // read only, shader with app + EvqUniform, // read only, shared with app + EvqBuffer, // read/write, shared with app EvqShared, // compute shader's read/write 'shared' qualifier // parameters diff --git a/glslang/Include/Types.h b/glslang/Include/Types.h index 4d5c3544..82d247cf 100644 --- a/glslang/Include/Types.h +++ b/glslang/Include/Types.h @@ -406,7 +406,7 @@ public: } } - bool isUniform() const + bool isUniformOrBuffer() const { switch (storage) { case EvqUniform: @@ -802,10 +802,15 @@ public: vectorSize = 0; } - bool isScalar() + bool isScalar() const { return matrixCols == 0 && vectorSize == 1 && arraySizes == 0 && userDef == 0; } + + bool isImage() const + { + return basicType == EbtSampler && sampler.image; + } }; typedef std::map TStructureMap; @@ -1008,9 +1013,11 @@ public: virtual bool isVector() const { return vectorSize > 1; } virtual bool isMatrix() const { return matrixCols ? true : false; } virtual bool isArray() const { return arraySizes != 0; } - virtual bool isImplicitlySizedArray() const { return isArray() && ! getArraySize(); } - virtual bool isExplicitlySizedArray() const { return ! isImplicitlySizedArray(); } + virtual bool isImplicitlySizedArray() const { return isArray() && ! getArraySize() && qualifier.storage != EvqBuffer; } + virtual bool isExplicitlySizedArray() const { return isArray() && getArraySize(); } + virtual bool isRuntimeSizedArray() const { return isArray() && ! getArraySize() && qualifier.storage == EvqBuffer; } virtual bool isStruct() const { return structure != 0; } + virtual bool isImage() const { return basicType == EbtSampler && getSampler().image; } // Recursively checks if the type contains the given basic type virtual bool containsBasicType(TBasicType checkType) const diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp index 4da9aa7e..a3484a91 100644 --- a/glslang/MachineIndependent/ParseHelper.cpp +++ b/glslang/MachineIndependent/ParseHelper.cpp @@ -526,10 +526,10 @@ void TParseContext::checkIndex(TSourceLoc loc, const TType& type, int& index) void TParseContext::handleIndexLimits(TSourceLoc loc, TIntermTyped* base, TIntermTyped* index) { if ((! limits.generalSamplerIndexing && base->getBasicType() == EbtSampler) || - (! limits.generalUniformIndexing && base->getQualifier().isUniform() && language != EShLangVertex) || + (! limits.generalUniformIndexing && base->getQualifier().isUniformOrBuffer() && language != EShLangVertex) || (! limits.generalAttributeMatrixVectorIndexing && base->getQualifier().isPipeInput() && language == EShLangVertex && (base->getType().isMatrix() || base->getType().isVector())) || (! limits.generalConstantMatrixVectorIndexing && base->getAsConstantUnion()) || - (! limits.generalVariableIndexing && ! base->getType().getQualifier().isUniform() && + (! limits.generalVariableIndexing && ! base->getType().getQualifier().isUniformOrBuffer() && ! base->getType().getQualifier().isPipeInput() && ! base->getType().getQualifier().isPipeOutput() && base->getType().getQualifier().storage != EvqConst) || @@ -1062,7 +1062,10 @@ TIntermTyped* TParseContext::handleLengthMethod(TSourceLoc loc, TFunction* funct else { const TType& type = intermNode->getAsTyped()->getType(); if (type.isArray()) { - if (type.isImplicitlySizedArray()) { + if (type.isRuntimeSizedArray()) { + // Create a unary op and let the back end handle it + return intermediate.addBuiltInFunctionCall(loc, EOpArrayLength, true, intermNode, TType(EbtInt)); + } else if (type.isImplicitlySizedArray()) { if (intermNode->getAsSymbolNode() && isIoResizeArray(type)) { // We could be between a layout declaration that gives a built-in io array implicit size and // a user redeclaration of that array, meaning we have to substitute its implicit size here @@ -1565,12 +1568,16 @@ bool TParseContext::lValueErrorCheck(TSourceLoc loc, const char* op, TIntermType case EvqConst: message = "can't modify a const"; break; case EvqConstReadOnly: message = "can't modify a const"; break; case EvqVaryingIn: message = "can't modify shader input"; break; - case EvqUniform: message = "can't modify a uniform"; break; case EvqInstanceId: message = "can't modify gl_InstanceID"; break; case EvqVertexId: message = "can't modify gl_VertexID"; break; case EvqFace: message = "can't modify gl_FrontFace"; break; case EvqFragCoord: message = "can't modify gl_FragCoord"; break; case EvqPointCoord: message = "can't modify gl_PointCoord"; break; + case EvqUniform: message = "can't modify a uniform"; break; + case EvqBuffer: + if (node->getQualifier().readonly) + message = "can't modify a readonly buffer"; + break; default: // @@ -1911,6 +1918,9 @@ void TParseContext::globalQualifierCheck(TSourceLoc loc, const TQualifier& quali if (! symbolTable.atGlobalLevel()) return; + if (qualifier.isMemory() && ! publicType.isImage() && publicType.qualifier.storage != EvqBuffer) + error(loc, "memory qualifiers cannot be used on this type", "", ""); + if (qualifier.storage != EvqVaryingIn && qualifier.storage != EvqVaryingOut) return; @@ -3281,8 +3291,8 @@ void TParseContext::layoutObjectCheck(TSourceLoc loc, const TSymbol& symbol) // Check packing and matrix if (qualifier.hasUniformLayout()) { switch (qualifier.storage) { - case EvqBuffer: case EvqUniform: + case EvqBuffer: if (type.getBasicType() != EbtBlock) { if (qualifier.hasMatrix()) error(loc, "cannot specify matrix layout on a variable declaration", "layout", ""); @@ -3396,7 +3406,7 @@ void TParseContext::layoutTypeCheck(TSourceLoc loc, const TType& type) // Image format if (qualifier.hasFormat()) { - if (type.getBasicType() != EbtSampler || ! type.getSampler().image) + if (! type.isImage()) error(loc, "only apply to images", TQualifier::getLayoutFormatString(qualifier.layoutFormat), ""); else { if (type.getSampler().type == EbtFloat && qualifier.layoutFormat > ElfFloatGuard) @@ -3406,10 +3416,8 @@ void TParseContext::layoutTypeCheck(TSourceLoc loc, const TType& type) if (type.getSampler().type == EbtUint && qualifier.layoutFormat < ElfIntGuard) error(loc, "does not apply to unsigned integer images", TQualifier::getLayoutFormatString(qualifier.layoutFormat), ""); } - } else if (type.getBasicType() == EbtSampler && type.getSampler().image && !qualifier.writeonly) + } else if (type.isImage() && ! qualifier.writeonly) error(loc, "image variables not declared 'writeonly' must have a format layout qualifier", "", ""); - if (qualifier.isMemory() && (type.getBasicType() != EbtSampler || ! type.getSampler().image)) - error(loc, "memory qualifiers can only be used on image types", "", ""); } // Do layout error checking that can be done within a qualifier proper, not needing to know @@ -3470,7 +3478,7 @@ void TParseContext::layoutQualifierCheck(TSourceLoc loc, const TQualifier& quali } if (qualifier.hasBinding()) { - if (qualifier.storage != EvqUniform && qualifier.storage != EvqBuffer) + if (! qualifier.isUniformOrBuffer()) error(loc, "requires uniform or buffer storage qualifier", "binding", ""); } if (qualifier.hasStream()) { @@ -3482,7 +3490,7 @@ void TParseContext::layoutQualifierCheck(TSourceLoc loc, const TQualifier& quali error(loc, "can only be used on an output", "xfb layout qualifier", ""); } if (qualifier.hasUniformLayout()) { - if (! (qualifier.storage == EvqUniform || qualifier.storage == EvqBuffer)) { + if (! qualifier.isUniformOrBuffer()) { if (qualifier.hasMatrix() || qualifier.hasPacking()) error(loc, "matrix or packing qualifiers can only be used on a uniform or buffer", "layout", ""); if (qualifier.hasOffset() || qualifier.hasAlign()) @@ -4122,14 +4130,14 @@ void TParseContext::declareBlock(TSourceLoc loc, TTypeList& typeList, const TStr arraySizeRequiredCheck(loc, arraySizes->getSize()); switch (currentBlockQualifier.storage) { - case EvqBuffer: - requireProfile(loc, ECoreProfile | ECompatibilityProfile, "buffer block"); - profileRequires(loc, ECoreProfile | ECompatibilityProfile, 430, 0, "buffer block"); - break; case EvqUniform: profileRequires(loc, EEsProfile, 300, 0, "uniform block"); profileRequires(loc, ENoProfile, 140, 0, "uniform block"); break; + case EvqBuffer: + requireProfile(loc, ECoreProfile | ECompatibilityProfile, "buffer block"); + profileRequires(loc, ECoreProfile | ECompatibilityProfile, 430, 0, "buffer block"); + break; case EvqVaryingIn: requireProfile(loc, ~EEsProfile, "input block"); profileRequires(loc, ~EEsProfile, 150, GL_ARB_separate_shader_objects, "input block"); @@ -4147,16 +4155,19 @@ void TParseContext::declareBlock(TSourceLoc loc, TTypeList& typeList, const TStr // fix and check for member storage qualifiers and types that don't belong within a block for (unsigned int member = 0; member < typeList.size(); ++member) { - TQualifier& memberQualifier = typeList[member].type->getQualifier(); + TType& memberType = *typeList[member].type; + TQualifier& memberQualifier = memberType.getQualifier(); TSourceLoc memberLoc = typeList[member].loc; pipeInOutFix(memberLoc, memberQualifier); if (memberQualifier.storage != EvqTemporary && memberQualifier.storage != EvqGlobal && memberQualifier.storage != currentBlockQualifier.storage) - error(memberLoc, "member storage qualifier cannot contradict block storage qualifier", typeList[member].type->getFieldName().c_str(), ""); + error(memberLoc, "member storage qualifier cannot contradict block storage qualifier", memberType.getFieldName().c_str(), ""); memberQualifier.storage = currentBlockQualifier.storage; - if (currentBlockQualifier.storage == EvqUniform && (memberQualifier.isInterpolation() || memberQualifier.isAuxiliary())) - error(memberLoc, "member of uniform block cannot have an auxiliary or interpolation qualifier", typeList[member].type->getFieldName().c_str(), ""); + if ((currentBlockQualifier.storage == EvqUniform || currentBlockQualifier.storage == EvqBuffer) && (memberQualifier.isInterpolation() || memberQualifier.isAuxiliary())) + error(memberLoc, "member of uniform or buffer block cannot have an auxiliary or interpolation qualifier", memberType.getFieldName().c_str(), ""); + if (memberType.isRuntimeSizedArray() && member < typeList.size() - 1) + error(memberLoc, "only the last member of a buffer block can be run-time sized", memberType.getFieldName().c_str(), ""); - TBasicType basicType = typeList[member].type->getBasicType(); + TBasicType basicType = memberType.getBasicType(); if (basicType == EbtSampler) error(memberLoc, "member of block cannot be a sampler type", typeList[member].type->getFieldName().c_str(), ""); } @@ -4179,8 +4190,8 @@ void TParseContext::declareBlock(TSourceLoc loc, TTypeList& typeList, const TStr TQualifier defaultQualification; switch (currentBlockQualifier.storage) { - case EvqBuffer: defaultQualification = globalBufferDefaults; break; case EvqUniform: defaultQualification = globalUniformDefaults; break; + case EvqBuffer: defaultQualification = globalBufferDefaults; break; case EvqVaryingIn: defaultQualification = globalInputDefaults; break; case EvqVaryingOut: defaultQualification = globalOutputDefaults; break; default: defaultQualification.clear(); break; @@ -4401,7 +4412,7 @@ void TParseContext::fixBlockXfbOffsets(TSourceLoc loc, TQualifier& qualifier, TT // void TParseContext::fixBlockUniformOffsets(TSourceLoc loc, TQualifier& qualifier, TTypeList& typeList) { - if (qualifier.storage != EvqUniform && qualifier.storage != EvqBuffer) + if (! qualifier.isUniformOrBuffer()) return; if (qualifier.layoutPacking != ElpStd140 && qualifier.layoutPacking != ElpStd430) return; diff --git a/glslang/MachineIndependent/glslang.y b/glslang/MachineIndependent/glslang.y index bc9ac87b..1e206933 100644 --- a/glslang/MachineIndependent/glslang.y +++ b/glslang/MachineIndependent/glslang.y @@ -1213,7 +1213,7 @@ storage_qualifier | BUFFER { parseContext.globalCheck($1.loc, "buffer"); $$.init($1.loc); - $$.qualifier.storage = EvqUniform; // TODO: 4.0 functionality: implement BUFFER + $$.qualifier.storage = EvqBuffer; } | SHARED { parseContext.requireProfile($1.loc, ~EEsProfile, "shared"); diff --git a/glslang/MachineIndependent/intermOut.cpp b/glslang/MachineIndependent/intermOut.cpp index 955f31a6..49140703 100644 --- a/glslang/MachineIndependent/intermOut.cpp +++ b/glslang/MachineIndependent/intermOut.cpp @@ -257,6 +257,8 @@ bool TOutputTraverser::visitUnary(TVisit /* visit */, TIntermUnary* node) case EOpAny: out.debug << "any"; break; case EOpAll: out.debug << "all"; break; + case EOpArrayLength: out.debug << "array length"; break; + case EOpEmitStreamVertex: out.debug << "EmitStreamVertex"; break; case EOpEndStreamPrimitive: out.debug << "EndStreamPrimitive"; break; diff --git a/glslang/MachineIndependent/linkValidate.cpp b/glslang/MachineIndependent/linkValidate.cpp index 1c4d5b86..3628f99c 100644 --- a/glslang/MachineIndependent/linkValidate.cpp +++ b/glslang/MachineIndependent/linkValidate.cpp @@ -604,13 +604,15 @@ int TIntermediate::addUsedLocation(const TQualifier& qualifier, const TType& typ set = 0; else if (qualifier.isPipeOutput()) set = 1; - else if (qualifier.isUniform()) + else if (qualifier.storage == EvqUniform) set = 2; + else if (qualifier.storage == EvqBuffer) + set = 3; else return -1; int size; - if (qualifier.isUniform()) { + if (qualifier.isUniformOrBuffer()) { if (type.isArray()) size = type.getArraySize(); else diff --git a/glslang/MachineIndependent/localintermediate.h b/glslang/MachineIndependent/localintermediate.h index 463aa86b..54aa6dd7 100644 --- a/glslang/MachineIndependent/localintermediate.h +++ b/glslang/MachineIndependent/localintermediate.h @@ -310,7 +310,7 @@ protected: TGraph callGraph; std::set ioAccessed; // set of names of statically read/written I/O that might need extra checking - std::vector usedIo[3]; // sets of used locations, one for each of in, out, and uniform + std::vector usedIo[4]; // sets of used locations, one for each of in, out, uniform and buffers std::vector xfbBuffers; // all the data we need to track per xfb buffer private: diff --git a/glslang/MachineIndependent/reflection.cpp b/glslang/MachineIndependent/reflection.cpp index ac9f3b6c..6c1299bf 100644 --- a/glslang/MachineIndependent/reflection.cpp +++ b/glslang/MachineIndependent/reflection.cpp @@ -265,7 +265,7 @@ public: // We have an array or structure or block dereference, see if it's a uniform // based dereference (if not, skip it). TIntermSymbol* base = findBase(topNode); - if (! base || base->getQualifier().storage != EvqUniform) + if (! base || ! base->getQualifier().isUniformOrBuffer()) return; // See if we've already processed this (e.g., in the middle of something