Bug 1303443 - Update ANGLE to chromium/2862. r=jgilbert

--HG--
extra : rebase_source : 9a1502c96f375c730bbee88248685eea0e4c184e
This commit is contained in:
Ethan Lin 2016-10-25 19:29:00 +02:00
parent 42404707d2
commit 1539628815
159 changed files with 7012 additions and 5917 deletions

View File

@ -497,7 +497,7 @@ config("angle_util_config") {
}
}
static_library("angle_util") {
shared_library("angle_util") {
sources = rebase_path(util_gypi.util_sources, ".", "util")
if (is_win) {
@ -514,6 +514,10 @@ static_library("angle_util") {
if (is_mac) {
sources += rebase_path(util_gypi.util_osx_sources, ".", "util")
libs = [
"AppKit.framework",
"QuartzCore.framework",
]
}
if (use_x11) {
@ -538,6 +542,7 @@ static_library("angle_util") {
defines = [
"GL_GLEXT_PROTOTYPES",
"EGL_EGLEXT_PROTOTYPES",
"LIBANGLE_UTIL_IMPLEMENTATION",
]
configs += [
@ -549,6 +554,13 @@ static_library("angle_util") {
":angle_util_config",
":internal_config",
]
if (is_mac && !is_component_build) {
ldflags = [
"-install_name",
"@rpath/lib${target_name}.dylib",
]
public_configs += [ ":shared_library_public_config" ]
}
deps = [
":angle_common",

View File

@ -49,7 +49,7 @@ typedef unsigned int GLenum;
// Version number for shader translation API.
// It is incremented every time the API changes.
#define ANGLE_SH_VERSION 155
#define ANGLE_SH_VERSION 161
typedef enum {
SH_GLES2_SPEC,
@ -61,27 +61,6 @@ typedef enum {
SH_GLES3_1_SPEC,
SH_WEBGL3_SPEC,
// The CSS Shaders spec is a subset of the WebGL spec.
//
// In both CSS vertex and fragment shaders, ANGLE:
// (1) Reserves the "css_" prefix.
// (2) Renames the main function to css_main.
// (3) Disables the gl_MaxDrawBuffers built-in.
//
// In CSS fragment shaders, ANGLE:
// (1) Disables the gl_FragColor built-in.
// (2) Disables the gl_FragData built-in.
// (3) Enables the css_MixColor built-in.
// (4) Enables the css_ColorMatrix built-in.
//
// After passing a CSS shader through ANGLE, the browser is expected to append
// a new main function to it.
// This new main function will call the css_main function.
// It may also perform additional operations like varying assignment, texture
// access, and gl_FragColor assignment in order to implement the CSS Shaders
// blend modes.
//
SH_CSS_SHADERS_SPEC
} ShShaderSpec;
typedef enum
@ -116,122 +95,109 @@ typedef enum
} ShShaderOutput;
// Compile options.
typedef enum {
SH_VALIDATE = 0,
SH_VALIDATE_LOOP_INDEXING = 0x0001,
SH_INTERMEDIATE_TREE = 0x0002,
SH_OBJECT_CODE = 0x0004,
SH_VARIABLES = 0x0008,
SH_LINE_DIRECTIVES = 0x0010,
SH_SOURCE_PATH = 0x0020,
SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX = 0x0040,
// If a sampler array index happens to be a loop index,
// 1) if its type is integer, unroll the loop.
// 2) if its type is float, fail the shader compile.
// This is to work around a mac driver bug.
SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX = 0x0080,
typedef uint64_t ShCompileOptions;
// This is needed only as a workaround for certain OpenGL driver bugs.
SH_EMULATE_BUILT_IN_FUNCTIONS = 0x0100,
const ShCompileOptions SH_VALIDATE = 0;
const ShCompileOptions SH_VALIDATE_LOOP_INDEXING = UINT64_C(1) << 0;
const ShCompileOptions SH_INTERMEDIATE_TREE = UINT64_C(1) << 1;
const ShCompileOptions SH_OBJECT_CODE = UINT64_C(1) << 2;
const ShCompileOptions SH_VARIABLES = UINT64_C(1) << 3;
const ShCompileOptions SH_LINE_DIRECTIVES = UINT64_C(1) << 4;
const ShCompileOptions SH_SOURCE_PATH = UINT64_C(1) << 5;
const ShCompileOptions SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX = UINT64_C(1) << 6;
// If a sampler array index happens to be a loop index,
// 1) if its type is integer, unroll the loop.
// 2) if its type is float, fail the shader compile.
// This is to work around a mac driver bug.
const ShCompileOptions SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX = UINT64_C(1) << 7;
// This is an experimental flag to enforce restrictions that aim to prevent
// timing attacks.
// It generates compilation errors for shaders that could expose sensitive
// texture information via the timing channel.
// To use this flag, you must compile the shader under the WebGL spec
// (using the SH_WEBGL_SPEC flag).
SH_TIMING_RESTRICTIONS = 0x0200,
// This flag works around bug in Intel Mac drivers related to abs(i) where
// i is an integer.
const ShCompileOptions SH_EMULATE_ABS_INT_FUNCTION = UINT64_C(1) << 8;
// This flag prints the dependency graph that is used to enforce timing
// restrictions on fragment shaders.
// This flag only has an effect if all of the following are true:
// - The shader spec is SH_WEBGL_SPEC.
// - The compile options contain the SH_TIMING_RESTRICTIONS flag.
// - The shader type is GL_FRAGMENT_SHADER.
SH_DEPENDENCY_GRAPH = 0x0400,
// Enforce the GLSL 1.017 Appendix A section 7 packing restrictions.
// This flag only enforces (and can only enforce) the packing
// restrictions for uniform variables in both vertex and fragment
// shaders. ShCheckVariablesWithinPackingLimits() lets embedders
// enforce the packing restrictions for varying variables during
// program link time.
const ShCompileOptions SH_ENFORCE_PACKING_RESTRICTIONS = UINT64_C(1) << 9;
// Enforce the GLSL 1.017 Appendix A section 7 packing restrictions.
// This flag only enforces (and can only enforce) the packing
// restrictions for uniform variables in both vertex and fragment
// shaders. ShCheckVariablesWithinPackingLimits() lets embedders
// enforce the packing restrictions for varying variables during
// program link time.
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. The ShArrayIndexClampingStrategy enum,
// specified in the ShBuiltInResources when constructing the
// compiler, selects the strategy for the clamping implementation.
const ShCompileOptions SH_CLAMP_INDIRECT_ARRAY_BOUNDS = UINT64_C(1) << 10;
// 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. The ShArrayIndexClampingStrategy enum,
// specified in the ShBuiltInResources when constructing the
// compiler, selects the strategy for the clamping implementation.
SH_CLAMP_INDIRECT_ARRAY_BOUNDS = 0x1000,
// This flag limits the complexity of an expression.
const ShCompileOptions SH_LIMIT_EXPRESSION_COMPLEXITY = UINT64_C(1) << 11;
// This flag limits the complexity of an expression.
SH_LIMIT_EXPRESSION_COMPLEXITY = 0x2000,
// This flag limits the depth of the call stack.
const ShCompileOptions SH_LIMIT_CALL_STACK_DEPTH = UINT64_C(1) << 12;
// This flag limits the depth of the call stack.
SH_LIMIT_CALL_STACK_DEPTH = 0x4000,
// This flag initializes gl_Position to vec4(0,0,0,0) at the
// beginning of the vertex shader's main(), and has no effect in the
// fragment shader. It is intended as a workaround for drivers which
// incorrectly fail to link programs if gl_Position is not written.
const ShCompileOptions SH_INIT_GL_POSITION = UINT64_C(1) << 13;
// This flag initializes gl_Position to vec4(0,0,0,0) at the
// beginning of the vertex shader's main(), and has no effect in the
// fragment shader. It is intended as a workaround for drivers which
// incorrectly fail to link programs if gl_Position is not written.
SH_INIT_GL_POSITION = 0x8000,
// This flag replaces
// "a && b" with "a ? b : false",
// "a || b" with "a ? true : b".
// This is to work around a MacOSX driver bug that |b| is executed
// independent of |a|'s value.
const ShCompileOptions SH_UNFOLD_SHORT_CIRCUIT = UINT64_C(1) << 14;
// This flag replaces
// "a && b" with "a ? b : false",
// "a || b" with "a ? true : b".
// This is to work around a MacOSX driver bug that |b| is executed
// independent of |a|'s value.
SH_UNFOLD_SHORT_CIRCUIT = 0x10000,
// This flag initializes output variables to 0 at the beginning of main().
// It is to avoid undefined behaviors.
const ShCompileOptions SH_INIT_OUTPUT_VARIABLES = UINT64_C(1) << 15;
// This flag initializes output variables to 0 at the beginning of main().
// It is to avoid undefined behaviors.
SH_INIT_OUTPUT_VARIABLES = 0x20000,
// TODO(zmo): obsolete, remove after ANGLE roll into Chromium.
SH_INIT_VARYINGS_WITHOUT_STATIC_USE = 0x20000,
// This flag scalarizes vec/ivec/bvec/mat constructor args.
// It is intended as a workaround for Linux/Mac driver bugs.
const ShCompileOptions SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS = UINT64_C(1) << 16;
// This flag scalarizes vec/ivec/bvec/mat constructor args.
// It is intended as a workaround for Linux/Mac driver bugs.
SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS = 0x40000,
// This flag overwrites a struct name with a unique prefix.
// It is intended as a workaround for drivers that do not handle
// struct scopes correctly, including all Mac drivers and Linux AMD.
const ShCompileOptions SH_REGENERATE_STRUCT_NAMES = UINT64_C(1) << 17;
// This flag overwrites a struct name with a unique prefix.
// It is intended as a workaround for drivers that do not handle
// struct scopes correctly, including all Mac drivers and Linux AMD.
SH_REGENERATE_STRUCT_NAMES = 0x80000,
// This flag makes the compiler not prune unused function early in the
// compilation process. Pruning coupled with SH_LIMIT_CALL_STACK_DEPTH
// helps avoid bad shaders causing stack overflows.
const ShCompileOptions SH_DONT_PRUNE_UNUSED_FUNCTIONS = UINT64_C(1) << 18;
// This flag makes the compiler not prune unused function early in the
// compilation process. Pruning coupled with SH_LIMIT_CALL_STACK_DEPTH
// helps avoid bad shaders causing stack overflows.
SH_DONT_PRUNE_UNUSED_FUNCTIONS = 0x100000,
// This flag works around a bug in NVIDIA 331 series drivers related
// to pow(x, y) where y is a constant vector.
const ShCompileOptions SH_REMOVE_POW_WITH_CONSTANT_EXPONENT = UINT64_C(1) << 19;
// This flag works around a bug in NVIDIA 331 series drivers related
// to pow(x, y) where y is a constant vector.
SH_REMOVE_POW_WITH_CONSTANT_EXPONENT = 0x200000,
// This flag works around bugs in Mac drivers related to do-while by
// transforming them into an other construct.
const ShCompileOptions SH_REWRITE_DO_WHILE_LOOPS = UINT64_C(1) << 20;
// This flag works around bugs in Mac drivers related to do-while by
// transforming them into an other construct.
SH_REWRITE_DO_WHILE_LOOPS = 0x400000,
// This flag works around a bug in the HLSL compiler optimizer that folds certain
// constant pow expressions incorrectly. Only applies to the HLSL back-end. It works
// by expanding the integer pow expressions into a series of multiplies.
const ShCompileOptions SH_EXPAND_SELECT_HLSL_INTEGER_POW_EXPRESSIONS = UINT64_C(1) << 21;
// This flag works around a bug in the HLSL compiler optimizer that folds certain
// constant pow expressions incorrectly. Only applies to the HLSL back-end. It works
// by expanding the integer pow expressions into a series of multiplies.
SH_EXPAND_SELECT_HLSL_INTEGER_POW_EXPRESSIONS = 0x800000,
// Flatten "#pragma STDGL invariant(all)" into the declarations of
// varying variables and built-in GLSL variables. This compiler
// option is enabled automatically when needed.
const ShCompileOptions SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL = UINT64_C(1) << 22;
// Flatten "#pragma STDGL invariant(all)" into the declarations of
// varying variables and built-in GLSL variables. This compiler
// option is enabled automatically when needed.
SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL = 0x1000000,
// Some drivers do not take into account the base level of the texture in the results of the
// HLSL GetDimensions builtin. This flag instructs the compiler to manually add the base level
// offsetting.
const ShCompileOptions SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL = UINT64_C(1) << 23;
// Some drivers do not take into account the base level of the texture in the results of the
// HLSL GetDimensions builtin. This flag instructs the compiler to manually add the base level
// offsetting.
SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL = 0x2000000,
// This flag works around an issue in translating GLSL function texelFetchOffset on
// INTEL drivers. It works by translating texelFetchOffset into texelFetch.
const ShCompileOptions SH_REWRITE_TEXELFETCHOFFSET_TO_TEXELFETCH = UINT64_C(1) << 24;
// This flag works around an issue in translating GLSL function texelFetchOffset on
// INTEL drivers. It works by translating texelFetchOffset into texelFetch.
SH_REWRITE_TEXELFETCHOFFSET_TO_TEXELFETCH = 0x4000000,
} ShCompileOptions;
// This flag works around condition bug of for and while loops in Intel Mac OSX drivers.
// Condition calculation is not correct. Rewrite it from "CONDITION" to "CONDITION && true".
const ShCompileOptions SH_ADD_AND_TRUE_TO_LOOP_CONDITION = UINT64_C(1) << 25;
// Defines alternate strategies for implementing array index clamping.
typedef enum {
@ -465,11 +431,10 @@ COMPILER_EXPORT void ShDestruct(ShHandle handle);
// SH_VARIABLES: Extracts attributes, uniforms, and varyings.
// Can be queried by calling ShGetVariableInfo().
//
COMPILER_EXPORT bool ShCompile(
const ShHandle handle,
const char * const shaderStrings[],
size_t numStrings,
int compileOptions);
COMPILER_EXPORT bool ShCompile(const ShHandle handle,
const char *const shaderStrings[],
size_t numStrings,
ShCompileOptions compileOptions);
// Clears the results from the previous compilation.
COMPILER_EXPORT void ShClearResults(const ShHandle handle);

View File

@ -10,13 +10,15 @@
#define LIBGLESV2_EXPORT_H_
#if defined(_WIN32)
# if defined(LIBGLESV2_IMPLEMENTATION) || defined(LIBANGLE_IMPLEMENTATION)
#if defined(LIBGLESV2_IMPLEMENTATION) || defined(LIBANGLE_IMPLEMENTATION) || \
defined(LIBANGLE_UTIL_IMPLEMENTATION)
# define ANGLE_EXPORT __declspec(dllexport)
# else
# define ANGLE_EXPORT __declspec(dllimport)
# endif
#elif defined(__GNUC__)
# if defined(LIBGLESV2_IMPLEMENTATION) || defined(LIBANGLE_IMPLEMENTATION)
#if defined(LIBGLESV2_IMPLEMENTATION) || defined(LIBANGLE_IMPLEMENTATION) || \
defined(LIBANGLE_UTIL_IMPLEMENTATION)
# define ANGLE_EXPORT __attribute__((visibility ("default")))
# else
# define ANGLE_EXPORT

View File

@ -28,11 +28,13 @@ UNIFIED_SOURCES += [
'src/compiler/preprocessor/Preprocessor.cpp',
'src/compiler/preprocessor/Token.cpp',
'src/compiler/preprocessor/Tokenizer.cpp',
'src/compiler/translator/AddAndTrueToLoopCondition.cpp',
'src/compiler/translator/AddDefaultReturnStatements.cpp',
'src/compiler/translator/ArrayReturnValueToOutParameter.cpp',
'src/compiler/translator/ASTMetadataHLSL.cpp',
'src/compiler/translator/blocklayout.cpp',
'src/compiler/translator/blocklayoutHLSL.cpp',
'src/compiler/translator/BreakVariableAliasingInInnerLoops.cpp',
'src/compiler/translator/BuiltInFunctionEmulator.cpp',
'src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp',
'src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp',
@ -40,11 +42,8 @@ UNIFIED_SOURCES += [
'src/compiler/translator/CallDAG.cpp',
'src/compiler/translator/CodeGen.cpp',
'src/compiler/translator/Compiler.cpp',
'src/compiler/translator/ConstantUnion.cpp',
'src/compiler/translator/DeferGlobalInitializers.cpp',
'src/compiler/translator/depgraph/DependencyGraph.cpp',
'src/compiler/translator/depgraph/DependencyGraphBuilder.cpp',
'src/compiler/translator/depgraph/DependencyGraphOutput.cpp',
'src/compiler/translator/depgraph/DependencyGraphTraverse.cpp',
'src/compiler/translator/Diagnostics.cpp',
'src/compiler/translator/DirectiveHandler.cpp',
'src/compiler/translator/EmulatePrecision.cpp',
@ -71,6 +70,7 @@ UNIFIED_SOURCES += [
'src/compiler/translator/ParseContext.cpp',
'src/compiler/translator/PoolAlloc.cpp',
'src/compiler/translator/PruneEmptyDeclarations.cpp',
'src/compiler/translator/QualifierTypes.cpp',
'src/compiler/translator/RecordConstantPrecision.cpp',
'src/compiler/translator/RegenerateStructNames.cpp',
'src/compiler/translator/RemoveDynamicIndexing.cpp',
@ -91,8 +91,6 @@ UNIFIED_SOURCES += [
'src/compiler/translator/StructureHLSL.cpp',
'src/compiler/translator/SymbolTable.cpp',
'src/compiler/translator/TextureFunctionHLSL.cpp',
'src/compiler/translator/timing/RestrictFragmentShaderTiming.cpp',
'src/compiler/translator/timing/RestrictVertexShaderTiming.cpp',
'src/compiler/translator/TranslatorESSL.cpp',
'src/compiler/translator/TranslatorGLSL.cpp',
'src/compiler/translator/TranslatorHLSL.cpp',

View File

@ -1,3 +1,3 @@
#define ANGLE_COMMIT_HASH ""
#define ANGLE_COMMIT_HASH_SIZE 12
#define ANGLE_COMMIT_DATE ""
#define ANGLE_COMMIT_HASH "8b3e8b4d1b09"
#define ANGLE_COMMIT_HASH_SIZE 12
#define ANGLE_COMMIT_DATE "2016-10-24 15:38:47 +0800"

View File

@ -22,9 +22,13 @@
'../include/GLSLANG/ShaderVars.h',
'../include/KHR/khrplatform.h',
'../include/angle_gl.h',
'compiler/translator/AddAndTrueToLoopCondition.cpp',
'compiler/translator/AddAndTrueToLoopCondition.h',
'compiler/translator/BaseTypes.h',
'compiler/translator/BuiltInFunctionEmulator.cpp',
'compiler/translator/BuiltInFunctionEmulator.h',
'compiler/translator/BreakVariableAliasingInInnerLoops.cpp',
'compiler/translator/BreakVariableAliasingInInnerLoops.h',
'compiler/translator/Cache.cpp',
'compiler/translator/Cache.h',
'compiler/translator/CallDAG.cpp',
@ -33,6 +37,7 @@
'compiler/translator/Common.h',
'compiler/translator/Compiler.cpp',
'compiler/translator/Compiler.h',
'compiler/translator/ConstantUnion.cpp',
'compiler/translator/ConstantUnion.h',
'compiler/translator/DeferGlobalInitializers.cpp',
'compiler/translator/DeferGlobalInitializers.h',
@ -81,6 +86,8 @@
'compiler/translator/Pragma.h',
'compiler/translator/PruneEmptyDeclarations.cpp',
'compiler/translator/PruneEmptyDeclarations.h',
'compiler/translator/QualifierTypes.h',
'compiler/translator/QualifierTypes.cpp',
'compiler/translator/RecordConstantPrecision.cpp',
'compiler/translator/RecordConstantPrecision.h',
'compiler/translator/RegenerateStructNames.cpp',
@ -91,7 +98,6 @@
'compiler/translator/RewriteDoWhile.h',
'compiler/translator/RewriteTexelFetchOffset.cpp',
'compiler/translator/RewriteTexelFetchOffset.h',
'compiler/translator/RenameFunction.h',
'compiler/translator/ScalarizeVecAndMatConstructorArgs.cpp',
'compiler/translator/ScalarizeVecAndMatConstructorArgs.h',
'compiler/translator/SearchSymbol.cpp',
@ -118,13 +124,6 @@
'compiler/translator/VariablePacker.h',
'compiler/translator/blocklayout.cpp',
'compiler/translator/blocklayout.h',
'compiler/translator/depgraph/DependencyGraph.cpp',
'compiler/translator/depgraph/DependencyGraph.h',
'compiler/translator/depgraph/DependencyGraphBuilder.cpp',
'compiler/translator/depgraph/DependencyGraphBuilder.h',
'compiler/translator/depgraph/DependencyGraphOutput.cpp',
'compiler/translator/depgraph/DependencyGraphOutput.h',
'compiler/translator/depgraph/DependencyGraphTraverse.cpp',
'compiler/translator/glslang.h',
'compiler/translator/glslang.l',
'compiler/translator/glslang.y',
@ -133,10 +132,6 @@
'compiler/translator/glslang_tab.h',
'compiler/translator/intermOut.cpp',
'compiler/translator/length_limits.h',
'compiler/translator/timing/RestrictFragmentShaderTiming.cpp',
'compiler/translator/timing/RestrictFragmentShaderTiming.h',
'compiler/translator/timing/RestrictVertexShaderTiming.cpp',
'compiler/translator/timing/RestrictVertexShaderTiming.h',
'compiler/translator/util.cpp',
'compiler/translator/util.h',
'third_party/compiler/ArrayBoundsClamper.cpp',

View File

@ -0,0 +1,59 @@
//
// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#include "compiler/translator/AddAndTrueToLoopCondition.h"
#include "compiler/translator/IntermNode.h"
namespace sh
{
namespace
{
// An AST traverser that rewrites for and while loops by replacing "condition" with
// "condition && true" to work around condition bug on Intel Mac.
class AddAndTrueToLoopConditionTraverser : public TIntermTraverser
{
public:
AddAndTrueToLoopConditionTraverser() : TIntermTraverser(true, false, false) {}
bool visitLoop(Visit, TIntermLoop *loop) override
{
// do-while loop doesn't have this bug.
if (loop->getType() != ELoopFor && loop->getType() != ELoopWhile)
{
return true;
}
// For loop may not have a condition.
if (loop->getCondition() == nullptr)
{
return true;
}
// Constant true.
TConstantUnion *trueConstant = new TConstantUnion();
trueConstant->setBConst(true);
TIntermTyped *trueValue = new TIntermConstantUnion(trueConstant, TType(EbtBool));
// CONDITION && true.
TIntermBinary *andOp = new TIntermBinary(EOpLogicalAnd, loop->getCondition(), trueValue);
loop->setCondition(andOp);
return true;
}
};
} // anonymous namespace
void AddAndTrueToLoopCondition(TIntermNode *root)
{
AddAndTrueToLoopConditionTraverser traverser;
root->traverse(&traverser);
}
} // namespace sh

View File

@ -0,0 +1,20 @@
//
// Copyright (c) 2016 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.
//
// Rewrite condition in for and while loops to work around driver bug on Intel Mac.
#ifndef COMPILER_TRANSLATOR_ADDANDTRUETOLOOPCONDITION_H_
#define COMPILER_TRANSLATOR_ADDANDTRUETOLOOPCONDITION_H_
class TIntermNode;
namespace sh
{
void AddAndTrueToLoopCondition(TIntermNode *root);
} // namespace sh
#endif // COMPILER_TRANSLATOR_ADDANDTRUETOLOOPCONDITION_H_

View File

@ -54,48 +54,13 @@ class AddDefaultReturnStatementsTraverser : private TIntermTraverser
return true;
}
static TIntermTyped *GenerateTypeConstructor(const TType &returnType)
{
// Base case, constructing a single element
if (!returnType.isArray())
{
size_t objectSize = returnType.getObjectSize();
TConstantUnion *constantUnion = new TConstantUnion[objectSize];
for (size_t constantIdx = 0; constantIdx < objectSize; constantIdx++)
{
constantUnion[constantIdx].setFConst(0.0f);
}
TIntermConstantUnion *intermConstantUnion =
new TIntermConstantUnion(constantUnion, returnType);
return intermConstantUnion;
}
// Recursive case, construct an array of single elements
TIntermAggregate *constructorAggrigate =
new TIntermAggregate(TypeToConstructorOperator(returnType));
constructorAggrigate->setType(returnType);
size_t arraySize = returnType.getArraySize();
for (size_t arrayIdx = 0; arrayIdx < arraySize; arrayIdx++)
{
TType arrayElementType(returnType);
arrayElementType.clearArrayness();
constructorAggrigate->getSequence()->push_back(
GenerateTypeConstructor(arrayElementType));
}
return constructorAggrigate;
}
bool visitAggregate(Visit, TIntermAggregate *node) override
{
TType returnType;
if (IsFunctionWithoutReturnStatement(node, &returnType))
{
TIntermBranch *branch =
new TIntermBranch(EOpReturn, GenerateTypeConstructor(returnType));
new TIntermBranch(EOpReturn, TIntermTyped::CreateZero(returnType));
TIntermAggregate *lastNode = node->getSequence()->back()->getAsAggregate();
lastNode->getSequence()->push_back(branch);

View File

@ -167,12 +167,11 @@ bool ArrayReturnValueToOutParameterTraverser::visitBranch(Visit visit, TIntermBr
// Instead of returning a value, assign to the out parameter and then return.
TIntermSequence replacements;
TIntermBinary *replacementAssignment = new TIntermBinary(EOpAssign);
TIntermTyped *expression = node->getExpression();
ASSERT(expression != nullptr);
replacementAssignment->setLeft(CreateReturnValueSymbol(expression->getType()));
replacementAssignment->setRight(node->getExpression());
replacementAssignment->setType(expression->getType());
TIntermSymbol *returnValueSymbol = CreateReturnValueSymbol(expression->getType());
TIntermBinary *replacementAssignment =
new TIntermBinary(EOpAssign, returnValueSymbol, expression);
replacementAssignment->setLine(expression->getLine());
replacements.push_back(replacementAssignment);

View File

@ -341,10 +341,11 @@ enum TQualifier
EvqLastFragData,
// GLSL ES 3.0 vertex output and fragment input
EvqSmooth, // Incomplete qualifier, smooth is the default
EvqFlat, // Incomplete qualifier
EvqSmoothOut = EvqSmooth,
EvqFlatOut = EvqFlat,
EvqSmooth, // Incomplete qualifier, smooth is the default
EvqFlat, // Incomplete qualifier
EvqCentroid, // Incomplete qualifier
EvqSmoothOut,
EvqFlatOut,
EvqCentroidOut, // Implies smooth
EvqSmoothIn,
EvqFlatIn,
@ -363,6 +364,11 @@ enum TQualifier
EvqLast
};
inline bool IsQualifierUnspecified(TQualifier qualifier)
{
return (qualifier == EvqTemporary || qualifier == EvqGlobal);
}
enum TLayoutMatrixPacking
{
EmpUnspecified,
@ -381,6 +387,7 @@ enum TLayoutBlockStorage
struct TLayoutQualifier
{
int location;
unsigned int locationsSpecified;
TLayoutMatrixPacking matrixPacking;
TLayoutBlockStorage blockStorage;
@ -392,6 +399,7 @@ struct TLayoutQualifier
TLayoutQualifier layoutQualifier;
layoutQualifier.location = -1;
layoutQualifier.locationsSpecified = 0;
layoutQualifier.matrixPacking = EmpUnspecified;
layoutQualifier.blockStorage = EbsUnspecified;
@ -482,6 +490,9 @@ inline const char* getQualifierString(TQualifier q)
case EvqSmoothIn: return "smooth in";
case EvqFlatIn: return "flat in";
case EvqCentroidIn: return "smooth centroid in";
case EvqCentroid: return "centroid";
case EvqFlat: return "flat";
case EvqSmooth: return "smooth";
case EvqComputeIn: return "in";
case EvqNumWorkGroups: return "NumWorkGroups";
case EvqWorkGroupSize: return "WorkGroupSize";

View File

@ -0,0 +1,106 @@
//
// Copyright (c) 2016 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.
//
// BreakVariableAliasingInInnerLoops.h: To optimize simple assignments, the HLSL compiler frontend
// may record a variable as aliasing another. Sometimes the alias information gets garbled
// so we work around this issue by breaking the aliasing chain in inner loops.
#include "BreakVariableAliasingInInnerLoops.h"
#include "compiler/translator/IntermNode.h"
// A HLSL compiler developer gave us more details on the root cause and the workaround needed:
// The root problem is that if the HLSL compiler is applying aliasing information even on
// incomplete simulations (in this case, a single pass). The bug is triggered by an assignment
// that comes from a series of assignments, possibly with swizzled or ternary operators with
// known conditionals, where the source is before the loop.
// So, a workaround is to add a +0 term to variables the first time they are assigned to in
// an inner loop (if they are declared in an outside scope, otherwise there is no need).
// This will break the aliasing chain.
// For simplicity here we add a +0 to any assignment that is in at least two nested loops. Because
// the bug only shows up with swizzles, and ternary assignment, whole array or whole structure
// assignment don't need a workaround.
namespace
{
class AliasingBreaker : public TIntermTraverser
{
public:
AliasingBreaker() : TIntermTraverser(true, false, true) {}
protected:
bool visitBinary(Visit visit, TIntermBinary *binary)
{
if (visit != PreVisit)
{
return false;
}
if (mLoopLevel < 2 || !binary->isAssignment())
{
return true;
}
TIntermTyped *B = binary->getRight();
TType type = B->getType();
if (!type.isScalar() && !type.isVector() && !type.isMatrix())
{
return true;
}
if (type.isArray() || IsSampler(type.getBasicType()))
{
return true;
}
// We have a scalar / vector / matrix assignment with loop depth 2.
// Transform it from
// A = B
// to
// A = (B + typeof<B>(0));
TIntermBinary *bPlusZero = new TIntermBinary(EOpAdd, B, TIntermTyped::CreateZero(type));
bPlusZero->setLine(B->getLine());
binary->replaceChildNode(B, bPlusZero);
return true;
}
bool visitLoop(Visit visit, TIntermLoop *loop)
{
if (visit == PreVisit)
{
mLoopLevel++;
}
else
{
ASSERT(mLoopLevel > 0);
mLoopLevel--;
}
return true;
}
private:
int mLoopLevel = 0;
};
} // anonymous namespace
namespace sh
{
void BreakVariableAliasingInInnerLoops(TIntermNode *root)
{
AliasingBreaker breaker;
root->traverse(&breaker);
}
} // namespace sh

View File

@ -0,0 +1,23 @@
//
// Copyright (c) 2016 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.
//
// BreakVariableAliasingInInnerLoops.h: To optimize simple assignments, the HLSL compiler frontend
// may record a variable as aliasing another. Sometimes the alias information gets garbled
// so we work around this issue by breaking the aliasing chain in inner loops.
#ifndef COMPILER_TRANSLATOR_BREAKVARIABLEALIASINGININNERLOOPS_H_
#define COMPILER_TRANSLATOR_BREAKVARIABLEALIASINGININNERLOOPS_H_
class TIntermNode;
namespace sh
{
void BreakVariableAliasingInInnerLoops(TIntermNode *root);
} // namespace sh
#endif // COMPILER_TRANSLATOR_BREAKVARIABLEALIASINGININNERLOOPS_H_

View File

@ -11,32 +11,14 @@
#include "compiler/translator/SymbolTable.h"
#include "compiler/translator/VersionGLSL.h"
void InitBuiltInFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu, sh::GLenum shaderType)
void InitBuiltInAbsFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu,
sh::GLenum shaderType)
{
// we use macros here instead of function definitions to work around more GLSL
// compiler bugs, in particular on NVIDIA hardware on Mac OSX. Macros are
// problematic because if the argument has side-effects they will be repeatedly
// evaluated. This is unlikely to show up in real shaders, but is something to
// consider.
const TType *float1 = TCache::getType(EbtFloat);
const TType *float2 = TCache::getType(EbtFloat, 2);
const TType *float3 = TCache::getType(EbtFloat, 3);
const TType *float4 = TCache::getType(EbtFloat, 4);
if (shaderType == GL_FRAGMENT_SHADER)
if (shaderType == GL_VERTEX_SHADER)
{
emu->addEmulatedFunction(EOpCos, float1, "webgl_emu_precision float webgl_cos_emu(webgl_emu_precision float a) { return cos(a); }");
emu->addEmulatedFunction(EOpCos, float2, "webgl_emu_precision vec2 webgl_cos_emu(webgl_emu_precision vec2 a) { return cos(a); }");
emu->addEmulatedFunction(EOpCos, float3, "webgl_emu_precision vec3 webgl_cos_emu(webgl_emu_precision vec3 a) { return cos(a); }");
emu->addEmulatedFunction(EOpCos, float4, "webgl_emu_precision vec4 webgl_cos_emu(webgl_emu_precision vec4 a) { return cos(a); }");
const TType *int1 = TCache::getType(EbtInt);
emu->addEmulatedFunction(EOpAbs, int1, "int webgl_abs_emu(int x) { return x * sign(x); }");
}
emu->addEmulatedFunction(EOpDistance, float1, float1, "#define webgl_distance_emu(x, y) ((x) >= (y) ? (x) - (y) : (y) - (x))");
emu->addEmulatedFunction(EOpDot, float1, float1, "#define webgl_dot_emu(x, y) ((x) * (y))");
emu->addEmulatedFunction(EOpLength, float1, "#define webgl_length_emu(x) ((x) >= 0.0 ? (x) : -(x))");
emu->addEmulatedFunction(EOpNormalize, float1, "#define webgl_normalize_emu(x) ((x) == 0.0 ? 0.0 : ((x) > 0.0 ? 1.0 : -1.0))");
emu->addEmulatedFunction(EOpReflect, float1, float1, "#define webgl_reflect_emu(I, N) ((I) - 2.0 * (N) * (I) * (N))");
emu->addEmulatedFunction(EOpFaceForward, float1, float1, float1, "#define webgl_faceforward_emu(N, I, Nref) (((Nref) * (I) < 0.0) ? (N) : -(N))");
}
// Emulate built-in functions missing from GLSL 1.30 and higher
@ -181,7 +163,9 @@ void InitBuiltInFunctionEmulatorForGLSLMissingFunctions(BuiltInFunctionEmulator
" float scale;\n"
" if(exponent < 0)\n"
" {\n"
" scale = 1.0 / (1 << -exponent);\n"
" // The negative unary operator is buggy on OSX.\n"
" // Work around this by using abs instead.\n"
" scale = 1.0 / (1 << abs(exponent));\n"
" }\n"
" else\n"
" {\n"

View File

@ -12,9 +12,10 @@
class BuiltInFunctionEmulator;
//
// This is only a workaround for OpenGL driver bugs, and isn't needed in general.
// This works around bug in Intel Mac drivers.
//
void InitBuiltInFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu, sh::GLenum shaderType);
void InitBuiltInAbsFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu,
sh::GLenum shaderType);
//
// This function is emulating built-in functions missing from GLSL 1.30 and higher.

View File

@ -4,6 +4,7 @@
// found in the LICENSE file.
//
#include "compiler/translator/AddAndTrueToLoopCondition.h"
#include "compiler/translator/Cache.h"
#include "compiler/translator/Compiler.h"
#include "compiler/translator/CallDAG.h"
@ -17,7 +18,6 @@
#include "compiler/translator/PruneEmptyDeclarations.h"
#include "compiler/translator/RegenerateStructNames.h"
#include "compiler/translator/RemovePow.h"
#include "compiler/translator/RenameFunction.h"
#include "compiler/translator/RewriteDoWhile.h"
#include "compiler/translator/ScalarizeVecAndMatConstructorArgs.h"
#include "compiler/translator/UnfoldShortCircuitAST.h"
@ -25,18 +25,13 @@
#include "compiler/translator/ValidateMaxParameters.h"
#include "compiler/translator/ValidateOutputs.h"
#include "compiler/translator/VariablePacker.h"
#include "compiler/translator/depgraph/DependencyGraph.h"
#include "compiler/translator/depgraph/DependencyGraphOutput.h"
#include "compiler/translator/timing/RestrictFragmentShaderTiming.h"
#include "compiler/translator/timing/RestrictVertexShaderTiming.h"
#include "third_party/compiler/ArrayBoundsClamper.h"
#include "angle_gl.h"
#include "common/utilities.h"
bool IsWebGLBasedSpec(ShShaderSpec spec)
{
return (spec == SH_WEBGL_SPEC || spec == SH_CSS_SHADERS_SPEC || spec == SH_WEBGL2_SPEC ||
spec == SH_WEBGL3_SPEC);
return (spec == SH_WEBGL_SPEC || spec == SH_WEBGL2_SPEC || spec == SH_WEBGL3_SPEC);
}
bool IsGLSL130OrNewer(ShShaderOutput output)
@ -60,7 +55,6 @@ size_t GetGlobalMaxTokenSize(ShShaderSpec spec)
switch (spec)
{
case SH_WEBGL_SPEC:
case SH_CSS_SHADERS_SPEC:
return 256;
default:
return 1024;
@ -111,7 +105,6 @@ int MapSpecToShaderVersion(ShShaderSpec spec)
{
case SH_GLES2_SPEC:
case SH_WEBGL_SPEC:
case SH_CSS_SHADERS_SPEC:
return 100;
case SH_GLES3_SPEC:
case SH_WEBGL2_SPEC:
@ -162,7 +155,7 @@ TCompiler::~TCompiler()
{
}
bool TCompiler::shouldRunLoopAndIndexingValidation(int compileOptions) const
bool TCompiler::shouldRunLoopAndIndexingValidation(ShCompileOptions compileOptions) const
{
// If compiling an ESSL 1.00 shader for WebGL, or if its been requested through the API,
// validate loop and indexing as well (to verify that the shader only uses minimal functionality
@ -197,15 +190,16 @@ bool TCompiler::Init(const ShBuiltInResources& resources)
return true;
}
TIntermNode *TCompiler::compileTreeForTesting(const char* const shaderStrings[],
size_t numStrings, int compileOptions)
TIntermNode *TCompiler::compileTreeForTesting(const char *const shaderStrings[],
size_t numStrings,
ShCompileOptions compileOptions)
{
return compileTreeImpl(shaderStrings, numStrings, compileOptions);
}
TIntermNode *TCompiler::compileTreeImpl(const char *const shaderStrings[],
size_t numStrings,
const int compileOptions)
const ShCompileOptions compileOptions)
{
clearResults();
@ -223,8 +217,7 @@ TIntermNode *TCompiler::compileTreeImpl(const char *const shaderStrings[],
++firstSource;
}
TIntermediate intermediate(infoSink);
TParseContext parseContext(symbolTable, extensionBehavior, intermediate, shaderType, shaderSpec,
TParseContext parseContext(symbolTable, extensionBehavior, shaderType, shaderSpec,
compileOptions, true, infoSink, getResources());
parseContext.setFragmentPrecisionHighOnESSL1(fragmentPrecisionHigh);
@ -258,7 +251,7 @@ TIntermNode *TCompiler::compileTreeImpl(const char *const shaderStrings[],
mComputeShaderLocalSize = parseContext.getComputeShaderLocalSize();
root = parseContext.getTreeRoot();
root = intermediate.postProcess(root);
root = TIntermediate::PostProcess(root);
// Highp might have been auto-enabled based on shader version
fragmentPrecisionHigh = parseContext.getFragmentPrecisionHigh();
@ -295,12 +288,6 @@ TIntermNode *TCompiler::compileTreeImpl(const char *const shaderStrings[],
if (success && shouldRunLoopAndIndexingValidation(compileOptions))
success = validateLimitations(root);
if (success && (compileOptions & SH_TIMING_RESTRICTIONS))
success = enforceTimingRestrictions(root, (compileOptions & SH_DEPENDENCY_GRAPH) != 0);
if (success && shaderSpec == SH_CSS_SHADERS_SPEC)
rewriteCSSShader(root);
// Unroll for-loop markup needs to happen after validateLimitations pass.
if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX))
{
@ -345,6 +332,9 @@ TIntermNode *TCompiler::compileTreeImpl(const char *const shaderStrings[],
if (success && (compileOptions & SH_REWRITE_DO_WHILE_LOOPS))
RewriteDoWhile(root, getTemporaryIndex());
if (success && (compileOptions & SH_ADD_AND_TRUE_TO_LOOP_CONDITION))
sh::AddAndTrueToLoopCondition(root);
if (success && (compileOptions & SH_UNFOLD_SHORT_CIRCUIT))
{
UnfoldShortCircuitAST unfoldShortCircuit;
@ -408,12 +398,14 @@ TIntermNode *TCompiler::compileTreeImpl(const char *const shaderStrings[],
return NULL;
}
bool TCompiler::compile(const char *const shaderStrings[], size_t numStrings, int compileOptionsIn)
bool TCompiler::compile(const char *const shaderStrings[],
size_t numStrings,
ShCompileOptions compileOptionsIn)
{
if (numStrings == 0)
return true;
int compileOptions = compileOptionsIn;
ShCompileOptions compileOptions = compileOptionsIn;
// Apply key workarounds.
if (shouldFlattenPragmaStdglInvariantAll())
@ -452,15 +444,13 @@ bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources)
symbolTable.push(); // ESSL3_1_BUILTINS
TPublicType integer;
integer.type = EbtInt;
integer.primarySize = 1;
integer.secondarySize = 1;
integer.setBasicType(EbtInt);
integer.initializeSizeForScalarTypes();
integer.array = false;
TPublicType floatingPoint;
floatingPoint.type = EbtFloat;
floatingPoint.primarySize = 1;
floatingPoint.secondarySize = 1;
floatingPoint.setBasicType(EbtFloat);
floatingPoint.initializeSizeForScalarTypes();
floatingPoint.array = false;
switch(shaderType)
@ -500,10 +490,9 @@ void TCompiler::initSamplerDefaultPrecision(TBasicType samplerType)
{
ASSERT(samplerType > EbtGuardSamplerBegin && samplerType < EbtGuardSamplerEnd);
TPublicType sampler;
sampler.primarySize = 1;
sampler.secondarySize = 1;
sampler.initializeSizeForScalarTypes();
sampler.setBasicType(samplerType);
sampler.array = false;
sampler.type = samplerType;
symbolTable.setDefaultPrecision(sampler, EbpLow);
}
@ -763,12 +752,6 @@ bool TCompiler::validateOutputs(TIntermNode* root)
return (validateOutputs.validateAndCountErrors(infoSink.info) == 0);
}
void TCompiler::rewriteCSSShader(TIntermNode* root)
{
RenameFunction renamer("main(", "css_main(");
root->traverse(&renamer);
}
bool TCompiler::validateLimitations(TIntermNode* root)
{
ValidateLimitations validate(shaderType, &infoSink.info);
@ -776,36 +759,6 @@ bool TCompiler::validateLimitations(TIntermNode* root)
return validate.numErrors() == 0;
}
bool TCompiler::enforceTimingRestrictions(TIntermNode* root, bool outputGraph)
{
if (shaderSpec != SH_WEBGL_SPEC)
{
infoSink.info << "Timing restrictions must be enforced under the WebGL spec.";
return false;
}
if (shaderType == GL_FRAGMENT_SHADER)
{
TDependencyGraph graph(root);
// Output any errors first.
bool success = enforceFragmentShaderTimingRestrictions(graph);
// Then, output the dependency graph.
if (outputGraph)
{
TDependencyGraphOutput output(infoSink.info);
output.outputAllSpanningTrees(graph);
}
return success;
}
else
{
return enforceVertexShaderTimingRestrictions(root);
}
}
bool TCompiler::limitExpressionComplexity(TIntermNode* root)
{
TMaxDepthTraverser traverser(maxExpressionComplexity+1);
@ -826,20 +779,6 @@ bool TCompiler::limitExpressionComplexity(TIntermNode* root)
return true;
}
bool TCompiler::enforceFragmentShaderTimingRestrictions(const TDependencyGraph& graph)
{
RestrictFragmentShaderTiming restrictor(infoSink.info);
restrictor.enforceRestrictions(graph);
return restrictor.numErrors() == 0;
}
bool TCompiler::enforceVertexShaderTimingRestrictions(TIntermNode* root)
{
RestrictVertexShaderTiming restrictor(infoSink.info);
restrictor.enforceRestrictions(root);
return restrictor.numErrors() == 0;
}
void TCompiler::collectVariables(TIntermNode* root)
{
if (!variablesCollected)
@ -920,7 +859,7 @@ const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const
return builtInFunctionEmulator;
}
void TCompiler::writePragma(int compileOptions)
void TCompiler::writePragma(ShCompileOptions compileOptions)
{
if (!(compileOptions & SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL))
{

View File

@ -25,14 +25,12 @@
#include "third_party/compiler/ArrayBoundsClamper.h"
class TCompiler;
class TDependencyGraph;
#ifdef ANGLE_ENABLE_HLSL
class TranslatorHLSL;
#endif // ANGLE_ENABLE_HLSL
//
// Helper function to identify specs that are based on the WebGL spec,
// like the CSS Shaders spec.
// Helper function to identify specs that are based on the WebGL spec.
//
bool IsWebGLBasedSpec(ShShaderSpec spec);
@ -75,11 +73,13 @@ class TCompiler : public TShHandleBase
// compileTreeForTesting should be used only when tests require access to
// the AST. Users of this function need to manually manage the global pool
// allocator. Returns NULL whenever there are compilation errors.
TIntermNode *compileTreeForTesting(const char* const shaderStrings[],
size_t numStrings, int compileOptions);
TIntermNode *compileTreeForTesting(const char *const shaderStrings[],
size_t numStrings,
ShCompileOptions compileOptions);
bool compile(const char* const shaderStrings[],
size_t numStrings, int compileOptions);
bool compile(const char *const shaderStrings[],
size_t numStrings,
ShCompileOptions compileOptions);
// Get results of the last compilation.
int getShaderVersion() const { return shaderVersion; }
@ -104,7 +104,7 @@ class TCompiler : public TShHandleBase
ShShaderOutput getOutputType() const { return outputType; }
const std::string &getBuiltInResourcesString() const { return builtInResourcesString; }
bool shouldRunLoopAndIndexingValidation(int compileOptions) const;
bool shouldRunLoopAndIndexingValidation(ShCompileOptions compileOptions) const;
// Get the resources set by InitBuiltInSymbolTable
const ShBuiltInResources& getResources() const;
@ -119,17 +119,16 @@ class TCompiler : public TShHandleBase
bool checkCallDepth();
// Returns true if a program has no conflicting or missing fragment outputs
bool validateOutputs(TIntermNode* root);
// Rewrites a shader's intermediate tree according to the CSS Shaders spec.
void rewriteCSSShader(TIntermNode* root);
// Returns true if the given shader does not exceed the minimum
// functionality mandated in GLSL 1.0 spec Appendix A.
bool validateLimitations(TIntermNode* root);
// Collect info for all attribs, uniforms, varyings.
void collectVariables(TIntermNode* root);
// Add emulated functions to the built-in function emulator.
virtual void initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, int compileOptions) {};
virtual void initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu,
ShCompileOptions compileOptions){};
// Translate to object code.
virtual void translate(TIntermNode *root, int compileOptions) = 0;
virtual void translate(TIntermNode *root, ShCompileOptions compileOptions) = 0;
// Returns true if, after applying the packing rules in the GLSL 1.017 spec
// Appendix A, section 7, the shader does not use too many uniforms.
bool enforcePackingRestrictions();
@ -141,20 +140,13 @@ class TCompiler : public TShHandleBase
// while spec says it is allowed.
// This function should only be applied to vertex shaders.
void initializeGLPosition(TIntermNode* root);
// Returns true if the shader passes the restrictions that aim to prevent timing attacks.
bool enforceTimingRestrictions(TIntermNode* root, bool outputGraph);
// Returns true if the shader does not use samplers.
bool enforceVertexShaderTimingRestrictions(TIntermNode* root);
// Returns true if the shader does not use sampler dependent values to affect control
// flow or in operations whose time can depend on the input values.
bool enforceFragmentShaderTimingRestrictions(const TDependencyGraph& graph);
// Return true if the maximum expression complexity is below the limit.
bool limitExpressionComplexity(TIntermNode* root);
// Get built-in extensions with default behavior.
const TExtensionBehavior& getExtensionBehavior() const;
const char *getSourcePath() const;
const TPragma& getPragma() const { return mPragma; }
void writePragma(int compileOptions);
void writePragma(ShCompileOptions compileOptions);
unsigned int *getTemporaryIndex() { return &mTemporaryIndex; }
// Relies on collectVariables having been called.
bool isVaryingDefined(const char *varyingName);
@ -163,7 +155,7 @@ class TCompiler : public TShHandleBase
ShArrayIndexClampingStrategy getArrayIndexClampingStrategy() const;
const BuiltInFunctionEmulator& getBuiltInFunctionEmulator() const;
virtual bool shouldCollectVariables(int compileOptions)
virtual bool shouldCollectVariables(ShCompileOptions compileOptions)
{
return (compileOptions & SH_VARIABLES) != 0;
}
@ -193,7 +185,7 @@ class TCompiler : public TShHandleBase
TIntermNode *compileTreeImpl(const char *const shaderStrings[],
size_t numStrings,
const int compileOptions);
const ShCompileOptions compileOptions);
sh::GLenum shaderType;
ShShaderSpec shaderSpec;

View File

@ -0,0 +1,443 @@
//
// Copyright 2016 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.
//
// ConstantUnion: Constant folding helper class.
#include "compiler/translator/ConstantUnion.h"
#include "compiler/translator/Diagnostics.h"
TConstantUnion::TConstantUnion()
{
iConst = 0;
type = EbtVoid;
}
bool TConstantUnion::cast(TBasicType newType, const TConstantUnion &constant)
{
switch (newType)
{
case EbtFloat:
switch (constant.type)
{
case EbtInt:
setFConst(static_cast<float>(constant.getIConst()));
break;
case EbtUInt:
setFConst(static_cast<float>(constant.getUConst()));
break;
case EbtBool:
setFConst(static_cast<float>(constant.getBConst()));
break;
case EbtFloat:
setFConst(static_cast<float>(constant.getFConst()));
break;
default:
return false;
}
break;
case EbtInt:
switch (constant.type)
{
case EbtInt:
setIConst(static_cast<int>(constant.getIConst()));
break;
case EbtUInt:
setIConst(static_cast<int>(constant.getUConst()));
break;
case EbtBool:
setIConst(static_cast<int>(constant.getBConst()));
break;
case EbtFloat:
setIConst(static_cast<int>(constant.getFConst()));
break;
default:
return false;
}
break;
case EbtUInt:
switch (constant.type)
{
case EbtInt:
setUConst(static_cast<unsigned int>(constant.getIConst()));
break;
case EbtUInt:
setUConst(static_cast<unsigned int>(constant.getUConst()));
break;
case EbtBool:
setUConst(static_cast<unsigned int>(constant.getBConst()));
break;
case EbtFloat:
setUConst(static_cast<unsigned int>(constant.getFConst()));
break;
default:
return false;
}
break;
case EbtBool:
switch (constant.type)
{
case EbtInt:
setBConst(constant.getIConst() != 0);
break;
case EbtUInt:
setBConst(constant.getUConst() != 0);
break;
case EbtBool:
setBConst(constant.getBConst());
break;
case EbtFloat:
setBConst(constant.getFConst() != 0.0f);
break;
default:
return false;
}
break;
case EbtStruct: // Struct fields don't get cast
switch (constant.type)
{
case EbtInt:
setIConst(constant.getIConst());
break;
case EbtUInt:
setUConst(constant.getUConst());
break;
case EbtBool:
setBConst(constant.getBConst());
break;
case EbtFloat:
setFConst(constant.getFConst());
break;
default:
return false;
}
break;
default:
return false;
}
return true;
}
bool TConstantUnion::operator==(const int i) const
{
return i == iConst;
}
bool TConstantUnion::operator==(const unsigned int u) const
{
return u == uConst;
}
bool TConstantUnion::operator==(const float f) const
{
return f == fConst;
}
bool TConstantUnion::operator==(const bool b) const
{
return b == bConst;
}
bool TConstantUnion::operator==(const TConstantUnion &constant) const
{
if (constant.type != type)
return false;
switch (type)
{
case EbtInt:
return constant.iConst == iConst;
case EbtUInt:
return constant.uConst == uConst;
case EbtFloat:
return constant.fConst == fConst;
case EbtBool:
return constant.bConst == bConst;
default:
return false;
}
}
bool TConstantUnion::operator!=(const int i) const
{
return !operator==(i);
}
bool TConstantUnion::operator!=(const unsigned int u) const
{
return !operator==(u);
}
bool TConstantUnion::operator!=(const float f) const
{
return !operator==(f);
}
bool TConstantUnion::operator!=(const bool b) const
{
return !operator==(b);
}
bool TConstantUnion::operator!=(const TConstantUnion &constant) const
{
return !operator==(constant);
}
bool TConstantUnion::operator>(const TConstantUnion &constant) const
{
ASSERT(type == constant.type);
switch (type)
{
case EbtInt:
return iConst > constant.iConst;
case EbtUInt:
return uConst > constant.uConst;
case EbtFloat:
return fConst > constant.fConst;
default:
return false; // Invalid operation, handled at semantic analysis
}
}
bool TConstantUnion::operator<(const TConstantUnion &constant) const
{
ASSERT(type == constant.type);
switch (type)
{
case EbtInt:
return iConst < constant.iConst;
case EbtUInt:
return uConst < constant.uConst;
case EbtFloat:
return fConst < constant.fConst;
default:
return false; // Invalid operation, handled at semantic analysis
}
}
// static
TConstantUnion TConstantUnion::add(const TConstantUnion &lhs,
const TConstantUnion &rhs,
TDiagnostics *diag)
{
TConstantUnion returnValue;
ASSERT(lhs.type == rhs.type);
switch (lhs.type)
{
case EbtInt:
returnValue.setIConst(lhs.iConst + rhs.iConst);
break;
case EbtUInt:
returnValue.setUConst(lhs.uConst + rhs.uConst);
break;
case EbtFloat:
returnValue.setFConst(lhs.fConst + rhs.fConst);
break;
default:
UNREACHABLE();
}
return returnValue;
}
// static
TConstantUnion TConstantUnion::sub(const TConstantUnion &lhs,
const TConstantUnion &rhs,
TDiagnostics *diag)
{
TConstantUnion returnValue;
ASSERT(lhs.type == rhs.type);
switch (lhs.type)
{
case EbtInt:
returnValue.setIConst(lhs.iConst - rhs.iConst);
break;
case EbtUInt:
returnValue.setUConst(lhs.uConst - rhs.uConst);
break;
case EbtFloat:
returnValue.setFConst(lhs.fConst - rhs.fConst);
break;
default:
UNREACHABLE();
}
return returnValue;
}
// static
TConstantUnion TConstantUnion::mul(const TConstantUnion &lhs,
const TConstantUnion &rhs,
TDiagnostics *diag)
{
TConstantUnion returnValue;
ASSERT(lhs.type == rhs.type);
switch (lhs.type)
{
case EbtInt:
returnValue.setIConst(lhs.iConst * rhs.iConst);
break;
case EbtUInt:
returnValue.setUConst(lhs.uConst * rhs.uConst);
break;
case EbtFloat:
returnValue.setFConst(lhs.fConst * rhs.fConst);
break;
default:
UNREACHABLE();
}
return returnValue;
}
TConstantUnion TConstantUnion::operator%(const TConstantUnion &constant) const
{
TConstantUnion returnValue;
ASSERT(type == constant.type);
switch (type)
{
case EbtInt:
returnValue.setIConst(iConst % constant.iConst);
break;
case EbtUInt:
returnValue.setUConst(uConst % constant.uConst);
break;
default:
UNREACHABLE();
}
return returnValue;
}
TConstantUnion TConstantUnion::operator>>(const TConstantUnion &constant) const
{
TConstantUnion returnValue;
ASSERT(type == constant.type);
switch (type)
{
case EbtInt:
returnValue.setIConst(iConst >> constant.iConst);
break;
case EbtUInt:
returnValue.setUConst(uConst >> constant.uConst);
break;
default:
UNREACHABLE();
}
return returnValue;
}
TConstantUnion TConstantUnion::operator<<(const TConstantUnion &constant) const
{
TConstantUnion returnValue;
// The signedness of the second parameter might be different, but we
// don't care, since the result is undefined if the second parameter is
// negative, and aliasing should not be a problem with unions.
ASSERT(constant.type == EbtInt || constant.type == EbtUInt);
switch (type)
{
case EbtInt:
returnValue.setIConst(iConst << constant.iConst);
break;
case EbtUInt:
returnValue.setUConst(uConst << constant.uConst);
break;
default:
UNREACHABLE();
}
return returnValue;
}
TConstantUnion TConstantUnion::operator&(const TConstantUnion &constant) const
{
TConstantUnion returnValue;
ASSERT(constant.type == EbtInt || constant.type == EbtUInt);
switch (type)
{
case EbtInt:
returnValue.setIConst(iConst & constant.iConst);
break;
case EbtUInt:
returnValue.setUConst(uConst & constant.uConst);
break;
default:
UNREACHABLE();
}
return returnValue;
}
TConstantUnion TConstantUnion::operator|(const TConstantUnion &constant) const
{
TConstantUnion returnValue;
ASSERT(type == constant.type);
switch (type)
{
case EbtInt:
returnValue.setIConst(iConst | constant.iConst);
break;
case EbtUInt:
returnValue.setUConst(uConst | constant.uConst);
break;
default:
UNREACHABLE();
}
return returnValue;
}
TConstantUnion TConstantUnion::operator^(const TConstantUnion &constant) const
{
TConstantUnion returnValue;
ASSERT(type == constant.type);
switch (type)
{
case EbtInt:
returnValue.setIConst(iConst ^ constant.iConst);
break;
case EbtUInt:
returnValue.setUConst(uConst ^ constant.uConst);
break;
default:
UNREACHABLE();
}
return returnValue;
}
TConstantUnion TConstantUnion::operator&&(const TConstantUnion &constant) const
{
TConstantUnion returnValue;
ASSERT(type == constant.type);
switch (type)
{
case EbtBool:
returnValue.setBConst(bConst && constant.bConst);
break;
default:
UNREACHABLE();
}
return returnValue;
}
TConstantUnion TConstantUnion::operator||(const TConstantUnion &constant) const
{
TConstantUnion returnValue;
ASSERT(type == constant.type);
switch (type)
{
case EbtBool:
returnValue.setBConst(bConst || constant.bConst);
break;
default:
UNREACHABLE();
}
return returnValue;
}

View File

@ -9,77 +9,18 @@
#include <assert.h>
#include "compiler/translator/Common.h"
#include "compiler/translator/BaseTypes.h"
class TConstantUnion {
public:
class TDiagnostics;
class TConstantUnion
{
public:
POOL_ALLOCATOR_NEW_DELETE();
TConstantUnion()
{
iConst = 0;
type = EbtVoid;
}
TConstantUnion();
bool cast(TBasicType newType, const TConstantUnion &constant)
{
switch (newType)
{
case EbtFloat:
switch (constant.type)
{
case EbtInt: setFConst(static_cast<float>(constant.getIConst())); break;
case EbtUInt: setFConst(static_cast<float>(constant.getUConst())); break;
case EbtBool: setFConst(static_cast<float>(constant.getBConst())); break;
case EbtFloat: setFConst(static_cast<float>(constant.getFConst())); break;
default: return false;
}
break;
case EbtInt:
switch (constant.type)
{
case EbtInt: setIConst(static_cast<int>(constant.getIConst())); break;
case EbtUInt: setIConst(static_cast<int>(constant.getUConst())); break;
case EbtBool: setIConst(static_cast<int>(constant.getBConst())); break;
case EbtFloat: setIConst(static_cast<int>(constant.getFConst())); break;
default: return false;
}
break;
case EbtUInt:
switch (constant.type)
{
case EbtInt: setUConst(static_cast<unsigned int>(constant.getIConst())); break;
case EbtUInt: setUConst(static_cast<unsigned int>(constant.getUConst())); break;
case EbtBool: setUConst(static_cast<unsigned int>(constant.getBConst())); break;
case EbtFloat: setUConst(static_cast<unsigned int>(constant.getFConst())); break;
default: return false;
}
break;
case EbtBool:
switch (constant.type)
{
case EbtInt: setBConst(constant.getIConst() != 0); break;
case EbtUInt: setBConst(constant.getUConst() != 0); break;
case EbtBool: setBConst(constant.getBConst()); break;
case EbtFloat: setBConst(constant.getFConst() != 0.0f); break;
default: return false;
}
break;
case EbtStruct: // Struct fields don't get cast
switch (constant.type)
{
case EbtInt: setIConst(constant.getIConst()); break;
case EbtUInt: setUConst(constant.getUConst()); break;
case EbtBool: setBConst(constant.getBConst()); break;
case EbtFloat: setFConst(constant.getFConst()); break;
default: return false;
}
break;
default:
return false;
}
return true;
}
bool cast(TBasicType newType, const TConstantUnion &constant);
void setIConst(int i) {iConst = i; type = EbtInt; }
void setUConst(unsigned int u) { uConst = u; type = EbtUInt; }
@ -91,256 +32,44 @@ public:
float getFConst() const { return fConst; }
bool getBConst() const { return bConst; }
bool operator==(const int i) const
{
return i == iConst;
}
bool operator==(const unsigned int u) const
{
return u == uConst;
}
bool operator==(const float f) const
{
return f == fConst;
}
bool operator==(const bool b) const
{
return b == bConst;
}
bool operator==(const TConstantUnion& constant) const
{
if (constant.type != type)
return false;
switch (type) {
case EbtInt:
return constant.iConst == iConst;
case EbtUInt:
return constant.uConst == uConst;
case EbtFloat:
return constant.fConst == fConst;
case EbtBool:
return constant.bConst == bConst;
default:
return false;
}
}
bool operator!=(const int i) const
{
return !operator==(i);
}
bool operator!=(const unsigned int u) const
{
return !operator==(u);
}
bool operator!=(const float f) const
{
return !operator==(f);
}
bool operator!=(const bool b) const
{
return !operator==(b);
}
bool operator!=(const TConstantUnion& constant) const
{
return !operator==(constant);
}
bool operator>(const TConstantUnion& constant) const
{
assert(type == constant.type);
switch (type) {
case EbtInt:
return iConst > constant.iConst;
case EbtUInt:
return uConst > constant.uConst;
case EbtFloat:
return fConst > constant.fConst;
default:
return false; // Invalid operation, handled at semantic analysis
}
}
bool operator<(const TConstantUnion& constant) const
{
assert(type == constant.type);
switch (type) {
case EbtInt:
return iConst < constant.iConst;
case EbtUInt:
return uConst < constant.uConst;
case EbtFloat:
return fConst < constant.fConst;
default:
return false; // Invalid operation, handled at semantic analysis
}
}
TConstantUnion operator+(const TConstantUnion& constant) const
{
TConstantUnion returnValue;
assert(type == constant.type);
switch (type) {
case EbtInt: returnValue.setIConst(iConst + constant.iConst); break;
case EbtUInt: returnValue.setUConst(uConst + constant.uConst); break;
case EbtFloat: returnValue.setFConst(fConst + constant.fConst); break;
default: assert(false && "Default missing");
}
return returnValue;
}
TConstantUnion operator-(const TConstantUnion& constant) const
{
TConstantUnion returnValue;
assert(type == constant.type);
switch (type) {
case EbtInt: returnValue.setIConst(iConst - constant.iConst); break;
case EbtUInt: returnValue.setUConst(uConst - constant.uConst); break;
case EbtFloat: returnValue.setFConst(fConst - constant.fConst); break;
default: assert(false && "Default missing");
}
return returnValue;
}
TConstantUnion operator*(const TConstantUnion& constant) const
{
TConstantUnion returnValue;
assert(type == constant.type);
switch (type) {
case EbtInt: returnValue.setIConst(iConst * constant.iConst); break;
case EbtUInt: returnValue.setUConst(uConst * constant.uConst); break;
case EbtFloat: returnValue.setFConst(fConst * constant.fConst); break;
default: assert(false && "Default missing");
}
return returnValue;
}
TConstantUnion operator%(const TConstantUnion& constant) const
{
TConstantUnion returnValue;
assert(type == constant.type);
switch (type) {
case EbtInt: returnValue.setIConst(iConst % constant.iConst); break;
case EbtUInt: returnValue.setUConst(uConst % constant.uConst); break;
default: assert(false && "Default missing");
}
return returnValue;
}
TConstantUnion operator>>(const TConstantUnion& constant) const
{
TConstantUnion returnValue;
assert(type == constant.type);
switch (type) {
case EbtInt: returnValue.setIConst(iConst >> constant.iConst); break;
case EbtUInt: returnValue.setUConst(uConst >> constant.uConst); break;
default: assert(false && "Default missing");
}
return returnValue;
}
TConstantUnion operator<<(const TConstantUnion& constant) const
{
TConstantUnion returnValue;
// The signedness of the second parameter might be different, but we
// don't care, since the result is undefined if the second parameter is
// negative, and aliasing should not be a problem with unions.
assert(constant.type == EbtInt || constant.type == EbtUInt);
switch (type) {
case EbtInt: returnValue.setIConst(iConst << constant.iConst); break;
case EbtUInt: returnValue.setUConst(uConst << constant.uConst); break;
default: assert(false && "Default missing");
}
return returnValue;
}
TConstantUnion operator&(const TConstantUnion& constant) const
{
TConstantUnion returnValue;
assert(constant.type == EbtInt || constant.type == EbtUInt);
switch (type) {
case EbtInt: returnValue.setIConst(iConst & constant.iConst); break;
case EbtUInt: returnValue.setUConst(uConst & constant.uConst); break;
default: assert(false && "Default missing");
}
return returnValue;
}
TConstantUnion operator|(const TConstantUnion& constant) const
{
TConstantUnion returnValue;
assert(type == constant.type);
switch (type) {
case EbtInt: returnValue.setIConst(iConst | constant.iConst); break;
case EbtUInt: returnValue.setUConst(uConst | constant.uConst); break;
default: assert(false && "Default missing");
}
return returnValue;
}
TConstantUnion operator^(const TConstantUnion& constant) const
{
TConstantUnion returnValue;
assert(type == constant.type);
switch (type) {
case EbtInt: returnValue.setIConst(iConst ^ constant.iConst); break;
case EbtUInt: returnValue.setUConst(uConst ^ constant.uConst); break;
default: assert(false && "Default missing");
}
return returnValue;
}
TConstantUnion operator&&(const TConstantUnion& constant) const
{
TConstantUnion returnValue;
assert(type == constant.type);
switch (type) {
case EbtBool: returnValue.setBConst(bConst && constant.bConst); break;
default: assert(false && "Default missing");
}
return returnValue;
}
TConstantUnion operator||(const TConstantUnion& constant) const
{
TConstantUnion returnValue;
assert(type == constant.type);
switch (type) {
case EbtBool: returnValue.setBConst(bConst || constant.bConst); break;
default: assert(false && "Default missing");
}
return returnValue;
}
bool operator==(const int i) const;
bool operator==(const unsigned int u) const;
bool operator==(const float f) const;
bool operator==(const bool b) const;
bool operator==(const TConstantUnion &constant) const;
bool operator!=(const int i) const;
bool operator!=(const unsigned int u) const;
bool operator!=(const float f) const;
bool operator!=(const bool b) const;
bool operator!=(const TConstantUnion &constant) const;
bool operator>(const TConstantUnion &constant) const;
bool operator<(const TConstantUnion &constant) const;
static TConstantUnion add(const TConstantUnion &lhs,
const TConstantUnion &rhs,
TDiagnostics *diag);
static TConstantUnion sub(const TConstantUnion &lhs,
const TConstantUnion &rhs,
TDiagnostics *diag);
static TConstantUnion mul(const TConstantUnion &lhs,
const TConstantUnion &rhs,
TDiagnostics *diag);
TConstantUnion operator%(const TConstantUnion &constant) const;
TConstantUnion operator>>(const TConstantUnion &constant) const;
TConstantUnion operator<<(const TConstantUnion &constant) const;
TConstantUnion operator&(const TConstantUnion &constant) const;
TConstantUnion operator|(const TConstantUnion &constant) const;
TConstantUnion operator^(const TConstantUnion &constant) const;
TConstantUnion operator&&(const TConstantUnion &constant) const;
TConstantUnion operator||(const TConstantUnion &constant) const;
TBasicType getType() const { return type; }
private:
union {
int iConst; // used for ivec, scalar ints
unsigned int uConst; // used for uvec, scalar uints
bool bConst; // used for bvec, scalar bools
float fConst; // used for vec, mat, scalar floats
} ;
private:
union {
int iConst; // used for ivec, scalar ints
unsigned int uConst; // used for uvec, scalar uints
bool bConst; // used for bvec, scalar bools
float fConst; // used for vec, mat, scalar floats
};
TBasicType type;
};

View File

@ -101,10 +101,8 @@ bool DeferGlobalInitializersTraverser::visitBinary(Visit visit, TIntermBinary *n
// Deferral is done also in any cases where the variable has not been constant folded,
// since otherwise there's a chance that HLSL output will generate extra statements
// from the initializer expression.
TIntermBinary *deferredInit = new TIntermBinary(EOpAssign);
deferredInit->setLeft(symbolNode->deepCopy());
deferredInit->setRight(node->getRight());
deferredInit->setType(node->getType());
TIntermBinary *deferredInit =
new TIntermBinary(EOpAssign, symbolNode->deepCopy(), node->getRight());
mDeferredInitializers.push_back(deferredInit);
// Change const global to a regular global if its initialization is deferred.

View File

@ -17,44 +17,18 @@
namespace
{
TIntermConstantUnion *constructIndexNode(int index)
{
TConstantUnion *u = new TConstantUnion[1];
u[0].setIConst(index);
TType type(EbtInt, EbpUndefined, EvqConst, 1);
TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
return node;
}
TIntermBinary *constructGLFragDataNode(int index)
{
TIntermBinary *indexDirect = new TIntermBinary(EOpIndexDirect);
TIntermSymbol *symbol = new TIntermSymbol(0, "gl_FragData", TType(EbtFloat, 4));
indexDirect->setLeft(symbol);
TIntermConstantUnion *indexNode = constructIndexNode(index);
indexDirect->setRight(indexNode);
return indexDirect;
}
TIntermBinary *constructGLFragDataAssignNode(int index)
{
TIntermBinary *assign = new TIntermBinary(EOpAssign);
assign->setLeft(constructGLFragDataNode(index));
assign->setRight(constructGLFragDataNode(0));
assign->setType(TType(EbtFloat, 4));
return assign;
}
class GLFragColorBroadcastTraverser : public TIntermTraverser
{
public:
GLFragColorBroadcastTraverser()
: TIntermTraverser(true, false, false), mMainSequence(nullptr), mGLFragColorUsed(false)
GLFragColorBroadcastTraverser(int maxDrawBuffers)
: TIntermTraverser(true, false, false),
mMainSequence(nullptr),
mGLFragColorUsed(false),
mMaxDrawBuffers(maxDrawBuffers)
{
}
void broadcastGLFragColor(int maxDrawBuffers);
void broadcastGLFragColor();
bool isGLFragColorUsed() const { return mGLFragColorUsed; }
@ -62,11 +36,35 @@ class GLFragColorBroadcastTraverser : public TIntermTraverser
void visitSymbol(TIntermSymbol *node) override;
bool visitAggregate(Visit visit, TIntermAggregate *node) override;
TIntermBinary *constructGLFragDataNode(int index) const;
TIntermBinary *constructGLFragDataAssignNode(int index) const;
private:
TIntermSequence *mMainSequence;
bool mGLFragColorUsed;
int mMaxDrawBuffers;
};
TIntermBinary *GLFragColorBroadcastTraverser::constructGLFragDataNode(int index) const
{
TType gl_FragDataType = TType(EbtFloat, EbpMedium, EvqFragData, 4);
gl_FragDataType.setArraySize(mMaxDrawBuffers);
TIntermSymbol *symbol = new TIntermSymbol(0, "gl_FragData", gl_FragDataType);
TIntermTyped *indexNode = TIntermTyped::CreateIndexNode(index);
TIntermBinary *binary = new TIntermBinary(EOpIndexDirect, symbol, indexNode);
return binary;
}
TIntermBinary *GLFragColorBroadcastTraverser::constructGLFragDataAssignNode(int index) const
{
TIntermTyped *fragDataIndex = constructGLFragDataNode(index);
TIntermTyped *fragDataZero = constructGLFragDataNode(0);
return new TIntermBinary(EOpAssign, fragDataIndex, fragDataZero);
}
void GLFragColorBroadcastTraverser::visitSymbol(TIntermSymbol *node)
{
if (node->getSymbol() == "gl_FragColor")
@ -101,9 +99,9 @@ bool GLFragColorBroadcastTraverser::visitAggregate(Visit visit, TIntermAggregate
return true;
}
void GLFragColorBroadcastTraverser::broadcastGLFragColor(int maxDrawBuffers)
void GLFragColorBroadcastTraverser::broadcastGLFragColor()
{
ASSERT(maxDrawBuffers > 1);
ASSERT(mMaxDrawBuffers > 1);
if (!mGLFragColorUsed)
{
return;
@ -113,7 +111,7 @@ void GLFragColorBroadcastTraverser::broadcastGLFragColor(int maxDrawBuffers)
// gl_FragData[1] = gl_FragData[0];
// ...
// gl_FragData[maxDrawBuffers - 1] = gl_FragData[0];
for (int colorIndex = 1; colorIndex < maxDrawBuffers; ++colorIndex)
for (int colorIndex = 1; colorIndex < mMaxDrawBuffers; ++colorIndex)
{
mMainSequence->insert(mMainSequence->end(), constructGLFragDataAssignNode(colorIndex));
}
@ -126,12 +124,12 @@ void EmulateGLFragColorBroadcast(TIntermNode *root,
std::vector<sh::OutputVariable> *outputVariables)
{
ASSERT(maxDrawBuffers > 1);
GLFragColorBroadcastTraverser traverser;
GLFragColorBroadcastTraverser traverser(maxDrawBuffers);
root->traverse(&traverser);
if (traverser.isGLFragColorUsed())
{
traverser.updateTree();
traverser.broadcastGLFragColor(maxDrawBuffers);
traverser.broadcastGLFragColor();
for (auto &var : *outputVariables)
{
if (var.name == "gl_FragColor")

View File

@ -124,10 +124,7 @@ bool Traverser::visitAggregate(Visit visit, TIntermAggregate *node)
// Create a chain of n-1 multiples.
for (int i = 1; i < n; ++i)
{
TIntermBinary *mul = new TIntermBinary(EOpMul);
mul->setLeft(current);
mul->setRight(createTempSymbol(lhs->getType()));
mul->setType(node->getType());
TIntermBinary *mul = new TIntermBinary(EOpMul, current, createTempSymbol(lhs->getType()));
mul->setLine(node->getLine());
current = mul;
}
@ -138,9 +135,7 @@ bool Traverser::visitAggregate(Visit visit, TIntermAggregate *node)
TConstantUnion *oneVal = new TConstantUnion();
oneVal->setFConst(1.0f);
TIntermConstantUnion *oneNode = new TIntermConstantUnion(oneVal, node->getType());
TIntermBinary *div = new TIntermBinary(EOpDiv);
div->setLeft(oneNode);
div->setRight(current);
TIntermBinary *div = new TIntermBinary(EOpDiv, oneNode, current);
current = div;
}

View File

@ -511,16 +511,13 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR
symbolTable.insertConstInt(ESSL1_BUILTINS, "gl_MaxVaryingVectors", resources.MaxVaryingVectors,
EbpMedium);
if (spec != SH_CSS_SHADERS_SPEC)
symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxDrawBuffers", resources.MaxDrawBuffers,
EbpMedium);
if (resources.EXT_blend_func_extended)
{
symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxDrawBuffers", resources.MaxDrawBuffers,
EbpMedium);
if (resources.EXT_blend_func_extended)
{
symbolTable.insertConstIntExt(COMMON_BUILTINS, "GL_EXT_blend_func_extended",
"gl_MaxDualSourceDrawBuffersEXT",
resources.MaxDualSourceDrawBuffers);
}
symbolTable.insertConstIntExt(COMMON_BUILTINS, "GL_EXT_blend_func_extended",
"gl_MaxDualSourceDrawBuffersEXT",
resources.MaxDualSourceDrawBuffers);
}
symbolTable.insertConstInt(ESSL3_BUILTINS, "gl_MaxVertexOutputVectors",
@ -590,85 +587,73 @@ void IdentifyBuiltIns(sh::GLenum type, ShShaderSpec spec,
switch (type)
{
case GL_FRAGMENT_SHADER:
symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_FragCoord"),
TType(EbtFloat, EbpMedium, EvqFragCoord, 4)));
symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_FrontFacing"),
TType(EbtBool, EbpUndefined, EvqFrontFacing, 1)));
symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_PointCoord"),
TType(EbtFloat, EbpMedium, EvqPointCoord, 2)));
{
symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_FragCoord"),
TType(EbtFloat, EbpMedium, EvqFragCoord, 4)));
symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_FrontFacing"),
TType(EbtBool, EbpUndefined, EvqFrontFacing, 1)));
symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_PointCoord"),
TType(EbtFloat, EbpMedium, EvqPointCoord, 2)));
//
// In CSS Shaders, gl_FragColor, gl_FragData, and gl_MaxDrawBuffers are not available.
// Instead, css_MixColor and css_ColorMatrix are available.
//
if (spec != SH_CSS_SHADERS_SPEC)
{
symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("gl_FragColor"),
TType(EbtFloat, EbpMedium, EvqFragColor, 4)));
TType fragData(EbtFloat, EbpMedium, EvqFragData, 4, 1, true);
fragData.setArraySize(resources.MaxDrawBuffers);
symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("gl_FragData"), fragData));
symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("gl_FragColor"),
TType(EbtFloat, EbpMedium, EvqFragColor, 4)));
TType fragData(EbtFloat, EbpMedium, EvqFragData, 4, 1, true);
fragData.setArraySize(resources.MaxDrawBuffers);
symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("gl_FragData"), fragData));
if (resources.EXT_blend_func_extended)
{
symbolTable.insert(
ESSL1_BUILTINS, "GL_EXT_blend_func_extended",
new TVariable(NewPoolTString("gl_SecondaryFragColorEXT"),
TType(EbtFloat, EbpMedium, EvqSecondaryFragColorEXT, 4)));
TType secondaryFragData(EbtFloat, EbpMedium, EvqSecondaryFragDataEXT, 4, 1, true);
secondaryFragData.setArraySize(resources.MaxDualSourceDrawBuffers);
symbolTable.insert(
ESSL1_BUILTINS, "GL_EXT_blend_func_extended",
new TVariable(NewPoolTString("gl_SecondaryFragDataEXT"), secondaryFragData));
}
if (resources.EXT_blend_func_extended)
{
symbolTable.insert(
ESSL1_BUILTINS, "GL_EXT_blend_func_extended",
new TVariable(NewPoolTString("gl_SecondaryFragColorEXT"),
TType(EbtFloat, EbpMedium, EvqSecondaryFragColorEXT, 4)));
TType secondaryFragData(EbtFloat, EbpMedium, EvqSecondaryFragDataEXT, 4, 1, true);
secondaryFragData.setArraySize(resources.MaxDualSourceDrawBuffers);
symbolTable.insert(
ESSL1_BUILTINS, "GL_EXT_blend_func_extended",
new TVariable(NewPoolTString("gl_SecondaryFragDataEXT"), secondaryFragData));
}
if (resources.EXT_frag_depth)
{
symbolTable.insert(
ESSL1_BUILTINS, "GL_EXT_frag_depth",
new TVariable(
NewPoolTString("gl_FragDepthEXT"),
TType(EbtFloat, resources.FragmentPrecisionHigh ? EbpHigh : EbpMedium,
EvqFragDepthEXT, 1)));
}
if (resources.EXT_frag_depth)
{
symbolTable.insert(
ESSL1_BUILTINS, "GL_EXT_frag_depth",
new TVariable(
NewPoolTString("gl_FragDepthEXT"),
TType(EbtFloat, resources.FragmentPrecisionHigh ? EbpHigh : EbpMedium,
EvqFragDepthEXT, 1)));
}
symbolTable.insert(ESSL3_BUILTINS,
new TVariable(NewPoolTString("gl_FragDepth"),
TType(EbtFloat, EbpHigh, EvqFragDepth, 1)));
symbolTable.insert(ESSL3_BUILTINS,
new TVariable(NewPoolTString("gl_FragDepth"),
TType(EbtFloat, EbpHigh, EvqFragDepth, 1)));
if (resources.EXT_shader_framebuffer_fetch || resources.NV_shader_framebuffer_fetch)
{
TType lastFragData(EbtFloat, EbpMedium, EvqLastFragData, 4, 1, true);
lastFragData.setArraySize(resources.MaxDrawBuffers);
if (resources.EXT_shader_framebuffer_fetch || resources.NV_shader_framebuffer_fetch)
{
TType lastFragData(EbtFloat, EbpMedium, EvqLastFragData, 4, 1, true);
lastFragData.setArraySize(resources.MaxDrawBuffers);
if (resources.EXT_shader_framebuffer_fetch)
{
symbolTable.insert(ESSL1_BUILTINS, "GL_EXT_shader_framebuffer_fetch",
new TVariable(NewPoolTString("gl_LastFragData"), lastFragData));
}
else if (resources.NV_shader_framebuffer_fetch)
{
symbolTable.insert(ESSL1_BUILTINS, "GL_NV_shader_framebuffer_fetch",
new TVariable(NewPoolTString("gl_LastFragColor"),
TType(EbtFloat, EbpMedium, EvqLastFragColor, 4)));
symbolTable.insert(ESSL1_BUILTINS, "GL_NV_shader_framebuffer_fetch",
new TVariable(NewPoolTString("gl_LastFragData"), lastFragData));
}
}
else if (resources.ARM_shader_framebuffer_fetch)
{
symbolTable.insert(ESSL1_BUILTINS, "GL_ARM_shader_framebuffer_fetch",
new TVariable(NewPoolTString("gl_LastFragColorARM"),
TType(EbtFloat, EbpMedium, EvqLastFragColor, 4)));
}
}
else
{
symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("css_MixColor"),
TType(EbtFloat, EbpMedium, EvqGlobal, 4)));
symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("css_ColorMatrix"),
TType(EbtFloat, EbpMedium, EvqGlobal, 4, 4)));
}
if (resources.EXT_shader_framebuffer_fetch)
{
symbolTable.insert(ESSL1_BUILTINS, "GL_EXT_shader_framebuffer_fetch",
new TVariable(NewPoolTString("gl_LastFragData"), lastFragData));
}
else if (resources.NV_shader_framebuffer_fetch)
{
symbolTable.insert(ESSL1_BUILTINS, "GL_NV_shader_framebuffer_fetch",
new TVariable(NewPoolTString("gl_LastFragColor"),
TType(EbtFloat, EbpMedium, EvqLastFragColor, 4)));
symbolTable.insert(ESSL1_BUILTINS, "GL_NV_shader_framebuffer_fetch",
new TVariable(NewPoolTString("gl_LastFragData"), lastFragData));
}
}
else if (resources.ARM_shader_framebuffer_fetch)
{
symbolTable.insert(ESSL1_BUILTINS, "GL_ARM_shader_framebuffer_fetch",
new TVariable(NewPoolTString("gl_LastFragColorARM"),
TType(EbtFloat, EbpMedium, EvqLastFragColor, 4)));
}
}
break;

View File

@ -14,46 +14,6 @@
namespace
{
TIntermConstantUnion *constructConstUnionNode(const TType &type)
{
TType myType = type;
myType.clearArrayness();
myType.setQualifier(EvqConst);
size_t size = myType.getObjectSize();
TConstantUnion *u = new TConstantUnion[size];
for (size_t ii = 0; ii < size; ++ii)
{
switch (type.getBasicType())
{
case EbtFloat:
u[ii].setFConst(0.0f);
break;
case EbtInt:
u[ii].setIConst(0);
break;
case EbtUInt:
u[ii].setUConst(0u);
break;
default:
UNREACHABLE();
return nullptr;
}
}
TIntermConstantUnion *node = new TIntermConstantUnion(u, myType);
return node;
}
TIntermConstantUnion *constructIndexNode(int index)
{
TConstantUnion *u = new TConstantUnion[1];
u[0].setIConst(index);
TType type(EbtInt, EbpUndefined, EvqConst, 1);
TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
return node;
}
class VariableInitializer : public TIntermTraverser
{
public:
@ -120,73 +80,43 @@ bool VariableInitializer::visitAggregate(Visit visit, TIntermAggregate *node)
void VariableInitializer::insertInitCode(TIntermSequence *sequence)
{
for (size_t ii = 0; ii < mVariables.size(); ++ii)
for (const auto &var : mVariables)
{
const sh::ShaderVariable &var = mVariables[ii];
TString name = TString(var.name.c_str());
TType type = sh::GetShaderVariableType(var);
// Assign the array elements one by one to keep the AST compatible with ESSL 1.00 which
// doesn't have array assignment.
if (var.isArray())
{
TType type = sh::ConvertShaderVariableTypeToTType(var.type);
size_t pos = name.find_last_of('[');
if (pos != TString::npos)
{
name = name.substr(0, pos);
for (int index = static_cast<int>(var.arraySize) - 1; index >= 0; --index)
{
TIntermBinary *assign = new TIntermBinary(EOpAssign);
sequence->insert(sequence->begin(), assign);
TIntermBinary *indexDirect = new TIntermBinary(EOpIndexDirect);
TIntermSymbol *symbol = new TIntermSymbol(0, name, type);
indexDirect->setLeft(symbol);
TIntermConstantUnion *indexNode = constructIndexNode(index);
indexDirect->setRight(indexNode);
assign->setLeft(indexDirect);
TIntermConstantUnion *zeroConst = constructConstUnionNode(type);
assign->setRight(zeroConst);
}
}
else if (var.isStruct())
{
TFieldList *fields = new TFieldList;
TSourceLoc loc;
for (auto field : var.fields)
{
fields->push_back(new TField(nullptr, new TString(field.name.c_str()), loc));
}
TStructure *structure = new TStructure(new TString(var.structName.c_str()), fields);
TType type;
type.setStruct(structure);
for (int fieldIndex = 0; fieldIndex < static_cast<int>(var.fields.size()); ++fieldIndex)
{
TIntermBinary *assign = new TIntermBinary(EOpAssign);
sequence->insert(sequence->begin(), assign);
TType elementType = type;
elementType.clearArrayness();
TIntermBinary *indexDirectStruct = new TIntermBinary(EOpIndexDirectStruct);
TIntermSymbol *symbol = new TIntermSymbol(0, name, type);
indexDirectStruct->setLeft(symbol);
TIntermConstantUnion *indexNode = constructIndexNode(fieldIndex);
indexDirectStruct->setRight(indexNode);
assign->setLeft(indexDirectStruct);
for (unsigned int i = 0; i < var.arraySize; ++i)
{
TIntermSymbol *arraySymbol = new TIntermSymbol(0, name, type);
TIntermBinary *element = new TIntermBinary(EOpIndexDirect, arraySymbol,
TIntermTyped::CreateIndexNode(i));
const sh::ShaderVariable &field = var.fields[fieldIndex];
TType fieldType = sh::ConvertShaderVariableTypeToTType(field.type);
TIntermConstantUnion *zeroConst = constructConstUnionNode(fieldType);
assign->setRight(zeroConst);
TIntermTyped *zero = TIntermTyped::CreateZero(elementType);
TIntermBinary *assignment = new TIntermBinary(EOpAssign, element, zero);
sequence->insert(sequence->begin(), assignment);
}
}
else
{
TType type = sh::ConvertShaderVariableTypeToTType(var.type);
TIntermBinary *assign = new TIntermBinary(EOpAssign);
sequence->insert(sequence->begin(), assign);
TIntermSymbol *symbol = new TIntermSymbol(0, name, type);
assign->setLeft(symbol);
TIntermConstantUnion *zeroConst = constructConstUnionNode(type);
assign->setRight(zeroConst);
}
TIntermTyped *zero = TIntermTyped::CreateZero(type);
TIntermBinary *assign = new TIntermBinary(EOpAssign, symbol, zero);
sequence->insert(sequence->begin(), assign);
}
}
}

View File

@ -13,6 +13,7 @@ class TIntermNode;
typedef std::vector<sh::ShaderVariable> InitVariableList;
// This function cannot currently initialize structures containing arrays for an ESSL 1.00 backend.
void InitializeVariables(TIntermNode *root, const InitVariableList &vars);
#endif // COMPILER_TRANSLATOR_INITIALIZEVARIABLES_H_

File diff suppressed because it is too large Load Diff

View File

@ -34,6 +34,7 @@ class TIntermAggregate;
class TIntermBinary;
class TIntermUnary;
class TIntermConstantUnion;
class TIntermTernary;
class TIntermSelection;
class TIntermSwitch;
class TIntermCase;
@ -93,6 +94,7 @@ class TIntermNode : angle::NonCopyable
virtual TIntermAggregate *getAsAggregate() { return 0; }
virtual TIntermBinary *getAsBinaryNode() { return 0; }
virtual TIntermUnary *getAsUnaryNode() { return 0; }
virtual TIntermTernary *getAsTernaryNode() { return nullptr; }
virtual TIntermSelection *getAsSelectionNode() { return 0; }
virtual TIntermSwitch *getAsSwitchNode() { return 0; }
virtual TIntermCase *getAsCaseNode() { return 0; }
@ -159,6 +161,9 @@ class TIntermTyped : public TIntermNode
bool isConstructorWithOnlyConstantUnionParameters();
static TIntermTyped *CreateIndexNode(int index);
static TIntermTyped *CreateZero(const TType &type);
protected:
TType mType;
@ -316,6 +321,7 @@ class TIntermConstantUnion : public TIntermTyped
TIntermConstantUnion(const TConstantUnion *unionPointer, const TType &type)
: TIntermTyped(type), mUnionArrayPointer(unionPointer)
{
ASSERT(unionPointer);
}
TIntermTyped *deepCopy() const override { return new TIntermConstantUnion(*this); }
@ -343,6 +349,7 @@ class TIntermConstantUnion : public TIntermTyped
void replaceConstantUnion(const TConstantUnion *safeConstantUnion)
{
ASSERT(safeConstantUnion);
// Previous union pointer freed on pool deallocation.
mUnionArrayPointer = safeConstantUnion;
}
@ -354,12 +361,13 @@ class TIntermConstantUnion : public TIntermTyped
TConstantUnion *foldBinary(TOperator op,
TIntermConstantUnion *rightNode,
TDiagnostics *diagnostics);
TConstantUnion *foldUnaryWithDifferentReturnType(TOperator op, TInfoSink &infoSink);
TConstantUnion *foldUnaryWithSameReturnType(TOperator op, TInfoSink &infoSink);
const TConstantUnion *foldIndexing(int index);
TConstantUnion *foldUnaryNonComponentWise(TOperator op);
TConstantUnion *foldUnaryComponentWise(TOperator op, TDiagnostics *diagnostics);
static TConstantUnion *FoldAggregateConstructor(TIntermAggregate *aggregate,
TInfoSink &infoSink);
static TConstantUnion *FoldAggregateBuiltIn(TIntermAggregate *aggregate, TInfoSink &infoSink);
static TConstantUnion *FoldAggregateConstructor(TIntermAggregate *aggregate);
static TConstantUnion *FoldAggregateBuiltIn(TIntermAggregate *aggregate,
TDiagnostics *diagnostics);
protected:
// Same data may be shared between multiple constant unions, so it can't be modified.
@ -367,7 +375,9 @@ class TIntermConstantUnion : public TIntermTyped
private:
typedef float(*FloatTypeUnaryFunc) (float);
bool foldFloatTypeUnary(const TConstantUnion &parameter, FloatTypeUnaryFunc builtinFunc, TInfoSink &infoSink, TConstantUnion *result) const;
void foldFloatTypeUnary(const TConstantUnion &parameter,
FloatTypeUnaryFunc builtinFunc,
TConstantUnion *result) const;
TIntermConstantUnion(const TIntermConstantUnion &node); // Note: not deleted, just private!
};
@ -379,7 +389,6 @@ class TIntermOperator : public TIntermTyped
{
public:
TOperator getOp() const { return mOp; }
void setOp(TOperator op) { mOp = op; }
bool isAssignment() const;
bool isMultiplication() const;
@ -406,12 +415,7 @@ class TIntermOperator : public TIntermTyped
class TIntermBinary : public TIntermOperator
{
public:
TIntermBinary(TOperator op)
: TIntermOperator(op),
mAddIndexClamp(false) {}
// This constructor determines the type of the binary node based on the operands and op.
// This is only supported for math/logical ops, not indexing.
TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right);
TIntermTyped *deepCopy() const override { return new TIntermBinary(*this); }
@ -428,8 +432,6 @@ class TIntermBinary : public TIntermOperator
return isAssignment() || mLeft->hasSideEffects() || mRight->hasSideEffects();
}
void setLeft(TIntermTyped *node) { mLeft = node; }
void setRight(TIntermTyped *node) { mRight = node; }
TIntermTyped *getLeft() const { return mLeft; }
TIntermTyped *getRight() const { return mRight; }
TIntermTyped *fold(TDiagnostics *diagnostics);
@ -456,14 +458,7 @@ class TIntermBinary : public TIntermOperator
class TIntermUnary : public TIntermOperator
{
public:
TIntermUnary(TOperator op, const TType &type)
: TIntermOperator(op, type),
mOperand(NULL),
mUseEmulatedFunction(false) {}
TIntermUnary(TOperator op)
: TIntermOperator(op),
mOperand(NULL),
mUseEmulatedFunction(false) {}
TIntermUnary(TOperator op, TIntermTyped *operand);
TIntermTyped *deepCopy() const override { return new TIntermUnary(*this); }
@ -473,10 +468,8 @@ class TIntermUnary : public TIntermOperator
bool hasSideEffects() const override { return isAssignment() || mOperand->hasSideEffects(); }
void setOperand(TIntermTyped *operand) { mOperand = operand; }
TIntermTyped *getOperand() { return mOperand; }
void promote(const TType *funcReturnType);
TIntermTyped *fold(TInfoSink &infoSink);
TIntermTyped *fold(TDiagnostics *diagnostics);
void setUseEmulatedFunction() { mUseEmulatedFunction = true; }
bool getUseEmulatedFunction() { return mUseEmulatedFunction; }
@ -489,6 +482,8 @@ class TIntermUnary : public TIntermOperator
bool mUseEmulatedFunction;
private:
void promote();
TIntermUnary(const TIntermUnary &node); // note: not deleted, just private!
};
@ -522,6 +517,8 @@ class TIntermAggregate : public TIntermOperator
// Note: only supported for nodes that can be a part of an expression.
TIntermTyped *deepCopy() const override { return new TIntermAggregate(*this); }
void setOp(TOperator op) { mOp = op; }
TIntermAggregate *getAsAggregate() override { return this; }
void traverse(TIntermTraverser *it) override;
bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
@ -529,9 +526,10 @@ class TIntermAggregate : public TIntermOperator
bool insertChildNodes(TIntermSequence::size_type position, TIntermSequence insertions);
// Conservatively assume function calls and other aggregate operators have side-effects
bool hasSideEffects() const override { return true; }
TIntermTyped *fold(TInfoSink &infoSink);
TIntermTyped *fold(TDiagnostics *diagnostics);
TIntermSequence *getSequence() { return &mSequence; }
const TIntermSequence *getSequence() const { return &mSequence; }
void setNameObj(const TName &name) { mName = name; }
const TName &getNameObj() const { return mName; }
@ -571,35 +569,53 @@ class TIntermAggregate : public TIntermOperator
TIntermAggregate(const TIntermAggregate &node); // note: not deleted, just private!
};
//
// For if tests.
//
class TIntermSelection : public TIntermTyped
// For ternary operators like a ? b : c.
class TIntermTernary : public TIntermTyped
{
public:
TIntermSelection(TIntermTyped *cond, TIntermNode *trueB, TIntermNode *falseB)
: TIntermTyped(TType(EbtVoid, EbpUndefined)),
mCondition(cond),
mTrueBlock(trueB),
mFalseBlock(falseB) {}
TIntermSelection(TIntermTyped *cond, TIntermNode *trueB, TIntermNode *falseB,
const TType &type)
: TIntermTyped(type),
mCondition(cond),
mTrueBlock(trueB),
mFalseBlock(falseB) {}
// Note: only supported for ternary operator nodes.
TIntermTyped *deepCopy() const override { return new TIntermSelection(*this); }
TIntermTernary(TIntermTyped *cond, TIntermTyped *trueExpression, TIntermTyped *falseExpression);
void traverse(TIntermTraverser *it) override;
bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
// Conservatively assume selections have side-effects
bool hasSideEffects() const override { return true; }
TIntermTyped *getCondition() const { return mCondition; }
TIntermTyped *getTrueExpression() const { return mTrueExpression; }
TIntermTyped *getFalseExpression() const { return mFalseExpression; }
TIntermTernary *getAsTernaryNode() override { return this; }
bool usesTernaryOperator() const { return getBasicType() != EbtVoid; }
TIntermNode *getCondition() const { return mCondition; }
TIntermTyped *deepCopy() const override { return new TIntermTernary(*this); }
bool hasSideEffects() const override
{
return mCondition->hasSideEffects() || mTrueExpression->hasSideEffects() ||
mFalseExpression->hasSideEffects();
}
static TQualifier DetermineQualifier(TIntermTyped *cond,
TIntermTyped *trueExpression,
TIntermTyped *falseExpression);
private:
TIntermTernary(const TIntermTernary &node); // Note: not deleted, just private!
TIntermTyped *mCondition;
TIntermTyped *mTrueExpression;
TIntermTyped *mFalseExpression;
};
// For if tests.
class TIntermSelection : public TIntermNode
{
public:
TIntermSelection(TIntermTyped *cond, TIntermNode *trueB, TIntermNode *falseB)
: TIntermNode(), mCondition(cond), mTrueBlock(trueB), mFalseBlock(falseB)
{
}
void traverse(TIntermTraverser *it) override;
bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
TIntermTyped *getCondition() const { return mCondition; }
TIntermNode *getTrueBlock() const { return mTrueBlock; }
TIntermNode *getFalseBlock() const { return mFalseBlock; }
TIntermSelection *getAsSelectionNode() override { return this; }
@ -608,9 +624,6 @@ class TIntermSelection : public TIntermTyped
TIntermTyped *mCondition;
TIntermNode *mTrueBlock;
TIntermNode *mFalseBlock;
private:
TIntermSelection(const TIntermSelection &node); // Note: not deleted, just private!
};
//
@ -696,6 +709,7 @@ class TIntermTraverser : angle::NonCopyable
virtual void visitConstantUnion(TIntermConstantUnion *node) {}
virtual bool visitBinary(Visit visit, TIntermBinary *node) { return true; }
virtual bool visitUnary(Visit visit, TIntermUnary *node) { return true; }
virtual bool visitTernary(Visit visit, TIntermTernary *node) { return true; }
virtual bool visitSelection(Visit visit, TIntermSelection *node) { return true; }
virtual bool visitSwitch(Visit visit, TIntermSwitch *node) { return true; }
virtual bool visitCase(Visit visit, TIntermCase *node) { return true; }
@ -711,6 +725,7 @@ class TIntermTraverser : angle::NonCopyable
virtual void traverseConstantUnion(TIntermConstantUnion *node);
virtual void traverseBinary(TIntermBinary *node);
virtual void traverseUnary(TIntermUnary *node);
virtual void traverseTernary(TIntermTernary *node);
virtual void traverseSelection(TIntermSelection *node);
virtual void traverseSwitch(TIntermSwitch *node);
virtual void traverseCase(TIntermCase *node);
@ -998,6 +1013,7 @@ class TMaxDepthTraverser : public TIntermTraverser
bool visitBinary(Visit, TIntermBinary *) override { return depthCheck(); }
bool visitUnary(Visit, TIntermUnary *) override { return depthCheck(); }
bool visitTernary(Visit, TIntermTernary *) override { return depthCheck(); }
bool visitSelection(Visit, TIntermSelection *) override { return depthCheck(); }
bool visitAggregate(Visit, TIntermAggregate *) override { return depthCheck(); }
bool visitLoop(Visit, TIntermLoop *) override { return depthCheck(); }

View File

@ -105,14 +105,11 @@ bool IntermNodePatternMatcher::match(TIntermAggregate *node, TIntermNode *parent
return false;
}
bool IntermNodePatternMatcher::match(TIntermSelection *node)
bool IntermNodePatternMatcher::match(TIntermTernary *node)
{
if ((mMask & kUnfoldedShortCircuitExpression) != 0)
{
if (node->usesTernaryOperator())
{
return true;
}
return true;
}
return false;
}

View File

@ -14,7 +14,7 @@
class TIntermAggregate;
class TIntermBinary;
class TIntermNode;
class TIntermSelection;
class TIntermTernary;
class IntermNodePatternMatcher
{
@ -42,7 +42,7 @@ class IntermNodePatternMatcher
bool match(TIntermBinary *node, TIntermNode *parentNode, bool isLValueRequiredHere);
bool match(TIntermAggregate *node, TIntermNode *parentNode);
bool match(TIntermSelection *node);
bool match(TIntermTernary *node);
private:
const unsigned int mMask;

View File

@ -33,6 +33,11 @@ void TIntermUnary::traverse(TIntermTraverser *it)
it->traverseUnary(this);
}
void TIntermTernary::traverse(TIntermTraverser *it)
{
it->traverseTernary(this);
}
void TIntermSelection::traverse(TIntermTraverser *it)
{
it->traverseSelection(this);
@ -147,10 +152,7 @@ TIntermAggregate *TIntermTraverser::createTempInitDeclaration(TIntermTyped *init
ASSERT(initializer != nullptr);
TIntermSymbol *tempSymbol = createTempSymbol(initializer->getType(), qualifier);
TIntermAggregate *tempDeclaration = new TIntermAggregate(EOpDeclaration);
TIntermBinary *tempInit = new TIntermBinary(EOpInitialize);
tempInit->setLeft(tempSymbol);
tempInit->setRight(initializer);
tempInit->setType(tempSymbol->getType());
TIntermBinary *tempInit = new TIntermBinary(EOpInitialize, tempSymbol, initializer);
tempDeclaration->getSequence()->push_back(tempInit);
return tempDeclaration;
}
@ -164,10 +166,7 @@ TIntermBinary *TIntermTraverser::createTempAssignment(TIntermTyped *rightNode)
{
ASSERT(rightNode != nullptr);
TIntermSymbol *tempSymbol = createTempSymbol(rightNode->getType());
TIntermBinary *assignment = new TIntermBinary(EOpAssign);
assignment->setLeft(tempSymbol);
assignment->setRight(rightNode);
assignment->setType(tempSymbol->getType());
TIntermBinary *assignment = new TIntermBinary(EOpAssign, tempSymbol, rightNode);
return assignment;
}
@ -572,6 +571,31 @@ void TLValueTrackingTraverser::traverseAggregate(TIntermAggregate *node)
visitAggregate(PostVisit, node);
}
//
// Traverse a ternary node. Same comments in binary node apply here.
//
void TIntermTraverser::traverseTernary(TIntermTernary *node)
{
bool visit = true;
if (preVisit)
visit = visitTernary(PreVisit, node);
if (visit)
{
incrementDepth(node);
node->getCondition()->traverse(this);
if (node->getTrueExpression())
node->getTrueExpression()->traverse(this);
if (node->getFalseExpression())
node->getFalseExpression()->traverse(this);
decrementDepth();
}
if (visit && postVisit)
visitTernary(PostVisit, node);
}
//
// Traverse a selection node. Same comments in binary node apply here.
//

View File

@ -44,38 +44,20 @@ TIntermSymbol *TIntermediate::addSymbol(
// Returns the added node.
// The caller should set the type of the returned node.
//
TIntermTyped *TIntermediate::addIndex(
TOperator op, TIntermTyped *base, TIntermTyped *index, const TSourceLoc &line)
TIntermTyped *TIntermediate::addIndex(TOperator op,
TIntermTyped *base,
TIntermTyped *index,
const TSourceLoc &line,
TDiagnostics *diagnostics)
{
TIntermBinary *node = new TIntermBinary(op);
TIntermBinary *node = new TIntermBinary(op, base, index);
node->setLine(line);
node->setLeft(base);
node->setRight(index);
// caller should set the type
return node;
}
//
// Add one node as the parent of another that it operates on.
//
// Returns the added node.
//
TIntermTyped *TIntermediate::addUnaryMath(
TOperator op, TIntermTyped *child, const TSourceLoc &line, const TType *funcReturnType)
{
//
// Make a new node for the operator.
//
TIntermUnary *node = new TIntermUnary(op);
node->setLine(line);
node->setOperand(child);
node->promote(funcReturnType);
TIntermTyped *foldedNode = node->fold(mInfoSink);
if (foldedNode)
return foldedNode;
TIntermTyped *folded = node->fold(diagnostics);
if (folded)
{
return folded;
}
return node;
}
@ -254,43 +236,37 @@ TIntermTyped *TIntermediate::addComma(TIntermTyped *left,
return commaNode;
}
//
// For "?:" test nodes. There are three children; a condition,
// a true path, and a false path. The two paths are specified
// as separate parameters.
//
// Returns the selection node created, or one of trueBlock and falseBlock if the expression could be folded.
//
TIntermTyped *TIntermediate::addSelection(TIntermTyped *cond, TIntermTyped *trueBlock, TIntermTyped *falseBlock,
const TSourceLoc &line)
// Returns the ternary node created, or one of trueExpression and falseExpression if the expression
// could be folded.
TIntermTyped *TIntermediate::AddTernarySelection(TIntermTyped *cond,
TIntermTyped *trueExpression,
TIntermTyped *falseExpression,
const TSourceLoc &line)
{
TQualifier resultQualifier = EvqTemporary;
if (cond->getQualifier() == EvqConst && trueBlock->getQualifier() == EvqConst &&
falseBlock->getQualifier() == EvqConst)
{
resultQualifier = EvqConst;
}
// Note that the node resulting from here can be a constant union without being qualified as
// constant.
if (cond->getAsConstantUnion())
{
TQualifier resultQualifier =
TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression);
if (cond->getAsConstantUnion()->getBConst(0))
{
trueBlock->getTypePointer()->setQualifier(resultQualifier);
return trueBlock;
trueExpression->getTypePointer()->setQualifier(resultQualifier);
return trueExpression;
}
else
{
falseBlock->getTypePointer()->setQualifier(resultQualifier);
return falseBlock;
falseExpression->getTypePointer()->setQualifier(resultQualifier);
return falseExpression;
}
}
//
// Make a selection node.
//
TIntermSelection *node = new TIntermSelection(cond, trueBlock, falseBlock, trueBlock->getType());
node->getTypePointer()->setQualifier(resultQualifier);
// Make a ternary node.
TIntermTernary *node = new TIntermTernary(cond, trueExpression, falseExpression);
node->setLine(line);
return node;
@ -335,6 +311,7 @@ TIntermTyped *TIntermediate::addSwizzle(
{
TIntermAggregate *node = new TIntermAggregate(EOpSequence);
node->getTypePointer()->setQualifier(EvqConst);
node->setLine(line);
TIntermConstantUnion *constIntNode;
@ -388,7 +365,7 @@ TIntermBranch* TIntermediate::addBranch(
// This is to be executed once the final root is put on top by the parsing
// process.
//
TIntermAggregate *TIntermediate::postProcess(TIntermNode *root)
TIntermAggregate *TIntermediate::PostProcess(TIntermNode *root)
{
if (root == nullptr)
return nullptr;
@ -411,7 +388,8 @@ TIntermAggregate *TIntermediate::postProcess(TIntermNode *root)
return aggRoot;
}
TIntermTyped *TIntermediate::foldAggregateBuiltIn(TIntermAggregate *aggregate)
TIntermTyped *TIntermediate::foldAggregateBuiltIn(TIntermAggregate *aggregate,
TDiagnostics *diagnostics)
{
switch (aggregate->getOp())
{
@ -438,12 +416,12 @@ TIntermTyped *TIntermediate::foldAggregateBuiltIn(TIntermAggregate *aggregate)
case EOpFaceForward:
case EOpReflect:
case EOpRefract:
return aggregate->fold(mInfoSink);
return aggregate->fold(diagnostics);
default:
// TODO: Add support for folding array constructors
if (aggregate->isConstructor() && !aggregate->isArray())
{
return aggregate->fold(mInfoSink);
return aggregate->fold(diagnostics);
}
// Constant folding not supported for the built-in.
return nullptr;

View File

@ -16,20 +16,21 @@ struct TVectorFields
};
//
// Set of helper functions to help parse and build the tree.
// Set of helper functions to help build the tree.
//
class TInfoSink;
class TIntermediate
{
public:
POOL_ALLOCATOR_NEW_DELETE();
TIntermediate(TInfoSink &i)
: mInfoSink(i) { }
TIntermediate() {}
TIntermSymbol *addSymbol(
int id, const TString &, const TType &, const TSourceLoc &);
TIntermTyped *addIndex(
TOperator op, TIntermTyped *base, TIntermTyped *index, const TSourceLoc &);
TIntermTyped *addIndex(TOperator op,
TIntermTyped *base,
TIntermTyped *index,
const TSourceLoc &line,
TDiagnostics *diagnostics);
TIntermTyped *addUnaryMath(
TOperator op, TIntermTyped *child, const TSourceLoc &line, const TType *funcReturnType);
TIntermAggregate *growAggregate(
@ -37,9 +38,11 @@ class TIntermediate
TIntermAggregate *makeAggregate(TIntermNode *node, const TSourceLoc &);
TIntermAggregate *ensureSequence(TIntermNode *node);
TIntermAggregate *setAggregateOperator(TIntermNode *, TOperator, const TSourceLoc &);
TIntermNode *addSelection(TIntermTyped *cond, TIntermNodePair code, const TSourceLoc &);
TIntermTyped *addSelection(TIntermTyped *cond, TIntermTyped *trueBlock, TIntermTyped *falseBlock,
const TSourceLoc &line);
TIntermNode *addSelection(TIntermTyped *cond, TIntermNodePair code, const TSourceLoc &line);
static TIntermTyped *AddTernarySelection(TIntermTyped *cond,
TIntermTyped *trueExpression,
TIntermTyped *falseExpression,
const TSourceLoc &line);
TIntermSwitch *addSwitch(
TIntermTyped *init, TIntermAggregate *statementList, const TSourceLoc &line);
TIntermCase *addCase(
@ -56,16 +59,14 @@ class TIntermediate
TIntermBranch *addBranch(TOperator, const TSourceLoc &);
TIntermBranch *addBranch(TOperator, TIntermTyped *, const TSourceLoc &);
TIntermTyped *addSwizzle(TVectorFields &, const TSourceLoc &);
TIntermAggregate *postProcess(TIntermNode *root);
static TIntermAggregate *PostProcess(TIntermNode *root);
static void outputTree(TIntermNode *, TInfoSinkBase &);
TIntermTyped *foldAggregateBuiltIn(TIntermAggregate *aggregate);
TIntermTyped *foldAggregateBuiltIn(TIntermAggregate *aggregate, TDiagnostics *diagnostics);
private:
void operator=(TIntermediate &); // prevent assignments
TInfoSink & mInfoSink;
};
#endif // COMPILER_TRANSLATOR_INTERMEDIATE_H_

View File

@ -27,11 +27,9 @@ bool isSingleStatement(TIntermNode *node)
return (aggregate->getOp() != EOpFunction) &&
(aggregate->getOp() != EOpSequence);
}
else if (const TIntermSelection *selection = node->getAsSelectionNode())
else if (node->getAsSelectionNode())
{
// Ternary operators are usually part of an assignment operator.
// This handles those rare cases in which they are all by themselves.
return selection->usesTernaryOperator();
return false;
}
else if (node->getAsLoopNode())
{
@ -711,40 +709,40 @@ bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
return true;
}
bool TOutputGLSLBase::visitTernary(Visit visit, TIntermTernary *node)
{
TInfoSinkBase &out = objSink();
// Notice two brackets at the beginning and end. The outer ones
// encapsulate the whole ternary expression. This preserves the
// order of precedence when ternary expressions are used in a
// compound expression, i.e., c = 2 * (a < b ? 1 : 2).
out << "((";
node->getCondition()->traverse(this);
out << ") ? (";
node->getTrueExpression()->traverse(this);
out << ") : (";
node->getFalseExpression()->traverse(this);
out << "))";
return false;
}
bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection *node)
{
TInfoSinkBase &out = objSink();
if (node->usesTernaryOperator())
{
// Notice two brackets at the beginning and end. The outer ones
// encapsulate the whole ternary expression. This preserves the
// order of precedence when ternary expressions are used in a
// compound expression, i.e., c = 2 * (a < b ? 1 : 2).
out << "((";
node->getCondition()->traverse(this);
out << ") ? (";
node->getTrueBlock()->traverse(this);
out << ") : (";
node->getFalseBlock()->traverse(this);
out << "))";
}
else
{
out << "if (";
node->getCondition()->traverse(this);
out << ")\n";
out << "if (";
node->getCondition()->traverse(this);
out << ")\n";
incrementDepth(node);
visitCodeBlock(node->getTrueBlock());
incrementDepth(node);
visitCodeBlock(node->getTrueBlock());
if (node->getFalseBlock())
{
out << "else\n";
visitCodeBlock(node->getFalseBlock());
}
decrementDepth();
if (node->getFalseBlock())
{
out << "else\n";
visitCodeBlock(node->getFalseBlock());
}
decrementDepth();
return false;
}

View File

@ -44,6 +44,7 @@ class TOutputGLSLBase : public TIntermTraverser
void visitConstantUnion(TIntermConstantUnion *node) override;
bool visitBinary(Visit visit, TIntermBinary *node) override;
bool visitUnary(Visit visit, TIntermUnary *node) override;
bool visitTernary(Visit visit, TIntermTernary *node) override;
bool visitSelection(Visit visit, TIntermSelection *node) override;
bool visitSwitch(Visit visit, TIntermSwitch *node) override;
bool visitCase(Visit visit, TIntermCase *node) override;

View File

@ -80,11 +80,14 @@ const TConstantUnion *WriteConstantUnionArray(TInfoSinkBase &out,
namespace sh
{
OutputHLSL::OutputHLSL(sh::GLenum shaderType, int shaderVersion,
const TExtensionBehavior &extensionBehavior,
const char *sourcePath, ShShaderOutput outputType,
int numRenderTargets, const std::vector<Uniform> &uniforms,
int compileOptions)
OutputHLSL::OutputHLSL(sh::GLenum shaderType,
int shaderVersion,
const TExtensionBehavior &extensionBehavior,
const char *sourcePath,
ShShaderOutput outputType,
int numRenderTargets,
const std::vector<Uniform> &uniforms,
ShCompileOptions compileOptions)
: TIntermTraverser(true, true, true),
mShaderType(shaderType),
mShaderVersion(shaderVersion),
@ -1456,9 +1459,8 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
// case statements into non-empty case statements, disallowing fall-through from them.
// Also no need to output ; after selection (if) statements or sequences. This is done just
// for code clarity.
TIntermSelection *asSelection = (*sit)->getAsSelectionNode();
ASSERT(asSelection == nullptr || !asSelection->usesTernaryOperator());
if ((*sit)->getAsCaseNode() == nullptr && asSelection == nullptr && !IsSequence(*sit))
if ((*sit)->getAsCaseNode() == nullptr && (*sit)->getAsSelectionNode() == nullptr &&
!IsSequence(*sit))
out << ";\n";
}
@ -1982,11 +1984,18 @@ void OutputHLSL::writeSelection(TInfoSinkBase &out, TIntermSelection *node)
}
}
bool OutputHLSL::visitTernary(Visit, TIntermTernary *)
{
// Ternary ops should have been already converted to something else in the AST. HLSL ternary
// operator doesn't short-circuit, so it's not the same as the GLSL ternary operator.
UNREACHABLE();
return false;
}
bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node)
{
TInfoSinkBase &out = getInfoSink();
ASSERT(!node->usesTernaryOperator());
ASSERT(mInsideFunction);
// D3D errors when there is a gradient operation in a loop in an unflattened if.

View File

@ -30,11 +30,14 @@ typedef std::map<TString, TIntermSymbol*> ReferencedSymbols;
class OutputHLSL : public TIntermTraverser
{
public:
OutputHLSL(sh::GLenum shaderType, int shaderVersion,
const TExtensionBehavior &extensionBehavior,
const char *sourcePath, ShShaderOutput outputType,
int numRenderTargets, const std::vector<Uniform> &uniforms,
int compileOptions);
OutputHLSL(sh::GLenum shaderType,
int shaderVersion,
const TExtensionBehavior &extensionBehavior,
const char *sourcePath,
ShShaderOutput outputType,
int numRenderTargets,
const std::vector<Uniform> &uniforms,
ShCompileOptions compileOptions);
~OutputHLSL();
@ -58,6 +61,7 @@ class OutputHLSL : public TIntermTraverser
void visitConstantUnion(TIntermConstantUnion*);
bool visitBinary(Visit visit, TIntermBinary*);
bool visitUnary(Visit visit, TIntermUnary*);
bool visitTernary(Visit visit, TIntermTernary *);
bool visitSelection(Visit visit, TIntermSelection*);
bool visitSwitch(Visit visit, TIntermSwitch *);
bool visitCase(Visit visit, TIntermCase *);
@ -117,7 +121,7 @@ class OutputHLSL : public TIntermTraverser
const TExtensionBehavior &mExtensionBehavior;
const char *mSourcePath;
const ShShaderOutput mOutputType;
int mCompileOptions;
ShCompileOptions mCompileOptions;
bool mInsideFunction;

File diff suppressed because it is too large Load Diff

View File

@ -11,6 +11,7 @@
#include "compiler/translator/DirectiveHandler.h"
#include "compiler/translator/Intermediate.h"
#include "compiler/translator/SymbolTable.h"
#include "compiler/translator/QualifierTypes.h"
#include "compiler/preprocessor/Preprocessor.h"
struct TMatrixFields
@ -30,14 +31,13 @@ class TParseContext : angle::NonCopyable
public:
TParseContext(TSymbolTable &symt,
TExtensionBehavior &ext,
TIntermediate &interm,
sh::GLenum type,
ShShaderSpec spec,
int options,
ShCompileOptions options,
bool checksPrecErrors,
TInfoSink &is,
const ShBuiltInResources &resources)
: intermediate(interm),
: intermediate(),
symbolTable(symt),
mDeferredSingleDeclarationErrorCheck(false),
mShaderType(type),
@ -67,7 +67,8 @@ class TParseContext : angle::NonCopyable
mUsesSecondaryOutputs(false),
mMinProgramTexelOffset(resources.MinProgramTexelOffset),
mMaxProgramTexelOffset(resources.MaxProgramTexelOffset),
mComputeShaderLocalSizeDeclared(false)
mComputeShaderLocalSizeDeclared(false),
mDeclaringFunction(false)
{
mComputeShaderLocalSize.fill(-1);
}
@ -119,6 +120,12 @@ class TParseContext : angle::NonCopyable
bool isComputeShaderLocalSizeDeclared() const { return mComputeShaderLocalSizeDeclared; }
sh::WorkGroupSize getComputeShaderLocalSize() const;
void enterFunctionDeclaration() { mDeclaringFunction = true; }
void exitFunctionDeclaration() { mDeclaringFunction = false; }
bool declaringFunction() const { return mDeclaringFunction; }
// This method is guaranteed to succeed, even if no variable with 'name' exists.
const TVariable *getNamedVariable(const TSourceLoc &location, const TString *name, const TSymbol *symbol);
TIntermTyped *parseVariableIdentifier(const TSourceLoc &location,
@ -152,7 +159,9 @@ class TParseContext : angle::NonCopyable
bool checkIsNonVoid(const TSourceLoc &line, const TString &identifier, const TBasicType &type);
void checkIsScalarBool(const TSourceLoc &line, const TIntermTyped *type);
void checkIsScalarBool(const TSourceLoc &line, const TPublicType &pType);
bool checkIsNotSampler(const TSourceLoc &line, const TPublicType &pType, const char *reason);
bool checkIsNotSampler(const TSourceLoc &line,
const TTypeSpecifierNonArray &pType,
const char *reason);
void checkDeclaratorLocationIsNotSpecified(const TSourceLoc &line, const TPublicType &pType);
void checkLocationIsNotSpecified(const TSourceLoc &location,
const TLayoutQualifier &layoutQualifier);
@ -160,8 +169,7 @@ class TParseContext : angle::NonCopyable
TQualifier qualifier,
const TType &type);
void checkIsParameterQualifierValid(const TSourceLoc &line,
TQualifier qualifier,
TQualifier paramQualifier,
const TTypeQualifierBuilder &typeQualifierBuilder,
TType *type);
bool checkCanUseExtension(const TSourceLoc &line, const TString &extension);
void singleDeclarationErrorCheck(const TPublicType &publicType,
@ -173,8 +181,9 @@ class TParseContext : angle::NonCopyable
const TLayoutQualifier &layoutQualifier);
void functionCallLValueErrorCheck(const TFunction *fnCandidate, TIntermAggregate *fnCall);
void checkInvariantIsOutVariableES3(const TQualifier qualifier,
const TSourceLoc &invariantLocation);
void checkInvariantVariableQualifier(bool invariant,
const TQualifier qualifier,
const TSourceLoc &invariantLocation);
void checkInputOutputTypeIsValidES3(const TQualifier qualifier,
const TPublicType &type,
const TSourceLoc &qualifierLocation);
@ -195,9 +204,7 @@ class TParseContext : angle::NonCopyable
TIntermTyped *initializer,
TIntermNode **intermNode);
TPublicType addFullySpecifiedType(TQualifier qualifier,
bool invariant,
TLayoutQualifier layoutQualifier,
TPublicType addFullySpecifiedType(const TTypeQualifierBuilder &typeQualifierBuilder,
const TPublicType &typeSpecifier);
TIntermAggregate *parseSingleDeclaration(TPublicType &publicType,
@ -224,7 +231,7 @@ class TParseContext : angle::NonCopyable
const TSourceLoc &initLocation,
TIntermTyped *initializer);
TIntermAggregate *parseInvariantDeclaration(const TSourceLoc &invariantLoc,
TIntermAggregate *parseInvariantDeclaration(const TTypeQualifierBuilder &typeQualifierBuilder,
const TSourceLoc &identifierLoc,
const TString *identifier,
const TSymbol *symbol);
@ -256,7 +263,7 @@ class TParseContext : angle::NonCopyable
const TSourceLoc &initLocation,
TIntermTyped *initializer);
void parseGlobalLayoutQualifier(const TPublicType &typeQualifier);
void parseGlobalLayoutQualifier(const TTypeQualifierBuilder &typeQualifierBuilder);
TIntermAggregate *addFunctionPrototypeDeclaration(const TFunction &function,
const TSourceLoc &location);
TIntermAggregate *addFunctionDefinition(const TFunction &function,
@ -277,8 +284,6 @@ class TParseContext : angle::NonCopyable
TFunction *fnCall,
const TSourceLoc &line);
TIntermTyped *addConstStruct(
const TString &identifier, TIntermTyped *node, const TSourceLoc& line);
TIntermTyped *addIndexExpression(TIntermTyped *baseExpression,
const TSourceLoc& location,
TIntermTyped *indexExpression);
@ -287,20 +292,24 @@ class TParseContext : angle::NonCopyable
const TString &fieldString,
const TSourceLoc &fieldLocation);
TFieldList *addStructDeclaratorListWithQualifiers(
const TTypeQualifierBuilder &typeQualifierBuilder,
TPublicType *typeSpecifier,
TFieldList *fieldList);
TFieldList *addStructDeclaratorList(const TPublicType &typeSpecifier, TFieldList *fieldList);
TPublicType addStructure(const TSourceLoc &structLine,
const TSourceLoc &nameLine,
const TString *structName,
TFieldList *fieldList);
TTypeSpecifierNonArray addStructure(const TSourceLoc &structLine,
const TSourceLoc &nameLine,
const TString *structName,
TFieldList *fieldList);
TIntermAggregate* addInterfaceBlock(const TPublicType &typeQualifier,
TIntermAggregate *addInterfaceBlock(const TTypeQualifierBuilder &typeQualifierBuilder,
const TSourceLoc &nameLine,
const TString &blockName,
TFieldList *fieldList,
const TString *instanceName,
const TSourceLoc &instanceLine,
TIntermTyped *arrayIndex,
const TSourceLoc& arrayIndexLine);
const TSourceLoc &arrayIndexLine);
void parseLocalSize(const TString &qualifierType,
const TSourceLoc &qualifierTypeLine,
@ -315,11 +324,10 @@ class TParseContext : angle::NonCopyable
const TSourceLoc &qualifierTypeLine,
int intValue,
const TSourceLoc &intValueLine);
TTypeQualifierBuilder *createTypeQualifierBuilder(const TSourceLoc &loc);
TLayoutQualifier joinLayoutQualifiers(TLayoutQualifier leftQualifier,
TLayoutQualifier rightQualifier,
const TSourceLoc &rightQualifierLocation);
TPublicType joinInterpolationQualifiers(const TSourceLoc &interpolationLoc, TQualifier interpolationQualifier,
const TSourceLoc &storageLoc, TQualifier storageQualifier);
// Performs an error check for embedded struct declarations.
void enterStructDeclaration(const TSourceLoc &line, const TString &identifier);
@ -352,11 +360,13 @@ class TParseContext : angle::NonCopyable
const TSourceLoc &loc,
bool *fatalError);
TIntermTyped *addTernarySelection(
TIntermTyped *cond, TIntermTyped *trueBlock, TIntermTyped *falseBlock, const TSourceLoc &line);
TIntermTyped *addTernarySelection(TIntermTyped *cond,
TIntermTyped *trueExpression,
TIntermTyped *falseExpression,
const TSourceLoc &line);
// TODO(jmadill): make these private
TIntermediate &intermediate; // to hold and build a parse tree
TIntermediate intermediate; // to build a parse tree
TSymbolTable &symbolTable; // symbol table that goes with the language currently being parsed
private:
@ -368,18 +378,6 @@ class TParseContext : angle::NonCopyable
const char *reason,
const char *token);
// Constant folding for element access. Note that the returned node does not have the correct
// type - it is expected to be fixed later.
TIntermConstantUnion *foldVectorSwizzle(TVectorFields &fields,
TIntermConstantUnion *baseNode,
const TSourceLoc &location);
TIntermConstantUnion *foldMatrixSubscript(int index,
TIntermConstantUnion *baseNode,
const TSourceLoc &location);
TIntermConstantUnion *foldArraySubscript(int index,
TIntermConstantUnion *baseNode,
const TSourceLoc &location);
bool declareVariable(const TSourceLoc &line, const TString &identifier, const TType &type, TVariable **variable);
void checkCanBeDeclaredWithoutInitializer(const TSourceLoc &line,
@ -409,16 +407,18 @@ class TParseContext : angle::NonCopyable
bool mDeferredSingleDeclarationErrorCheck;
sh::GLenum mShaderType; // vertex or fragment language (future: pack or unpack)
ShShaderSpec mShaderSpec; // The language specification compiler conforms to - GLES2 or WebGL.
int mCompileOptions; // Options passed to TCompiler
ShShaderSpec mShaderSpec; // The language specification compiler conforms to - GLES2 or WebGL.
ShCompileOptions mCompileOptions; // Options passed to TCompiler
int mShaderVersion;
TIntermNode *mTreeRoot; // root of parse tree being created
TIntermNode *mTreeRoot; // root of parse tree being created
int mLoopNestingLevel; // 0 if outside all loops
int mStructNestingLevel; // incremented while parsing a struct declaration
int mStructNestingLevel; // incremented while parsing a struct declaration
int mSwitchNestingLevel; // 0 if outside all switch statements
const TType *mCurrentFunctionType; // the return type of the function that's currently being parsed
const TType
*mCurrentFunctionType; // the return type of the function that's currently being parsed
bool mFunctionReturnsValue; // true if a non-void function has a return
bool mChecksPrecisionErrors; // true if an error will be generated when a variable is declared without precision, explicit or implicit.
bool mChecksPrecisionErrors; // true if an error will be generated when a variable is declared
// without precision, explicit or implicit.
bool mFragmentPrecisionHighOnESSL1; // true if highp precision is supported when compiling
// ESSL1.
TLayoutMatrixPacking mDefaultMatrixPacking;
@ -438,6 +438,8 @@ class TParseContext : angle::NonCopyable
// keep track of local group size declared in layout. It should be declared only once.
bool mComputeShaderLocalSizeDeclared;
sh::WorkGroupSize mComputeShaderLocalSize;
// keeps track whether we are declaring / defining a function
bool mDeclaringFunction;
};
int PaParseStrings(

View File

@ -0,0 +1,636 @@
//
// Copyright (c) 2002-2016 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#include "compiler/translator/QualifierTypes.h"
#include "compiler/translator/Diagnostics.h"
#include <algorithm>
namespace sh
{
TLayoutQualifier JoinLayoutQualifiers(TLayoutQualifier leftQualifier,
TLayoutQualifier rightQualifier,
const TSourceLoc &rightQualifierLocation,
TDiagnostics *diagnostics)
{
TLayoutQualifier joinedQualifier = leftQualifier;
if (rightQualifier.location != -1)
{
joinedQualifier.location = rightQualifier.location;
++joinedQualifier.locationsSpecified;
}
if (rightQualifier.matrixPacking != EmpUnspecified)
{
joinedQualifier.matrixPacking = rightQualifier.matrixPacking;
}
if (rightQualifier.blockStorage != EbsUnspecified)
{
joinedQualifier.blockStorage = rightQualifier.blockStorage;
}
for (size_t i = 0u; i < rightQualifier.localSize.size(); ++i)
{
if (rightQualifier.localSize[i] != -1)
{
if (joinedQualifier.localSize[i] != -1 &&
joinedQualifier.localSize[i] != rightQualifier.localSize[i])
{
diagnostics->error(rightQualifierLocation,
"Cannot have multiple different work group size specifiers",
getWorkGroupSizeString(i), "");
}
joinedQualifier.localSize[i] = rightQualifier.localSize[i];
}
}
return joinedQualifier;
}
} // namespace sh
namespace
{
// GLSL ES 3.10 does not impose a strict order on type qualifiers and allows multiple layout
// declarations.
// GLSL ES 3.10 Revision 4, 4.10 Order of Qualification
bool AreTypeQualifierChecksRelaxed(int shaderVersion)
{
return shaderVersion >= 310;
}
#if defined(ANGLE_ENABLE_ASSERTS)
bool IsScopeQualifier(TQualifier qualifier)
{
return qualifier == EvqGlobal || qualifier == EvqTemporary;
}
bool IsScopeQualifierWrapper(const TQualifierWrapperBase *qualifier)
{
if (qualifier->getType() != QtStorage)
return false;
const TStorageQualifierWrapper *storageQualifier =
static_cast<const TStorageQualifierWrapper *>(qualifier);
TQualifier q = storageQualifier->getQualifier();
return IsScopeQualifier(q);
}
// Returns true if the invariant for the qualifier sequence holds
bool IsInvariantCorrect(const TTypeQualifierBuilder::QualifierSequence &qualifiers)
{
// We should have at least one qualifier.
// The first qualifier always tells the scope.
return qualifiers.size() >= 1 && IsScopeQualifierWrapper(qualifiers[0]);
}
#endif
// Returns true if there are qualifiers which have been specified multiple times
// If areQualifierChecksRelaxed is set to true, then layout qualifier repetition is allowed.
bool HasRepeatingQualifiers(const TTypeQualifierBuilder::QualifierSequence &qualifiers,
bool areQualifierChecksRelaxed,
std::string *errorMessage)
{
bool invariantFound = false;
bool precisionFound = false;
bool layoutFound = false;
bool interpolationFound = false;
unsigned int locationsSpecified = 0;
bool isOut = false;
// The iteration starts from one since the first qualifier only reveals the scope of the
// expression. It is inserted first whenever the sequence gets created.
for (size_t i = 1; i < qualifiers.size(); ++i)
{
switch (qualifiers[i]->getType())
{
case QtInvariant:
{
if (invariantFound)
{
*errorMessage = "The invariant qualifier specified multiple times.";
return true;
}
invariantFound = true;
break;
}
case QtPrecision:
{
if (precisionFound)
{
*errorMessage = "The precision qualifier specified multiple times.";
return true;
}
precisionFound = true;
break;
}
case QtLayout:
{
if (layoutFound && !areQualifierChecksRelaxed)
{
*errorMessage = "The layout qualifier specified multiple times.";
return true;
}
layoutFound = true;
const TLayoutQualifier &currentQualifier =
static_cast<const TLayoutQualifierWrapper *>(qualifiers[i])->getQualifier();
locationsSpecified += currentQualifier.locationsSpecified;
break;
}
case QtInterpolation:
{
// 'centroid' is treated as a storage qualifier
// 'flat centroid' will be squashed to 'flat'
// 'smooth centroid' will be squashed to 'centroid'
if (interpolationFound)
{
*errorMessage = "The interpolation qualifier specified multiple times.";
return true;
}
interpolationFound = true;
break;
}
case QtStorage:
{
// Go over all of the storage qualifiers up until the current one and check for
// repetitions.
TQualifier currentQualifier =
static_cast<const TStorageQualifierWrapper *>(qualifiers[i])->getQualifier();
if (currentQualifier == EvqVertexOut || currentQualifier == EvqFragmentOut)
{
isOut = true;
}
for (size_t j = 1; j < i; ++j)
{
if (qualifiers[j]->getType() == QtStorage)
{
const TStorageQualifierWrapper *previousQualifierWrapper =
static_cast<const TStorageQualifierWrapper *>(qualifiers[j]);
TQualifier previousQualifier = previousQualifierWrapper->getQualifier();
if (currentQualifier == previousQualifier)
{
*errorMessage = previousQualifierWrapper->getQualifierString().c_str();
*errorMessage += " specified multiple times";
return true;
}
}
}
break;
}
default:
UNREACHABLE();
}
}
if (locationsSpecified > 1 && isOut)
{
// GLSL ES 3.00.6 section 4.3.8.2 Output Layout Qualifiers
// GLSL ES 3.10 section 4.4.2 Output Layout Qualifiers
// "The qualifier may appear at most once within a declaration."
*errorMessage = "Output layout location specified multiple times.";
return true;
}
return false;
}
// GLSL ES 3.00_6, 4.7 Order of Qualification
// The correct order of qualifiers is:
// invariant-qualifier interpolation-qualifier storage-qualifier precision-qualifier
// layout-qualifier has to be before storage-qualifier.
bool AreQualifiersInOrder(const TTypeQualifierBuilder::QualifierSequence &qualifiers,
std::string *errorMessage)
{
bool foundInterpolation = false;
bool foundStorage = false;
bool foundPrecision = false;
for (size_t i = 1; i < qualifiers.size(); ++i)
{
switch (qualifiers[i]->getType())
{
case QtInvariant:
if (foundInterpolation || foundStorage || foundPrecision)
{
*errorMessage = "The invariant qualifier has to be first in the expression.";
return false;
}
break;
case QtInterpolation:
if (foundStorage)
{
*errorMessage = "Storage qualifiers have to be after interpolation qualifiers.";
return false;
}
else if (foundPrecision)
{
*errorMessage =
"Precision qualifiers have to be after interpolation qualifiers.";
return false;
}
foundInterpolation = true;
break;
case QtLayout:
if (foundStorage)
{
*errorMessage = "Storage qualifiers have to be after layout qualifiers.";
return false;
}
else if (foundPrecision)
{
*errorMessage = "Precision qualifiers have to be after layout qualifiers.";
return false;
}
break;
case QtStorage:
if (foundPrecision)
{
*errorMessage = "Precision qualifiers have to be after storage qualifiers.";
return false;
}
foundStorage = true;
break;
case QtPrecision:
foundPrecision = true;
break;
default:
UNREACHABLE();
}
}
return true;
}
struct QualifierComparator
{
bool operator()(const TQualifierWrapperBase *q1, const TQualifierWrapperBase *q2)
{
return q1->getRank() < q2->getRank();
}
};
void SortSequence(TTypeQualifierBuilder::QualifierSequence &qualifiers)
{
// We need a stable sorting algorithm since the order of layout-qualifier declarations matter.
// The sorting starts from index 1, instead of 0, since the element at index 0 tells the scope
// and we always want it to be first.
std::stable_sort(qualifiers.begin() + 1, qualifiers.end(), QualifierComparator());
}
// Handles the joining of storage qualifiers for variables.
bool JoinVariableStorageQualifier(TQualifier *joinedQualifier, TQualifier storageQualifier)
{
switch (*joinedQualifier)
{
case EvqGlobal:
*joinedQualifier = storageQualifier;
break;
case EvqTemporary:
{
switch (storageQualifier)
{
case EvqConst:
*joinedQualifier = storageQualifier;
break;
default:
return false;
}
break;
}
case EvqSmooth:
{
switch (storageQualifier)
{
case EvqCentroid:
*joinedQualifier = EvqCentroid;
break;
case EvqVertexOut:
*joinedQualifier = EvqSmoothOut;
break;
case EvqFragmentIn:
*joinedQualifier = EvqSmoothIn;
break;
default:
return false;
}
break;
}
case EvqFlat:
{
switch (storageQualifier)
{
case EvqCentroid:
*joinedQualifier = EvqFlat;
break;
case EvqVertexOut:
*joinedQualifier = EvqFlatOut;
break;
case EvqFragmentIn:
*joinedQualifier = EvqFlatIn;
break;
default:
return false;
}
break;
}
case EvqCentroid:
{
switch (storageQualifier)
{
case EvqVertexOut:
*joinedQualifier = EvqCentroidOut;
break;
case EvqFragmentIn:
*joinedQualifier = EvqCentroidIn;
break;
default:
return false;
}
break;
}
default:
return false;
}
return true;
}
// Handles the joining of storage qualifiers for a parameter in a function.
bool JoinParameterStorageQualifier(TQualifier *joinedQualifier, TQualifier storageQualifier)
{
switch (*joinedQualifier)
{
case EvqTemporary:
*joinedQualifier = storageQualifier;
break;
case EvqConst:
{
switch (storageQualifier)
{
case EvqIn:
*joinedQualifier = EvqConstReadOnly;
break;
default:
return false;
}
break;
}
default:
return false;
}
return true;
}
TTypeQualifier GetVariableTypeQualifierFromSortedSequence(
const TTypeQualifierBuilder::QualifierSequence &sortedSequence,
TDiagnostics *diagnostics)
{
TTypeQualifier typeQualifier(
static_cast<const TStorageQualifierWrapper *>(sortedSequence[0])->getQualifier(),
sortedSequence[0]->getLine());
for (size_t i = 1; i < sortedSequence.size(); ++i)
{
const TQualifierWrapperBase *qualifier = sortedSequence[i];
bool isQualifierValid = false;
switch (qualifier->getType())
{
case QtInvariant:
isQualifierValid = true;
typeQualifier.invariant = true;
break;
case QtInterpolation:
{
switch (typeQualifier.qualifier)
{
case EvqGlobal:
isQualifierValid = true;
typeQualifier.qualifier =
static_cast<const TInterpolationQualifierWrapper *>(qualifier)
->getQualifier();
break;
default:
isQualifierValid = false;
}
break;
}
case QtLayout:
{
const TLayoutQualifierWrapper *layoutQualifierWrapper =
static_cast<const TLayoutQualifierWrapper *>(qualifier);
isQualifierValid = true;
typeQualifier.layoutQualifier = sh::JoinLayoutQualifiers(
typeQualifier.layoutQualifier, layoutQualifierWrapper->getQualifier(),
layoutQualifierWrapper->getLine(), diagnostics);
break;
}
case QtStorage:
isQualifierValid = JoinVariableStorageQualifier(
&typeQualifier.qualifier,
static_cast<const TStorageQualifierWrapper *>(qualifier)->getQualifier());
break;
case QtPrecision:
isQualifierValid = true;
typeQualifier.precision =
static_cast<const TPrecisionQualifierWrapper *>(qualifier)->getQualifier();
ASSERT(typeQualifier.precision != EbpUndefined);
break;
default:
UNREACHABLE();
}
if (!isQualifierValid)
{
const TString &qualifierString = qualifier->getQualifierString();
diagnostics->error(qualifier->getLine(), "invalid qualifier combination",
qualifierString.c_str(), "");
break;
}
}
return typeQualifier;
}
TTypeQualifier GetParameterTypeQualifierFromSortedSequence(
const TTypeQualifierBuilder::QualifierSequence &sortedSequence,
TDiagnostics *diagnostics)
{
TTypeQualifier typeQualifier(EvqTemporary, sortedSequence[0]->getLine());
for (size_t i = 1; i < sortedSequence.size(); ++i)
{
const TQualifierWrapperBase *qualifier = sortedSequence[i];
bool isQualifierValid = false;
switch (qualifier->getType())
{
case QtInvariant:
case QtInterpolation:
case QtLayout:
break;
case QtStorage:
isQualifierValid = JoinParameterStorageQualifier(
&typeQualifier.qualifier,
static_cast<const TStorageQualifierWrapper *>(qualifier)->getQualifier());
break;
case QtPrecision:
isQualifierValid = true;
typeQualifier.precision =
static_cast<const TPrecisionQualifierWrapper *>(qualifier)->getQualifier();
ASSERT(typeQualifier.precision != EbpUndefined);
break;
default:
UNREACHABLE();
}
if (!isQualifierValid)
{
const TString &qualifierString = qualifier->getQualifierString();
diagnostics->error(qualifier->getLine(), "invalid parameter qualifier",
qualifierString.c_str(), "");
break;
}
}
switch (typeQualifier.qualifier)
{
case EvqIn:
case EvqConstReadOnly: // const in
case EvqOut:
case EvqInOut:
break;
case EvqConst:
typeQualifier.qualifier = EvqConstReadOnly;
break;
case EvqTemporary:
// no qualifier has been specified, set it to EvqIn which is the default
typeQualifier.qualifier = EvqIn;
break;
default:
diagnostics->error(sortedSequence[0]->getLine(), "Invalid parameter qualifier ",
getQualifierString(typeQualifier.qualifier), "");
}
return typeQualifier;
}
} // namespace
unsigned int TInvariantQualifierWrapper::getRank() const
{
return 0u;
}
unsigned int TInterpolationQualifierWrapper::getRank() const
{
return 1u;
}
unsigned int TLayoutQualifierWrapper::getRank() const
{
return 2u;
}
unsigned int TStorageQualifierWrapper::getRank() const
{
// Force the 'centroid' auxilary storage qualifier to be always first among all storage
// qualifiers.
if (mStorageQualifier == EvqCentroid)
{
return 3u;
}
else
{
return 4u;
}
}
unsigned int TPrecisionQualifierWrapper::getRank() const
{
return 5u;
}
TTypeQualifier::TTypeQualifier(TQualifier scope, const TSourceLoc &loc)
: layoutQualifier(TLayoutQualifier::create()),
precision(EbpUndefined),
qualifier(scope),
invariant(false),
line(loc)
{
ASSERT(IsScopeQualifier(qualifier));
}
TTypeQualifierBuilder::TTypeQualifierBuilder(const TStorageQualifierWrapper *scope,
int shaderVersion)
: mShaderVersion(shaderVersion)
{
ASSERT(IsScopeQualifier(scope->getQualifier()));
mQualifiers.push_back(scope);
}
void TTypeQualifierBuilder::appendQualifier(const TQualifierWrapperBase *qualifier)
{
mQualifiers.push_back(qualifier);
}
bool TTypeQualifierBuilder::checkSequenceIsValid(TDiagnostics *diagnostics) const
{
bool areQualifierChecksRelaxed = AreTypeQualifierChecksRelaxed(mShaderVersion);
std::string errorMessage;
if (HasRepeatingQualifiers(mQualifiers, areQualifierChecksRelaxed, &errorMessage))
{
diagnostics->error(mQualifiers[0]->getLine(), "qualifier sequence", errorMessage.c_str(),
"");
return false;
}
if (!areQualifierChecksRelaxed && !AreQualifiersInOrder(mQualifiers, &errorMessage))
{
diagnostics->error(mQualifiers[0]->getLine(), "qualifier sequence", errorMessage.c_str(),
"");
return false;
}
return true;
}
TTypeQualifier TTypeQualifierBuilder::getParameterTypeQualifier(TDiagnostics *diagnostics) const
{
ASSERT(IsInvariantCorrect(mQualifiers));
ASSERT(static_cast<const TStorageQualifierWrapper *>(mQualifiers[0])->getQualifier() ==
EvqTemporary);
if (!checkSequenceIsValid(diagnostics))
{
return TTypeQualifier(EvqTemporary, mQualifiers[0]->getLine());
}
// If the qualifier checks are relaxed, then it is easier to sort the qualifiers so
// that the order imposed by the GLSL ES 3.00 spec is kept. Then we can use the same code to
// combine the qualifiers.
if (AreTypeQualifierChecksRelaxed(mShaderVersion))
{
// Copy the qualifier sequence so that we can sort them.
QualifierSequence sortedQualifierSequence = mQualifiers;
SortSequence(sortedQualifierSequence);
return GetParameterTypeQualifierFromSortedSequence(sortedQualifierSequence, diagnostics);
}
return GetParameterTypeQualifierFromSortedSequence(mQualifiers, diagnostics);
}
TTypeQualifier TTypeQualifierBuilder::getVariableTypeQualifier(TDiagnostics *diagnostics) const
{
ASSERT(IsInvariantCorrect(mQualifiers));
if (!checkSequenceIsValid(diagnostics))
{
return TTypeQualifier(
static_cast<const TStorageQualifierWrapper *>(mQualifiers[0])->getQualifier(),
mQualifiers[0]->getLine());
}
// If the qualifier checks are relaxed, then it is easier to sort the qualifiers so
// that the order imposed by the GLSL ES 3.00 spec is kept. Then we can use the same code to
// combine the qualifiers.
if (AreTypeQualifierChecksRelaxed(mShaderVersion))
{
// Copy the qualifier sequence so that we can sort them.
QualifierSequence sortedQualifierSequence = mQualifiers;
SortSequence(sortedQualifierSequence);
return GetVariableTypeQualifierFromSortedSequence(sortedQualifierSequence, diagnostics);
}
return GetVariableTypeQualifierFromSortedSequence(mQualifiers, diagnostics);
}

View File

@ -0,0 +1,170 @@
//
// Copyright (c) 2002-2016 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_QUALIFIER_TYPES_H_
#define COMPILER_TRANSLATOR_QUALIFIER_TYPES_H_
#include "common/angleutils.h"
#include "compiler/translator/BaseTypes.h"
#include "compiler/translator/Types.h"
class TDiagnostics;
namespace sh
{
TLayoutQualifier JoinLayoutQualifiers(TLayoutQualifier leftQualifier,
TLayoutQualifier rightQualifier,
const TSourceLoc &rightQualifierLocation,
TDiagnostics *diagnostics);
} // namespace sh
enum TQualifierType
{
QtInvariant,
QtInterpolation,
QtLayout,
QtStorage,
QtPrecision
};
class TQualifierWrapperBase : angle::NonCopyable
{
public:
POOL_ALLOCATOR_NEW_DELETE();
TQualifierWrapperBase(const TSourceLoc &line) : mLine(line) {}
virtual ~TQualifierWrapperBase(){};
virtual TQualifierType getType() const = 0;
virtual TString getQualifierString() const = 0;
virtual unsigned int getRank() const = 0;
const TSourceLoc &getLine() const { return mLine; }
private:
TSourceLoc mLine;
};
class TInvariantQualifierWrapper final : public TQualifierWrapperBase
{
public:
TInvariantQualifierWrapper(const TSourceLoc &line) : TQualifierWrapperBase(line) {}
~TInvariantQualifierWrapper() {}
TQualifierType getType() const { return QtInvariant; }
TString getQualifierString() const { return "invariant"; }
unsigned int getRank() const;
};
class TInterpolationQualifierWrapper final : public TQualifierWrapperBase
{
public:
TInterpolationQualifierWrapper(TQualifier interpolationQualifier, const TSourceLoc &line)
: TQualifierWrapperBase(line), mInterpolationQualifier(interpolationQualifier)
{
}
~TInterpolationQualifierWrapper() {}
TQualifierType getType() const { return QtInterpolation; }
TString getQualifierString() const { return ::getQualifierString(mInterpolationQualifier); }
TQualifier getQualifier() const { return mInterpolationQualifier; }
unsigned int getRank() const;
private:
TQualifier mInterpolationQualifier;
};
class TLayoutQualifierWrapper final : public TQualifierWrapperBase
{
public:
TLayoutQualifierWrapper(TLayoutQualifier layoutQualifier, const TSourceLoc &line)
: TQualifierWrapperBase(line), mLayoutQualifier(layoutQualifier)
{
}
~TLayoutQualifierWrapper() {}
TQualifierType getType() const { return QtLayout; }
TString getQualifierString() const { return "layout"; }
const TLayoutQualifier &getQualifier() const { return mLayoutQualifier; }
unsigned int getRank() const;
private:
TLayoutQualifier mLayoutQualifier;
};
class TStorageQualifierWrapper final : public TQualifierWrapperBase
{
public:
TStorageQualifierWrapper(TQualifier storageQualifier, const TSourceLoc &line)
: TQualifierWrapperBase(line), mStorageQualifier(storageQualifier)
{
}
~TStorageQualifierWrapper() {}
TQualifierType getType() const { return QtStorage; }
TString getQualifierString() const { return ::getQualifierString(mStorageQualifier); }
TQualifier getQualifier() const { return mStorageQualifier; }
unsigned int getRank() const;
private:
TQualifier mStorageQualifier;
};
class TPrecisionQualifierWrapper final : public TQualifierWrapperBase
{
public:
TPrecisionQualifierWrapper(TPrecision precisionQualifier, const TSourceLoc &line)
: TQualifierWrapperBase(line), mPrecisionQualifier(precisionQualifier)
{
}
~TPrecisionQualifierWrapper() {}
TQualifierType getType() const { return QtPrecision; }
TString getQualifierString() const { return ::getPrecisionString(mPrecisionQualifier); }
TPrecision getQualifier() const { return mPrecisionQualifier; }
unsigned int getRank() const;
private:
TPrecision mPrecisionQualifier;
};
// TTypeQualifier tightly covers type_qualifier from the grammar
struct TTypeQualifier
{
// initializes all of the qualifiers and sets the scope
TTypeQualifier(TQualifier scope, const TSourceLoc &loc);
TLayoutQualifier layoutQualifier;
TPrecision precision;
TQualifier qualifier;
bool invariant;
TSourceLoc line;
};
// TTypeQualifierBuilder contains all of the qualifiers when type_qualifier gets parsed.
// It is to be used to validate the qualifier sequence and build a TTypeQualifier from it.
class TTypeQualifierBuilder : angle::NonCopyable
{
public:
using QualifierSequence = TVector<const TQualifierWrapperBase *>;
public:
POOL_ALLOCATOR_NEW_DELETE();
TTypeQualifierBuilder(const TStorageQualifierWrapper *scope, int shaderVersion);
// Adds the passed qualifier to the end of the sequence.
void appendQualifier(const TQualifierWrapperBase *qualifier);
// Checks for the order of qualification and repeating qualifiers.
bool checkSequenceIsValid(TDiagnostics *diagnostics) const;
// Goes over the qualifier sequence and parses it to form a type qualifier for a function
// parameter.
// The returned object is initialized even if the parsing fails.
TTypeQualifier getParameterTypeQualifier(TDiagnostics *diagnostics) const;
// Goes over the qualifier sequence and parses it to form a type qualifier for a variable.
// The returned object is initialized even if the parsing fails.
TTypeQualifier getVariableTypeQualifier(TDiagnostics *diagnostics) const;
private:
QualifierSequence mQualifiers;
int mShaderVersion;
};
#endif // COMPILER_TRANSLATOR_QUALIFIER_TYPES_H_

View File

@ -92,21 +92,15 @@ TIntermBinary *CreateIndexDirectBaseSymbolNode(const TType &indexedType,
const int index,
TQualifier baseQualifier)
{
TIntermBinary *indexNode = new TIntermBinary(EOpIndexDirect);
indexNode->setType(fieldType);
TIntermSymbol *baseSymbol = CreateBaseSymbol(indexedType, baseQualifier);
indexNode->setLeft(baseSymbol);
indexNode->setRight(CreateIntConstantNode(index));
TIntermBinary *indexNode =
new TIntermBinary(EOpIndexDirect, baseSymbol, TIntermTyped::CreateIndexNode(index));
return indexNode;
}
TIntermBinary *CreateAssignValueSymbolNode(TIntermTyped *targetNode, const TType &assignedValueType)
{
TIntermBinary *assignNode = new TIntermBinary(EOpAssign);
assignNode->setType(assignedValueType);
assignNode->setLeft(targetNode);
assignNode->setRight(CreateValueSymbol(assignedValueType));
return assignNode;
return new TIntermBinary(EOpAssign, targetNode, CreateValueSymbol(assignedValueType));
}
TIntermTyped *EnsureSignedInt(TIntermTyped *node)
@ -256,10 +250,9 @@ TIntermAggregate *GetIndexFunctionDefinition(TType type, bool write)
TIntermAggregate *bodyNode = new TIntermAggregate(EOpSequence);
bodyNode->getSequence()->push_back(switchNode);
TIntermBinary *cond = new TIntermBinary(EOpLessThan);
TIntermBinary *cond =
new TIntermBinary(EOpLessThan, CreateIndexSymbol(), CreateIntConstantNode(0));
cond->setType(TType(EbtBool, EbpUndefined));
cond->setLeft(CreateIndexSymbol());
cond->setRight(CreateIntConstantNode(0));
// Two blocks: one accesses (either reads or writes) the first element and returns,
// the other accesses the last element.

View File

@ -55,19 +55,15 @@ bool RemovePowTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
TIntermTyped *x = node->getSequence()->at(0)->getAsTyped();
TIntermTyped *y = node->getSequence()->at(1)->getAsTyped();
TIntermUnary *log = new TIntermUnary(EOpLog2);
log->setOperand(x);
TIntermUnary *log = new TIntermUnary(EOpLog2, x);
log->setLine(node->getLine());
log->setType(x->getType());
TOperator op = TIntermBinary::GetMulOpBasedOnOperands(y->getType(), log->getType());
TIntermBinary *mul = new TIntermBinary(op, y, log);
mul->setLine(node->getLine());
TIntermUnary *exp = new TIntermUnary(EOpExp2);
exp->setOperand(mul);
TIntermUnary *exp = new TIntermUnary(EOpExp2, mul);
exp->setLine(node->getLine());
exp->setType(node->getType());
queueReplacement(node, exp, OriginalNode::IS_DROPPED);

View File

@ -62,6 +62,13 @@ bool RemoveSwitchFallThrough::visitUnary(Visit, TIntermUnary *node)
return false;
}
bool RemoveSwitchFallThrough::visitTernary(Visit, TIntermTernary *node)
{
mPreviousCase->getSequence()->push_back(node);
mLastStatementWasBreak = false;
return false;
}
bool RemoveSwitchFallThrough::visitSelection(Visit, TIntermSelection *node)
{
mPreviousCase->getSequence()->push_back(node);

View File

@ -23,6 +23,7 @@ class RemoveSwitchFallThrough : public TIntermTraverser
void visitConstantUnion(TIntermConstantUnion *node) override;
bool visitBinary(Visit, TIntermBinary *node) override;
bool visitUnary(Visit, TIntermUnary *node) override;
bool visitTernary(Visit visit, TIntermTernary *node) override;
bool visitSelection(Visit visit, TIntermSelection *node) override;
bool visitSwitch(Visit, TIntermSwitch *node) override;
bool visitCase(Visit, TIntermCase *node) override;

View File

@ -1,36 +0,0 @@
//
// Copyright (c) 2012 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_RENAMEFUNCTION_H_
#define COMPILER_TRANSLATOR_RENAMEFUNCTION_H_
#include "compiler/translator/IntermNode.h"
//
// Renames a function, including its declaration and any calls to it.
//
class RenameFunction : public TIntermTraverser
{
public:
RenameFunction(const TString& oldFunctionName, const TString& newFunctionName)
: TIntermTraverser(true, false, false)
, mOldFunctionName(oldFunctionName)
, mNewFunctionName(newFunctionName) {}
bool visitAggregate(Visit visit, TIntermAggregate *node) override
{
TOperator op = node->getOp();
if ((op == EOpFunction || op == EOpFunctionCall) && node->getName() == mOldFunctionName)
node->setName(mNewFunctionName);
return true;
}
private:
const TString mOldFunctionName;
const TString mNewFunctionName;
};
#endif // COMPILER_TRANSLATOR_RENAMEFUNCTION_H_

View File

@ -102,8 +102,8 @@ class DoWhileRewriter : public TIntermTraverser
TIntermAggregate *breakBlock = new TIntermAggregate(EOpSequence);
breakBlock->getSequence()->push_back(breakStatement);
TIntermUnary *negatedCondition = new TIntermUnary(EOpLogicalNot);
negatedCondition->setOperand(loop->getCondition());
TIntermUnary *negatedCondition =
new TIntermUnary(EOpLogicalNot, loop->getCondition());
TIntermSelection *innerIf =
new TIntermSelection(negatedCondition, breakBlock, nullptr);

View File

@ -31,13 +31,6 @@ class ElseBlockRewriter : public TIntermTraverser
TIntermNode *rewriteSelection(TIntermSelection *selection);
};
TIntermUnary *MakeNewUnary(TOperator op, TIntermTyped *operand)
{
TIntermUnary *unary = new TIntermUnary(op, operand->getType());
unary->setOperand(operand);
return unary;
}
ElseBlockRewriter::ElseBlockRewriter()
: TIntermTraverser(true, false, true),
mFunctionType(NULL)
@ -113,7 +106,7 @@ TIntermNode *ElseBlockRewriter::rewriteSelection(TIntermSelection *selection)
}
TIntermSymbol *conditionSymbolElse = createTempSymbol(boolType);
TIntermUnary *negatedCondition = MakeNewUnary(EOpLogicalNot, conditionSymbolElse);
TIntermUnary *negatedCondition = new TIntermUnary(EOpLogicalNot, conditionSymbolElse);
falseBlock = new TIntermSelection(negatedCondition,
selection->getFalseBlock(), negatedElse);
}

View File

@ -113,16 +113,11 @@ bool Traverser::visitAggregate(Visit visit, TIntermAggregate *node)
// sampler
newsequence.push_back(sequence->at(0));
// Position+offset
TIntermBinary *add = new TIntermBinary(EOpAdd);
add->setType(node->getType());
// Position
TIntermTyped *texCoordNode = sequence->at(1)->getAsTyped();
ASSERT(texCoordNode);
add->setLine(texCoordNode->getLine());
add->setType(texCoordNode->getType());
add->setLeft(texCoordNode);
// offset
TIntermTyped *offsetNode = nullptr;
ASSERT(sequence->at(3)->getAsTyped());
if (is2DArray)
{
@ -143,12 +138,16 @@ bool Traverser::visitAggregate(Visit visit, TIntermAggregate *node)
ivec3Sequence.push_back(zeroNode);
constructIVec3Node->insertChildNodes(0, ivec3Sequence);
add->setRight(constructIVec3Node);
offsetNode = constructIVec3Node;
}
else
{
add->setRight(sequence->at(3)->getAsTyped());
offsetNode = sequence->at(3)->getAsTyped();
}
// Position+offset
TIntermBinary *add = new TIntermBinary(EOpAdd, texCoordNode, offsetNode);
add->setLine(texCoordNode->getLine());
newsequence.push_back(add);
// lod

View File

@ -37,23 +37,9 @@ bool ContainsVectorNode(const TIntermSequence &sequence)
return false;
}
TIntermConstantUnion *ConstructIndexNode(int index)
{
TConstantUnion *u = new TConstantUnion[1];
u[0].setIConst(index);
TType type(EbtInt, EbpUndefined, EvqConst, 1);
TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
return node;
}
TIntermBinary *ConstructVectorIndexBinaryNode(TIntermSymbol *symbolNode, int index)
{
TIntermBinary *binary = new TIntermBinary(EOpIndexDirect);
binary->setLeft(symbolNode);
TIntermConstantUnion *indexNode = ConstructIndexNode(index);
binary->setRight(indexNode);
return binary;
return new TIntermBinary(EOpIndexDirect, symbolNode, TIntermTyped::CreateIndexNode(index));
}
TIntermBinary *ConstructMatrixIndexBinaryNode(
@ -62,11 +48,8 @@ TIntermBinary *ConstructMatrixIndexBinaryNode(
TIntermBinary *colVectorNode =
ConstructVectorIndexBinaryNode(symbolNode, colIndex);
TIntermBinary *binary = new TIntermBinary(EOpIndexDirect);
binary->setLeft(colVectorNode);
TIntermConstantUnion *rowIndexNode = ConstructIndexNode(rowIndex);
binary->setRight(rowIndexNode);
return binary;
return new TIntermBinary(EOpIndexDirect, colVectorNode,
TIntermTyped::CreateIndexNode(rowIndex));
}
} // namespace anonymous
@ -278,11 +261,8 @@ TString ScalarizeVecAndMatConstructorArgs::createTempVariable(TIntermTyped *orig
type.setPrecision(mFragmentPrecisionHigh ? EbpHigh : EbpMedium);
}
TIntermBinary *init = new TIntermBinary(EOpInitialize);
TIntermSymbol *symbolNode = new TIntermSymbol(-1, tempVarName, type);
init->setLeft(symbolNode);
init->setRight(original);
init->setType(type);
TIntermBinary *init = new TIntermBinary(EOpInitialize, symbolNode, original);
TIntermAggregate *decl = new TIntermAggregate(EOpDeclaration);
decl->getSequence()->push_back(init);

View File

@ -69,10 +69,8 @@ bool SeparateArrayInitTraverser::visitAggregate(Visit, TIntermAggregate *node)
replacementDeclaration->setLine(symbol->getLine());
replacements.push_back(replacementDeclaration);
TIntermBinary *replacementAssignment = new TIntermBinary(EOpAssign);
replacementAssignment->setLeft(symbol);
replacementAssignment->setRight(initializer);
replacementAssignment->setType(initializer->getType());
TIntermBinary *replacementAssignment =
new TIntermBinary(EOpAssign, symbol, initializer);
replacementAssignment->setLine(symbol->getLine());
replacements.push_back(replacementAssignment);

View File

@ -49,11 +49,7 @@ SeparateExpressionsTraverser::SeparateExpressionsTraverser()
// and also needs to be replaced in its original location by a different node.
TIntermBinary *CopyAssignmentNode(TIntermBinary *node)
{
TIntermBinary *copyNode = new TIntermBinary(node->getOp());
copyNode->setLeft(node->getLeft());
copyNode->setRight(node->getRight());
copyNode->setType(node->getType());
return copyNode;
return new TIntermBinary(node->getOp(), node->getLeft(), node->getRight());
}
// Performs a shallow copy of a constructor/function call node.

View File

@ -268,11 +268,10 @@ const std::string &ShGetBuiltInResourcesString(const ShHandle handle)
// Return: The return value of ShCompile is really boolean, indicating
// success or failure.
//
bool ShCompile(
const ShHandle handle,
const char *const shaderStrings[],
size_t numStrings,
int compileOptions)
bool ShCompile(const ShHandle handle,
const char *const shaderStrings[],
size_t numStrings,
ShCompileOptions compileOptions)
{
TCompiler *compiler = GetCompilerFromHandle(handle);
ASSERT(compiler);

View File

@ -36,7 +36,7 @@ class SimplifyLoopConditionsTraverser : public TLValueTrackingTraverser
bool visitBinary(Visit visit, TIntermBinary *node) override;
bool visitAggregate(Visit visit, TIntermAggregate *node) override;
bool visitSelection(Visit visit, TIntermSelection *node) override;
bool visitTernary(Visit visit, TIntermTernary *node) override;
void nextIteration();
bool foundLoopToChange() const { return mFoundLoopToChange; }
@ -100,14 +100,14 @@ bool SimplifyLoopConditionsTraverser::visitAggregate(Visit visit, TIntermAggrega
return !mFoundLoopToChange;
}
bool SimplifyLoopConditionsTraverser::visitSelection(Visit visit, TIntermSelection *node)
bool SimplifyLoopConditionsTraverser::visitTernary(Visit visit, TIntermTernary *node)
{
if (mFoundLoopToChange)
return false;
// Don't traverse ternary operators outside loop conditions.
if (!mInsideLoopConditionOrExpression)
return !node->usesTernaryOperator();
return false;
mFoundLoopToChange = mConditionsToSimplify.match(node);
return !mFoundLoopToChange;

View File

@ -26,7 +26,7 @@ class SplitSequenceOperatorTraverser : public TLValueTrackingTraverser
bool visitBinary(Visit visit, TIntermBinary *node) override;
bool visitAggregate(Visit visit, TIntermAggregate *node) override;
bool visitSelection(Visit visit, TIntermSelection *node) override;
bool visitTernary(Visit visit, TIntermTernary *node) override;
void nextIteration();
bool foundExpressionToSplit() const { return mFoundExpressionToSplit; }
@ -123,7 +123,7 @@ bool SplitSequenceOperatorTraverser::visitAggregate(Visit visit, TIntermAggregat
return true;
}
bool SplitSequenceOperatorTraverser::visitSelection(Visit visit, TIntermSelection *node)
bool SplitSequenceOperatorTraverser::visitTernary(Visit visit, TIntermTernary *node)
{
if (mFoundExpressionToSplit)
return false;

View File

@ -471,15 +471,15 @@ class TSymbolTable : angle::NonCopyable
bool setDefaultPrecision(const TPublicType &type, TPrecision prec)
{
if (!SupportsPrecision(type.type))
if (!SupportsPrecision(type.getBasicType()))
return false;
if (type.type == EbtUInt)
if (type.getBasicType() == EbtUInt)
return false; // ESSL 3.00.4 section 4.5.4
if (type.isAggregate())
return false; // Not allowed to set for aggregate types
int indexOfLastElement = static_cast<int>(precisionStack.size()) - 1;
// Uses map operator [], overwrites the current value
(*precisionStack[indexOfLastElement])[type.type] = prec;
(*precisionStack[indexOfLastElement])[type.getBasicType()] = prec;
return true;
}

View File

@ -6,7 +6,6 @@
#include "compiler/translator/TranslatorESSL.h"
#include "compiler/translator/BuiltInFunctionEmulatorGLSL.h"
#include "compiler/translator/EmulatePrecision.h"
#include "compiler/translator/RecordConstantPrecision.h"
#include "compiler/translator/OutputESSL.h"
@ -17,15 +16,7 @@ TranslatorESSL::TranslatorESSL(sh::GLenum type, ShShaderSpec spec)
{
}
void TranslatorESSL::initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, int compileOptions)
{
if (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS)
{
InitBuiltInFunctionEmulatorForGLSLWorkarounds(emu, getShaderType());
}
}
void TranslatorESSL::translate(TIntermNode *root, int compileOptions)
void TranslatorESSL::translate(TIntermNode *root, ShCompileOptions compileOptions)
{
TInfoSinkBase& sink = getInfoSink().obj;

View File

@ -15,9 +15,7 @@ class TranslatorESSL : public TCompiler
TranslatorESSL(sh::GLenum type, ShShaderSpec spec);
protected:
void initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, int compileOptions) override;
void translate(TIntermNode *root, int compileOptions) override;
void translate(TIntermNode *root, ShCompileOptions compileOptions) override;
bool shouldFlattenPragmaStdglInvariantAll() override;
private:

View File

@ -11,6 +11,7 @@
#include "compiler/translator/EmulatePrecision.h"
#include "compiler/translator/ExtensionGLSL.h"
#include "compiler/translator/OutputGLSL.h"
#include "compiler/translator/RewriteTexelFetchOffset.h"
#include "compiler/translator/VersionGLSL.h"
TranslatorGLSL::TranslatorGLSL(sh::GLenum type,
@ -19,18 +20,19 @@ TranslatorGLSL::TranslatorGLSL(sh::GLenum type,
: TCompiler(type, spec, output) {
}
void TranslatorGLSL::initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, int compileOptions)
void TranslatorGLSL::initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu,
ShCompileOptions compileOptions)
{
if (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS)
if (compileOptions & SH_EMULATE_ABS_INT_FUNCTION)
{
InitBuiltInFunctionEmulatorForGLSLWorkarounds(emu, getShaderType());
InitBuiltInAbsFunctionEmulatorForGLSLWorkarounds(emu, getShaderType());
}
int targetGLSLVersion = ShaderOutputTypeToGLSLVersion(getOutputType());
InitBuiltInFunctionEmulatorForGLSLMissingFunctions(emu, getShaderType(), targetGLSLVersion);
}
void TranslatorGLSL::translate(TIntermNode *root, int compileOptions)
void TranslatorGLSL::translate(TIntermNode *root, ShCompileOptions compileOptions)
{
TInfoSinkBase& sink = getInfoSink().obj;
@ -75,6 +77,12 @@ void TranslatorGLSL::translate(TIntermNode *root, int compileOptions)
}
}
if ((compileOptions & SH_REWRITE_TEXELFETCHOFFSET_TO_TEXELFETCH) != 0)
{
sh::RewriteTexelFetchOffset(root, getTemporaryIndex(), getSymbolTable(),
getShaderVersion());
}
bool precisionEmulation = getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision;
if (precisionEmulation)

View File

@ -15,9 +15,10 @@ class TranslatorGLSL : public TCompiler
TranslatorGLSL(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output);
protected:
void initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, int compileOptions) override;
void initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu,
ShCompileOptions compileOptions) override;
void translate(TIntermNode *root, int compileOptions) override;
void translate(TIntermNode *root, ShCompileOptions compileOptions) override;
bool shouldFlattenPragmaStdglInvariantAll() override;
private:

View File

@ -8,6 +8,7 @@
#include "compiler/translator/AddDefaultReturnStatements.h"
#include "compiler/translator/ArrayReturnValueToOutParameter.h"
#include "compiler/translator/BreakVariableAliasingInInnerLoops.h"
#include "compiler/translator/EmulatePrecision.h"
#include "compiler/translator/ExpandIntegerPowExpressions.h"
#include "compiler/translator/IntermNodePatternMatcher.h"
@ -27,7 +28,7 @@ TranslatorHLSL::TranslatorHLSL(sh::GLenum type, ShShaderSpec spec, ShShaderOutpu
{
}
void TranslatorHLSL::translate(TIntermNode *root, int compileOptions)
void TranslatorHLSL::translate(TIntermNode *root, ShCompileOptions compileOptions)
{
const ShBuiltInResources &resources = getResources();
int numRenderTargets = resources.EXT_draw_buffers ? resources.MaxDrawBuffers : 1;
@ -75,6 +76,12 @@ void TranslatorHLSL::translate(TIntermNode *root, int compileOptions)
sh::RewriteElseBlocks(root, getTemporaryIndex());
}
// Work around an HLSL compiler frontend aliasing optimization bug.
// TODO(cwallez) The date is 2016-08-25, Microsoft said the bug would be fixed
// in the next release of d3dcompiler.dll, it would be nice to detect the DLL
// version and only apply the workaround if it is too old.
sh::BreakVariableAliasingInInnerLoops(root);
bool precisionEmulation =
getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision;

View File

@ -21,11 +21,11 @@ class TranslatorHLSL : public TCompiler
const std::map<std::string, unsigned int> *getUniformRegisterMap() const;
protected:
void translate(TIntermNode *root, int compileOptions) override;
void translate(TIntermNode *root, ShCompileOptions compileOptions) override;
bool shouldFlattenPragmaStdglInvariantAll() override;
// collectVariables needs to be run always so registers can be assigned.
bool shouldCollectVariables(int compileOptions) override { return true; }
bool shouldCollectVariables(ShCompileOptions compileOptions) override { return true; }
std::map<std::string, unsigned int> mInterfaceBlockRegisterMap;
std::map<std::string, unsigned int> mUniformRegisterMap;

View File

@ -11,6 +11,7 @@
#include "compiler/translator/Types.h"
#include "compiler/translator/InfoSink.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/SymbolTable.h"
#include <algorithm>
#include <climits>
@ -48,12 +49,20 @@ const char* getBasicString(TBasicType t)
}
TType::TType(const TPublicType &p)
: type(p.type), precision(p.precision), qualifier(p.qualifier), invariant(p.invariant),
layoutQualifier(p.layoutQualifier), primarySize(p.primarySize), secondarySize(p.secondarySize),
array(p.array), arraySize(p.arraySize), interfaceBlock(0), structure(0)
: type(p.getBasicType()),
precision(p.precision),
qualifier(p.qualifier),
invariant(p.invariant),
layoutQualifier(p.layoutQualifier),
primarySize(p.getPrimarySize()),
secondarySize(p.getSecondarySize()),
array(p.array),
arraySize(p.arraySize),
interfaceBlock(0),
structure(0)
{
if (p.userDef)
structure = p.userDef->getStruct();
if (p.getUserDef())
structure = p.getUserDef()->getStruct();
}
bool TStructure::equals(const TStructure &other) const
@ -328,6 +337,14 @@ size_t TType::getObjectSize() const
return totalSize;
}
TStructure::TStructure(const TString *name, TFieldList *fields)
: TFieldListCollection(name, fields),
mDeepestNesting(0),
mUniqueId(TSymbolTable::nextUniqueId()),
mAtGlobalScope(false)
{
}
bool TStructure::containsArrays() const
{
for (size_t i = 0; i < mFields->size(); ++i)

View File

@ -103,13 +103,7 @@ class TStructure : public TFieldListCollection
{
public:
POOL_ALLOCATOR_NEW_DELETE();
TStructure(const TString *name, TFieldList *fields)
: TFieldListCollection(name, fields),
mDeepestNesting(0),
mUniqueId(0),
mAtGlobalScope(false)
{
}
TStructure(const TString *name, TFieldList *fields);
int deepestNesting() const
{
@ -594,6 +588,46 @@ class TType
mutable TString mangled;
};
// TTypeSpecifierNonArray stores all of the necessary fields for type_specifier_nonarray from the
// grammar
struct TTypeSpecifierNonArray
{
TBasicType type;
unsigned char primarySize; // size of vector or cols of matrix
unsigned char secondarySize; // rows of matrix
TType *userDef;
TSourceLoc line;
// true if the type was defined by a struct specifier rather than a reference to a type name.
bool isStructSpecifier;
void initialize(TBasicType bt, const TSourceLoc &ln)
{
type = bt;
primarySize = 1;
secondarySize = 1;
userDef = nullptr;
line = ln;
isStructSpecifier = false;
}
void setAggregate(unsigned char size)
{
primarySize = size;
}
void setMatrix(unsigned char columns, unsigned char rows)
{
ASSERT(columns > 1 && rows > 1 && columns <= 4 && rows <= 4);
primarySize = columns;
secondarySize = rows;
}
bool isMatrix() const { return primarySize > 1 && secondarySize > 1; }
bool isVector() const { return primarySize > 1 && secondarySize == 1; }
};
//
// This is a workaround for a problem with the yacc stack, It can't have
// types that it thinks have non-trivial constructors. It should
@ -605,114 +639,76 @@ class TType
//
struct TPublicType
{
TBasicType type;
TTypeSpecifierNonArray typeSpecifierNonArray;
TLayoutQualifier layoutQualifier;
TQualifier qualifier;
bool invariant;
TPrecision precision;
unsigned char primarySize; // size of vector or cols of matrix
unsigned char secondarySize; // rows of matrix
bool array;
int arraySize;
TType *userDef;
TSourceLoc line;
// true if the type was defined by a struct specifier rather than a reference to a type name.
bool isStructSpecifier;
void setBasic(TBasicType bt, TQualifier q, const TSourceLoc &ln)
void initialize(const TTypeSpecifierNonArray &typeSpecifier, TQualifier q)
{
type = bt;
layoutQualifier = TLayoutQualifier::create();
qualifier = q;
invariant = false;
precision = EbpUndefined;
primarySize = 1;
secondarySize = 1;
array = false;
arraySize = 0;
userDef = 0;
line = ln;
isStructSpecifier = false;
typeSpecifierNonArray = typeSpecifier;
layoutQualifier = TLayoutQualifier::create();
qualifier = q;
invariant = false;
precision = EbpUndefined;
array = false;
arraySize = 0;
}
void setAggregate(unsigned char size)
TBasicType getBasicType() const { return typeSpecifierNonArray.type; }
void setBasicType(TBasicType basicType) { typeSpecifierNonArray.type = basicType; }
unsigned char getPrimarySize() const { return typeSpecifierNonArray.primarySize; }
unsigned char getSecondarySize() const { return typeSpecifierNonArray.secondarySize; }
void initializeSizeForScalarTypes()
{
primarySize = size;
typeSpecifierNonArray.primarySize = 1;
typeSpecifierNonArray.secondarySize = 1;
}
void setMatrix(unsigned char c, unsigned char r)
{
ASSERT(c > 1 && r > 1 && c <= 4 && r <= 4);
primarySize = c;
secondarySize = r;
}
const TType *getUserDef() const { return typeSpecifierNonArray.userDef; }
const TSourceLoc &getLine() const { return typeSpecifierNonArray.line; }
bool isUnsizedArray() const
{
return array && arraySize == 0;
}
void setArraySize(int s)
{
array = true;
arraySize = s;
}
void clearArrayness()
{
array = false;
arraySize = 0;
}
bool isStructSpecifier() const { return typeSpecifierNonArray.isStructSpecifier; }
bool isStructureContainingArrays() const
{
if (!userDef)
if (!typeSpecifierNonArray.userDef)
{
return false;
}
return userDef->isStructureContainingArrays();
return typeSpecifierNonArray.userDef->isStructureContainingArrays();
}
bool isStructureContainingType(TBasicType t) const
{
if (!userDef)
if (!typeSpecifierNonArray.userDef)
{
return false;
}
return userDef->isStructureContainingType(t);
return typeSpecifierNonArray.userDef->isStructureContainingType(t);
}
bool isMatrix() const
bool isUnsizedArray() const { return array && arraySize == 0; }
void setArraySize(int s)
{
return primarySize > 1 && secondarySize > 1;
array = true;
arraySize = s;
}
bool isVector() const
void clearArrayness()
{
return primarySize > 1 && secondarySize == 1;
}
int getCols() const
{
ASSERT(isMatrix());
return primarySize;
}
int getRows() const
{
ASSERT(isMatrix());
return secondarySize;
}
int getNominalSize() const
{
return primarySize;
array = false;
arraySize = 0;
}
bool isAggregate() const
{
return array || isMatrix() || isVector();
return array || typeSpecifierNonArray.isMatrix() || typeSpecifierNonArray.isVector();
}
};

View File

@ -10,32 +10,30 @@ namespace
{
// "x || y" is equivalent to "x ? true : y".
TIntermSelection *UnfoldOR(TIntermTyped *x, TIntermTyped *y)
TIntermTernary *UnfoldOR(TIntermTyped *x, TIntermTyped *y)
{
const TType boolType(EbtBool, EbpUndefined);
TConstantUnion *u = new TConstantUnion;
u->setBConst(true);
TIntermConstantUnion *trueNode = new TIntermConstantUnion(
u, TType(EbtBool, EbpUndefined, EvqConst, 1));
return new TIntermSelection(x, trueNode, y, boolType);
return new TIntermTernary(x, trueNode, y);
}
// "x && y" is equivalent to "x ? y : false".
TIntermSelection *UnfoldAND(TIntermTyped *x, TIntermTyped *y)
TIntermTernary *UnfoldAND(TIntermTyped *x, TIntermTyped *y)
{
const TType boolType(EbtBool, EbpUndefined);
TConstantUnion *u = new TConstantUnion;
u->setBConst(false);
TIntermConstantUnion *falseNode = new TIntermConstantUnion(
u, TType(EbtBool, EbpUndefined, EvqConst, 1));
return new TIntermSelection(x, y, falseNode, boolType);
return new TIntermTernary(x, y, falseNode);
}
} // namespace anonymous
bool UnfoldShortCircuitAST::visitBinary(Visit visit, TIntermBinary *node)
{
TIntermSelection *replacement = NULL;
TIntermTernary *replacement = nullptr;
switch (node->getOp())
{

View File

@ -23,7 +23,7 @@ class UnfoldShortCircuitTraverser : public TIntermTraverser
UnfoldShortCircuitTraverser();
bool visitBinary(Visit visit, TIntermBinary *node) override;
bool visitSelection(Visit visit, TIntermSelection *node) override;
bool visitTernary(Visit visit, TIntermTernary *node) override;
void nextIteration();
bool foundShortCircuit() const { return mFoundShortCircuit; }
@ -79,8 +79,7 @@ bool UnfoldShortCircuitTraverser::visitBinary(Visit visit, TIntermBinary *node)
ASSERT(node->getRight()->getType() == boolType);
assignRightBlock->getSequence()->push_back(createTempAssignment(node->getRight()));
TIntermUnary *notTempSymbol = new TIntermUnary(EOpLogicalNot, boolType);
notTempSymbol->setOperand(createTempSymbol(boolType));
TIntermUnary *notTempSymbol = new TIntermUnary(EOpLogicalNot, createTempSymbol(boolType));
TIntermSelection *ifNode = new TIntermSelection(notTempSymbol, assignRightBlock, nullptr);
insertions.push_back(ifNode);
@ -119,7 +118,7 @@ bool UnfoldShortCircuitTraverser::visitBinary(Visit visit, TIntermBinary *node)
}
}
bool UnfoldShortCircuitTraverser::visitSelection(Visit visit, TIntermSelection *node)
bool UnfoldShortCircuitTraverser::visitTernary(Visit visit, TIntermTernary *node)
{
if (mFoundShortCircuit)
return false;
@ -132,8 +131,6 @@ bool UnfoldShortCircuitTraverser::visitSelection(Visit visit, TIntermSelection *
mFoundShortCircuit = true;
ASSERT(node->usesTernaryOperator());
// Unfold "b ? x : y" into "type s; if(b) s = x; else s = y;"
TIntermSequence insertions;
@ -143,11 +140,11 @@ bool UnfoldShortCircuitTraverser::visitSelection(Visit visit, TIntermSelection *
insertions.push_back(tempDeclaration);
TIntermAggregate *trueBlock = new TIntermAggregate(EOpSequence);
TIntermBinary *trueAssignment = createTempAssignment(node->getTrueBlock()->getAsTyped());
TIntermBinary *trueAssignment = createTempAssignment(node->getTrueExpression());
trueBlock->getSequence()->push_back(trueAssignment);
TIntermAggregate *falseBlock = new TIntermAggregate(EOpSequence);
TIntermBinary *falseAssignment = createTempAssignment(node->getFalseBlock()->getAsTyped());
TIntermBinary *falseAssignment = createTempAssignment(node->getFalseExpression());
falseBlock->getSequence()->push_back(falseAssignment);
TIntermSelection *ifNode =

View File

@ -56,6 +56,14 @@ bool ValidateSwitch::visitBinary(Visit, TIntermBinary *)
}
bool ValidateSwitch::visitUnary(Visit, TIntermUnary *)
{
if (!mFirstCaseFound)
mStatementBeforeCase = true;
mLastStatementWasCase = false;
return true;
}
bool ValidateSwitch::visitTernary(Visit, TIntermTernary *)
{
if (!mFirstCaseFound)
mStatementBeforeCase = true;

View File

@ -23,6 +23,7 @@ class ValidateSwitch : public TIntermTraverser
void visitConstantUnion(TIntermConstantUnion *) override;
bool visitBinary(Visit, TIntermBinary *) override;
bool visitUnary(Visit, TIntermUnary *) override;
bool visitTernary(Visit, TIntermTernary *) override;
bool visitSelection(Visit visit, TIntermSelection *) override;
bool visitSwitch(Visit, TIntermSwitch *) override;
bool visitCase(Visit, TIntermCase *node) override;

View File

@ -1,95 +0,0 @@
//
// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#include "compiler/translator/depgraph/DependencyGraph.h"
#include "compiler/translator/depgraph/DependencyGraphBuilder.h"
TDependencyGraph::TDependencyGraph(TIntermNode* intermNode)
{
TDependencyGraphBuilder::build(intermNode, this);
}
TDependencyGraph::~TDependencyGraph()
{
for (TGraphNodeVector::const_iterator iter = mAllNodes.begin(); iter != mAllNodes.end(); ++iter)
{
TGraphNode* node = *iter;
delete node;
}
}
TGraphArgument* TDependencyGraph::createArgument(TIntermAggregate* intermFunctionCall,
int argumentNumber)
{
TGraphArgument* argument = new TGraphArgument(intermFunctionCall, argumentNumber);
mAllNodes.push_back(argument);
return argument;
}
TGraphFunctionCall* TDependencyGraph::createFunctionCall(TIntermAggregate* intermFunctionCall)
{
TGraphFunctionCall* functionCall = new TGraphFunctionCall(intermFunctionCall);
mAllNodes.push_back(functionCall);
if (functionCall->getIntermFunctionCall()->isUserDefined())
mUserDefinedFunctionCalls.push_back(functionCall);
return functionCall;
}
TGraphSymbol* TDependencyGraph::getOrCreateSymbol(TIntermSymbol* intermSymbol)
{
TSymbolIdMap::const_iterator iter = mSymbolIdMap.find(intermSymbol->getId());
TGraphSymbol* symbol = NULL;
if (iter != mSymbolIdMap.end()) {
TSymbolIdPair pair = *iter;
symbol = pair.second;
} else {
symbol = new TGraphSymbol(intermSymbol);
mAllNodes.push_back(symbol);
TSymbolIdPair pair(intermSymbol->getId(), symbol);
mSymbolIdMap.insert(pair);
// We save all sampler symbols in a collection, so we can start graph traversals from them quickly.
if (IsSampler(intermSymbol->getBasicType()))
mSamplerSymbols.push_back(symbol);
}
return symbol;
}
TGraphSelection* TDependencyGraph::createSelection(TIntermSelection* intermSelection)
{
TGraphSelection* selection = new TGraphSelection(intermSelection);
mAllNodes.push_back(selection);
return selection;
}
TGraphLoop* TDependencyGraph::createLoop(TIntermLoop* intermLoop)
{
TGraphLoop* loop = new TGraphLoop(intermLoop);
mAllNodes.push_back(loop);
return loop;
}
TGraphLogicalOp* TDependencyGraph::createLogicalOp(TIntermBinary* intermLogicalOp)
{
TGraphLogicalOp* logicalOp = new TGraphLogicalOp(intermLogicalOp);
mAllNodes.push_back(logicalOp);
return logicalOp;
}
const char* TGraphLogicalOp::getOpString() const
{
const char* opString = NULL;
switch (getIntermLogicalOp()->getOp()) {
case EOpLogicalAnd: opString = "and"; break;
case EOpLogicalOr: opString = "or"; break;
default: opString = "unknown"; break;
}
return opString;
}

View File

@ -1,199 +0,0 @@
//
// Copyright (c) 2012 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_DEPGRAPH_DEPENDENCYGRAPH_H_
#define COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPH_H_
#include "compiler/translator/IntermNode.h"
#include <set>
#include <stack>
class TGraphNode;
class TGraphParentNode;
class TGraphArgument;
class TGraphFunctionCall;
class TGraphSymbol;
class TGraphSelection;
class TGraphLoop;
class TGraphLogicalOp;
class TDependencyGraphTraverser;
class TDependencyGraphOutput;
typedef std::set<TGraphNode*> TGraphNodeSet;
typedef std::vector<TGraphNode*> TGraphNodeVector;
typedef std::vector<TGraphSymbol*> TGraphSymbolVector;
typedef std::vector<TGraphFunctionCall*> TFunctionCallVector;
//
// Base class for all dependency graph nodes.
//
class TGraphNode {
public:
TGraphNode(TIntermNode* node) : intermNode(node) {}
virtual ~TGraphNode() {}
virtual void traverse(TDependencyGraphTraverser* graphTraverser);
protected:
TIntermNode* intermNode;
};
//
// Base class for dependency graph nodes that may have children.
//
class TGraphParentNode : public TGraphNode {
public:
TGraphParentNode(TIntermNode* node) : TGraphNode(node) {}
~TGraphParentNode() override {}
void addDependentNode(TGraphNode* node) { if (node != this) mDependentNodes.insert(node); }
void traverse(TDependencyGraphTraverser *graphTraverser) override;
private:
TGraphNodeSet mDependentNodes;
};
//
// Handle function call arguments.
//
class TGraphArgument : public TGraphParentNode {
public:
TGraphArgument(TIntermAggregate* intermFunctionCall, int argumentNumber)
: TGraphParentNode(intermFunctionCall)
, mArgumentNumber(argumentNumber) {}
~TGraphArgument() override {}
const TIntermAggregate* getIntermFunctionCall() const { return intermNode->getAsAggregate(); }
int getArgumentNumber() const { return mArgumentNumber; }
void traverse(TDependencyGraphTraverser *graphTraverser) override;
private:
int mArgumentNumber;
};
//
// Handle function calls.
//
class TGraphFunctionCall : public TGraphParentNode {
public:
TGraphFunctionCall(TIntermAggregate* intermFunctionCall)
: TGraphParentNode(intermFunctionCall) {}
~TGraphFunctionCall() override {}
const TIntermAggregate* getIntermFunctionCall() const { return intermNode->getAsAggregate(); }
void traverse(TDependencyGraphTraverser *graphTraverser) override;
};
//
// Handle symbols.
//
class TGraphSymbol : public TGraphParentNode {
public:
TGraphSymbol(TIntermSymbol* intermSymbol) : TGraphParentNode(intermSymbol) {}
~TGraphSymbol() override {}
const TIntermSymbol* getIntermSymbol() const { return intermNode->getAsSymbolNode(); }
void traverse(TDependencyGraphTraverser *graphTraverser) override;
};
//
// Handle if statements and ternary operators.
//
class TGraphSelection : public TGraphNode {
public:
TGraphSelection(TIntermSelection* intermSelection) : TGraphNode(intermSelection) {}
~TGraphSelection() override {}
const TIntermSelection* getIntermSelection() const { return intermNode->getAsSelectionNode(); }
void traverse(TDependencyGraphTraverser *graphTraverser) override;
};
//
// Handle for, do-while, and while loops.
//
class TGraphLoop : public TGraphNode {
public:
TGraphLoop(TIntermLoop* intermLoop) : TGraphNode(intermLoop) {}
~TGraphLoop() override {}
const TIntermLoop* getIntermLoop() const { return intermNode->getAsLoopNode(); }
void traverse(TDependencyGraphTraverser *graphTraverser) override;
};
//
// Handle logical and, or.
//
class TGraphLogicalOp : public TGraphNode {
public:
TGraphLogicalOp(TIntermBinary* intermLogicalOp) : TGraphNode(intermLogicalOp) {}
~TGraphLogicalOp() override {}
const TIntermBinary* getIntermLogicalOp() const { return intermNode->getAsBinaryNode(); }
const char* getOpString() const;
void traverse(TDependencyGraphTraverser *graphTraverser) override;
};
//
// A dependency graph of symbols, function calls, conditions etc.
//
// This class provides an interface to the entry points of the dependency graph.
//
// Dependency graph nodes should be created by using one of the provided "create..." methods.
// This class (and nobody else) manages the memory of the created nodes.
// Nodes may not be removed after being added, so all created nodes will exist while the
// TDependencyGraph instance exists.
//
class TDependencyGraph {
public:
TDependencyGraph(TIntermNode* intermNode);
~TDependencyGraph();
const TGraphNodeVector &allNodes() const { return mAllNodes; }
const TGraphSymbolVector &samplerSymbols() const { return mSamplerSymbols; }
const TFunctionCallVector &userDefinedFunctionCalls() const
{
return mUserDefinedFunctionCalls;
}
TGraphArgument* createArgument(TIntermAggregate* intermFunctionCall, int argumentNumber);
TGraphFunctionCall* createFunctionCall(TIntermAggregate* intermFunctionCall);
TGraphSymbol* getOrCreateSymbol(TIntermSymbol* intermSymbol);
TGraphSelection* createSelection(TIntermSelection* intermSelection);
TGraphLoop* createLoop(TIntermLoop* intermLoop);
TGraphLogicalOp* createLogicalOp(TIntermBinary* intermLogicalOp);
private:
typedef TMap<int, TGraphSymbol*> TSymbolIdMap;
typedef std::pair<int, TGraphSymbol*> TSymbolIdPair;
TGraphNodeVector mAllNodes;
TGraphSymbolVector mSamplerSymbols;
TFunctionCallVector mUserDefinedFunctionCalls;
TSymbolIdMap mSymbolIdMap;
};
//
// For traversing the dependency graph. Users should derive from this,
// put their traversal specific data in it, and then pass it to a
// traverse method.
//
// When using this, just fill in the methods for nodes you want visited.
//
class TDependencyGraphTraverser : angle::NonCopyable {
public:
TDependencyGraphTraverser() : mDepth(0) {}
virtual ~TDependencyGraphTraverser() {}
virtual void visitSymbol(TGraphSymbol* symbol) {};
virtual void visitArgument(TGraphArgument* selection) {};
virtual void visitFunctionCall(TGraphFunctionCall* functionCall) {};
virtual void visitSelection(TGraphSelection* selection) {};
virtual void visitLoop(TGraphLoop* loop) {};
virtual void visitLogicalOp(TGraphLogicalOp* logicalOp) {};
int getDepth() const { return mDepth; }
void incrementDepth() { ++mDepth; }
void decrementDepth() { --mDepth; }
void clearVisited() { mVisited.clear(); }
void markVisited(TGraphNode* node) { mVisited.insert(node); }
bool isVisited(TGraphNode* node) const { return mVisited.find(node) != mVisited.end(); }
private:
int mDepth;
TGraphNodeSet mVisited;
};
#endif // COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPH_H_

View File

@ -1,255 +0,0 @@
//
// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#include "compiler/translator/depgraph/DependencyGraphBuilder.h"
void TDependencyGraphBuilder::build(TIntermNode *node, TDependencyGraph *graph)
{
TDependencyGraphBuilder builder(graph);
builder.build(node);
}
bool TDependencyGraphBuilder::visitAggregate(
Visit visit, TIntermAggregate *intermAggregate)
{
switch (intermAggregate->getOp())
{
case EOpFunction:
visitFunctionDefinition(intermAggregate);
break;
case EOpFunctionCall:
visitFunctionCall(intermAggregate);
break;
default:
visitAggregateChildren(intermAggregate);
break;
}
return false;
}
void TDependencyGraphBuilder::visitFunctionDefinition(
TIntermAggregate *intermAggregate)
{
// Currently, we do not support user defined functions.
if (intermAggregate->getName() != "main(")
return;
visitAggregateChildren(intermAggregate);
}
// Takes an expression like "f(x)" and creates a dependency graph like
// "x -> argument 0 -> function call".
void TDependencyGraphBuilder::visitFunctionCall(
TIntermAggregate *intermFunctionCall)
{
TGraphFunctionCall *functionCall =
mGraph->createFunctionCall(intermFunctionCall);
// Run through the function call arguments.
int argumentNumber = 0;
TIntermSequence *intermArguments = intermFunctionCall->getSequence();
for (TIntermSequence::const_iterator iter = intermArguments->begin();
iter != intermArguments->end();
++iter, ++argumentNumber)
{
TNodeSetMaintainer nodeSetMaintainer(this);
TIntermNode *intermArgument = *iter;
intermArgument->traverse(this);
if (TParentNodeSet *argumentNodes = mNodeSets.getTopSet())
{
TGraphArgument *argument = mGraph->createArgument(
intermFunctionCall, argumentNumber);
connectMultipleNodesToSingleNode(argumentNodes, argument);
argument->addDependentNode(functionCall);
}
}
// Push the leftmost symbol of this function call into the current set of
// dependent symbols to represent the result of this function call.
// Thus, an expression like "y = f(x)" will yield a dependency graph like
// "x -> argument 0 -> function call -> y".
// This line essentially passes the function call node back up to an earlier
// visitAssignment call, which will create the connection "function call -> y".
mNodeSets.insertIntoTopSet(functionCall);
}
void TDependencyGraphBuilder::visitAggregateChildren(
TIntermAggregate *intermAggregate)
{
TIntermSequence *sequence = intermAggregate->getSequence();
for (TIntermSequence::const_iterator iter = sequence->begin();
iter != sequence->end(); ++iter)
{
TIntermNode *intermChild = *iter;
intermChild->traverse(this);
}
}
void TDependencyGraphBuilder::visitSymbol(TIntermSymbol *intermSymbol)
{
// Push this symbol into the set of dependent symbols for the current
// assignment or condition that we are traversing.
TGraphSymbol *symbol = mGraph->getOrCreateSymbol(intermSymbol);
mNodeSets.insertIntoTopSet(symbol);
// If this symbol is the current leftmost symbol under an assignment, replace
// the previous leftmost symbol with this symbol.
if (!mLeftmostSymbols.empty() && mLeftmostSymbols.top() != &mRightSubtree)
{
mLeftmostSymbols.pop();
mLeftmostSymbols.push(symbol);
}
}
bool TDependencyGraphBuilder::visitBinary(Visit visit, TIntermBinary *intermBinary)
{
TOperator op = intermBinary->getOp();
if (op == EOpInitialize || intermBinary->isAssignment())
visitAssignment(intermBinary);
else if (op == EOpLogicalAnd || op == EOpLogicalOr)
visitLogicalOp(intermBinary);
else
visitBinaryChildren(intermBinary);
return false;
}
void TDependencyGraphBuilder::visitAssignment(TIntermBinary *intermAssignment)
{
TIntermTyped *intermLeft = intermAssignment->getLeft();
if (!intermLeft)
return;
TGraphSymbol *leftmostSymbol = NULL;
{
TNodeSetMaintainer nodeSetMaintainer(this);
{
TLeftmostSymbolMaintainer leftmostSymbolMaintainer(this, mLeftSubtree);
intermLeft->traverse(this);
leftmostSymbol = mLeftmostSymbols.top();
// After traversing the left subtree of this assignment, we should
// have found a real leftmost symbol, and the leftmost symbol should
// not be a placeholder.
ASSERT(leftmostSymbol != &mLeftSubtree);
ASSERT(leftmostSymbol != &mRightSubtree);
}
if (TIntermTyped *intermRight = intermAssignment->getRight())
{
TLeftmostSymbolMaintainer leftmostSymbolMaintainer(this, mRightSubtree);
intermRight->traverse(this);
}
if (TParentNodeSet *assignmentNodes = mNodeSets.getTopSet())
connectMultipleNodesToSingleNode(assignmentNodes, leftmostSymbol);
}
// Push the leftmost symbol of this assignment into the current set of dependent
// symbols to represent the result of this assignment.
// An expression like "a = (b = c)" will yield a dependency graph like
// "c -> b -> a".
// This line essentially passes the leftmost symbol of the nested assignment
// ("b" in this example) back up to the earlier visitAssignment call for the
// outer assignment, which will create the connection "b -> a".
mNodeSets.insertIntoTopSet(leftmostSymbol);
}
void TDependencyGraphBuilder::visitLogicalOp(TIntermBinary *intermLogicalOp)
{
if (TIntermTyped *intermLeft = intermLogicalOp->getLeft())
{
TNodeSetPropagatingMaintainer nodeSetMaintainer(this);
intermLeft->traverse(this);
if (TParentNodeSet *leftNodes = mNodeSets.getTopSet())
{
TGraphLogicalOp *logicalOp = mGraph->createLogicalOp(intermLogicalOp);
connectMultipleNodesToSingleNode(leftNodes, logicalOp);
}
}
if (TIntermTyped *intermRight = intermLogicalOp->getRight())
{
TLeftmostSymbolMaintainer leftmostSymbolMaintainer(this, mRightSubtree);
intermRight->traverse(this);
}
}
void TDependencyGraphBuilder::visitBinaryChildren(TIntermBinary *intermBinary)
{
if (TIntermTyped *intermLeft = intermBinary->getLeft())
intermLeft->traverse(this);
if (TIntermTyped *intermRight = intermBinary->getRight())
{
TLeftmostSymbolMaintainer leftmostSymbolMaintainer(this, mRightSubtree);
intermRight->traverse(this);
}
}
bool TDependencyGraphBuilder::visitSelection(
Visit visit, TIntermSelection *intermSelection)
{
if (TIntermNode *intermCondition = intermSelection->getCondition())
{
TNodeSetMaintainer nodeSetMaintainer(this);
intermCondition->traverse(this);
if (TParentNodeSet *conditionNodes = mNodeSets.getTopSet())
{
TGraphSelection *selection = mGraph->createSelection(intermSelection);
connectMultipleNodesToSingleNode(conditionNodes, selection);
}
}
if (TIntermNode *intermTrueBlock = intermSelection->getTrueBlock())
intermTrueBlock->traverse(this);
if (TIntermNode *intermFalseBlock = intermSelection->getFalseBlock())
intermFalseBlock->traverse(this);
return false;
}
bool TDependencyGraphBuilder::visitLoop(Visit visit, TIntermLoop *intermLoop)
{
if (TIntermTyped *intermCondition = intermLoop->getCondition())
{
TNodeSetMaintainer nodeSetMaintainer(this);
intermCondition->traverse(this);
if (TParentNodeSet *conditionNodes = mNodeSets.getTopSet())
{
TGraphLoop *loop = mGraph->createLoop(intermLoop);
connectMultipleNodesToSingleNode(conditionNodes, loop);
}
}
if (TIntermNode* intermBody = intermLoop->getBody())
intermBody->traverse(this);
if (TIntermTyped *intermExpression = intermLoop->getExpression())
intermExpression->traverse(this);
return false;
}
void TDependencyGraphBuilder::connectMultipleNodesToSingleNode(
TParentNodeSet *nodes, TGraphNode *node) const
{
for (TParentNodeSet::const_iterator iter = nodes->begin();
iter != nodes->end(); ++iter)
{
TGraphParentNode *currentNode = *iter;
currentNode->addDependentNode(node);
}
}

View File

@ -1,199 +0,0 @@
//
// Copyright (c) 2012 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_DEPGRAPH_DEPENDENCYGRAPHBUILDER_H_
#define COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPHBUILDER_H_
#include "compiler/translator/depgraph/DependencyGraph.h"
//
// Creates a dependency graph of symbols, function calls, conditions etc. by
// traversing a intermediate tree.
//
class TDependencyGraphBuilder : public TIntermTraverser
{
public:
static void build(TIntermNode *node, TDependencyGraph *graph);
void visitSymbol(TIntermSymbol *) override;
bool visitBinary(Visit visit, TIntermBinary *) override;
bool visitSelection(Visit visit, TIntermSelection *) override;
bool visitAggregate(Visit visit, TIntermAggregate *) override;
bool visitLoop(Visit visit, TIntermLoop *) override;
private:
typedef std::stack<TGraphSymbol *> TSymbolStack;
typedef std::set<TGraphParentNode *> TParentNodeSet;
//
// For collecting the dependent nodes of assignments, conditions, etc.
// while traversing the intermediate tree.
//
// This data structure is stack of sets. Each set contains dependency graph
// parent nodes.
//
class TNodeSetStack
{
public:
TNodeSetStack() {};
~TNodeSetStack() { clear(); }
// This should only be called after a pushSet.
// Returns NULL if the top set is empty.
TParentNodeSet *getTopSet() const
{
ASSERT(!mNodeSets.empty());
TParentNodeSet *topSet = mNodeSets.top();
return !topSet->empty() ? topSet : NULL;
}
void pushSet() { mNodeSets.push(new TParentNodeSet()); }
void popSet()
{
ASSERT(!mNodeSets.empty());
delete mNodeSets.top();
mNodeSets.pop();
}
// Pops the top set and adds its contents to the new top set.
// This should only be called after a pushSet.
// If there is no set below the top set, the top set is just deleted.
void popSetIntoNext()
{
ASSERT(!mNodeSets.empty());
TParentNodeSet *oldTopSet = mNodeSets.top();
mNodeSets.pop();
if (!mNodeSets.empty())
{
TParentNodeSet *newTopSet = mNodeSets.top();
newTopSet->insert(oldTopSet->begin(), oldTopSet->end());
}
delete oldTopSet;
}
// Does nothing if there is no top set.
// This can be called when there is no top set if we are visiting
// symbols that are not under an assignment or condition.
// We don't need to track those symbols.
void insertIntoTopSet(TGraphParentNode *node)
{
if (mNodeSets.empty())
return;
mNodeSets.top()->insert(node);
}
void clear()
{
while (!mNodeSets.empty())
popSet();
}
private:
typedef std::stack<TParentNodeSet *> TParentNodeSetStack;
TParentNodeSetStack mNodeSets;
};
//
// An instance of this class pushes a new node set when instantiated.
// When the instance goes out of scope, it and pops the node set.
//
class TNodeSetMaintainer : angle::NonCopyable
{
public:
TNodeSetMaintainer(TDependencyGraphBuilder *factory)
: mSets(factory->mNodeSets)
{
mSets.pushSet();
}
~TNodeSetMaintainer() { mSets.popSet(); }
protected:
TNodeSetStack &mSets;
};
//
// An instance of this class pushes a new node set when instantiated.
// When the instance goes out of scope, it and pops the top node set and adds
// its contents to the new top node set.
//
class TNodeSetPropagatingMaintainer : angle::NonCopyable
{
public:
TNodeSetPropagatingMaintainer(TDependencyGraphBuilder *factory)
: mSets(factory->mNodeSets)
{
mSets.pushSet();
}
~TNodeSetPropagatingMaintainer() { mSets.popSetIntoNext(); }
protected:
TNodeSetStack &mSets;
};
//
// An instance of this class keeps track of the leftmost symbol while we're
// exploring an assignment.
// It will push the placeholder symbol kLeftSubtree when instantiated under a
// left subtree, and kRightSubtree under a right subtree.
// When it goes out of scope, it will pop the leftmost symbol at the top of the
// scope.
// During traversal, the TDependencyGraphBuilder will replace kLeftSubtree with
// a real symbol.
// kRightSubtree will never be replaced by a real symbol because we are tracking
// the leftmost symbol.
//
class TLeftmostSymbolMaintainer : angle::NonCopyable
{
public:
TLeftmostSymbolMaintainer(
TDependencyGraphBuilder *factory, TGraphSymbol &subtree)
: mLeftmostSymbols(factory->mLeftmostSymbols)
{
mNeedsPlaceholderSymbol =
mLeftmostSymbols.empty() || mLeftmostSymbols.top() != &subtree;
if (mNeedsPlaceholderSymbol)
mLeftmostSymbols.push(&subtree);
}
~TLeftmostSymbolMaintainer()
{
if (mNeedsPlaceholderSymbol)
mLeftmostSymbols.pop();
}
protected:
TSymbolStack& mLeftmostSymbols;
bool mNeedsPlaceholderSymbol;
};
TDependencyGraphBuilder(TDependencyGraph *graph)
: TIntermTraverser(true, false, false),
mLeftSubtree(NULL),
mRightSubtree(NULL),
mGraph(graph) {}
void build(TIntermNode *intermNode) { intermNode->traverse(this); }
void connectMultipleNodesToSingleNode(
TParentNodeSet *nodes, TGraphNode *node) const;
void visitAssignment(TIntermBinary *);
void visitLogicalOp(TIntermBinary *);
void visitBinaryChildren(TIntermBinary *);
void visitFunctionDefinition(TIntermAggregate *);
void visitFunctionCall(TIntermAggregate *intermFunctionCall);
void visitAggregateChildren(TIntermAggregate *);
TGraphSymbol mLeftSubtree;
TGraphSymbol mRightSubtree;
TDependencyGraph *mGraph;
TNodeSetStack mNodeSets;
TSymbolStack mLeftmostSymbols;
};
#endif // COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPHBUILDER_H_

View File

@ -1,64 +0,0 @@
//
// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#include "compiler/translator/depgraph/DependencyGraphOutput.h"
void TDependencyGraphOutput::outputIndentation()
{
for (int i = 0; i < getDepth(); ++i)
mSink << " ";
}
void TDependencyGraphOutput::visitArgument(TGraphArgument* parameter)
{
outputIndentation();
mSink << "argument " << parameter->getArgumentNumber() << " of call to "
<< parameter->getIntermFunctionCall()->getName() << "\n";
}
void TDependencyGraphOutput::visitFunctionCall(TGraphFunctionCall* functionCall)
{
outputIndentation();
mSink << "function call " << functionCall->getIntermFunctionCall()->getName() << "\n";
}
void TDependencyGraphOutput::visitSymbol(TGraphSymbol* symbol)
{
outputIndentation();
mSink << symbol->getIntermSymbol()->getSymbol() << " (symbol id: "
<< symbol->getIntermSymbol()->getId() << ")\n";
}
void TDependencyGraphOutput::visitSelection(TGraphSelection* selection)
{
outputIndentation();
mSink << "selection\n";
}
void TDependencyGraphOutput::visitLoop(TGraphLoop* loop)
{
outputIndentation();
mSink << "loop condition\n";
}
void TDependencyGraphOutput::visitLogicalOp(TGraphLogicalOp* logicalOp)
{
outputIndentation();
mSink << "logical " << logicalOp->getOpString() << "\n";
}
void TDependencyGraphOutput::outputAllSpanningTrees(TDependencyGraph& graph)
{
mSink << "\n";
for (auto symbol : graph.allNodes())
{
mSink << "--- Dependency graph spanning tree ---\n";
clearVisited();
symbol->traverse(this);
mSink << "\n";
}
}

View File

@ -1,31 +0,0 @@
//
// Copyright (c) 2012 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_DEPGRAPH_DEPENDENCYGRAPHOUTPUT_H_
#define COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPHOUTPUT_H_
#include "compiler/translator/depgraph/DependencyGraph.h"
#include "compiler/translator/InfoSink.h"
class TDependencyGraphOutput : public TDependencyGraphTraverser
{
public:
TDependencyGraphOutput(TInfoSinkBase& sink) : mSink(sink) {}
void visitSymbol(TGraphSymbol* symbol) override;
void visitArgument(TGraphArgument* parameter) override;
void visitFunctionCall(TGraphFunctionCall* functionCall) override;
void visitSelection(TGraphSelection* selection) override;
void visitLoop(TGraphLoop* loop) override;
void visitLogicalOp(TGraphLogicalOp* logicalOp) override;
void outputAllSpanningTrees(TDependencyGraph& graph);
private:
void outputIndentation();
TInfoSinkBase& mSink;
};
#endif // COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPHOUTPUT_H_

View File

@ -1,69 +0,0 @@
//
// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#include "compiler/translator/depgraph/DependencyGraph.h"
// These methods do a breadth-first traversal through the graph and mark visited nodes.
void TGraphNode::traverse(TDependencyGraphTraverser* graphTraverser)
{
graphTraverser->markVisited(this);
}
void TGraphParentNode::traverse(TDependencyGraphTraverser* graphTraverser)
{
TGraphNode::traverse(graphTraverser);
graphTraverser->incrementDepth();
// Visit the parent node's children.
for (TGraphNodeSet::const_iterator iter = mDependentNodes.begin();
iter != mDependentNodes.end();
++iter)
{
TGraphNode* node = *iter;
if (!graphTraverser->isVisited(node))
node->traverse(graphTraverser);
}
graphTraverser->decrementDepth();
}
void TGraphArgument::traverse(TDependencyGraphTraverser* graphTraverser)
{
graphTraverser->visitArgument(this);
TGraphParentNode::traverse(graphTraverser);
}
void TGraphFunctionCall::traverse(TDependencyGraphTraverser* graphTraverser)
{
graphTraverser->visitFunctionCall(this);
TGraphParentNode::traverse(graphTraverser);
}
void TGraphSymbol::traverse(TDependencyGraphTraverser* graphTraverser)
{
graphTraverser->visitSymbol(this);
TGraphParentNode::traverse(graphTraverser);
}
void TGraphSelection::traverse(TDependencyGraphTraverser* graphTraverser)
{
graphTraverser->visitSelection(this);
TGraphNode::traverse(graphTraverser);
}
void TGraphLoop::traverse(TDependencyGraphTraverser* graphTraverser)
{
graphTraverser->visitLoop(this);
TGraphNode::traverse(graphTraverser);
}
void TGraphLogicalOp::traverse(TDependencyGraphTraverser* graphTraverser)
{
graphTraverser->visitLogicalOp(this);
TGraphNode::traverse(graphTraverser);
}

View File

@ -80,6 +80,7 @@ WHICH GENERATES THE GLSL ES PARSER (glslang_tab.cpp AND glslang_tab.h).
TIntermCase* intermCase;
};
union {
TTypeSpecifierNonArray typeSpecifierNonArray;
TPublicType type;
TPrecision precision;
TLayoutQualifier layoutQualifier;
@ -88,6 +89,8 @@ WHICH GENERATES THE GLSL ES PARSER (glslang_tab.cpp AND glslang_tab.h).
TParameter param;
TField* field;
TFieldList* fieldList;
TQualifierWrapperBase* qualifierWrapper;
TTypeQualifierBuilder* typeQualifierBuilder;
};
} interm;
}
@ -205,13 +208,18 @@ extern void yyerror(YYLTYPE* yylloc, TParseContext* context, void *scanner, cons
%type <interm> single_declaration init_declarator_list
%type <interm> parameter_declaration parameter_declarator parameter_type_specifier
%type <interm.qualifier> parameter_qualifier parameter_type_qualifier
%type <interm.layoutQualifier> layout_qualifier layout_qualifier_id_list layout_qualifier_id
%type <interm.layoutQualifier> layout_qualifier_id_list layout_qualifier_id
%type <interm.type> fully_specified_type type_specifier
%type <interm.precision> precision_qualifier
%type <interm.type> type_qualifier fully_specified_type type_specifier storage_qualifier interpolation_qualifier
%type <interm.type> type_specifier_no_prec type_specifier_nonarray
%type <interm.type> struct_specifier
%type <interm.layoutQualifier> layout_qualifier
%type <interm.qualifier> storage_qualifier interpolation_qualifier
%type <interm.qualifierWrapper> single_type_qualifier invariant_qualifier
%type <interm.typeQualifierBuilder> type_qualifier
%type <interm.typeSpecifierNonArray> type_specifier_nonarray struct_specifier
%type <interm.type> type_specifier_no_prec
%type <interm.field> struct_declarator
%type <interm.fieldList> struct_declarator_list struct_declaration struct_declaration_list
%type <interm.function> function_header function_declarator function_identifier
@ -604,31 +612,36 @@ declaration
context->error(@1, "precision is not supported in fragment shader", "highp");
}
if (!context->symbolTable.setDefaultPrecision( $3, $2 )) {
context->error(@1, "illegal type argument for default precision qualifier", getBasicString($3.type));
context->error(@1, "illegal type argument for default precision qualifier", getBasicString($3.getBasicType()));
}
$$ = 0;
}
| type_qualifier enter_struct struct_declaration_list RIGHT_BRACE SEMICOLON {
ES3_OR_NEWER(getQualifierString($1.qualifier), @1, "interface blocks");
$$ = context->addInterfaceBlock($1, @2, *$2.string, $3, NULL, @$, NULL, @$);
ES3_OR_NEWER($2.string->c_str(), @1, "interface blocks");
$$ = context->addInterfaceBlock(*$1, @2, *$2.string, $3, NULL, @$, NULL, @$);
}
| type_qualifier enter_struct struct_declaration_list RIGHT_BRACE IDENTIFIER SEMICOLON {
ES3_OR_NEWER(getQualifierString($1.qualifier), @1, "interface blocks");
$$ = context->addInterfaceBlock($1, @2, *$2.string, $3, $5.string, @5, NULL, @$);
ES3_OR_NEWER($2.string->c_str(), @1, "interface blocks");
$$ = context->addInterfaceBlock(*$1, @2, *$2.string, $3, $5.string, @5, NULL, @$);
}
| type_qualifier enter_struct struct_declaration_list RIGHT_BRACE IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET SEMICOLON {
ES3_OR_NEWER(getQualifierString($1.qualifier), @1, "interface blocks");
$$ = context->addInterfaceBlock($1, @2, *$2.string, $3, $5.string, @5, $7, @6);
ES3_OR_NEWER($2.string->c_str(), @1, "interface blocks");
$$ = context->addInterfaceBlock(*$1, @2, *$2.string, $3, $5.string, @5, $7, @6);
}
| type_qualifier SEMICOLON {
context->parseGlobalLayoutQualifier($1);
context->parseGlobalLayoutQualifier(*$1);
$$ = 0;
}
| type_qualifier IDENTIFIER SEMICOLON // e.g. to qualify an existing variable as invariant
{
$$ = context->parseInvariantDeclaration(*$1, @2, $2.string, $2.symbol);
}
;
function_prototype
: function_declarator RIGHT_PAREN {
$$.function = context->parseFunctionDeclarator(@2, $1);
context->exitFunctionDeclaration();
}
;
@ -675,13 +688,14 @@ function_header
$$ = context->parseFunctionHeader($1, $2.string, @2);
context->symbolTable.push();
context->enterFunctionDeclaration();
}
;
parameter_declarator
// Type + name
: type_specifier identifier {
if ($1.type == EbtVoid) {
if ($1.getBasicType() == EbtVoid) {
context->error(@2, "illegal use of type 'void'", $2.string->c_str());
}
context->checkIsNotReserved(@2, *$2.string);
@ -713,41 +727,21 @@ parameter_declaration
//
// Type + name
//
: parameter_type_qualifier parameter_qualifier parameter_declarator {
$$ = $3;
context->checkIsParameterQualifierValid(@3, $1, $2, $$.param.type);
}
| parameter_qualifier parameter_declarator {
: type_qualifier parameter_declarator {
$$ = $2;
context->checkOutParameterIsNotSampler(@2, $1, *$2.param.type);
context->checkIsParameterQualifierValid(@2, EvqTemporary, $1, $$.param.type);
context->checkIsParameterQualifierValid(@2, *$1, $2.param.type);
}
//
// Only type
//
| parameter_type_qualifier parameter_qualifier parameter_type_specifier {
$$ = $3;
context->checkIsParameterQualifierValid(@3, $1, $2, $$.param.type);
| parameter_declarator {
$$ = $1;
$$.param.type->setQualifier(EvqIn);
}
| parameter_qualifier parameter_type_specifier {
| type_qualifier parameter_type_specifier {
$$ = $2;
context->checkOutParameterIsNotSampler(@2, $1, *$2.param.type);
context->checkIsParameterQualifierValid(@2, EvqTemporary, $1, $$.param.type);
context->checkIsParameterQualifierValid(@2, *$1, $2.param.type);
}
;
parameter_qualifier
: /* empty */ {
$$ = EvqIn;
}
| IN_QUAL {
$$ = EvqIn;
}
| OUT_QUAL {
$$ = EvqOut;
}
| INOUT_QUAL {
$$ = EvqInOut;
| parameter_type_specifier {
$$ = $1;
$$.param.type->setQualifier(EvqIn);
}
;
@ -813,10 +807,6 @@ single_declaration
$$.type = $1;
$$.intermAggregate = context->parseSingleInitDeclaration($$.type, @2, *$2.string, @3, $4);
}
| INVARIANT IDENTIFIER {
// $$.type is not used in invariant declarations.
$$.intermAggregate = context->parseInvariantDeclaration(@1, @2, $2.string, $2.symbol);
}
;
fully_specified_type
@ -830,124 +820,134 @@ fully_specified_type
}
}
}
| type_qualifier type_specifier {
$$ = context->addFullySpecifiedType($1.qualifier, $1.invariant, $1.layoutQualifier, $2);
| type_qualifier type_specifier {
$$ = context->addFullySpecifiedType(*$1, $2);
}
;
interpolation_qualifier
: SMOOTH {
$$.qualifier = EvqSmooth;
$$ = EvqSmooth;
}
| FLAT {
$$.qualifier = EvqFlat;
}
;
parameter_type_qualifier
: CONST_QUAL {
$$ = EvqConst;
$$ = EvqFlat;
}
;
type_qualifier
: ATTRIBUTE {
: single_type_qualifier {
$$ = context->createTypeQualifierBuilder(@1);
$$->appendQualifier($1);
}
| type_qualifier single_type_qualifier {
$$ = $1;
$$->appendQualifier($2);
}
;
invariant_qualifier
: INVARIANT {
// empty
}
;
single_type_qualifier
: storage_qualifier {
if (!context->declaringFunction() && $1 != EvqConst && !context->symbolTable.atGlobalLevel())
{
context->error(@1, "Local variables can only use the const storage qualifier.", getQualifierString($1));
}
$$ = new TStorageQualifierWrapper($1, @1);
}
| layout_qualifier {
context->checkIsAtGlobalLevel(@1, "layout");
$$ = new TLayoutQualifierWrapper($1, @1);
}
| precision_qualifier {
$$ = new TPrecisionQualifierWrapper($1, @1);
}
| interpolation_qualifier {
$$ = new TInterpolationQualifierWrapper($1, @1);
}
| invariant_qualifier {
context->checkIsAtGlobalLevel(@1, "invariant");
$$ = new TInvariantQualifierWrapper(@1);
}
;
storage_qualifier
:
ATTRIBUTE {
VERTEX_ONLY("attribute", @1);
ES2_ONLY("attribute", @1);
context->checkIsAtGlobalLevel(@1, "attribute");
$$.setBasic(EbtVoid, EvqAttribute, @1);
$$ = EvqAttribute;
}
| VARYING {
ES2_ONLY("varying", @1);
context->checkIsAtGlobalLevel(@1, "varying");
if (context->getShaderType() == GL_VERTEX_SHADER)
$$.setBasic(EbtVoid, EvqVaryingOut, @1);
$$ = EvqVaryingOut;
else
$$.setBasic(EbtVoid, EvqVaryingIn, @1);
$$ = EvqVaryingIn;
}
| INVARIANT VARYING {
ES2_ONLY("varying", @1);
context->checkIsAtGlobalLevel(@1, "invariant varying");
if (context->getShaderType() == GL_VERTEX_SHADER)
$$.setBasic(EbtVoid, EvqVaryingOut, @1);
else
$$.setBasic(EbtVoid, EvqVaryingIn, @1);
$$.invariant = true;
}
| storage_qualifier {
if ($1.qualifier != EvqConst && !context->symbolTable.atGlobalLevel())
{
context->error(@1, "Local variables can only use the const storage qualifier.", getQualifierString($1.qualifier));
}
$$.setBasic(EbtVoid, $1.qualifier, @1);
}
| interpolation_qualifier storage_qualifier {
$$ = context->joinInterpolationQualifiers(@1, $1.qualifier, @2, $2.qualifier);
}
| interpolation_qualifier {
context->error(@1, "interpolation qualifier requires a fragment 'in' or vertex 'out' storage qualifier", getInterpolationString($1.qualifier));
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtVoid, qual, @1);
}
| layout_qualifier {
$$.qualifier = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.layoutQualifier = $1;
}
| layout_qualifier storage_qualifier {
$$.setBasic(EbtVoid, $2.qualifier, @2);
$$.layoutQualifier = $1;
}
| INVARIANT storage_qualifier {
context->checkInvariantIsOutVariableES3($2.qualifier, @1);
$$.setBasic(EbtVoid, $2.qualifier, @2);
$$.invariant = true;
}
| INVARIANT interpolation_qualifier storage_qualifier {
context->checkInvariantIsOutVariableES3($3.qualifier, @1);
$$ = context->joinInterpolationQualifiers(@2, $2.qualifier, @3, $3.qualifier);
$$.invariant = true;
}
;
storage_qualifier
: CONST_QUAL {
$$.qualifier = EvqConst;
| CONST_QUAL {
$$ = EvqConst;
}
| IN_QUAL {
if (context->getShaderType() == GL_FRAGMENT_SHADER)
if (context->declaringFunction())
{
$$ = EvqIn;
}
else if (context->getShaderType() == GL_FRAGMENT_SHADER)
{
ES3_OR_NEWER("in", @1, "storage qualifier");
$$.qualifier = EvqFragmentIn;
$$ = EvqFragmentIn;
}
else if (context->getShaderType() == GL_VERTEX_SHADER)
{
ES3_OR_NEWER("in", @1, "storage qualifier");
$$.qualifier = EvqVertexIn;
$$ = EvqVertexIn;
}
else
{
$$.qualifier = EvqComputeIn;
$$ = EvqComputeIn;
}
}
| OUT_QUAL {
ES3_OR_NEWER("out", @1, "storage qualifier");
NON_COMPUTE_ONLY("out", @1);
$$.qualifier = (context->getShaderType() == GL_FRAGMENT_SHADER) ? EvqFragmentOut : EvqVertexOut;
if (context->declaringFunction())
{
$$ = EvqOut;
}
else
{
ES3_OR_NEWER("out", @1, "storage qualifier");
NON_COMPUTE_ONLY("out", @1);
if (context->getShaderType() == GL_FRAGMENT_SHADER)
{
$$ = EvqFragmentOut;
}
else
{
$$ = EvqVertexOut;
}
}
}
| CENTROID IN_QUAL {
ES3_OR_NEWER("centroid in", @1, "storage qualifier");
FRAG_ONLY("centroid in", @1);
$$.qualifier = EvqCentroidIn;
| INOUT_QUAL {
if (!context->declaringFunction())
{
context->error(@1, "invalid inout qualifier", "'inout' can be only used with function parameters");
}
$$ = EvqInOut;
}
| CENTROID OUT_QUAL {
ES3_OR_NEWER("centroid out", @1, "storage qualifier");
VERTEX_ONLY("centroid out", @1);
$$.qualifier = EvqCentroidOut;
| CENTROID {
ES3_OR_NEWER("centroid", @1, "storage qualifier");
$$ = EvqCentroid;
}
| UNIFORM {
context->checkIsAtGlobalLevel(@1, "uniform");
$$.qualifier = EvqUniform;
$$ = EvqUniform;
}
;
@ -956,16 +956,7 @@ type_specifier
$$ = $1;
if ($$.precision == EbpUndefined) {
$$.precision = context->symbolTable.getDefaultPrecision($1.type);
context->checkPrecisionSpecified(@1, $$.precision, $1.type);
}
}
| precision_qualifier type_specifier_no_prec {
$$ = $2;
$$.precision = $1;
if (!SupportsPrecision($2.type)) {
context->error(@1, "illegal type for precision qualifier", getBasicString($2.type));
$$.precision = context->symbolTable.getDefaultPrecision($1.getBasicType());
}
}
;
@ -1012,17 +1003,16 @@ layout_qualifier_id
type_specifier_no_prec
: type_specifier_nonarray {
$$ = $1;
$$.initialize($1, (context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary));
}
| type_specifier_nonarray LEFT_BRACKET RIGHT_BRACKET {
ES3_OR_NEWER("[]", @2, "implicitly sized array");
$$ = $1;
$$.initialize($1, (context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary));
$$.setArraySize(0);
}
| type_specifier_nonarray LEFT_BRACKET constant_expression RIGHT_BRACKET {
$$ = $1;
if (context->checkIsValidTypeForArray(@2, $1))
$$.initialize($1, (context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary));
if (context->checkIsValidTypeForArray(@2, $$))
{
unsigned int size = context->checkIsValidArraySize(@2, $3);
$$.setArraySize(size);
@ -1032,208 +1022,164 @@ type_specifier_no_prec
type_specifier_nonarray
: VOID_TYPE {
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtVoid, qual, @1);
$$.initialize(EbtVoid, @1);
}
| FLOAT_TYPE {
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtFloat, qual, @1);
$$.initialize(EbtFloat, @1);
}
| INT_TYPE {
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtInt, qual, @1);
$$.initialize(EbtInt, @1);
}
| UINT_TYPE {
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtUInt, qual, @1);
$$.initialize(EbtUInt, @1);
}
| BOOL_TYPE {
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtBool, qual, @1);
$$.initialize(EbtBool, @1);
}
| VEC2 {
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtFloat, qual, @1);
$$.initialize(EbtFloat, @1);
$$.setAggregate(2);
}
| VEC3 {
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtFloat, qual, @1);
$$.initialize(EbtFloat, @1);
$$.setAggregate(3);
}
| VEC4 {
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtFloat, qual, @1);
$$.initialize(EbtFloat, @1);
$$.setAggregate(4);
}
| BVEC2 {
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtBool, qual, @1);
$$.initialize(EbtBool, @1);
$$.setAggregate(2);
}
| BVEC3 {
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtBool, qual, @1);
$$.initialize(EbtBool, @1);
$$.setAggregate(3);
}
| BVEC4 {
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtBool, qual, @1);
$$.initialize(EbtBool, @1);
$$.setAggregate(4);
}
| IVEC2 {
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtInt, qual, @1);
$$.initialize(EbtInt, @1);
$$.setAggregate(2);
}
| IVEC3 {
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtInt, qual, @1);
$$.initialize(EbtInt, @1);
$$.setAggregate(3);
}
| IVEC4 {
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtInt, qual, @1);
$$.initialize(EbtInt, @1);
$$.setAggregate(4);
}
| UVEC2 {
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtUInt, qual, @1);
$$.initialize(EbtUInt, @1);
$$.setAggregate(2);
}
| UVEC3 {
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtUInt, qual, @1);
$$.initialize(EbtUInt, @1);
$$.setAggregate(3);
}
| UVEC4 {
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtUInt, qual, @1);
$$.initialize(EbtUInt, @1);
$$.setAggregate(4);
}
| MATRIX2 {
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtFloat, qual, @1);
$$.initialize(EbtFloat, @1);
$$.setMatrix(2, 2);
}
| MATRIX3 {
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtFloat, qual, @1);
$$.initialize(EbtFloat, @1);
$$.setMatrix(3, 3);
}
| MATRIX4 {
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtFloat, qual, @1);
$$.initialize(EbtFloat, @1);
$$.setMatrix(4, 4);
}
| MATRIX2x3 {
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtFloat, qual, @1);
$$.initialize(EbtFloat, @1);
$$.setMatrix(2, 3);
}
| MATRIX3x2 {
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtFloat, qual, @1);
$$.initialize(EbtFloat, @1);
$$.setMatrix(3, 2);
}
| MATRIX2x4 {
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtFloat, qual, @1);
$$.initialize(EbtFloat, @1);
$$.setMatrix(2, 4);
}
| MATRIX4x2 {
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtFloat, qual, @1);
$$.initialize(EbtFloat, @1);
$$.setMatrix(4, 2);
}
| MATRIX3x4 {
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtFloat, qual, @1);
$$.initialize(EbtFloat, @1);
$$.setMatrix(3, 4);
}
| MATRIX4x3 {
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtFloat, qual, @1);
$$.initialize(EbtFloat, @1);
$$.setMatrix(4, 3);
}
| SAMPLER2D {
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtSampler2D, qual, @1);
$$.initialize(EbtSampler2D, @1);
}
| SAMPLER3D {
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtSampler3D, qual, @1);
$$.initialize(EbtSampler3D, @1);
}
| SAMPLERCUBE {
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtSamplerCube, qual, @1);
$$.initialize(EbtSamplerCube, @1);
}
| SAMPLER2DARRAY {
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtSampler2DArray, qual, @1);
$$.initialize(EbtSampler2DArray, @1);
}
| ISAMPLER2D {
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtISampler2D, qual, @1);
$$.initialize(EbtISampler2D, @1);
}
| ISAMPLER3D {
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtISampler3D, qual, @1);
$$.initialize(EbtISampler3D, @1);
}
| ISAMPLERCUBE {
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtISamplerCube, qual, @1);
$$.initialize(EbtISamplerCube, @1);
}
| ISAMPLER2DARRAY {
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtISampler2DArray, qual, @1);
$$.initialize(EbtISampler2DArray, @1);
}
| USAMPLER2D {
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtUSampler2D, qual, @1);
$$.initialize(EbtUSampler2D, @1);
}
| USAMPLER3D {
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtUSampler3D, qual, @1);
$$.initialize(EbtUSampler3D, @1);
}
| USAMPLERCUBE {
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtUSamplerCube, qual, @1);
$$.initialize(EbtUSamplerCube, @1);
}
| USAMPLER2DARRAY {
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtUSampler2DArray, qual, @1);
$$.initialize(EbtUSampler2DArray, @1);
}
| SAMPLER2DSHADOW {
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtSampler2DShadow, qual, @1);
$$.initialize(EbtSampler2DShadow, @1);
}
| SAMPLERCUBESHADOW {
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtSamplerCubeShadow, qual, @1);
$$.initialize(EbtSamplerCubeShadow, @1);
}
| SAMPLER2DARRAYSHADOW {
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtSampler2DArrayShadow, qual, @1);
$$.initialize(EbtSampler2DArrayShadow, @1);
}
| SAMPLER_EXTERNAL_OES {
if (!context->supportsExtension("GL_OES_EGL_image_external") &&
!context->supportsExtension("GL_NV_EGL_stream_consumer_external")) {
context->error(@1, "unsupported type", "samplerExternalOES");
}
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtSamplerExternalOES, qual, @1);
$$.initialize(EbtSamplerExternalOES, @1);
}
| SAMPLER2DRECT {
if (!context->supportsExtension("GL_ARB_texture_rectangle")) {
context->error(@1, "unsupported type", "sampler2DRect");
}
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtSampler2DRect, qual, @1);
$$.initialize(EbtSampler2DRect, @1);
}
| struct_specifier {
$$ = $1;
$$.qualifier = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
}
| TYPE_NAME {
//
@ -1241,8 +1187,7 @@ type_specifier_nonarray
// type.
//
TType& structure = static_cast<TVariable*>($1.symbol)->getType();
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtStruct, qual, @1);
$$.initialize(EbtStruct, @1);
$$.userDef = &structure;
}
;
@ -1280,9 +1225,7 @@ struct_declaration
}
| type_qualifier type_specifier struct_declarator_list SEMICOLON {
// ES3 Only, but errors should be handled elsewhere
$2.qualifier = $1.qualifier;
$2.layoutQualifier = $1.layoutQualifier;
$$ = context->addStructDeclaratorList($2, $3);
$$ = context->addStructDeclaratorListWithQualifiers(*$1, &$2, $3);
}
;

