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/IntermNode.h"
14#include "compiler/translator/SymbolTable.h"
15#include "compiler/translator/tree_util/FindMain.h"
16#include "compiler/translator/tree_util/IntermNode_util.h"
17#include "compiler/translator/util.h"
18
19namespace sh
20{
21
22namespace
23{
24
25void AddNodeUseStatements(TIntermTyped *node, TIntermSequence *sequence)
26{
27 if (node->isArray())
28 {
29 for (unsigned int i = 0u; i < node->getOutermostArraySize(); ++i)
30 {
31 TIntermBinary *element =
32 new TIntermBinary(EOpIndexDirect, node->deepCopy(), CreateIndexNode(i));
33 AddNodeUseStatements(element, sequence);
34 }
35 }
36 else
37 {
38 sequence->insert(sequence->begin(), node);
39 }
40}
41
42void AddFieldUseStatements(const ShaderVariable &var,
43 TIntermSequence *sequence,
44 const TSymbolTable &symbolTable)
45{
46 ASSERT(var.name.find_last_of('[') == std::string::npos);
47 TIntermSymbol *symbol = ReferenceGlobalVariable(ImmutableString(var.name), symbolTable);
48 AddNodeUseStatements(symbol, sequence);
49}
50
51void InsertUseCode(const InterfaceBlock &block, TIntermTyped *blockNode, TIntermSequence *sequence)
52{
53 for (unsigned int i = 0; i < block.fields.size(); ++i)
54 {
55 TIntermBinary *element = new TIntermBinary(EOpIndexDirectInterfaceBlock,
56 blockNode->deepCopy(), CreateIndexNode(i));
57 sequence->insert(sequence->begin(), element);
58 }
59}
60
61void InsertUseCode(TIntermSequence *sequence,
62 const InterfaceBlockList &blocks,
63 const TSymbolTable &symbolTable)
64{
65 for (const auto &block : blocks)
66 {
67 if (block.instanceName.empty())
68 {
69 for (const auto &var : block.fields)
70 {
71 AddFieldUseStatements(var, sequence, symbolTable);
72 }
73 }
74 else if (block.arraySize > 0u)
75 {
76 TIntermSymbol *arraySymbol =
77 ReferenceGlobalVariable(ImmutableString(block.instanceName), symbolTable);
78 for (unsigned int i = 0u; i < block.arraySize; ++i)
79 {
80 TIntermBinary *elementSymbol =
81 new TIntermBinary(EOpIndexDirect, arraySymbol->deepCopy(), CreateIndexNode(i));
82 InsertUseCode(block, elementSymbol, sequence);
83 }
84 }
85 else
86 {
87 TIntermSymbol *blockSymbol =
88 ReferenceGlobalVariable(ImmutableString(block.instanceName), symbolTable);
89 InsertUseCode(block, blockSymbol, sequence);
90 }
91 }
92}
93
94} // namespace
95
96void UseInterfaceBlockFields(TIntermBlock *root,
97 const InterfaceBlockList &blocks,
98 const TSymbolTable &symbolTable)
99{
100 TIntermBlock *mainBody = FindMainBody(root);
101 InsertUseCode(mainBody->getSequence(), blocks, symbolTable);
102}
103
104} // namespace sh
105