Commit 94ac7b78 by Zhenyao Mo

Invariant related processing.

* Fix a bug in PreProcessor for STDGL pragma. * Record all invariant settings and set them in ShaderVariable. * Write #pragma STDGL invariant(all) in GL BUG=angle:776 TEST=https://www.khronos.org/registry/webgl/sdk/tests/conformance/glsl/misc/shaders-with-invariance.html Change-Id: Ie28b75480deed79f0c9f26e3b98f1778d1290182 Reviewed-on: https://chromium-review.googlesource.com/223610Tested-by: 's avatarZhenyao Mo <zmo@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent f99b0cff
...@@ -29,7 +29,8 @@ class DirectiveHandler ...@@ -29,7 +29,8 @@ class DirectiveHandler
// Handle pragma of form: #pragma name[(value)] // Handle pragma of form: #pragma name[(value)]
virtual void handlePragma(const SourceLocation &loc, virtual void handlePragma(const SourceLocation &loc,
const std::string &name, const std::string &name,
const std::string &value) = 0; const std::string &value,
bool stdgl) = 0;
virtual void handleExtension(const SourceLocation &loc, virtual void handleExtension(const SourceLocation &loc,
const std::string &name, const std::string &name,
......
...@@ -592,6 +592,11 @@ void DirectiveParser::parsePragma(Token *token) ...@@ -592,6 +592,11 @@ void DirectiveParser::parsePragma(Token *token)
int state = PRAGMA_NAME; int state = PRAGMA_NAME;
mTokenizer->lex(token); mTokenizer->lex(token);
bool stdgl = token->text == "STDGL";
if (stdgl)
{
mTokenizer->lex(token);
}
while ((token->type != '\n') && (token->type != Token::LAST)) while ((token->type != '\n') && (token->type != Token::LAST))
{ {
switch(state++) switch(state++)
...@@ -627,7 +632,7 @@ void DirectiveParser::parsePragma(Token *token) ...@@ -627,7 +632,7 @@ void DirectiveParser::parsePragma(Token *token)
} }
else if (state > PRAGMA_NAME) // Do not notify for empty pragma. else if (state > PRAGMA_NAME) // Do not notify for empty pragma.
{ {
mDirectiveHandler->handlePragma(token->location, name, value); mDirectiveHandler->handlePragma(token->location, name, value, stdgl);
} }
} }
......
...@@ -181,6 +181,12 @@ bool TCompiler::compile(const char* const shaderStrings[], ...@@ -181,6 +181,12 @@ bool TCompiler::compile(const char* const shaderStrings[],
if (success) if (success)
{ {
mPragma = parseContext.pragma();
if (mPragma.stdgl.invariantAll)
{
symbolTable.setGlobalInvariant();
}
TIntermNode* root = parseContext.treeRoot; TIntermNode* root = parseContext.treeRoot;
success = intermediate.postProcess(root); success = intermediate.postProcess(root);
...@@ -508,7 +514,8 @@ void TCompiler::collectVariables(TIntermNode* root) ...@@ -508,7 +514,8 @@ void TCompiler::collectVariables(TIntermNode* root)
&uniforms, &uniforms,
&varyings, &varyings,
&interfaceBlocks, &interfaceBlocks,
hashFunction); hashFunction,
symbolTable);
root->traverse(&collect); root->traverse(&collect);
// For backwards compatiblity with ShGetVariableInfo, expand struct // For backwards compatiblity with ShGetVariableInfo, expand struct
...@@ -582,3 +589,10 @@ const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const ...@@ -582,3 +589,10 @@ const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const
{ {
return builtInFunctionEmulator; return builtInFunctionEmulator;
} }
void TCompiler::writePragma()
{
TInfoSinkBase &sink = infoSink.obj;
if (mPragma.stdgl.invariantAll)
sink << "#pragma STDGL invariant(all)\n";
}
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "compiler/translator/ExtensionBehavior.h" #include "compiler/translator/ExtensionBehavior.h"
#include "compiler/translator/HashNames.h" #include "compiler/translator/HashNames.h"
#include "compiler/translator/InfoSink.h" #include "compiler/translator/InfoSink.h"
#include "compiler/translator/Pragma.h"
#include "compiler/translator/SymbolTable.h" #include "compiler/translator/SymbolTable.h"
#include "compiler/translator/VariableInfo.h" #include "compiler/translator/VariableInfo.h"
#include "third_party/compiler/ArrayBoundsClamper.h" #include "third_party/compiler/ArrayBoundsClamper.h"
...@@ -131,6 +132,8 @@ class TCompiler : public TShHandleBase ...@@ -131,6 +132,8 @@ class TCompiler : public TShHandleBase
bool limitExpressionComplexity(TIntermNode* root); bool limitExpressionComplexity(TIntermNode* root);
// Get built-in extensions with default behavior. // Get built-in extensions with default behavior.
const TExtensionBehavior& getExtensionBehavior() const; const TExtensionBehavior& getExtensionBehavior() const;
const TPragma& getPragma() const { return mPragma; }
void writePragma();
const ArrayBoundsClamper& getArrayBoundsClamper() const; const ArrayBoundsClamper& getArrayBoundsClamper() const;
ShArrayIndexClampingStrategy getArrayIndexClampingStrategy() const; ShArrayIndexClampingStrategy getArrayIndexClampingStrategy() const;
...@@ -174,6 +177,8 @@ class TCompiler : public TShHandleBase ...@@ -174,6 +177,8 @@ class TCompiler : public TShHandleBase
// name hashing. // name hashing.
ShHashFunction64 hashFunction; ShHashFunction64 hashFunction;
NameMap nameMap; NameMap nameMap;
TPragma mPragma;
}; };
// //
......
...@@ -13,10 +13,10 @@ ...@@ -13,10 +13,10 @@
static TBehavior getBehavior(const std::string& str) static TBehavior getBehavior(const std::string& str)
{ {
static const std::string kRequire("require"); const char kRequire[] = "require";
static const std::string kEnable("enable"); const char kEnable[] = "enable";
static const std::string kDisable("disable"); const char kDisable[] = "disable";
static const std::string kWarn("warn"); const char kWarn[] = "warn";
if (str == kRequire) return EBhRequire; if (str == kRequire) return EBhRequire;
else if (str == kEnable) return EBhEnable; else if (str == kEnable) return EBhEnable;
...@@ -46,50 +46,61 @@ void TDirectiveHandler::handleError(const pp::SourceLocation& loc, ...@@ -46,50 +46,61 @@ void TDirectiveHandler::handleError(const pp::SourceLocation& loc,
void TDirectiveHandler::handlePragma(const pp::SourceLocation& loc, void TDirectiveHandler::handlePragma(const pp::SourceLocation& loc,
const std::string& name, const std::string& name,
const std::string& value) const std::string& value,
bool stdgl)
{ {
static const std::string kSTDGL("STDGL"); if (stdgl)
static const std::string kOptimize("optimize");
static const std::string kDebug("debug");
static const std::string kOn("on");
static const std::string kOff("off");
bool invalidValue = false;
if (name == kSTDGL)
{ {
const char kInvariant[] = "invariant";
const char kAll[] = "all";
if (name == kInvariant && value == kAll)
mPragma.stdgl.invariantAll = true;
// The STDGL pragma is used to reserve pragmas for use by future // The STDGL pragma is used to reserve pragmas for use by future
// revisions of GLSL. Ignore it. // revisions of GLSL. Do not generate an error on unexpected
// name and value.
return; return;
} }
else if (name == kOptimize)
{
if (value == kOn) mPragma.optimize = true;
else if (value == kOff) mPragma.optimize = false;
else invalidValue = true;
}
else if (name == kDebug)
{
if (value == kOn) mPragma.debug = true;
else if (value == kOff) mPragma.debug = false;
else invalidValue = true;
}
else else
{ {
mDiagnostics.report(pp::Diagnostics::PP_UNRECOGNIZED_PRAGMA, loc, name); const char kOptimize[] = "optimize";
return; const char kDebug[] = "debug";
} const char kOn[] = "on";
const char kOff[] = "off";
if (invalidValue) bool invalidValue = false;
mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc, if (name == kOptimize)
"invalid pragma value", value, {
"'on' or 'off' expected"); if (value == kOn) mPragma.optimize = true;
else if (value == kOff) mPragma.optimize = false;
else invalidValue = true;
}
else if (name == kDebug)
{
if (value == kOn) mPragma.debug = true;
else if (value == kOff) mPragma.debug = false;
else invalidValue = true;
}
else
{
mDiagnostics.report(pp::Diagnostics::PP_UNRECOGNIZED_PRAGMA, loc, name);
return;
}
if (invalidValue)
{
mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc,
"invalid pragma value", value,
"'on' or 'off' expected");
}
}
} }
void TDirectiveHandler::handleExtension(const pp::SourceLocation& loc, void TDirectiveHandler::handleExtension(const pp::SourceLocation& loc,
const std::string& name, const std::string& name,
const std::string& behavior) const std::string& behavior)
{ {
static const std::string kExtAll("all"); const char kExtAll[] = "all";
TBehavior behaviorVal = getBehavior(behavior); TBehavior behaviorVal = getBehavior(behavior);
if (behaviorVal == EBhUndefined) if (behaviorVal == EBhUndefined)
......
...@@ -29,7 +29,8 @@ class TDirectiveHandler : public pp::DirectiveHandler ...@@ -29,7 +29,8 @@ class TDirectiveHandler : public pp::DirectiveHandler
virtual void handlePragma(const pp::SourceLocation& loc, virtual void handlePragma(const pp::SourceLocation& loc,
const std::string& name, const std::string& name,
const std::string& value); const std::string& value,
bool stdgl);
virtual void handleExtension(const pp::SourceLocation& loc, virtual void handleExtension(const pp::SourceLocation& loc,
const std::string& name, const std::string& name,
......
...@@ -650,17 +650,18 @@ bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node) ...@@ -650,17 +650,18 @@ bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
mDeclaringVariables = false; mDeclaringVariables = false;
} }
break; break;
case EOpInvariantDeclaration: { case EOpInvariantDeclaration:
// Invariant declaration. // Invariant declaration.
ASSERT(visit == PreVisit); ASSERT(visit == PreVisit);
{
const TIntermSequence *sequence = node->getSequence(); const TIntermSequence *sequence = node->getSequence();
ASSERT(sequence && sequence->size() == 1); ASSERT(sequence && sequence->size() == 1);
const TIntermSymbol *symbol = sequence->front()->getAsSymbolNode(); const TIntermSymbol *symbol = sequence->front()->getAsSymbolNode();
ASSERT(symbol); ASSERT(symbol);
out << "invariant " << symbol->getSymbol() << ";"; out << "invariant " << hashVariableName(symbol->getSymbol()) << ";";
visitChildren = false;
break;
} }
visitChildren = false;
break;
case EOpConstructFloat: case EOpConstructFloat:
writeTriplet(visit, "float(", NULL, ")"); writeTriplet(visit, "float(", NULL, ")");
break; break;
......
...@@ -1004,12 +1004,12 @@ void TParseContext::handleExtensionDirective(const TSourceLoc& loc, const char* ...@@ -1004,12 +1004,12 @@ void TParseContext::handleExtensionDirective(const TSourceLoc& loc, const char*
directiveHandler.handleExtension(srcLoc, extName, behavior); directiveHandler.handleExtension(srcLoc, extName, behavior);
} }
void TParseContext::handlePragmaDirective(const TSourceLoc& loc, const char* name, const char* value) void TParseContext::handlePragmaDirective(const TSourceLoc& loc, const char* name, const char* value, bool stdgl)
{ {
pp::SourceLocation srcLoc; pp::SourceLocation srcLoc;
srcLoc.file = loc.first_file; srcLoc.file = loc.first_file;
srcLoc.line = loc.first_line; srcLoc.line = loc.first_line;
directiveHandler.handlePragma(srcLoc, name, value); directiveHandler.handlePragma(srcLoc, name, value, stdgl);
} }
///////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////
...@@ -1364,11 +1364,18 @@ TIntermAggregate* TParseContext::parseInvariantDeclaration(const TSourceLoc &inv ...@@ -1364,11 +1364,18 @@ TIntermAggregate* TParseContext::parseInvariantDeclaration(const TSourceLoc &inv
{ {
error(identifierLoc, "undeclared identifier declared as invariant", identifier->c_str()); error(identifierLoc, "undeclared identifier declared as invariant", identifier->c_str());
recover(); recover();
return NULL; return NULL;
} }
else else
{ {
const TString kGlFrontFacing("gl_FrontFacing");
if (*identifier == kGlFrontFacing)
{
error(identifierLoc, "identifier should not be declared as invariant", identifier->c_str());
recover();
return NULL;
}
symbolTable.addInvariantVarying(*identifier);
const TVariable *variable = getNamedVariable(identifierLoc, identifier, symbol); const TVariable *variable = getNamedVariable(identifierLoc, identifier, symbol);
ASSERT(variable); ASSERT(variable);
const TType &type = variable->getType(); const TType &type = variable->getType();
......
...@@ -116,7 +116,7 @@ struct TParseContext { ...@@ -116,7 +116,7 @@ struct TParseContext {
bool supportsExtension(const char* extension); bool supportsExtension(const char* extension);
bool isExtensionEnabled(const char* extension) const; bool isExtensionEnabled(const char* extension) const;
void handleExtensionDirective(const TSourceLoc& loc, const char* extName, const char* behavior); void handleExtensionDirective(const TSourceLoc& loc, const char* extName, const char* behavior);
void handlePragmaDirective(const TSourceLoc& loc, const char* name, const char* value); void handlePragmaDirective(const TSourceLoc& loc, const char* name, const char* value, bool stdgl);
bool containsSampler(TType& type); bool containsSampler(TType& type);
bool areAllChildConst(TIntermAggregate* aggrNode); bool areAllChildConst(TIntermAggregate* aggrNode);
......
...@@ -7,13 +7,23 @@ ...@@ -7,13 +7,23 @@
#ifndef COMPILER_PRAGMA_H_ #ifndef COMPILER_PRAGMA_H_
#define COMPILER_PRAGMA_H_ #define COMPILER_PRAGMA_H_
struct TPragma { struct TPragma
{
struct STDGL
{
STDGL() : invariantAll(false) { }
bool invariantAll;
};
// By default optimization is turned on and debug is turned off. // By default optimization is turned on and debug is turned off.
TPragma() : optimize(true), debug(false) { } TPragma() : optimize(true), debug(false) { }
TPragma(bool o, bool d) : optimize(o), debug(d) { } TPragma(bool o, bool d) : optimize(o), debug(d) { }
bool optimize; bool optimize;
bool debug; bool debug;
STDGL stdgl;
}; };
#endif // COMPILER_PRAGMA_H_ #endif // COMPILER_PRAGMA_H_
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
// //
#include <assert.h> #include <assert.h>
#include <set>
#include "common/angleutils.h" #include "common/angleutils.h"
#include "compiler/translator/InfoSink.h" #include "compiler/translator/InfoSink.h"
...@@ -313,6 +314,7 @@ class TSymbolTable ...@@ -313,6 +314,7 @@ class TSymbolTable
{ {
public: public:
TSymbolTable() TSymbolTable()
: mGlobalInvariant(false)
{ {
// The symbol table cannot be used until push() is called, but // The symbol table cannot be used until push() is called, but
// the lack of an initial call to push() can be used to detect // the lack of an initial call to push() can be used to detect
...@@ -409,6 +411,25 @@ class TSymbolTable ...@@ -409,6 +411,25 @@ class TSymbolTable
// for the specified TBasicType // for the specified TBasicType
TPrecision getDefaultPrecision(TBasicType type) const; TPrecision getDefaultPrecision(TBasicType type) const;
// This records invariant varyings declared through
// "invariant varying_name;".
void addInvariantVarying(const TString &originalName)
{
mInvariantVaryings.insert(originalName);
}
// If this returns false, the varying could still be invariant
// if it is set as invariant during the varying variable
// declaration - this piece of information is stored in the
// variable's type, not here.
bool isVaryingInvariant(const TString &originalName) const
{
return (mGlobalInvariant ||
mInvariantVaryings.count(originalName) > 0);
}
void setGlobalInvariant() { mGlobalInvariant = true; }
bool getGlobalInvariant() const { return mGlobalInvariant; }
static int nextUniqueId() static int nextUniqueId()
{ {
return ++uniqueIdCounter; return ++uniqueIdCounter;
...@@ -424,6 +445,9 @@ class TSymbolTable ...@@ -424,6 +445,9 @@ class TSymbolTable
typedef TMap<TBasicType, TPrecision> PrecisionStackLevel; typedef TMap<TBasicType, TPrecision> PrecisionStackLevel;
std::vector< PrecisionStackLevel *> precisionStack; std::vector< PrecisionStackLevel *> precisionStack;
std::set<TString> mInvariantVaryings;
bool mGlobalInvariant;
static int uniqueIdCounter; static int uniqueIdCounter;
}; };
......
...@@ -16,6 +16,8 @@ TranslatorESSL::TranslatorESSL(sh::GLenum type, ShShaderSpec spec) ...@@ -16,6 +16,8 @@ TranslatorESSL::TranslatorESSL(sh::GLenum type, ShShaderSpec spec)
void TranslatorESSL::translate(TIntermNode* root) { void TranslatorESSL::translate(TIntermNode* root) {
TInfoSinkBase& sink = getInfoSink().obj; TInfoSinkBase& sink = getInfoSink().obj;
writePragma();
// Write built-in extension behaviors. // Write built-in extension behaviors.
writeExtensionBehavior(); writeExtensionBehavior();
......
...@@ -9,18 +9,6 @@ ...@@ -9,18 +9,6 @@
#include "compiler/translator/OutputGLSL.h" #include "compiler/translator/OutputGLSL.h"
#include "compiler/translator/VersionGLSL.h" #include "compiler/translator/VersionGLSL.h"
static void writeVersion(sh::GLenum type, TIntermNode* root,
TInfoSinkBase& sink) {
TVersionGLSL versionGLSL(type);
root->traverse(&versionGLSL);
int version = versionGLSL.getVersion();
// We need to write version directive only if it is greater than 110.
// If there is no version directive in the shader, 110 is implied.
if (version > 110) {
sink << "#version " << version << "\n";
}
}
TranslatorGLSL::TranslatorGLSL(sh::GLenum type, ShShaderSpec spec) TranslatorGLSL::TranslatorGLSL(sh::GLenum type, ShShaderSpec spec)
: TCompiler(type, spec, SH_GLSL_OUTPUT) { : TCompiler(type, spec, SH_GLSL_OUTPUT) {
} }
...@@ -29,7 +17,9 @@ void TranslatorGLSL::translate(TIntermNode* root) { ...@@ -29,7 +17,9 @@ void TranslatorGLSL::translate(TIntermNode* root) {
TInfoSinkBase& sink = getInfoSink().obj; TInfoSinkBase& sink = getInfoSink().obj;
// Write GLSL version. // Write GLSL version.
writeVersion(getShaderType(), root, sink); writeVersion(root);
writePragma();
// Write extension behaviour as needed // Write extension behaviour as needed
writeExtensionBehavior(); writeExtensionBehavior();
...@@ -46,6 +36,20 @@ void TranslatorGLSL::translate(TIntermNode* root) { ...@@ -46,6 +36,20 @@ void TranslatorGLSL::translate(TIntermNode* root) {
root->traverse(&outputGLSL); root->traverse(&outputGLSL);
} }
void TranslatorGLSL::writeVersion(TIntermNode *root)
{
TVersionGLSL versionGLSL(getShaderType(), getPragma());
root->traverse(&versionGLSL);
int version = versionGLSL.getVersion();
// We need to write version directive only if it is greater than 110.
// If there is no version directive in the shader, 110 is implied.
if (version > 110)
{
TInfoSinkBase& sink = getInfoSink().obj;
sink << "#version " << version << "\n";
}
}
void TranslatorGLSL::writeExtensionBehavior() { void TranslatorGLSL::writeExtensionBehavior() {
TInfoSinkBase& sink = getInfoSink().obj; TInfoSinkBase& sink = getInfoSink().obj;
const TExtensionBehavior& extensionBehavior = getExtensionBehavior(); const TExtensionBehavior& extensionBehavior = getExtensionBehavior();
......
...@@ -9,14 +9,16 @@ ...@@ -9,14 +9,16 @@
#include "compiler/translator/Compiler.h" #include "compiler/translator/Compiler.h"
class TranslatorGLSL : public TCompiler { class TranslatorGLSL : public TCompiler
public: {
public:
TranslatorGLSL(sh::GLenum type, ShShaderSpec spec); TranslatorGLSL(sh::GLenum type, ShShaderSpec spec);
protected: protected:
virtual void translate(TIntermNode* root); virtual void translate(TIntermNode *root);
private: private:
void writeVersion(TIntermNode *root);
void writeExtensionBehavior(); void writeExtensionBehavior();
}; };
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
// //
#include "angle_gl.h" #include "angle_gl.h"
#include "compiler/translator/SymbolTable.h"
#include "compiler/translator/VariableInfo.h" #include "compiler/translator/VariableInfo.h"
#include "compiler/translator/util.h" #include "compiler/translator/util.h"
#include "common/utilities.h" #include "common/utilities.h"
...@@ -131,7 +132,8 @@ CollectVariables::CollectVariables(std::vector<sh::Attribute> *attribs, ...@@ -131,7 +132,8 @@ CollectVariables::CollectVariables(std::vector<sh::Attribute> *attribs,
std::vector<sh::Uniform> *uniforms, std::vector<sh::Uniform> *uniforms,
std::vector<sh::Varying> *varyings, std::vector<sh::Varying> *varyings,
std::vector<sh::InterfaceBlock> *interfaceBlocks, std::vector<sh::InterfaceBlock> *interfaceBlocks,
ShHashFunction64 hashFunction) ShHashFunction64 hashFunction,
const TSymbolTable &symbolTable)
: mAttribs(attribs), : mAttribs(attribs),
mOutputVariables(outputVariables), mOutputVariables(outputVariables),
mUniforms(uniforms), mUniforms(uniforms),
...@@ -140,7 +142,10 @@ CollectVariables::CollectVariables(std::vector<sh::Attribute> *attribs, ...@@ -140,7 +142,10 @@ CollectVariables::CollectVariables(std::vector<sh::Attribute> *attribs,
mPointCoordAdded(false), mPointCoordAdded(false),
mFrontFacingAdded(false), mFrontFacingAdded(false),
mFragCoordAdded(false), mFragCoordAdded(false),
mHashFunction(hashFunction) mPositionAdded(false),
mPointSizeAdded(false),
mHashFunction(hashFunction),
mSymbolTable(symbolTable)
{ {
} }
...@@ -200,12 +205,14 @@ void CollectVariables::visitSymbol(TIntermSymbol *symbol) ...@@ -200,12 +205,14 @@ void CollectVariables::visitSymbol(TIntermSymbol *symbol)
if (!mFragCoordAdded) if (!mFragCoordAdded)
{ {
Varying info; Varying info;
info.name = "gl_FragCoord"; const char kName[] = "gl_FragCoord";
info.mappedName = "gl_FragCoord"; info.name = kName;
info.mappedName = kName;
info.type = GL_FLOAT_VEC4; info.type = GL_FLOAT_VEC4;
info.arraySize = 0; info.arraySize = 0;
info.precision = GL_MEDIUM_FLOAT; // Use mediump as it doesn't really matter. info.precision = GL_MEDIUM_FLOAT; // Defined by spec.
info.staticUse = true; info.staticUse = true;
info.isInvariant = mSymbolTable.isVaryingInvariant(kName);
mVaryings->push_back(info); mVaryings->push_back(info);
mFragCoordAdded = true; mFragCoordAdded = true;
} }
...@@ -214,12 +221,14 @@ void CollectVariables::visitSymbol(TIntermSymbol *symbol) ...@@ -214,12 +221,14 @@ void CollectVariables::visitSymbol(TIntermSymbol *symbol)
if (!mFrontFacingAdded) if (!mFrontFacingAdded)
{ {
Varying info; Varying info;
info.name = "gl_FrontFacing"; const char kName[] = "gl_FrontFacing";
info.mappedName = "gl_FrontFacing"; info.name = kName;
info.mappedName = kName;
info.type = GL_BOOL; info.type = GL_BOOL;
info.arraySize = 0; info.arraySize = 0;
info.precision = GL_NONE; info.precision = GL_NONE;
info.staticUse = true; info.staticUse = true;
info.isInvariant = mSymbolTable.isVaryingInvariant(kName);
mVaryings->push_back(info); mVaryings->push_back(info);
mFrontFacingAdded = true; mFrontFacingAdded = true;
} }
...@@ -228,16 +237,50 @@ void CollectVariables::visitSymbol(TIntermSymbol *symbol) ...@@ -228,16 +237,50 @@ void CollectVariables::visitSymbol(TIntermSymbol *symbol)
if (!mPointCoordAdded) if (!mPointCoordAdded)
{ {
Varying info; Varying info;
info.name = "gl_PointCoord"; const char kName[] = "gl_PointCoord";
info.mappedName = "gl_PointCoord"; info.name = kName;
info.mappedName = kName;
info.type = GL_FLOAT_VEC2; info.type = GL_FLOAT_VEC2;
info.arraySize = 0; info.arraySize = 0;
info.precision = GL_MEDIUM_FLOAT; // Use mediump as it doesn't really matter. info.precision = GL_MEDIUM_FLOAT; // Defined by spec.
info.staticUse = true; info.staticUse = true;
info.isInvariant = mSymbolTable.isVaryingInvariant(kName);
mVaryings->push_back(info); mVaryings->push_back(info);
mPointCoordAdded = true; mPointCoordAdded = true;
} }
return; return;
case EvqPosition:
if (!mPositionAdded)
{
Varying info;
const char kName[] = "gl_Position";
info.name = kName;
info.mappedName = kName;
info.type = GL_FLOAT_VEC4;
info.arraySize = 0;
info.precision = GL_HIGH_FLOAT; // Defined by spec.
info.staticUse = true;
info.isInvariant = mSymbolTable.isVaryingInvariant(kName);
mVaryings->push_back(info);
mPositionAdded = true;
}
return;
case EvqPointSize:
if (!mPointSizeAdded)
{
Varying info;
const char kName[] = "gl_PointSize";
info.name = kName;
info.mappedName = kName;
info.type = GL_FLOAT;
info.arraySize = 0;
info.precision = GL_MEDIUM_FLOAT; // Defined by spec.
info.staticUse = true;
info.isInvariant = mSymbolTable.isVaryingInvariant(kName);
mVaryings->push_back(info);
mPointSizeAdded = true;
}
return;
default: default:
break; break;
} }
...@@ -251,8 +294,10 @@ void CollectVariables::visitSymbol(TIntermSymbol *symbol) ...@@ -251,8 +294,10 @@ void CollectVariables::visitSymbol(TIntermSymbol *symbol)
class NameHashingTraverser : public GetVariableTraverser class NameHashingTraverser : public GetVariableTraverser
{ {
public: public:
NameHashingTraverser(ShHashFunction64 hashFunction) NameHashingTraverser(ShHashFunction64 hashFunction,
: mHashFunction(hashFunction) const TSymbolTable &symbolTable)
: GetVariableTraverser(symbolTable),
mHashFunction(hashFunction)
{} {}
private: private:
...@@ -312,7 +357,7 @@ void CollectVariables::visitVariable(const TIntermSymbol *variable, ...@@ -312,7 +357,7 @@ void CollectVariables::visitVariable(const TIntermSymbol *variable,
const TString &fullFieldName = InterfaceBlockFieldName(*blockType, field); const TString &fullFieldName = InterfaceBlockFieldName(*blockType, field);
const TType &fieldType = *field.type(); const TType &fieldType = *field.type();
GetVariableTraverser traverser; GetVariableTraverser traverser(mSymbolTable);
traverser.traverse(fieldType, fullFieldName, &interfaceBlock.fields); traverser.traverse(fieldType, fullFieldName, &interfaceBlock.fields);
interfaceBlock.fields.back().isRowMajorLayout = (fieldType.getLayoutQualifier().matrixPacking == EmpRowMajor); interfaceBlock.fields.back().isRowMajorLayout = (fieldType.getLayoutQualifier().matrixPacking == EmpRowMajor);
...@@ -325,7 +370,7 @@ template <typename VarT> ...@@ -325,7 +370,7 @@ template <typename VarT>
void CollectVariables::visitVariable(const TIntermSymbol *variable, void CollectVariables::visitVariable(const TIntermSymbol *variable,
std::vector<VarT> *infoList) const std::vector<VarT> *infoList) const
{ {
NameHashingTraverser traverser(mHashFunction); NameHashingTraverser traverser(mHashFunction, mSymbolTable);
traverser.traverse(variable->getType(), variable->getSymbol(), infoList); traverser.traverse(variable->getType(), variable->getSymbol(), infoList);
} }
......
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
#include "compiler/translator/IntermNode.h" #include "compiler/translator/IntermNode.h"
class TSymbolTable;
namespace sh namespace sh
{ {
...@@ -23,7 +25,8 @@ class CollectVariables : public TIntermTraverser ...@@ -23,7 +25,8 @@ class CollectVariables : public TIntermTraverser
std::vector<Uniform> *uniforms, std::vector<Uniform> *uniforms,
std::vector<Varying> *varyings, std::vector<Varying> *varyings,
std::vector<InterfaceBlock> *interfaceBlocks, std::vector<InterfaceBlock> *interfaceBlocks,
ShHashFunction64 hashFunction); ShHashFunction64 hashFunction,
const TSymbolTable &symbolTable);
virtual void visitSymbol(TIntermSymbol *symbol); virtual void visitSymbol(TIntermSymbol *symbol);
virtual bool visitAggregate(Visit, TIntermAggregate *node); virtual bool visitAggregate(Visit, TIntermAggregate *node);
...@@ -48,7 +51,12 @@ class CollectVariables : public TIntermTraverser ...@@ -48,7 +51,12 @@ class CollectVariables : public TIntermTraverser
bool mFrontFacingAdded; bool mFrontFacingAdded;
bool mFragCoordAdded; bool mFragCoordAdded;
bool mPositionAdded;
bool mPointSizeAdded;
ShHashFunction64 mHashFunction; ShHashFunction64 mHashFunction;
const TSymbolTable &mSymbolTable;
}; };
// Expand struct variables to flattened lists of split variables // Expand struct variables to flattened lists of split variables
......
...@@ -26,18 +26,12 @@ static const int GLSL_VERSION_120 = 120; ...@@ -26,18 +26,12 @@ static const int GLSL_VERSION_120 = 120;
// GLSL 1.2 relaxed the restriction on arrays, section 5.8: "Variables that // GLSL 1.2 relaxed the restriction on arrays, section 5.8: "Variables that
// are built-in types, entire structures or arrays... are all l-values." // are built-in types, entire structures or arrays... are all l-values."
// //
// TODO(alokp): The following two cases of invariant decalaration get lost TVersionGLSL::TVersionGLSL(sh::GLenum type, const TPragma &pragma)
// during parsing - they do not get carried over to the intermediate tree.
// Handle these cases:
// 1. When a pragma is used to force all output variables to be invariant:
// - #pragma STDGL invariant(all)
// 2. When a previously decalared or built-in variable is marked invariant:
// - invariant gl_Position;
// - varying vec3 color; invariant color;
//
TVersionGLSL::TVersionGLSL(sh::GLenum type)
: mVersion(GLSL_VERSION_110)
{ {
if (pragma.stdgl.invariantAll)
mVersion = GLSL_VERSION_120;
else
mVersion = GLSL_VERSION_110;
} }
void TVersionGLSL::visitSymbol(TIntermSymbol *node) void TVersionGLSL::visitSymbol(TIntermSymbol *node)
......
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
#include "compiler/translator/IntermNode.h" #include "compiler/translator/IntermNode.h"
#include "compiler/translator/Pragma.h"
// Traverses the intermediate tree to return the minimum GLSL version // Traverses the intermediate tree to return the minimum GLSL version
// required to legally access all built-in features used in the shader. // required to legally access all built-in features used in the shader.
// GLSL 1.1 which is mandated by OpenGL 2.0 provides: // GLSL 1.1 which is mandated by OpenGL 2.0 provides:
...@@ -27,7 +29,7 @@ ...@@ -27,7 +29,7 @@
class TVersionGLSL : public TIntermTraverser class TVersionGLSL : public TIntermTraverser
{ {
public: public:
TVersionGLSL(sh::GLenum type); TVersionGLSL(sh::GLenum type, const TPragma &pragma);
// Returns 120 if the following is used the shader: // Returns 120 if the following is used the shader:
// - "invariant", // - "invariant",
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <limits> #include <limits>
#include "compiler/preprocessor/numeric_lex.h" #include "compiler/preprocessor/numeric_lex.h"
#include "compiler/translator/SymbolTable.h"
#include "common/utilities.h" #include "common/utilities.h"
bool atof_clamp(const char *str, float *value) bool atof_clamp(const char *str, float *value)
...@@ -281,8 +282,45 @@ InterpolationType GetInterpolationType(TQualifier qualifier) ...@@ -281,8 +282,45 @@ InterpolationType GetInterpolationType(TQualifier qualifier)
} }
} }
GetVariableTraverser::GetVariableTraverser(const TSymbolTable &symbolTable)
: mSymbolTable(symbolTable)
{
}
template void GetVariableTraverser::setTypeSpecificInfo(
const TType &type, const TString& name, InterfaceBlockField *variable);
template void GetVariableTraverser::setTypeSpecificInfo(
const TType &type, const TString& name, ShaderVariable *variable);
template void GetVariableTraverser::setTypeSpecificInfo(
const TType &type, const TString& name, Uniform *variable);
template<>
void GetVariableTraverser::setTypeSpecificInfo(
const TType &type, const TString& name, Varying *variable)
{
ASSERT(variable);
switch (type.getQualifier())
{
case EvqInvariantVaryingIn:
case EvqInvariantVaryingOut:
variable->isInvariant = true;
break;
case EvqVaryingIn:
case EvqVaryingOut:
if (mSymbolTable.isVaryingInvariant(name))
{
variable->isInvariant = true;
}
break;
default:
break;
}
}
template <typename VarT> template <typename VarT>
void GetVariableTraverser::traverse(const TType &type, const TString &name, std::vector<VarT> *output) void GetVariableTraverser::traverse(const TType &type,
const TString &name,
std::vector<VarT> *output)
{ {
const TStructure *structure = type.getStruct(); const TStructure *structure = type.getStruct();
...@@ -309,15 +347,16 @@ void GetVariableTraverser::traverse(const TType &type, const TString &name, std: ...@@ -309,15 +347,16 @@ void GetVariableTraverser::traverse(const TType &type, const TString &name, std:
traverse(*field->type(), field->name(), &variable.fields); traverse(*field->type(), field->name(), &variable.fields);
} }
} }
setTypeSpecificInfo(type, name, &variable);
visitVariable(&variable); visitVariable(&variable);
ASSERT(output); ASSERT(output);
output->push_back(variable); output->push_back(variable);
} }
template void GetVariableTraverser::traverse(const TType &, const TString &, std::vector<InterfaceBlockField> *);
template void GetVariableTraverser::traverse(const TType &, const TString &, std::vector<ShaderVariable> *);
template void GetVariableTraverser::traverse(const TType &, const TString &, std::vector<Uniform> *); template void GetVariableTraverser::traverse(const TType &, const TString &, std::vector<Uniform> *);
template void GetVariableTraverser::traverse(const TType &, const TString &, std::vector<Varying> *); template void GetVariableTraverser::traverse(const TType &, const TString &, std::vector<Varying> *);
template void GetVariableTraverser::traverse(const TType &, const TString &, std::vector<InterfaceBlockField> *);
} }
...@@ -24,6 +24,8 @@ extern bool atof_clamp(const char *str, float *value); ...@@ -24,6 +24,8 @@ extern bool atof_clamp(const char *str, float *value);
// Return false if overflow happens. // Return false if overflow happens.
extern bool atoi_clamp(const char *str, int *value); extern bool atoi_clamp(const char *str, int *value);
class TSymbolTable;
namespace sh namespace sh
{ {
...@@ -38,7 +40,7 @@ TString ArrayString(const TType &type); ...@@ -38,7 +40,7 @@ TString ArrayString(const TType &type);
class GetVariableTraverser class GetVariableTraverser
{ {
public: public:
GetVariableTraverser() {} GetVariableTraverser(const TSymbolTable &symbolTable);
template <typename VarT> template <typename VarT>
void traverse(const TType &type, const TString &name, std::vector<VarT> *output); void traverse(const TType &type, const TString &name, std::vector<VarT> *output);
...@@ -48,6 +50,14 @@ class GetVariableTraverser ...@@ -48,6 +50,14 @@ class GetVariableTraverser
virtual void visitVariable(ShaderVariable *newVar) {} virtual void visitVariable(ShaderVariable *newVar) {}
private: private:
// Helper function called by traverse() to fill specific fields
// for attributes/varyings/uniforms.
template <typename VarT>
void setTypeSpecificInfo(
const TType &type, const TString &name, VarT *variable) {}
const TSymbolTable &mSymbolTable;
DISALLOW_COPY_AND_ASSIGN(GetVariableTraverser); DISALLOW_COPY_AND_ASSIGN(GetVariableTraverser);
}; };
......
...@@ -16,10 +16,11 @@ class MockDirectiveHandler : public pp::DirectiveHandler ...@@ -16,10 +16,11 @@ class MockDirectiveHandler : public pp::DirectiveHandler
MOCK_METHOD2(handleError, MOCK_METHOD2(handleError,
void(const pp::SourceLocation& loc, const std::string& msg)); void(const pp::SourceLocation& loc, const std::string& msg));
MOCK_METHOD3(handlePragma, MOCK_METHOD4(handlePragma,
void(const pp::SourceLocation& loc, void(const pp::SourceLocation& loc,
const std::string& name, const std::string& name,
const std::string& value)); const std::string& value,
bool stdgl));
MOCK_METHOD3(handleExtension, MOCK_METHOD3(handleExtension,
void(const pp::SourceLocation& loc, void(const pp::SourceLocation& loc,
......
...@@ -18,7 +18,7 @@ TEST_F(PragmaTest, EmptyName) ...@@ -18,7 +18,7 @@ TEST_F(PragmaTest, EmptyName)
using testing::_; using testing::_;
// No handlePragma calls. // No handlePragma calls.
EXPECT_CALL(mDirectiveHandler, handlePragma(_, _, _)).Times(0); EXPECT_CALL(mDirectiveHandler, handlePragma(_, _, _, false)).Times(0);
// No error or warning. // No error or warning.
EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0); EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
...@@ -32,7 +32,7 @@ TEST_F(PragmaTest, EmptyValue) ...@@ -32,7 +32,7 @@ TEST_F(PragmaTest, EmptyValue)
using testing::_; using testing::_;
EXPECT_CALL(mDirectiveHandler, EXPECT_CALL(mDirectiveHandler,
handlePragma(pp::SourceLocation(0, 1), "foo", "")); handlePragma(pp::SourceLocation(0, 1), "foo", "", false));
// No error or warning. // No error or warning.
EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0); EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
...@@ -46,7 +46,35 @@ TEST_F(PragmaTest, NameValue) ...@@ -46,7 +46,35 @@ TEST_F(PragmaTest, NameValue)
using testing::_; using testing::_;
EXPECT_CALL(mDirectiveHandler, EXPECT_CALL(mDirectiveHandler,
handlePragma(pp::SourceLocation(0, 1), "foo", "bar")); handlePragma(pp::SourceLocation(0, 1), "foo", "bar", false));
// No error or warning.
EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
preprocess(str, expected);
}
TEST_F(PragmaTest, STDGL)
{
const char* str = "#pragma STDGL\n";
const char* expected = "\n";
using testing::_;
EXPECT_CALL(mDirectiveHandler,
handlePragma(_, _, _, _)).Times(0);
// No error or warning.
EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
preprocess(str, expected);
}
TEST_F(PragmaTest, STDGLInvariantAll)
{
const char* str = "#pragma STDGL invariant(all)\n";
const char* expected = "\n";
using testing::_;
EXPECT_CALL(mDirectiveHandler,
handlePragma(pp::SourceLocation(0, 1), "invariant", "all", true));
// No error or warning. // No error or warning.
EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0); EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
...@@ -74,7 +102,7 @@ TEST_F(PragmaTest, Comments) ...@@ -74,7 +102,7 @@ TEST_F(PragmaTest, Comments)
using testing::_; using testing::_;
EXPECT_CALL(mDirectiveHandler, EXPECT_CALL(mDirectiveHandler,
handlePragma(pp::SourceLocation(0, 1), "foo", "bar")); handlePragma(pp::SourceLocation(0, 1), "foo", "bar", false));
// No error or warning. // No error or warning.
EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0); EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
...@@ -89,7 +117,7 @@ TEST_F(PragmaTest, MissingNewline) ...@@ -89,7 +117,7 @@ TEST_F(PragmaTest, MissingNewline)
using testing::_; using testing::_;
// Pragma successfully parsed. // Pragma successfully parsed.
EXPECT_CALL(mDirectiveHandler, EXPECT_CALL(mDirectiveHandler,
handlePragma(pp::SourceLocation(0, 1), "foo", "bar")); handlePragma(pp::SourceLocation(0, 1), "foo", "bar", false));
// Error reported about EOF. // Error reported about EOF.
EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_EOF_IN_DIRECTIVE, _, _)); EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_EOF_IN_DIRECTIVE, _, _));
...@@ -108,7 +136,7 @@ TEST_P(InvalidPragmaTest, Identified) ...@@ -108,7 +136,7 @@ TEST_P(InvalidPragmaTest, Identified)
using testing::_; using testing::_;
// No handlePragma calls. // No handlePragma calls.
EXPECT_CALL(mDirectiveHandler, handlePragma(_, _, _)).Times(0); EXPECT_CALL(mDirectiveHandler, handlePragma(_, _, _, false)).Times(0);
// Unrecognized pragma warning. // Unrecognized pragma warning.
EXPECT_CALL(mDiagnostics, EXPECT_CALL(mDiagnostics,
print(pp::Diagnostics::PP_UNRECOGNIZED_PRAGMA, print(pp::Diagnostics::PP_UNRECOGNIZED_PRAGMA,
......
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