File diff suppressed because it is too large Load Diff

View File

@ -208,6 +208,7 @@ union YYSTYPE
TIntermCase* intermCase;
};
union {
TTypeSpecifierNonArray typeSpecifierNonArray;
TPublicType type;
TPrecision precision;
TLayoutQualifier layoutQualifier;
@ -216,6 +217,8 @@ union YYSTYPE
TParameter param;
TField* field;
TFieldList* fieldList;
TQualifierWrapperBase *qualifierWrapper;
TTypeQualifierBuilder *typeQualifierBuilder;
};
} interm;

View File

@ -44,10 +44,12 @@ class TOutputTraverser : public TIntermTraverser
void visitConstantUnion(TIntermConstantUnion *) override;
bool visitBinary(Visit visit, TIntermBinary *) override;
bool visitUnary(Visit visit, TIntermUnary *) override;
bool visitTernary(Visit visit, TIntermTernary *node) override;
bool visitSelection(Visit visit, TIntermSelection *) override;
bool visitAggregate(Visit visit, TIntermAggregate *) override;
bool visitLoop(Visit visit, TIntermLoop *) override;
bool visitBranch(Visit visit, TIntermBranch *) override;
// TODO: Add missing visit functions
};
//
@ -457,14 +459,46 @@ bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
return true;
}
bool TOutputTraverser::visitTernary(Visit visit, TIntermTernary *node)
{
TInfoSinkBase &out = sink;
OutputTreeText(out, node, mDepth);
out << "Ternary selection";
out << " (" << node->getCompleteString() << ")\n";
++mDepth;
OutputTreeText(sink, node, mDepth);
out << "Condition\n";
node->getCondition()->traverse(this);
OutputTreeText(sink, node, mDepth);
if (node->getTrueExpression())
{
out << "true case\n";
node->getTrueExpression()->traverse(this);
}
if (node->getFalseExpression())
{
OutputTreeText(sink, node, mDepth);
out << "false case\n";
node->getFalseExpression()->traverse(this);
}
--mDepth;
return false;
}
bool TOutputTraverser::visitSelection(Visit visit, TIntermSelection *node)
{
TInfoSinkBase &out = sink;
OutputTreeText(out, node, mDepth);
out << "Test condition and select";
out << " (" << node->getCompleteString() << ")\n";
out << "If test\n";
++mDepth;

View File

@ -1,130 +0,0 @@
//
// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#include "compiler/translator/InfoSink.h"
#include "compiler/translator/ParseContext.h"
#include "compiler/translator/depgraph/DependencyGraphOutput.h"
#include "compiler/translator/timing/RestrictFragmentShaderTiming.h"
RestrictFragmentShaderTiming::RestrictFragmentShaderTiming(TInfoSinkBase& sink)
: mSink(sink)
, mNumErrors(0)
{
// Sampling ops found only in fragment shaders.
mSamplingOps.insert("texture2D(s21;vf2;f1;");
mSamplingOps.insert("texture2DProj(s21;vf3;f1;");
mSamplingOps.insert("texture2DProj(s21;vf4;f1;");
mSamplingOps.insert("textureCube(sC1;vf3;f1;");
// Sampling ops found in both vertex and fragment shaders.
mSamplingOps.insert("texture2D(s21;vf2;");
mSamplingOps.insert("texture2DProj(s21;vf3;");
mSamplingOps.insert("texture2DProj(s21;vf4;");
mSamplingOps.insert("textureCube(sC1;vf3;");
// Sampling ops provided by OES_EGL_image_external.
mSamplingOps.insert("texture2D(1;vf2;");
mSamplingOps.insert("texture2DProj(1;vf3;");
mSamplingOps.insert("texture2DProj(1;vf4;");
// Sampling ops provided by ARB_texture_rectangle.
mSamplingOps.insert("texture2DRect(1;vf2;");
mSamplingOps.insert("texture2DRectProj(1;vf3;");
mSamplingOps.insert("texture2DRectProj(1;vf4;");
// Sampling ops provided by EXT_shader_texture_lod.
mSamplingOps.insert("texture2DLodEXT(1;vf2;f1;");
mSamplingOps.insert("texture2DProjLodEXT(1;vf3;f1;");
mSamplingOps.insert("texture2DProjLodEXT(1;vf4;f1;");
mSamplingOps.insert("textureCubeLodEXT(1;vf4;f1;");
mSamplingOps.insert("texture2DGradEXT(1;vf2;vf2;vf2;");
mSamplingOps.insert("texture2DProjGradEXT(1;vf3;vf2;vf2;");
mSamplingOps.insert("texture2DProjGradEXT(1;vf4;vf2;vf2;");
mSamplingOps.insert("textureCubeGradEXT(1;vf3;vf3;vf3;");
}
// FIXME(mvujovic): We do not know if the execution time of built-in operations like sin, pow, etc.
// can vary based on the value of the input arguments. If so, we should restrict those as well.
void RestrictFragmentShaderTiming::enforceRestrictions(const TDependencyGraph& graph)
{
mNumErrors = 0;
// FIXME(mvujovic): The dependency graph does not support user defined function calls right now,
// so we generate errors for them.
validateUserDefinedFunctionCallUsage(graph);
// Starting from each sampler, traverse the dependency graph and generate an error each time we
// hit a node where sampler dependent values are not allowed.
for (auto samplerSymbol : graph.samplerSymbols())
{
clearVisited();
samplerSymbol->traverse(this);
}
}
void RestrictFragmentShaderTiming::validateUserDefinedFunctionCallUsage(const TDependencyGraph& graph)
{
for (const auto* functionCall : graph.userDefinedFunctionCalls())
{
beginError(functionCall->getIntermFunctionCall());
mSink << "A call to a user defined function is not permitted.\n";
}
}
void RestrictFragmentShaderTiming::beginError(const TIntermNode* node)
{
++mNumErrors;
mSink.prefix(EPrefixError);
mSink.location(node->getLine());
}
bool RestrictFragmentShaderTiming::isSamplingOp(const TIntermAggregate* intermFunctionCall) const
{
return !intermFunctionCall->isUserDefined() &&
mSamplingOps.find(intermFunctionCall->getName()) != mSamplingOps.end();
}
void RestrictFragmentShaderTiming::visitArgument(TGraphArgument* parameter)
{
// Texture cache access time might leak sensitive information.
// Thus, we restrict sampler dependent values from affecting the coordinate or LOD bias of a
// sampling operation.
if (isSamplingOp(parameter->getIntermFunctionCall())) {
switch (parameter->getArgumentNumber()) {
case 1:
// Second argument (coord)
beginError(parameter->getIntermFunctionCall());
mSink << "An expression dependent on a sampler is not permitted to be the"
<< " coordinate argument of a sampling operation.\n";
break;
case 2:
// Third argument (bias)
beginError(parameter->getIntermFunctionCall());
mSink << "An expression dependent on a sampler is not permitted to be the"
<< " bias argument of a sampling operation.\n";
break;
default:
// First argument (sampler)
break;
}
}
}
void RestrictFragmentShaderTiming::visitSelection(TGraphSelection* selection)
{
beginError(selection->getIntermSelection());
mSink << "An expression dependent on a sampler is not permitted in a conditional statement.\n";
}
void RestrictFragmentShaderTiming::visitLoop(TGraphLoop* loop)
{
beginError(loop->getIntermLoop());
mSink << "An expression dependent on a sampler is not permitted in a loop condition.\n";
}
void RestrictFragmentShaderTiming::visitLogicalOp(TGraphLogicalOp* logicalOp)
{
beginError(logicalOp->getIntermLogicalOp());
mSink << "An expression dependent on a sampler is not permitted on the left hand side of a logical "
<< logicalOp->getOpString()
<< " operator.\n";
}

View File

@ -1,39 +0,0 @@
//
// Copyright (c) 2012 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_TIMING_RESTRICTFRAGMENTSHADERTIMING_H_
#define COMPILER_TRANSLATOR_TIMING_RESTRICTFRAGMENTSHADERTIMING_H_
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/depgraph/DependencyGraph.h"
class TInfoSinkBase;
class RestrictFragmentShaderTiming : TDependencyGraphTraverser
{
public:
RestrictFragmentShaderTiming(TInfoSinkBase &sink);
void enforceRestrictions(const TDependencyGraph &graph);
int numErrors() const { return mNumErrors; }
void visitArgument(TGraphArgument *parameter) override;
void visitSelection(TGraphSelection *selection) override;
void visitLoop(TGraphLoop *loop) override;
void visitLogicalOp(TGraphLogicalOp *logicalOp) override;
private:
void beginError(const TIntermNode *node);
void validateUserDefinedFunctionCallUsage(const TDependencyGraph &graph);
bool isSamplingOp(const TIntermAggregate *intermFunctionCall) const;
TInfoSinkBase &mSink;
int mNumErrors;
typedef std::set<TString> StringSet;
StringSet mSamplingOps;
};
#endif // COMPILER_TRANSLATOR_TIMING_RESTRICTFRAGMENTSHADERTIMING_H_

View File

@ -1,17 +0,0 @@
//
// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#include "compiler/translator/timing/RestrictVertexShaderTiming.h"
void RestrictVertexShaderTiming::visitSymbol(TIntermSymbol* node)
{
if (IsSampler(node->getBasicType())) {
++mNumErrors;
mSink.message(EPrefixError,
node->getLine(),
"Samplers are not permitted in vertex shaders.\n");
}
}

View File

@ -1,32 +0,0 @@
//
// Copyright (c) 2012 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_TIMING_RESTRICTVERTEXSHADERTIMING_H_
#define COMPILER_TRANSLATOR_TIMING_RESTRICTVERTEXSHADERTIMING_H_
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/InfoSink.h"
class TInfoSinkBase;
class RestrictVertexShaderTiming : public TIntermTraverser {
public:
RestrictVertexShaderTiming(TInfoSinkBase& sink)
: TIntermTraverser(true, false, false)
, mSink(sink)
, mNumErrors(0) {}
void enforceRestrictions(TIntermNode* root) { root->traverse(this); }
int numErrors() { return mNumErrors; }
void visitSymbol(TIntermSymbol *) override;
private:
TInfoSinkBase& mSink;
int mNumErrors;
};
#endif // COMPILER_TRANSLATOR_TIMING_RESTRICTVERTEXSHADERTIMING_H_

View File

@ -278,9 +278,9 @@ InterpolationType GetInterpolationType(TQualifier qualifier)
}
}
TType ConvertShaderVariableTypeToTType(sh::GLenum type)
TType GetShaderVariableBasicType(const sh::ShaderVariable &var)
{
switch (type)
switch (var.type)
{
case GL_FLOAT:
return TType(EbtFloat);
@ -330,6 +330,35 @@ TType ConvertShaderVariableTypeToTType(sh::GLenum type)
}
}
TType GetShaderVariableType(const sh::ShaderVariable &var)
{
TType type;
if (var.isStruct())
{
TFieldList *fields = new TFieldList;
TSourceLoc loc;
for (const auto &field : var.fields)
{
TType *fieldType = new TType(GetShaderVariableType(field));
fields->push_back(new TField(fieldType, new TString(field.name.c_str()), loc));
}
TStructure *structure = new TStructure(new TString(var.structName.c_str()), fields);
type.setBasicType(EbtStruct);
type.setStruct(structure);
}
else
{
type = GetShaderVariableBasicType(var);
}
if (var.isArray())
{
type.setArraySize(var.elementCount());
}
return type;
}
TOperator TypeToConstructorOperator(const TType &type)
{
switch (type.getBasicType())
@ -537,4 +566,52 @@ template void GetVariableTraverser::traverse(const TType &, const TString &, std
template void GetVariableTraverser::traverse(const TType &, const TString &, std::vector<Uniform> *);
template void GetVariableTraverser::traverse(const TType &, const TString &, std::vector<Varying> *);
// GLSL ES 1.0.17 4.6.1 The Invariant Qualifier
bool CanBeInvariantESSL1(TQualifier qualifier)
{
return IsVaryingIn(qualifier) || IsVaryingOut(qualifier) ||
IsBuiltinOutputVariable(qualifier) ||
(IsBuiltinFragmentInputVariable(qualifier) && qualifier != EvqFrontFacing);
}
// GLSL ES 3.00 Revision 6, 4.6.1 The Invariant Qualifier
// GLSL ES 3.10 Revision 4, 4.8.1 The Invariant Qualifier
bool CanBeInvariantESSL3OrGreater(TQualifier qualifier)
{
return IsVaryingOut(qualifier) || qualifier == EvqFragmentOut ||
IsBuiltinOutputVariable(qualifier);
}
bool IsBuiltinOutputVariable(TQualifier qualifier)
{
switch (qualifier)
{
case EvqPosition:
case EvqPointSize:
case EvqFragDepth:
case EvqFragDepthEXT:
case EvqFragColor:
case EvqSecondaryFragColorEXT:
case EvqFragData:
case EvqSecondaryFragDataEXT:
return true;
default:
break;
}
return false;
}
bool IsBuiltinFragmentInputVariable(TQualifier qualifier)
{
switch (qualifier)
{
case EvqFragCoord:
case EvqPointCoord:
case EvqFrontFacing:
return true;
default:
break;
}
return false;
}
} // namespace sh

View File

@ -37,8 +37,9 @@ bool IsVaryingOut(TQualifier qualifier);
bool IsVarying(TQualifier qualifier);
InterpolationType GetInterpolationType(TQualifier qualifier);
TString ArrayString(const TType &type);
// Handles only basic output variable types.
TType ConvertShaderVariableTypeToTType(sh::GLenum type);
TType GetShaderVariableBasicType(const sh::ShaderVariable &var);
TType GetShaderVariableType(const sh::ShaderVariable &var);
TOperator TypeToConstructorOperator(const TType &type);
@ -65,6 +66,10 @@ class GetVariableTraverser : angle::NonCopyable
const TSymbolTable &mSymbolTable;
};
bool IsBuiltinOutputVariable(TQualifier qualifier);
bool IsBuiltinFragmentInputVariable(TQualifier qualifier);
bool CanBeInvariantESSL1(TQualifier qualifier);
bool CanBeInvariantESSL3OrGreater(TQualifier qualifier);
}
#endif // COMPILER_TRANSLATOR_UTIL_H_

