* We follow similar rules to uniform block exploding.
ReflectOptions |= EShReflectionSeparateBuffers;
} else if (lowerword == "reflect-all-block-variables") {
ReflectOptions |= EShReflectionAllBlockVariables;
+ } else if (lowerword == "reflect-unwrap-io-blocks") {
+ ReflectOptions |= EShReflectionUnwrapIOBlocks;
} else if (lowerword == "resource-set-bindings" || // synonyms
lowerword == "resource-set-binding" ||
lowerword == "rsb") {
" separately to uniforms\n"
" --reflect-all-block-variables reflect all variables in blocks, whether\n"
" inactive or active\n"
+ " --reflect-unwrap-io-blocks unwrap input/output blocks the same as\n"
+ " uniform blocks\n"
" --resource-set-binding [stage] name set binding\n"
" set descriptor set and binding for\n"
" individual resources\n"
Buffer block reflection:
Pipeline input reflection:
-vertin: offset 0, type 1406, size 0, index 0, binding -1, stages 1
+vertin: offset 0, type 1406, size 1, index 0, binding -1, stages 1
Pipeline output reflection:
-fragout: offset 0, type 1406, size 0, index 0, binding -1, stages 16
+fragout: offset 0, type 1406, size 1, index 0, binding -1, stages 16
Buffer block reflection:
Pipeline input reflection:
-inval: offset 0, type 1406, size 0, index 0, binding -1, stages 16
+inval: offset 0, type 1406, size 1, index 0, binding -1, stages 16
Pipeline output reflection:
--- /dev/null
+reflection.options.geom
+Uniform reflection:
+
+Uniform block reflection:
+
+Buffer variable reflection:
+
+Buffer block reflection:
+
+Pipeline input reflection:
+gl_PerVertex.gl_Position: offset 0, type 8b52, size 1, index 0, binding -1, stages 8
+gl_PerVertex.gl_PointSize: offset 0, type 1406, size 1, index 0, binding -1, stages 8
+gl_PerVertex.gl_ClipDistance[0]: offset 0, type 1406, size 1, index 0, binding -1, stages 8
+block.Color: offset 0, type 8b50, size 1, index 0, binding -1, stages 8
+block.Texcoord: offset 0, type 8b50, size 1, index 0, binding -1, stages 8
+block.in_a: offset 0, type 8b54, size 1, index 0, binding -1, stages 8
+
+Pipeline output reflection:
+gl_Position: offset 0, type 8b52, size 1, index 0, binding -1, stages 8
+gl_PointSize: offset 0, type 1406, size 1, index 0, binding -1, stages 8
+gl_ClipDistance[0]: offset 0, type 1406, size 1, index 0, binding -1, stages 8
+block.Color: offset 0, type 8b52, size 1, index 0, binding -1, stages 8
+block.a: offset 0, type 8b52, size 1, index 0, binding -1, stages 8
+block.b[0]: offset 0, type 8b50, size 3, index 0, binding -1, stages 8
+
MultipleArrays: offset -1, type ffffffff, size 500, index -1, binding -1, stages 1, numMembers 9
Pipeline input reflection:
-gl_InstanceID: offset 0, type 1404, size 0, index 0, binding -1, stages 1
+gl_InstanceID: offset 0, type 1404, size 1, index 0, binding -1, stages 1
Pipeline output reflection:
-outval: offset 0, type 1406, size 0, index 0, binding -1, stages 1
+outval.val: offset 0, type 1406, size 1, index 0, binding -1, stages 1
+outval.a: offset 0, type 8b51, size 1, index 0, binding -1, stages 1
+outval.b[0]: offset 0, type 8b50, size 4, index 0, binding -1, stages 1
+outval.c: offset 0, type 8b5a, size 1, index 0, binding -1, stages 1
--- /dev/null
+#version 330 core\r
+\r
+precision highp float;\r
+\r
+layout(triangles) in;\r
+layout(triangle_strip, max_vertices = 4) out;\r
+\r
+in block\r
+{\r
+ vec2 Color;\r
+ vec2 Texcoord;\r
+ flat ivec3 in_a;\r
+} In[];\r
+\r
+out block\r
+{\r
+ vec4 Color;\r
+ vec4 a;\r
+ vec2 b[3];\r
+} Out;\r
+\r
+void main()\r
+{\r
+ for(int i = 0; i < gl_in.length(); ++i)\r
+ {\r
+ gl_Position = gl_in[i].gl_Position;\r
+ Out.Color = vec4(In[i].Color, 0, 1);\r
+ EmitVertex();\r
+ }\r
+ EndPrimitive();\r
+}\r
uvec4 unused;\r
} ubo;\r
\r
-out float outval;\r
+struct OutputStruct {\r
+ float val;\r
+ vec3 a;\r
+ vec2 b[4];\r
+ mat2x2 c;\r
+};\r
+\r
+out OutputStruct outval;\r
\r
void main()\r
{\r
f += ubo.verts[gl_InstanceID].position[0];\r
f += ubo.flt[gl_InstanceID];\r
TriangleInfo tlocal[5] = t;\r
- outval = f;\r
+ outval.val = f;\r
}\r
echo Running reflection...
$EXE -l -q -C reflection.vert > $TARGETDIR/reflection.vert.out
diff -b $BASEDIR/reflection.vert.out $TARGETDIR/reflection.vert.out || HASERROR=1
-$EXE -l -q -C --reflect-strict-array-suffix --reflect-basic-array-suffix --reflect-intermediate-io --reflect-separate-buffers --reflect-all-block-variables reflection.options.vert > $TARGETDIR/reflection.options.vert.out
+$EXE -l -q -C --reflect-strict-array-suffix --reflect-basic-array-suffix --reflect-intermediate-io --reflect-separate-buffers --reflect-all-block-variables --reflect-unwrap-io-blocks reflection.options.vert > $TARGETDIR/reflection.options.vert.out
diff -b $BASEDIR/reflection.options.vert.out $TARGETDIR/reflection.options.vert.out || HASERROR=1
$EXE -l -q -C reflection.frag > $TARGETDIR/reflection.frag.out
diff -b $BASEDIR/reflection.frag.out $TARGETDIR/reflection.frag.out || HASERROR=1
-$EXE -l -q -C --reflect-strict-array-suffix --reflect-basic-array-suffix --reflect-intermediate-io --reflect-separate-buffers --reflect-all-block-variables reflection.frag > $TARGETDIR/reflection.options.frag.out
+$EXE -l -q -C --reflect-strict-array-suffix --reflect-basic-array-suffix --reflect-intermediate-io --reflect-separate-buffers --reflect-all-block-variables --reflect-unwrap-io-blocks reflection.frag > $TARGETDIR/reflection.options.frag.out
diff -b $BASEDIR/reflection.options.frag.out $TARGETDIR/reflection.options.frag.out || HASERROR=1
+$EXE -l -q -C --reflect-strict-array-suffix --reflect-basic-array-suffix --reflect-intermediate-io --reflect-separate-buffers --reflect-all-block-variables --reflect-unwrap-io-blocks reflection.options.geom > $TARGETDIR/reflection.options.geom.out
+diff -b $BASEDIR/reflection.options.geom.out $TARGETDIR/reflection.options.geom.out || HASERROR=1
$EXE -l -q -C reflection.linked.vert reflection.linked.frag > $TARGETDIR/reflection.linked.out
diff -b $BASEDIR/reflection.linked.out $TARGETDIR/reflection.linked.out || HASERROR=1
-$EXE -l -q -C --reflect-strict-array-suffix --reflect-basic-array-suffix --reflect-intermediate-io --reflect-separate-buffers --reflect-all-block-variables reflection.linked.vert reflection.linked.frag > $TARGETDIR/reflection.linked.options.out
+$EXE -l -q -C --reflect-strict-array-suffix --reflect-basic-array-suffix --reflect-intermediate-io --reflect-separate-buffers --reflect-all-block-variables --reflect-unwrap-io-blocks reflection.linked.vert reflection.linked.frag > $TARGETDIR/reflection.linked.options.out
diff -b $BASEDIR/reflection.linked.options.out $TARGETDIR/reflection.linked.options.out || HASERROR=1
$EXE -D -Od -e flizv -l -q -C -V -Od hlsl.reflection.vert > $TARGETDIR/hlsl.reflection.vert.out
diff -b $BASEDIR/hlsl.reflection.vert.out $TARGETDIR/hlsl.reflection.vert.out || HASERROR=1
}
}
- void addPipeInput(const TIntermSymbol& base)
+ void addPipeIOVariable(const TIntermSymbol& base)
{
if (processedDerefs.find(&base) == processedDerefs.end()) {
processedDerefs.insert(&base);
const TString &name = base.getName();
const TType &type = base.getType();
+ const bool input = base.getQualifier().isPipeInput();
- TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(name.c_str());
- if (it == reflection.nameToIndex.end()) {
- reflection.nameToIndex[name.c_str()] = (int)reflection.indexToPipeInput.size();
- reflection.indexToPipeInput.push_back(TObjectReflection(name.c_str(), type, 0, mapToGlType(type), 0, 0));
+ TReflection::TMapIndexToReflection &ioItems =
+ input ? reflection.indexToPipeInput : reflection.indexToPipeOutput;
- EShLanguageMask& stages = reflection.indexToPipeInput.back().stages;
- stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
- } else {
- EShLanguageMask& stages = reflection.indexToPipeInput[it->second].stages;
- stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
- }
- }
- }
+ if (reflection.options & EShReflectionUnwrapIOBlocks) {
+ bool anonymous = IsAnonymous(name);
- void addPipeOutput(const TIntermSymbol& base)
- {
- if (processedDerefs.find(&base) == processedDerefs.end()) {
- processedDerefs.insert(&base);
-
- const TString &name = base.getName();
- const TType &type = base.getType();
-
- TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(name.c_str());
- if (it == reflection.nameToIndex.end()) {
- reflection.nameToIndex[name.c_str()] = (int)reflection.indexToPipeOutput.size();
- reflection.indexToPipeOutput.push_back(TObjectReflection(name.c_str(), type, 0, mapToGlType(type), 0, 0));
+ TString baseName;
+ if (type.getBasicType() == EbtBlock) {
+ baseName = anonymous ? TString() : type.getTypeName();
+ } else {
+ baseName = anonymous ? TString() : name;
+ }
- EShLanguageMask& stages = reflection.indexToPipeOutput.back().stages;
- stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
+ // by convention if this is an arrayed block we ignore the array in the reflection
+ if (type.isArray()) {
+ blowUpIOAggregate(input, baseName, TType(type, 0));
+ } else {
+ blowUpIOAggregate(input, baseName, type);
+ }
} else {
- EShLanguageMask& stages = reflection.indexToPipeOutput[it->second].stages;
- stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
+ TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(name.c_str());
+ if (it == reflection.nameToIndex.end()) {
+ reflection.nameToIndex[name.c_str()] = (int)ioItems.size();
+ ioItems.push_back(TObjectReflection(name.c_str(), type, 0, mapToGlType(type), 0, 0));
+
+ EShLanguageMask& stages = ioItems.back().stages;
+ stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
+ } else {
+ EShLanguageMask& stages = ioItems[it->second].stages;
+ stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
+ }
}
}
}
}
}
}
+
+ // similar to blowUpActiveAggregate, but with simpler rules and no dereferences to follow.
+ void blowUpIOAggregate(bool input, const TString &baseName, const TType &type)
+ {
+ TString name = baseName;
+
+ // if the type is still too coarse a granularity, this is still an aggregate to expand, expand it...
+ if (! isReflectionGranularity(type)) {
+ if (type.isArray()) {
+ // Visit all the indices of this array, and for each one,
+ // fully explode the remaining aggregate to dereference
+ for (int i = 0; i < std::max(type.getOuterArraySize(), 1); ++i) {
+ TString newBaseName = name;
+ newBaseName.append(TString("[") + String(i) + "]");
+ TType derefType(type, 0);
+
+ blowUpIOAggregate(input, newBaseName, derefType);
+ }
+ } else {
+ // Visit all members of this aggregate, and for each one,
+ // fully explode the remaining aggregate to dereference
+ const TTypeList& typeList = *type.getStruct();
+
+ for (int i = 0; i < (int)typeList.size(); ++i) {
+ TString newBaseName = name;
+ if (newBaseName.size() > 0)
+ newBaseName.append(".");
+ newBaseName.append(typeList[i].type->getFieldName());
+ TType derefType(type, i);
+
+ blowUpIOAggregate(input, newBaseName, derefType);
+ }
+ }
+
+ // it was all completed in the recursive calls above
+ return;
+ }
+
+ if ((reflection.options & EShReflectionBasicArraySuffix) && type.isArray()) {
+ name.append(TString("[0]"));
+ }
+
+ TReflection::TMapIndexToReflection &ioItems =
+ input ? reflection.indexToPipeInput : reflection.indexToPipeOutput;
+
+ std::string namespacedName = input ? "in " : "out ";
+ namespacedName += name.c_str();
+
+ TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(namespacedName);
+ if (it == reflection.nameToIndex.end()) {
+ reflection.nameToIndex[namespacedName] = (int)ioItems.size();
+ ioItems.push_back(
+ TObjectReflection(name.c_str(), type, 0, mapToGlType(type), mapToGlArraySize(type), 0));
+
+ EShLanguageMask& stages = ioItems.back().stages;
+ stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
+ } else {
+ EShLanguageMask& stages = ioItems[it->second].stages;
+ stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
+ }
+ }
// Add a uniform dereference where blocks/struct/arrays are involved in the access.
// Handles the situation where the left node is at the correct or too coarse a
if (base->getQualifier().storage == EvqUniform)
addUniform(*base);
- if (intermediate.getStage() == reflection.firstStage && base->getQualifier().isPipeInput())
- addPipeInput(*base);
-
- if (intermediate.getStage() == reflection.lastStage && base->getQualifier().isPipeOutput())
- addPipeOutput(*base);
+ if ((intermediate.getStage() == reflection.firstStage && base->getQualifier().isPipeInput()) ||
+ (intermediate.getStage() == reflection.lastStage && base->getQualifier().isPipeOutput()))
+ addPipeIOVariable(*base);
}
//
EShReflectionIntermediateIO = (1 << 2), // reflect inputs and outputs to program, even with no vertex shader
EShReflectionSeparateBuffers = (1 << 3), // buffer variables and buffer blocks are reflected separately
EShReflectionAllBlockVariables = (1 << 4), // reflect all variables in blocks, even if they are inactive
+ EShReflectionUnwrapIOBlocks = (1 << 5), // unwrap input/output blocks the same as with uniform blocks
} EShReflectionOptions;
//