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