View File

@ -44,45 +44,33 @@ const std::string &Buffer::getLabel() const
return mLabel;
}
Error Buffer::bufferData(const void *data, GLsizeiptr size, GLenum usage)
Error Buffer::bufferData(GLenum target, const void *data, GLsizeiptr size, GLenum usage)
{
gl::Error error = mBuffer->setData(data, size, usage);
if (error.isError())
{
return error;
}
ANGLE_TRY(mBuffer->setData(target, data, size, usage));
mIndexRangeCache.clear();
mUsage = usage;
mSize = size;
return error;
return NoError();
}
Error Buffer::bufferSubData(const void *data, GLsizeiptr size, GLintptr offset)
Error Buffer::bufferSubData(GLenum target, const void *data, GLsizeiptr size, GLintptr offset)
{
gl::Error error = mBuffer->setSubData(data, size, offset);
if (error.isError())
{
return error;
}
ANGLE_TRY(mBuffer->setSubData(target, data, size, offset));
mIndexRangeCache.invalidateRange(static_cast<unsigned int>(offset), static_cast<unsigned int>(size));
return error;
return NoError();
}
Error Buffer::copyBufferSubData(Buffer* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size)
{
gl::Error error = mBuffer->copySubData(source->getImplementation(), sourceOffset, destOffset, size);
if (error.isError())
{
return error;
}
ANGLE_TRY(mBuffer->copySubData(source->getImplementation(), sourceOffset, destOffset, size));
mIndexRangeCache.invalidateRange(static_cast<unsigned int>(destOffset), static_cast<unsigned int>(size));
return error;
return NoError();
}
Error Buffer::map(GLenum access)
@ -178,18 +166,14 @@ Error Buffer::getIndexRange(GLenum type,
{
if (mIndexRangeCache.findRange(type, offset, count, primitiveRestartEnabled, outRange))
{
return gl::Error(GL_NO_ERROR);
return NoError();
}
Error error = mBuffer->getIndexRange(type, offset, count, primitiveRestartEnabled, outRange);
if (error.isError())
{
return error;
}
ANGLE_TRY(mBuffer->getIndexRange(type, offset, count, primitiveRestartEnabled, outRange));
mIndexRangeCache.addRange(type, offset, count, primitiveRestartEnabled, *outRange);
return Error(GL_NO_ERROR);
return NoError();
}
} // namespace gl

