Commit acd2d8a5 by kbr@chromium.org

Incorporated BSD-licensed changes implementing array bounds clamping.

BUG=none TEST=ran associated WebKit layout tests in Chromium Review URL: https://codereview.appspot.com/6999052 git-svn-id: https://angleproject.googlecode.com/svn/trunk@1638 736b8ea6-26fd-11df-bfd4-992fa37f6226
parent 69d97523
...@@ -12,6 +12,7 @@ TransGaming Inc. ...@@ -12,6 +12,7 @@ TransGaming Inc.
3DLabs Inc. Ltd. 3DLabs Inc. Ltd.
Adobe Systems Inc. Adobe Systems Inc.
Apple Inc.
Autodesk, Inc. Autodesk, Inc.
Cloud Party, Inc. Cloud Party, Inc.
Intel Corporation Intel Corporation
......
...@@ -150,7 +150,13 @@ typedef enum { ...@@ -150,7 +150,13 @@ typedef enum {
SH_DEPENDENCY_GRAPH = 0x0400, SH_DEPENDENCY_GRAPH = 0x0400,
// Enforce the GLSL 1.017 Appendix A section 7 packing restrictions. // Enforce the GLSL 1.017 Appendix A section 7 packing restrictions.
SH_ENFORCE_PACKING_RESTRICTIONS = 0x0800 SH_ENFORCE_PACKING_RESTRICTIONS = 0x0800,
// This flag ensures all indirect (expression-based) array indexing
// is clamped to the bounds of the array. This ensures, for example,
// that you cannot read off the end of a uniform, whether an array
// vec234, or mat234 type.
SH_CLAMP_INDIRECT_ARRAY_BOUNDS = 0x1000
} ShCompileOptions; } ShCompileOptions;
// //
......
...@@ -60,6 +60,8 @@ ...@@ -60,6 +60,8 @@
'COMPILER_IMPLEMENTATION', 'COMPILER_IMPLEMENTATION',
], ],
'sources': [ 'sources': [
'compiler/ArrayBoundsClamper.cpp',
'compiler/ArrayBoundsClamper.h',
'compiler/BaseTypes.h', 'compiler/BaseTypes.h',
'compiler/BuiltInFunctionEmulator.cpp', 'compiler/BuiltInFunctionEmulator.cpp',
'compiler/BuiltInFunctionEmulator.h', 'compiler/BuiltInFunctionEmulator.h',
......
#define MAJOR_VERSION 1 #define MAJOR_VERSION 1
#define MINOR_VERSION 0 #define MINOR_VERSION 0
#define BUILD_VERSION 0 #define BUILD_VERSION 0
#define BUILD_REVISION 1563 #define BUILD_REVISION 1638
#define STRINGIFY(x) #x #define STRINGIFY(x) #x
#define MACRO_STRINGIFY(x) STRINGIFY(x) #define MACRO_STRINGIFY(x) STRINGIFY(x)
......
/*
* Copyright (C) 2012 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE, INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "compiler/ArrayBoundsClamper.h"
const char* kIntClampBegin = "// BEGIN: Generated code for array bounds clamping\n\n";
const char* kIntClampEnd = "// END: Generated code for array bounds clamping\n\n";
const char* kIntClampDefinition = "int webgl_int_clamp(int value, int minValue, int maxValue) { return ((value < minValue) ? minValue : ((value > maxValue) ? maxValue : value)); }\n\n";
namespace {
class ArrayBoundsClamperMarker : public TIntermTraverser {
public:
ArrayBoundsClamperMarker()
: mNeedsClamp(false)
{
}
virtual bool visitBinary(Visit visit, TIntermBinary* node)
{
if (node->getOp() == EOpIndexIndirect)
{
TIntermTyped* left = node->getLeft();
if (left->isArray() || left->isVector() || left->isMatrix())
{
node->setAddIndexClamp();
mNeedsClamp = true;
}
}
return true;
}
bool GetNeedsClamp() { return mNeedsClamp; }
private:
bool mNeedsClamp;
};
} // anonymous namespace
ArrayBoundsClamper::ArrayBoundsClamper()
: mArrayBoundsClampDefinitionNeeded(false)
{
}
void ArrayBoundsClamper::OutputClampingFunctionDefinition(TInfoSinkBase& out) const
{
if (!mArrayBoundsClampDefinitionNeeded)
{
return;
}
out << kIntClampBegin << kIntClampDefinition << kIntClampEnd;
}
void ArrayBoundsClamper::MarkIndirectArrayBoundsForClamping(TIntermNode* root)
{
ASSERT(root);
ArrayBoundsClamperMarker clamper;
root->traverse(&clamper);
if (clamper.GetNeedsClamp())
{
SetArrayBoundsClampDefinitionNeeded();
}
}
/*
* Copyright (C) 2012 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE, INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef COMPILER_ARRAY_BOUNDS_CLAMPER_H_
#define COMPILER_ARRAY_BOUNDS_CLAMPER_H_
#include "GLSLANG/ShaderLang.h"
#include "compiler/InfoSink.h"
#include "compiler/intermediate.h"
class ArrayBoundsClamper {
public:
ArrayBoundsClamper();
// Output array clamp function source into the shader source.
void OutputClampingFunctionDefinition(TInfoSinkBase& out) const;
// Marks nodes in the tree that index arrays indirectly as
// requiring clamping.
void MarkIndirectArrayBoundsForClamping(TIntermNode* root);
void Cleanup()
{
mArrayBoundsClampDefinitionNeeded = false;
}
private:
bool GetArrayBoundsClampDefinitionNeeded() const { return mArrayBoundsClampDefinitionNeeded; }
void SetArrayBoundsClampDefinitionNeeded() { mArrayBoundsClampDefinitionNeeded = true; }
bool mArrayBoundsClampDefinitionNeeded;
};
#endif // COMPILER_ARRAY_BOUNDS_CLAMPER_H_
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
// found in the LICENSE file. // found in the LICENSE file.
// //
#include "compiler/ArrayBoundsClamper.h"
#include "compiler/BuiltInFunctionEmulator.h" #include "compiler/BuiltInFunctionEmulator.h"
#include "compiler/DetectRecursion.h" #include "compiler/DetectRecursion.h"
#include "compiler/ForLoopUnroll.h" #include "compiler/ForLoopUnroll.h"
...@@ -192,6 +193,10 @@ bool TCompiler::compile(const char* const shaderStrings[], ...@@ -192,6 +193,10 @@ bool TCompiler::compile(const char* const shaderStrings[],
if (success && (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS)) if (success && (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS))
builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(root); builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(root);
// Clamping uniform array bounds needs to happen after validateLimitations pass.
if (success && (compileOptions & SH_CLAMP_INDIRECT_ARRAY_BOUNDS))
arrayBoundsClamper.MarkIndirectArrayBoundsForClamping(root);
// Call mapLongVariableNames() before collectAttribsUniforms() so in // Call mapLongVariableNames() before collectAttribsUniforms() so in
// collectAttribsUniforms() we already have the mapped symbol names and // collectAttribsUniforms() we already have the mapped symbol names and
// we could composite mapped and original variable names. // we could composite mapped and original variable names.
...@@ -237,6 +242,7 @@ bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources& resources) ...@@ -237,6 +242,7 @@ bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources& resources)
void TCompiler::clearResults() void TCompiler::clearResults()
{ {
arrayBoundsClamper.Cleanup();
infoSink.info.erase(); infoSink.info.erase();
infoSink.obj.erase(); infoSink.obj.erase();
infoSink.debug.erase(); infoSink.debug.erase();
...@@ -353,3 +359,9 @@ const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const ...@@ -353,3 +359,9 @@ const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const
{ {
return builtInFunctionEmulator; return builtInFunctionEmulator;
} }
const ArrayBoundsClamper& TCompiler::getArrayBoundsClamper() const
{
return arrayBoundsClamper;
}
...@@ -212,9 +212,38 @@ bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary* node) ...@@ -212,9 +212,38 @@ bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary* node)
break; break;
case EOpIndexDirect: case EOpIndexDirect:
case EOpIndexIndirect:
writeTriplet(visit, NULL, "[", "]"); writeTriplet(visit, NULL, "[", "]");
break; break;
case EOpIndexIndirect:
if (node->getAddIndexClamp())
{
if (visit == InVisit)
{
out << "[webgl_int_clamp(";
}
else if (visit == PostVisit)
{
int maxSize;
TIntermTyped *left = node->getLeft();
TType leftType = left->getType();
if (left->isArray())
{
// The shader will fail validation if the array length is not > 0.
maxSize = leftType.getArraySize() - 1;
}
else
{
maxSize = leftType.getNominalSize() - 1;
}
out << ", 0, " << maxSize << ")]";
}
}
else
{
writeTriplet(visit, NULL, "[", "]");
}
break;
case EOpIndexDirectStruct: case EOpIndexDirectStruct:
if (visit == InVisit) if (visit == InVisit)
{ {
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "GLSLANG/ShaderLang.h" #include "GLSLANG/ShaderLang.h"
#include "compiler/ArrayBoundsClamper.h"
#include "compiler/BuiltInFunctionEmulator.h" #include "compiler/BuiltInFunctionEmulator.h"
#include "compiler/ExtensionBehavior.h" #include "compiler/ExtensionBehavior.h"
#include "compiler/HashNames.h" #include "compiler/HashNames.h"
...@@ -106,6 +107,7 @@ protected: ...@@ -106,6 +107,7 @@ protected:
// Get built-in extensions with default behavior. // Get built-in extensions with default behavior.
const TExtensionBehavior& getExtensionBehavior() const; const TExtensionBehavior& getExtensionBehavior() const;
const ArrayBoundsClamper& getArrayBoundsClamper() const;
const BuiltInFunctionEmulator& getBuiltInFunctionEmulator() const; const BuiltInFunctionEmulator& getBuiltInFunctionEmulator() const;
private: private:
...@@ -120,6 +122,7 @@ private: ...@@ -120,6 +122,7 @@ private:
// Built-in extensions with default behavior. // Built-in extensions with default behavior.
TExtensionBehavior extensionBehavior; TExtensionBehavior extensionBehavior;
ArrayBoundsClamper arrayBoundsClamper;
BuiltInFunctionEmulator builtInFunctionEmulator; BuiltInFunctionEmulator builtInFunctionEmulator;
// Results of compilation. // Results of compilation.
......
...@@ -22,6 +22,9 @@ void TranslatorESSL::translate(TIntermNode* root) { ...@@ -22,6 +22,9 @@ void TranslatorESSL::translate(TIntermNode* root) {
getBuiltInFunctionEmulator().OutputEmulatedFunctionDefinition( getBuiltInFunctionEmulator().OutputEmulatedFunctionDefinition(
sink, getShaderType() == SH_FRAGMENT_SHADER); sink, getShaderType() == SH_FRAGMENT_SHADER);
// Write array bounds clamping emulation if needed.
getArrayBoundsClamper().OutputClampingFunctionDefinition(sink);
// Write translated shader. // Write translated shader.
TOutputESSL outputESSL(sink, getHashFunction(), getNameMap(), getSymbolTable()); TOutputESSL outputESSL(sink, getHashFunction(), getNameMap(), getSymbolTable());
root->traverse(&outputESSL); root->traverse(&outputESSL);
......
...@@ -35,6 +35,9 @@ void TranslatorGLSL::translate(TIntermNode* root) { ...@@ -35,6 +35,9 @@ void TranslatorGLSL::translate(TIntermNode* root) {
getBuiltInFunctionEmulator().OutputEmulatedFunctionDefinition( getBuiltInFunctionEmulator().OutputEmulatedFunctionDefinition(
sink, false); sink, false);
// Write array bounds clamping emulation if needed.
getArrayBoundsClamper().OutputClampingFunctionDefinition(sink);
// Write translated shader. // Write translated shader.
TOutputGLSL outputGLSL(sink, getHashFunction(), getNameMap(), getSymbolTable()); TOutputGLSL outputGLSL(sink, getHashFunction(), getNameMap(), getSymbolTable());
root->traverse(&outputGLSL); root->traverse(&outputGLSL);
......
...@@ -42,7 +42,7 @@ TString TType::getCompleteString() const ...@@ -42,7 +42,7 @@ TString TType::getCompleteString() const
if (qualifier != EvqTemporary && qualifier != EvqGlobal) if (qualifier != EvqTemporary && qualifier != EvqGlobal)
stream << getQualifierString() << " " << getPrecisionString() << " "; stream << getQualifierString() << " " << getPrecisionString() << " ";
if (array) if (array)
stream << "array of "; stream << "array[" << getArraySize() << "] of ";
if (matrix) if (matrix)
stream << size << "X" << size << " matrix of "; stream << size << "X" << size << " matrix of ";
else if (size > 1) else if (size > 1)
......
...@@ -391,7 +391,7 @@ protected: ...@@ -391,7 +391,7 @@ protected:
// //
class TIntermBinary : public TIntermOperator { class TIntermBinary : public TIntermOperator {
public: public:
TIntermBinary(TOperator o) : TIntermOperator(o) {} TIntermBinary(TOperator o) : TIntermOperator(o), addIndexClamp(false) {}
virtual TIntermBinary* getAsBinaryNode() { return this; } virtual TIntermBinary* getAsBinaryNode() { return this; }
virtual void traverse(TIntermTraverser*); virtual void traverse(TIntermTraverser*);
...@@ -402,9 +402,15 @@ public: ...@@ -402,9 +402,15 @@ public:
TIntermTyped* getRight() const { return right; } TIntermTyped* getRight() const { return right; }
bool promote(TInfoSink&); bool promote(TInfoSink&);
void setAddIndexClamp() { addIndexClamp = true; }
bool getAddIndexClamp() { return addIndexClamp; }
protected: protected:
TIntermTyped* left; TIntermTyped* left;
TIntermTyped* right; TIntermTyped* right;
// If set to true, wrap any EOpIndexIndirect with a clamp to bounds.
bool addIndexClamp;
}; };
// //
......
...@@ -138,6 +138,7 @@ ...@@ -138,6 +138,7 @@
</ClCompile> </ClCompile>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="ArrayBoundsClamper.cpp" />
<ClCompile Include="BuiltInFunctionEmulator.cpp" /> <ClCompile Include="BuiltInFunctionEmulator.cpp" />
<ClCompile Include="Compiler.cpp" /> <ClCompile Include="Compiler.cpp" />
<ClCompile Include="debug.cpp" /> <ClCompile Include="debug.cpp" />
...@@ -225,6 +226,7 @@ ...@@ -225,6 +226,7 @@
</CustomBuild> </CustomBuild>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="ArrayBoundsClamper.h" />
<ClInclude Include="BaseTypes.h" /> <ClInclude Include="BaseTypes.h" />
<ClInclude Include="BuiltInFunctionEmulator.h" /> <ClInclude Include="BuiltInFunctionEmulator.h" />
<ClInclude Include="Common.h" /> <ClInclude Include="Common.h" />
...@@ -279,4 +281,4 @@ ...@@ -279,4 +281,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">
</ImportGroup> </ImportGroup>
</Project> </Project>
\ No newline at end of file
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