Line data Source code
1 : //
2 : // Copyright (c) 2013 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 : #include "compiler/translator/ValidateOutputs.h"
8 : #include "compiler/translator/InfoSink.h"
9 : #include "compiler/translator/InitializeParseContext.h"
10 : #include "compiler/translator/ParseContext.h"
11 :
12 : namespace sh
13 : {
14 :
15 : namespace
16 : {
17 0 : void error(int *errorCount, TInfoSinkBase &sink, const TIntermSymbol &symbol, const char *reason)
18 : {
19 0 : sink.prefix(EPrefixError);
20 0 : sink.location(symbol.getLine());
21 0 : sink << "'" << symbol.getSymbol() << "' : " << reason << "\n";
22 0 : (*errorCount)++;
23 0 : }
24 :
25 : } // namespace
26 :
27 0 : ValidateOutputs::ValidateOutputs(const TExtensionBehavior &extBehavior, int maxDrawBuffers)
28 : : TIntermTraverser(true, false, false),
29 : mMaxDrawBuffers(maxDrawBuffers),
30 : mAllowUnspecifiedOutputLocationResolution(
31 0 : IsExtensionEnabled(extBehavior, "GL_EXT_blend_func_extended"))
32 : {
33 0 : }
34 :
35 0 : void ValidateOutputs::visitSymbol(TIntermSymbol *symbol)
36 : {
37 0 : TString name = symbol->getSymbol();
38 0 : TQualifier qualifier = symbol->getQualifier();
39 :
40 0 : if (mVisitedSymbols.count(name.c_str()) == 1)
41 0 : return;
42 :
43 0 : mVisitedSymbols.insert(name.c_str());
44 :
45 0 : if (qualifier == EvqFragmentOut)
46 : {
47 0 : if (symbol->getType().getLayoutQualifier().location == -1)
48 : {
49 0 : mUnspecifiedLocationOutputs.push_back(symbol);
50 : }
51 : else
52 : {
53 0 : mOutputs.push_back(symbol);
54 : }
55 : }
56 : }
57 :
58 0 : int ValidateOutputs::validateAndCountErrors(TInfoSinkBase &sink) const
59 : {
60 0 : OutputVector validOutputs(mMaxDrawBuffers);
61 0 : int errorCount = 0;
62 :
63 0 : for (const auto &symbol : mOutputs)
64 : {
65 0 : const TType &type = symbol->getType();
66 0 : const size_t elementCount = static_cast<size_t>(type.isArray() ? type.getArraySize() : 1u);
67 0 : const size_t location = static_cast<size_t>(type.getLayoutQualifier().location);
68 :
69 0 : ASSERT(type.getLayoutQualifier().location != -1);
70 :
71 0 : if (location + elementCount <= validOutputs.size())
72 : {
73 0 : for (size_t elementIndex = 0; elementIndex < elementCount; elementIndex++)
74 : {
75 0 : const size_t offsetLocation = location + elementIndex;
76 0 : if (validOutputs[offsetLocation])
77 : {
78 0 : std::stringstream strstr;
79 : strstr << "conflicting output locations with previously defined output '"
80 0 : << validOutputs[offsetLocation]->getSymbol() << "'";
81 0 : error(&errorCount, sink, *symbol, strstr.str().c_str());
82 : }
83 : else
84 : {
85 0 : validOutputs[offsetLocation] = symbol;
86 : }
87 : }
88 : }
89 : else
90 : {
91 0 : if (elementCount > 0)
92 : {
93 0 : error(&errorCount, sink, *symbol,
94 : elementCount > 1 ? "output array locations would exceed MAX_DRAW_BUFFERS"
95 0 : : "output location must be < MAX_DRAW_BUFFERS");
96 : }
97 : }
98 : }
99 :
100 0 : if (!mAllowUnspecifiedOutputLocationResolution &&
101 0 : ((!mOutputs.empty() && !mUnspecifiedLocationOutputs.empty()) ||
102 0 : mUnspecifiedLocationOutputs.size() > 1))
103 : {
104 0 : for (const auto &symbol : mUnspecifiedLocationOutputs)
105 : {
106 0 : error(&errorCount, sink, *symbol,
107 0 : "must explicitly specify all locations when using multiple fragment outputs");
108 : }
109 : }
110 0 : return errorCount;
111 : }
112 :
113 : } // namespace sh
|