View File

@ -34,8 +34,8 @@ class Buffer final : public RefCountObject, public LabeledObject
void setLabel(const std::string &label) override;
const std::string &getLabel() const override;
Error bufferData(const void *data, GLsizeiptr size, GLenum usage);
Error bufferSubData(const void *data, GLsizeiptr size, GLintptr offset);
Error bufferData(GLenum target, const void *data, GLsizeiptr size, GLenum usage);
Error bufferSubData(GLenum target, const void *data, GLsizeiptr size, GLintptr offset);
Error copyBufferSubData(Buffer* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size);
Error map(GLenum access);
Error mapRange(GLintptr offset, GLsizeiptr length, GLbitfield access);

View File

@ -3430,4 +3430,23 @@ void Context::popDebugGroup()
mGLState.getDebug().popGroup();
}
void Context::bufferData(GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage)
{
Buffer *buffer = mGLState.getTargetBuffer(target);
ASSERT(buffer);
handleError(buffer->bufferData(target, data, size, usage));
}
void Context::bufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data)
{
if (data == nullptr)
{
return;
}
Buffer *buffer = mGLState.getTargetBuffer(target);
ASSERT(buffer);
handleError(buffer->bufferSubData(target, data, size, offset));
}
} // namespace gl

View File

@ -567,6 +567,9 @@ class Context final : public ValidationContext
GLint components,
const GLfloat *coeffs);
void bufferData(GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage);
void bufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data);
void handleError(const Error &error) override;
GLenum getError();

