mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-21 09:15:35 +00:00
Bug 1303443 - Update ANGLE to chromium/2862. r=jgilbert
--HG-- extra : rebase_source : 9a1502c96f375c730bbee88248685eea0e4c184e
This commit is contained in:
parent
42404707d2
commit
1539628815
@ -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",
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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',
|
||||
|
@ -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"
|
||||
|
@ -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',
|
||||
|
@ -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
|
@ -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_
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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";
|
||||
|
@ -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
|
@ -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_
|
@ -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"
|
||||
|
@ -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.
|
||||
|
@ -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))
|
||||
{
|
||||
|
@ -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;
|
||||
|
443
gfx/angle/src/compiler/translator/ConstantUnion.cpp
Normal file
443
gfx/angle/src/compiler/translator/ConstantUnion.cpp
Normal 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;
|
||||
}
|
@ -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;
|
||||
};
|
||||
|
@ -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.
|
||||
|
@ -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")
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
@ -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 ¶meter, FloatTypeUnaryFunc builtinFunc, TInfoSink &infoSink, TConstantUnion *result) const;
|
||||
void foldFloatTypeUnary(const TConstantUnion ¶meter,
|
||||
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(); }
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
//
|
||||
|
@ -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;
|
||||
|
@ -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_
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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
@ -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(
|
||||
|
636
gfx/angle/src/compiler/translator/QualifierTypes.cpp
Normal file
636
gfx/angle/src/compiler/translator/QualifierTypes.cpp
Normal 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 ¤tQualifier =
|
||||
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);
|
||||
}
|
170
gfx/angle/src/compiler/translator/QualifierTypes.h
Normal file
170
gfx/angle/src/compiler/translator/QualifierTypes.h
Normal 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_
|
@ -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.
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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_
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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())
|
||||
{
|
||||
|
@ -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 =
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
@ -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_
|
@ -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);
|
||||
}
|
||||
}
|
@ -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_
|
@ -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";
|
||||
}
|
||||
}
|
@ -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_
|
@ -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);
|
||||
}
|
@ -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
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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";
|
||||
}
|
@ -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_
|
@ -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");
|
||||
}
|
||||
}
|
@ -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_
|
@ -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
|
||||
|
@ -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_
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -68,6 +68,7 @@ class ImageIndexIterator
|
||||
const Range<GLint> &layerRange, const GLsizei *layerCounts);
|
||||
|
||||
GLint maxLayer() const;
|
||||
void done();
|
||||
|
||||
GLenum mType;
|
||||
Range<GLint> mMipRange;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 |
|
||||
|
@ -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',
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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 **));
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user