return numComponents;
}
+static int getFragmentOutputMaxLocation (const ProgramInterfaceDefinition::Shader* shader)
+{
+ DE_ASSERT(shader->getType() == glu::SHADERTYPE_FRAGMENT);
+
+ int maxOutputLocation = -1;
+
+ for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx)
+ {
+ if (shader->getDefaultBlock().variables[ndx].storage == glu::STORAGE_OUT)
+ {
+ // missing location qualifier means location == 0
+ const int outputLocation = (shader->getDefaultBlock().variables[ndx].layout.location == -1)
+ ? (0)
+ : (shader->getDefaultBlock().variables[ndx].layout.location);
+
+ // only basic types or arrays of basic types possible
+ DE_ASSERT(!shader->getDefaultBlock().variables[ndx].varType.isStructType());
+
+ const int locationSlotsTaken = (shader->getDefaultBlock().variables[ndx].varType.isArrayType())
+ ? (shader->getDefaultBlock().variables[ndx].varType.getArraySize())
+ : (1);
+
+ maxOutputLocation = de::max(maxOutputLocation, outputLocation + locationSlotsTaken - 1);
+ }
+ }
+
+ return maxOutputLocation;
+}
+
} // anonymous
std::vector<std::string> getProgramInterfaceBlockMemberResourceList (const glu::InterfaceBlock& interfaceBlock)
{
ProgramInterfaceDefinition::ProgramResourceUsage retVal;
- retVal.uniformBufferMaxBinding = 0;
+ retVal.uniformBufferMaxBinding = -1; // max binding is inclusive upper bound. Allow 0 bindings by using negative value
retVal.uniformBufferMaxSize = 0;
retVal.numUniformBlocks = 0;
retVal.numCombinedVertexUniformComponents = 0;
retVal.numCombinedFragmentUniformComponents = 0;
- retVal.shaderStorageBufferMaxBinding = 0;
+ retVal.shaderStorageBufferMaxBinding = -1; // see above
retVal.shaderStorageBufferMaxSize = 0;
retVal.numShaderStorageBlocks = 0;
retVal.numVaryingComponents = 0;
retVal.numVaryingVectors = 0;
retVal.numCombinedSamplers = 0;
- retVal.atomicCounterBufferMaxBinding = 0;
+ retVal.atomicCounterBufferMaxBinding = -1; // see above
retVal.atomicCounterBufferMaxSize = 0;
retVal.numAtomicCounterBuffers = 0;
retVal.numAtomicCounters = 0;
- retVal.maxImageBinding = 0;
+ retVal.maxImageBinding = -1; // see above
retVal.numCombinedImages = 0;
retVal.numCombinedOutputResources = 0;
retVal.numXFBInterleavedComponents = 0;
retVal.numXFBSeparateAttribs = 0;
retVal.numXFBSeparateComponents = 0;
+ retVal.fragmentOutputMaxBinding = -1; // see above
for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
{
retVal.numCombinedOutputResources += getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeImage);
retVal.numCombinedOutputResources += getNumShaderBlocks(shader, glu::STORAGE_BUFFER);
+
if (shader->getType() == glu::SHADERTYPE_FRAGMENT)
+ {
retVal.numCombinedOutputResources += getNumVectors(shader, glu::STORAGE_OUT);
+ retVal.fragmentOutputMaxBinding = de::max(retVal.fragmentOutputMaxBinding, getFragmentOutputMaxLocation(shader));
+ }
}
if (program->getTransformFeedbackMode() == GL_INTERLEAVED_ATTRIBS)
{ GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE, usage.atomicCounterBufferMaxSize },
{ GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS, usage.numAtomicCounterBuffers },
{ GL_MAX_COMBINED_ATOMIC_COUNTERS, usage.numAtomicCounters },
- { GL_MAX_IMAGE_UNITS, usage.maxImageBinding },
+ { GL_MAX_IMAGE_UNITS, usage.maxImageBinding+1 },
{ GL_MAX_COMBINED_IMAGE_UNIFORMS, usage.numCombinedImages },
{ GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, usage.shaderStorageBufferMaxBinding+1 },
{ GL_MAX_SHADER_STORAGE_BLOCK_SIZE, usage.shaderStorageBufferMaxSize },
{ GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS, usage.numXFBInterleavedComponents },
{ GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, usage.numXFBSeparateAttribs },
{ GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS, usage.numXFBSeparateComponents },
+ { GL_MAX_DRAW_BUFFERS, usage.fragmentOutputMaxBinding+1 },
};
bool allOk = true;