View File

@ -135,7 +135,12 @@ ImageIndexIterator::ImageIndexIterator(GLenum type, const Range<GLint> &mipRange
GLint ImageIndexIterator::maxLayer() const
{
return (mLayerCounts ? static_cast<GLint>(mLayerCounts[mCurrentMip]) : mLayerRange.end);
if (mLayerCounts)
{
ASSERT(mCurrentMip >= 0);
return (mCurrentMip < mMipRange.end) ? mLayerCounts[mCurrentMip] : 0;
}
return mLayerRange.end;
}
ImageIndex ImageIndexIterator::next()
@ -149,21 +154,29 @@ ImageIndex ImageIndexIterator::next()
if (mCurrentLayer != ImageIndex::ENTIRE_LEVEL)
{
if (mCurrentLayer < maxLayer()-1)
if (mCurrentLayer < maxLayer() - 1)
{
mCurrentLayer++;
}
else if (mCurrentMip < mMipRange.end-1)
else if (mCurrentMip < mMipRange.end - 1)
{
mCurrentMip++;
mCurrentLayer = mLayerRange.start;
}
else
{
done();
}
}
else if (mCurrentMip < mMipRange.end-1)
else if (mCurrentMip < mMipRange.end - 1)
{
mCurrentMip++;
mCurrentLayer = mLayerRange.start;
}
else
{
done();
}
return value;
}
@ -185,4 +198,10 @@ bool ImageIndexIterator::hasNext() const
return (mCurrentMip < mMipRange.end || mCurrentLayer < maxLayer());
}
void ImageIndexIterator::done()
{
mCurrentMip = mMipRange.end;
mCurrentLayer = maxLayer();
}
} // namespace gl

