1*8975f5c5SAndroid Build Coastguard Worker //
2*8975f5c5SAndroid Build Coastguard Worker // Copyright 2013 The ANGLE Project Authors. All rights reserved.
3*8975f5c5SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
4*8975f5c5SAndroid Build Coastguard Worker // found in the LICENSE file.
5*8975f5c5SAndroid Build Coastguard Worker //
6*8975f5c5SAndroid Build Coastguard Worker // ValidateOutputs validates fragment shader outputs. It checks for conflicting locations,
7*8975f5c5SAndroid Build Coastguard Worker // out-of-range locations, that locations are specified when using multiple outputs, and YUV output
8*8975f5c5SAndroid Build Coastguard Worker // validity.
9*8975f5c5SAndroid Build Coastguard Worker
10*8975f5c5SAndroid Build Coastguard Worker #include "compiler/translator/ValidateOutputs.h"
11*8975f5c5SAndroid Build Coastguard Worker
12*8975f5c5SAndroid Build Coastguard Worker #include <set>
13*8975f5c5SAndroid Build Coastguard Worker
14*8975f5c5SAndroid Build Coastguard Worker #include "compiler/translator/InfoSink.h"
15*8975f5c5SAndroid Build Coastguard Worker #include "compiler/translator/ParseContext.h"
16*8975f5c5SAndroid Build Coastguard Worker #include "compiler/translator/tree_util/IntermTraverse.h"
17*8975f5c5SAndroid Build Coastguard Worker
18*8975f5c5SAndroid Build Coastguard Worker namespace sh
19*8975f5c5SAndroid Build Coastguard Worker {
20*8975f5c5SAndroid Build Coastguard Worker
21*8975f5c5SAndroid Build Coastguard Worker namespace
22*8975f5c5SAndroid Build Coastguard Worker {
23*8975f5c5SAndroid Build Coastguard Worker
error(const TIntermSymbol & symbol,const char * reason,TDiagnostics * diagnostics)24*8975f5c5SAndroid Build Coastguard Worker void error(const TIntermSymbol &symbol, const char *reason, TDiagnostics *diagnostics)
25*8975f5c5SAndroid Build Coastguard Worker {
26*8975f5c5SAndroid Build Coastguard Worker diagnostics->error(symbol.getLine(), reason, symbol.getName().data());
27*8975f5c5SAndroid Build Coastguard Worker }
28*8975f5c5SAndroid Build Coastguard Worker
29*8975f5c5SAndroid Build Coastguard Worker class ValidateOutputsTraverser : public TIntermTraverser
30*8975f5c5SAndroid Build Coastguard Worker {
31*8975f5c5SAndroid Build Coastguard Worker public:
32*8975f5c5SAndroid Build Coastguard Worker ValidateOutputsTraverser(const TExtensionBehavior &extBehavior,
33*8975f5c5SAndroid Build Coastguard Worker const ShBuiltInResources &resources,
34*8975f5c5SAndroid Build Coastguard Worker bool usesPixelLocalStorage,
35*8975f5c5SAndroid Build Coastguard Worker bool isWebGL);
36*8975f5c5SAndroid Build Coastguard Worker
37*8975f5c5SAndroid Build Coastguard Worker void validate(TDiagnostics *diagnostics) const;
38*8975f5c5SAndroid Build Coastguard Worker
39*8975f5c5SAndroid Build Coastguard Worker void visitSymbol(TIntermSymbol *) override;
40*8975f5c5SAndroid Build Coastguard Worker
41*8975f5c5SAndroid Build Coastguard Worker private:
42*8975f5c5SAndroid Build Coastguard Worker int mMaxDrawBuffers;
43*8975f5c5SAndroid Build Coastguard Worker int mMaxDualSourceDrawBuffers;
44*8975f5c5SAndroid Build Coastguard Worker bool mEnablesBlendFuncExtended;
45*8975f5c5SAndroid Build Coastguard Worker bool mUsesIndex1;
46*8975f5c5SAndroid Build Coastguard Worker bool mUsesPixelLocalStorage;
47*8975f5c5SAndroid Build Coastguard Worker bool mIsWebGL;
48*8975f5c5SAndroid Build Coastguard Worker bool mUsesFragDepth;
49*8975f5c5SAndroid Build Coastguard Worker
50*8975f5c5SAndroid Build Coastguard Worker typedef std::vector<TIntermSymbol *> OutputVector;
51*8975f5c5SAndroid Build Coastguard Worker OutputVector mOutputs;
52*8975f5c5SAndroid Build Coastguard Worker OutputVector mUnspecifiedLocationOutputs;
53*8975f5c5SAndroid Build Coastguard Worker OutputVector mYuvOutputs;
54*8975f5c5SAndroid Build Coastguard Worker std::set<int> mVisitedSymbols; // Visited symbol ids.
55*8975f5c5SAndroid Build Coastguard Worker };
56*8975f5c5SAndroid Build Coastguard Worker
ValidateOutputsTraverser(const TExtensionBehavior & extBehavior,const ShBuiltInResources & resources,bool usesPixelLocalStorage,bool isWebGL)57*8975f5c5SAndroid Build Coastguard Worker ValidateOutputsTraverser::ValidateOutputsTraverser(const TExtensionBehavior &extBehavior,
58*8975f5c5SAndroid Build Coastguard Worker const ShBuiltInResources &resources,
59*8975f5c5SAndroid Build Coastguard Worker bool usesPixelLocalStorage,
60*8975f5c5SAndroid Build Coastguard Worker bool isWebGL)
61*8975f5c5SAndroid Build Coastguard Worker : TIntermTraverser(true, false, false),
62*8975f5c5SAndroid Build Coastguard Worker mMaxDrawBuffers(resources.MaxDrawBuffers),
63*8975f5c5SAndroid Build Coastguard Worker mMaxDualSourceDrawBuffers(resources.MaxDualSourceDrawBuffers),
64*8975f5c5SAndroid Build Coastguard Worker mEnablesBlendFuncExtended(
65*8975f5c5SAndroid Build Coastguard Worker IsExtensionEnabled(extBehavior, TExtension::EXT_blend_func_extended)),
66*8975f5c5SAndroid Build Coastguard Worker mUsesIndex1(false),
67*8975f5c5SAndroid Build Coastguard Worker mUsesPixelLocalStorage(usesPixelLocalStorage),
68*8975f5c5SAndroid Build Coastguard Worker mIsWebGL(isWebGL),
69*8975f5c5SAndroid Build Coastguard Worker mUsesFragDepth(false)
70*8975f5c5SAndroid Build Coastguard Worker {}
71*8975f5c5SAndroid Build Coastguard Worker
visitSymbol(TIntermSymbol * symbol)72*8975f5c5SAndroid Build Coastguard Worker void ValidateOutputsTraverser::visitSymbol(TIntermSymbol *symbol)
73*8975f5c5SAndroid Build Coastguard Worker {
74*8975f5c5SAndroid Build Coastguard Worker if (symbol->variable().symbolType() == SymbolType::Empty)
75*8975f5c5SAndroid Build Coastguard Worker return;
76*8975f5c5SAndroid Build Coastguard Worker
77*8975f5c5SAndroid Build Coastguard Worker if (mVisitedSymbols.count(symbol->uniqueId().get()) == 1)
78*8975f5c5SAndroid Build Coastguard Worker return;
79*8975f5c5SAndroid Build Coastguard Worker
80*8975f5c5SAndroid Build Coastguard Worker mVisitedSymbols.insert(symbol->uniqueId().get());
81*8975f5c5SAndroid Build Coastguard Worker
82*8975f5c5SAndroid Build Coastguard Worker TQualifier qualifier = symbol->getQualifier();
83*8975f5c5SAndroid Build Coastguard Worker if (qualifier == EvqFragmentOut)
84*8975f5c5SAndroid Build Coastguard Worker {
85*8975f5c5SAndroid Build Coastguard Worker const TLayoutQualifier &layoutQualifier = symbol->getType().getLayoutQualifier();
86*8975f5c5SAndroid Build Coastguard Worker if (layoutQualifier.location != -1)
87*8975f5c5SAndroid Build Coastguard Worker {
88*8975f5c5SAndroid Build Coastguard Worker mOutputs.push_back(symbol);
89*8975f5c5SAndroid Build Coastguard Worker if (layoutQualifier.index == 1)
90*8975f5c5SAndroid Build Coastguard Worker {
91*8975f5c5SAndroid Build Coastguard Worker mUsesIndex1 = true;
92*8975f5c5SAndroid Build Coastguard Worker }
93*8975f5c5SAndroid Build Coastguard Worker }
94*8975f5c5SAndroid Build Coastguard Worker else if (layoutQualifier.yuv == true)
95*8975f5c5SAndroid Build Coastguard Worker {
96*8975f5c5SAndroid Build Coastguard Worker mYuvOutputs.push_back(symbol);
97*8975f5c5SAndroid Build Coastguard Worker }
98*8975f5c5SAndroid Build Coastguard Worker else
99*8975f5c5SAndroid Build Coastguard Worker {
100*8975f5c5SAndroid Build Coastguard Worker mUnspecifiedLocationOutputs.push_back(symbol);
101*8975f5c5SAndroid Build Coastguard Worker }
102*8975f5c5SAndroid Build Coastguard Worker }
103*8975f5c5SAndroid Build Coastguard Worker else if (qualifier == EvqFragDepth)
104*8975f5c5SAndroid Build Coastguard Worker {
105*8975f5c5SAndroid Build Coastguard Worker mUsesFragDepth = true;
106*8975f5c5SAndroid Build Coastguard Worker }
107*8975f5c5SAndroid Build Coastguard Worker }
108*8975f5c5SAndroid Build Coastguard Worker
validate(TDiagnostics * diagnostics) const109*8975f5c5SAndroid Build Coastguard Worker void ValidateOutputsTraverser::validate(TDiagnostics *diagnostics) const
110*8975f5c5SAndroid Build Coastguard Worker {
111*8975f5c5SAndroid Build Coastguard Worker ASSERT(diagnostics);
112*8975f5c5SAndroid Build Coastguard Worker OutputVector validOutputs(mUsesIndex1 ? mMaxDualSourceDrawBuffers : mMaxDrawBuffers, nullptr);
113*8975f5c5SAndroid Build Coastguard Worker OutputVector validSecondaryOutputs(mMaxDualSourceDrawBuffers, nullptr);
114*8975f5c5SAndroid Build Coastguard Worker
115*8975f5c5SAndroid Build Coastguard Worker for (const auto &symbol : mOutputs)
116*8975f5c5SAndroid Build Coastguard Worker {
117*8975f5c5SAndroid Build Coastguard Worker const TType &type = symbol->getType();
118*8975f5c5SAndroid Build Coastguard Worker ASSERT(!type.isArrayOfArrays()); // Disallowed in GLSL ES 3.10 section 4.3.6.
119*8975f5c5SAndroid Build Coastguard Worker const size_t elementCount =
120*8975f5c5SAndroid Build Coastguard Worker static_cast<size_t>(type.isArray() ? type.getOutermostArraySize() : 1u);
121*8975f5c5SAndroid Build Coastguard Worker const size_t location = static_cast<size_t>(type.getLayoutQualifier().location);
122*8975f5c5SAndroid Build Coastguard Worker
123*8975f5c5SAndroid Build Coastguard Worker ASSERT(type.getLayoutQualifier().location != -1);
124*8975f5c5SAndroid Build Coastguard Worker
125*8975f5c5SAndroid Build Coastguard Worker OutputVector *validOutputsToUse = &validOutputs;
126*8975f5c5SAndroid Build Coastguard Worker OutputVector *otherOutputsToUse = &validSecondaryOutputs;
127*8975f5c5SAndroid Build Coastguard Worker // The default index is 0, so we only assign the output to secondary outputs in case the
128*8975f5c5SAndroid Build Coastguard Worker // index is explicitly set to 1.
129*8975f5c5SAndroid Build Coastguard Worker if (type.getLayoutQualifier().index == 1)
130*8975f5c5SAndroid Build Coastguard Worker {
131*8975f5c5SAndroid Build Coastguard Worker validOutputsToUse = &validSecondaryOutputs;
132*8975f5c5SAndroid Build Coastguard Worker otherOutputsToUse = &validOutputs;
133*8975f5c5SAndroid Build Coastguard Worker }
134*8975f5c5SAndroid Build Coastguard Worker
135*8975f5c5SAndroid Build Coastguard Worker if (location + elementCount <= validOutputsToUse->size())
136*8975f5c5SAndroid Build Coastguard Worker {
137*8975f5c5SAndroid Build Coastguard Worker for (size_t elementIndex = 0; elementIndex < elementCount; elementIndex++)
138*8975f5c5SAndroid Build Coastguard Worker {
139*8975f5c5SAndroid Build Coastguard Worker const size_t offsetLocation = location + elementIndex;
140*8975f5c5SAndroid Build Coastguard Worker if ((*validOutputsToUse)[offsetLocation])
141*8975f5c5SAndroid Build Coastguard Worker {
142*8975f5c5SAndroid Build Coastguard Worker std::stringstream strstr = sh::InitializeStream<std::stringstream>();
143*8975f5c5SAndroid Build Coastguard Worker strstr << "conflicting output locations with previously defined output '"
144*8975f5c5SAndroid Build Coastguard Worker << (*validOutputsToUse)[offsetLocation]->getName() << "'";
145*8975f5c5SAndroid Build Coastguard Worker error(*symbol, strstr.str().c_str(), diagnostics);
146*8975f5c5SAndroid Build Coastguard Worker }
147*8975f5c5SAndroid Build Coastguard Worker else
148*8975f5c5SAndroid Build Coastguard Worker {
149*8975f5c5SAndroid Build Coastguard Worker (*validOutputsToUse)[offsetLocation] = symbol;
150*8975f5c5SAndroid Build Coastguard Worker if (offsetLocation < otherOutputsToUse->size())
151*8975f5c5SAndroid Build Coastguard Worker {
152*8975f5c5SAndroid Build Coastguard Worker TIntermSymbol *otherSymbol = (*otherOutputsToUse)[offsetLocation];
153*8975f5c5SAndroid Build Coastguard Worker if (otherSymbol && otherSymbol->getType().getBasicType() !=
154*8975f5c5SAndroid Build Coastguard Worker symbol->getType().getBasicType())
155*8975f5c5SAndroid Build Coastguard Worker {
156*8975f5c5SAndroid Build Coastguard Worker std::stringstream strstr = sh::InitializeStream<std::stringstream>();
157*8975f5c5SAndroid Build Coastguard Worker strstr << "conflicting output types with previously defined output "
158*8975f5c5SAndroid Build Coastguard Worker << "'" << (*otherOutputsToUse)[offsetLocation]->getName() << "'"
159*8975f5c5SAndroid Build Coastguard Worker << " for location " << offsetLocation;
160*8975f5c5SAndroid Build Coastguard Worker error(*symbol, strstr.str().c_str(), diagnostics);
161*8975f5c5SAndroid Build Coastguard Worker }
162*8975f5c5SAndroid Build Coastguard Worker }
163*8975f5c5SAndroid Build Coastguard Worker }
164*8975f5c5SAndroid Build Coastguard Worker }
165*8975f5c5SAndroid Build Coastguard Worker }
166*8975f5c5SAndroid Build Coastguard Worker else
167*8975f5c5SAndroid Build Coastguard Worker {
168*8975f5c5SAndroid Build Coastguard Worker if (elementCount > 0)
169*8975f5c5SAndroid Build Coastguard Worker {
170*8975f5c5SAndroid Build Coastguard Worker std::stringstream strstr = sh::InitializeStream<std::stringstream>();
171*8975f5c5SAndroid Build Coastguard Worker strstr << (elementCount > 1 ? "output array locations would exceed "
172*8975f5c5SAndroid Build Coastguard Worker : "output location must be < ")
173*8975f5c5SAndroid Build Coastguard Worker << "MAX_" << (mUsesIndex1 ? "DUAL_SOURCE_" : "") << "DRAW_BUFFERS";
174*8975f5c5SAndroid Build Coastguard Worker error(*symbol, strstr.str().c_str(), diagnostics);
175*8975f5c5SAndroid Build Coastguard Worker }
176*8975f5c5SAndroid Build Coastguard Worker }
177*8975f5c5SAndroid Build Coastguard Worker }
178*8975f5c5SAndroid Build Coastguard Worker
179*8975f5c5SAndroid Build Coastguard Worker if ((!mOutputs.empty() && !mUnspecifiedLocationOutputs.empty()) ||
180*8975f5c5SAndroid Build Coastguard Worker mUnspecifiedLocationOutputs.size() > 1)
181*8975f5c5SAndroid Build Coastguard Worker {
182*8975f5c5SAndroid Build Coastguard Worker const char *unspecifiedLocationErrorMessage = nullptr;
183*8975f5c5SAndroid Build Coastguard Worker if (!mEnablesBlendFuncExtended)
184*8975f5c5SAndroid Build Coastguard Worker {
185*8975f5c5SAndroid Build Coastguard Worker unspecifiedLocationErrorMessage =
186*8975f5c5SAndroid Build Coastguard Worker "must explicitly specify all locations when using multiple fragment outputs";
187*8975f5c5SAndroid Build Coastguard Worker }
188*8975f5c5SAndroid Build Coastguard Worker else if (mUsesPixelLocalStorage)
189*8975f5c5SAndroid Build Coastguard Worker {
190*8975f5c5SAndroid Build Coastguard Worker unspecifiedLocationErrorMessage =
191*8975f5c5SAndroid Build Coastguard Worker "must explicitly specify all locations when using multiple fragment outputs and "
192*8975f5c5SAndroid Build Coastguard Worker "pixel local storage, even if EXT_blend_func_extended is enabled";
193*8975f5c5SAndroid Build Coastguard Worker }
194*8975f5c5SAndroid Build Coastguard Worker else if (mIsWebGL)
195*8975f5c5SAndroid Build Coastguard Worker {
196*8975f5c5SAndroid Build Coastguard Worker unspecifiedLocationErrorMessage =
197*8975f5c5SAndroid Build Coastguard Worker "must explicitly specify all locations when using multiple fragment outputs "
198*8975f5c5SAndroid Build Coastguard Worker "in WebGL contexts, even if EXT_blend_func_extended is enabled";
199*8975f5c5SAndroid Build Coastguard Worker }
200*8975f5c5SAndroid Build Coastguard Worker if (unspecifiedLocationErrorMessage != nullptr)
201*8975f5c5SAndroid Build Coastguard Worker {
202*8975f5c5SAndroid Build Coastguard Worker for (const auto &symbol : mUnspecifiedLocationOutputs)
203*8975f5c5SAndroid Build Coastguard Worker {
204*8975f5c5SAndroid Build Coastguard Worker error(*symbol, unspecifiedLocationErrorMessage, diagnostics);
205*8975f5c5SAndroid Build Coastguard Worker }
206*8975f5c5SAndroid Build Coastguard Worker }
207*8975f5c5SAndroid Build Coastguard Worker }
208*8975f5c5SAndroid Build Coastguard Worker
209*8975f5c5SAndroid Build Coastguard Worker if (!mYuvOutputs.empty() && (mYuvOutputs.size() > 1 || mUsesFragDepth || !mOutputs.empty() ||
210*8975f5c5SAndroid Build Coastguard Worker !mUnspecifiedLocationOutputs.empty()))
211*8975f5c5SAndroid Build Coastguard Worker {
212*8975f5c5SAndroid Build Coastguard Worker for (const auto &symbol : mYuvOutputs)
213*8975f5c5SAndroid Build Coastguard Worker {
214*8975f5c5SAndroid Build Coastguard Worker error(*symbol,
215*8975f5c5SAndroid Build Coastguard Worker "not allowed to specify yuv qualifier when using depth or multiple color "
216*8975f5c5SAndroid Build Coastguard Worker "fragment outputs",
217*8975f5c5SAndroid Build Coastguard Worker diagnostics);
218*8975f5c5SAndroid Build Coastguard Worker }
219*8975f5c5SAndroid Build Coastguard Worker }
220*8975f5c5SAndroid Build Coastguard Worker }
221*8975f5c5SAndroid Build Coastguard Worker
222*8975f5c5SAndroid Build Coastguard Worker } // anonymous namespace
223*8975f5c5SAndroid Build Coastguard Worker
ValidateOutputs(TIntermBlock * root,const TExtensionBehavior & extBehavior,const ShBuiltInResources & resources,bool usesPixelLocalStorage,bool isWebGL,TDiagnostics * diagnostics)224*8975f5c5SAndroid Build Coastguard Worker bool ValidateOutputs(TIntermBlock *root,
225*8975f5c5SAndroid Build Coastguard Worker const TExtensionBehavior &extBehavior,
226*8975f5c5SAndroid Build Coastguard Worker const ShBuiltInResources &resources,
227*8975f5c5SAndroid Build Coastguard Worker bool usesPixelLocalStorage,
228*8975f5c5SAndroid Build Coastguard Worker bool isWebGL,
229*8975f5c5SAndroid Build Coastguard Worker TDiagnostics *diagnostics)
230*8975f5c5SAndroid Build Coastguard Worker {
231*8975f5c5SAndroid Build Coastguard Worker ValidateOutputsTraverser validateOutputs(extBehavior, resources, usesPixelLocalStorage,
232*8975f5c5SAndroid Build Coastguard Worker isWebGL);
233*8975f5c5SAndroid Build Coastguard Worker root->traverse(&validateOutputs);
234*8975f5c5SAndroid Build Coastguard Worker int numErrorsBefore = diagnostics->numErrors();
235*8975f5c5SAndroid Build Coastguard Worker validateOutputs.validate(diagnostics);
236*8975f5c5SAndroid Build Coastguard Worker return (diagnostics->numErrors() == numErrorsBefore);
237*8975f5c5SAndroid Build Coastguard Worker }
238*8975f5c5SAndroid Build Coastguard Worker
239*8975f5c5SAndroid Build Coastguard Worker } // namespace sh
240