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/branches/dx11proto@1701 736b8ea6-26fd-11df-bfd4-992fa37f6226
This commit is contained in:
daniel@transgaming.com 2013-01-11 04:11:53 +00:00
Родитель 761630a947
Коммит 4167cc9102
13 изменённых файлов: 217 добавлений и 5 удалений

Просмотреть файл

@ -12,6 +12,7 @@ TransGaming Inc.
3DLabs Inc. Ltd.
Adobe Systems Inc.
Apple Inc.
Autodesk, Inc.
Cloud Party, Inc.
Intel Corporation

Просмотреть файл

@ -151,7 +151,13 @@ typedef enum {
SH_DEPENDENCY_GRAPH = 0x0400,
// 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;
//

Просмотреть файл

@ -60,6 +60,8 @@
'COMPILER_IMPLEMENTATION',
],
'sources': [
'compiler/ArrayBoundsClamper.cpp',
'compiler/ArrayBoundsClamper.h',
'compiler/BaseTypes.h',
'compiler/BuiltInFunctionEmulator.cpp',
'compiler/BuiltInFunctionEmulator.h',

Просмотреть файл

@ -0,0 +1,88 @@
/*
* 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();
}
}

Просмотреть файл

@ -0,0 +1,57 @@
/*
* 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 @@
// found in the LICENSE file.
//
#include "compiler/ArrayBoundsClamper.h"
#include "compiler/BuiltInFunctionEmulator.h"
#include "compiler/DetectRecursion.h"
#include "compiler/ForLoopUnroll.h"
@ -192,6 +193,10 @@ bool TCompiler::compile(const char* const shaderStrings[],
if (success && (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS))
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
// collectAttribsUniforms() we already have the mapped symbol names and
// we could composite mapped and original variable names.
@ -237,6 +242,7 @@ bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources& resources)
void TCompiler::clearResults()
{
arrayBoundsClamper.Cleanup();
infoSink.info.erase();
infoSink.obj.erase();
infoSink.debug.erase();
@ -353,3 +359,9 @@ const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const
{
return builtInFunctionEmulator;
}
const ArrayBoundsClamper& TCompiler::getArrayBoundsClamper() const
{
return arrayBoundsClamper;
}

Просмотреть файл

@ -212,9 +212,38 @@ bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary* node)
break;
case EOpIndexDirect:
case EOpIndexIndirect:
writeTriplet(visit, NULL, "[", "]");
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:
if (visit == InVisit)
{

Просмотреть файл

@ -16,6 +16,7 @@
#include "GLSLANG/ShaderLang.h"
#include "compiler/ArrayBoundsClamper.h"
#include "compiler/BuiltInFunctionEmulator.h"
#include "compiler/ExtensionBehavior.h"
#include "compiler/HashNames.h"
@ -108,6 +109,7 @@ protected:
// Get built-in extensions with default behavior.
const TExtensionBehavior& getExtensionBehavior() const;
const ArrayBoundsClamper& getArrayBoundsClamper() const;
const BuiltInFunctionEmulator& getBuiltInFunctionEmulator() const;
private:
@ -122,6 +124,7 @@ private:
// Built-in extensions with default behavior.
TExtensionBehavior extensionBehavior;
ArrayBoundsClamper arrayBoundsClamper;
BuiltInFunctionEmulator builtInFunctionEmulator;
// Results of compilation.

Просмотреть файл

@ -22,6 +22,9 @@ void TranslatorESSL::translate(TIntermNode* root) {
getBuiltInFunctionEmulator().OutputEmulatedFunctionDefinition(
sink, getShaderType() == SH_FRAGMENT_SHADER);
// Write array bounds clamping emulation if needed.
getArrayBoundsClamper().OutputClampingFunctionDefinition(sink);
// Write translated shader.
TOutputESSL outputESSL(sink, getHashFunction(), getNameMap(), getSymbolTable());
root->traverse(&outputESSL);

Просмотреть файл

@ -35,6 +35,9 @@ void TranslatorGLSL::translate(TIntermNode* root) {
getBuiltInFunctionEmulator().OutputEmulatedFunctionDefinition(
sink, false);
// Write array bounds clamping emulation if needed.
getArrayBoundsClamper().OutputClampingFunctionDefinition(sink);
// Write translated shader.
TOutputGLSL outputGLSL(sink, getHashFunction(), getNameMap(), getSymbolTable());
root->traverse(&outputGLSL);

Просмотреть файл

@ -42,7 +42,7 @@ TString TType::getCompleteString() const
if (qualifier != EvqTemporary && qualifier != EvqGlobal)
stream << getQualifierString() << " " << getPrecisionString() << " ";
if (array)
stream << "array of ";
stream << "array[" << getArraySize() << "] of ";
if (matrix)
stream << size << "X" << size << " matrix of ";
else if (size > 1)

Просмотреть файл

@ -395,7 +395,7 @@ protected:
//
class TIntermBinary : public TIntermOperator {
public:
TIntermBinary(TOperator o) : TIntermOperator(o) {}
TIntermBinary(TOperator o) : TIntermOperator(o), addIndexClamp(false) {}
virtual TIntermBinary* getAsBinaryNode() { return this; }
virtual void traverse(TIntermTraverser*);
@ -406,9 +406,15 @@ public:
TIntermTyped* getRight() const { return right; }
bool promote(TInfoSink&);
void setAddIndexClamp() { addIndexClamp = true; }
bool getAddIndexClamp() { return addIndexClamp; }
protected:
TIntermTyped* left;
TIntermTyped* right;
// If set to true, wrap any EOpIndexIndirect with a clamp to bounds.
bool addIndexClamp;
};
//

Просмотреть файл

@ -138,6 +138,7 @@
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="ArrayBoundsClamper.cpp" />
<ClCompile Include="BuiltInFunctionEmulator.cpp" />
<ClCompile Include="Compiler.cpp" />
<ClCompile Include="debug.cpp" />
@ -225,6 +226,7 @@
</CustomBuild>
</ItemGroup>
<ItemGroup>
<ClInclude Include="ArrayBoundsClamper.h" />
<ClInclude Include="BaseTypes.h" />
<ClInclude Include="BuiltInFunctionEmulator.h" />
<ClInclude Include="Common.h" />
@ -279,4 +281,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>