View File

@ -68,6 +68,7 @@ class ImageIndexIterator
const Range<GLint> &layerRange, const GLsizei *layerCounts);
GLint maxLayer() const;
void done();
GLenum mType;
Range<GLint> mMipRange;

View File

@ -41,6 +41,8 @@ TEST(ImageIndexTest, Iterator2D)
EXPECT_EQ(current.mipIndex, nextIndex.mipIndex);
EXPECT_EQ(current.layerIndex, nextIndex.layerIndex);
}
EXPECT_FALSE(iter.hasNext());
}
TEST(ImageIndexTest, IteratorCube)
@ -64,6 +66,8 @@ TEST(ImageIndexTest, IteratorCube)
EXPECT_TRUE(nextIndex.hasLayer());
}
}
EXPECT_FALSE(iter.hasNext());
}
TEST(ImageIndexTest, Iterator3D)
@ -85,6 +89,8 @@ TEST(ImageIndexTest, Iterator3D)
EXPECT_TRUE(nextIndex.hasLayer());
}
}
EXPECT_FALSE(iter.hasNext());
}
TEST(ImageIndexTest, Iterator2DArray)
@ -109,6 +115,8 @@ TEST(ImageIndexTest, Iterator2DArray)
EXPECT_TRUE(nextIndex.hasLayer());
}
}
EXPECT_FALSE(iter.hasNext());
}
} // namespace

