| // |
| // Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| // |
| |
| #include "compiler/translator/ValidateOutputs.h" |
| #include "compiler/translator/InfoSink.h" |
| #include "compiler/translator/InitializeParseContext.h" |
| #include "compiler/translator/ParseContext.h" |
| |
| ValidateOutputs::ValidateOutputs(TInfoSinkBase& sink, int maxDrawBuffers) |
| : mSink(sink), |
| mMaxDrawBuffers(maxDrawBuffers), |
| mNumErrors(0), |
| mHasUnspecifiedOutputLocation(false) |
| { |
| } |
| |
| void ValidateOutputs::visitSymbol(TIntermSymbol *symbol) |
| { |
| TString name = symbol->getSymbol(); |
| TQualifier qualifier = symbol->getQualifier(); |
| |
| if (mVisitedSymbols.count(name) == 1) |
| return; |
| |
| mVisitedSymbols.insert(name); |
| |
| if (qualifier == EvqFragmentOut) |
| { |
| const TType &type = symbol->getType(); |
| const int location = type.getLayoutQualifier().location; |
| |
| if (mHasUnspecifiedOutputLocation) |
| { |
| error(symbol->getLine(), "must explicitly specify all locations when using multiple fragment outputs", name.c_str()); |
| } |
| else if (location == -1) |
| { |
| mHasUnspecifiedOutputLocation = true; |
| } |
| else |
| { |
| OutputMap::iterator mapEntry = mOutputMap.find(location); |
| if (mapEntry == mOutputMap.end()) |
| { |
| const int elementCount = type.isArray() ? type.getArraySize() : 1; |
| if (location + elementCount > mMaxDrawBuffers) |
| { |
| error(symbol->getLine(), "output location must be < MAX_DRAW_BUFFERS", name.c_str()); |
| } |
| |
| for (int elementIndex = 0; elementIndex < elementCount; elementIndex++) |
| { |
| const int offsetLocation = location + elementIndex; |
| mOutputMap[offsetLocation] = symbol; |
| } |
| } |
| else |
| { |
| std::stringstream strstr; |
| strstr << "conflicting output locations with previously defined output '" |
| << mapEntry->second->getSymbol() << "'"; |
| |
| error(symbol->getLine(), strstr.str().c_str(), name.c_str()); |
| } |
| } |
| } |
| } |
| |
| void ValidateOutputs::error(TSourceLoc loc, const char *reason, const char* token) |
| { |
| mSink.prefix(EPrefixError); |
| mSink.location(loc); |
| mSink << "'" << token << "' : " << reason << "\n"; |
| mNumErrors++; |
| } |