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
12ValidateOutputs::ValidateOutputs(TInfoSinkBase& sink, int maxDrawBuffers)
13    : mSink(sink),
14      mMaxDrawBuffers(maxDrawBuffers),
15      mNumErrors(0),
16      mHasUnspecifiedOutputLocation(false)
17{
18}
19
20void ValidateOutputs::visitSymbol(TIntermSymbol *symbol)
21{
22    TString name = symbol->getSymbol();
23    TQualifier qualifier = symbol->getQualifier();
24
25    if (mVisitedSymbols.count(name) == 1)
26        return;
27
28    mVisitedSymbols.insert(name);
29
30    if (qualifier == EvqFragmentOut)
31    {
32        const TType &type = symbol->getType();
33        const int location = type.getLayoutQualifier().location;
34
35        if (mHasUnspecifiedOutputLocation)
36        {
37            error(symbol->getLine(), "must explicitly specify all locations when using multiple fragment outputs", name.c_str());
38        }
39        else if (location == -1)
40        {
41            mHasUnspecifiedOutputLocation = true;
42        }
43        else
44        {
45            OutputMap::iterator mapEntry = mOutputMap.find(location);
46            if (mapEntry == mOutputMap.end())
47            {
48                const int elementCount = type.isArray() ? type.getArraySize() : 1;
49                if (location + elementCount > mMaxDrawBuffers)
50                {
51                    error(symbol->getLine(), "output location must be < MAX_DRAW_BUFFERS", name.c_str());
52                }
53
54                for (int elementIndex = 0; elementIndex < elementCount; elementIndex++)
55                {
56                    const int offsetLocation = location + elementIndex;
57                    mOutputMap[offsetLocation] = symbol;
58                }
59            }
60            else
61            {
62                std::stringstream strstr;
63                strstr << "conflicting output locations with previously defined output '"
64                       << mapEntry->second->getSymbol() << "'";
65
66                error(symbol->getLine(), strstr.str().c_str(), name.c_str());
67            }
68        }
69    }
70}
71
72void ValidateOutputs::error(TSourceLoc loc, const char *reason, const char* token)
73{
74    mSink.prefix(EPrefixError);
75    mSink.location(loc);
76    mSink << "'" << token << "' : " << reason << "\n";
77    mNumErrors++;
78}
79