View File

@ -243,9 +243,9 @@ void Shader::compile(Compiler *compiler)
std::stringstream sourceStream;
std::string sourcePath;
int additionalOptions =
ShCompileOptions additionalOptions =
mImplementation->prepareSourceAndReturnOptions(&sourceStream, &sourcePath);
int compileOptions = (SH_OBJECT_CODE | SH_VARIABLES | additionalOptions);
ShCompileOptions compileOptions = (SH_OBJECT_CODE | SH_VARIABLES | additionalOptions);
// Some targets (eg D3D11 Feature Level 9_3 and below) do not support non-constant loop indexes
// in fragment shaders. Shader compilation will fail. To provide a better error message we can

View File

@ -716,7 +716,7 @@ static InternalFormatInfoMap BuildInternalFormatInfoMap()
AddDepthStencilFormat(&map, GL_STENCIL_INDEX8, 0, 8, 0, GL_STENCIL, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, RequireES<2>, RequireES<2>, NeverSupported);
// From GL_ANGLE_lossy_etc_decode
map.insert(InternalFormatInfoPair(GL_ETC1_RGB8_LOSSY_DECODE_ANGLE, CompressedFormat(4, 4, 64, 3, GL_ETC1_RGB8_OES, GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::lossyETCDecode>, NeverSupported, AlwaysSupported)));
map.insert(InternalFormatInfoPair(GL_ETC1_RGB8_LOSSY_DECODE_ANGLE, CompressedFormat(4, 4, 64, 3, GL_ETC1_RGB8_LOSSY_DECODE_ANGLE, GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::lossyETCDecode>, NeverSupported, AlwaysSupported)));
// From GL_EXT_texture_norm16
// | Internal format | R | G | B | A |S | Format | Type | Component type | SRGB | Texture supported | Renderable | Filterable |

