Commit b59a778c by alokp@chromium.org

Implemented validation for loop and indexing limitations specified by GLSL ES…

Implemented validation for loop and indexing limitations specified by GLSL ES spec 1.0 Appendix A Section 4 and 5. A couple of things to note: - This CL only validates the "form" of loop and indexing. It does not detect number-of-iterations or out-of-bound access. This will require more involved analysis/heuristics. - I haved combined SH_VALIDATE_CONTROL_FLOW and SH_VALIDATE_INDEXING into one flag - SH_VALIDATE_LOOP_INDEXING. Validating both together is much easier. BUG=48 Review URL: http://codereview.appspot.com/3225041 git-svn-id: https://angleproject.googlecode.com/svn/trunk@491 736b8ea6-26fd-11df-bfd4-992fa37f6226
parent 9d1c9b4b
...@@ -17,7 +17,7 @@ extern "C" { ...@@ -17,7 +17,7 @@ extern "C" {
// Version number for shader translation API. // Version number for shader translation API.
// It is incremented everytime the API changes. // It is incremented everytime the API changes.
#define SH_VERSION 102 #define SH_VERSION 103
// //
// The names of the following enums have been derived by replacing GL prefix // The names of the following enums have been derived by replacing GL prefix
...@@ -68,11 +68,10 @@ typedef enum { ...@@ -68,11 +68,10 @@ typedef enum {
// Compile options. // Compile options.
typedef enum { typedef enum {
SH_VALIDATE = 0, SH_VALIDATE = 0,
SH_VALIDATE_CONTROL_FLOW = 0x0001, SH_VALIDATE_LOOP_INDEXING = 0x0001,
SH_VALIDATE_INDEXING = 0x0002, SH_INTERMEDIATE_TREE = 0x0002,
SH_INTERMEDIATE_TREE = 0x0004, SH_OBJECT_CODE = 0x0004,
SH_OBJECT_CODE = 0x0008, SH_ATTRIBUTES_UNIFORMS = 0x0008
SH_ATTRIBUTES_UNIFORMS = 0x0010
} ShCompileOptions; } ShCompileOptions;
// //
...@@ -146,16 +145,12 @@ void ShDestruct(ShHandle handle); ...@@ -146,16 +145,12 @@ void ShDestruct(ShHandle handle);
// compileOptions: A mask containing the following parameters: // compileOptions: A mask containing the following parameters:
// SH_VALIDATE: Validates shader to ensure that it conforms to the spec // SH_VALIDATE: Validates shader to ensure that it conforms to the spec
// specified during compiler construction. // specified during compiler construction.
// SH_VALIDATE_CONTROL_FLOW: Validates control flow in the shader to ensure // SH_VALIDATE_LOOP_INDEXING: Validates loop and indexing in the shader to
// that they do not exceed the minimum functionality // ensure that they do not exceed the minimum
// mandated in GLSL 1.0 spec, Appendix A, Section 4. // functionality mandated in GLSL 1.0 spec,
// Appendix A, Section 4 and 5.
// There is no need to specify this parameter when // There is no need to specify this parameter when
// compiling for WebGL - it is implied. // compiling for WebGL - it is implied.
// SH_VALIDATE_INDEXING: Validates indexing of arrays, vectors, and matrices
// in the shader to ensure that they do not exceed the
// minimum functionality mandated in GLSL 1.0 spec,
// Appendix A, Section 5. There is no need to specify this
// parameter when compiling for WebGL - it is implied.
// SH_INTERMEDIATE_TREE: Writes intermediate tree to info log. // SH_INTERMEDIATE_TREE: Writes intermediate tree to info log.
// Can be queried by calling ShGetInfoLog(). // Can be queried by calling ShGetInfoLog().
// SH_OBJECT_CODE: Translates intermediate tree to glsl or hlsl shader. // SH_OBJECT_CODE: Translates intermediate tree to glsl or hlsl shader.
......
...@@ -59,6 +59,8 @@ ...@@ -59,6 +59,8 @@
'compiler/unistd.h', 'compiler/unistd.h',
'compiler/util.cpp', 'compiler/util.cpp',
'compiler/util.h', 'compiler/util.h',
'compiler/ValidateLimitations.cpp',
'compiler/ValidateLimitations.h',
'compiler/VariableInfo.cpp', 'compiler/VariableInfo.cpp',
'compiler/VariableInfo.h', 'compiler/VariableInfo.h',
'compiler/preprocessor/atom.c', 'compiler/preprocessor/atom.c',
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "compiler/Initialize.h" #include "compiler/Initialize.h"
#include "compiler/ParseHelper.h" #include "compiler/ParseHelper.h"
#include "compiler/ShHandle.h" #include "compiler/ShHandle.h"
#include "compiler/ValidateLimitations.h"
namespace { namespace {
bool InitializeSymbolTable( bool InitializeSymbolTable(
...@@ -110,10 +111,9 @@ bool TCompiler::compile(const char* const shaderStrings[], ...@@ -110,10 +111,9 @@ bool TCompiler::compile(const char* const shaderStrings[],
if (numStrings == 0) if (numStrings == 0)
return true; return true;
// If compiling for WebGL, validate control-flow and indexing as well. // If compiling for WebGL, validate loop and indexing as well.
if (shaderSpec == SH_WEBGL_SPEC) { if (shaderSpec == SH_WEBGL_SPEC)
compileOptions |= SH_VALIDATE_CONTROL_FLOW | SH_VALIDATE_INDEXING; compileOptions |= SH_VALIDATE_LOOP_INDEXING;
}
TIntermediate intermediate(infoSink); TIntermediate intermediate(infoSink);
TParseContext parseContext(symbolTable, extensionBehavior, intermediate, TParseContext parseContext(symbolTable, extensionBehavior, intermediate,
...@@ -131,16 +131,20 @@ bool TCompiler::compile(const char* const shaderStrings[], ...@@ -131,16 +131,20 @@ bool TCompiler::compile(const char* const shaderStrings[],
(PaParseStrings(numStrings, shaderStrings, NULL, &parseContext) == 0) && (PaParseStrings(numStrings, shaderStrings, NULL, &parseContext) == 0) &&
(parseContext.treeRoot != NULL); (parseContext.treeRoot != NULL);
if (success) { if (success) {
success = intermediate.postProcess(parseContext.treeRoot); TIntermNode* root = parseContext.treeRoot;
success = intermediate.postProcess(root);
if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING))
success = validateLimitations(root);
if (success && (compileOptions & SH_INTERMEDIATE_TREE)) if (success && (compileOptions & SH_INTERMEDIATE_TREE))
intermediate.outputTree(parseContext.treeRoot); intermediate.outputTree(root);
if (success && (compileOptions & SH_OBJECT_CODE)) if (success && (compileOptions & SH_OBJECT_CODE))
translate(parseContext.treeRoot); translate(root);
if (success && (compileOptions & SH_ATTRIBUTES_UNIFORMS)) if (success && (compileOptions & SH_ATTRIBUTES_UNIFORMS))
collectAttribsUniforms(parseContext.treeRoot); collectAttribsUniforms(root);
} }
// Cleanup memory. // Cleanup memory.
...@@ -172,6 +176,12 @@ void TCompiler::clearResults() ...@@ -172,6 +176,12 @@ void TCompiler::clearResults()
uniforms.clear(); uniforms.clear();
} }
bool TCompiler::validateLimitations(TIntermNode* root) {
ValidateLimitations validate(shaderType, infoSink.info);
root->traverse(&validate);
return validate.numErrors() == 0;
}
void TCompiler::collectAttribsUniforms(TIntermNode* root) void TCompiler::collectAttribsUniforms(TIntermNode* root)
{ {
CollectAttribsUniforms collect(attribs, uniforms); CollectAttribsUniforms collect(attribs, uniforms);
......
...@@ -22,6 +22,101 @@ static TPrecision GetHigherPrecision( TPrecision left, TPrecision right ){ ...@@ -22,6 +22,101 @@ static TPrecision GetHigherPrecision( TPrecision left, TPrecision right ){
return left > right ? left : right; return left > right ? left : right;
} }
const char* getOperatorString(TOperator op) {
switch (op) {
case EOpInitialize: return "=";
case EOpAssign: return "=";
case EOpAddAssign: return "+=";
case EOpSubAssign: return "-=";
case EOpDivAssign: return "/=";
// Fall-through.
case EOpMulAssign:
case EOpVectorTimesMatrixAssign:
case EOpVectorTimesScalarAssign:
case EOpMatrixTimesScalarAssign:
case EOpMatrixTimesMatrixAssign: return "*=";
// Fall-through.
case EOpIndexDirect:
case EOpIndexIndirect: return "[]";
case EOpIndexDirectStruct: return ".";
case EOpVectorSwizzle: return ".";
case EOpAdd: return "+";
case EOpSub: return "-";
case EOpMul: return "*";
case EOpDiv: return "/";
case EOpMod: UNIMPLEMENTED(); break;
case EOpEqual: return "==";
case EOpNotEqual: return "!=";
case EOpLessThan: return "<";
case EOpGreaterThan: return ">";
case EOpLessThanEqual: return "<=";
case EOpGreaterThanEqual: return ">=";
// Fall-through.
case EOpVectorTimesScalar:
case EOpVectorTimesMatrix:
case EOpMatrixTimesVector:
case EOpMatrixTimesScalar:
case EOpMatrixTimesMatrix: return "*";
case EOpLogicalOr: return "||";
case EOpLogicalXor: return "^^";
case EOpLogicalAnd: return "&&";
case EOpNegative: return "-";
case EOpVectorLogicalNot: return "not";
case EOpLogicalNot: return "!";
case EOpPostIncrement: return "++";
case EOpPostDecrement: return "--";
case EOpPreIncrement: return "++";
case EOpPreDecrement: return "--";
// Fall-through.
case EOpConvIntToBool:
case EOpConvFloatToBool: return "bool";
// Fall-through.
case EOpConvBoolToFloat:
case EOpConvIntToFloat: return "float";
// Fall-through.
case EOpConvFloatToInt:
case EOpConvBoolToInt: return "int";
case EOpRadians: return "radians";
case EOpDegrees: return "degrees";
case EOpSin: return "sin";
case EOpCos: return "cos";
case EOpTan: return "tan";
case EOpAsin: return "asin";
case EOpAcos: return "acos";
case EOpAtan: return "atan";
case EOpExp: return "exp";
case EOpLog: return "log";
case EOpExp2: return "exp2";
case EOpLog2: return "log2";
case EOpSqrt: return "sqrt";
case EOpInverseSqrt: return "inversesqrt";
case EOpAbs: return "abs";
case EOpSign: return "sign";
case EOpFloor: return "floor";
case EOpCeil: return "ceil";
case EOpFract: return "fract";
case EOpLength: return "length";
case EOpNormalize: return "normalize";
case EOpDFdx: return "dFdx";
case EOpDFdy: return "dFdy";
case EOpFwidth: return "fwidth";
case EOpAny: return "any";
case EOpAll: return "all";
default: break;
}
return "";
}
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// //
// First set of functions are to help build the intermediate representation. // First set of functions are to help build the intermediate representation.
......
...@@ -65,6 +65,9 @@ protected: ...@@ -65,6 +65,9 @@ protected:
bool InitBuiltInSymbolTable(const ShBuiltInResources& resources); bool InitBuiltInSymbolTable(const ShBuiltInResources& resources);
// Clears the results from the previous compilation. // Clears the results from the previous compilation.
void clearResults(); void clearResults();
// Returns true if the given shader does not exceed the minimum
// functionality mandated in GLSL 1.0 spec Appendix A.
bool validateLimitations(TIntermNode* root);
// Collect info for all attribs and uniforms. // Collect info for all attribs and uniforms.
void collectAttribsUniforms(TIntermNode* root); void collectAttribsUniforms(TIntermNode* root);
// Translate to object code. // Translate to object code.
......
//
// Copyright (c) 2010 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"
class TInfoSinkBase;
struct TLoopInfo {
struct TIndex {
int id; // symbol id.
} index;
};
typedef TVector<TLoopInfo> TLoopStack;
// Traverses intermediate tree to ensure that the shader does not exceed the
// minimum functionality mandated in GLSL 1.0 spec, Appendix A.
class ValidateLimitations : public TIntermTraverser {
public:
ValidateLimitations(ShShaderType shaderType, TInfoSinkBase& sink);
int numErrors() const { return mNumErrors; }
virtual void visitSymbol(TIntermSymbol*);
virtual void visitConstantUnion(TIntermConstantUnion*);
virtual bool visitBinary(Visit, TIntermBinary*);
virtual bool visitUnary(Visit, TIntermUnary*);
virtual bool visitSelection(Visit, TIntermSelection*);
virtual bool visitAggregate(Visit, TIntermAggregate*);
virtual bool visitLoop(Visit, TIntermLoop*);
virtual bool visitBranch(Visit, TIntermBranch*);
private:
void error(TSourceLoc loc, const char *reason, const char* token);
bool withinLoopBody() const;
bool isLoopIndex(const TIntermSymbol* symbol) const;
bool validateLoopType(TIntermLoop* node);
bool validateForLoopHeader(TIntermLoop* node, TLoopInfo* info);
bool validateForLoopInit(TIntermLoop* node, TLoopInfo* info);
bool validateForLoopCond(TIntermLoop* node, TLoopInfo* info);
bool validateForLoopExpr(TIntermLoop* node, TLoopInfo* info);
// Returns true if none of the loop indices is used as the argument to
// the given function out or inout parameter.
bool validateFunctionCall(TIntermAggregate* node);
bool validateOperation(TIntermOperator* node, TIntermNode* operand);
// Returns true if indexing does not exceed the minimum functionality
// mandated in GLSL 1.0 spec, Appendix A, Section 5.
bool isConstExpr(TIntermNode* node);
bool isConstIndexExpr(TIntermNode* node);
bool validateIndexing(TIntermBinary* node);
ShShaderType mShaderType;
TInfoSinkBase& mSink;
int mNumErrors;
TLoopStack mLoopStack;
};
...@@ -184,6 +184,8 @@ enum TOperator { ...@@ -184,6 +184,8 @@ enum TOperator {
EOpDivAssign, EOpDivAssign,
}; };
extern const char* getOperatorString(TOperator op);
class TIntermTraverser; class TIntermTraverser;
class TIntermAggregate; class TIntermAggregate;
class TIntermBinary; class TIntermBinary;
......
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