1 //
2 // Copyright 2016 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 // UseInterfaceBlockFields.cpp: insert statements to reference all members in InterfaceBlock list at
8 // the beginning of main. This is to work around a Mac driver that treats unused standard/shared
9 // uniform blocks as inactive.
10 
11 #include "compiler/translator/tree_ops/UseInterfaceBlockFields.h"
12 
13 #include "compiler/translator/Compiler.h"
14 #include "compiler/translator/IntermNode.h"
15 #include "compiler/translator/SymbolTable.h"
16 #include "compiler/translator/tree_util/FindMain.h"
17 #include "compiler/translator/tree_util/IntermNode_util.h"
18 #include "compiler/translator/util.h"
19 
20 namespace sh
21 {
22 
23 namespace
24 {
25 
AddNodeUseStatements(TIntermTyped * node,TIntermSequence * sequence)26 void AddNodeUseStatements(TIntermTyped *node, TIntermSequence *sequence)
27 {
28     if (node->isArray())
29     {
30         for (unsigned int i = 0u; i < node->getOutermostArraySize(); ++i)
31         {
32             TIntermBinary *element =
33                 new TIntermBinary(EOpIndexDirect, node->deepCopy(), CreateIndexNode(i));
34             AddNodeUseStatements(element, sequence);
35         }
36     }
37     else
38     {
39         sequence->insert(sequence->begin(), node);
40     }
41 }
42 
AddFieldUseStatements(const ShaderVariable & var,TIntermSequence * sequence,const TSymbolTable & symbolTable)43 void AddFieldUseStatements(const ShaderVariable &var,
44                            TIntermSequence *sequence,
45                            const TSymbolTable &symbolTable)
46 {
47     ASSERT(var.name.find_last_of('[') == std::string::npos);
48     TIntermSymbol *symbol = ReferenceGlobalVariable(ImmutableString(var.name), symbolTable);
49     AddNodeUseStatements(symbol, sequence);
50 }
51 
InsertUseCode(const InterfaceBlock & block,TIntermTyped * blockNode,TIntermSequence * sequence)52 void InsertUseCode(const InterfaceBlock &block, TIntermTyped *blockNode, TIntermSequence *sequence)
53 {
54     for (unsigned int i = 0; i < block.fields.size(); ++i)
55     {
56         TIntermBinary *element = new TIntermBinary(EOpIndexDirectInterfaceBlock,
57                                                    blockNode->deepCopy(), CreateIndexNode(i));
58         sequence->insert(sequence->begin(), element);
59     }
60 }
61 
InsertUseCode(TIntermSequence * sequence,const InterfaceBlockList & blocks,const TSymbolTable & symbolTable)62 void InsertUseCode(TIntermSequence *sequence,
63                    const InterfaceBlockList &blocks,
64                    const TSymbolTable &symbolTable)
65 {
66     for (const auto &block : blocks)
67     {
68         if (block.instanceName.empty())
69         {
70             for (const auto &var : block.fields)
71             {
72                 AddFieldUseStatements(var, sequence, symbolTable);
73             }
74         }
75         else if (block.arraySize > 0u)
76         {
77             TIntermSymbol *arraySymbol =
78                 ReferenceGlobalVariable(ImmutableString(block.instanceName), symbolTable);
79             for (unsigned int i = 0u; i < block.arraySize; ++i)
80             {
81                 TIntermBinary *elementSymbol =
82                     new TIntermBinary(EOpIndexDirect, arraySymbol->deepCopy(), CreateIndexNode(i));
83                 InsertUseCode(block, elementSymbol, sequence);
84             }
85         }
86         else
87         {
88             TIntermSymbol *blockSymbol =
89                 ReferenceGlobalVariable(ImmutableString(block.instanceName), symbolTable);
90             InsertUseCode(block, blockSymbol, sequence);
91         }
92     }
93 }
94 
95 }  // namespace
96 
UseInterfaceBlockFields(TCompiler * compiler,TIntermBlock * root,const InterfaceBlockList & blocks,const TSymbolTable & symbolTable)97 bool UseInterfaceBlockFields(TCompiler *compiler,
98                              TIntermBlock *root,
99                              const InterfaceBlockList &blocks,
100                              const TSymbolTable &symbolTable)
101 {
102     TIntermBlock *mainBody = FindMainBody(root);
103     InsertUseCode(mainBody->getSequence(), blocks, symbolTable);
104 
105     return compiler->validateAST(root);
106 }
107 
108 }  // namespace sh
109