View File

@ -29,11 +29,13 @@ UNIFIED_SOURCES += [
'../compiler/preprocessor/Preprocessor.cpp',
'../compiler/preprocessor/Token.cpp',
'../compiler/preprocessor/Tokenizer.cpp',
'../compiler/translator/AddAndTrueToLoopCondition.cpp',
'../compiler/translator/AddDefaultReturnStatements.cpp',
'../compiler/translator/ArrayReturnValueToOutParameter.cpp',
'../compiler/translator/ASTMetadataHLSL.cpp',
'../compiler/translator/blocklayout.cpp',
'../compiler/translator/blocklayoutHLSL.cpp',
'../compiler/translator/BreakVariableAliasingInInnerLoops.cpp',
'../compiler/translator/BuiltInFunctionEmulator.cpp',
'../compiler/translator/BuiltInFunctionEmulatorGLSL.cpp',
'../compiler/translator/BuiltInFunctionEmulatorHLSL.cpp',
@ -41,11 +43,8 @@ UNIFIED_SOURCES += [
'../compiler/translator/CallDAG.cpp',
'../compiler/translator/CodeGen.cpp',
'../compiler/translator/Compiler.cpp',
'../compiler/translator/ConstantUnion.cpp',
'../compiler/translator/DeferGlobalInitializers.cpp',
'../compiler/translator/depgraph/DependencyGraph.cpp',
'../compiler/translator/depgraph/DependencyGraphBuilder.cpp',
'../compiler/translator/depgraph/DependencyGraphOutput.cpp',
'../compiler/translator/depgraph/DependencyGraphTraverse.cpp',
'../compiler/translator/Diagnostics.cpp',
'../compiler/translator/DirectiveHandler.cpp',
'../compiler/translator/EmulatePrecision.cpp',
@ -72,6 +71,7 @@ UNIFIED_SOURCES += [
'../compiler/translator/ParseContext.cpp',
'../compiler/translator/PoolAlloc.cpp',
'../compiler/translator/PruneEmptyDeclarations.cpp',
'../compiler/translator/QualifierTypes.cpp',
'../compiler/translator/RecordConstantPrecision.cpp',
'../compiler/translator/RegenerateStructNames.cpp',
'../compiler/translator/RemoveDynamicIndexing.cpp',
@ -92,8 +92,6 @@ UNIFIED_SOURCES += [
'../compiler/translator/StructureHLSL.cpp',
'../compiler/translator/SymbolTable.cpp',
'../compiler/translator/TextureFunctionHLSL.cpp',
'../compiler/translator/timing/RestrictFragmentShaderTiming.cpp',
'../compiler/translator/timing/RestrictVertexShaderTiming.cpp',
'../compiler/translator/TranslatorESSL.cpp',
'../compiler/translator/TranslatorGLSL.cpp',
'../compiler/translator/TranslatorHLSL.cpp',

View File

@ -86,17 +86,6 @@ QueryT CastStateValue(GLenum pname, NativeT value)
} // anonymous namespace
template <>
GLenum GLTypeToGLenum<GLint>::value = GL_INT;
template <>
GLenum GLTypeToGLenum<GLuint>::value = GL_UNSIGNED_INT;
template <>
GLenum GLTypeToGLenum<GLboolean>::value = GL_BOOL;
template <>
GLenum GLTypeToGLenum<GLint64>::value = GL_INT_64_ANGLEX;
template <>
GLenum GLTypeToGLenum<GLfloat>::value = GL_FLOAT;
template <typename QueryT>
void CastStateValues(Context *context, GLenum nativeType, GLenum pname,
unsigned int numParams, QueryT *outParams)

View File

@ -23,7 +23,33 @@ class Context;
template <typename GLType>
struct GLTypeToGLenum
{
static GLenum value;
// static constexpr GLenum value;
};
template <>
struct GLTypeToGLenum<GLint>
{
static constexpr GLenum value = GL_INT;
};
template <>
struct GLTypeToGLenum<GLuint>
{
static constexpr GLenum value = GL_UNSIGNED_INT;
};
template <>
struct GLTypeToGLenum<GLboolean>
{
static constexpr GLenum value = GL_BOOL;
};
template <>
struct GLTypeToGLenum<GLint64>
{
static constexpr GLenum value = GL_INT_64_ANGLEX;
};
template <>
struct GLTypeToGLenum<GLfloat>
{
static constexpr GLenum value = GL_FLOAT;
};
// The GL state query API types are: bool, int, uint, float, int64

View File

@ -23,8 +23,8 @@ class BufferImpl : angle::NonCopyable
public:
virtual ~BufferImpl() { }
virtual gl::Error setData(const void *data, size_t size, GLenum usage) = 0;
virtual gl::Error setSubData(const void *data, size_t size, size_t offset) = 0;
virtual gl::Error setData(GLenum target, const void *data, size_t size, GLenum usage) = 0;
virtual gl::Error setSubData(GLenum target, const void *data, size_t size, size_t offset) = 0;
virtual gl::Error copySubData(BufferImpl *source,
GLintptr sourceOffset,
GLintptr destOffset,

View File

@ -21,8 +21,8 @@ class MockBufferImpl : public BufferImpl
public:
~MockBufferImpl() { destructor(); }
MOCK_METHOD3(setData, gl::Error(const void*, size_t, GLenum));
MOCK_METHOD3(setSubData, gl::Error(const void*, size_t, size_t));
MOCK_METHOD4(setData, gl::Error(GLenum, const void *, size_t, GLenum));
MOCK_METHOD4(setSubData, gl::Error(GLenum, const void *, size_t, size_t));
MOCK_METHOD4(copySubData, gl::Error(BufferImpl *, GLintptr, GLintptr, GLsizeiptr));
MOCK_METHOD2(map, gl::Error(GLenum, GLvoid **));
MOCK_METHOD4(mapRange, gl::Error(size_t, size_t, GLbitfield, GLvoid **));

View File

@ -22,8 +22,8 @@ class ShaderImpl : angle::NonCopyable
virtual ~ShaderImpl() { }
// Returns additional ShCompile options.
virtual int prepareSourceAndReturnOptions(std::stringstream *sourceStream,
std::string *sourcePath) = 0;
virtual ShCompileOptions prepareSourceAndReturnOptions(std::stringstream *sourceStream,
std::string *sourcePath) = 0;
// Returns success for compiling on the driver. Returns success.
virtual bool postTranslateCompile(gl::Compiler *compiler, std::string *infoLog) = 0;

View File

@ -136,7 +136,8 @@ gl::Error HLSLCompiler::initialize()
if (!mD3DCompilerModule)
{
return gl::Error(GL_INVALID_OPERATION, "No D3D compiler module found - aborting!\n");
ERR("D3D compiler module not found.");
return gl::Error(GL_OUT_OF_MEMORY, "D3D compiler module not found.");
}
mD3DCompileFunc = reinterpret_cast<pD3DCompile>(GetProcAddress(mD3DCompilerModule, "D3DCompile"));
@ -155,7 +156,7 @@ gl::Error HLSLCompiler::initialize()
if (mD3DCompileFunc == nullptr)
{
return gl::Error(GL_INVALID_OPERATION, "Error finding D3DCompile entry point");
return gl::Error(GL_OUT_OF_MEMORY, "Error finding D3DCompile entry point.");
}
mInitialized = true;

Some files were not shown because too many files have changed in this diff Show More