Commit 05a80ceb by Jamie Madill Committed by Shannon Woods

Validate fragment shader outputs and produce a compile error on missing or conflicting assignments.

TRAC #22704 Signed-off-by: Geoff Lang Signed-off-by: Nicolas Capens Authored-by: Jamie Madill
parent 975af378
......@@ -124,6 +124,8 @@
'compiler/util.h',
'compiler/ValidateLimitations.cpp',
'compiler/ValidateLimitations.h',
'compiler/ValidateOutput.cpp',
'compiler/ValidateOutput.h',
'compiler/VariableInfo.cpp',
'compiler/VariableInfo.h',
'compiler/VariablePacker.cpp',
......
......@@ -14,6 +14,7 @@
#include "compiler/RenameFunction.h"
#include "compiler/ShHandle.h"
#include "compiler/ValidateLimitations.h"
#include "compiler/ValidateOutputs.h"
#include "compiler/VariablePacker.h"
#include "compiler/depgraph/DependencyGraph.h"
#include "compiler/depgraph/DependencyGraphOutput.h"
......@@ -143,6 +144,9 @@ bool TCompiler::compile(const char* const shaderStrings[],
if (success)
success = detectRecursion(root);
if (success && shaderVersion == 300 && shaderType == SH_FRAGMENT_SHADER)
success = validateOutputs(root);
if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING))
success = validateLimitations(root);
......@@ -272,6 +276,13 @@ bool TCompiler::detectRecursion(TIntermNode* root)
}
}
bool TCompiler::validateOutputs(TIntermNode* root)
{
ValidateOutputs validateOutputs(infoSink.info, compileResources.MaxDrawBuffers);
root->traverse(&validateOutputs);
return (validateOutputs.numErrors() == 0);
}
void TCompiler::rewriteCSSShader(TIntermNode* root)
{
RenameFunction renamer("main(", "css_main(");
......
......@@ -2320,17 +2320,16 @@ TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierTyp
}
else
{
// must check that location is non-negative
if (intValue < 0)
{
error(intValueLine, "out of range", intValueString.c_str(), "value must be non-negative and < MAX_DRAW_BUFFERS");
error(intValueLine, "out of range:", intValueString.c_str(), "location must be non-negative");
recover();
}
else
{
qualifier.location = intValue;
}
// TODO: must check that location is < MAX_DRAW_BUFFERS
}
return qualifier;
......
......@@ -86,6 +86,8 @@ protected:
void clearResults();
// Return true if function recursion is detected.
bool detectRecursion(TIntermNode* root);
// Returns true if a program has no conflicting or missing fragment outputs
bool validateOutputs(TIntermNode* root);
// Rewrites a shader's intermediate tree according to the CSS Shaders spec.
void rewriteCSSShader(TIntermNode* root);
// Returns true if the given shader does not exceed the minimum
......
//
// 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/ValidateOutputs.h"
#include "compiler/InfoSink.h"
#include "compiler/InitializeParseContext.h"
#include "compiler/ParseHelper.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 == EvqFragmentOutput)
{
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++;
}
//
// 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 "GLSLANG/ShaderLang.h"
#include "compiler/intermediate.h"
#include <set>
class TInfoSinkBase;
class ValidateOutputs : public TIntermTraverser
{
public:
ValidateOutputs(TInfoSinkBase& sink, int maxDrawBuffers);
int numErrors() const { return mNumErrors; }
virtual void visitSymbol(TIntermSymbol*);
private:
TInfoSinkBase& mSink;
int mMaxDrawBuffers;
int mNumErrors;
bool mHasUnspecifiedOutputLocation;
typedef std::map<int, TIntermSymbol*> OutputMap;
OutputMap mOutputMap;
std::set<TString> mVisitedSymbols;
void error(TSourceLoc loc, const char *reason, const char* token);
};
......@@ -164,6 +164,7 @@
<ClCompile Include="SymbolTable.cpp" />
<ClCompile Include="util.cpp" />
<ClCompile Include="ValidateLimitations.cpp" />
<ClCompile Include="ValidateOutputs.cpp" />
<ClCompile Include="VariableInfo.cpp" />
<ClCompile Include="VariablePacker.cpp" />
<ClCompile Include="glslang_lex.cpp" />
......@@ -258,6 +259,7 @@
<ClInclude Include="Types.h" />
<ClInclude Include="util.h" />
<ClInclude Include="ValidateLimitations.h" />
<ClInclude Include="ValidateOutputs.h" />
<ClInclude Include="VariableInfo.h" />
<ClInclude Include="VariablePacker.h" />
<ClInclude Include="glslang_tab.h" />
......
......@@ -140,6 +140,9 @@
<ClCompile Include="..\common\utilities.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ValidateOutputs.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="BaseTypes.h">
......@@ -262,6 +265,9 @@
<ClInclude Include="..\third_party\compiler\ArrayBoundsClamper.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ValidateOutputs.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="glslang.l">
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment