Commit 853dc1ab by Olli Etuaho Committed by Nicolas Capens

Add mediump and lowp precision emulation support for GLSL output

This implements the rounding as specified in WEBGL_debug_shader_precision extension proposal for desktop GLSL and ESSL output. The bulk of the new functionality is added in the form of a new EmulatePrecision AST traverser, which inserts calls to the rounding routines angle_frm and angle_frl in the appropriate places, and writes the rounding routines themselves to the shader. Compound assignments which are subject to emulation are transformed from "x op= y" to "angle_compound_op_frm(x, y)", a call to a function which does the appropriate rounding and places the result of the operation to x. The angle_ prefixed names should not clash with user-defined names if name hashing is on. If name hashing is not on, the precision emulation can only be used if the angle_ prefix is reserved for use by ANGLE. To support the rounding routines in output, a new operator type is added for internal helper function calls, which are not subject to name hashing. In ESSL output, all variables are forced to highp when precision emulation is on to ensure consistency with how precision emulation performs on desktop. Comprehensive tests for the added code generation are included. BUG=angle:787 Change-Id: I0d0ad9327888f803a32e79b64b08763c654c913b Reviewed-on: https://chromium-review.googlesource.com/229631Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Tested-by: 's avatarOlli Etuaho <oetuaho@nvidia.com>
parent 1c9ecfd7
...@@ -223,6 +223,7 @@ typedef struct ...@@ -223,6 +223,7 @@ typedef struct
int EXT_draw_buffers; int EXT_draw_buffers;
int EXT_frag_depth; int EXT_frag_depth;
int EXT_shader_texture_lod; int EXT_shader_texture_lod;
int WEBGL_debug_shader_precision;
// Set to 1 to enable replacing GL_EXT_draw_buffers #extension directives // Set to 1 to enable replacing GL_EXT_draw_buffers #extension directives
// with GL_NV_draw_buffers in ESSL output. This flag can be used to emulate // with GL_NV_draw_buffers in ESSL output. This flag can be used to emulate
......
...@@ -52,6 +52,8 @@ ...@@ -52,6 +52,8 @@
'compiler/translator/Diagnostics.h', 'compiler/translator/Diagnostics.h',
'compiler/translator/DirectiveHandler.cpp', 'compiler/translator/DirectiveHandler.cpp',
'compiler/translator/DirectiveHandler.h', 'compiler/translator/DirectiveHandler.h',
'compiler/translator/EmulatePrecision.cpp',
'compiler/translator/EmulatePrecision.h',
'compiler/translator/ExtensionBehavior.h', 'compiler/translator/ExtensionBehavior.h',
'compiler/translator/FlagStd140Structs.cpp', 'compiler/translator/FlagStd140Structs.cpp',
'compiler/translator/FlagStd140Structs.h', 'compiler/translator/FlagStd140Structs.h',
......
...@@ -182,10 +182,12 @@ bool TCompiler::compile(const char* const shaderStrings[], ...@@ -182,10 +182,12 @@ bool TCompiler::compile(const char* const shaderStrings[],
++firstSource; ++firstSource;
} }
bool debugShaderPrecision = getResources().WEBGL_debug_shader_precision == 1;
TIntermediate intermediate(infoSink); TIntermediate intermediate(infoSink);
TParseContext parseContext(symbolTable, extensionBehavior, intermediate, TParseContext parseContext(symbolTable, extensionBehavior, intermediate,
shaderType, shaderSpec, compileOptions, true, shaderType, shaderSpec, compileOptions, true,
sourcePath, infoSink); sourcePath, infoSink, debugShaderPrecision);
parseContext.fragmentPrecisionHigh = fragmentPrecisionHigh; parseContext.fragmentPrecisionHigh = fragmentPrecisionHigh;
SetGlobalParseContext(&parseContext); SetGlobalParseContext(&parseContext);
...@@ -394,7 +396,8 @@ void TCompiler::setResourceString() ...@@ -394,7 +396,8 @@ void TCompiler::setResourceString()
<< ":MaxFragmentInputVectors:" << compileResources.MaxFragmentInputVectors << ":MaxFragmentInputVectors:" << compileResources.MaxFragmentInputVectors
<< ":MinProgramTexelOffset:" << compileResources.MinProgramTexelOffset << ":MinProgramTexelOffset:" << compileResources.MinProgramTexelOffset
<< ":MaxProgramTexelOffset:" << compileResources.MaxProgramTexelOffset << ":MaxProgramTexelOffset:" << compileResources.MaxProgramTexelOffset
<< ":NV_draw_buffers:" << compileResources.NV_draw_buffers; << ":NV_draw_buffers:" << compileResources.NV_draw_buffers
<< ":WEBGL_debug_shader_precision:" << compileResources.WEBGL_debug_shader_precision;
builtInResourcesString = strstream.str(); builtInResourcesString = strstream.str();
} }
......
...@@ -27,10 +27,12 @@ static TBehavior getBehavior(const std::string& str) ...@@ -27,10 +27,12 @@ static TBehavior getBehavior(const std::string& str)
TDirectiveHandler::TDirectiveHandler(TExtensionBehavior& extBehavior, TDirectiveHandler::TDirectiveHandler(TExtensionBehavior& extBehavior,
TDiagnostics& diagnostics, TDiagnostics& diagnostics,
int& shaderVersion) int& shaderVersion,
bool debugShaderPrecisionSupported)
: mExtensionBehavior(extBehavior), : mExtensionBehavior(extBehavior),
mDiagnostics(diagnostics), mDiagnostics(diagnostics),
mShaderVersion(shaderVersion) mShaderVersion(shaderVersion),
mDebugShaderPrecisionSupported(debugShaderPrecisionSupported)
{ {
} }
...@@ -65,6 +67,7 @@ void TDirectiveHandler::handlePragma(const pp::SourceLocation& loc, ...@@ -65,6 +67,7 @@ void TDirectiveHandler::handlePragma(const pp::SourceLocation& loc,
{ {
const char kOptimize[] = "optimize"; const char kOptimize[] = "optimize";
const char kDebug[] = "debug"; const char kDebug[] = "debug";
const char kDebugShaderPrecision[] = "webgl_debug_shader_precision";
const char kOn[] = "on"; const char kOn[] = "on";
const char kOff[] = "off"; const char kOff[] = "off";
...@@ -81,6 +84,12 @@ void TDirectiveHandler::handlePragma(const pp::SourceLocation& loc, ...@@ -81,6 +84,12 @@ void TDirectiveHandler::handlePragma(const pp::SourceLocation& loc,
else if (value == kOff) mPragma.debug = false; else if (value == kOff) mPragma.debug = false;
else invalidValue = true; else invalidValue = true;
} }
else if (name == kDebugShaderPrecision && mDebugShaderPrecisionSupported)
{
if (value == kOn) mPragma.debugShaderPrecision = true;
else if (value == kOff) mPragma.debugShaderPrecision = false;
else invalidValue = true;
}
else else
{ {
mDiagnostics.report(pp::Diagnostics::PP_UNRECOGNIZED_PRAGMA, loc, name); mDiagnostics.report(pp::Diagnostics::PP_UNRECOGNIZED_PRAGMA, loc, name);
......
...@@ -18,7 +18,8 @@ class TDirectiveHandler : public pp::DirectiveHandler ...@@ -18,7 +18,8 @@ class TDirectiveHandler : public pp::DirectiveHandler
public: public:
TDirectiveHandler(TExtensionBehavior& extBehavior, TDirectiveHandler(TExtensionBehavior& extBehavior,
TDiagnostics& diagnostics, TDiagnostics& diagnostics,
int& shaderVersion); int& shaderVersion,
bool debugShaderPrecisionSupported);
virtual ~TDirectiveHandler(); virtual ~TDirectiveHandler();
const TPragma& pragma() const { return mPragma; } const TPragma& pragma() const { return mPragma; }
...@@ -44,6 +45,7 @@ class TDirectiveHandler : public pp::DirectiveHandler ...@@ -44,6 +45,7 @@ class TDirectiveHandler : public pp::DirectiveHandler
TExtensionBehavior& mExtensionBehavior; TExtensionBehavior& mExtensionBehavior;
TDiagnostics& mDiagnostics; TDiagnostics& mDiagnostics;
int& mShaderVersion; int& mShaderVersion;
bool mDebugShaderPrecisionSupported;
}; };
#endif // COMPILER_TRANSLATOR_DIRECTIVEHANDLER_H_ #endif // COMPILER_TRANSLATOR_DIRECTIVEHANDLER_H_
//
// Copyright (c) 2002-2014 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.
//
#ifndef COMPILER_TRANSLATOR_EMULATE_PRECISION_H_
#define COMPILER_TRANSLATOR_EMULATE_PRECISION_H_
#include "common/angleutils.h"
#include "compiler/translator/InfoSink.h"
#include "compiler/translator/IntermNode.h"
#include "GLSLANG/ShaderLang.h"
// This class gathers all compound assignments from the AST and can then write
// the functions required for their precision emulation. This way there is no
// need to write a huge number of variations of the emulated compound assignment
// to every translated shader with emulation enabled.
class EmulatePrecision : public TIntermTraverser
{
public:
EmulatePrecision();
virtual void visitSymbol(TIntermSymbol *node);
virtual bool visitBinary(Visit visit, TIntermBinary *node);
virtual bool visitUnary(Visit visit, TIntermUnary *node);
virtual bool visitAggregate(Visit visit, TIntermAggregate *node);
void writeEmulationHelpers(TInfoSinkBase& sink, ShShaderOutput outputLanguage);
private:
DISALLOW_COPY_AND_ASSIGN(EmulatePrecision);
struct TypePair
{
TypePair(const char *l, const char *r)
: lType(l), rType(r) { }
const char *lType;
const char *rType;
};
struct TypePairComparator
{
bool operator() (const TypePair& l, const TypePair& r) const
{
if (l.lType == r.lType)
return l.rType < r.rType;
return l.lType < r.lType;
}
};
typedef std::set<TypePair, TypePairComparator> EmulationSet;
EmulationSet mEmulateCompoundAdd;
EmulationSet mEmulateCompoundSub;
EmulationSet mEmulateCompoundMul;
EmulationSet mEmulateCompoundDiv;
// Stack of function call parameter iterators
std::vector<TIntermSequence::const_iterator> mSeqIterStack;
bool mDeclaringVariables;
bool mInLValue;
bool mInFunctionCallOutParameter;
struct TStringComparator
{
bool operator() (const TString& a, const TString& b) const { return a.compare(b) < 0; }
};
// Map from function names to their parameter sequences
std::map<TString, TIntermSequence*, TStringComparator> mFunctionMap;
};
#endif // COMPILER_TRANSLATOR_EMULATE_PRECISION_H_
...@@ -1181,3 +1181,29 @@ TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunctio ...@@ -1181,3 +1181,29 @@ TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunctio
TString hashedName = stream.str(); TString hashedName = stream.str();
return hashedName; return hashedName;
} }
void TIntermTraverser::updateTree()
{
for (size_t ii = 0; ii < mReplacements.size(); ++ii)
{
const NodeUpdateEntry& entry = mReplacements[ii];
ASSERT(entry.parent);
bool replaced = entry.parent->replaceChildNode(
entry.original, entry.replacement);
ASSERT(replaced);
if (!entry.originalBecomesChildOfReplacement)
{
// In AST traversing, a parent is visited before its children.
// After we replace a node, if an immediate child is to
// be replaced, we need to make sure we don't update the replaced
// node; instead, we update the replacement node.
for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
{
NodeUpdateEntry& entry2 = mReplacements[jj];
if (entry2.parent == entry.original)
entry2.parent = entry.replacement;
}
}
}
}
...@@ -33,6 +33,7 @@ enum TOperator ...@@ -33,6 +33,7 @@ enum TOperator
EOpNull, // if in a node, should only mean a node is still being built EOpNull, // if in a node, should only mean a node is still being built
EOpSequence, // denotes a list of statements, or parameters, etc. EOpSequence, // denotes a list of statements, or parameters, etc.
EOpFunctionCall, EOpFunctionCall,
EOpInternalFunctionCall, // Call to an internal helper function
EOpFunction, // For function definition EOpFunction, // For function definition
EOpParameters, // an aggregate listing the parameters to a function EOpParameters, // an aggregate listing the parameters to a function
...@@ -741,12 +742,38 @@ class TIntermTraverser ...@@ -741,12 +742,38 @@ class TIntermTraverser
const bool postVisit; const bool postVisit;
const bool rightToLeft; const bool rightToLeft;
// If traversers need to replace nodes, they can add the replacements in
// mReplacements during traversal and the user of the traverser should call
// this function after traversal to perform them.
void updateTree();
protected: protected:
int mDepth; int mDepth;
int mMaxDepth; int mMaxDepth;
// All the nodes from root to the current node's parent during traversing. // All the nodes from root to the current node's parent during traversing.
TVector<TIntermNode *> mPath; TVector<TIntermNode *> mPath;
struct NodeUpdateEntry
{
NodeUpdateEntry(TIntermNode *_parent,
TIntermNode *_original,
TIntermNode *_replacement,
bool _originalBecomesChildOfReplacement)
: parent(_parent),
original(_original),
replacement(_replacement),
originalBecomesChildOfReplacement(_originalBecomesChildOfReplacement) {}
TIntermNode *parent;
TIntermNode *original;
TIntermNode *replacement;
bool originalBecomesChildOfReplacement;
};
// During traversing, save all the changes that need to happen into
// mReplacements, then do them by calling updateTree().
std::vector<NodeUpdateEntry> mReplacements;
}; };
// //
......
...@@ -11,8 +11,10 @@ TOutputESSL::TOutputESSL(TInfoSinkBase& objSink, ...@@ -11,8 +11,10 @@ TOutputESSL::TOutputESSL(TInfoSinkBase& objSink,
ShHashFunction64 hashFunction, ShHashFunction64 hashFunction,
NameMap& nameMap, NameMap& nameMap,
TSymbolTable& symbolTable, TSymbolTable& symbolTable,
int shaderVersion) int shaderVersion,
: TOutputGLSLBase(objSink, clampingStrategy, hashFunction, nameMap, symbolTable, shaderVersion) bool forceHighp)
: TOutputGLSLBase(objSink, clampingStrategy, hashFunction, nameMap, symbolTable, shaderVersion),
mForceHighp(forceHighp)
{ {
} }
...@@ -22,6 +24,9 @@ bool TOutputESSL::writeVariablePrecision(TPrecision precision) ...@@ -22,6 +24,9 @@ bool TOutputESSL::writeVariablePrecision(TPrecision precision)
return false; return false;
TInfoSinkBase& out = objSink(); TInfoSinkBase& out = objSink();
out << getPrecisionString(precision); if (mForceHighp)
out << getPrecisionString(EbpHigh);
else
out << getPrecisionString(precision);
return true; return true;
} }
...@@ -17,10 +17,13 @@ public: ...@@ -17,10 +17,13 @@ public:
ShHashFunction64 hashFunction, ShHashFunction64 hashFunction,
NameMap& nameMap, NameMap& nameMap,
TSymbolTable& symbolTable, TSymbolTable& symbolTable,
int shaderVersion); int shaderVersion,
bool forceHighp);
protected: protected:
virtual bool writeVariablePrecision(TPrecision precision); virtual bool writeVariablePrecision(TPrecision precision);
private:
bool mForceHighp;
}; };
#endif // COMPILER_TRANSLATOR_OUTPUTESSL_H_ #endif // COMPILER_TRANSLATOR_OUTPUTESSL_H_
...@@ -622,6 +622,15 @@ bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node) ...@@ -622,6 +622,15 @@ bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
else else
out << ")"; out << ")";
break; break;
case EOpInternalFunctionCall:
// Function call to an internal helper function.
if (visit == PreVisit)
out << node->getName() << "(";
else if (visit == InVisit)
out << ", ";
else
out << ")";
break;
case EOpParameters: case EOpParameters:
// Function parameters. // Function parameters.
ASSERT(visit == PreVisit); ASSERT(visit == PreVisit);
......
...@@ -25,7 +25,7 @@ struct TMatrixFields { ...@@ -25,7 +25,7 @@ struct TMatrixFields {
// they can be passed to the parser without needing a global. // they can be passed to the parser without needing a global.
// //
struct TParseContext { struct TParseContext {
TParseContext(TSymbolTable& symt, TExtensionBehavior& ext, TIntermediate& interm, sh::GLenum type, ShShaderSpec spec, int options, bool checksPrecErrors, const char* sourcePath, TInfoSink& is) : TParseContext(TSymbolTable& symt, TExtensionBehavior& ext, TIntermediate& interm, sh::GLenum type, ShShaderSpec spec, int options, bool checksPrecErrors, const char* sourcePath, TInfoSink& is, bool debugShaderPrecisionSupported) :
intermediate(interm), intermediate(interm),
symbolTable(symt), symbolTable(symt),
shaderType(type), shaderType(type),
...@@ -42,7 +42,7 @@ struct TParseContext { ...@@ -42,7 +42,7 @@ struct TParseContext {
defaultBlockStorage(EbsShared), defaultBlockStorage(EbsShared),
diagnostics(is), diagnostics(is),
shaderVersion(100), shaderVersion(100),
directiveHandler(ext, diagnostics, shaderVersion), directiveHandler(ext, diagnostics, shaderVersion, debugShaderPrecisionSupported),
preprocessor(&diagnostics, &directiveHandler), preprocessor(&diagnostics, &directiveHandler),
scanner(NULL) { } scanner(NULL) { }
TIntermediate& intermediate; // to hold and build a parse tree TIntermediate& intermediate; // to hold and build a parse tree
......
...@@ -18,11 +18,14 @@ struct TPragma ...@@ -18,11 +18,14 @@ struct TPragma
// 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) { } // Precision emulation is turned on by default, but has no effect unless
TPragma(bool o, bool d) : optimize(o), debug(d) { } // the extension is enabled.
TPragma() : optimize(true), debug(false), debugShaderPrecision(true) { }
TPragma(bool o, bool d) : optimize(o), debug(d), debugShaderPrecision(true) { }
bool optimize; bool optimize;
bool debug; bool debug;
bool debugShaderPrecision;
STDGL stdgl; STDGL stdgl;
}; };
......
...@@ -153,6 +153,7 @@ void ShInitBuiltInResources(ShBuiltInResources* resources) ...@@ -153,6 +153,7 @@ void ShInitBuiltInResources(ShBuiltInResources* resources)
resources->EXT_draw_buffers = 0; resources->EXT_draw_buffers = 0;
resources->EXT_frag_depth = 0; resources->EXT_frag_depth = 0;
resources->EXT_shader_texture_lod = 0; resources->EXT_shader_texture_lod = 0;
resources->WEBGL_debug_shader_precision = 0;
resources->NV_draw_buffers = 0; resources->NV_draw_buffers = 0;
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "compiler/translator/TranslatorESSL.h" #include "compiler/translator/TranslatorESSL.h"
#include "compiler/translator/EmulatePrecision.h"
#include "compiler/translator/OutputESSL.h" #include "compiler/translator/OutputESSL.h"
#include "angle_gl.h" #include "angle_gl.h"
...@@ -21,6 +22,16 @@ void TranslatorESSL::translate(TIntermNode* root) { ...@@ -21,6 +22,16 @@ void TranslatorESSL::translate(TIntermNode* root) {
// Write built-in extension behaviors. // Write built-in extension behaviors.
writeExtensionBehavior(); writeExtensionBehavior();
bool precisionEmulation = getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision;
if (precisionEmulation)
{
EmulatePrecision emulatePrecision;
root->traverse(&emulatePrecision);
emulatePrecision.updateTree();
emulatePrecision.writeEmulationHelpers(sink, SH_ESSL_OUTPUT);
}
// Write emulated built-in functions if needed. // Write emulated built-in functions if needed.
getBuiltInFunctionEmulator().OutputEmulatedFunctionDefinition( getBuiltInFunctionEmulator().OutputEmulatedFunctionDefinition(
sink, getShaderType() == GL_FRAGMENT_SHADER); sink, getShaderType() == GL_FRAGMENT_SHADER);
...@@ -29,7 +40,7 @@ void TranslatorESSL::translate(TIntermNode* root) { ...@@ -29,7 +40,7 @@ void TranslatorESSL::translate(TIntermNode* root) {
getArrayBoundsClamper().OutputClampingFunctionDefinition(sink); getArrayBoundsClamper().OutputClampingFunctionDefinition(sink);
// Write translated shader. // Write translated shader.
TOutputESSL outputESSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(), getSymbolTable(), getShaderVersion()); TOutputESSL outputESSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(), getSymbolTable(), getShaderVersion(), precisionEmulation);
root->traverse(&outputESSL); root->traverse(&outputESSL);
} }
......
...@@ -6,9 +6,11 @@ ...@@ -6,9 +6,11 @@
#include "compiler/translator/TranslatorGLSL.h" #include "compiler/translator/TranslatorGLSL.h"
#include "compiler/translator/EmulatePrecision.h"
#include "compiler/translator/OutputGLSL.h" #include "compiler/translator/OutputGLSL.h"
#include "compiler/translator/VersionGLSL.h" #include "compiler/translator/VersionGLSL.h"
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) {
} }
...@@ -24,6 +26,16 @@ void TranslatorGLSL::translate(TIntermNode* root) { ...@@ -24,6 +26,16 @@ void TranslatorGLSL::translate(TIntermNode* root) {
// Write extension behaviour as needed // Write extension behaviour as needed
writeExtensionBehavior(); writeExtensionBehavior();
bool precisionEmulation = getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision;
if (precisionEmulation)
{
EmulatePrecision emulatePrecision;
root->traverse(&emulatePrecision);
emulatePrecision.updateTree();
emulatePrecision.writeEmulationHelpers(sink, SH_GLSL_OUTPUT);
}
// Write emulated built-in functions if needed. // Write emulated built-in functions if needed.
getBuiltInFunctionEmulator().OutputEmulatedFunctionDefinition( getBuiltInFunctionEmulator().OutputEmulatedFunctionDefinition(
sink, false); sink, false);
......
...@@ -325,6 +325,10 @@ class TType ...@@ -325,6 +325,10 @@ class TType
{ {
return primarySize > 1 && secondarySize > 1; return primarySize > 1 && secondarySize > 1;
} }
bool isNonSquareMatrix() const
{
return isMatrix() && primarySize != secondarySize;
}
bool isArray() const bool isArray() const
{ {
return array ? true : false; return array ? true : false;
......
...@@ -50,32 +50,8 @@ bool UnfoldShortCircuitAST::visitBinary(Visit visit, TIntermBinary *node) ...@@ -50,32 +50,8 @@ bool UnfoldShortCircuitAST::visitBinary(Visit visit, TIntermBinary *node)
} }
if (replacement) if (replacement)
{ {
replacements.push_back( mReplacements.push_back(
NodeUpdateEntry(getParentNode(), node, replacement)); NodeUpdateEntry(getParentNode(), node, replacement, false));
} }
return true; return true;
} }
void UnfoldShortCircuitAST::updateTree()
{
for (size_t ii = 0; ii < replacements.size(); ++ii)
{
const NodeUpdateEntry& entry = replacements[ii];
ASSERT(entry.parent);
bool replaced = entry.parent->replaceChildNode(
entry.original, entry.replacement);
ASSERT(replaced);
// In AST traversing, a parent is visited before its children.
// After we replace a node, if an immediate child is to
// be replaced, we need to make sure we don't update the replaced
// node; instead, we update the replacement node.
for (size_t jj = ii + 1; jj < replacements.size(); ++jj)
{
NodeUpdateEntry& entry2 = replacements[jj];
if (entry2.parent == entry.original)
entry2.parent = entry.replacement;
}
}
}
...@@ -24,27 +24,7 @@ class UnfoldShortCircuitAST : public TIntermTraverser ...@@ -24,27 +24,7 @@ class UnfoldShortCircuitAST : public TIntermTraverser
virtual bool visitBinary(Visit visit, TIntermBinary *); virtual bool visitBinary(Visit visit, TIntermBinary *);
void updateTree();
private: private:
struct NodeUpdateEntry
{
NodeUpdateEntry(TIntermNode *_parent,
TIntermNode *_original,
TIntermNode *_replacement)
: parent(_parent),
original(_original),
replacement(_replacement) {}
TIntermNode *parent;
TIntermNode *original;
TIntermNode *replacement;
};
// During traversing, save all the replacements that need to happen;
// then replace them by calling updateNodes().
std::vector<NodeUpdateEntry> replacements;
DISALLOW_COPY_AND_ASSIGN(UnfoldShortCircuitAST); DISALLOW_COPY_AND_ASSIGN(UnfoldShortCircuitAST);
}; };
......
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