blob: 859507ffd94d7445be17db8b84a26db56e24bb1c [file] [log] [blame]
Qin Jiajia7835b522016-10-08 11:20:17 +08001//
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/UseInterfaceBlockFields.h"
12
13#include "compiler/translator/IntermNode.h"
14#include "compiler/translator/util.h"
15
16namespace sh
17{
18
19namespace
20{
21
22class UseUniformBlockMembers : public TIntermTraverser
23{
24 public:
25 UseUniformBlockMembers(const InterfaceBlockList &blocks)
26 : TIntermTraverser(true, false, false), mBlocks(blocks), mCodeInserted(false)
27 {
28 }
29
30 protected:
31 bool visitAggregate(Visit visit, TIntermAggregate *node) override;
32
33 private:
34 void insertUseCode(TIntermSequence *sequence);
35 void AddFieldUseStatements(const ShaderVariable &var, TIntermSequence *sequence);
36
37 const InterfaceBlockList &mBlocks;
38 bool mCodeInserted;
39};
40
41bool UseUniformBlockMembers::visitAggregate(Visit visit, TIntermAggregate *node)
42{
43 bool visitChildren = !mCodeInserted;
44 switch (node->getOp())
45 {
46 case EOpFunction:
47 {
48 ASSERT(visit == PreVisit);
49 if (node->getFunctionSymbolInfo()->isMain())
50 {
51 TIntermSequence *sequence = node->getSequence();
52 ASSERT(sequence->size() == 2);
53 TIntermBlock *body = (*sequence)[1]->getAsBlock();
54 ASSERT(body);
55 insertUseCode(body->getSequence());
56 mCodeInserted = true;
57 visitChildren = false;
58 }
59 break;
60 }
61 default:
62 visitChildren = false;
63 break;
64 }
65 return visitChildren;
66}
67
68void UseUniformBlockMembers::AddFieldUseStatements(const ShaderVariable &var,
69 TIntermSequence *sequence)
70{
71 TString name = TString(var.name.c_str());
72 TType type = GetShaderVariableType(var);
73
74 if (var.isArray())
75 {
76 size_t pos = name.find_last_of('[');
77 if (pos != TString::npos)
78 {
79 name = name.substr(0, pos);
80 }
81 TType elementType = type;
82 elementType.clearArrayness();
83
84 TIntermSymbol *arraySymbol = new TIntermSymbol(0, name, type);
85 for (unsigned int i = 0; i < var.arraySize; ++i)
86 {
87 TIntermBinary *element =
88 new TIntermBinary(EOpIndexDirect, arraySymbol, TIntermTyped::CreateIndexNode(i));
89
90 sequence->insert(sequence->begin(), element);
91 }
92 }
93 else if (var.isStruct())
94 {
95 TIntermSymbol *structSymbol = new TIntermSymbol(0, name, type);
96 for (unsigned int i = 0; i < var.fields.size(); ++i)
97 {
98 TIntermBinary *element = new TIntermBinary(EOpIndexDirectStruct, structSymbol,
99 TIntermTyped::CreateIndexNode(i));
100
101 sequence->insert(sequence->begin(), element);
102 }
103 }
104 else
105 {
106 TIntermSymbol *symbol = new TIntermSymbol(0, name, type);
107
108 sequence->insert(sequence->begin(), symbol);
109 }
110}
111
112void UseUniformBlockMembers::insertUseCode(TIntermSequence *sequence)
113{
114 for (const auto &block : mBlocks)
115 {
116 if (block.instanceName.empty())
117 {
118 for (const auto &var : block.fields)
119 {
120 AddFieldUseStatements(var, sequence);
121 }
122 }
123 else if (block.arraySize > 0)
124 {
125 TType type = GetInterfaceBlockType(block);
126 TString name = TString(block.instanceName.c_str());
127 TIntermSymbol *arraySymbol = new TIntermSymbol(0, name, type);
128 for (unsigned int i = 0; i < block.arraySize; ++i)
129 {
130 TIntermBinary *instanceSymbol = new TIntermBinary(EOpIndexDirect, arraySymbol,
131 TIntermTyped::CreateIndexNode(i));
132 for (unsigned int j = 0; j < block.fields.size(); ++j)
133 {
134 TIntermBinary *element =
135 new TIntermBinary(EOpIndexDirectInterfaceBlock, instanceSymbol,
136 TIntermTyped::CreateIndexNode(j));
137 sequence->insert(sequence->begin(), element);
138 }
139 }
140 }
141 else
142 {
143 TType type = GetInterfaceBlockType(block);
144 TString name = TString(block.instanceName.c_str());
145 TIntermSymbol *blockSymbol = new TIntermSymbol(0, name, type);
146 for (unsigned int i = 0; i < block.fields.size(); ++i)
147 {
148 TIntermBinary *element = new TIntermBinary(
149 EOpIndexDirectInterfaceBlock, blockSymbol, TIntermTyped::CreateIndexNode(i));
150
151 sequence->insert(sequence->begin(), element);
152 }
153 }
154 }
155}
156
157} // namespace anonymous
158
159void UseInterfaceBlockFields(TIntermNode *root, const InterfaceBlockList &blocks)
160{
161 UseUniformBlockMembers useUniformBlock(blocks);
162 root->traverse(&useUniformBlock);
163}
164
165} // namespace sh