xref: /aosp_15_r20/external/angle/src/compiler/translator/ValidateOutputs.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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