Source

Target

Showing with 509 additions and 394 deletions
//
// Copyright (c) 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.
//
// SwapChainPanelNativeWindow.h: NativeWindow for managing ISwapChainPanel native window types.
#ifndef COMMON_WINRT_SWAPCHAINPANELNATIVEWINDOW_H_
#define COMMON_WINRT_SWAPCHAINPANELNATIVEWINDOW_H_
#include "common/winrt/InspectableNativeWindow.h"
namespace rx
{
class SwapChainPanelNativeWindow : public InspectableNativeWindow, public std::enable_shared_from_this<SwapChainPanelNativeWindow>
{
public:
~SwapChainPanelNativeWindow();
bool initialize(EGLNativeWindowType window, EGLNativeDisplayType display, IPropertySet *propertySet);
bool registerForSizeChangeEvents();
void unregisterForSizeChangeEvents();
HRESULT createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain);
HRESULT scaleSwapChain(const SIZE &newSize);
private:
ComPtr<ABI::Windows::UI::Xaml::Controls::ISwapChainPanel> mSwapChainPanel;
ComPtr<IMap<HSTRING, IInspectable*>> mPropertyMap;
ComPtr<DXGISwapChain> mSwapChain;
};
[uuid(8ACBD974-8187-4508-AD80-AEC77F93CF36)]
class SwapChainPanelSizeChangedHandler :
public Microsoft::WRL::RuntimeClass<Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>, ABI::Windows::UI::Xaml::ISizeChangedEventHandler>
{
public:
SwapChainPanelSizeChangedHandler() { }
HRESULT RuntimeClassInitialize(std::shared_ptr<InspectableNativeWindow> host)
{
if (!host)
{
return E_INVALIDARG;
}
mHost = host;
return S_OK;
}
// ISizeChangedEventHandler
IFACEMETHOD(Invoke)(IInspectable *sender, ABI::Windows::UI::Xaml::ISizeChangedEventArgs *sizeChangedEventArgs)
{
std::shared_ptr<InspectableNativeWindow> host = mHost.lock();
if (host)
{
// The size of the ISwapChainPanel control is returned in DIPs.
// We are keeping these in dips because the swapchain created for composition
// also uses dip units. This keeps dimensions, viewports, etc in the same unit.
// XAML Clients of the ISwapChainPanel are required to use dips to define their
// layout sizes as well.
ABI::Windows::Foundation::Size newSize;
HRESULT result = sizeChangedEventArgs->get_NewSize(&newSize);
if (SUCCEEDED(result))
{
SIZE windowSize = { lround(newSize.Width), lround(newSize.Height) };
host->setNewClientSize(windowSize);
}
}
return S_OK;
}
private:
std::weak_ptr<InspectableNativeWindow> mHost;
};
HRESULT GetSwapChainPanelSize(const ComPtr<ABI::Windows::UI::Xaml::Controls::ISwapChainPanel> &swapChainPanel, RECT *windowSize);
}
#endif // COMMON_WINRT_SWAPCHAINPANELNATIVEWINDOW_H_
......@@ -29,7 +29,8 @@ class DirectiveHandler
// Handle pragma of form: #pragma name[(value)]
virtual void handlePragma(const SourceLocation &loc,
const std::string &name,
const std::string &value) = 0;
const std::string &value,
bool stdgl) = 0;
virtual void handleExtension(const SourceLocation &loc,
const std::string &name,
......
......@@ -38,19 +38,19 @@ enum DirectiveType
DirectiveType getDirective(const pp::Token *token)
{
static const std::string kDirectiveDefine("define");
static const std::string kDirectiveUndef("undef");
static const std::string kDirectiveIf("if");
static const std::string kDirectiveIfdef("ifdef");
static const std::string kDirectiveIfndef("ifndef");
static const std::string kDirectiveElse("else");
static const std::string kDirectiveElif("elif");
static const std::string kDirectiveEndif("endif");
static const std::string kDirectiveError("error");
static const std::string kDirectivePragma("pragma");
static const std::string kDirectiveExtension("extension");
static const std::string kDirectiveVersion("version");
static const std::string kDirectiveLine("line");
const char kDirectiveDefine[] = "define";
const char kDirectiveUndef[] = "undef";
const char kDirectiveIf[] = "if";
const char kDirectiveIfdef[] = "ifdef";
const char kDirectiveIfndef[] = "ifndef";
const char kDirectiveElse[] = "else";
const char kDirectiveElif[] = "elif";
const char kDirectiveEndif[] = "endif";
const char kDirectiveError[] = "error";
const char kDirectivePragma[] = "pragma";
const char kDirectiveExtension[] = "extension";
const char kDirectiveVersion[] = "version";
const char kDirectiveLine[] = "line";
if (token->type != pp::Token::IDENTIFIER)
return DIRECTIVE_NONE;
......@@ -155,7 +155,7 @@ class DefinedParser : public Lexer
protected:
virtual void lex(Token *token)
{
static const std::string kDefined("defined");
const char kDefined[] = "defined";
mLexer->lex(token);
if (token->type != Token::IDENTIFIER)
......@@ -592,6 +592,11 @@ void DirectiveParser::parsePragma(Token *token)
int state = PRAGMA_NAME;
mTokenizer->lex(token);
bool stdgl = token->text == "STDGL";
if (stdgl)
{
mTokenizer->lex(token);
}
while ((token->type != '\n') && (token->type != Token::LAST))
{
switch(state++)
......@@ -627,7 +632,7 @@ void DirectiveParser::parsePragma(Token *token)
}
else if (state > PRAGMA_NAME) // Do not notify for empty pragma.
{
mDirectiveHandler->handlePragma(token->location, name, value);
mDirectiveHandler->handlePragma(token->location, name, value, stdgl);
}
}
......
......@@ -194,8 +194,8 @@ bool MacroExpander::expandMacro(const Macro &macro,
if (macro.predefined)
{
static const std::string kLine = "__LINE__";
static const std::string kFile = "__FILE__";
const char kLine[] = "__LINE__";
const char kFile[] = "__FILE__";
assert(replacements->size() == 1);
Token& repl = replacements->front();
......
......@@ -29,24 +29,27 @@
bool IsWebGLBasedSpec(ShShaderSpec spec)
{
return spec == SH_WEBGL_SPEC || spec == SH_CSS_SHADERS_SPEC;
return (spec == SH_WEBGL_SPEC ||
spec == SH_CSS_SHADERS_SPEC ||
spec == SH_WEBGL2_SPEC);
}
size_t GetGlobalMaxTokenSize(ShShaderSpec spec)
{
// WebGL defines a max token legnth of 256, while ES2 leaves max token
// size undefined. ES3 defines a max size of 1024 characters.
if (IsWebGLBasedSpec(spec))
switch (spec)
{
case SH_WEBGL_SPEC:
case SH_CSS_SHADERS_SPEC:
return 256;
}
else
{
default:
return 1024;
}
}
namespace {
class TScopedPoolAllocator
{
public:
......@@ -82,6 +85,24 @@ class TScopedSymbolTableLevel
private:
TSymbolTable* mTable;
};
int MapSpecToShaderVersion(ShShaderSpec spec)
{
switch (spec)
{
case SH_GLES2_SPEC:
case SH_WEBGL_SPEC:
case SH_CSS_SHADERS_SPEC:
return 100;
case SH_GLES3_SPEC:
case SH_WEBGL2_SPEC:
return 300;
default:
UNREACHABLE();
return 0;
}
}
} // namespace
TShHandleBase::TShHandleBase()
......@@ -178,9 +199,21 @@ bool TCompiler::compile(const char* const shaderStrings[],
(parseContext.treeRoot != NULL);
shaderVersion = parseContext.getShaderVersion();
if (success && MapSpecToShaderVersion(shaderSpec) < shaderVersion)
{
infoSink.info.prefix(EPrefixError);
infoSink.info << "unsupported shader version";
success = false;
}
if (success)
{
mPragma = parseContext.pragma();
if (mPragma.stdgl.invariantAll)
{
symbolTable.setGlobalInvariant();
}
TIntermNode* root = parseContext.treeRoot;
success = intermediate.postProcess(root);
......@@ -360,7 +393,8 @@ void TCompiler::setResourceString()
<< ":MaxVertexOutputVectors:" << compileResources.MaxVertexOutputVectors
<< ":MaxFragmentInputVectors:" << compileResources.MaxFragmentInputVectors
<< ":MinProgramTexelOffset:" << compileResources.MinProgramTexelOffset
<< ":MaxProgramTexelOffset:" << compileResources.MaxProgramTexelOffset;
<< ":MaxProgramTexelOffset:" << compileResources.MaxProgramTexelOffset
<< ":NV_draw_buffers:" << compileResources.NV_draw_buffers;
builtInResourcesString = strstream.str();
}
......@@ -377,7 +411,6 @@ void TCompiler::clearResults()
uniforms.clear();
expandedUniforms.clear();
varyings.clear();
expandedVaryings.clear();
interfaceBlocks.clear();
builtInFunctionEmulator.Cleanup();
......@@ -507,13 +540,12 @@ void TCompiler::collectVariables(TIntermNode* root)
&uniforms,
&varyings,
&interfaceBlocks,
hashFunction);
hashFunction,
symbolTable);
root->traverse(&collect);
// For backwards compatiblity with ShGetVariableInfo, expand struct
// uniforms and varyings into separate variables for each field.
sh::ExpandVariables(uniforms, &expandedUniforms);
sh::ExpandVariables(varyings, &expandedVaryings);
// This is for enforcePackingRestriction().
sh::ExpandUniforms(uniforms, &expandedUniforms);
}
bool TCompiler::enforcePackingRestrictions()
......@@ -581,3 +613,10 @@ const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const
{
return builtInFunctionEmulator;
}
void TCompiler::writePragma()
{
TInfoSinkBase &sink = infoSink.obj;
if (mPragma.stdgl.invariantAll)
sink << "#pragma STDGL invariant(all)\n";
}
......@@ -18,6 +18,7 @@
#include "compiler/translator/ExtensionBehavior.h"
#include "compiler/translator/HashNames.h"
#include "compiler/translator/InfoSink.h"
#include "compiler/translator/Pragma.h"
#include "compiler/translator/SymbolTable.h"
#include "compiler/translator/VariableInfo.h"
#include "third_party/compiler/ArrayBoundsClamper.h"
......@@ -71,9 +72,7 @@ class TCompiler : public TShHandleBase
const std::vector<sh::Attribute> &getAttributes() const { return attributes; }
const std::vector<sh::Attribute> &getOutputVariables() const { return outputVariables; }
const std::vector<sh::Uniform> &getUniforms() const { return uniforms; }
const std::vector<sh::ShaderVariable> &getExpandedUniforms() const { return expandedUniforms; }
const std::vector<sh::Varying> &getVaryings() const { return varyings; }
const std::vector<sh::ShaderVariable> &getExpandedVaryings() const { return expandedVaryings; }
const std::vector<sh::InterfaceBlock> &getInterfaceBlocks() const { return interfaceBlocks; }
ShHashFunction64 getHashFunction() const { return hashFunction; }
......@@ -81,7 +80,7 @@ class TCompiler : public TShHandleBase
TSymbolTable& getSymbolTable() { return symbolTable; }
ShShaderSpec getShaderSpec() const { return shaderSpec; }
ShShaderOutput getOutputType() const { return outputType; }
std::string getBuiltInResourcesString() const { return builtInResourcesString; }
const std::string &getBuiltInResourcesString() const { return builtInResourcesString; }
// Get the resources set by InitBuiltInSymbolTable
const ShBuiltInResources& getResources() const;
......@@ -131,6 +130,8 @@ class TCompiler : public TShHandleBase
bool limitExpressionComplexity(TIntermNode* root);
// Get built-in extensions with default behavior.
const TExtensionBehavior& getExtensionBehavior() const;
const TPragma& getPragma() const { return mPragma; }
void writePragma();
const ArrayBoundsClamper& getArrayBoundsClamper() const;
ShArrayIndexClampingStrategy getArrayIndexClampingStrategy() const;
......@@ -141,7 +142,6 @@ class TCompiler : public TShHandleBase
std::vector<sh::Uniform> uniforms;
std::vector<sh::ShaderVariable> expandedUniforms;
std::vector<sh::Varying> varyings;
std::vector<sh::ShaderVariable> expandedVaryings;
std::vector<sh::InterfaceBlock> interfaceBlocks;
private:
......@@ -174,6 +174,8 @@ class TCompiler : public TShHandleBase
// name hashing.
ShHashFunction64 hashFunction;
NameMap nameMap;
TPragma mPragma;
};
//
......
......@@ -14,6 +14,9 @@
namespace sh
{
// Detect Loop Discontinuity
bool DetectLoopDiscontinuity::traverse(TIntermNode *node)
{
mLoopDepth = 0;
......@@ -74,6 +77,55 @@ bool containsLoopDiscontinuity(TIntermNode *node)
return detectLoopDiscontinuity.traverse(node);
}
// Detect Any Loop
bool DetectAnyLoop::traverse(TIntermNode *node)
{
mHasLoop = false;
node->traverse(this);
return mHasLoop;
}
bool DetectAnyLoop::visitLoop(Visit visit, TIntermLoop *loop)
{
mHasLoop = true;
return false;
}
// The following definitions stop all traversal when we have found a loop
bool DetectAnyLoop::visitBinary(Visit, TIntermBinary *)
{
return !mHasLoop;
}
bool DetectAnyLoop::visitUnary(Visit, TIntermUnary *)
{
return !mHasLoop;
}
bool DetectAnyLoop::visitSelection(Visit, TIntermSelection *)
{
return !mHasLoop;
}
bool DetectAnyLoop::visitAggregate(Visit, TIntermAggregate *)
{
return !mHasLoop;
}
bool DetectAnyLoop::visitBranch(Visit, TIntermBranch *)
{
return !mHasLoop;
}
bool containsAnyLoop(TIntermNode *node)
{
DetectAnyLoop detectAnyLoop;
return detectAnyLoop.traverse(node);
}
// Detect Gradient Operation
bool DetectGradientOperation::traverse(TIntermNode *node)
{
mGradientOperation = false;
......
......@@ -32,6 +32,25 @@ class DetectLoopDiscontinuity : public TIntermTraverser
bool containsLoopDiscontinuity(TIntermNode *node);
// Checks for the existence of any loop
class DetectAnyLoop : public TIntermTraverser
{
public:
bool traverse(TIntermNode *node);
protected:
bool visitBinary(Visit, TIntermBinary *);
bool visitUnary(Visit, TIntermUnary *);
bool visitSelection(Visit, TIntermSelection *);
bool visitAggregate(Visit, TIntermAggregate *);
bool visitLoop(Visit, TIntermLoop *);
bool visitBranch(Visit, TIntermBranch *);
bool mHasLoop;
};
bool containsAnyLoop(TIntermNode *node);
// Checks for intrinsic functions which compute gradients
class DetectGradientOperation : public TIntermTraverser
{
......
......@@ -13,10 +13,10 @@
static TBehavior getBehavior(const std::string& str)
{
static const std::string kRequire("require");
static const std::string kEnable("enable");
static const std::string kDisable("disable");
static const std::string kWarn("warn");
const char kRequire[] = "require";
const char kEnable[] = "enable";
const char kDisable[] = "disable";
const char kWarn[] = "warn";
if (str == kRequire) return EBhRequire;
else if (str == kEnable) return EBhEnable;
......@@ -46,50 +46,61 @@ void TDirectiveHandler::handleError(const pp::SourceLocation& loc,
void TDirectiveHandler::handlePragma(const pp::SourceLocation& loc,
const std::string& name,
const std::string& value)
const std::string& value,
bool stdgl)
{
static const std::string kSTDGL("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)
if (stdgl)
{
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
// revisions of GLSL. Ignore it.
// revisions of GLSL. Do not generate an error on unexpected
// name and value.
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
{
mDiagnostics.report(pp::Diagnostics::PP_UNRECOGNIZED_PRAGMA, loc, name);
return;
}
const char kOptimize[] = "optimize";
const char kDebug[] = "debug";
const char kOn[] = "on";
const char kOff[] = "off";
if (invalidValue)
mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc,
"invalid pragma value", value,
"'on' or 'off' expected");
bool invalidValue = false;
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
{
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,
const std::string& name,
const std::string& behavior)
{
static const std::string kExtAll("all");
const char kExtAll[] = "all";
TBehavior behaviorVal = getBehavior(behavior);
if (behaviorVal == EBhUndefined)
......
......@@ -29,7 +29,8 @@ class TDirectiveHandler : public pp::DirectiveHandler
virtual void handlePragma(const pp::SourceLocation& loc,
const std::string& name,
const std::string& value);
const std::string& value,
bool stdgl);
virtual void handleExtension(const pp::SourceLocation& loc,
const std::string& name,
......
......@@ -133,6 +133,14 @@ bool CompareStructure(const TType &leftNodeType,
//
////////////////////////////////////////////////////////////////
void TIntermTyped::setTypePreservePrecision(const TType &t)
{
TPrecision precision = getPrecision();
mType = t;
ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
mType.setPrecision(precision);
}
#define REPLACE_IF_IS(node, type, original, replacement) \
if (node == original) { \
node = static_cast<type *>(replacement); \
......@@ -237,6 +245,52 @@ void TIntermAggregate::enqueueChildren(std::queue<TIntermNode *> *nodeQueue) con
}
}
void TIntermAggregate::setPrecisionFromChildren()
{
if (getBasicType() == EbtBool)
{
mType.setPrecision(EbpUndefined);
return;
}
TPrecision precision = EbpUndefined;
TIntermSequence::iterator childIter = mSequence.begin();
while (childIter != mSequence.end())
{
TIntermTyped *typed = (*childIter)->getAsTyped();
if (typed)
precision = GetHigherPrecision(typed->getPrecision(), precision);
++childIter;
}
mType.setPrecision(precision);
}
void TIntermAggregate::setBuiltInFunctionPrecision()
{
// All built-ins returning bool should be handled as ops, not functions.
ASSERT(getBasicType() != EbtBool);
TPrecision precision = EbpUndefined;
TIntermSequence::iterator childIter = mSequence.begin();
while (childIter != mSequence.end())
{
TIntermTyped *typed = (*childIter)->getAsTyped();
// ESSL spec section 8: texture functions get their precision from the sampler.
if (typed && IsSampler(typed->getBasicType()))
{
precision = typed->getPrecision();
break;
}
++childIter;
}
// ESSL 3.0 spec section 8: textureSize always gets highp precision.
// All other functions that take a sampler are assumed to be texture functions.
if (mName.find("textureSize") == 0)
mType.setPrecision(EbpHigh);
else
mType.setPrecision(precision);
}
bool TIntermSelection::replaceChildNode(
TIntermNode *original, TIntermNode *replacement)
{
......@@ -336,6 +390,7 @@ bool TIntermUnary::promote(TInfoSink &)
return false;
break;
case EOpNegative:
case EOpPositive:
case EOpPostIncrement:
case EOpPostDecrement:
case EOpPreIncrement:
......@@ -1068,6 +1123,27 @@ TIntermTyped *TIntermConstantUnion::fold(
}
break;
case EOpPositive:
switch (getType().getBasicType())
{
case EbtFloat:
tempConstArray[i].setFConst(unionArray[i].getFConst());
break;
case EbtInt:
tempConstArray[i].setIConst(unionArray[i].getIConst());
break;
case EbtUInt:
tempConstArray[i].setUConst(static_cast<unsigned int>(
static_cast<int>(unionArray[i].getUConst())));
break;
default:
infoSink.info.message(
EPrefixInternalError, getLine(),
"Unary operation not folded into constant");
return NULL;
}
break;
case EOpLogicalNot:
// this code is written for possible future use,
// will not get executed currently
......
......@@ -45,6 +45,7 @@ enum TOperator
//
EOpNegative,
EOpPositive,
EOpLogicalNot,
EOpVectorLogicalNot,
......@@ -265,6 +266,7 @@ class TIntermTyped : public TIntermNode
virtual bool hasSideEffects() const = 0;
void setType(const TType &t) { mType = t; }
void setTypePreservePrecision(const TType &t);
const TType &getType() const { return mType; }
TType *getTypePointer() { return &mType; }
......@@ -613,6 +615,9 @@ class TIntermAggregate : public TIntermOperator
virtual void enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const;
void setPrecisionFromChildren();
void setBuiltInFunctionPrecision();
protected:
TIntermAggregate(const TIntermAggregate &); // disallow copy constructor
TIntermAggregate &operator=(const TIntermAggregate &); // disallow assignment operator
......
......@@ -198,6 +198,7 @@ TIntermTyped *TIntermediate::addUnaryMath(
case EOpPostDecrement:
case EOpPreDecrement:
case EOpNegative:
case EOpPositive:
if (child->getType().getBasicType() == EbtStruct ||
child->getType().isArray())
{
......
......@@ -395,6 +395,7 @@ bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
switch (node->getOp())
{
case EOpNegative: preString = "(-"; break;
case EOpPositive: preString = "(+"; break;
case EOpVectorLogicalNot: preString = "not("; break;
case EOpLogicalNot: preString = "(!"; break;
......@@ -574,7 +575,7 @@ bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
// Function declaration.
ASSERT(visit == PreVisit);
writeVariableType(node->getType());
out << " " << hashName(node->getName());
out << " " << hashFunctionName(node->getName());
out << "(";
writeFunctionParameters(*(node->getSequence()));
......@@ -649,17 +650,18 @@ bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
mDeclaringVariables = false;
}
break;
case EOpInvariantDeclaration: {
// Invariant declaration.
ASSERT(visit == PreVisit);
case EOpInvariantDeclaration:
// Invariant declaration.
ASSERT(visit == PreVisit);
{
const TIntermSequence *sequence = node->getSequence();
ASSERT(sequence && sequence->size() == 1);
const TIntermSymbol *symbol = sequence->front()->getAsSymbolNode();
ASSERT(symbol);
out << "invariant " << symbol->getSymbol() << ";";
visitChildren = false;
break;
out << "invariant " << hashVariableName(symbol->getSymbol());
}
visitChildren = false;
break;
case EOpConstructFloat:
writeTriplet(visit, "float(", NULL, ")");
break;
......@@ -741,7 +743,7 @@ bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
writeBuiltInFunctionTriplet(visit, "notEqual(", useEmulatedFunction);
break;
case EOpComma:
writeTriplet(visit, NULL, ", ", NULL);
writeTriplet(visit, "(", ", ", ")");
break;
case EOpMod:
......
......@@ -135,6 +135,7 @@ OutputHLSL::OutputHLSL(TParseContext &context, TranslatorHLSL *parentTranslator)
mUniqueIndex = 0;
mContainsLoopDiscontinuity = false;
mContainsAnyLoop = false;
mOutputLod0Function = false;
mInsideDiscontinuousLoop = false;
mNestedLoopDepth = 0;
......@@ -172,6 +173,7 @@ OutputHLSL::~OutputHLSL()
void OutputHLSL::output()
{
mContainsLoopDiscontinuity = mContext.shaderType == GL_FRAGMENT_SHADER && containsLoopDiscontinuity(mContext.treeRoot);
mContainsAnyLoop = containsAnyLoop(mContext.treeRoot);
const std::vector<TIntermTyped*> &flaggedStructs = FlagStd140ValueStructs(mContext.treeRoot);
makeFlaggedStructMaps(flaggedStructs);
......@@ -320,14 +322,22 @@ void OutputHLSL::header()
if (mUsesDiscardRewriting)
{
out << "#define ANGLE_USES_DISCARD_REWRITING" << "\n";
out << "#define ANGLE_USES_DISCARD_REWRITING\n";
}
if (mUsesNestedBreak)
{
out << "#define ANGLE_USES_NESTED_BREAK" << "\n";
out << "#define ANGLE_USES_NESTED_BREAK\n";
}
out << "#ifdef ANGLE_ENABLE_LOOP_FLATTEN\n"
"#define LOOP [loop]\n"
"#define FLATTEN [flatten]\n"
"#else\n"
"#define LOOP\n"
"#define FLATTEN\n"
"#endif\n";
if (mContext.shaderType == GL_FRAGMENT_SHADER)
{
TExtensionBehavior::const_iterator iter = mContext.extensionBehavior().find("GL_EXT_draw_buffers");
......@@ -1747,6 +1757,7 @@ bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
switch (node->getOp())
{
case EOpNegative: outputTriplet(visit, "(-", "", ")"); break;
case EOpPositive: outputTriplet(visit, "(+", "", ")"); break;
case EOpVectorLogicalNot: outputTriplet(visit, "(!", "", ")"); break;
case EOpLogicalNot: outputTriplet(visit, "(!", "", ")"); break;
case EOpPostIncrement: outputTriplet(visit, "(", "", "++)"); break;
......@@ -1860,15 +1871,20 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
if (!variable->getAsSymbolNode() || variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration
{
if (!mInsideFunction)
for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); sit++)
{
out << "static ";
}
if (isSingleStatement(*sit))
{
mUnfoldShortCircuit->traverse(*sit);
}
out << TypeString(variable->getType()) + " ";
if (!mInsideFunction)
{
out << "static ";
}
out << TypeString(variable->getType()) + " ";
for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); sit++)
{
TIntermSymbol *symbol = (*sit)->getAsSymbolNode();
if (symbol)
......@@ -1884,7 +1900,7 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
if (*sit != sequence->back())
{
out << ", ";
out << ";\n";
}
}
}
......@@ -1925,7 +1941,7 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
case EOpPrototype:
if (visit == PreVisit)
{
out << TypeString(node->getType()) << " " << Decorate(node->getName()) << (mOutputLod0Function ? "Lod0(" : "(");
out << TypeString(node->getType()) << " " << Decorate(TFunction::unmangleName(node->getName())) << (mOutputLod0Function ? "Lod0(" : "(");
TIntermSequence *arguments = node->getSequence();
......@@ -2287,6 +2303,15 @@ bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node)
{
mUnfoldShortCircuit->traverse(node->getCondition());
// D3D errors when there is a gradient operation in a loop in an unflattened if
// however flattening all the ifs in branch heavy shaders made D3D error too.
// As a temporary workaround we flatten the ifs only if there is at least a loop
// present somewhere in the shader.
if (mContext.shaderType == GL_FRAGMENT_SHADER && mContainsAnyLoop)
{
out << "FLATTEN ";
}
out << "if (";
node->getCondition()->traverse(this);
......@@ -2367,14 +2392,14 @@ bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
if (node->getType() == ELoopDoWhile)
{
out << "{do\n";
out << "{LOOP do\n";
outputLineDirective(node->getLine().first_line);
out << "{\n";
}
else
{
out << "{for(";
out << "{LOOP for(";
if (node->getInit())
{
......@@ -2503,6 +2528,12 @@ bool OutputHLSL::isSingleStatement(TIntermNode *node)
{
return false;
}
else if (aggregate->getOp() == EOpDeclaration)
{
// Declaring multiple comma-separated variables must be considered multiple statements
// because each individual declaration has side effects which are visible in the next.
return false;
}
else
{
for (TIntermSequence::iterator sit = aggregate->getSequence()->begin(); sit != aggregate->getSequence()->end(); sit++)
......@@ -2675,7 +2706,7 @@ bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node)
// for(int index = initial; index < clampedLimit; index += increment)
out << "for(";
out << "LOOP for(";
index->traverse(this);
out << " = ";
out << initial;
......
......@@ -144,6 +144,7 @@ class OutputHLSL : public TIntermTraverser
int mUniqueIndex; // For creating unique names
bool mContainsLoopDiscontinuity;
bool mContainsAnyLoop;
bool mOutputLod0Function;
bool mInsideDiscontinuousLoop;
int mNestedLoopDepth;
......
......@@ -1004,12 +1004,12 @@ void TParseContext::handleExtensionDirective(const TSourceLoc& loc, const char*
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;
srcLoc.file = loc.first_file;
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
{
error(identifierLoc, "undeclared identifier declared as invariant", identifier->c_str());
recover();
return NULL;
}
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);
ASSERT(variable);
const TType &type = variable->getType();
......
......@@ -116,7 +116,7 @@ struct TParseContext {
bool supportsExtension(const char* extension);
bool isExtensionEnabled(const char* extension) const;
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 areAllChildConst(TIntermAggregate* aggrNode);
......
......@@ -7,13 +7,23 @@
#ifndef 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.
TPragma() : optimize(true), debug(false) { }
TPragma(bool o, bool d) : optimize(o), debug(d) { }
bool optimize;
bool debug;
STDGL stdgl;
};
#endif // COMPILER_PRAGMA_H_
......@@ -37,72 +37,6 @@ bool isInitialized = false;
// and the shading language compiler.
//
static bool CheckVariableMaxLengths(const ShHandle handle,
size_t expectedValue)
{
size_t activeUniformLimit = 0;
ShGetInfo(handle, SH_ACTIVE_UNIFORM_MAX_LENGTH, &activeUniformLimit);
size_t activeAttribLimit = 0;
ShGetInfo(handle, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, &activeAttribLimit);
size_t varyingLimit = 0;
ShGetInfo(handle, SH_VARYING_MAX_LENGTH, &varyingLimit);
return (expectedValue == activeUniformLimit &&
expectedValue == activeAttribLimit &&
expectedValue == varyingLimit);
}
bool CheckMappedNameMaxLength(const ShHandle handle, size_t expectedValue)
{
size_t mappedNameMaxLength = 0;
ShGetInfo(handle, SH_MAPPED_NAME_MAX_LENGTH, &mappedNameMaxLength);
return (expectedValue == mappedNameMaxLength);
}
template <typename VarT>
const sh::ShaderVariable *ReturnVariable(const std::vector<VarT> &infoList, int index)
{
if (index < 0 || static_cast<size_t>(index) >= infoList.size())
{
return NULL;
}
return &infoList[index];
}
const sh::ShaderVariable *GetVariable(const TCompiler *compiler, ShShaderInfo varType, int index)
{
switch (varType)
{
case SH_ACTIVE_ATTRIBUTES:
return ReturnVariable(compiler->getAttributes(), index);
case SH_ACTIVE_UNIFORMS:
return ReturnVariable(compiler->getExpandedUniforms(), index);
case SH_VARYINGS:
return ReturnVariable(compiler->getExpandedVaryings(), index);
default:
UNREACHABLE();
return NULL;
}
}
ShPrecisionType ConvertPrecision(sh::GLenum precision)
{
switch (precision)
{
case GL_HIGH_FLOAT:
case GL_HIGH_INT:
return SH_PRECISION_HIGHP;
case GL_MEDIUM_FLOAT:
case GL_MEDIUM_INT:
return SH_PRECISION_MEDIUMP;
case GL_LOW_FLOAT:
case GL_LOW_INT:
return SH_PRECISION_LOWP;
default:
return SH_PRECISION_UNDEFINED;
}
}
template <typename VarT>
const std::vector<VarT> *GetVariableList(const TCompiler *compiler, ShaderVariableType variableType);
......@@ -150,32 +84,48 @@ const std::vector<VarT> *GetShaderVariables(const ShHandle handle, ShaderVariabl
return GetVariableList<VarT>(compiler, variableType);
}
TCompiler *GetCompilerFromHandle(ShHandle handle)
{
if (!handle)
return NULL;
TShHandleBase *base = static_cast<TShHandleBase *>(handle);
return base->getAsCompiler();
}
TranslatorHLSL *GetTranslatorHLSLFromHandle(ShHandle handle)
{
if (!handle)
return NULL;
TShHandleBase *base = static_cast<TShHandleBase *>(handle);
return base->getAsTranslatorHLSL();
}
} // namespace anonymous
//
// Driver must call this first, once, before doing any other compiler operations.
// Subsequent calls to this function are no-op.
//
int ShInitialize()
bool ShInitialize()
{
if (!isInitialized)
{
isInitialized = InitProcess();
}
return isInitialized ? 1 : 0;
return isInitialized;
}
//
// Cleanup symbol tables
//
int ShFinalize()
bool ShFinalize()
{
if (isInitialized)
{
DetachProcess();
isInitialized = false;
}
return 1;
return true;
}
//
......@@ -183,6 +133,9 @@ int ShFinalize()
//
void ShInitBuiltInResources(ShBuiltInResources* resources)
{
// Make comparable.
memset(resources, 0, sizeof(*resources));
// Constants.
resources->MaxVertexAttribs = 8;
resources->MaxVertexUniformVectors = 128;
......@@ -201,6 +154,8 @@ void ShInitBuiltInResources(ShBuiltInResources* resources)
resources->EXT_frag_depth = 0;
resources->EXT_shader_texture_lod = 0;
resources->NV_draw_buffers = 0;
// Disable highp precision in fragment shader by default.
resources->FragmentPrecisionHigh = 0;
......@@ -251,23 +206,13 @@ void ShDestruct(ShHandle handle)
DeleteCompiler(base->getAsCompiler());
}
void ShGetBuiltInResourcesString(const ShHandle handle, size_t outStringLen, char *outString)
const std::string &ShGetBuiltInResourcesString(const ShHandle handle)
{
if (!handle || !outString)
{
return;
}
TShHandleBase *base = static_cast<TShHandleBase*>(handle);
TCompiler *compiler = base->getAsCompiler();
if (!compiler)
{
return;
}
strncpy(outString, compiler->getBuiltInResourcesString().c_str(), outStringLen);
outString[outStringLen - 1] = '\0';
TCompiler *compiler = GetCompilerFromHandle(handle);
ASSERT(compiler);
return compiler->getBuiltInResourcesString();
}
//
// Do an actual compile on the given strings. The result is left
// in the given compile object.
......@@ -275,219 +220,62 @@ void ShGetBuiltInResourcesString(const ShHandle handle, size_t outStringLen, cha
// Return: The return value of ShCompile is really boolean, indicating
// success or failure.
//
int ShCompile(
bool ShCompile(
const ShHandle handle,
const char* const shaderStrings[],
const char *const shaderStrings[],
size_t numStrings,
int compileOptions)
{
if (handle == 0)
return 0;
TCompiler *compiler = GetCompilerFromHandle(handle);
ASSERT(compiler);
TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
TCompiler* compiler = base->getAsCompiler();
if (compiler == 0)
return 0;
bool success = compiler->compile(shaderStrings, numStrings, compileOptions);
return success ? 1 : 0;
return compiler->compile(shaderStrings, numStrings, compileOptions);
}
void ShGetInfo(const ShHandle handle, ShShaderInfo pname, size_t* params)
int ShGetShaderVersion(const ShHandle handle)
{
if (!handle || !params)
return;
TShHandleBase* base = static_cast<TShHandleBase*>(handle);
TCompiler* compiler = base->getAsCompiler();
if (!compiler) return;
TCompiler* compiler = GetCompilerFromHandle(handle);
ASSERT(compiler);
return compiler->getShaderVersion();
}
switch(pname)
{
case SH_INFO_LOG_LENGTH:
*params = compiler->getInfoSink().info.size() + 1;
break;
case SH_OBJECT_CODE_LENGTH:
*params = compiler->getInfoSink().obj.size() + 1;
break;
case SH_ACTIVE_UNIFORMS:
*params = compiler->getExpandedUniforms().size();
break;
case SH_ACTIVE_UNIFORM_MAX_LENGTH:
*params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec());
break;
case SH_ACTIVE_ATTRIBUTES:
*params = compiler->getAttributes().size();
break;
case SH_ACTIVE_ATTRIBUTE_MAX_LENGTH:
*params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec());
break;
case SH_VARYINGS:
*params = compiler->getExpandedVaryings().size();
break;
case SH_VARYING_MAX_LENGTH:
*params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec());
break;
case SH_MAPPED_NAME_MAX_LENGTH:
// Use longer length than MAX_SHORTENED_IDENTIFIER_SIZE to
// handle array and struct dereferences.
*params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec());
break;
case SH_NAME_MAX_LENGTH:
*params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec());
break;
case SH_HASHED_NAME_MAX_LENGTH:
if (compiler->getHashFunction() == NULL) {
*params = 0;
} else {
// 64 bits hashing output requires 16 bytes for hex
// representation.
const char HashedNamePrefix[] = HASHED_NAME_PREFIX;
(void)HashedNamePrefix;
*params = 16 + sizeof(HashedNamePrefix);
}
break;
case SH_HASHED_NAMES_COUNT:
*params = compiler->getNameMap().size();
break;
case SH_SHADER_VERSION:
*params = compiler->getShaderVersion();
break;
case SH_RESOURCES_STRING_LENGTH:
*params = compiler->getBuiltInResourcesString().length() + 1;
break;
case SH_OUTPUT_TYPE:
*params = compiler->getOutputType();
break;
default: UNREACHABLE();
}
ShShaderOutput ShGetShaderOutputType(const ShHandle handle)
{
TCompiler* compiler = GetCompilerFromHandle(handle);
ASSERT(compiler);
return compiler->getOutputType();
}
//
// Return any compiler log of messages for the application.
//
void ShGetInfoLog(const ShHandle handle, char* infoLog)
const std::string &ShGetInfoLog(const ShHandle handle)
{
if (!handle || !infoLog)
return;
TCompiler *compiler = GetCompilerFromHandle(handle);
ASSERT(compiler);
TShHandleBase* base = static_cast<TShHandleBase*>(handle);
TCompiler* compiler = base->getAsCompiler();
if (!compiler) return;
TInfoSink& infoSink = compiler->getInfoSink();
strcpy(infoLog, infoSink.info.c_str());
TInfoSink &infoSink = compiler->getInfoSink();
return infoSink.info.str();
}
//
// Return any object code.
//
void ShGetObjectCode(const ShHandle handle, char* objCode)
const std::string &ShGetObjectCode(const ShHandle handle)
{
if (!handle || !objCode)
return;
TShHandleBase* base = static_cast<TShHandleBase*>(handle);
TCompiler* compiler = base->getAsCompiler();
if (!compiler) return;
TInfoSink& infoSink = compiler->getInfoSink();
strcpy(objCode, infoSink.obj.c_str());
}
void ShGetVariableInfo(const ShHandle handle,
ShShaderInfo varType,
int index,
size_t* length,
int* size,
sh::GLenum* type,
ShPrecisionType* precision,
int* staticUse,
char* name,
char* mappedName)
{
if (!handle || !size || !type || !precision || !staticUse || !name)
return;
ASSERT((varType == SH_ACTIVE_ATTRIBUTES) ||
(varType == SH_ACTIVE_UNIFORMS) ||
(varType == SH_VARYINGS));
TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
TCompiler* compiler = base->getAsCompiler();
if (compiler == 0)
return;
const sh::ShaderVariable *varInfo = GetVariable(compiler, varType, index);
if (!varInfo)
{
return;
}
TCompiler *compiler = GetCompilerFromHandle(handle);
ASSERT(compiler);
if (length) *length = varInfo->name.size();
*size = varInfo->elementCount();
*type = varInfo->type;
*precision = ConvertPrecision(varInfo->precision);
*staticUse = varInfo->staticUse ? 1 : 0;
// This size must match that queried by
// SH_ACTIVE_UNIFORM_MAX_LENGTH, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, SH_VARYING_MAX_LENGTH
// in ShGetInfo, below.
size_t variableLength = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec());
ASSERT(CheckVariableMaxLengths(handle, variableLength));
strncpy(name, varInfo->name.c_str(), variableLength);
name[variableLength - 1] = 0;
if (mappedName)
{
// This size must match that queried by
// SH_MAPPED_NAME_MAX_LENGTH in ShGetInfo, below.
size_t maxMappedNameLength = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec());
ASSERT(CheckMappedNameMaxLength(handle, maxMappedNameLength));
strncpy(mappedName, varInfo->mappedName.c_str(), maxMappedNameLength);
mappedName[maxMappedNameLength - 1] = 0;
}
TInfoSink &infoSink = compiler->getInfoSink();
return infoSink.obj.str();
}
void ShGetNameHashingEntry(const ShHandle handle,
int index,
char* name,
char* hashedName)
const std::map<std::string, std::string> *ShGetNameHashingMap(
const ShHandle handle)
{
if (!handle || !name || !hashedName || index < 0)
return;
TShHandleBase* base = static_cast<TShHandleBase*>(handle);
TCompiler* compiler = base->getAsCompiler();
if (!compiler) return;
const NameMap& nameMap = compiler->getNameMap();
if (index >= static_cast<int>(nameMap.size()))
return;
NameMap::const_iterator it = nameMap.begin();
for (int i = 0; i < index; ++i)
++it;
size_t len = it->first.length() + 1;
size_t max_len = 0;
ShGetInfo(handle, SH_NAME_MAX_LENGTH, &max_len);
if (len > max_len) {
ASSERT(false);
len = max_len;
}
strncpy(name, it->first.c_str(), len);
// To be on the safe side in case the source is longer than expected.
name[len - 1] = '\0';
len = it->second.length() + 1;
max_len = 0;
ShGetInfo(handle, SH_HASHED_NAME_MAX_LENGTH, &max_len);
if (len > max_len) {
ASSERT(false);
len = max_len;
}
strncpy(hashedName, it->second.c_str(), len);
// To be on the safe side in case the source is longer than expected.
hashedName[len - 1] = '\0';
TCompiler *compiler = GetCompilerFromHandle(handle);
ASSERT(compiler);
return &(compiler->getNameMap());
}
const std::vector<sh::Uniform> *ShGetUniforms(const ShHandle handle)
......@@ -515,11 +303,11 @@ const std::vector<sh::InterfaceBlock> *ShGetInterfaceBlocks(const ShHandle handl
return GetShaderVariables<sh::InterfaceBlock>(handle, SHADERVAR_INTERFACEBLOCK);
}
int ShCheckVariablesWithinPackingLimits(
int maxVectors, ShVariableInfo* varInfoArray, size_t varInfoArraySize)
bool ShCheckVariablesWithinPackingLimits(
int maxVectors, ShVariableInfo *varInfoArray, size_t varInfoArraySize)
{
if (varInfoArraySize == 0)
return 1;
return true;
ASSERT(varInfoArray);
std::vector<sh::ShaderVariable> variables;
for (size_t ii = 0; ii < varInfoArraySize; ++ii)
......@@ -528,24 +316,17 @@ int ShCheckVariablesWithinPackingLimits(
variables.push_back(var);
}
VariablePacker packer;
return packer.CheckVariablesWithinPackingLimits(maxVectors, variables) ? 1 : 0;
return packer.CheckVariablesWithinPackingLimits(maxVectors, variables);
}
bool ShGetInterfaceBlockRegister(const ShHandle handle,
const char *interfaceBlockName,
const std::string &interfaceBlockName,
unsigned int *indexOut)
{
if (!handle || !interfaceBlockName || !indexOut)
{
return false;
}
ASSERT(indexOut);
TShHandleBase* base = static_cast<TShHandleBase*>(handle);
TranslatorHLSL* translator = base->getAsTranslatorHLSL();
if (!translator)
{
return false;
}
TranslatorHLSL *translator = GetTranslatorHLSLFromHandle(handle);
ASSERT(translator);
if (!translator->hasInterfaceBlock(interfaceBlockName))
{
......@@ -557,20 +338,12 @@ bool ShGetInterfaceBlockRegister(const ShHandle handle,
}
bool ShGetUniformRegister(const ShHandle handle,
const char *uniformName,
const std::string &uniformName,
unsigned int *indexOut)
{
if (!handle || !uniformName || !indexOut)
{
return false;
}
TShHandleBase* base = static_cast<TShHandleBase*>(handle);
TranslatorHLSL* translator = base->getAsTranslatorHLSL();
if (!translator)
{
return false;
}
ASSERT(indexOut);
TranslatorHLSL *translator = GetTranslatorHLSLFromHandle(handle);
ASSERT(translator);
if (!translator->hasUniform(uniformName))
{
......