Add support for passing nested structs in standard layout by value.
We add support for this by using global scratch values as storage for the structs in
uniform blocks. Any structs in std140 layouts that are referenced by value are initialized
in the shader scope, without any packing, so the type of the structs are equivalent with what
a GLSL program would expect.
TRAC #23327
Signed-off-by: Geoff Lang
Signed-off-by: Shannon Woods
Authored-by: Jamie Madill
diff --git a/src/compiler/FlagStd140Structs.cpp b/src/compiler/FlagStd140Structs.cpp
new file mode 100644
index 0000000..1aaf50b
--- /dev/null
+++ b/src/compiler/FlagStd140Structs.cpp
@@ -0,0 +1,77 @@
+//
+// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/FlagStd140Structs.h"
+
+namespace sh
+{
+
+bool FlagStd140Structs::visitBinary(Visit visit, TIntermBinary *binaryNode)
+{
+ if (binaryNode->getRight()->getBasicType() == EbtStruct)
+ {
+ switch (binaryNode->getOp())
+ {
+ case EOpIndexDirectInterfaceBlock:
+ case EOpIndexDirectStruct:
+ if (isInStd140InterfaceBlock(binaryNode->getLeft()))
+ {
+ mFlaggedNodes.push_back(binaryNode);
+ }
+ break;
+
+ default: break;
+ }
+ return false;
+ }
+
+ if (binaryNode->getOp() == EOpIndexDirectStruct)
+ {
+ return false;
+ }
+
+ return visit == PreVisit;
+}
+
+void FlagStd140Structs::visitSymbol(TIntermSymbol *symbol)
+{
+ if (isInStd140InterfaceBlock(symbol) && symbol->getBasicType() == EbtStruct)
+ {
+ mFlaggedNodes.push_back(symbol);
+ }
+}
+
+bool FlagStd140Structs::isInStd140InterfaceBlock(TIntermTyped *node) const
+{
+ TIntermBinary *binaryNode = node->getAsBinaryNode();
+
+ if (binaryNode)
+ {
+ return isInStd140InterfaceBlock(binaryNode->getLeft());
+ }
+
+ const TType &type = node->getType();
+
+ if (type.isInterfaceBlockMember() || type.getBasicType() == EbtInterfaceBlock)
+ {
+ // determine if we are in the standard layout
+ const TType &interfaceBlockType = (type.isInterfaceBlockMember() ? *type.getInterfaceBlockType() : type);
+ return (interfaceBlockType.getLayoutQualifier().blockStorage == EbsStd140);
+ }
+
+ return false;
+}
+
+std::vector<TIntermTyped *> FlagStd140ValueStructs(TIntermNode *node)
+{
+ FlagStd140Structs flaggingTraversal;
+
+ node->traverse(&flaggingTraversal);
+
+ return flaggingTraversal.getFlaggedNodes();
+}
+
+}