mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-21 17:25:36 +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")
|
sources = rebase_path(util_gypi.util_sources, ".", "util")
|
||||||
|
|
||||||
if (is_win) {
|
if (is_win) {
|
||||||
@ -514,6 +514,10 @@ static_library("angle_util") {
|
|||||||
|
|
||||||
if (is_mac) {
|
if (is_mac) {
|
||||||
sources += rebase_path(util_gypi.util_osx_sources, ".", "util")
|
sources += rebase_path(util_gypi.util_osx_sources, ".", "util")
|
||||||
|
libs = [
|
||||||
|
"AppKit.framework",
|
||||||
|
"QuartzCore.framework",
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
if (use_x11) {
|
if (use_x11) {
|
||||||
@ -538,6 +542,7 @@ static_library("angle_util") {
|
|||||||
defines = [
|
defines = [
|
||||||
"GL_GLEXT_PROTOTYPES",
|
"GL_GLEXT_PROTOTYPES",
|
||||||
"EGL_EGLEXT_PROTOTYPES",
|
"EGL_EGLEXT_PROTOTYPES",
|
||||||
|
"LIBANGLE_UTIL_IMPLEMENTATION",
|
||||||
]
|
]
|
||||||
|
|
||||||
configs += [
|
configs += [
|
||||||
@ -549,6 +554,13 @@ static_library("angle_util") {
|
|||||||
":angle_util_config",
|
":angle_util_config",
|
||||||
":internal_config",
|
":internal_config",
|
||||||
]
|
]
|
||||||
|
if (is_mac && !is_component_build) {
|
||||||
|
ldflags = [
|
||||||
|
"-install_name",
|
||||||
|
"@rpath/lib${target_name}.dylib",
|
||||||
|
]
|
||||||
|
public_configs += [ ":shared_library_public_config" ]
|
||||||
|
}
|
||||||
|
|
||||||
deps = [
|
deps = [
|
||||||
":angle_common",
|
":angle_common",
|
||||||
|
@ -49,7 +49,7 @@ typedef unsigned int GLenum;
|
|||||||
|
|
||||||
// Version number for shader translation API.
|
// Version number for shader translation API.
|
||||||
// It is incremented every time the API changes.
|
// It is incremented every time the API changes.
|
||||||
#define ANGLE_SH_VERSION 155
|
#define ANGLE_SH_VERSION 161
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SH_GLES2_SPEC,
|
SH_GLES2_SPEC,
|
||||||
@ -61,27 +61,6 @@ typedef enum {
|
|||||||
SH_GLES3_1_SPEC,
|
SH_GLES3_1_SPEC,
|
||||||
SH_WEBGL3_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;
|
} ShShaderSpec;
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
@ -116,122 +95,109 @@ typedef enum
|
|||||||
} ShShaderOutput;
|
} ShShaderOutput;
|
||||||
|
|
||||||
// Compile options.
|
// Compile options.
|
||||||
typedef enum {
|
typedef uint64_t ShCompileOptions;
|
||||||
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,
|
|
||||||
|
|
||||||
// This is needed only as a workaround for certain OpenGL driver bugs.
|
const ShCompileOptions SH_VALIDATE = 0;
|
||||||
SH_EMULATE_BUILT_IN_FUNCTIONS = 0x0100,
|
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
|
// This flag works around bug in Intel Mac drivers related to abs(i) where
|
||||||
// timing attacks.
|
// i is an integer.
|
||||||
// It generates compilation errors for shaders that could expose sensitive
|
const ShCompileOptions SH_EMULATE_ABS_INT_FUNCTION = UINT64_C(1) << 8;
|
||||||
// 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 prints the dependency graph that is used to enforce timing
|
// Enforce the GLSL 1.017 Appendix A section 7 packing restrictions.
|
||||||
// restrictions on fragment shaders.
|
// This flag only enforces (and can only enforce) the packing
|
||||||
// This flag only has an effect if all of the following are true:
|
// restrictions for uniform variables in both vertex and fragment
|
||||||
// - The shader spec is SH_WEBGL_SPEC.
|
// shaders. ShCheckVariablesWithinPackingLimits() lets embedders
|
||||||
// - The compile options contain the SH_TIMING_RESTRICTIONS flag.
|
// enforce the packing restrictions for varying variables during
|
||||||
// - The shader type is GL_FRAGMENT_SHADER.
|
// program link time.
|
||||||
SH_DEPENDENCY_GRAPH = 0x0400,
|
const ShCompileOptions SH_ENFORCE_PACKING_RESTRICTIONS = UINT64_C(1) << 9;
|
||||||
|
|
||||||
// Enforce the GLSL 1.017 Appendix A section 7 packing restrictions.
|
// This flag ensures all indirect (expression-based) array indexing
|
||||||
// This flag only enforces (and can only enforce) the packing
|
// is clamped to the bounds of the array. This ensures, for example,
|
||||||
// restrictions for uniform variables in both vertex and fragment
|
// that you cannot read off the end of a uniform, whether an array
|
||||||
// shaders. ShCheckVariablesWithinPackingLimits() lets embedders
|
// vec234, or mat234 type. The ShArrayIndexClampingStrategy enum,
|
||||||
// enforce the packing restrictions for varying variables during
|
// specified in the ShBuiltInResources when constructing the
|
||||||
// program link time.
|
// compiler, selects the strategy for the clamping implementation.
|
||||||
SH_ENFORCE_PACKING_RESTRICTIONS = 0x0800,
|
const ShCompileOptions SH_CLAMP_INDIRECT_ARRAY_BOUNDS = UINT64_C(1) << 10;
|
||||||
|
|
||||||
// This flag ensures all indirect (expression-based) array indexing
|
// This flag limits the complexity of an expression.
|
||||||
// is clamped to the bounds of the array. This ensures, for example,
|
const ShCompileOptions SH_LIMIT_EXPRESSION_COMPLEXITY = UINT64_C(1) << 11;
|
||||||
// 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.
|
// This flag limits the depth of the call stack.
|
||||||
SH_LIMIT_EXPRESSION_COMPLEXITY = 0x2000,
|
const ShCompileOptions SH_LIMIT_CALL_STACK_DEPTH = UINT64_C(1) << 12;
|
||||||
|
|
||||||
// This flag limits the depth of the call stack.
|
// This flag initializes gl_Position to vec4(0,0,0,0) at the
|
||||||
SH_LIMIT_CALL_STACK_DEPTH = 0x4000,
|
// 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
|
// This flag replaces
|
||||||
// beginning of the vertex shader's main(), and has no effect in the
|
// "a && b" with "a ? b : false",
|
||||||
// fragment shader. It is intended as a workaround for drivers which
|
// "a || b" with "a ? true : b".
|
||||||
// incorrectly fail to link programs if gl_Position is not written.
|
// This is to work around a MacOSX driver bug that |b| is executed
|
||||||
SH_INIT_GL_POSITION = 0x8000,
|
// independent of |a|'s value.
|
||||||
|
const ShCompileOptions SH_UNFOLD_SHORT_CIRCUIT = UINT64_C(1) << 14;
|
||||||
|
|
||||||
// This flag replaces
|
// This flag initializes output variables to 0 at the beginning of main().
|
||||||
// "a && b" with "a ? b : false",
|
// It is to avoid undefined behaviors.
|
||||||
// "a || b" with "a ? true : b".
|
const ShCompileOptions SH_INIT_OUTPUT_VARIABLES = UINT64_C(1) << 15;
|
||||||
// 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().
|
// This flag scalarizes vec/ivec/bvec/mat constructor args.
|
||||||
// It is to avoid undefined behaviors.
|
// It is intended as a workaround for Linux/Mac driver bugs.
|
||||||
SH_INIT_OUTPUT_VARIABLES = 0x20000,
|
const ShCompileOptions SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS = UINT64_C(1) << 16;
|
||||||
// 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.
|
// This flag overwrites a struct name with a unique prefix.
|
||||||
// It is intended as a workaround for Linux/Mac driver bugs.
|
// It is intended as a workaround for drivers that do not handle
|
||||||
SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS = 0x40000,
|
// 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.
|
// This flag makes the compiler not prune unused function early in the
|
||||||
// It is intended as a workaround for drivers that do not handle
|
// compilation process. Pruning coupled with SH_LIMIT_CALL_STACK_DEPTH
|
||||||
// struct scopes correctly, including all Mac drivers and Linux AMD.
|
// helps avoid bad shaders causing stack overflows.
|
||||||
SH_REGENERATE_STRUCT_NAMES = 0x80000,
|
const ShCompileOptions SH_DONT_PRUNE_UNUSED_FUNCTIONS = UINT64_C(1) << 18;
|
||||||
|
|
||||||
// This flag makes the compiler not prune unused function early in the
|
// This flag works around a bug in NVIDIA 331 series drivers related
|
||||||
// compilation process. Pruning coupled with SH_LIMIT_CALL_STACK_DEPTH
|
// to pow(x, y) where y is a constant vector.
|
||||||
// helps avoid bad shaders causing stack overflows.
|
const ShCompileOptions SH_REMOVE_POW_WITH_CONSTANT_EXPONENT = UINT64_C(1) << 19;
|
||||||
SH_DONT_PRUNE_UNUSED_FUNCTIONS = 0x100000,
|
|
||||||
|
|
||||||
// This flag works around a bug in NVIDIA 331 series drivers related
|
// This flag works around bugs in Mac drivers related to do-while by
|
||||||
// to pow(x, y) where y is a constant vector.
|
// transforming them into an other construct.
|
||||||
SH_REMOVE_POW_WITH_CONSTANT_EXPONENT = 0x200000,
|
const ShCompileOptions SH_REWRITE_DO_WHILE_LOOPS = UINT64_C(1) << 20;
|
||||||
|
|
||||||
// This flag works around bugs in Mac drivers related to do-while by
|
// This flag works around a bug in the HLSL compiler optimizer that folds certain
|
||||||
// transforming them into an other construct.
|
// constant pow expressions incorrectly. Only applies to the HLSL back-end. It works
|
||||||
SH_REWRITE_DO_WHILE_LOOPS = 0x400000,
|
// 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
|
// Flatten "#pragma STDGL invariant(all)" into the declarations of
|
||||||
// constant pow expressions incorrectly. Only applies to the HLSL back-end. It works
|
// varying variables and built-in GLSL variables. This compiler
|
||||||
// by expanding the integer pow expressions into a series of multiplies.
|
// option is enabled automatically when needed.
|
||||||
SH_EXPAND_SELECT_HLSL_INTEGER_POW_EXPRESSIONS = 0x800000,
|
const ShCompileOptions SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL = UINT64_C(1) << 22;
|
||||||
|
|
||||||
// Flatten "#pragma STDGL invariant(all)" into the declarations of
|
// Some drivers do not take into account the base level of the texture in the results of the
|
||||||
// varying variables and built-in GLSL variables. This compiler
|
// HLSL GetDimensions builtin. This flag instructs the compiler to manually add the base level
|
||||||
// option is enabled automatically when needed.
|
// offsetting.
|
||||||
SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL = 0x1000000,
|
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
|
// This flag works around an issue in translating GLSL function texelFetchOffset on
|
||||||
// HLSL GetDimensions builtin. This flag instructs the compiler to manually add the base level
|
// INTEL drivers. It works by translating texelFetchOffset into texelFetch.
|
||||||
// offsetting.
|
const ShCompileOptions SH_REWRITE_TEXELFETCHOFFSET_TO_TEXELFETCH = UINT64_C(1) << 24;
|
||||||
SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL = 0x2000000,
|
|
||||||
|
|
||||||
// This flag works around an issue in translating GLSL function texelFetchOffset on
|
// This flag works around condition bug of for and while loops in Intel Mac OSX drivers.
|
||||||
// INTEL drivers. It works by translating texelFetchOffset into texelFetch.
|
// Condition calculation is not correct. Rewrite it from "CONDITION" to "CONDITION && true".
|
||||||
SH_REWRITE_TEXELFETCHOFFSET_TO_TEXELFETCH = 0x4000000,
|
const ShCompileOptions SH_ADD_AND_TRUE_TO_LOOP_CONDITION = UINT64_C(1) << 25;
|
||||||
} ShCompileOptions;
|
|
||||||
|
|
||||||
// Defines alternate strategies for implementing array index clamping.
|
// Defines alternate strategies for implementing array index clamping.
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@ -465,11 +431,10 @@ COMPILER_EXPORT void ShDestruct(ShHandle handle);
|
|||||||
// SH_VARIABLES: Extracts attributes, uniforms, and varyings.
|
// SH_VARIABLES: Extracts attributes, uniforms, and varyings.
|
||||||
// Can be queried by calling ShGetVariableInfo().
|
// Can be queried by calling ShGetVariableInfo().
|
||||||
//
|
//
|
||||||
COMPILER_EXPORT bool ShCompile(
|
COMPILER_EXPORT bool ShCompile(const ShHandle handle,
|
||||||
const ShHandle handle,
|
const char *const shaderStrings[],
|
||||||
const char * const shaderStrings[],
|
size_t numStrings,
|
||||||
size_t numStrings,
|
ShCompileOptions compileOptions);
|
||||||
int compileOptions);
|
|
||||||
|
|
||||||
// Clears the results from the previous compilation.
|
// Clears the results from the previous compilation.
|
||||||
COMPILER_EXPORT void ShClearResults(const ShHandle handle);
|
COMPILER_EXPORT void ShClearResults(const ShHandle handle);
|
||||||
|
@ -10,13 +10,15 @@
|
|||||||
#define LIBGLESV2_EXPORT_H_
|
#define LIBGLESV2_EXPORT_H_
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#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)
|
# define ANGLE_EXPORT __declspec(dllexport)
|
||||||
# else
|
# else
|
||||||
# define ANGLE_EXPORT __declspec(dllimport)
|
# define ANGLE_EXPORT __declspec(dllimport)
|
||||||
# endif
|
# endif
|
||||||
#elif defined(__GNUC__)
|
#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")))
|
# define ANGLE_EXPORT __attribute__((visibility ("default")))
|
||||||
# else
|
# else
|
||||||
# define ANGLE_EXPORT
|
# define ANGLE_EXPORT
|
||||||
|
@ -28,11 +28,13 @@ UNIFIED_SOURCES += [
|
|||||||
'src/compiler/preprocessor/Preprocessor.cpp',
|
'src/compiler/preprocessor/Preprocessor.cpp',
|
||||||
'src/compiler/preprocessor/Token.cpp',
|
'src/compiler/preprocessor/Token.cpp',
|
||||||
'src/compiler/preprocessor/Tokenizer.cpp',
|
'src/compiler/preprocessor/Tokenizer.cpp',
|
||||||
|
'src/compiler/translator/AddAndTrueToLoopCondition.cpp',
|
||||||
'src/compiler/translator/AddDefaultReturnStatements.cpp',
|
'src/compiler/translator/AddDefaultReturnStatements.cpp',
|
||||||
'src/compiler/translator/ArrayReturnValueToOutParameter.cpp',
|
'src/compiler/translator/ArrayReturnValueToOutParameter.cpp',
|
||||||
'src/compiler/translator/ASTMetadataHLSL.cpp',
|
'src/compiler/translator/ASTMetadataHLSL.cpp',
|
||||||
'src/compiler/translator/blocklayout.cpp',
|
'src/compiler/translator/blocklayout.cpp',
|
||||||
'src/compiler/translator/blocklayoutHLSL.cpp',
|
'src/compiler/translator/blocklayoutHLSL.cpp',
|
||||||
|
'src/compiler/translator/BreakVariableAliasingInInnerLoops.cpp',
|
||||||
'src/compiler/translator/BuiltInFunctionEmulator.cpp',
|
'src/compiler/translator/BuiltInFunctionEmulator.cpp',
|
||||||
'src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp',
|
'src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp',
|
||||||
'src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp',
|
'src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp',
|
||||||
@ -40,11 +42,8 @@ UNIFIED_SOURCES += [
|
|||||||
'src/compiler/translator/CallDAG.cpp',
|
'src/compiler/translator/CallDAG.cpp',
|
||||||
'src/compiler/translator/CodeGen.cpp',
|
'src/compiler/translator/CodeGen.cpp',
|
||||||
'src/compiler/translator/Compiler.cpp',
|
'src/compiler/translator/Compiler.cpp',
|
||||||
|
'src/compiler/translator/ConstantUnion.cpp',
|
||||||
'src/compiler/translator/DeferGlobalInitializers.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/Diagnostics.cpp',
|
||||||
'src/compiler/translator/DirectiveHandler.cpp',
|
'src/compiler/translator/DirectiveHandler.cpp',
|
||||||
'src/compiler/translator/EmulatePrecision.cpp',
|
'src/compiler/translator/EmulatePrecision.cpp',
|
||||||
@ -71,6 +70,7 @@ UNIFIED_SOURCES += [
|
|||||||
'src/compiler/translator/ParseContext.cpp',
|
'src/compiler/translator/ParseContext.cpp',
|
||||||
'src/compiler/translator/PoolAlloc.cpp',
|
'src/compiler/translator/PoolAlloc.cpp',
|
||||||
'src/compiler/translator/PruneEmptyDeclarations.cpp',
|
'src/compiler/translator/PruneEmptyDeclarations.cpp',
|
||||||
|
'src/compiler/translator/QualifierTypes.cpp',
|
||||||
'src/compiler/translator/RecordConstantPrecision.cpp',
|
'src/compiler/translator/RecordConstantPrecision.cpp',
|
||||||
'src/compiler/translator/RegenerateStructNames.cpp',
|
'src/compiler/translator/RegenerateStructNames.cpp',
|
||||||
'src/compiler/translator/RemoveDynamicIndexing.cpp',
|
'src/compiler/translator/RemoveDynamicIndexing.cpp',
|
||||||
@ -91,8 +91,6 @@ UNIFIED_SOURCES += [
|
|||||||
'src/compiler/translator/StructureHLSL.cpp',
|
'src/compiler/translator/StructureHLSL.cpp',
|
||||||
'src/compiler/translator/SymbolTable.cpp',
|
'src/compiler/translator/SymbolTable.cpp',
|
||||||
'src/compiler/translator/TextureFunctionHLSL.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/TranslatorESSL.cpp',
|
||||||
'src/compiler/translator/TranslatorGLSL.cpp',
|
'src/compiler/translator/TranslatorGLSL.cpp',
|
||||||
'src/compiler/translator/TranslatorHLSL.cpp',
|
'src/compiler/translator/TranslatorHLSL.cpp',
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
#define ANGLE_COMMIT_HASH ""
|
#define ANGLE_COMMIT_HASH "8b3e8b4d1b09"
|
||||||
#define ANGLE_COMMIT_HASH_SIZE 12
|
#define ANGLE_COMMIT_HASH_SIZE 12
|
||||||
#define ANGLE_COMMIT_DATE ""
|
#define ANGLE_COMMIT_DATE "2016-10-24 15:38:47 +0800"
|
||||||
|
@ -22,9 +22,13 @@
|
|||||||
'../include/GLSLANG/ShaderVars.h',
|
'../include/GLSLANG/ShaderVars.h',
|
||||||
'../include/KHR/khrplatform.h',
|
'../include/KHR/khrplatform.h',
|
||||||
'../include/angle_gl.h',
|
'../include/angle_gl.h',
|
||||||
|
'compiler/translator/AddAndTrueToLoopCondition.cpp',
|
||||||
|
'compiler/translator/AddAndTrueToLoopCondition.h',
|
||||||
'compiler/translator/BaseTypes.h',
|
'compiler/translator/BaseTypes.h',
|
||||||
'compiler/translator/BuiltInFunctionEmulator.cpp',
|
'compiler/translator/BuiltInFunctionEmulator.cpp',
|
||||||
'compiler/translator/BuiltInFunctionEmulator.h',
|
'compiler/translator/BuiltInFunctionEmulator.h',
|
||||||
|
'compiler/translator/BreakVariableAliasingInInnerLoops.cpp',
|
||||||
|
'compiler/translator/BreakVariableAliasingInInnerLoops.h',
|
||||||
'compiler/translator/Cache.cpp',
|
'compiler/translator/Cache.cpp',
|
||||||
'compiler/translator/Cache.h',
|
'compiler/translator/Cache.h',
|
||||||
'compiler/translator/CallDAG.cpp',
|
'compiler/translator/CallDAG.cpp',
|
||||||
@ -33,6 +37,7 @@
|
|||||||
'compiler/translator/Common.h',
|
'compiler/translator/Common.h',
|
||||||
'compiler/translator/Compiler.cpp',
|
'compiler/translator/Compiler.cpp',
|
||||||
'compiler/translator/Compiler.h',
|
'compiler/translator/Compiler.h',
|
||||||
|
'compiler/translator/ConstantUnion.cpp',
|
||||||
'compiler/translator/ConstantUnion.h',
|
'compiler/translator/ConstantUnion.h',
|
||||||
'compiler/translator/DeferGlobalInitializers.cpp',
|
'compiler/translator/DeferGlobalInitializers.cpp',
|
||||||
'compiler/translator/DeferGlobalInitializers.h',
|
'compiler/translator/DeferGlobalInitializers.h',
|
||||||
@ -81,6 +86,8 @@
|
|||||||
'compiler/translator/Pragma.h',
|
'compiler/translator/Pragma.h',
|
||||||
'compiler/translator/PruneEmptyDeclarations.cpp',
|
'compiler/translator/PruneEmptyDeclarations.cpp',
|
||||||
'compiler/translator/PruneEmptyDeclarations.h',
|
'compiler/translator/PruneEmptyDeclarations.h',
|
||||||
|
'compiler/translator/QualifierTypes.h',
|
||||||
|
'compiler/translator/QualifierTypes.cpp',
|
||||||
'compiler/translator/RecordConstantPrecision.cpp',
|
'compiler/translator/RecordConstantPrecision.cpp',
|
||||||
'compiler/translator/RecordConstantPrecision.h',
|
'compiler/translator/RecordConstantPrecision.h',
|
||||||
'compiler/translator/RegenerateStructNames.cpp',
|
'compiler/translator/RegenerateStructNames.cpp',
|
||||||
@ -91,7 +98,6 @@
|
|||||||
'compiler/translator/RewriteDoWhile.h',
|
'compiler/translator/RewriteDoWhile.h',
|
||||||
'compiler/translator/RewriteTexelFetchOffset.cpp',
|
'compiler/translator/RewriteTexelFetchOffset.cpp',
|
||||||
'compiler/translator/RewriteTexelFetchOffset.h',
|
'compiler/translator/RewriteTexelFetchOffset.h',
|
||||||
'compiler/translator/RenameFunction.h',
|
|
||||||
'compiler/translator/ScalarizeVecAndMatConstructorArgs.cpp',
|
'compiler/translator/ScalarizeVecAndMatConstructorArgs.cpp',
|
||||||
'compiler/translator/ScalarizeVecAndMatConstructorArgs.h',
|
'compiler/translator/ScalarizeVecAndMatConstructorArgs.h',
|
||||||
'compiler/translator/SearchSymbol.cpp',
|
'compiler/translator/SearchSymbol.cpp',
|
||||||
@ -118,13 +124,6 @@
|
|||||||
'compiler/translator/VariablePacker.h',
|
'compiler/translator/VariablePacker.h',
|
||||||
'compiler/translator/blocklayout.cpp',
|
'compiler/translator/blocklayout.cpp',
|
||||||
'compiler/translator/blocklayout.h',
|
'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.h',
|
||||||
'compiler/translator/glslang.l',
|
'compiler/translator/glslang.l',
|
||||||
'compiler/translator/glslang.y',
|
'compiler/translator/glslang.y',
|
||||||
@ -133,10 +132,6 @@
|
|||||||
'compiler/translator/glslang_tab.h',
|
'compiler/translator/glslang_tab.h',
|
||||||
'compiler/translator/intermOut.cpp',
|
'compiler/translator/intermOut.cpp',
|
||||||
'compiler/translator/length_limits.h',
|
'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.cpp',
|
||||||
'compiler/translator/util.h',
|
'compiler/translator/util.h',
|
||||||
'third_party/compiler/ArrayBoundsClamper.cpp',
|
'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;
|
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
|
bool visitAggregate(Visit, TIntermAggregate *node) override
|
||||||
{
|
{
|
||||||
TType returnType;
|
TType returnType;
|
||||||
if (IsFunctionWithoutReturnStatement(node, &returnType))
|
if (IsFunctionWithoutReturnStatement(node, &returnType))
|
||||||
{
|
{
|
||||||
TIntermBranch *branch =
|
TIntermBranch *branch =
|
||||||
new TIntermBranch(EOpReturn, GenerateTypeConstructor(returnType));
|
new TIntermBranch(EOpReturn, TIntermTyped::CreateZero(returnType));
|
||||||
|
|
||||||
TIntermAggregate *lastNode = node->getSequence()->back()->getAsAggregate();
|
TIntermAggregate *lastNode = node->getSequence()->back()->getAsAggregate();
|
||||||
lastNode->getSequence()->push_back(branch);
|
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.
|
// Instead of returning a value, assign to the out parameter and then return.
|
||||||
TIntermSequence replacements;
|
TIntermSequence replacements;
|
||||||
|
|
||||||
TIntermBinary *replacementAssignment = new TIntermBinary(EOpAssign);
|
|
||||||
TIntermTyped *expression = node->getExpression();
|
TIntermTyped *expression = node->getExpression();
|
||||||
ASSERT(expression != nullptr);
|
ASSERT(expression != nullptr);
|
||||||
replacementAssignment->setLeft(CreateReturnValueSymbol(expression->getType()));
|
TIntermSymbol *returnValueSymbol = CreateReturnValueSymbol(expression->getType());
|
||||||
replacementAssignment->setRight(node->getExpression());
|
TIntermBinary *replacementAssignment =
|
||||||
replacementAssignment->setType(expression->getType());
|
new TIntermBinary(EOpAssign, returnValueSymbol, expression);
|
||||||
replacementAssignment->setLine(expression->getLine());
|
replacementAssignment->setLine(expression->getLine());
|
||||||
replacements.push_back(replacementAssignment);
|
replacements.push_back(replacementAssignment);
|
||||||
|
|
||||||
|
@ -341,10 +341,11 @@ enum TQualifier
|
|||||||
EvqLastFragData,
|
EvqLastFragData,
|
||||||
|
|
||||||
// GLSL ES 3.0 vertex output and fragment input
|
// GLSL ES 3.0 vertex output and fragment input
|
||||||
EvqSmooth, // Incomplete qualifier, smooth is the default
|
EvqSmooth, // Incomplete qualifier, smooth is the default
|
||||||
EvqFlat, // Incomplete qualifier
|
EvqFlat, // Incomplete qualifier
|
||||||
EvqSmoothOut = EvqSmooth,
|
EvqCentroid, // Incomplete qualifier
|
||||||
EvqFlatOut = EvqFlat,
|
EvqSmoothOut,
|
||||||
|
EvqFlatOut,
|
||||||
EvqCentroidOut, // Implies smooth
|
EvqCentroidOut, // Implies smooth
|
||||||
EvqSmoothIn,
|
EvqSmoothIn,
|
||||||
EvqFlatIn,
|
EvqFlatIn,
|
||||||
@ -363,6 +364,11 @@ enum TQualifier
|
|||||||
EvqLast
|
EvqLast
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline bool IsQualifierUnspecified(TQualifier qualifier)
|
||||||
|
{
|
||||||
|
return (qualifier == EvqTemporary || qualifier == EvqGlobal);
|
||||||
|
}
|
||||||
|
|
||||||
enum TLayoutMatrixPacking
|
enum TLayoutMatrixPacking
|
||||||
{
|
{
|
||||||
EmpUnspecified,
|
EmpUnspecified,
|
||||||
@ -381,6 +387,7 @@ enum TLayoutBlockStorage
|
|||||||
struct TLayoutQualifier
|
struct TLayoutQualifier
|
||||||
{
|
{
|
||||||
int location;
|
int location;
|
||||||
|
unsigned int locationsSpecified;
|
||||||
TLayoutMatrixPacking matrixPacking;
|
TLayoutMatrixPacking matrixPacking;
|
||||||
TLayoutBlockStorage blockStorage;
|
TLayoutBlockStorage blockStorage;
|
||||||
|
|
||||||
@ -392,6 +399,7 @@ struct TLayoutQualifier
|
|||||||
TLayoutQualifier layoutQualifier;
|
TLayoutQualifier layoutQualifier;
|
||||||
|
|
||||||
layoutQualifier.location = -1;
|
layoutQualifier.location = -1;
|
||||||
|
layoutQualifier.locationsSpecified = 0;
|
||||||
layoutQualifier.matrixPacking = EmpUnspecified;
|
layoutQualifier.matrixPacking = EmpUnspecified;
|
||||||
layoutQualifier.blockStorage = EbsUnspecified;
|
layoutQualifier.blockStorage = EbsUnspecified;
|
||||||
|
|
||||||
@ -482,6 +490,9 @@ inline const char* getQualifierString(TQualifier q)
|
|||||||
case EvqSmoothIn: return "smooth in";
|
case EvqSmoothIn: return "smooth in";
|
||||||
case EvqFlatIn: return "flat in";
|
case EvqFlatIn: return "flat in";
|
||||||
case EvqCentroidIn: return "smooth centroid in";
|
case EvqCentroidIn: return "smooth centroid in";
|
||||||
|
case EvqCentroid: return "centroid";
|
||||||
|
case EvqFlat: return "flat";
|
||||||
|
case EvqSmooth: return "smooth";
|
||||||
case EvqComputeIn: return "in";
|
case EvqComputeIn: return "in";
|
||||||
case EvqNumWorkGroups: return "NumWorkGroups";
|
case EvqNumWorkGroups: return "NumWorkGroups";
|
||||||
case EvqWorkGroupSize: return "WorkGroupSize";
|
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/SymbolTable.h"
|
||||||
#include "compiler/translator/VersionGLSL.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
|
if (shaderType == GL_VERTEX_SHADER)
|
||||||
// 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)
|
|
||||||
{
|
{
|
||||||
emu->addEmulatedFunction(EOpCos, float1, "webgl_emu_precision float webgl_cos_emu(webgl_emu_precision float a) { return cos(a); }");
|
const TType *int1 = TCache::getType(EbtInt);
|
||||||
emu->addEmulatedFunction(EOpCos, float2, "webgl_emu_precision vec2 webgl_cos_emu(webgl_emu_precision vec2 a) { return cos(a); }");
|
emu->addEmulatedFunction(EOpAbs, int1, "int webgl_abs_emu(int x) { return x * sign(x); }");
|
||||||
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); }");
|
|
||||||
}
|
}
|
||||||
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
|
// Emulate built-in functions missing from GLSL 1.30 and higher
|
||||||
@ -181,7 +163,9 @@ void InitBuiltInFunctionEmulatorForGLSLMissingFunctions(BuiltInFunctionEmulator
|
|||||||
" float scale;\n"
|
" float scale;\n"
|
||||||
" if(exponent < 0)\n"
|
" if(exponent < 0)\n"
|
||||||
" {\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"
|
" }\n"
|
||||||
" else\n"
|
" else\n"
|
||||||
" {\n"
|
" {\n"
|
||||||
|
@ -12,9 +12,10 @@
|
|||||||
class BuiltInFunctionEmulator;
|
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.
|
// This function is emulating built-in functions missing from GLSL 1.30 and higher.
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include "compiler/translator/AddAndTrueToLoopCondition.h"
|
||||||
#include "compiler/translator/Cache.h"
|
#include "compiler/translator/Cache.h"
|
||||||
#include "compiler/translator/Compiler.h"
|
#include "compiler/translator/Compiler.h"
|
||||||
#include "compiler/translator/CallDAG.h"
|
#include "compiler/translator/CallDAG.h"
|
||||||
@ -17,7 +18,6 @@
|
|||||||
#include "compiler/translator/PruneEmptyDeclarations.h"
|
#include "compiler/translator/PruneEmptyDeclarations.h"
|
||||||
#include "compiler/translator/RegenerateStructNames.h"
|
#include "compiler/translator/RegenerateStructNames.h"
|
||||||
#include "compiler/translator/RemovePow.h"
|
#include "compiler/translator/RemovePow.h"
|
||||||
#include "compiler/translator/RenameFunction.h"
|
|
||||||
#include "compiler/translator/RewriteDoWhile.h"
|
#include "compiler/translator/RewriteDoWhile.h"
|
||||||
#include "compiler/translator/ScalarizeVecAndMatConstructorArgs.h"
|
#include "compiler/translator/ScalarizeVecAndMatConstructorArgs.h"
|
||||||
#include "compiler/translator/UnfoldShortCircuitAST.h"
|
#include "compiler/translator/UnfoldShortCircuitAST.h"
|
||||||
@ -25,18 +25,13 @@
|
|||||||
#include "compiler/translator/ValidateMaxParameters.h"
|
#include "compiler/translator/ValidateMaxParameters.h"
|
||||||
#include "compiler/translator/ValidateOutputs.h"
|
#include "compiler/translator/ValidateOutputs.h"
|
||||||
#include "compiler/translator/VariablePacker.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 "third_party/compiler/ArrayBoundsClamper.h"
|
||||||
#include "angle_gl.h"
|
#include "angle_gl.h"
|
||||||
#include "common/utilities.h"
|
#include "common/utilities.h"
|
||||||
|
|
||||||
bool IsWebGLBasedSpec(ShShaderSpec spec)
|
bool IsWebGLBasedSpec(ShShaderSpec spec)
|
||||||
{
|
{
|
||||||
return (spec == SH_WEBGL_SPEC || spec == SH_CSS_SHADERS_SPEC || spec == SH_WEBGL2_SPEC ||
|
return (spec == SH_WEBGL_SPEC || spec == SH_WEBGL2_SPEC || spec == SH_WEBGL3_SPEC);
|
||||||
spec == SH_WEBGL3_SPEC);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsGLSL130OrNewer(ShShaderOutput output)
|
bool IsGLSL130OrNewer(ShShaderOutput output)
|
||||||
@ -60,7 +55,6 @@ size_t GetGlobalMaxTokenSize(ShShaderSpec spec)
|
|||||||
switch (spec)
|
switch (spec)
|
||||||
{
|
{
|
||||||
case SH_WEBGL_SPEC:
|
case SH_WEBGL_SPEC:
|
||||||
case SH_CSS_SHADERS_SPEC:
|
|
||||||
return 256;
|
return 256;
|
||||||
default:
|
default:
|
||||||
return 1024;
|
return 1024;
|
||||||
@ -111,7 +105,6 @@ int MapSpecToShaderVersion(ShShaderSpec spec)
|
|||||||
{
|
{
|
||||||
case SH_GLES2_SPEC:
|
case SH_GLES2_SPEC:
|
||||||
case SH_WEBGL_SPEC:
|
case SH_WEBGL_SPEC:
|
||||||
case SH_CSS_SHADERS_SPEC:
|
|
||||||
return 100;
|
return 100;
|
||||||
case SH_GLES3_SPEC:
|
case SH_GLES3_SPEC:
|
||||||
case SH_WEBGL2_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,
|
// 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
|
// 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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
TIntermNode *TCompiler::compileTreeForTesting(const char* const shaderStrings[],
|
TIntermNode *TCompiler::compileTreeForTesting(const char *const shaderStrings[],
|
||||||
size_t numStrings, int compileOptions)
|
size_t numStrings,
|
||||||
|
ShCompileOptions compileOptions)
|
||||||
{
|
{
|
||||||
return compileTreeImpl(shaderStrings, numStrings, compileOptions);
|
return compileTreeImpl(shaderStrings, numStrings, compileOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
TIntermNode *TCompiler::compileTreeImpl(const char *const shaderStrings[],
|
TIntermNode *TCompiler::compileTreeImpl(const char *const shaderStrings[],
|
||||||
size_t numStrings,
|
size_t numStrings,
|
||||||
const int compileOptions)
|
const ShCompileOptions compileOptions)
|
||||||
{
|
{
|
||||||
clearResults();
|
clearResults();
|
||||||
|
|
||||||
@ -223,8 +217,7 @@ TIntermNode *TCompiler::compileTreeImpl(const char *const shaderStrings[],
|
|||||||
++firstSource;
|
++firstSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
TIntermediate intermediate(infoSink);
|
TParseContext parseContext(symbolTable, extensionBehavior, shaderType, shaderSpec,
|
||||||
TParseContext parseContext(symbolTable, extensionBehavior, intermediate, shaderType, shaderSpec,
|
|
||||||
compileOptions, true, infoSink, getResources());
|
compileOptions, true, infoSink, getResources());
|
||||||
|
|
||||||
parseContext.setFragmentPrecisionHighOnESSL1(fragmentPrecisionHigh);
|
parseContext.setFragmentPrecisionHighOnESSL1(fragmentPrecisionHigh);
|
||||||
@ -258,7 +251,7 @@ TIntermNode *TCompiler::compileTreeImpl(const char *const shaderStrings[],
|
|||||||
mComputeShaderLocalSize = parseContext.getComputeShaderLocalSize();
|
mComputeShaderLocalSize = parseContext.getComputeShaderLocalSize();
|
||||||
|
|
||||||
root = parseContext.getTreeRoot();
|
root = parseContext.getTreeRoot();
|
||||||
root = intermediate.postProcess(root);
|
root = TIntermediate::PostProcess(root);
|
||||||
|
|
||||||
// Highp might have been auto-enabled based on shader version
|
// Highp might have been auto-enabled based on shader version
|
||||||
fragmentPrecisionHigh = parseContext.getFragmentPrecisionHigh();
|
fragmentPrecisionHigh = parseContext.getFragmentPrecisionHigh();
|
||||||
@ -295,12 +288,6 @@ TIntermNode *TCompiler::compileTreeImpl(const char *const shaderStrings[],
|
|||||||
if (success && shouldRunLoopAndIndexingValidation(compileOptions))
|
if (success && shouldRunLoopAndIndexingValidation(compileOptions))
|
||||||
success = validateLimitations(root);
|
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.
|
// Unroll for-loop markup needs to happen after validateLimitations pass.
|
||||||
if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX))
|
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))
|
if (success && (compileOptions & SH_REWRITE_DO_WHILE_LOOPS))
|
||||||
RewriteDoWhile(root, getTemporaryIndex());
|
RewriteDoWhile(root, getTemporaryIndex());
|
||||||
|
|
||||||
|
if (success && (compileOptions & SH_ADD_AND_TRUE_TO_LOOP_CONDITION))
|
||||||
|
sh::AddAndTrueToLoopCondition(root);
|
||||||
|
|
||||||
if (success && (compileOptions & SH_UNFOLD_SHORT_CIRCUIT))
|
if (success && (compileOptions & SH_UNFOLD_SHORT_CIRCUIT))
|
||||||
{
|
{
|
||||||
UnfoldShortCircuitAST unfoldShortCircuit;
|
UnfoldShortCircuitAST unfoldShortCircuit;
|
||||||
@ -408,12 +398,14 @@ TIntermNode *TCompiler::compileTreeImpl(const char *const shaderStrings[],
|
|||||||
return NULL;
|
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)
|
if (numStrings == 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
int compileOptions = compileOptionsIn;
|
ShCompileOptions compileOptions = compileOptionsIn;
|
||||||
|
|
||||||
// Apply key workarounds.
|
// Apply key workarounds.
|
||||||
if (shouldFlattenPragmaStdglInvariantAll())
|
if (shouldFlattenPragmaStdglInvariantAll())
|
||||||
@ -452,15 +444,13 @@ bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources)
|
|||||||
symbolTable.push(); // ESSL3_1_BUILTINS
|
symbolTable.push(); // ESSL3_1_BUILTINS
|
||||||
|
|
||||||
TPublicType integer;
|
TPublicType integer;
|
||||||
integer.type = EbtInt;
|
integer.setBasicType(EbtInt);
|
||||||
integer.primarySize = 1;
|
integer.initializeSizeForScalarTypes();
|
||||||
integer.secondarySize = 1;
|
|
||||||
integer.array = false;
|
integer.array = false;
|
||||||
|
|
||||||
TPublicType floatingPoint;
|
TPublicType floatingPoint;
|
||||||
floatingPoint.type = EbtFloat;
|
floatingPoint.setBasicType(EbtFloat);
|
||||||
floatingPoint.primarySize = 1;
|
floatingPoint.initializeSizeForScalarTypes();
|
||||||
floatingPoint.secondarySize = 1;
|
|
||||||
floatingPoint.array = false;
|
floatingPoint.array = false;
|
||||||
|
|
||||||
switch(shaderType)
|
switch(shaderType)
|
||||||
@ -500,10 +490,9 @@ void TCompiler::initSamplerDefaultPrecision(TBasicType samplerType)
|
|||||||
{
|
{
|
||||||
ASSERT(samplerType > EbtGuardSamplerBegin && samplerType < EbtGuardSamplerEnd);
|
ASSERT(samplerType > EbtGuardSamplerBegin && samplerType < EbtGuardSamplerEnd);
|
||||||
TPublicType sampler;
|
TPublicType sampler;
|
||||||
sampler.primarySize = 1;
|
sampler.initializeSizeForScalarTypes();
|
||||||
sampler.secondarySize = 1;
|
sampler.setBasicType(samplerType);
|
||||||
sampler.array = false;
|
sampler.array = false;
|
||||||
sampler.type = samplerType;
|
|
||||||
symbolTable.setDefaultPrecision(sampler, EbpLow);
|
symbolTable.setDefaultPrecision(sampler, EbpLow);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -763,12 +752,6 @@ bool TCompiler::validateOutputs(TIntermNode* root)
|
|||||||
return (validateOutputs.validateAndCountErrors(infoSink.info) == 0);
|
return (validateOutputs.validateAndCountErrors(infoSink.info) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TCompiler::rewriteCSSShader(TIntermNode* root)
|
|
||||||
{
|
|
||||||
RenameFunction renamer("main(", "css_main(");
|
|
||||||
root->traverse(&renamer);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TCompiler::validateLimitations(TIntermNode* root)
|
bool TCompiler::validateLimitations(TIntermNode* root)
|
||||||
{
|
{
|
||||||
ValidateLimitations validate(shaderType, &infoSink.info);
|
ValidateLimitations validate(shaderType, &infoSink.info);
|
||||||
@ -776,36 +759,6 @@ bool TCompiler::validateLimitations(TIntermNode* root)
|
|||||||
return validate.numErrors() == 0;
|
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)
|
bool TCompiler::limitExpressionComplexity(TIntermNode* root)
|
||||||
{
|
{
|
||||||
TMaxDepthTraverser traverser(maxExpressionComplexity+1);
|
TMaxDepthTraverser traverser(maxExpressionComplexity+1);
|
||||||
@ -826,20 +779,6 @@ bool TCompiler::limitExpressionComplexity(TIntermNode* root)
|
|||||||
return true;
|
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)
|
void TCompiler::collectVariables(TIntermNode* root)
|
||||||
{
|
{
|
||||||
if (!variablesCollected)
|
if (!variablesCollected)
|
||||||
@ -920,7 +859,7 @@ const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const
|
|||||||
return builtInFunctionEmulator;
|
return builtInFunctionEmulator;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TCompiler::writePragma(int compileOptions)
|
void TCompiler::writePragma(ShCompileOptions compileOptions)
|
||||||
{
|
{
|
||||||
if (!(compileOptions & SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL))
|
if (!(compileOptions & SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL))
|
||||||
{
|
{
|
||||||
|
@ -25,14 +25,12 @@
|
|||||||
#include "third_party/compiler/ArrayBoundsClamper.h"
|
#include "third_party/compiler/ArrayBoundsClamper.h"
|
||||||
|
|
||||||
class TCompiler;
|
class TCompiler;
|
||||||
class TDependencyGraph;
|
|
||||||
#ifdef ANGLE_ENABLE_HLSL
|
#ifdef ANGLE_ENABLE_HLSL
|
||||||
class TranslatorHLSL;
|
class TranslatorHLSL;
|
||||||
#endif // ANGLE_ENABLE_HLSL
|
#endif // ANGLE_ENABLE_HLSL
|
||||||
|
|
||||||
//
|
//
|
||||||
// Helper function to identify specs that are based on the WebGL spec,
|
// Helper function to identify specs that are based on the WebGL spec.
|
||||||
// like the CSS Shaders spec.
|
|
||||||
//
|
//
|
||||||
bool IsWebGLBasedSpec(ShShaderSpec spec);
|
bool IsWebGLBasedSpec(ShShaderSpec spec);
|
||||||
|
|
||||||
@ -75,11 +73,13 @@ class TCompiler : public TShHandleBase
|
|||||||
// compileTreeForTesting should be used only when tests require access to
|
// compileTreeForTesting should be used only when tests require access to
|
||||||
// the AST. Users of this function need to manually manage the global pool
|
// the AST. Users of this function need to manually manage the global pool
|
||||||
// allocator. Returns NULL whenever there are compilation errors.
|
// allocator. Returns NULL whenever there are compilation errors.
|
||||||
TIntermNode *compileTreeForTesting(const char* const shaderStrings[],
|
TIntermNode *compileTreeForTesting(const char *const shaderStrings[],
|
||||||
size_t numStrings, int compileOptions);
|
size_t numStrings,
|
||||||
|
ShCompileOptions compileOptions);
|
||||||
|
|
||||||
bool compile(const char* const shaderStrings[],
|
bool compile(const char *const shaderStrings[],
|
||||||
size_t numStrings, int compileOptions);
|
size_t numStrings,
|
||||||
|
ShCompileOptions compileOptions);
|
||||||
|
|
||||||
// Get results of the last compilation.
|
// Get results of the last compilation.
|
||||||
int getShaderVersion() const { return shaderVersion; }
|
int getShaderVersion() const { return shaderVersion; }
|
||||||
@ -104,7 +104,7 @@ class TCompiler : public TShHandleBase
|
|||||||
ShShaderOutput getOutputType() const { return outputType; }
|
ShShaderOutput getOutputType() const { return outputType; }
|
||||||
const std::string &getBuiltInResourcesString() const { return builtInResourcesString; }
|
const std::string &getBuiltInResourcesString() const { return builtInResourcesString; }
|
||||||
|
|
||||||
bool shouldRunLoopAndIndexingValidation(int compileOptions) const;
|
bool shouldRunLoopAndIndexingValidation(ShCompileOptions compileOptions) const;
|
||||||
|
|
||||||
// Get the resources set by InitBuiltInSymbolTable
|
// Get the resources set by InitBuiltInSymbolTable
|
||||||
const ShBuiltInResources& getResources() const;
|
const ShBuiltInResources& getResources() const;
|
||||||
@ -119,17 +119,16 @@ class TCompiler : public TShHandleBase
|
|||||||
bool checkCallDepth();
|
bool checkCallDepth();
|
||||||
// Returns true if a program has no conflicting or missing fragment outputs
|
// Returns true if a program has no conflicting or missing fragment outputs
|
||||||
bool validateOutputs(TIntermNode* root);
|
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
|
// Returns true if the given shader does not exceed the minimum
|
||||||
// functionality mandated in GLSL 1.0 spec Appendix A.
|
// functionality mandated in GLSL 1.0 spec Appendix A.
|
||||||
bool validateLimitations(TIntermNode* root);
|
bool validateLimitations(TIntermNode* root);
|
||||||
// Collect info for all attribs, uniforms, varyings.
|
// Collect info for all attribs, uniforms, varyings.
|
||||||
void collectVariables(TIntermNode* root);
|
void collectVariables(TIntermNode* root);
|
||||||
// Add emulated functions to the built-in function emulator.
|
// 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.
|
// 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
|
// 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.
|
// Appendix A, section 7, the shader does not use too many uniforms.
|
||||||
bool enforcePackingRestrictions();
|
bool enforcePackingRestrictions();
|
||||||
@ -141,20 +140,13 @@ class TCompiler : public TShHandleBase
|
|||||||
// while spec says it is allowed.
|
// while spec says it is allowed.
|
||||||
// This function should only be applied to vertex shaders.
|
// This function should only be applied to vertex shaders.
|
||||||
void initializeGLPosition(TIntermNode* root);
|
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.
|
// Return true if the maximum expression complexity is below the limit.
|
||||||
bool limitExpressionComplexity(TIntermNode* root);
|
bool limitExpressionComplexity(TIntermNode* root);
|
||||||
// Get built-in extensions with default behavior.
|
// Get built-in extensions with default behavior.
|
||||||
const TExtensionBehavior& getExtensionBehavior() const;
|
const TExtensionBehavior& getExtensionBehavior() const;
|
||||||
const char *getSourcePath() const;
|
const char *getSourcePath() const;
|
||||||
const TPragma& getPragma() const { return mPragma; }
|
const TPragma& getPragma() const { return mPragma; }
|
||||||
void writePragma(int compileOptions);
|
void writePragma(ShCompileOptions compileOptions);
|
||||||
unsigned int *getTemporaryIndex() { return &mTemporaryIndex; }
|
unsigned int *getTemporaryIndex() { return &mTemporaryIndex; }
|
||||||
// Relies on collectVariables having been called.
|
// Relies on collectVariables having been called.
|
||||||
bool isVaryingDefined(const char *varyingName);
|
bool isVaryingDefined(const char *varyingName);
|
||||||
@ -163,7 +155,7 @@ class TCompiler : public TShHandleBase
|
|||||||
ShArrayIndexClampingStrategy getArrayIndexClampingStrategy() const;
|
ShArrayIndexClampingStrategy getArrayIndexClampingStrategy() const;
|
||||||
const BuiltInFunctionEmulator& getBuiltInFunctionEmulator() const;
|
const BuiltInFunctionEmulator& getBuiltInFunctionEmulator() const;
|
||||||
|
|
||||||
virtual bool shouldCollectVariables(int compileOptions)
|
virtual bool shouldCollectVariables(ShCompileOptions compileOptions)
|
||||||
{
|
{
|
||||||
return (compileOptions & SH_VARIABLES) != 0;
|
return (compileOptions & SH_VARIABLES) != 0;
|
||||||
}
|
}
|
||||||
@ -193,7 +185,7 @@ class TCompiler : public TShHandleBase
|
|||||||
|
|
||||||
TIntermNode *compileTreeImpl(const char *const shaderStrings[],
|
TIntermNode *compileTreeImpl(const char *const shaderStrings[],
|
||||||
size_t numStrings,
|
size_t numStrings,
|
||||||
const int compileOptions);
|
const ShCompileOptions compileOptions);
|
||||||
|
|
||||||
sh::GLenum shaderType;
|
sh::GLenum shaderType;
|
||||||
ShShaderSpec shaderSpec;
|
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 <assert.h>
|
||||||
|
|
||||||
|
#include "compiler/translator/Common.h"
|
||||||
#include "compiler/translator/BaseTypes.h"
|
#include "compiler/translator/BaseTypes.h"
|
||||||
|
|
||||||
class TConstantUnion {
|
class TDiagnostics;
|
||||||
public:
|
|
||||||
|
class TConstantUnion
|
||||||
|
{
|
||||||
|
public:
|
||||||
POOL_ALLOCATOR_NEW_DELETE();
|
POOL_ALLOCATOR_NEW_DELETE();
|
||||||
TConstantUnion()
|
TConstantUnion();
|
||||||
{
|
|
||||||
iConst = 0;
|
|
||||||
type = EbtVoid;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cast(TBasicType newType, const TConstantUnion &constant)
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setIConst(int i) {iConst = i; type = EbtInt; }
|
void setIConst(int i) {iConst = i; type = EbtInt; }
|
||||||
void setUConst(unsigned int u) { uConst = u; type = EbtUInt; }
|
void setUConst(unsigned int u) { uConst = u; type = EbtUInt; }
|
||||||
@ -91,256 +32,44 @@ public:
|
|||||||
float getFConst() const { return fConst; }
|
float getFConst() const { return fConst; }
|
||||||
bool getBConst() const { return bConst; }
|
bool getBConst() const { return bConst; }
|
||||||
|
|
||||||
bool operator==(const int i) const
|
bool operator==(const int i) const;
|
||||||
{
|
bool operator==(const unsigned int u) const;
|
||||||
return i == iConst;
|
bool operator==(const float f) const;
|
||||||
}
|
bool operator==(const bool b) const;
|
||||||
|
bool operator==(const TConstantUnion &constant) const;
|
||||||
bool operator==(const unsigned int u) const
|
bool operator!=(const int i) const;
|
||||||
{
|
bool operator!=(const unsigned int u) const;
|
||||||
return u == uConst;
|
bool operator!=(const float f) const;
|
||||||
}
|
bool operator!=(const bool b) const;
|
||||||
|
bool operator!=(const TConstantUnion &constant) const;
|
||||||
bool operator==(const float f) const
|
bool operator>(const TConstantUnion &constant) const;
|
||||||
{
|
bool operator<(const TConstantUnion &constant) const;
|
||||||
return f == fConst;
|
static TConstantUnion add(const TConstantUnion &lhs,
|
||||||
}
|
const TConstantUnion &rhs,
|
||||||
|
TDiagnostics *diag);
|
||||||
bool operator==(const bool b) const
|
static TConstantUnion sub(const TConstantUnion &lhs,
|
||||||
{
|
const TConstantUnion &rhs,
|
||||||
return b == bConst;
|
TDiagnostics *diag);
|
||||||
}
|
static TConstantUnion mul(const TConstantUnion &lhs,
|
||||||
|
const TConstantUnion &rhs,
|
||||||
bool operator==(const TConstantUnion& constant) const
|
TDiagnostics *diag);
|
||||||
{
|
TConstantUnion operator%(const TConstantUnion &constant) const;
|
||||||
if (constant.type != type)
|
TConstantUnion operator>>(const TConstantUnion &constant) const;
|
||||||
return false;
|
TConstantUnion operator<<(const TConstantUnion &constant) const;
|
||||||
|
TConstantUnion operator&(const TConstantUnion &constant) const;
|
||||||
switch (type) {
|
TConstantUnion operator|(const TConstantUnion &constant) const;
|
||||||
case EbtInt:
|
TConstantUnion operator^(const TConstantUnion &constant) const;
|
||||||
return constant.iConst == iConst;
|
TConstantUnion operator&&(const TConstantUnion &constant) const;
|
||||||
case EbtUInt:
|
TConstantUnion operator||(const TConstantUnion &constant) const;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
TBasicType getType() const { return type; }
|
TBasicType getType() const { return type; }
|
||||||
private:
|
private:
|
||||||
|
union {
|
||||||
union {
|
int iConst; // used for ivec, scalar ints
|
||||||
int iConst; // used for ivec, scalar ints
|
unsigned int uConst; // used for uvec, scalar uints
|
||||||
unsigned int uConst; // used for uvec, scalar uints
|
bool bConst; // used for bvec, scalar bools
|
||||||
bool bConst; // used for bvec, scalar bools
|
float fConst; // used for vec, mat, scalar floats
|
||||||
float fConst; // used for vec, mat, scalar floats
|
};
|
||||||
} ;
|
|
||||||
|
|
||||||
TBasicType type;
|
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,
|
// 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
|
// since otherwise there's a chance that HLSL output will generate extra statements
|
||||||
// from the initializer expression.
|
// from the initializer expression.
|
||||||
TIntermBinary *deferredInit = new TIntermBinary(EOpAssign);
|
TIntermBinary *deferredInit =
|
||||||
deferredInit->setLeft(symbolNode->deepCopy());
|
new TIntermBinary(EOpAssign, symbolNode->deepCopy(), node->getRight());
|
||||||
deferredInit->setRight(node->getRight());
|
|
||||||
deferredInit->setType(node->getType());
|
|
||||||
mDeferredInitializers.push_back(deferredInit);
|
mDeferredInitializers.push_back(deferredInit);
|
||||||
|
|
||||||
// Change const global to a regular global if its initialization is deferred.
|
// Change const global to a regular global if its initialization is deferred.
|
||||||
|
@ -17,44 +17,18 @@
|
|||||||
namespace
|
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
|
class GLFragColorBroadcastTraverser : public TIntermTraverser
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GLFragColorBroadcastTraverser()
|
GLFragColorBroadcastTraverser(int maxDrawBuffers)
|
||||||
: TIntermTraverser(true, false, false), mMainSequence(nullptr), mGLFragColorUsed(false)
|
: TIntermTraverser(true, false, false),
|
||||||
|
mMainSequence(nullptr),
|
||||||
|
mGLFragColorUsed(false),
|
||||||
|
mMaxDrawBuffers(maxDrawBuffers)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void broadcastGLFragColor(int maxDrawBuffers);
|
void broadcastGLFragColor();
|
||||||
|
|
||||||
bool isGLFragColorUsed() const { return mGLFragColorUsed; }
|
bool isGLFragColorUsed() const { return mGLFragColorUsed; }
|
||||||
|
|
||||||
@ -62,11 +36,35 @@ class GLFragColorBroadcastTraverser : public TIntermTraverser
|
|||||||
void visitSymbol(TIntermSymbol *node) override;
|
void visitSymbol(TIntermSymbol *node) override;
|
||||||
bool visitAggregate(Visit visit, TIntermAggregate *node) override;
|
bool visitAggregate(Visit visit, TIntermAggregate *node) override;
|
||||||
|
|
||||||
|
TIntermBinary *constructGLFragDataNode(int index) const;
|
||||||
|
TIntermBinary *constructGLFragDataAssignNode(int index) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TIntermSequence *mMainSequence;
|
TIntermSequence *mMainSequence;
|
||||||
bool mGLFragColorUsed;
|
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)
|
void GLFragColorBroadcastTraverser::visitSymbol(TIntermSymbol *node)
|
||||||
{
|
{
|
||||||
if (node->getSymbol() == "gl_FragColor")
|
if (node->getSymbol() == "gl_FragColor")
|
||||||
@ -101,9 +99,9 @@ bool GLFragColorBroadcastTraverser::visitAggregate(Visit visit, TIntermAggregate
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLFragColorBroadcastTraverser::broadcastGLFragColor(int maxDrawBuffers)
|
void GLFragColorBroadcastTraverser::broadcastGLFragColor()
|
||||||
{
|
{
|
||||||
ASSERT(maxDrawBuffers > 1);
|
ASSERT(mMaxDrawBuffers > 1);
|
||||||
if (!mGLFragColorUsed)
|
if (!mGLFragColorUsed)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@ -113,7 +111,7 @@ void GLFragColorBroadcastTraverser::broadcastGLFragColor(int maxDrawBuffers)
|
|||||||
// gl_FragData[1] = gl_FragData[0];
|
// gl_FragData[1] = gl_FragData[0];
|
||||||
// ...
|
// ...
|
||||||
// gl_FragData[maxDrawBuffers - 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));
|
mMainSequence->insert(mMainSequence->end(), constructGLFragDataAssignNode(colorIndex));
|
||||||
}
|
}
|
||||||
@ -126,12 +124,12 @@ void EmulateGLFragColorBroadcast(TIntermNode *root,
|
|||||||
std::vector<sh::OutputVariable> *outputVariables)
|
std::vector<sh::OutputVariable> *outputVariables)
|
||||||
{
|
{
|
||||||
ASSERT(maxDrawBuffers > 1);
|
ASSERT(maxDrawBuffers > 1);
|
||||||
GLFragColorBroadcastTraverser traverser;
|
GLFragColorBroadcastTraverser traverser(maxDrawBuffers);
|
||||||
root->traverse(&traverser);
|
root->traverse(&traverser);
|
||||||
if (traverser.isGLFragColorUsed())
|
if (traverser.isGLFragColorUsed())
|
||||||
{
|
{
|
||||||
traverser.updateTree();
|
traverser.updateTree();
|
||||||
traverser.broadcastGLFragColor(maxDrawBuffers);
|
traverser.broadcastGLFragColor();
|
||||||
for (auto &var : *outputVariables)
|
for (auto &var : *outputVariables)
|
||||||
{
|
{
|
||||||
if (var.name == "gl_FragColor")
|
if (var.name == "gl_FragColor")
|
||||||
|
@ -124,10 +124,7 @@ bool Traverser::visitAggregate(Visit visit, TIntermAggregate *node)
|
|||||||
// Create a chain of n-1 multiples.
|
// Create a chain of n-1 multiples.
|
||||||
for (int i = 1; i < n; ++i)
|
for (int i = 1; i < n; ++i)
|
||||||
{
|
{
|
||||||
TIntermBinary *mul = new TIntermBinary(EOpMul);
|
TIntermBinary *mul = new TIntermBinary(EOpMul, current, createTempSymbol(lhs->getType()));
|
||||||
mul->setLeft(current);
|
|
||||||
mul->setRight(createTempSymbol(lhs->getType()));
|
|
||||||
mul->setType(node->getType());
|
|
||||||
mul->setLine(node->getLine());
|
mul->setLine(node->getLine());
|
||||||
current = mul;
|
current = mul;
|
||||||
}
|
}
|
||||||
@ -138,9 +135,7 @@ bool Traverser::visitAggregate(Visit visit, TIntermAggregate *node)
|
|||||||
TConstantUnion *oneVal = new TConstantUnion();
|
TConstantUnion *oneVal = new TConstantUnion();
|
||||||
oneVal->setFConst(1.0f);
|
oneVal->setFConst(1.0f);
|
||||||
TIntermConstantUnion *oneNode = new TIntermConstantUnion(oneVal, node->getType());
|
TIntermConstantUnion *oneNode = new TIntermConstantUnion(oneVal, node->getType());
|
||||||
TIntermBinary *div = new TIntermBinary(EOpDiv);
|
TIntermBinary *div = new TIntermBinary(EOpDiv, oneNode, current);
|
||||||
div->setLeft(oneNode);
|
|
||||||
div->setRight(current);
|
|
||||||
current = div;
|
current = div;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -511,16 +511,13 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR
|
|||||||
symbolTable.insertConstInt(ESSL1_BUILTINS, "gl_MaxVaryingVectors", resources.MaxVaryingVectors,
|
symbolTable.insertConstInt(ESSL1_BUILTINS, "gl_MaxVaryingVectors", resources.MaxVaryingVectors,
|
||||||
EbpMedium);
|
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,
|
symbolTable.insertConstIntExt(COMMON_BUILTINS, "GL_EXT_blend_func_extended",
|
||||||
EbpMedium);
|
"gl_MaxDualSourceDrawBuffersEXT",
|
||||||
if (resources.EXT_blend_func_extended)
|
resources.MaxDualSourceDrawBuffers);
|
||||||
{
|
|
||||||
symbolTable.insertConstIntExt(COMMON_BUILTINS, "GL_EXT_blend_func_extended",
|
|
||||||
"gl_MaxDualSourceDrawBuffersEXT",
|
|
||||||
resources.MaxDualSourceDrawBuffers);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
symbolTable.insertConstInt(ESSL3_BUILTINS, "gl_MaxVertexOutputVectors",
|
symbolTable.insertConstInt(ESSL3_BUILTINS, "gl_MaxVertexOutputVectors",
|
||||||
@ -590,85 +587,73 @@ void IdentifyBuiltIns(sh::GLenum type, ShShaderSpec spec,
|
|||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case GL_FRAGMENT_SHADER:
|
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_FragCoord"),
|
||||||
symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_FrontFacing"),
|
TType(EbtFloat, EbpMedium, EvqFragCoord, 4)));
|
||||||
TType(EbtBool, EbpUndefined, EvqFrontFacing, 1)));
|
symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_FrontFacing"),
|
||||||
symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_PointCoord"),
|
TType(EbtBool, EbpUndefined, EvqFrontFacing, 1)));
|
||||||
TType(EbtFloat, EbpMedium, EvqPointCoord, 2)));
|
symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_PointCoord"),
|
||||||
|
TType(EbtFloat, EbpMedium, EvqPointCoord, 2)));
|
||||||
|
|
||||||
//
|
symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("gl_FragColor"),
|
||||||
// In CSS Shaders, gl_FragColor, gl_FragData, and gl_MaxDrawBuffers are not available.
|
TType(EbtFloat, EbpMedium, EvqFragColor, 4)));
|
||||||
// Instead, css_MixColor and css_ColorMatrix are available.
|
TType fragData(EbtFloat, EbpMedium, EvqFragData, 4, 1, true);
|
||||||
//
|
fragData.setArraySize(resources.MaxDrawBuffers);
|
||||||
if (spec != SH_CSS_SHADERS_SPEC)
|
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)
|
if (resources.EXT_blend_func_extended)
|
||||||
{
|
{
|
||||||
symbolTable.insert(
|
symbolTable.insert(
|
||||||
ESSL1_BUILTINS, "GL_EXT_blend_func_extended",
|
ESSL1_BUILTINS, "GL_EXT_blend_func_extended",
|
||||||
new TVariable(NewPoolTString("gl_SecondaryFragColorEXT"),
|
new TVariable(NewPoolTString("gl_SecondaryFragColorEXT"),
|
||||||
TType(EbtFloat, EbpMedium, EvqSecondaryFragColorEXT, 4)));
|
TType(EbtFloat, EbpMedium, EvqSecondaryFragColorEXT, 4)));
|
||||||
TType secondaryFragData(EbtFloat, EbpMedium, EvqSecondaryFragDataEXT, 4, 1, true);
|
TType secondaryFragData(EbtFloat, EbpMedium, EvqSecondaryFragDataEXT, 4, 1, true);
|
||||||
secondaryFragData.setArraySize(resources.MaxDualSourceDrawBuffers);
|
secondaryFragData.setArraySize(resources.MaxDualSourceDrawBuffers);
|
||||||
symbolTable.insert(
|
symbolTable.insert(
|
||||||
ESSL1_BUILTINS, "GL_EXT_blend_func_extended",
|
ESSL1_BUILTINS, "GL_EXT_blend_func_extended",
|
||||||
new TVariable(NewPoolTString("gl_SecondaryFragDataEXT"), secondaryFragData));
|
new TVariable(NewPoolTString("gl_SecondaryFragDataEXT"), secondaryFragData));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resources.EXT_frag_depth)
|
if (resources.EXT_frag_depth)
|
||||||
{
|
{
|
||||||
symbolTable.insert(
|
symbolTable.insert(
|
||||||
ESSL1_BUILTINS, "GL_EXT_frag_depth",
|
ESSL1_BUILTINS, "GL_EXT_frag_depth",
|
||||||
new TVariable(
|
new TVariable(
|
||||||
NewPoolTString("gl_FragDepthEXT"),
|
NewPoolTString("gl_FragDepthEXT"),
|
||||||
TType(EbtFloat, resources.FragmentPrecisionHigh ? EbpHigh : EbpMedium,
|
TType(EbtFloat, resources.FragmentPrecisionHigh ? EbpHigh : EbpMedium,
|
||||||
EvqFragDepthEXT, 1)));
|
EvqFragDepthEXT, 1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
symbolTable.insert(ESSL3_BUILTINS,
|
symbolTable.insert(ESSL3_BUILTINS,
|
||||||
new TVariable(NewPoolTString("gl_FragDepth"),
|
new TVariable(NewPoolTString("gl_FragDepth"),
|
||||||
TType(EbtFloat, EbpHigh, EvqFragDepth, 1)));
|
TType(EbtFloat, EbpHigh, EvqFragDepth, 1)));
|
||||||
|
|
||||||
if (resources.EXT_shader_framebuffer_fetch || resources.NV_shader_framebuffer_fetch)
|
if (resources.EXT_shader_framebuffer_fetch || resources.NV_shader_framebuffer_fetch)
|
||||||
{
|
{
|
||||||
TType lastFragData(EbtFloat, EbpMedium, EvqLastFragData, 4, 1, true);
|
TType lastFragData(EbtFloat, EbpMedium, EvqLastFragData, 4, 1, true);
|
||||||
lastFragData.setArraySize(resources.MaxDrawBuffers);
|
lastFragData.setArraySize(resources.MaxDrawBuffers);
|
||||||
|
|
||||||
if (resources.EXT_shader_framebuffer_fetch)
|
if (resources.EXT_shader_framebuffer_fetch)
|
||||||
{
|
{
|
||||||
symbolTable.insert(ESSL1_BUILTINS, "GL_EXT_shader_framebuffer_fetch",
|
symbolTable.insert(ESSL1_BUILTINS, "GL_EXT_shader_framebuffer_fetch",
|
||||||
new TVariable(NewPoolTString("gl_LastFragData"), lastFragData));
|
new TVariable(NewPoolTString("gl_LastFragData"), lastFragData));
|
||||||
}
|
}
|
||||||
else if (resources.NV_shader_framebuffer_fetch)
|
else if (resources.NV_shader_framebuffer_fetch)
|
||||||
{
|
{
|
||||||
symbolTable.insert(ESSL1_BUILTINS, "GL_NV_shader_framebuffer_fetch",
|
symbolTable.insert(ESSL1_BUILTINS, "GL_NV_shader_framebuffer_fetch",
|
||||||
new TVariable(NewPoolTString("gl_LastFragColor"),
|
new TVariable(NewPoolTString("gl_LastFragColor"),
|
||||||
TType(EbtFloat, EbpMedium, EvqLastFragColor, 4)));
|
TType(EbtFloat, EbpMedium, EvqLastFragColor, 4)));
|
||||||
symbolTable.insert(ESSL1_BUILTINS, "GL_NV_shader_framebuffer_fetch",
|
symbolTable.insert(ESSL1_BUILTINS, "GL_NV_shader_framebuffer_fetch",
|
||||||
new TVariable(NewPoolTString("gl_LastFragData"), lastFragData));
|
new TVariable(NewPoolTString("gl_LastFragData"), lastFragData));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (resources.ARM_shader_framebuffer_fetch)
|
else if (resources.ARM_shader_framebuffer_fetch)
|
||||||
{
|
{
|
||||||
symbolTable.insert(ESSL1_BUILTINS, "GL_ARM_shader_framebuffer_fetch",
|
symbolTable.insert(ESSL1_BUILTINS, "GL_ARM_shader_framebuffer_fetch",
|
||||||
new TVariable(NewPoolTString("gl_LastFragColorARM"),
|
new TVariable(NewPoolTString("gl_LastFragColorARM"),
|
||||||
TType(EbtFloat, EbpMedium, EvqLastFragColor, 4)));
|
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)));
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -14,46 +14,6 @@
|
|||||||
namespace
|
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
|
class VariableInitializer : public TIntermTraverser
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -120,73 +80,43 @@ bool VariableInitializer::visitAggregate(Visit visit, TIntermAggregate *node)
|
|||||||
|
|
||||||
void VariableInitializer::insertInitCode(TIntermSequence *sequence)
|
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());
|
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())
|
if (var.isArray())
|
||||||
{
|
{
|
||||||
TType type = sh::ConvertShaderVariableTypeToTType(var.type);
|
|
||||||
size_t pos = name.find_last_of('[');
|
size_t pos = name.find_last_of('[');
|
||||||
if (pos != TString::npos)
|
if (pos != TString::npos)
|
||||||
|
{
|
||||||
name = name.substr(0, pos);
|
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);
|
|
||||||
}
|
}
|
||||||
}
|
TType elementType = type;
|
||||||
else if (var.isStruct())
|
elementType.clearArrayness();
|
||||||
{
|
|
||||||
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);
|
|
||||||
|
|
||||||
TIntermBinary *indexDirectStruct = new TIntermBinary(EOpIndexDirectStruct);
|
for (unsigned int i = 0; i < var.arraySize; ++i)
|
||||||
TIntermSymbol *symbol = new TIntermSymbol(0, name, type);
|
{
|
||||||
indexDirectStruct->setLeft(symbol);
|
TIntermSymbol *arraySymbol = new TIntermSymbol(0, name, type);
|
||||||
TIntermConstantUnion *indexNode = constructIndexNode(fieldIndex);
|
TIntermBinary *element = new TIntermBinary(EOpIndexDirect, arraySymbol,
|
||||||
indexDirectStruct->setRight(indexNode);
|
TIntermTyped::CreateIndexNode(i));
|
||||||
assign->setLeft(indexDirectStruct);
|
|
||||||
|
|
||||||
const sh::ShaderVariable &field = var.fields[fieldIndex];
|
TIntermTyped *zero = TIntermTyped::CreateZero(elementType);
|
||||||
TType fieldType = sh::ConvertShaderVariableTypeToTType(field.type);
|
TIntermBinary *assignment = new TIntermBinary(EOpAssign, element, zero);
|
||||||
TIntermConstantUnion *zeroConst = constructConstUnionNode(fieldType);
|
|
||||||
assign->setRight(zeroConst);
|
sequence->insert(sequence->begin(), assignment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
TType type = sh::ConvertShaderVariableTypeToTType(var.type);
|
|
||||||
TIntermBinary *assign = new TIntermBinary(EOpAssign);
|
|
||||||
sequence->insert(sequence->begin(), assign);
|
|
||||||
TIntermSymbol *symbol = new TIntermSymbol(0, name, type);
|
TIntermSymbol *symbol = new TIntermSymbol(0, name, type);
|
||||||
assign->setLeft(symbol);
|
TIntermTyped *zero = TIntermTyped::CreateZero(type);
|
||||||
TIntermConstantUnion *zeroConst = constructConstUnionNode(type);
|
|
||||||
assign->setRight(zeroConst);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
TIntermBinary *assign = new TIntermBinary(EOpAssign, symbol, zero);
|
||||||
|
sequence->insert(sequence->begin(), assign);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ class TIntermNode;
|
|||||||
|
|
||||||
typedef std::vector<sh::ShaderVariable> InitVariableList;
|
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);
|
void InitializeVariables(TIntermNode *root, const InitVariableList &vars);
|
||||||
|
|
||||||
#endif // COMPILER_TRANSLATOR_INITIALIZEVARIABLES_H_
|
#endif // COMPILER_TRANSLATOR_INITIALIZEVARIABLES_H_
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -34,6 +34,7 @@ class TIntermAggregate;
|
|||||||
class TIntermBinary;
|
class TIntermBinary;
|
||||||
class TIntermUnary;
|
class TIntermUnary;
|
||||||
class TIntermConstantUnion;
|
class TIntermConstantUnion;
|
||||||
|
class TIntermTernary;
|
||||||
class TIntermSelection;
|
class TIntermSelection;
|
||||||
class TIntermSwitch;
|
class TIntermSwitch;
|
||||||
class TIntermCase;
|
class TIntermCase;
|
||||||
@ -93,6 +94,7 @@ class TIntermNode : angle::NonCopyable
|
|||||||
virtual TIntermAggregate *getAsAggregate() { return 0; }
|
virtual TIntermAggregate *getAsAggregate() { return 0; }
|
||||||
virtual TIntermBinary *getAsBinaryNode() { return 0; }
|
virtual TIntermBinary *getAsBinaryNode() { return 0; }
|
||||||
virtual TIntermUnary *getAsUnaryNode() { return 0; }
|
virtual TIntermUnary *getAsUnaryNode() { return 0; }
|
||||||
|
virtual TIntermTernary *getAsTernaryNode() { return nullptr; }
|
||||||
virtual TIntermSelection *getAsSelectionNode() { return 0; }
|
virtual TIntermSelection *getAsSelectionNode() { return 0; }
|
||||||
virtual TIntermSwitch *getAsSwitchNode() { return 0; }
|
virtual TIntermSwitch *getAsSwitchNode() { return 0; }
|
||||||
virtual TIntermCase *getAsCaseNode() { return 0; }
|
virtual TIntermCase *getAsCaseNode() { return 0; }
|
||||||
@ -159,6 +161,9 @@ class TIntermTyped : public TIntermNode
|
|||||||
|
|
||||||
bool isConstructorWithOnlyConstantUnionParameters();
|
bool isConstructorWithOnlyConstantUnionParameters();
|
||||||
|
|
||||||
|
static TIntermTyped *CreateIndexNode(int index);
|
||||||
|
static TIntermTyped *CreateZero(const TType &type);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
TType mType;
|
TType mType;
|
||||||
|
|
||||||
@ -316,6 +321,7 @@ class TIntermConstantUnion : public TIntermTyped
|
|||||||
TIntermConstantUnion(const TConstantUnion *unionPointer, const TType &type)
|
TIntermConstantUnion(const TConstantUnion *unionPointer, const TType &type)
|
||||||
: TIntermTyped(type), mUnionArrayPointer(unionPointer)
|
: TIntermTyped(type), mUnionArrayPointer(unionPointer)
|
||||||
{
|
{
|
||||||
|
ASSERT(unionPointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
TIntermTyped *deepCopy() const override { return new TIntermConstantUnion(*this); }
|
TIntermTyped *deepCopy() const override { return new TIntermConstantUnion(*this); }
|
||||||
@ -343,6 +349,7 @@ class TIntermConstantUnion : public TIntermTyped
|
|||||||
|
|
||||||
void replaceConstantUnion(const TConstantUnion *safeConstantUnion)
|
void replaceConstantUnion(const TConstantUnion *safeConstantUnion)
|
||||||
{
|
{
|
||||||
|
ASSERT(safeConstantUnion);
|
||||||
// Previous union pointer freed on pool deallocation.
|
// Previous union pointer freed on pool deallocation.
|
||||||
mUnionArrayPointer = safeConstantUnion;
|
mUnionArrayPointer = safeConstantUnion;
|
||||||
}
|
}
|
||||||
@ -354,12 +361,13 @@ class TIntermConstantUnion : public TIntermTyped
|
|||||||
TConstantUnion *foldBinary(TOperator op,
|
TConstantUnion *foldBinary(TOperator op,
|
||||||
TIntermConstantUnion *rightNode,
|
TIntermConstantUnion *rightNode,
|
||||||
TDiagnostics *diagnostics);
|
TDiagnostics *diagnostics);
|
||||||
TConstantUnion *foldUnaryWithDifferentReturnType(TOperator op, TInfoSink &infoSink);
|
const TConstantUnion *foldIndexing(int index);
|
||||||
TConstantUnion *foldUnaryWithSameReturnType(TOperator op, TInfoSink &infoSink);
|
TConstantUnion *foldUnaryNonComponentWise(TOperator op);
|
||||||
|
TConstantUnion *foldUnaryComponentWise(TOperator op, TDiagnostics *diagnostics);
|
||||||
|
|
||||||
static TConstantUnion *FoldAggregateConstructor(TIntermAggregate *aggregate,
|
static TConstantUnion *FoldAggregateConstructor(TIntermAggregate *aggregate);
|
||||||
TInfoSink &infoSink);
|
static TConstantUnion *FoldAggregateBuiltIn(TIntermAggregate *aggregate,
|
||||||
static TConstantUnion *FoldAggregateBuiltIn(TIntermAggregate *aggregate, TInfoSink &infoSink);
|
TDiagnostics *diagnostics);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Same data may be shared between multiple constant unions, so it can't be modified.
|
// Same data may be shared between multiple constant unions, so it can't be modified.
|
||||||
@ -367,7 +375,9 @@ class TIntermConstantUnion : public TIntermTyped
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
typedef float(*FloatTypeUnaryFunc) (float);
|
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!
|
TIntermConstantUnion(const TIntermConstantUnion &node); // Note: not deleted, just private!
|
||||||
};
|
};
|
||||||
@ -379,7 +389,6 @@ class TIntermOperator : public TIntermTyped
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TOperator getOp() const { return mOp; }
|
TOperator getOp() const { return mOp; }
|
||||||
void setOp(TOperator op) { mOp = op; }
|
|
||||||
|
|
||||||
bool isAssignment() const;
|
bool isAssignment() const;
|
||||||
bool isMultiplication() const;
|
bool isMultiplication() const;
|
||||||
@ -406,12 +415,7 @@ class TIntermOperator : public TIntermTyped
|
|||||||
class TIntermBinary : public TIntermOperator
|
class TIntermBinary : public TIntermOperator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TIntermBinary(TOperator op)
|
|
||||||
: TIntermOperator(op),
|
|
||||||
mAddIndexClamp(false) {}
|
|
||||||
|
|
||||||
// This constructor determines the type of the binary node based on the operands and op.
|
// 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);
|
TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right);
|
||||||
|
|
||||||
TIntermTyped *deepCopy() const override { return new TIntermBinary(*this); }
|
TIntermTyped *deepCopy() const override { return new TIntermBinary(*this); }
|
||||||
@ -428,8 +432,6 @@ class TIntermBinary : public TIntermOperator
|
|||||||
return isAssignment() || mLeft->hasSideEffects() || mRight->hasSideEffects();
|
return isAssignment() || mLeft->hasSideEffects() || mRight->hasSideEffects();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setLeft(TIntermTyped *node) { mLeft = node; }
|
|
||||||
void setRight(TIntermTyped *node) { mRight = node; }
|
|
||||||
TIntermTyped *getLeft() const { return mLeft; }
|
TIntermTyped *getLeft() const { return mLeft; }
|
||||||
TIntermTyped *getRight() const { return mRight; }
|
TIntermTyped *getRight() const { return mRight; }
|
||||||
TIntermTyped *fold(TDiagnostics *diagnostics);
|
TIntermTyped *fold(TDiagnostics *diagnostics);
|
||||||
@ -456,14 +458,7 @@ class TIntermBinary : public TIntermOperator
|
|||||||
class TIntermUnary : public TIntermOperator
|
class TIntermUnary : public TIntermOperator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TIntermUnary(TOperator op, const TType &type)
|
TIntermUnary(TOperator op, TIntermTyped *operand);
|
||||||
: TIntermOperator(op, type),
|
|
||||||
mOperand(NULL),
|
|
||||||
mUseEmulatedFunction(false) {}
|
|
||||||
TIntermUnary(TOperator op)
|
|
||||||
: TIntermOperator(op),
|
|
||||||
mOperand(NULL),
|
|
||||||
mUseEmulatedFunction(false) {}
|
|
||||||
|
|
||||||
TIntermTyped *deepCopy() const override { return new TIntermUnary(*this); }
|
TIntermTyped *deepCopy() const override { return new TIntermUnary(*this); }
|
||||||
|
|
||||||
@ -473,10 +468,8 @@ class TIntermUnary : public TIntermOperator
|
|||||||
|
|
||||||
bool hasSideEffects() const override { return isAssignment() || mOperand->hasSideEffects(); }
|
bool hasSideEffects() const override { return isAssignment() || mOperand->hasSideEffects(); }
|
||||||
|
|
||||||
void setOperand(TIntermTyped *operand) { mOperand = operand; }
|
|
||||||
TIntermTyped *getOperand() { return mOperand; }
|
TIntermTyped *getOperand() { return mOperand; }
|
||||||
void promote(const TType *funcReturnType);
|
TIntermTyped *fold(TDiagnostics *diagnostics);
|
||||||
TIntermTyped *fold(TInfoSink &infoSink);
|
|
||||||
|
|
||||||
void setUseEmulatedFunction() { mUseEmulatedFunction = true; }
|
void setUseEmulatedFunction() { mUseEmulatedFunction = true; }
|
||||||
bool getUseEmulatedFunction() { return mUseEmulatedFunction; }
|
bool getUseEmulatedFunction() { return mUseEmulatedFunction; }
|
||||||
@ -489,6 +482,8 @@ class TIntermUnary : public TIntermOperator
|
|||||||
bool mUseEmulatedFunction;
|
bool mUseEmulatedFunction;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void promote();
|
||||||
|
|
||||||
TIntermUnary(const TIntermUnary &node); // note: not deleted, just private!
|
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.
|
// Note: only supported for nodes that can be a part of an expression.
|
||||||
TIntermTyped *deepCopy() const override { return new TIntermAggregate(*this); }
|
TIntermTyped *deepCopy() const override { return new TIntermAggregate(*this); }
|
||||||
|
|
||||||
|
void setOp(TOperator op) { mOp = op; }
|
||||||
|
|
||||||
TIntermAggregate *getAsAggregate() override { return this; }
|
TIntermAggregate *getAsAggregate() override { return this; }
|
||||||
void traverse(TIntermTraverser *it) override;
|
void traverse(TIntermTraverser *it) override;
|
||||||
bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
|
bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
|
||||||
@ -529,9 +526,10 @@ class TIntermAggregate : public TIntermOperator
|
|||||||
bool insertChildNodes(TIntermSequence::size_type position, TIntermSequence insertions);
|
bool insertChildNodes(TIntermSequence::size_type position, TIntermSequence insertions);
|
||||||
// Conservatively assume function calls and other aggregate operators have side-effects
|
// Conservatively assume function calls and other aggregate operators have side-effects
|
||||||
bool hasSideEffects() const override { return true; }
|
bool hasSideEffects() const override { return true; }
|
||||||
TIntermTyped *fold(TInfoSink &infoSink);
|
TIntermTyped *fold(TDiagnostics *diagnostics);
|
||||||
|
|
||||||
TIntermSequence *getSequence() { return &mSequence; }
|
TIntermSequence *getSequence() { return &mSequence; }
|
||||||
|
const TIntermSequence *getSequence() const { return &mSequence; }
|
||||||
|
|
||||||
void setNameObj(const TName &name) { mName = name; }
|
void setNameObj(const TName &name) { mName = name; }
|
||||||
const TName &getNameObj() const { return mName; }
|
const TName &getNameObj() const { return mName; }
|
||||||
@ -571,35 +569,53 @@ class TIntermAggregate : public TIntermOperator
|
|||||||
TIntermAggregate(const TIntermAggregate &node); // note: not deleted, just private!
|
TIntermAggregate(const TIntermAggregate &node); // note: not deleted, just private!
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
// For ternary operators like a ? b : c.
|
||||||
// For if tests.
|
class TIntermTernary : public TIntermTyped
|
||||||
//
|
|
||||||
class TIntermSelection : public TIntermTyped
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TIntermSelection(TIntermTyped *cond, TIntermNode *trueB, TIntermNode *falseB)
|
TIntermTernary(TIntermTyped *cond, TIntermTyped *trueExpression, TIntermTyped *falseExpression);
|
||||||
: 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); }
|
|
||||||
|
|
||||||
void traverse(TIntermTraverser *it) override;
|
void traverse(TIntermTraverser *it) override;
|
||||||
bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
|
bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
|
||||||
|
|
||||||
// Conservatively assume selections have side-effects
|
TIntermTyped *getCondition() const { return mCondition; }
|
||||||
bool hasSideEffects() const override { return true; }
|
TIntermTyped *getTrueExpression() const { return mTrueExpression; }
|
||||||
|
TIntermTyped *getFalseExpression() const { return mFalseExpression; }
|
||||||
|
TIntermTernary *getAsTernaryNode() override { return this; }
|
||||||
|
|
||||||
bool usesTernaryOperator() const { return getBasicType() != EbtVoid; }
|
TIntermTyped *deepCopy() const override { return new TIntermTernary(*this); }
|
||||||
TIntermNode *getCondition() const { return mCondition; }
|
|
||||||
|
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 *getTrueBlock() const { return mTrueBlock; }
|
||||||
TIntermNode *getFalseBlock() const { return mFalseBlock; }
|
TIntermNode *getFalseBlock() const { return mFalseBlock; }
|
||||||
TIntermSelection *getAsSelectionNode() override { return this; }
|
TIntermSelection *getAsSelectionNode() override { return this; }
|
||||||
@ -608,9 +624,6 @@ class TIntermSelection : public TIntermTyped
|
|||||||
TIntermTyped *mCondition;
|
TIntermTyped *mCondition;
|
||||||
TIntermNode *mTrueBlock;
|
TIntermNode *mTrueBlock;
|
||||||
TIntermNode *mFalseBlock;
|
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 void visitConstantUnion(TIntermConstantUnion *node) {}
|
||||||
virtual bool visitBinary(Visit visit, TIntermBinary *node) { return true; }
|
virtual bool visitBinary(Visit visit, TIntermBinary *node) { return true; }
|
||||||
virtual bool visitUnary(Visit visit, TIntermUnary *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 visitSelection(Visit visit, TIntermSelection *node) { return true; }
|
||||||
virtual bool visitSwitch(Visit visit, TIntermSwitch *node) { return true; }
|
virtual bool visitSwitch(Visit visit, TIntermSwitch *node) { return true; }
|
||||||
virtual bool visitCase(Visit visit, TIntermCase *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 traverseConstantUnion(TIntermConstantUnion *node);
|
||||||
virtual void traverseBinary(TIntermBinary *node);
|
virtual void traverseBinary(TIntermBinary *node);
|
||||||
virtual void traverseUnary(TIntermUnary *node);
|
virtual void traverseUnary(TIntermUnary *node);
|
||||||
|
virtual void traverseTernary(TIntermTernary *node);
|
||||||
virtual void traverseSelection(TIntermSelection *node);
|
virtual void traverseSelection(TIntermSelection *node);
|
||||||
virtual void traverseSwitch(TIntermSwitch *node);
|
virtual void traverseSwitch(TIntermSwitch *node);
|
||||||
virtual void traverseCase(TIntermCase *node);
|
virtual void traverseCase(TIntermCase *node);
|
||||||
@ -998,6 +1013,7 @@ class TMaxDepthTraverser : public TIntermTraverser
|
|||||||
|
|
||||||
bool visitBinary(Visit, TIntermBinary *) override { return depthCheck(); }
|
bool visitBinary(Visit, TIntermBinary *) override { return depthCheck(); }
|
||||||
bool visitUnary(Visit, TIntermUnary *) 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 visitSelection(Visit, TIntermSelection *) override { return depthCheck(); }
|
||||||
bool visitAggregate(Visit, TIntermAggregate *) override { return depthCheck(); }
|
bool visitAggregate(Visit, TIntermAggregate *) override { return depthCheck(); }
|
||||||
bool visitLoop(Visit, TIntermLoop *) override { return depthCheck(); }
|
bool visitLoop(Visit, TIntermLoop *) override { return depthCheck(); }
|
||||||
|
@ -105,14 +105,11 @@ bool IntermNodePatternMatcher::match(TIntermAggregate *node, TIntermNode *parent
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IntermNodePatternMatcher::match(TIntermSelection *node)
|
bool IntermNodePatternMatcher::match(TIntermTernary *node)
|
||||||
{
|
{
|
||||||
if ((mMask & kUnfoldedShortCircuitExpression) != 0)
|
if ((mMask & kUnfoldedShortCircuitExpression) != 0)
|
||||||
{
|
{
|
||||||
if (node->usesTernaryOperator())
|
return true;
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
class TIntermAggregate;
|
class TIntermAggregate;
|
||||||
class TIntermBinary;
|
class TIntermBinary;
|
||||||
class TIntermNode;
|
class TIntermNode;
|
||||||
class TIntermSelection;
|
class TIntermTernary;
|
||||||
|
|
||||||
class IntermNodePatternMatcher
|
class IntermNodePatternMatcher
|
||||||
{
|
{
|
||||||
@ -42,7 +42,7 @@ class IntermNodePatternMatcher
|
|||||||
bool match(TIntermBinary *node, TIntermNode *parentNode, bool isLValueRequiredHere);
|
bool match(TIntermBinary *node, TIntermNode *parentNode, bool isLValueRequiredHere);
|
||||||
|
|
||||||
bool match(TIntermAggregate *node, TIntermNode *parentNode);
|
bool match(TIntermAggregate *node, TIntermNode *parentNode);
|
||||||
bool match(TIntermSelection *node);
|
bool match(TIntermTernary *node);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const unsigned int mMask;
|
const unsigned int mMask;
|
||||||
|
@ -33,6 +33,11 @@ void TIntermUnary::traverse(TIntermTraverser *it)
|
|||||||
it->traverseUnary(this);
|
it->traverseUnary(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TIntermTernary::traverse(TIntermTraverser *it)
|
||||||
|
{
|
||||||
|
it->traverseTernary(this);
|
||||||
|
}
|
||||||
|
|
||||||
void TIntermSelection::traverse(TIntermTraverser *it)
|
void TIntermSelection::traverse(TIntermTraverser *it)
|
||||||
{
|
{
|
||||||
it->traverseSelection(this);
|
it->traverseSelection(this);
|
||||||
@ -147,10 +152,7 @@ TIntermAggregate *TIntermTraverser::createTempInitDeclaration(TIntermTyped *init
|
|||||||
ASSERT(initializer != nullptr);
|
ASSERT(initializer != nullptr);
|
||||||
TIntermSymbol *tempSymbol = createTempSymbol(initializer->getType(), qualifier);
|
TIntermSymbol *tempSymbol = createTempSymbol(initializer->getType(), qualifier);
|
||||||
TIntermAggregate *tempDeclaration = new TIntermAggregate(EOpDeclaration);
|
TIntermAggregate *tempDeclaration = new TIntermAggregate(EOpDeclaration);
|
||||||
TIntermBinary *tempInit = new TIntermBinary(EOpInitialize);
|
TIntermBinary *tempInit = new TIntermBinary(EOpInitialize, tempSymbol, initializer);
|
||||||
tempInit->setLeft(tempSymbol);
|
|
||||||
tempInit->setRight(initializer);
|
|
||||||
tempInit->setType(tempSymbol->getType());
|
|
||||||
tempDeclaration->getSequence()->push_back(tempInit);
|
tempDeclaration->getSequence()->push_back(tempInit);
|
||||||
return tempDeclaration;
|
return tempDeclaration;
|
||||||
}
|
}
|
||||||
@ -164,10 +166,7 @@ TIntermBinary *TIntermTraverser::createTempAssignment(TIntermTyped *rightNode)
|
|||||||
{
|
{
|
||||||
ASSERT(rightNode != nullptr);
|
ASSERT(rightNode != nullptr);
|
||||||
TIntermSymbol *tempSymbol = createTempSymbol(rightNode->getType());
|
TIntermSymbol *tempSymbol = createTempSymbol(rightNode->getType());
|
||||||
TIntermBinary *assignment = new TIntermBinary(EOpAssign);
|
TIntermBinary *assignment = new TIntermBinary(EOpAssign, tempSymbol, rightNode);
|
||||||
assignment->setLeft(tempSymbol);
|
|
||||||
assignment->setRight(rightNode);
|
|
||||||
assignment->setType(tempSymbol->getType());
|
|
||||||
return assignment;
|
return assignment;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -572,6 +571,31 @@ void TLValueTrackingTraverser::traverseAggregate(TIntermAggregate *node)
|
|||||||
visitAggregate(PostVisit, 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.
|
// Traverse a selection node. Same comments in binary node apply here.
|
||||||
//
|
//
|
||||||
|
@ -44,38 +44,20 @@ TIntermSymbol *TIntermediate::addSymbol(
|
|||||||
// Returns the added node.
|
// Returns the added node.
|
||||||
// The caller should set the type of the returned node.
|
// The caller should set the type of the returned node.
|
||||||
//
|
//
|
||||||
TIntermTyped *TIntermediate::addIndex(
|
TIntermTyped *TIntermediate::addIndex(TOperator op,
|
||||||
TOperator op, TIntermTyped *base, TIntermTyped *index, const TSourceLoc &line)
|
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->setLine(line);
|
||||||
node->setLeft(base);
|
|
||||||
node->setRight(index);
|
|
||||||
|
|
||||||
// caller should set the type
|
TIntermTyped *folded = node->fold(diagnostics);
|
||||||
|
if (folded)
|
||||||
return node;
|
{
|
||||||
}
|
return folded;
|
||||||
|
}
|
||||||
//
|
|
||||||
// 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;
|
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
@ -254,43 +236,37 @@ TIntermTyped *TIntermediate::addComma(TIntermTyped *left,
|
|||||||
return commaNode;
|
return commaNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// For "?:" test nodes. There are three children; a condition,
|
// For "?:" test nodes. There are three children; a condition,
|
||||||
// a true path, and a false path. The two paths are specified
|
// a true path, and a false path. The two paths are specified
|
||||||
// as separate parameters.
|
// as separate parameters.
|
||||||
//
|
//
|
||||||
// Returns the selection node created, or one of trueBlock and falseBlock if the expression could be folded.
|
// Returns the ternary node created, or one of trueExpression and falseExpression if the expression
|
||||||
//
|
// could be folded.
|
||||||
TIntermTyped *TIntermediate::addSelection(TIntermTyped *cond, TIntermTyped *trueBlock, TIntermTyped *falseBlock,
|
TIntermTyped *TIntermediate::AddTernarySelection(TIntermTyped *cond,
|
||||||
const TSourceLoc &line)
|
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
|
// Note that the node resulting from here can be a constant union without being qualified as
|
||||||
// constant.
|
// constant.
|
||||||
if (cond->getAsConstantUnion())
|
if (cond->getAsConstantUnion())
|
||||||
{
|
{
|
||||||
|
TQualifier resultQualifier =
|
||||||
|
TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression);
|
||||||
if (cond->getAsConstantUnion()->getBConst(0))
|
if (cond->getAsConstantUnion()->getBConst(0))
|
||||||
{
|
{
|
||||||
trueBlock->getTypePointer()->setQualifier(resultQualifier);
|
trueExpression->getTypePointer()->setQualifier(resultQualifier);
|
||||||
return trueBlock;
|
return trueExpression;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
falseBlock->getTypePointer()->setQualifier(resultQualifier);
|
falseExpression->getTypePointer()->setQualifier(resultQualifier);
|
||||||
return falseBlock;
|
return falseExpression;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
// Make a ternary node.
|
||||||
// Make a selection node.
|
TIntermTernary *node = new TIntermTernary(cond, trueExpression, falseExpression);
|
||||||
//
|
|
||||||
TIntermSelection *node = new TIntermSelection(cond, trueBlock, falseBlock, trueBlock->getType());
|
|
||||||
node->getTypePointer()->setQualifier(resultQualifier);
|
|
||||||
node->setLine(line);
|
node->setLine(line);
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
@ -335,6 +311,7 @@ TIntermTyped *TIntermediate::addSwizzle(
|
|||||||
{
|
{
|
||||||
|
|
||||||
TIntermAggregate *node = new TIntermAggregate(EOpSequence);
|
TIntermAggregate *node = new TIntermAggregate(EOpSequence);
|
||||||
|
node->getTypePointer()->setQualifier(EvqConst);
|
||||||
|
|
||||||
node->setLine(line);
|
node->setLine(line);
|
||||||
TIntermConstantUnion *constIntNode;
|
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
|
// This is to be executed once the final root is put on top by the parsing
|
||||||
// process.
|
// process.
|
||||||
//
|
//
|
||||||
TIntermAggregate *TIntermediate::postProcess(TIntermNode *root)
|
TIntermAggregate *TIntermediate::PostProcess(TIntermNode *root)
|
||||||
{
|
{
|
||||||
if (root == nullptr)
|
if (root == nullptr)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -411,7 +388,8 @@ TIntermAggregate *TIntermediate::postProcess(TIntermNode *root)
|
|||||||
return aggRoot;
|
return aggRoot;
|
||||||
}
|
}
|
||||||
|
|
||||||
TIntermTyped *TIntermediate::foldAggregateBuiltIn(TIntermAggregate *aggregate)
|
TIntermTyped *TIntermediate::foldAggregateBuiltIn(TIntermAggregate *aggregate,
|
||||||
|
TDiagnostics *diagnostics)
|
||||||
{
|
{
|
||||||
switch (aggregate->getOp())
|
switch (aggregate->getOp())
|
||||||
{
|
{
|
||||||
@ -438,12 +416,12 @@ TIntermTyped *TIntermediate::foldAggregateBuiltIn(TIntermAggregate *aggregate)
|
|||||||
case EOpFaceForward:
|
case EOpFaceForward:
|
||||||
case EOpReflect:
|
case EOpReflect:
|
||||||
case EOpRefract:
|
case EOpRefract:
|
||||||
return aggregate->fold(mInfoSink);
|
return aggregate->fold(diagnostics);
|
||||||
default:
|
default:
|
||||||
// TODO: Add support for folding array constructors
|
// TODO: Add support for folding array constructors
|
||||||
if (aggregate->isConstructor() && !aggregate->isArray())
|
if (aggregate->isConstructor() && !aggregate->isArray())
|
||||||
{
|
{
|
||||||
return aggregate->fold(mInfoSink);
|
return aggregate->fold(diagnostics);
|
||||||
}
|
}
|
||||||
// Constant folding not supported for the built-in.
|
// Constant folding not supported for the built-in.
|
||||||
return nullptr;
|
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
|
class TIntermediate
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
POOL_ALLOCATOR_NEW_DELETE();
|
POOL_ALLOCATOR_NEW_DELETE();
|
||||||
TIntermediate(TInfoSink &i)
|
TIntermediate() {}
|
||||||
: mInfoSink(i) { }
|
|
||||||
|
|
||||||
TIntermSymbol *addSymbol(
|
TIntermSymbol *addSymbol(
|
||||||
int id, const TString &, const TType &, const TSourceLoc &);
|
int id, const TString &, const TType &, const TSourceLoc &);
|
||||||
TIntermTyped *addIndex(
|
TIntermTyped *addIndex(TOperator op,
|
||||||
TOperator op, TIntermTyped *base, TIntermTyped *index, const TSourceLoc &);
|
TIntermTyped *base,
|
||||||
|
TIntermTyped *index,
|
||||||
|
const TSourceLoc &line,
|
||||||
|
TDiagnostics *diagnostics);
|
||||||
TIntermTyped *addUnaryMath(
|
TIntermTyped *addUnaryMath(
|
||||||
TOperator op, TIntermTyped *child, const TSourceLoc &line, const TType *funcReturnType);
|
TOperator op, TIntermTyped *child, const TSourceLoc &line, const TType *funcReturnType);
|
||||||
TIntermAggregate *growAggregate(
|
TIntermAggregate *growAggregate(
|
||||||
@ -37,9 +38,11 @@ class TIntermediate
|
|||||||
TIntermAggregate *makeAggregate(TIntermNode *node, const TSourceLoc &);
|
TIntermAggregate *makeAggregate(TIntermNode *node, const TSourceLoc &);
|
||||||
TIntermAggregate *ensureSequence(TIntermNode *node);
|
TIntermAggregate *ensureSequence(TIntermNode *node);
|
||||||
TIntermAggregate *setAggregateOperator(TIntermNode *, TOperator, const TSourceLoc &);
|
TIntermAggregate *setAggregateOperator(TIntermNode *, TOperator, const TSourceLoc &);
|
||||||
TIntermNode *addSelection(TIntermTyped *cond, TIntermNodePair code, const TSourceLoc &);
|
TIntermNode *addSelection(TIntermTyped *cond, TIntermNodePair code, const TSourceLoc &line);
|
||||||
TIntermTyped *addSelection(TIntermTyped *cond, TIntermTyped *trueBlock, TIntermTyped *falseBlock,
|
static TIntermTyped *AddTernarySelection(TIntermTyped *cond,
|
||||||
const TSourceLoc &line);
|
TIntermTyped *trueExpression,
|
||||||
|
TIntermTyped *falseExpression,
|
||||||
|
const TSourceLoc &line);
|
||||||
TIntermSwitch *addSwitch(
|
TIntermSwitch *addSwitch(
|
||||||
TIntermTyped *init, TIntermAggregate *statementList, const TSourceLoc &line);
|
TIntermTyped *init, TIntermAggregate *statementList, const TSourceLoc &line);
|
||||||
TIntermCase *addCase(
|
TIntermCase *addCase(
|
||||||
@ -56,16 +59,14 @@ class TIntermediate
|
|||||||
TIntermBranch *addBranch(TOperator, const TSourceLoc &);
|
TIntermBranch *addBranch(TOperator, const TSourceLoc &);
|
||||||
TIntermBranch *addBranch(TOperator, TIntermTyped *, const TSourceLoc &);
|
TIntermBranch *addBranch(TOperator, TIntermTyped *, const TSourceLoc &);
|
||||||
TIntermTyped *addSwizzle(TVectorFields &, const TSourceLoc &);
|
TIntermTyped *addSwizzle(TVectorFields &, const TSourceLoc &);
|
||||||
TIntermAggregate *postProcess(TIntermNode *root);
|
static TIntermAggregate *PostProcess(TIntermNode *root);
|
||||||
|
|
||||||
static void outputTree(TIntermNode *, TInfoSinkBase &);
|
static void outputTree(TIntermNode *, TInfoSinkBase &);
|
||||||
|
|
||||||
TIntermTyped *foldAggregateBuiltIn(TIntermAggregate *aggregate);
|
TIntermTyped *foldAggregateBuiltIn(TIntermAggregate *aggregate, TDiagnostics *diagnostics);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void operator=(TIntermediate &); // prevent assignments
|
void operator=(TIntermediate &); // prevent assignments
|
||||||
|
|
||||||
TInfoSink & mInfoSink;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // COMPILER_TRANSLATOR_INTERMEDIATE_H_
|
#endif // COMPILER_TRANSLATOR_INTERMEDIATE_H_
|
||||||
|
@ -27,11 +27,9 @@ bool isSingleStatement(TIntermNode *node)
|
|||||||
return (aggregate->getOp() != EOpFunction) &&
|
return (aggregate->getOp() != EOpFunction) &&
|
||||||
(aggregate->getOp() != EOpSequence);
|
(aggregate->getOp() != EOpSequence);
|
||||||
}
|
}
|
||||||
else if (const TIntermSelection *selection = node->getAsSelectionNode())
|
else if (node->getAsSelectionNode())
|
||||||
{
|
{
|
||||||
// Ternary operators are usually part of an assignment operator.
|
return false;
|
||||||
// This handles those rare cases in which they are all by themselves.
|
|
||||||
return selection->usesTernaryOperator();
|
|
||||||
}
|
}
|
||||||
else if (node->getAsLoopNode())
|
else if (node->getAsLoopNode())
|
||||||
{
|
{
|
||||||
@ -711,40 +709,40 @@ bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
|
|||||||
return true;
|
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)
|
bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection *node)
|
||||||
{
|
{
|
||||||
TInfoSinkBase &out = objSink();
|
TInfoSinkBase &out = objSink();
|
||||||
|
|
||||||
if (node->usesTernaryOperator())
|
out << "if (";
|
||||||
{
|
node->getCondition()->traverse(this);
|
||||||
// Notice two brackets at the beginning and end. The outer ones
|
out << ")\n";
|
||||||
// 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";
|
|
||||||
|
|
||||||
incrementDepth(node);
|
incrementDepth(node);
|
||||||
visitCodeBlock(node->getTrueBlock());
|
visitCodeBlock(node->getTrueBlock());
|
||||||
|
|
||||||
if (node->getFalseBlock())
|
if (node->getFalseBlock())
|
||||||
{
|
{
|
||||||
out << "else\n";
|
out << "else\n";
|
||||||
visitCodeBlock(node->getFalseBlock());
|
visitCodeBlock(node->getFalseBlock());
|
||||||
}
|
|
||||||
decrementDepth();
|
|
||||||
}
|
}
|
||||||
|
decrementDepth();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,6 +44,7 @@ class TOutputGLSLBase : public TIntermTraverser
|
|||||||
void visitConstantUnion(TIntermConstantUnion *node) override;
|
void visitConstantUnion(TIntermConstantUnion *node) override;
|
||||||
bool visitBinary(Visit visit, TIntermBinary *node) override;
|
bool visitBinary(Visit visit, TIntermBinary *node) override;
|
||||||
bool visitUnary(Visit visit, TIntermUnary *node) override;
|
bool visitUnary(Visit visit, TIntermUnary *node) override;
|
||||||
|
bool visitTernary(Visit visit, TIntermTernary *node) override;
|
||||||
bool visitSelection(Visit visit, TIntermSelection *node) override;
|
bool visitSelection(Visit visit, TIntermSelection *node) override;
|
||||||
bool visitSwitch(Visit visit, TIntermSwitch *node) override;
|
bool visitSwitch(Visit visit, TIntermSwitch *node) override;
|
||||||
bool visitCase(Visit visit, TIntermCase *node) override;
|
bool visitCase(Visit visit, TIntermCase *node) override;
|
||||||
|
@ -80,11 +80,14 @@ const TConstantUnion *WriteConstantUnionArray(TInfoSinkBase &out,
|
|||||||
namespace sh
|
namespace sh
|
||||||
{
|
{
|
||||||
|
|
||||||
OutputHLSL::OutputHLSL(sh::GLenum shaderType, int shaderVersion,
|
OutputHLSL::OutputHLSL(sh::GLenum shaderType,
|
||||||
const TExtensionBehavior &extensionBehavior,
|
int shaderVersion,
|
||||||
const char *sourcePath, ShShaderOutput outputType,
|
const TExtensionBehavior &extensionBehavior,
|
||||||
int numRenderTargets, const std::vector<Uniform> &uniforms,
|
const char *sourcePath,
|
||||||
int compileOptions)
|
ShShaderOutput outputType,
|
||||||
|
int numRenderTargets,
|
||||||
|
const std::vector<Uniform> &uniforms,
|
||||||
|
ShCompileOptions compileOptions)
|
||||||
: TIntermTraverser(true, true, true),
|
: TIntermTraverser(true, true, true),
|
||||||
mShaderType(shaderType),
|
mShaderType(shaderType),
|
||||||
mShaderVersion(shaderVersion),
|
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.
|
// 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
|
// Also no need to output ; after selection (if) statements or sequences. This is done just
|
||||||
// for code clarity.
|
// for code clarity.
|
||||||
TIntermSelection *asSelection = (*sit)->getAsSelectionNode();
|
if ((*sit)->getAsCaseNode() == nullptr && (*sit)->getAsSelectionNode() == nullptr &&
|
||||||
ASSERT(asSelection == nullptr || !asSelection->usesTernaryOperator());
|
!IsSequence(*sit))
|
||||||
if ((*sit)->getAsCaseNode() == nullptr && asSelection == nullptr && !IsSequence(*sit))
|
|
||||||
out << ";\n";
|
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)
|
bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node)
|
||||||
{
|
{
|
||||||
TInfoSinkBase &out = getInfoSink();
|
TInfoSinkBase &out = getInfoSink();
|
||||||
|
|
||||||
ASSERT(!node->usesTernaryOperator());
|
|
||||||
ASSERT(mInsideFunction);
|
ASSERT(mInsideFunction);
|
||||||
|
|
||||||
// D3D errors when there is a gradient operation in a loop in an unflattened if.
|
// 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
|
class OutputHLSL : public TIntermTraverser
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
OutputHLSL(sh::GLenum shaderType, int shaderVersion,
|
OutputHLSL(sh::GLenum shaderType,
|
||||||
const TExtensionBehavior &extensionBehavior,
|
int shaderVersion,
|
||||||
const char *sourcePath, ShShaderOutput outputType,
|
const TExtensionBehavior &extensionBehavior,
|
||||||
int numRenderTargets, const std::vector<Uniform> &uniforms,
|
const char *sourcePath,
|
||||||
int compileOptions);
|
ShShaderOutput outputType,
|
||||||
|
int numRenderTargets,
|
||||||
|
const std::vector<Uniform> &uniforms,
|
||||||
|
ShCompileOptions compileOptions);
|
||||||
|
|
||||||
~OutputHLSL();
|
~OutputHLSL();
|
||||||
|
|
||||||
@ -58,6 +61,7 @@ class OutputHLSL : public TIntermTraverser
|
|||||||
void visitConstantUnion(TIntermConstantUnion*);
|
void visitConstantUnion(TIntermConstantUnion*);
|
||||||
bool visitBinary(Visit visit, TIntermBinary*);
|
bool visitBinary(Visit visit, TIntermBinary*);
|
||||||
bool visitUnary(Visit visit, TIntermUnary*);
|
bool visitUnary(Visit visit, TIntermUnary*);
|
||||||
|
bool visitTernary(Visit visit, TIntermTernary *);
|
||||||
bool visitSelection(Visit visit, TIntermSelection*);
|
bool visitSelection(Visit visit, TIntermSelection*);
|
||||||
bool visitSwitch(Visit visit, TIntermSwitch *);
|
bool visitSwitch(Visit visit, TIntermSwitch *);
|
||||||
bool visitCase(Visit visit, TIntermCase *);
|
bool visitCase(Visit visit, TIntermCase *);
|
||||||
@ -117,7 +121,7 @@ class OutputHLSL : public TIntermTraverser
|
|||||||
const TExtensionBehavior &mExtensionBehavior;
|
const TExtensionBehavior &mExtensionBehavior;
|
||||||
const char *mSourcePath;
|
const char *mSourcePath;
|
||||||
const ShShaderOutput mOutputType;
|
const ShShaderOutput mOutputType;
|
||||||
int mCompileOptions;
|
ShCompileOptions mCompileOptions;
|
||||||
|
|
||||||
bool mInsideFunction;
|
bool mInsideFunction;
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -11,6 +11,7 @@
|
|||||||
#include "compiler/translator/DirectiveHandler.h"
|
#include "compiler/translator/DirectiveHandler.h"
|
||||||
#include "compiler/translator/Intermediate.h"
|
#include "compiler/translator/Intermediate.h"
|
||||||
#include "compiler/translator/SymbolTable.h"
|
#include "compiler/translator/SymbolTable.h"
|
||||||
|
#include "compiler/translator/QualifierTypes.h"
|
||||||
#include "compiler/preprocessor/Preprocessor.h"
|
#include "compiler/preprocessor/Preprocessor.h"
|
||||||
|
|
||||||
struct TMatrixFields
|
struct TMatrixFields
|
||||||
@ -30,14 +31,13 @@ class TParseContext : angle::NonCopyable
|
|||||||
public:
|
public:
|
||||||
TParseContext(TSymbolTable &symt,
|
TParseContext(TSymbolTable &symt,
|
||||||
TExtensionBehavior &ext,
|
TExtensionBehavior &ext,
|
||||||
TIntermediate &interm,
|
|
||||||
sh::GLenum type,
|
sh::GLenum type,
|
||||||
ShShaderSpec spec,
|
ShShaderSpec spec,
|
||||||
int options,
|
ShCompileOptions options,
|
||||||
bool checksPrecErrors,
|
bool checksPrecErrors,
|
||||||
TInfoSink &is,
|
TInfoSink &is,
|
||||||
const ShBuiltInResources &resources)
|
const ShBuiltInResources &resources)
|
||||||
: intermediate(interm),
|
: intermediate(),
|
||||||
symbolTable(symt),
|
symbolTable(symt),
|
||||||
mDeferredSingleDeclarationErrorCheck(false),
|
mDeferredSingleDeclarationErrorCheck(false),
|
||||||
mShaderType(type),
|
mShaderType(type),
|
||||||
@ -67,7 +67,8 @@ class TParseContext : angle::NonCopyable
|
|||||||
mUsesSecondaryOutputs(false),
|
mUsesSecondaryOutputs(false),
|
||||||
mMinProgramTexelOffset(resources.MinProgramTexelOffset),
|
mMinProgramTexelOffset(resources.MinProgramTexelOffset),
|
||||||
mMaxProgramTexelOffset(resources.MaxProgramTexelOffset),
|
mMaxProgramTexelOffset(resources.MaxProgramTexelOffset),
|
||||||
mComputeShaderLocalSizeDeclared(false)
|
mComputeShaderLocalSizeDeclared(false),
|
||||||
|
mDeclaringFunction(false)
|
||||||
{
|
{
|
||||||
mComputeShaderLocalSize.fill(-1);
|
mComputeShaderLocalSize.fill(-1);
|
||||||
}
|
}
|
||||||
@ -119,6 +120,12 @@ class TParseContext : angle::NonCopyable
|
|||||||
bool isComputeShaderLocalSizeDeclared() const { return mComputeShaderLocalSizeDeclared; }
|
bool isComputeShaderLocalSizeDeclared() const { return mComputeShaderLocalSizeDeclared; }
|
||||||
sh::WorkGroupSize getComputeShaderLocalSize() const;
|
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.
|
// 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);
|
const TVariable *getNamedVariable(const TSourceLoc &location, const TString *name, const TSymbol *symbol);
|
||||||
TIntermTyped *parseVariableIdentifier(const TSourceLoc &location,
|
TIntermTyped *parseVariableIdentifier(const TSourceLoc &location,
|
||||||
@ -152,7 +159,9 @@ class TParseContext : angle::NonCopyable
|
|||||||
bool checkIsNonVoid(const TSourceLoc &line, const TString &identifier, const TBasicType &type);
|
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 TIntermTyped *type);
|
||||||
void checkIsScalarBool(const TSourceLoc &line, const TPublicType &pType);
|
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 checkDeclaratorLocationIsNotSpecified(const TSourceLoc &line, const TPublicType &pType);
|
||||||
void checkLocationIsNotSpecified(const TSourceLoc &location,
|
void checkLocationIsNotSpecified(const TSourceLoc &location,
|
||||||
const TLayoutQualifier &layoutQualifier);
|
const TLayoutQualifier &layoutQualifier);
|
||||||
@ -160,8 +169,7 @@ class TParseContext : angle::NonCopyable
|
|||||||
TQualifier qualifier,
|
TQualifier qualifier,
|
||||||
const TType &type);
|
const TType &type);
|
||||||
void checkIsParameterQualifierValid(const TSourceLoc &line,
|
void checkIsParameterQualifierValid(const TSourceLoc &line,
|
||||||
TQualifier qualifier,
|
const TTypeQualifierBuilder &typeQualifierBuilder,
|
||||||
TQualifier paramQualifier,
|
|
||||||
TType *type);
|
TType *type);
|
||||||
bool checkCanUseExtension(const TSourceLoc &line, const TString &extension);
|
bool checkCanUseExtension(const TSourceLoc &line, const TString &extension);
|
||||||
void singleDeclarationErrorCheck(const TPublicType &publicType,
|
void singleDeclarationErrorCheck(const TPublicType &publicType,
|
||||||
@ -173,8 +181,9 @@ class TParseContext : angle::NonCopyable
|
|||||||
const TLayoutQualifier &layoutQualifier);
|
const TLayoutQualifier &layoutQualifier);
|
||||||
|
|
||||||
void functionCallLValueErrorCheck(const TFunction *fnCandidate, TIntermAggregate *fnCall);
|
void functionCallLValueErrorCheck(const TFunction *fnCandidate, TIntermAggregate *fnCall);
|
||||||
void checkInvariantIsOutVariableES3(const TQualifier qualifier,
|
void checkInvariantVariableQualifier(bool invariant,
|
||||||
const TSourceLoc &invariantLocation);
|
const TQualifier qualifier,
|
||||||
|
const TSourceLoc &invariantLocation);
|
||||||
void checkInputOutputTypeIsValidES3(const TQualifier qualifier,
|
void checkInputOutputTypeIsValidES3(const TQualifier qualifier,
|
||||||
const TPublicType &type,
|
const TPublicType &type,
|
||||||
const TSourceLoc &qualifierLocation);
|
const TSourceLoc &qualifierLocation);
|
||||||
@ -195,9 +204,7 @@ class TParseContext : angle::NonCopyable
|
|||||||
TIntermTyped *initializer,
|
TIntermTyped *initializer,
|
||||||
TIntermNode **intermNode);
|
TIntermNode **intermNode);
|
||||||
|
|
||||||
TPublicType addFullySpecifiedType(TQualifier qualifier,
|
TPublicType addFullySpecifiedType(const TTypeQualifierBuilder &typeQualifierBuilder,
|
||||||
bool invariant,
|
|
||||||
TLayoutQualifier layoutQualifier,
|
|
||||||
const TPublicType &typeSpecifier);
|
const TPublicType &typeSpecifier);
|
||||||
|
|
||||||
TIntermAggregate *parseSingleDeclaration(TPublicType &publicType,
|
TIntermAggregate *parseSingleDeclaration(TPublicType &publicType,
|
||||||
@ -224,7 +231,7 @@ class TParseContext : angle::NonCopyable
|
|||||||
const TSourceLoc &initLocation,
|
const TSourceLoc &initLocation,
|
||||||
TIntermTyped *initializer);
|
TIntermTyped *initializer);
|
||||||
|
|
||||||
TIntermAggregate *parseInvariantDeclaration(const TSourceLoc &invariantLoc,
|
TIntermAggregate *parseInvariantDeclaration(const TTypeQualifierBuilder &typeQualifierBuilder,
|
||||||
const TSourceLoc &identifierLoc,
|
const TSourceLoc &identifierLoc,
|
||||||
const TString *identifier,
|
const TString *identifier,
|
||||||
const TSymbol *symbol);
|
const TSymbol *symbol);
|
||||||
@ -256,7 +263,7 @@ class TParseContext : angle::NonCopyable
|
|||||||
const TSourceLoc &initLocation,
|
const TSourceLoc &initLocation,
|
||||||
TIntermTyped *initializer);
|
TIntermTyped *initializer);
|
||||||
|
|
||||||
void parseGlobalLayoutQualifier(const TPublicType &typeQualifier);
|
void parseGlobalLayoutQualifier(const TTypeQualifierBuilder &typeQualifierBuilder);
|
||||||
TIntermAggregate *addFunctionPrototypeDeclaration(const TFunction &function,
|
TIntermAggregate *addFunctionPrototypeDeclaration(const TFunction &function,
|
||||||
const TSourceLoc &location);
|
const TSourceLoc &location);
|
||||||
TIntermAggregate *addFunctionDefinition(const TFunction &function,
|
TIntermAggregate *addFunctionDefinition(const TFunction &function,
|
||||||
@ -277,8 +284,6 @@ class TParseContext : angle::NonCopyable
|
|||||||
TFunction *fnCall,
|
TFunction *fnCall,
|
||||||
const TSourceLoc &line);
|
const TSourceLoc &line);
|
||||||
|
|
||||||
TIntermTyped *addConstStruct(
|
|
||||||
const TString &identifier, TIntermTyped *node, const TSourceLoc& line);
|
|
||||||
TIntermTyped *addIndexExpression(TIntermTyped *baseExpression,
|
TIntermTyped *addIndexExpression(TIntermTyped *baseExpression,
|
||||||
const TSourceLoc& location,
|
const TSourceLoc& location,
|
||||||
TIntermTyped *indexExpression);
|
TIntermTyped *indexExpression);
|
||||||
@ -287,20 +292,24 @@ class TParseContext : angle::NonCopyable
|
|||||||
const TString &fieldString,
|
const TString &fieldString,
|
||||||
const TSourceLoc &fieldLocation);
|
const TSourceLoc &fieldLocation);
|
||||||
|
|
||||||
|
TFieldList *addStructDeclaratorListWithQualifiers(
|
||||||
|
const TTypeQualifierBuilder &typeQualifierBuilder,
|
||||||
|
TPublicType *typeSpecifier,
|
||||||
|
TFieldList *fieldList);
|
||||||
TFieldList *addStructDeclaratorList(const TPublicType &typeSpecifier, TFieldList *fieldList);
|
TFieldList *addStructDeclaratorList(const TPublicType &typeSpecifier, TFieldList *fieldList);
|
||||||
TPublicType addStructure(const TSourceLoc &structLine,
|
TTypeSpecifierNonArray addStructure(const TSourceLoc &structLine,
|
||||||
const TSourceLoc &nameLine,
|
const TSourceLoc &nameLine,
|
||||||
const TString *structName,
|
const TString *structName,
|
||||||
TFieldList *fieldList);
|
TFieldList *fieldList);
|
||||||
|
|
||||||
TIntermAggregate* addInterfaceBlock(const TPublicType &typeQualifier,
|
TIntermAggregate *addInterfaceBlock(const TTypeQualifierBuilder &typeQualifierBuilder,
|
||||||
const TSourceLoc &nameLine,
|
const TSourceLoc &nameLine,
|
||||||
const TString &blockName,
|
const TString &blockName,
|
||||||
TFieldList *fieldList,
|
TFieldList *fieldList,
|
||||||
const TString *instanceName,
|
const TString *instanceName,
|
||||||
const TSourceLoc &instanceLine,
|
const TSourceLoc &instanceLine,
|
||||||
TIntermTyped *arrayIndex,
|
TIntermTyped *arrayIndex,
|
||||||
const TSourceLoc& arrayIndexLine);
|
const TSourceLoc &arrayIndexLine);
|
||||||
|
|
||||||
void parseLocalSize(const TString &qualifierType,
|
void parseLocalSize(const TString &qualifierType,
|
||||||
const TSourceLoc &qualifierTypeLine,
|
const TSourceLoc &qualifierTypeLine,
|
||||||
@ -315,11 +324,10 @@ class TParseContext : angle::NonCopyable
|
|||||||
const TSourceLoc &qualifierTypeLine,
|
const TSourceLoc &qualifierTypeLine,
|
||||||
int intValue,
|
int intValue,
|
||||||
const TSourceLoc &intValueLine);
|
const TSourceLoc &intValueLine);
|
||||||
|
TTypeQualifierBuilder *createTypeQualifierBuilder(const TSourceLoc &loc);
|
||||||
TLayoutQualifier joinLayoutQualifiers(TLayoutQualifier leftQualifier,
|
TLayoutQualifier joinLayoutQualifiers(TLayoutQualifier leftQualifier,
|
||||||
TLayoutQualifier rightQualifier,
|
TLayoutQualifier rightQualifier,
|
||||||
const TSourceLoc &rightQualifierLocation);
|
const TSourceLoc &rightQualifierLocation);
|
||||||
TPublicType joinInterpolationQualifiers(const TSourceLoc &interpolationLoc, TQualifier interpolationQualifier,
|
|
||||||
const TSourceLoc &storageLoc, TQualifier storageQualifier);
|
|
||||||
|
|
||||||
// Performs an error check for embedded struct declarations.
|
// Performs an error check for embedded struct declarations.
|
||||||
void enterStructDeclaration(const TSourceLoc &line, const TString &identifier);
|
void enterStructDeclaration(const TSourceLoc &line, const TString &identifier);
|
||||||
@ -352,11 +360,13 @@ class TParseContext : angle::NonCopyable
|
|||||||
const TSourceLoc &loc,
|
const TSourceLoc &loc,
|
||||||
bool *fatalError);
|
bool *fatalError);
|
||||||
|
|
||||||
TIntermTyped *addTernarySelection(
|
TIntermTyped *addTernarySelection(TIntermTyped *cond,
|
||||||
TIntermTyped *cond, TIntermTyped *trueBlock, TIntermTyped *falseBlock, const TSourceLoc &line);
|
TIntermTyped *trueExpression,
|
||||||
|
TIntermTyped *falseExpression,
|
||||||
|
const TSourceLoc &line);
|
||||||
|
|
||||||
// TODO(jmadill): make these private
|
// 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
|
TSymbolTable &symbolTable; // symbol table that goes with the language currently being parsed
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -368,18 +378,6 @@ class TParseContext : angle::NonCopyable
|
|||||||
const char *reason,
|
const char *reason,
|
||||||
const char *token);
|
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);
|
bool declareVariable(const TSourceLoc &line, const TString &identifier, const TType &type, TVariable **variable);
|
||||||
|
|
||||||
void checkCanBeDeclaredWithoutInitializer(const TSourceLoc &line,
|
void checkCanBeDeclaredWithoutInitializer(const TSourceLoc &line,
|
||||||
@ -409,16 +407,18 @@ class TParseContext : angle::NonCopyable
|
|||||||
bool mDeferredSingleDeclarationErrorCheck;
|
bool mDeferredSingleDeclarationErrorCheck;
|
||||||
|
|
||||||
sh::GLenum mShaderType; // vertex or fragment language (future: pack or unpack)
|
sh::GLenum mShaderType; // vertex or fragment language (future: pack or unpack)
|
||||||
ShShaderSpec mShaderSpec; // The language specification compiler conforms to - GLES2 or WebGL.
|
ShShaderSpec mShaderSpec; // The language specification compiler conforms to - GLES2 or WebGL.
|
||||||
int mCompileOptions; // Options passed to TCompiler
|
ShCompileOptions mCompileOptions; // Options passed to TCompiler
|
||||||
int mShaderVersion;
|
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 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
|
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 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
|
bool mFragmentPrecisionHighOnESSL1; // true if highp precision is supported when compiling
|
||||||
// ESSL1.
|
// ESSL1.
|
||||||
TLayoutMatrixPacking mDefaultMatrixPacking;
|
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.
|
// keep track of local group size declared in layout. It should be declared only once.
|
||||||
bool mComputeShaderLocalSizeDeclared;
|
bool mComputeShaderLocalSizeDeclared;
|
||||||
sh::WorkGroupSize mComputeShaderLocalSize;
|
sh::WorkGroupSize mComputeShaderLocalSize;
|
||||||
|
// keeps track whether we are declaring / defining a function
|
||||||
|
bool mDeclaringFunction;
|
||||||
};
|
};
|
||||||
|
|
||||||
int PaParseStrings(
|
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,
|
const int index,
|
||||||
TQualifier baseQualifier)
|
TQualifier baseQualifier)
|
||||||
{
|
{
|
||||||
TIntermBinary *indexNode = new TIntermBinary(EOpIndexDirect);
|
|
||||||
indexNode->setType(fieldType);
|
|
||||||
TIntermSymbol *baseSymbol = CreateBaseSymbol(indexedType, baseQualifier);
|
TIntermSymbol *baseSymbol = CreateBaseSymbol(indexedType, baseQualifier);
|
||||||
indexNode->setLeft(baseSymbol);
|
TIntermBinary *indexNode =
|
||||||
indexNode->setRight(CreateIntConstantNode(index));
|
new TIntermBinary(EOpIndexDirect, baseSymbol, TIntermTyped::CreateIndexNode(index));
|
||||||
return indexNode;
|
return indexNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
TIntermBinary *CreateAssignValueSymbolNode(TIntermTyped *targetNode, const TType &assignedValueType)
|
TIntermBinary *CreateAssignValueSymbolNode(TIntermTyped *targetNode, const TType &assignedValueType)
|
||||||
{
|
{
|
||||||
TIntermBinary *assignNode = new TIntermBinary(EOpAssign);
|
return new TIntermBinary(EOpAssign, targetNode, CreateValueSymbol(assignedValueType));
|
||||||
assignNode->setType(assignedValueType);
|
|
||||||
assignNode->setLeft(targetNode);
|
|
||||||
assignNode->setRight(CreateValueSymbol(assignedValueType));
|
|
||||||
return assignNode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TIntermTyped *EnsureSignedInt(TIntermTyped *node)
|
TIntermTyped *EnsureSignedInt(TIntermTyped *node)
|
||||||
@ -256,10 +250,9 @@ TIntermAggregate *GetIndexFunctionDefinition(TType type, bool write)
|
|||||||
TIntermAggregate *bodyNode = new TIntermAggregate(EOpSequence);
|
TIntermAggregate *bodyNode = new TIntermAggregate(EOpSequence);
|
||||||
bodyNode->getSequence()->push_back(switchNode);
|
bodyNode->getSequence()->push_back(switchNode);
|
||||||
|
|
||||||
TIntermBinary *cond = new TIntermBinary(EOpLessThan);
|
TIntermBinary *cond =
|
||||||
|
new TIntermBinary(EOpLessThan, CreateIndexSymbol(), CreateIntConstantNode(0));
|
||||||
cond->setType(TType(EbtBool, EbpUndefined));
|
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,
|
// Two blocks: one accesses (either reads or writes) the first element and returns,
|
||||||
// the other accesses the last element.
|
// 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 *x = node->getSequence()->at(0)->getAsTyped();
|
||||||
TIntermTyped *y = node->getSequence()->at(1)->getAsTyped();
|
TIntermTyped *y = node->getSequence()->at(1)->getAsTyped();
|
||||||
|
|
||||||
TIntermUnary *log = new TIntermUnary(EOpLog2);
|
TIntermUnary *log = new TIntermUnary(EOpLog2, x);
|
||||||
log->setOperand(x);
|
|
||||||
log->setLine(node->getLine());
|
log->setLine(node->getLine());
|
||||||
log->setType(x->getType());
|
|
||||||
|
|
||||||
TOperator op = TIntermBinary::GetMulOpBasedOnOperands(y->getType(), log->getType());
|
TOperator op = TIntermBinary::GetMulOpBasedOnOperands(y->getType(), log->getType());
|
||||||
TIntermBinary *mul = new TIntermBinary(op, y, log);
|
TIntermBinary *mul = new TIntermBinary(op, y, log);
|
||||||
mul->setLine(node->getLine());
|
mul->setLine(node->getLine());
|
||||||
|
|
||||||
TIntermUnary *exp = new TIntermUnary(EOpExp2);
|
TIntermUnary *exp = new TIntermUnary(EOpExp2, mul);
|
||||||
exp->setOperand(mul);
|
|
||||||
exp->setLine(node->getLine());
|
exp->setLine(node->getLine());
|
||||||
exp->setType(node->getType());
|
|
||||||
|
|
||||||
queueReplacement(node, exp, OriginalNode::IS_DROPPED);
|
queueReplacement(node, exp, OriginalNode::IS_DROPPED);
|
||||||
|
|
||||||
|
@ -62,6 +62,13 @@ bool RemoveSwitchFallThrough::visitUnary(Visit, TIntermUnary *node)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RemoveSwitchFallThrough::visitTernary(Visit, TIntermTernary *node)
|
||||||
|
{
|
||||||
|
mPreviousCase->getSequence()->push_back(node);
|
||||||
|
mLastStatementWasBreak = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool RemoveSwitchFallThrough::visitSelection(Visit, TIntermSelection *node)
|
bool RemoveSwitchFallThrough::visitSelection(Visit, TIntermSelection *node)
|
||||||
{
|
{
|
||||||
mPreviousCase->getSequence()->push_back(node);
|
mPreviousCase->getSequence()->push_back(node);
|
||||||
|
@ -23,6 +23,7 @@ class RemoveSwitchFallThrough : public TIntermTraverser
|
|||||||
void visitConstantUnion(TIntermConstantUnion *node) override;
|
void visitConstantUnion(TIntermConstantUnion *node) override;
|
||||||
bool visitBinary(Visit, TIntermBinary *node) override;
|
bool visitBinary(Visit, TIntermBinary *node) override;
|
||||||
bool visitUnary(Visit, TIntermUnary *node) override;
|
bool visitUnary(Visit, TIntermUnary *node) override;
|
||||||
|
bool visitTernary(Visit visit, TIntermTernary *node) override;
|
||||||
bool visitSelection(Visit visit, TIntermSelection *node) override;
|
bool visitSelection(Visit visit, TIntermSelection *node) override;
|
||||||
bool visitSwitch(Visit, TIntermSwitch *node) override;
|
bool visitSwitch(Visit, TIntermSwitch *node) override;
|
||||||
bool visitCase(Visit, TIntermCase *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);
|
TIntermAggregate *breakBlock = new TIntermAggregate(EOpSequence);
|
||||||
breakBlock->getSequence()->push_back(breakStatement);
|
breakBlock->getSequence()->push_back(breakStatement);
|
||||||
|
|
||||||
TIntermUnary *negatedCondition = new TIntermUnary(EOpLogicalNot);
|
TIntermUnary *negatedCondition =
|
||||||
negatedCondition->setOperand(loop->getCondition());
|
new TIntermUnary(EOpLogicalNot, loop->getCondition());
|
||||||
|
|
||||||
TIntermSelection *innerIf =
|
TIntermSelection *innerIf =
|
||||||
new TIntermSelection(negatedCondition, breakBlock, nullptr);
|
new TIntermSelection(negatedCondition, breakBlock, nullptr);
|
||||||
|
@ -31,13 +31,6 @@ class ElseBlockRewriter : public TIntermTraverser
|
|||||||
TIntermNode *rewriteSelection(TIntermSelection *selection);
|
TIntermNode *rewriteSelection(TIntermSelection *selection);
|
||||||
};
|
};
|
||||||
|
|
||||||
TIntermUnary *MakeNewUnary(TOperator op, TIntermTyped *operand)
|
|
||||||
{
|
|
||||||
TIntermUnary *unary = new TIntermUnary(op, operand->getType());
|
|
||||||
unary->setOperand(operand);
|
|
||||||
return unary;
|
|
||||||
}
|
|
||||||
|
|
||||||
ElseBlockRewriter::ElseBlockRewriter()
|
ElseBlockRewriter::ElseBlockRewriter()
|
||||||
: TIntermTraverser(true, false, true),
|
: TIntermTraverser(true, false, true),
|
||||||
mFunctionType(NULL)
|
mFunctionType(NULL)
|
||||||
@ -113,7 +106,7 @@ TIntermNode *ElseBlockRewriter::rewriteSelection(TIntermSelection *selection)
|
|||||||
}
|
}
|
||||||
|
|
||||||
TIntermSymbol *conditionSymbolElse = createTempSymbol(boolType);
|
TIntermSymbol *conditionSymbolElse = createTempSymbol(boolType);
|
||||||
TIntermUnary *negatedCondition = MakeNewUnary(EOpLogicalNot, conditionSymbolElse);
|
TIntermUnary *negatedCondition = new TIntermUnary(EOpLogicalNot, conditionSymbolElse);
|
||||||
falseBlock = new TIntermSelection(negatedCondition,
|
falseBlock = new TIntermSelection(negatedCondition,
|
||||||
selection->getFalseBlock(), negatedElse);
|
selection->getFalseBlock(), negatedElse);
|
||||||
}
|
}
|
||||||
|
@ -113,16 +113,11 @@ bool Traverser::visitAggregate(Visit visit, TIntermAggregate *node)
|
|||||||
// sampler
|
// sampler
|
||||||
newsequence.push_back(sequence->at(0));
|
newsequence.push_back(sequence->at(0));
|
||||||
|
|
||||||
// Position+offset
|
|
||||||
TIntermBinary *add = new TIntermBinary(EOpAdd);
|
|
||||||
add->setType(node->getType());
|
|
||||||
// Position
|
// Position
|
||||||
TIntermTyped *texCoordNode = sequence->at(1)->getAsTyped();
|
TIntermTyped *texCoordNode = sequence->at(1)->getAsTyped();
|
||||||
ASSERT(texCoordNode);
|
ASSERT(texCoordNode);
|
||||||
add->setLine(texCoordNode->getLine());
|
|
||||||
add->setType(texCoordNode->getType());
|
|
||||||
add->setLeft(texCoordNode);
|
|
||||||
// offset
|
// offset
|
||||||
|
TIntermTyped *offsetNode = nullptr;
|
||||||
ASSERT(sequence->at(3)->getAsTyped());
|
ASSERT(sequence->at(3)->getAsTyped());
|
||||||
if (is2DArray)
|
if (is2DArray)
|
||||||
{
|
{
|
||||||
@ -143,12 +138,16 @@ bool Traverser::visitAggregate(Visit visit, TIntermAggregate *node)
|
|||||||
ivec3Sequence.push_back(zeroNode);
|
ivec3Sequence.push_back(zeroNode);
|
||||||
constructIVec3Node->insertChildNodes(0, ivec3Sequence);
|
constructIVec3Node->insertChildNodes(0, ivec3Sequence);
|
||||||
|
|
||||||
add->setRight(constructIVec3Node);
|
offsetNode = constructIVec3Node;
|
||||||
}
|
}
|
||||||
else
|
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);
|
newsequence.push_back(add);
|
||||||
|
|
||||||
// lod
|
// lod
|
||||||
|
@ -37,23 +37,9 @@ bool ContainsVectorNode(const TIntermSequence &sequence)
|
|||||||
return false;
|
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 *ConstructVectorIndexBinaryNode(TIntermSymbol *symbolNode, int index)
|
||||||
{
|
{
|
||||||
TIntermBinary *binary = new TIntermBinary(EOpIndexDirect);
|
return new TIntermBinary(EOpIndexDirect, symbolNode, TIntermTyped::CreateIndexNode(index));
|
||||||
binary->setLeft(symbolNode);
|
|
||||||
TIntermConstantUnion *indexNode = ConstructIndexNode(index);
|
|
||||||
binary->setRight(indexNode);
|
|
||||||
return binary;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TIntermBinary *ConstructMatrixIndexBinaryNode(
|
TIntermBinary *ConstructMatrixIndexBinaryNode(
|
||||||
@ -62,11 +48,8 @@ TIntermBinary *ConstructMatrixIndexBinaryNode(
|
|||||||
TIntermBinary *colVectorNode =
|
TIntermBinary *colVectorNode =
|
||||||
ConstructVectorIndexBinaryNode(symbolNode, colIndex);
|
ConstructVectorIndexBinaryNode(symbolNode, colIndex);
|
||||||
|
|
||||||
TIntermBinary *binary = new TIntermBinary(EOpIndexDirect);
|
return new TIntermBinary(EOpIndexDirect, colVectorNode,
|
||||||
binary->setLeft(colVectorNode);
|
TIntermTyped::CreateIndexNode(rowIndex));
|
||||||
TIntermConstantUnion *rowIndexNode = ConstructIndexNode(rowIndex);
|
|
||||||
binary->setRight(rowIndexNode);
|
|
||||||
return binary;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace anonymous
|
} // namespace anonymous
|
||||||
@ -278,11 +261,8 @@ TString ScalarizeVecAndMatConstructorArgs::createTempVariable(TIntermTyped *orig
|
|||||||
type.setPrecision(mFragmentPrecisionHigh ? EbpHigh : EbpMedium);
|
type.setPrecision(mFragmentPrecisionHigh ? EbpHigh : EbpMedium);
|
||||||
}
|
}
|
||||||
|
|
||||||
TIntermBinary *init = new TIntermBinary(EOpInitialize);
|
|
||||||
TIntermSymbol *symbolNode = new TIntermSymbol(-1, tempVarName, type);
|
TIntermSymbol *symbolNode = new TIntermSymbol(-1, tempVarName, type);
|
||||||
init->setLeft(symbolNode);
|
TIntermBinary *init = new TIntermBinary(EOpInitialize, symbolNode, original);
|
||||||
init->setRight(original);
|
|
||||||
init->setType(type);
|
|
||||||
|
|
||||||
TIntermAggregate *decl = new TIntermAggregate(EOpDeclaration);
|
TIntermAggregate *decl = new TIntermAggregate(EOpDeclaration);
|
||||||
decl->getSequence()->push_back(init);
|
decl->getSequence()->push_back(init);
|
||||||
|
@ -69,10 +69,8 @@ bool SeparateArrayInitTraverser::visitAggregate(Visit, TIntermAggregate *node)
|
|||||||
replacementDeclaration->setLine(symbol->getLine());
|
replacementDeclaration->setLine(symbol->getLine());
|
||||||
replacements.push_back(replacementDeclaration);
|
replacements.push_back(replacementDeclaration);
|
||||||
|
|
||||||
TIntermBinary *replacementAssignment = new TIntermBinary(EOpAssign);
|
TIntermBinary *replacementAssignment =
|
||||||
replacementAssignment->setLeft(symbol);
|
new TIntermBinary(EOpAssign, symbol, initializer);
|
||||||
replacementAssignment->setRight(initializer);
|
|
||||||
replacementAssignment->setType(initializer->getType());
|
|
||||||
replacementAssignment->setLine(symbol->getLine());
|
replacementAssignment->setLine(symbol->getLine());
|
||||||
replacements.push_back(replacementAssignment);
|
replacements.push_back(replacementAssignment);
|
||||||
|
|
||||||
|
@ -49,11 +49,7 @@ SeparateExpressionsTraverser::SeparateExpressionsTraverser()
|
|||||||
// and also needs to be replaced in its original location by a different node.
|
// and also needs to be replaced in its original location by a different node.
|
||||||
TIntermBinary *CopyAssignmentNode(TIntermBinary *node)
|
TIntermBinary *CopyAssignmentNode(TIntermBinary *node)
|
||||||
{
|
{
|
||||||
TIntermBinary *copyNode = new TIntermBinary(node->getOp());
|
return new TIntermBinary(node->getOp(), node->getLeft(), node->getRight());
|
||||||
copyNode->setLeft(node->getLeft());
|
|
||||||
copyNode->setRight(node->getRight());
|
|
||||||
copyNode->setType(node->getType());
|
|
||||||
return copyNode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Performs a shallow copy of a constructor/function call node.
|
// 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
|
// Return: The return value of ShCompile is really boolean, indicating
|
||||||
// success or failure.
|
// success or failure.
|
||||||
//
|
//
|
||||||
bool ShCompile(
|
bool ShCompile(const ShHandle handle,
|
||||||
const ShHandle handle,
|
const char *const shaderStrings[],
|
||||||
const char *const shaderStrings[],
|
size_t numStrings,
|
||||||
size_t numStrings,
|
ShCompileOptions compileOptions)
|
||||||
int compileOptions)
|
|
||||||
{
|
{
|
||||||
TCompiler *compiler = GetCompilerFromHandle(handle);
|
TCompiler *compiler = GetCompilerFromHandle(handle);
|
||||||
ASSERT(compiler);
|
ASSERT(compiler);
|
||||||
|
@ -36,7 +36,7 @@ class SimplifyLoopConditionsTraverser : public TLValueTrackingTraverser
|
|||||||
|
|
||||||
bool visitBinary(Visit visit, TIntermBinary *node) override;
|
bool visitBinary(Visit visit, TIntermBinary *node) override;
|
||||||
bool visitAggregate(Visit visit, TIntermAggregate *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();
|
void nextIteration();
|
||||||
bool foundLoopToChange() const { return mFoundLoopToChange; }
|
bool foundLoopToChange() const { return mFoundLoopToChange; }
|
||||||
@ -100,14 +100,14 @@ bool SimplifyLoopConditionsTraverser::visitAggregate(Visit visit, TIntermAggrega
|
|||||||
return !mFoundLoopToChange;
|
return !mFoundLoopToChange;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SimplifyLoopConditionsTraverser::visitSelection(Visit visit, TIntermSelection *node)
|
bool SimplifyLoopConditionsTraverser::visitTernary(Visit visit, TIntermTernary *node)
|
||||||
{
|
{
|
||||||
if (mFoundLoopToChange)
|
if (mFoundLoopToChange)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Don't traverse ternary operators outside loop conditions.
|
// Don't traverse ternary operators outside loop conditions.
|
||||||
if (!mInsideLoopConditionOrExpression)
|
if (!mInsideLoopConditionOrExpression)
|
||||||
return !node->usesTernaryOperator();
|
return false;
|
||||||
|
|
||||||
mFoundLoopToChange = mConditionsToSimplify.match(node);
|
mFoundLoopToChange = mConditionsToSimplify.match(node);
|
||||||
return !mFoundLoopToChange;
|
return !mFoundLoopToChange;
|
||||||
|
@ -26,7 +26,7 @@ class SplitSequenceOperatorTraverser : public TLValueTrackingTraverser
|
|||||||
|
|
||||||
bool visitBinary(Visit visit, TIntermBinary *node) override;
|
bool visitBinary(Visit visit, TIntermBinary *node) override;
|
||||||
bool visitAggregate(Visit visit, TIntermAggregate *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();
|
void nextIteration();
|
||||||
bool foundExpressionToSplit() const { return mFoundExpressionToSplit; }
|
bool foundExpressionToSplit() const { return mFoundExpressionToSplit; }
|
||||||
@ -123,7 +123,7 @@ bool SplitSequenceOperatorTraverser::visitAggregate(Visit visit, TIntermAggregat
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SplitSequenceOperatorTraverser::visitSelection(Visit visit, TIntermSelection *node)
|
bool SplitSequenceOperatorTraverser::visitTernary(Visit visit, TIntermTernary *node)
|
||||||
{
|
{
|
||||||
if (mFoundExpressionToSplit)
|
if (mFoundExpressionToSplit)
|
||||||
return false;
|
return false;
|
||||||
|
@ -471,15 +471,15 @@ class TSymbolTable : angle::NonCopyable
|
|||||||
|
|
||||||
bool setDefaultPrecision(const TPublicType &type, TPrecision prec)
|
bool setDefaultPrecision(const TPublicType &type, TPrecision prec)
|
||||||
{
|
{
|
||||||
if (!SupportsPrecision(type.type))
|
if (!SupportsPrecision(type.getBasicType()))
|
||||||
return false;
|
return false;
|
||||||
if (type.type == EbtUInt)
|
if (type.getBasicType() == EbtUInt)
|
||||||
return false; // ESSL 3.00.4 section 4.5.4
|
return false; // ESSL 3.00.4 section 4.5.4
|
||||||
if (type.isAggregate())
|
if (type.isAggregate())
|
||||||
return false; // Not allowed to set for aggregate types
|
return false; // Not allowed to set for aggregate types
|
||||||
int indexOfLastElement = static_cast<int>(precisionStack.size()) - 1;
|
int indexOfLastElement = static_cast<int>(precisionStack.size()) - 1;
|
||||||
// Uses map operator [], overwrites the current value
|
// Uses map operator [], overwrites the current value
|
||||||
(*precisionStack[indexOfLastElement])[type.type] = prec;
|
(*precisionStack[indexOfLastElement])[type.getBasicType()] = prec;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
#include "compiler/translator/TranslatorESSL.h"
|
#include "compiler/translator/TranslatorESSL.h"
|
||||||
|
|
||||||
#include "compiler/translator/BuiltInFunctionEmulatorGLSL.h"
|
|
||||||
#include "compiler/translator/EmulatePrecision.h"
|
#include "compiler/translator/EmulatePrecision.h"
|
||||||
#include "compiler/translator/RecordConstantPrecision.h"
|
#include "compiler/translator/RecordConstantPrecision.h"
|
||||||
#include "compiler/translator/OutputESSL.h"
|
#include "compiler/translator/OutputESSL.h"
|
||||||
@ -17,15 +16,7 @@ TranslatorESSL::TranslatorESSL(sh::GLenum type, ShShaderSpec spec)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void TranslatorESSL::initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, int compileOptions)
|
void TranslatorESSL::translate(TIntermNode *root, ShCompileOptions compileOptions)
|
||||||
{
|
|
||||||
if (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS)
|
|
||||||
{
|
|
||||||
InitBuiltInFunctionEmulatorForGLSLWorkarounds(emu, getShaderType());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TranslatorESSL::translate(TIntermNode *root, int compileOptions)
|
|
||||||
{
|
{
|
||||||
TInfoSinkBase& sink = getInfoSink().obj;
|
TInfoSinkBase& sink = getInfoSink().obj;
|
||||||
|
|
||||||
|
@ -15,9 +15,7 @@ class TranslatorESSL : public TCompiler
|
|||||||
TranslatorESSL(sh::GLenum type, ShShaderSpec spec);
|
TranslatorESSL(sh::GLenum type, ShShaderSpec spec);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, int compileOptions) override;
|
void translate(TIntermNode *root, ShCompileOptions compileOptions) override;
|
||||||
|
|
||||||
void translate(TIntermNode *root, int compileOptions) override;
|
|
||||||
bool shouldFlattenPragmaStdglInvariantAll() override;
|
bool shouldFlattenPragmaStdglInvariantAll() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include "compiler/translator/EmulatePrecision.h"
|
#include "compiler/translator/EmulatePrecision.h"
|
||||||
#include "compiler/translator/ExtensionGLSL.h"
|
#include "compiler/translator/ExtensionGLSL.h"
|
||||||
#include "compiler/translator/OutputGLSL.h"
|
#include "compiler/translator/OutputGLSL.h"
|
||||||
|
#include "compiler/translator/RewriteTexelFetchOffset.h"
|
||||||
#include "compiler/translator/VersionGLSL.h"
|
#include "compiler/translator/VersionGLSL.h"
|
||||||
|
|
||||||
TranslatorGLSL::TranslatorGLSL(sh::GLenum type,
|
TranslatorGLSL::TranslatorGLSL(sh::GLenum type,
|
||||||
@ -19,18 +20,19 @@ TranslatorGLSL::TranslatorGLSL(sh::GLenum type,
|
|||||||
: TCompiler(type, spec, output) {
|
: 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());
|
int targetGLSLVersion = ShaderOutputTypeToGLSLVersion(getOutputType());
|
||||||
InitBuiltInFunctionEmulatorForGLSLMissingFunctions(emu, getShaderType(), targetGLSLVersion);
|
InitBuiltInFunctionEmulatorForGLSLMissingFunctions(emu, getShaderType(), targetGLSLVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TranslatorGLSL::translate(TIntermNode *root, int compileOptions)
|
void TranslatorGLSL::translate(TIntermNode *root, ShCompileOptions compileOptions)
|
||||||
{
|
{
|
||||||
TInfoSinkBase& sink = getInfoSink().obj;
|
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;
|
bool precisionEmulation = getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision;
|
||||||
|
|
||||||
if (precisionEmulation)
|
if (precisionEmulation)
|
||||||
|
@ -15,9 +15,10 @@ class TranslatorGLSL : public TCompiler
|
|||||||
TranslatorGLSL(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output);
|
TranslatorGLSL(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output);
|
||||||
|
|
||||||
protected:
|
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;
|
bool shouldFlattenPragmaStdglInvariantAll() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include "compiler/translator/AddDefaultReturnStatements.h"
|
#include "compiler/translator/AddDefaultReturnStatements.h"
|
||||||
#include "compiler/translator/ArrayReturnValueToOutParameter.h"
|
#include "compiler/translator/ArrayReturnValueToOutParameter.h"
|
||||||
|
#include "compiler/translator/BreakVariableAliasingInInnerLoops.h"
|
||||||
#include "compiler/translator/EmulatePrecision.h"
|
#include "compiler/translator/EmulatePrecision.h"
|
||||||
#include "compiler/translator/ExpandIntegerPowExpressions.h"
|
#include "compiler/translator/ExpandIntegerPowExpressions.h"
|
||||||
#include "compiler/translator/IntermNodePatternMatcher.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();
|
const ShBuiltInResources &resources = getResources();
|
||||||
int numRenderTargets = resources.EXT_draw_buffers ? resources.MaxDrawBuffers : 1;
|
int numRenderTargets = resources.EXT_draw_buffers ? resources.MaxDrawBuffers : 1;
|
||||||
@ -75,6 +76,12 @@ void TranslatorHLSL::translate(TIntermNode *root, int compileOptions)
|
|||||||
sh::RewriteElseBlocks(root, getTemporaryIndex());
|
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 =
|
bool precisionEmulation =
|
||||||
getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision;
|
getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision;
|
||||||
|
|
||||||
|
@ -21,11 +21,11 @@ class TranslatorHLSL : public TCompiler
|
|||||||
const std::map<std::string, unsigned int> *getUniformRegisterMap() const;
|
const std::map<std::string, unsigned int> *getUniformRegisterMap() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void translate(TIntermNode *root, int compileOptions) override;
|
void translate(TIntermNode *root, ShCompileOptions compileOptions) override;
|
||||||
bool shouldFlattenPragmaStdglInvariantAll() override;
|
bool shouldFlattenPragmaStdglInvariantAll() override;
|
||||||
|
|
||||||
// collectVariables needs to be run always so registers can be assigned.
|
// 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> mInterfaceBlockRegisterMap;
|
||||||
std::map<std::string, unsigned int> mUniformRegisterMap;
|
std::map<std::string, unsigned int> mUniformRegisterMap;
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include "compiler/translator/Types.h"
|
#include "compiler/translator/Types.h"
|
||||||
#include "compiler/translator/InfoSink.h"
|
#include "compiler/translator/InfoSink.h"
|
||||||
#include "compiler/translator/IntermNode.h"
|
#include "compiler/translator/IntermNode.h"
|
||||||
|
#include "compiler/translator/SymbolTable.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <climits>
|
#include <climits>
|
||||||
@ -48,12 +49,20 @@ const char* getBasicString(TBasicType t)
|
|||||||
}
|
}
|
||||||
|
|
||||||
TType::TType(const TPublicType &p)
|
TType::TType(const TPublicType &p)
|
||||||
: type(p.type), precision(p.precision), qualifier(p.qualifier), invariant(p.invariant),
|
: type(p.getBasicType()),
|
||||||
layoutQualifier(p.layoutQualifier), primarySize(p.primarySize), secondarySize(p.secondarySize),
|
precision(p.precision),
|
||||||
array(p.array), arraySize(p.arraySize), interfaceBlock(0), structure(0)
|
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)
|
if (p.getUserDef())
|
||||||
structure = p.userDef->getStruct();
|
structure = p.getUserDef()->getStruct();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TStructure::equals(const TStructure &other) const
|
bool TStructure::equals(const TStructure &other) const
|
||||||
@ -328,6 +337,14 @@ size_t TType::getObjectSize() const
|
|||||||
return totalSize;
|
return totalSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TStructure::TStructure(const TString *name, TFieldList *fields)
|
||||||
|
: TFieldListCollection(name, fields),
|
||||||
|
mDeepestNesting(0),
|
||||||
|
mUniqueId(TSymbolTable::nextUniqueId()),
|
||||||
|
mAtGlobalScope(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
bool TStructure::containsArrays() const
|
bool TStructure::containsArrays() const
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < mFields->size(); ++i)
|
for (size_t i = 0; i < mFields->size(); ++i)
|
||||||
|
@ -103,13 +103,7 @@ class TStructure : public TFieldListCollection
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
POOL_ALLOCATOR_NEW_DELETE();
|
POOL_ALLOCATOR_NEW_DELETE();
|
||||||
TStructure(const TString *name, TFieldList *fields)
|
TStructure(const TString *name, TFieldList *fields);
|
||||||
: TFieldListCollection(name, fields),
|
|
||||||
mDeepestNesting(0),
|
|
||||||
mUniqueId(0),
|
|
||||||
mAtGlobalScope(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
int deepestNesting() const
|
int deepestNesting() const
|
||||||
{
|
{
|
||||||
@ -594,6 +588,46 @@ class TType
|
|||||||
mutable TString mangled;
|
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
|
// 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
|
// types that it thinks have non-trivial constructors. It should
|
||||||
@ -605,114 +639,76 @@ class TType
|
|||||||
//
|
//
|
||||||
struct TPublicType
|
struct TPublicType
|
||||||
{
|
{
|
||||||
TBasicType type;
|
TTypeSpecifierNonArray typeSpecifierNonArray;
|
||||||
TLayoutQualifier layoutQualifier;
|
TLayoutQualifier layoutQualifier;
|
||||||
TQualifier qualifier;
|
TQualifier qualifier;
|
||||||
bool invariant;
|
bool invariant;
|
||||||
TPrecision precision;
|
TPrecision precision;
|
||||||
unsigned char primarySize; // size of vector or cols of matrix
|
|
||||||
unsigned char secondarySize; // rows of matrix
|
|
||||||
bool array;
|
bool array;
|
||||||
int arraySize;
|
int arraySize;
|
||||||
TType *userDef;
|
|
||||||
TSourceLoc line;
|
|
||||||
|
|
||||||
// true if the type was defined by a struct specifier rather than a reference to a type name.
|
void initialize(const TTypeSpecifierNonArray &typeSpecifier, TQualifier q)
|
||||||
bool isStructSpecifier;
|
|
||||||
|
|
||||||
void setBasic(TBasicType bt, TQualifier q, const TSourceLoc &ln)
|
|
||||||
{
|
{
|
||||||
type = bt;
|
typeSpecifierNonArray = typeSpecifier;
|
||||||
layoutQualifier = TLayoutQualifier::create();
|
layoutQualifier = TLayoutQualifier::create();
|
||||||
qualifier = q;
|
qualifier = q;
|
||||||
invariant = false;
|
invariant = false;
|
||||||
precision = EbpUndefined;
|
precision = EbpUndefined;
|
||||||
primarySize = 1;
|
array = false;
|
||||||
secondarySize = 1;
|
arraySize = 0;
|
||||||
array = false;
|
|
||||||
arraySize = 0;
|
|
||||||
userDef = 0;
|
|
||||||
line = ln;
|
|
||||||
isStructSpecifier = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
const TType *getUserDef() const { return typeSpecifierNonArray.userDef; }
|
||||||
{
|
const TSourceLoc &getLine() const { return typeSpecifierNonArray.line; }
|
||||||
ASSERT(c > 1 && r > 1 && c <= 4 && r <= 4);
|
|
||||||
primarySize = c;
|
|
||||||
secondarySize = r;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isUnsizedArray() const
|
bool isStructSpecifier() const { return typeSpecifierNonArray.isStructSpecifier; }
|
||||||
{
|
|
||||||
return array && arraySize == 0;
|
|
||||||
}
|
|
||||||
void setArraySize(int s)
|
|
||||||
{
|
|
||||||
array = true;
|
|
||||||
arraySize = s;
|
|
||||||
}
|
|
||||||
void clearArrayness()
|
|
||||||
{
|
|
||||||
array = false;
|
|
||||||
arraySize = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isStructureContainingArrays() const
|
bool isStructureContainingArrays() const
|
||||||
{
|
{
|
||||||
if (!userDef)
|
if (!typeSpecifierNonArray.userDef)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return userDef->isStructureContainingArrays();
|
return typeSpecifierNonArray.userDef->isStructureContainingArrays();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isStructureContainingType(TBasicType t) const
|
bool isStructureContainingType(TBasicType t) const
|
||||||
{
|
{
|
||||||
if (!userDef)
|
if (!typeSpecifierNonArray.userDef)
|
||||||
{
|
{
|
||||||
return false;
|
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;
|
||||||
}
|
}
|
||||||
|
void clearArrayness()
|
||||||
bool isVector() const
|
|
||||||
{
|
{
|
||||||
return primarySize > 1 && secondarySize == 1;
|
array = false;
|
||||||
}
|
arraySize = 0;
|
||||||
|
|
||||||
int getCols() const
|
|
||||||
{
|
|
||||||
ASSERT(isMatrix());
|
|
||||||
return primarySize;
|
|
||||||
}
|
|
||||||
|
|
||||||
int getRows() const
|
|
||||||
{
|
|
||||||
ASSERT(isMatrix());
|
|
||||||
return secondarySize;
|
|
||||||
}
|
|
||||||
|
|
||||||
int getNominalSize() const
|
|
||||||
{
|
|
||||||
return primarySize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isAggregate() const
|
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".
|
// "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;
|
TConstantUnion *u = new TConstantUnion;
|
||||||
u->setBConst(true);
|
u->setBConst(true);
|
||||||
TIntermConstantUnion *trueNode = new TIntermConstantUnion(
|
TIntermConstantUnion *trueNode = new TIntermConstantUnion(
|
||||||
u, TType(EbtBool, EbpUndefined, EvqConst, 1));
|
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".
|
// "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;
|
TConstantUnion *u = new TConstantUnion;
|
||||||
u->setBConst(false);
|
u->setBConst(false);
|
||||||
TIntermConstantUnion *falseNode = new TIntermConstantUnion(
|
TIntermConstantUnion *falseNode = new TIntermConstantUnion(
|
||||||
u, TType(EbtBool, EbpUndefined, EvqConst, 1));
|
u, TType(EbtBool, EbpUndefined, EvqConst, 1));
|
||||||
return new TIntermSelection(x, y, falseNode, boolType);
|
return new TIntermTernary(x, y, falseNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace anonymous
|
} // namespace anonymous
|
||||||
|
|
||||||
bool UnfoldShortCircuitAST::visitBinary(Visit visit, TIntermBinary *node)
|
bool UnfoldShortCircuitAST::visitBinary(Visit visit, TIntermBinary *node)
|
||||||
{
|
{
|
||||||
TIntermSelection *replacement = NULL;
|
TIntermTernary *replacement = nullptr;
|
||||||
|
|
||||||
switch (node->getOp())
|
switch (node->getOp())
|
||||||
{
|
{
|
||||||
|
@ -23,7 +23,7 @@ class UnfoldShortCircuitTraverser : public TIntermTraverser
|
|||||||
UnfoldShortCircuitTraverser();
|
UnfoldShortCircuitTraverser();
|
||||||
|
|
||||||
bool visitBinary(Visit visit, TIntermBinary *node) override;
|
bool visitBinary(Visit visit, TIntermBinary *node) override;
|
||||||
bool visitSelection(Visit visit, TIntermSelection *node) override;
|
bool visitTernary(Visit visit, TIntermTernary *node) override;
|
||||||
|
|
||||||
void nextIteration();
|
void nextIteration();
|
||||||
bool foundShortCircuit() const { return mFoundShortCircuit; }
|
bool foundShortCircuit() const { return mFoundShortCircuit; }
|
||||||
@ -79,8 +79,7 @@ bool UnfoldShortCircuitTraverser::visitBinary(Visit visit, TIntermBinary *node)
|
|||||||
ASSERT(node->getRight()->getType() == boolType);
|
ASSERT(node->getRight()->getType() == boolType);
|
||||||
assignRightBlock->getSequence()->push_back(createTempAssignment(node->getRight()));
|
assignRightBlock->getSequence()->push_back(createTempAssignment(node->getRight()));
|
||||||
|
|
||||||
TIntermUnary *notTempSymbol = new TIntermUnary(EOpLogicalNot, boolType);
|
TIntermUnary *notTempSymbol = new TIntermUnary(EOpLogicalNot, createTempSymbol(boolType));
|
||||||
notTempSymbol->setOperand(createTempSymbol(boolType));
|
|
||||||
TIntermSelection *ifNode = new TIntermSelection(notTempSymbol, assignRightBlock, nullptr);
|
TIntermSelection *ifNode = new TIntermSelection(notTempSymbol, assignRightBlock, nullptr);
|
||||||
insertions.push_back(ifNode);
|
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)
|
if (mFoundShortCircuit)
|
||||||
return false;
|
return false;
|
||||||
@ -132,8 +131,6 @@ bool UnfoldShortCircuitTraverser::visitSelection(Visit visit, TIntermSelection *
|
|||||||
|
|
||||||
mFoundShortCircuit = true;
|
mFoundShortCircuit = true;
|
||||||
|
|
||||||
ASSERT(node->usesTernaryOperator());
|
|
||||||
|
|
||||||
// Unfold "b ? x : y" into "type s; if(b) s = x; else s = y;"
|
// Unfold "b ? x : y" into "type s; if(b) s = x; else s = y;"
|
||||||
TIntermSequence insertions;
|
TIntermSequence insertions;
|
||||||
|
|
||||||
@ -143,11 +140,11 @@ bool UnfoldShortCircuitTraverser::visitSelection(Visit visit, TIntermSelection *
|
|||||||
insertions.push_back(tempDeclaration);
|
insertions.push_back(tempDeclaration);
|
||||||
|
|
||||||
TIntermAggregate *trueBlock = new TIntermAggregate(EOpSequence);
|
TIntermAggregate *trueBlock = new TIntermAggregate(EOpSequence);
|
||||||
TIntermBinary *trueAssignment = createTempAssignment(node->getTrueBlock()->getAsTyped());
|
TIntermBinary *trueAssignment = createTempAssignment(node->getTrueExpression());
|
||||||
trueBlock->getSequence()->push_back(trueAssignment);
|
trueBlock->getSequence()->push_back(trueAssignment);
|
||||||
|
|
||||||
TIntermAggregate *falseBlock = new TIntermAggregate(EOpSequence);
|
TIntermAggregate *falseBlock = new TIntermAggregate(EOpSequence);
|
||||||
TIntermBinary *falseAssignment = createTempAssignment(node->getFalseBlock()->getAsTyped());
|
TIntermBinary *falseAssignment = createTempAssignment(node->getFalseExpression());
|
||||||
falseBlock->getSequence()->push_back(falseAssignment);
|
falseBlock->getSequence()->push_back(falseAssignment);
|
||||||
|
|
||||||
TIntermSelection *ifNode =
|
TIntermSelection *ifNode =
|
||||||
|
@ -56,6 +56,14 @@ bool ValidateSwitch::visitBinary(Visit, TIntermBinary *)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool ValidateSwitch::visitUnary(Visit, TIntermUnary *)
|
bool ValidateSwitch::visitUnary(Visit, TIntermUnary *)
|
||||||
|
{
|
||||||
|
if (!mFirstCaseFound)
|
||||||
|
mStatementBeforeCase = true;
|
||||||
|
mLastStatementWasCase = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ValidateSwitch::visitTernary(Visit, TIntermTernary *)
|
||||||
{
|
{
|
||||||
if (!mFirstCaseFound)
|
if (!mFirstCaseFound)
|
||||||
mStatementBeforeCase = true;
|
mStatementBeforeCase = true;
|
||||||
|
@ -23,6 +23,7 @@ class ValidateSwitch : public TIntermTraverser
|
|||||||
void visitConstantUnion(TIntermConstantUnion *) override;
|
void visitConstantUnion(TIntermConstantUnion *) override;
|
||||||
bool visitBinary(Visit, TIntermBinary *) override;
|
bool visitBinary(Visit, TIntermBinary *) override;
|
||||||
bool visitUnary(Visit, TIntermUnary *) override;
|
bool visitUnary(Visit, TIntermUnary *) override;
|
||||||
|
bool visitTernary(Visit, TIntermTernary *) override;
|
||||||
bool visitSelection(Visit visit, TIntermSelection *) override;
|
bool visitSelection(Visit visit, TIntermSelection *) override;
|
||||||
bool visitSwitch(Visit, TIntermSwitch *) override;
|
bool visitSwitch(Visit, TIntermSwitch *) override;
|
||||||
bool visitCase(Visit, TIntermCase *node) 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;
|
TIntermCase* intermCase;
|
||||||
};
|
};
|
||||||
union {
|
union {
|
||||||
|
TTypeSpecifierNonArray typeSpecifierNonArray;
|
||||||
TPublicType type;
|
TPublicType type;
|
||||||
TPrecision precision;
|
TPrecision precision;
|
||||||
TLayoutQualifier layoutQualifier;
|
TLayoutQualifier layoutQualifier;
|
||||||
@ -88,6 +89,8 @@ WHICH GENERATES THE GLSL ES PARSER (glslang_tab.cpp AND glslang_tab.h).
|
|||||||
TParameter param;
|
TParameter param;
|
||||||
TField* field;
|
TField* field;
|
||||||
TFieldList* fieldList;
|
TFieldList* fieldList;
|
||||||
|
TQualifierWrapperBase* qualifierWrapper;
|
||||||
|
TTypeQualifierBuilder* typeQualifierBuilder;
|
||||||
};
|
};
|
||||||
} interm;
|
} interm;
|
||||||
}
|
}
|
||||||
@ -205,13 +208,18 @@ extern void yyerror(YYLTYPE* yylloc, TParseContext* context, void *scanner, cons
|
|||||||
%type <interm> single_declaration init_declarator_list
|
%type <interm> single_declaration init_declarator_list
|
||||||
|
|
||||||
%type <interm> parameter_declaration parameter_declarator parameter_type_specifier
|
%type <interm> parameter_declaration parameter_declarator parameter_type_specifier
|
||||||
%type <interm.qualifier> parameter_qualifier parameter_type_qualifier
|
%type <interm.layoutQualifier> layout_qualifier_id_list layout_qualifier_id
|
||||||
%type <interm.layoutQualifier> layout_qualifier layout_qualifier_id_list layout_qualifier_id
|
|
||||||
|
%type <interm.type> fully_specified_type type_specifier
|
||||||
|
|
||||||
%type <interm.precision> precision_qualifier
|
%type <interm.precision> precision_qualifier
|
||||||
%type <interm.type> type_qualifier fully_specified_type type_specifier storage_qualifier interpolation_qualifier
|
%type <interm.layoutQualifier> layout_qualifier
|
||||||
%type <interm.type> type_specifier_no_prec type_specifier_nonarray
|
%type <interm.qualifier> storage_qualifier interpolation_qualifier
|
||||||
%type <interm.type> struct_specifier
|
%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.field> struct_declarator
|
||||||
%type <interm.fieldList> struct_declarator_list struct_declaration struct_declaration_list
|
%type <interm.fieldList> struct_declarator_list struct_declaration struct_declaration_list
|
||||||
%type <interm.function> function_header function_declarator function_identifier
|
%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");
|
context->error(@1, "precision is not supported in fragment shader", "highp");
|
||||||
}
|
}
|
||||||
if (!context->symbolTable.setDefaultPrecision( $3, $2 )) {
|
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;
|
$$ = 0;
|
||||||
}
|
}
|
||||||
| type_qualifier enter_struct struct_declaration_list RIGHT_BRACE SEMICOLON {
|
| type_qualifier enter_struct struct_declaration_list RIGHT_BRACE SEMICOLON {
|
||||||
ES3_OR_NEWER(getQualifierString($1.qualifier), @1, "interface blocks");
|
ES3_OR_NEWER($2.string->c_str(), @1, "interface blocks");
|
||||||
$$ = context->addInterfaceBlock($1, @2, *$2.string, $3, NULL, @$, NULL, @$);
|
$$ = context->addInterfaceBlock(*$1, @2, *$2.string, $3, NULL, @$, NULL, @$);
|
||||||
}
|
}
|
||||||
| type_qualifier enter_struct struct_declaration_list RIGHT_BRACE IDENTIFIER SEMICOLON {
|
| type_qualifier enter_struct struct_declaration_list RIGHT_BRACE IDENTIFIER SEMICOLON {
|
||||||
ES3_OR_NEWER(getQualifierString($1.qualifier), @1, "interface blocks");
|
ES3_OR_NEWER($2.string->c_str(), @1, "interface blocks");
|
||||||
$$ = context->addInterfaceBlock($1, @2, *$2.string, $3, $5.string, @5, NULL, @$);
|
$$ = 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 {
|
| 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");
|
ES3_OR_NEWER($2.string->c_str(), @1, "interface blocks");
|
||||||
$$ = context->addInterfaceBlock($1, @2, *$2.string, $3, $5.string, @5, $7, @6);
|
$$ = context->addInterfaceBlock(*$1, @2, *$2.string, $3, $5.string, @5, $7, @6);
|
||||||
}
|
}
|
||||||
| type_qualifier SEMICOLON {
|
| type_qualifier SEMICOLON {
|
||||||
context->parseGlobalLayoutQualifier($1);
|
context->parseGlobalLayoutQualifier(*$1);
|
||||||
$$ = 0;
|
$$ = 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_prototype
|
||||||
: function_declarator RIGHT_PAREN {
|
: function_declarator RIGHT_PAREN {
|
||||||
$$.function = context->parseFunctionDeclarator(@2, $1);
|
$$.function = context->parseFunctionDeclarator(@2, $1);
|
||||||
|
context->exitFunctionDeclaration();
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -675,13 +688,14 @@ function_header
|
|||||||
$$ = context->parseFunctionHeader($1, $2.string, @2);
|
$$ = context->parseFunctionHeader($1, $2.string, @2);
|
||||||
|
|
||||||
context->symbolTable.push();
|
context->symbolTable.push();
|
||||||
|
context->enterFunctionDeclaration();
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
parameter_declarator
|
parameter_declarator
|
||||||
// Type + name
|
// Type + name
|
||||||
: type_specifier identifier {
|
: type_specifier identifier {
|
||||||
if ($1.type == EbtVoid) {
|
if ($1.getBasicType() == EbtVoid) {
|
||||||
context->error(@2, "illegal use of type 'void'", $2.string->c_str());
|
context->error(@2, "illegal use of type 'void'", $2.string->c_str());
|
||||||
}
|
}
|
||||||
context->checkIsNotReserved(@2, *$2.string);
|
context->checkIsNotReserved(@2, *$2.string);
|
||||||
@ -713,41 +727,21 @@ parameter_declaration
|
|||||||
//
|
//
|
||||||
// Type + name
|
// Type + name
|
||||||
//
|
//
|
||||||
: parameter_type_qualifier parameter_qualifier parameter_declarator {
|
: type_qualifier parameter_declarator {
|
||||||
$$ = $3;
|
|
||||||
context->checkIsParameterQualifierValid(@3, $1, $2, $$.param.type);
|
|
||||||
}
|
|
||||||
| parameter_qualifier parameter_declarator {
|
|
||||||
$$ = $2;
|
$$ = $2;
|
||||||
context->checkOutParameterIsNotSampler(@2, $1, *$2.param.type);
|
context->checkIsParameterQualifierValid(@2, *$1, $2.param.type);
|
||||||
context->checkIsParameterQualifierValid(@2, EvqTemporary, $1, $$.param.type);
|
|
||||||
}
|
}
|
||||||
//
|
| parameter_declarator {
|
||||||
// Only type
|
$$ = $1;
|
||||||
//
|
$$.param.type->setQualifier(EvqIn);
|
||||||
| parameter_type_qualifier parameter_qualifier parameter_type_specifier {
|
|
||||||
$$ = $3;
|
|
||||||
context->checkIsParameterQualifierValid(@3, $1, $2, $$.param.type);
|
|
||||||
}
|
}
|
||||||
| parameter_qualifier parameter_type_specifier {
|
| type_qualifier parameter_type_specifier {
|
||||||
$$ = $2;
|
$$ = $2;
|
||||||
context->checkOutParameterIsNotSampler(@2, $1, *$2.param.type);
|
context->checkIsParameterQualifierValid(@2, *$1, $2.param.type);
|
||||||
context->checkIsParameterQualifierValid(@2, EvqTemporary, $1, $$.param.type);
|
|
||||||
}
|
}
|
||||||
;
|
| parameter_type_specifier {
|
||||||
|
$$ = $1;
|
||||||
parameter_qualifier
|
$$.param.type->setQualifier(EvqIn);
|
||||||
: /* empty */ {
|
|
||||||
$$ = EvqIn;
|
|
||||||
}
|
|
||||||
| IN_QUAL {
|
|
||||||
$$ = EvqIn;
|
|
||||||
}
|
|
||||||
| OUT_QUAL {
|
|
||||||
$$ = EvqOut;
|
|
||||||
}
|
|
||||||
| INOUT_QUAL {
|
|
||||||
$$ = EvqInOut;
|
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -813,10 +807,6 @@ single_declaration
|
|||||||
$$.type = $1;
|
$$.type = $1;
|
||||||
$$.intermAggregate = context->parseSingleInitDeclaration($$.type, @2, *$2.string, @3, $4);
|
$$.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
|
fully_specified_type
|
||||||
@ -830,124 +820,134 @@ fully_specified_type
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
| type_qualifier type_specifier {
|
| type_qualifier type_specifier {
|
||||||
$$ = context->addFullySpecifiedType($1.qualifier, $1.invariant, $1.layoutQualifier, $2);
|
$$ = context->addFullySpecifiedType(*$1, $2);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
interpolation_qualifier
|
interpolation_qualifier
|
||||||
: SMOOTH {
|
: SMOOTH {
|
||||||
$$.qualifier = EvqSmooth;
|
$$ = EvqSmooth;
|
||||||
}
|
}
|
||||||
| FLAT {
|
| FLAT {
|
||||||
$$.qualifier = EvqFlat;
|
$$ = EvqFlat;
|
||||||
}
|
|
||||||
;
|
|
||||||
|
|
||||||
parameter_type_qualifier
|
|
||||||
: CONST_QUAL {
|
|
||||||
$$ = EvqConst;
|
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
type_qualifier
|
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);
|
VERTEX_ONLY("attribute", @1);
|
||||||
ES2_ONLY("attribute", @1);
|
ES2_ONLY("attribute", @1);
|
||||||
context->checkIsAtGlobalLevel(@1, "attribute");
|
context->checkIsAtGlobalLevel(@1, "attribute");
|
||||||
$$.setBasic(EbtVoid, EvqAttribute, @1);
|
$$ = EvqAttribute;
|
||||||
}
|
}
|
||||||
| VARYING {
|
| VARYING {
|
||||||
ES2_ONLY("varying", @1);
|
ES2_ONLY("varying", @1);
|
||||||
context->checkIsAtGlobalLevel(@1, "varying");
|
context->checkIsAtGlobalLevel(@1, "varying");
|
||||||
if (context->getShaderType() == GL_VERTEX_SHADER)
|
if (context->getShaderType() == GL_VERTEX_SHADER)
|
||||||
$$.setBasic(EbtVoid, EvqVaryingOut, @1);
|
$$ = EvqVaryingOut;
|
||||||
else
|
else
|
||||||
$$.setBasic(EbtVoid, EvqVaryingIn, @1);
|
$$ = EvqVaryingIn;
|
||||||
}
|
}
|
||||||
| INVARIANT VARYING {
|
| CONST_QUAL {
|
||||||
ES2_ONLY("varying", @1);
|
$$ = EvqConst;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
| IN_QUAL {
|
| 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");
|
ES3_OR_NEWER("in", @1, "storage qualifier");
|
||||||
$$.qualifier = EvqFragmentIn;
|
$$ = EvqFragmentIn;
|
||||||
}
|
}
|
||||||
else if (context->getShaderType() == GL_VERTEX_SHADER)
|
else if (context->getShaderType() == GL_VERTEX_SHADER)
|
||||||
{
|
{
|
||||||
ES3_OR_NEWER("in", @1, "storage qualifier");
|
ES3_OR_NEWER("in", @1, "storage qualifier");
|
||||||
$$.qualifier = EvqVertexIn;
|
$$ = EvqVertexIn;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$$.qualifier = EvqComputeIn;
|
$$ = EvqComputeIn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
| OUT_QUAL {
|
| OUT_QUAL {
|
||||||
ES3_OR_NEWER("out", @1, "storage qualifier");
|
if (context->declaringFunction())
|
||||||
NON_COMPUTE_ONLY("out", @1);
|
{
|
||||||
$$.qualifier = (context->getShaderType() == GL_FRAGMENT_SHADER) ? EvqFragmentOut : EvqVertexOut;
|
$$ = 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 {
|
| INOUT_QUAL {
|
||||||
ES3_OR_NEWER("centroid in", @1, "storage qualifier");
|
if (!context->declaringFunction())
|
||||||
FRAG_ONLY("centroid in", @1);
|
{
|
||||||
$$.qualifier = EvqCentroidIn;
|
context->error(@1, "invalid inout qualifier", "'inout' can be only used with function parameters");
|
||||||
|
}
|
||||||
|
$$ = EvqInOut;
|
||||||
}
|
}
|
||||||
| CENTROID OUT_QUAL {
|
| CENTROID {
|
||||||
ES3_OR_NEWER("centroid out", @1, "storage qualifier");
|
ES3_OR_NEWER("centroid", @1, "storage qualifier");
|
||||||
VERTEX_ONLY("centroid out", @1);
|
$$ = EvqCentroid;
|
||||||
$$.qualifier = EvqCentroidOut;
|
|
||||||
}
|
}
|
||||||
| UNIFORM {
|
| UNIFORM {
|
||||||
context->checkIsAtGlobalLevel(@1, "uniform");
|
context->checkIsAtGlobalLevel(@1, "uniform");
|
||||||
$$.qualifier = EvqUniform;
|
$$ = EvqUniform;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -956,16 +956,7 @@ type_specifier
|
|||||||
$$ = $1;
|
$$ = $1;
|
||||||
|
|
||||||
if ($$.precision == EbpUndefined) {
|
if ($$.precision == EbpUndefined) {
|
||||||
$$.precision = context->symbolTable.getDefaultPrecision($1.type);
|
$$.precision = context->symbolTable.getDefaultPrecision($1.getBasicType());
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
@ -1012,17 +1003,16 @@ layout_qualifier_id
|
|||||||
|
|
||||||
type_specifier_no_prec
|
type_specifier_no_prec
|
||||||
: type_specifier_nonarray {
|
: type_specifier_nonarray {
|
||||||
$$ = $1;
|
$$.initialize($1, (context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary));
|
||||||
}
|
}
|
||||||
| type_specifier_nonarray LEFT_BRACKET RIGHT_BRACKET {
|
| type_specifier_nonarray LEFT_BRACKET RIGHT_BRACKET {
|
||||||
ES3_OR_NEWER("[]", @2, "implicitly sized array");
|
ES3_OR_NEWER("[]", @2, "implicitly sized array");
|
||||||
$$ = $1;
|
$$.initialize($1, (context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary));
|
||||||
$$.setArraySize(0);
|
$$.setArraySize(0);
|
||||||
}
|
}
|
||||||
| type_specifier_nonarray LEFT_BRACKET constant_expression RIGHT_BRACKET {
|
| type_specifier_nonarray LEFT_BRACKET constant_expression RIGHT_BRACKET {
|
||||||
$$ = $1;
|
$$.initialize($1, (context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary));
|
||||||
|
if (context->checkIsValidTypeForArray(@2, $$))
|
||||||
if (context->checkIsValidTypeForArray(@2, $1))
|
|
||||||
{
|
{
|
||||||
unsigned int size = context->checkIsValidArraySize(@2, $3);
|
unsigned int size = context->checkIsValidArraySize(@2, $3);
|
||||||
$$.setArraySize(size);
|
$$.setArraySize(size);
|
||||||
@ -1032,208 +1022,164 @@ type_specifier_no_prec
|
|||||||
|
|
||||||
type_specifier_nonarray
|
type_specifier_nonarray
|
||||||
: VOID_TYPE {
|
: VOID_TYPE {
|
||||||
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
$$.initialize(EbtVoid, @1);
|
||||||
$$.setBasic(EbtVoid, qual, @1);
|
|
||||||
}
|
}
|
||||||
| FLOAT_TYPE {
|
| FLOAT_TYPE {
|
||||||
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
$$.initialize(EbtFloat, @1);
|
||||||
$$.setBasic(EbtFloat, qual, @1);
|
|
||||||
}
|
}
|
||||||
| INT_TYPE {
|
| INT_TYPE {
|
||||||
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
$$.initialize(EbtInt, @1);
|
||||||
$$.setBasic(EbtInt, qual, @1);
|
|
||||||
}
|
}
|
||||||
| UINT_TYPE {
|
| UINT_TYPE {
|
||||||
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
$$.initialize(EbtUInt, @1);
|
||||||
$$.setBasic(EbtUInt, qual, @1);
|
|
||||||
}
|
}
|
||||||
| BOOL_TYPE {
|
| BOOL_TYPE {
|
||||||
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
$$.initialize(EbtBool, @1);
|
||||||
$$.setBasic(EbtBool, qual, @1);
|
|
||||||
}
|
}
|
||||||
| VEC2 {
|
| VEC2 {
|
||||||
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
$$.initialize(EbtFloat, @1);
|
||||||
$$.setBasic(EbtFloat, qual, @1);
|
|
||||||
$$.setAggregate(2);
|
$$.setAggregate(2);
|
||||||
}
|
}
|
||||||
| VEC3 {
|
| VEC3 {
|
||||||
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
$$.initialize(EbtFloat, @1);
|
||||||
$$.setBasic(EbtFloat, qual, @1);
|
|
||||||
$$.setAggregate(3);
|
$$.setAggregate(3);
|
||||||
}
|
}
|
||||||
| VEC4 {
|
| VEC4 {
|
||||||
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
$$.initialize(EbtFloat, @1);
|
||||||
$$.setBasic(EbtFloat, qual, @1);
|
|
||||||
$$.setAggregate(4);
|
$$.setAggregate(4);
|
||||||
}
|
}
|
||||||
| BVEC2 {
|
| BVEC2 {
|
||||||
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
$$.initialize(EbtBool, @1);
|
||||||
$$.setBasic(EbtBool, qual, @1);
|
|
||||||
$$.setAggregate(2);
|
$$.setAggregate(2);
|
||||||
}
|
}
|
||||||
| BVEC3 {
|
| BVEC3 {
|
||||||
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
$$.initialize(EbtBool, @1);
|
||||||
$$.setBasic(EbtBool, qual, @1);
|
|
||||||
$$.setAggregate(3);
|
$$.setAggregate(3);
|
||||||
}
|
}
|
||||||
| BVEC4 {
|
| BVEC4 {
|
||||||
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
$$.initialize(EbtBool, @1);
|
||||||
$$.setBasic(EbtBool, qual, @1);
|
|
||||||
$$.setAggregate(4);
|
$$.setAggregate(4);
|
||||||
}
|
}
|
||||||
| IVEC2 {
|
| IVEC2 {
|
||||||
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
$$.initialize(EbtInt, @1);
|
||||||
$$.setBasic(EbtInt, qual, @1);
|
|
||||||
$$.setAggregate(2);
|
$$.setAggregate(2);
|
||||||
}
|
}
|
||||||
| IVEC3 {
|
| IVEC3 {
|
||||||
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
$$.initialize(EbtInt, @1);
|
||||||
$$.setBasic(EbtInt, qual, @1);
|
|
||||||
$$.setAggregate(3);
|
$$.setAggregate(3);
|
||||||
}
|
}
|
||||||
| IVEC4 {
|
| IVEC4 {
|
||||||
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
$$.initialize(EbtInt, @1);
|
||||||
$$.setBasic(EbtInt, qual, @1);
|
|
||||||
$$.setAggregate(4);
|
$$.setAggregate(4);
|
||||||
}
|
}
|
||||||
| UVEC2 {
|
| UVEC2 {
|
||||||
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
$$.initialize(EbtUInt, @1);
|
||||||
$$.setBasic(EbtUInt, qual, @1);
|
|
||||||
$$.setAggregate(2);
|
$$.setAggregate(2);
|
||||||
}
|
}
|
||||||
| UVEC3 {
|
| UVEC3 {
|
||||||
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
$$.initialize(EbtUInt, @1);
|
||||||
$$.setBasic(EbtUInt, qual, @1);
|
|
||||||
$$.setAggregate(3);
|
$$.setAggregate(3);
|
||||||
}
|
}
|
||||||
| UVEC4 {
|
| UVEC4 {
|
||||||
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
$$.initialize(EbtUInt, @1);
|
||||||
$$.setBasic(EbtUInt, qual, @1);
|
|
||||||
$$.setAggregate(4);
|
$$.setAggregate(4);
|
||||||
}
|
}
|
||||||
| MATRIX2 {
|
| MATRIX2 {
|
||||||
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
$$.initialize(EbtFloat, @1);
|
||||||
$$.setBasic(EbtFloat, qual, @1);
|
|
||||||
$$.setMatrix(2, 2);
|
$$.setMatrix(2, 2);
|
||||||
}
|
}
|
||||||
| MATRIX3 {
|
| MATRIX3 {
|
||||||
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
$$.initialize(EbtFloat, @1);
|
||||||
$$.setBasic(EbtFloat, qual, @1);
|
|
||||||
$$.setMatrix(3, 3);
|
$$.setMatrix(3, 3);
|
||||||
}
|
}
|
||||||
| MATRIX4 {
|
| MATRIX4 {
|
||||||
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
$$.initialize(EbtFloat, @1);
|
||||||
$$.setBasic(EbtFloat, qual, @1);
|
|
||||||
$$.setMatrix(4, 4);
|
$$.setMatrix(4, 4);
|
||||||
}
|
}
|
||||||
| MATRIX2x3 {
|
| MATRIX2x3 {
|
||||||
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
$$.initialize(EbtFloat, @1);
|
||||||
$$.setBasic(EbtFloat, qual, @1);
|
|
||||||
$$.setMatrix(2, 3);
|
$$.setMatrix(2, 3);
|
||||||
}
|
}
|
||||||
| MATRIX3x2 {
|
| MATRIX3x2 {
|
||||||
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
$$.initialize(EbtFloat, @1);
|
||||||
$$.setBasic(EbtFloat, qual, @1);
|
|
||||||
$$.setMatrix(3, 2);
|
$$.setMatrix(3, 2);
|
||||||
}
|
}
|
||||||
| MATRIX2x4 {
|
| MATRIX2x4 {
|
||||||
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
$$.initialize(EbtFloat, @1);
|
||||||
$$.setBasic(EbtFloat, qual, @1);
|
|
||||||
$$.setMatrix(2, 4);
|
$$.setMatrix(2, 4);
|
||||||
}
|
}
|
||||||
| MATRIX4x2 {
|
| MATRIX4x2 {
|
||||||
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
$$.initialize(EbtFloat, @1);
|
||||||
$$.setBasic(EbtFloat, qual, @1);
|
|
||||||
$$.setMatrix(4, 2);
|
$$.setMatrix(4, 2);
|
||||||
}
|
}
|
||||||
| MATRIX3x4 {
|
| MATRIX3x4 {
|
||||||
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
$$.initialize(EbtFloat, @1);
|
||||||
$$.setBasic(EbtFloat, qual, @1);
|
|
||||||
$$.setMatrix(3, 4);
|
$$.setMatrix(3, 4);
|
||||||
}
|
}
|
||||||
| MATRIX4x3 {
|
| MATRIX4x3 {
|
||||||
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
$$.initialize(EbtFloat, @1);
|
||||||
$$.setBasic(EbtFloat, qual, @1);
|
|
||||||
$$.setMatrix(4, 3);
|
$$.setMatrix(4, 3);
|
||||||
}
|
}
|
||||||
| SAMPLER2D {
|
| SAMPLER2D {
|
||||||
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
$$.initialize(EbtSampler2D, @1);
|
||||||
$$.setBasic(EbtSampler2D, qual, @1);
|
|
||||||
}
|
}
|
||||||
| SAMPLER3D {
|
| SAMPLER3D {
|
||||||
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
$$.initialize(EbtSampler3D, @1);
|
||||||
$$.setBasic(EbtSampler3D, qual, @1);
|
|
||||||
}
|
}
|
||||||
| SAMPLERCUBE {
|
| SAMPLERCUBE {
|
||||||
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
$$.initialize(EbtSamplerCube, @1);
|
||||||
$$.setBasic(EbtSamplerCube, qual, @1);
|
|
||||||
}
|
}
|
||||||
| SAMPLER2DARRAY {
|
| SAMPLER2DARRAY {
|
||||||
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
$$.initialize(EbtSampler2DArray, @1);
|
||||||
$$.setBasic(EbtSampler2DArray, qual, @1);
|
|
||||||
}
|
}
|
||||||
| ISAMPLER2D {
|
| ISAMPLER2D {
|
||||||
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
$$.initialize(EbtISampler2D, @1);
|
||||||
$$.setBasic(EbtISampler2D, qual, @1);
|
|
||||||
}
|
}
|
||||||
| ISAMPLER3D {
|
| ISAMPLER3D {
|
||||||
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
$$.initialize(EbtISampler3D, @1);
|
||||||
$$.setBasic(EbtISampler3D, qual, @1);
|
|
||||||
}
|
}
|
||||||
| ISAMPLERCUBE {
|
| ISAMPLERCUBE {
|
||||||
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
$$.initialize(EbtISamplerCube, @1);
|
||||||
$$.setBasic(EbtISamplerCube, qual, @1);
|
|
||||||
}
|
}
|
||||||
| ISAMPLER2DARRAY {
|
| ISAMPLER2DARRAY {
|
||||||
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
$$.initialize(EbtISampler2DArray, @1);
|
||||||
$$.setBasic(EbtISampler2DArray, qual, @1);
|
|
||||||
}
|
}
|
||||||
| USAMPLER2D {
|
| USAMPLER2D {
|
||||||
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
$$.initialize(EbtUSampler2D, @1);
|
||||||
$$.setBasic(EbtUSampler2D, qual, @1);
|
|
||||||
}
|
}
|
||||||
| USAMPLER3D {
|
| USAMPLER3D {
|
||||||
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
$$.initialize(EbtUSampler3D, @1);
|
||||||
$$.setBasic(EbtUSampler3D, qual, @1);
|
|
||||||
}
|
}
|
||||||
| USAMPLERCUBE {
|
| USAMPLERCUBE {
|
||||||
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
$$.initialize(EbtUSamplerCube, @1);
|
||||||
$$.setBasic(EbtUSamplerCube, qual, @1);
|
|
||||||
}
|
}
|
||||||
| USAMPLER2DARRAY {
|
| USAMPLER2DARRAY {
|
||||||
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
$$.initialize(EbtUSampler2DArray, @1);
|
||||||
$$.setBasic(EbtUSampler2DArray, qual, @1);
|
|
||||||
}
|
}
|
||||||
| SAMPLER2DSHADOW {
|
| SAMPLER2DSHADOW {
|
||||||
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
$$.initialize(EbtSampler2DShadow, @1);
|
||||||
$$.setBasic(EbtSampler2DShadow, qual, @1);
|
|
||||||
}
|
}
|
||||||
| SAMPLERCUBESHADOW {
|
| SAMPLERCUBESHADOW {
|
||||||
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
$$.initialize(EbtSamplerCubeShadow, @1);
|
||||||
$$.setBasic(EbtSamplerCubeShadow, qual, @1);
|
|
||||||
}
|
}
|
||||||
| SAMPLER2DARRAYSHADOW {
|
| SAMPLER2DARRAYSHADOW {
|
||||||
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
$$.initialize(EbtSampler2DArrayShadow, @1);
|
||||||
$$.setBasic(EbtSampler2DArrayShadow, qual, @1);
|
|
||||||
}
|
}
|
||||||
| SAMPLER_EXTERNAL_OES {
|
| SAMPLER_EXTERNAL_OES {
|
||||||
if (!context->supportsExtension("GL_OES_EGL_image_external") &&
|
if (!context->supportsExtension("GL_OES_EGL_image_external") &&
|
||||||
!context->supportsExtension("GL_NV_EGL_stream_consumer_external")) {
|
!context->supportsExtension("GL_NV_EGL_stream_consumer_external")) {
|
||||||
context->error(@1, "unsupported type", "samplerExternalOES");
|
context->error(@1, "unsupported type", "samplerExternalOES");
|
||||||
}
|
}
|
||||||
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
$$.initialize(EbtSamplerExternalOES, @1);
|
||||||
$$.setBasic(EbtSamplerExternalOES, qual, @1);
|
|
||||||
}
|
}
|
||||||
| SAMPLER2DRECT {
|
| SAMPLER2DRECT {
|
||||||
if (!context->supportsExtension("GL_ARB_texture_rectangle")) {
|
if (!context->supportsExtension("GL_ARB_texture_rectangle")) {
|
||||||
context->error(@1, "unsupported type", "sampler2DRect");
|
context->error(@1, "unsupported type", "sampler2DRect");
|
||||||
}
|
}
|
||||||
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
$$.initialize(EbtSampler2DRect, @1);
|
||||||
$$.setBasic(EbtSampler2DRect, qual, @1);
|
|
||||||
}
|
}
|
||||||
| struct_specifier {
|
| struct_specifier {
|
||||||
$$ = $1;
|
$$ = $1;
|
||||||
$$.qualifier = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
|
||||||
}
|
}
|
||||||
| TYPE_NAME {
|
| TYPE_NAME {
|
||||||
//
|
//
|
||||||
@ -1241,8 +1187,7 @@ type_specifier_nonarray
|
|||||||
// type.
|
// type.
|
||||||
//
|
//
|
||||||
TType& structure = static_cast<TVariable*>($1.symbol)->getType();
|
TType& structure = static_cast<TVariable*>($1.symbol)->getType();
|
||||||
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
$$.initialize(EbtStruct, @1);
|
||||||
$$.setBasic(EbtStruct, qual, @1);
|
|
||||||
$$.userDef = &structure;
|
$$.userDef = &structure;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
@ -1280,9 +1225,7 @@ struct_declaration
|
|||||||
}
|
}
|
||||||
| type_qualifier type_specifier struct_declarator_list SEMICOLON {
|
| type_qualifier type_specifier struct_declarator_list SEMICOLON {
|
||||||
// ES3 Only, but errors should be handled elsewhere
|
// ES3 Only, but errors should be handled elsewhere
|
||||||
$2.qualifier = $1.qualifier;
|
$$ = context->addStructDeclaratorListWithQualifiers(*$1, &$2, $3);
|
||||||
$2.layoutQualifier = $1.layoutQualifier;
|
|
||||||
$$ = context->addStructDeclaratorList($2, $3);
|
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -208,6 +208,7 @@ union YYSTYPE
|
|||||||
TIntermCase* intermCase;
|
TIntermCase* intermCase;
|
||||||
};
|
};
|
||||||
union {
|
union {
|
||||||
|
TTypeSpecifierNonArray typeSpecifierNonArray;
|
||||||
TPublicType type;
|
TPublicType type;
|
||||||
TPrecision precision;
|
TPrecision precision;
|
||||||
TLayoutQualifier layoutQualifier;
|
TLayoutQualifier layoutQualifier;
|
||||||
@ -216,6 +217,8 @@ union YYSTYPE
|
|||||||
TParameter param;
|
TParameter param;
|
||||||
TField* field;
|
TField* field;
|
||||||
TFieldList* fieldList;
|
TFieldList* fieldList;
|
||||||
|
TQualifierWrapperBase *qualifierWrapper;
|
||||||
|
TTypeQualifierBuilder *typeQualifierBuilder;
|
||||||
};
|
};
|
||||||
} interm;
|
} interm;
|
||||||
|
|
||||||
|
@ -44,10 +44,12 @@ class TOutputTraverser : public TIntermTraverser
|
|||||||
void visitConstantUnion(TIntermConstantUnion *) override;
|
void visitConstantUnion(TIntermConstantUnion *) override;
|
||||||
bool visitBinary(Visit visit, TIntermBinary *) override;
|
bool visitBinary(Visit visit, TIntermBinary *) override;
|
||||||
bool visitUnary(Visit visit, TIntermUnary *) override;
|
bool visitUnary(Visit visit, TIntermUnary *) override;
|
||||||
|
bool visitTernary(Visit visit, TIntermTernary *node) override;
|
||||||
bool visitSelection(Visit visit, TIntermSelection *) override;
|
bool visitSelection(Visit visit, TIntermSelection *) override;
|
||||||
bool visitAggregate(Visit visit, TIntermAggregate *) override;
|
bool visitAggregate(Visit visit, TIntermAggregate *) override;
|
||||||
bool visitLoop(Visit visit, TIntermLoop *) override;
|
bool visitLoop(Visit visit, TIntermLoop *) override;
|
||||||
bool visitBranch(Visit visit, TIntermBranch *) 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;
|
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)
|
bool TOutputTraverser::visitSelection(Visit visit, TIntermSelection *node)
|
||||||
{
|
{
|
||||||
TInfoSinkBase &out = sink;
|
TInfoSinkBase &out = sink;
|
||||||
|
|
||||||
OutputTreeText(out, node, mDepth);
|
OutputTreeText(out, node, mDepth);
|
||||||
|
|
||||||
out << "Test condition and select";
|
out << "If test\n";
|
||||||
out << " (" << node->getCompleteString() << ")\n";
|
|
||||||
|
|
||||||
++mDepth;
|
++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:
|
case GL_FLOAT:
|
||||||
return TType(EbtFloat);
|
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)
|
TOperator TypeToConstructorOperator(const TType &type)
|
||||||
{
|
{
|
||||||
switch (type.getBasicType())
|
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<Uniform> *);
|
||||||
template void GetVariableTraverser::traverse(const TType &, const TString &, std::vector<Varying> *);
|
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);
|
bool IsVarying(TQualifier qualifier);
|
||||||
InterpolationType GetInterpolationType(TQualifier qualifier);
|
InterpolationType GetInterpolationType(TQualifier qualifier);
|
||||||
TString ArrayString(const TType &type);
|
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);
|
TOperator TypeToConstructorOperator(const TType &type);
|
||||||
|
|
||||||
@ -65,6 +66,10 @@ class GetVariableTraverser : angle::NonCopyable
|
|||||||
const TSymbolTable &mSymbolTable;
|
const TSymbolTable &mSymbolTable;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool IsBuiltinOutputVariable(TQualifier qualifier);
|
||||||
|
bool IsBuiltinFragmentInputVariable(TQualifier qualifier);
|
||||||
|
bool CanBeInvariantESSL1(TQualifier qualifier);
|
||||||
|
bool CanBeInvariantESSL3OrGreater(TQualifier qualifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // COMPILER_TRANSLATOR_UTIL_H_
|
#endif // COMPILER_TRANSLATOR_UTIL_H_
|
||||||
|
@ -44,45 +44,33 @@ const std::string &Buffer::getLabel() const
|
|||||||
return mLabel;
|
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);
|
ANGLE_TRY(mBuffer->setData(target, data, size, usage));
|
||||||
if (error.isError())
|
|
||||||
{
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
mIndexRangeCache.clear();
|
mIndexRangeCache.clear();
|
||||||
mUsage = usage;
|
mUsage = usage;
|
||||||
mSize = size;
|
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);
|
ANGLE_TRY(mBuffer->setSubData(target, data, size, offset));
|
||||||
if (error.isError())
|
|
||||||
{
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
mIndexRangeCache.invalidateRange(static_cast<unsigned int>(offset), static_cast<unsigned int>(size));
|
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)
|
Error Buffer::copyBufferSubData(Buffer* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size)
|
||||||
{
|
{
|
||||||
gl::Error error = mBuffer->copySubData(source->getImplementation(), sourceOffset, destOffset, size);
|
ANGLE_TRY(mBuffer->copySubData(source->getImplementation(), sourceOffset, destOffset, size));
|
||||||
if (error.isError())
|
|
||||||
{
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
mIndexRangeCache.invalidateRange(static_cast<unsigned int>(destOffset), static_cast<unsigned int>(size));
|
mIndexRangeCache.invalidateRange(static_cast<unsigned int>(destOffset), static_cast<unsigned int>(size));
|
||||||
|
|
||||||
return error;
|
return NoError();
|
||||||
}
|
}
|
||||||
|
|
||||||
Error Buffer::map(GLenum access)
|
Error Buffer::map(GLenum access)
|
||||||
@ -178,18 +166,14 @@ Error Buffer::getIndexRange(GLenum type,
|
|||||||
{
|
{
|
||||||
if (mIndexRangeCache.findRange(type, offset, count, primitiveRestartEnabled, outRange))
|
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);
|
ANGLE_TRY(mBuffer->getIndexRange(type, offset, count, primitiveRestartEnabled, outRange));
|
||||||
if (error.isError())
|
|
||||||
{
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
mIndexRangeCache.addRange(type, offset, count, primitiveRestartEnabled, *outRange);
|
mIndexRangeCache.addRange(type, offset, count, primitiveRestartEnabled, *outRange);
|
||||||
|
|
||||||
return Error(GL_NO_ERROR);
|
return NoError();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace gl
|
} // namespace gl
|
||||||
|
@ -34,8 +34,8 @@ class Buffer final : public RefCountObject, public LabeledObject
|
|||||||
void setLabel(const std::string &label) override;
|
void setLabel(const std::string &label) override;
|
||||||
const std::string &getLabel() const override;
|
const std::string &getLabel() const override;
|
||||||
|
|
||||||
Error bufferData(const void *data, GLsizeiptr size, GLenum usage);
|
Error bufferData(GLenum target, const void *data, GLsizeiptr size, GLenum usage);
|
||||||
Error bufferSubData(const void *data, GLsizeiptr size, GLintptr offset);
|
Error bufferSubData(GLenum target, const void *data, GLsizeiptr size, GLintptr offset);
|
||||||
Error copyBufferSubData(Buffer* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size);
|
Error copyBufferSubData(Buffer* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size);
|
||||||
Error map(GLenum access);
|
Error map(GLenum access);
|
||||||
Error mapRange(GLintptr offset, GLsizeiptr length, GLbitfield access);
|
Error mapRange(GLintptr offset, GLsizeiptr length, GLbitfield access);
|
||||||
|
@ -3430,4 +3430,23 @@ void Context::popDebugGroup()
|
|||||||
mGLState.getDebug().popGroup();
|
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
|
} // namespace gl
|
||||||
|
@ -567,6 +567,9 @@ class Context final : public ValidationContext
|
|||||||
GLint components,
|
GLint components,
|
||||||
const GLfloat *coeffs);
|
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;
|
void handleError(const Error &error) override;
|
||||||
|
|
||||||
GLenum getError();
|
GLenum getError();
|
||||||
|
@ -135,7 +135,12 @@ ImageIndexIterator::ImageIndexIterator(GLenum type, const Range<GLint> &mipRange
|
|||||||
|
|
||||||
GLint ImageIndexIterator::maxLayer() const
|
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()
|
ImageIndex ImageIndexIterator::next()
|
||||||
@ -149,21 +154,29 @@ ImageIndex ImageIndexIterator::next()
|
|||||||
|
|
||||||
if (mCurrentLayer != ImageIndex::ENTIRE_LEVEL)
|
if (mCurrentLayer != ImageIndex::ENTIRE_LEVEL)
|
||||||
{
|
{
|
||||||
if (mCurrentLayer < maxLayer()-1)
|
if (mCurrentLayer < maxLayer() - 1)
|
||||||
{
|
{
|
||||||
mCurrentLayer++;
|
mCurrentLayer++;
|
||||||
}
|
}
|
||||||
else if (mCurrentMip < mMipRange.end-1)
|
else if (mCurrentMip < mMipRange.end - 1)
|
||||||
{
|
{
|
||||||
mCurrentMip++;
|
mCurrentMip++;
|
||||||
mCurrentLayer = mLayerRange.start;
|
mCurrentLayer = mLayerRange.start;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
done();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (mCurrentMip < mMipRange.end-1)
|
else if (mCurrentMip < mMipRange.end - 1)
|
||||||
{
|
{
|
||||||
mCurrentMip++;
|
mCurrentMip++;
|
||||||
mCurrentLayer = mLayerRange.start;
|
mCurrentLayer = mLayerRange.start;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
@ -185,4 +198,10 @@ bool ImageIndexIterator::hasNext() const
|
|||||||
return (mCurrentMip < mMipRange.end || mCurrentLayer < maxLayer());
|
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);
|
const Range<GLint> &layerRange, const GLsizei *layerCounts);
|
||||||
|
|
||||||
GLint maxLayer() const;
|
GLint maxLayer() const;
|
||||||
|
void done();
|
||||||
|
|
||||||
GLenum mType;
|
GLenum mType;
|
||||||
Range<GLint> mMipRange;
|
Range<GLint> mMipRange;
|
||||||
|
@ -41,6 +41,8 @@ TEST(ImageIndexTest, Iterator2D)
|
|||||||
EXPECT_EQ(current.mipIndex, nextIndex.mipIndex);
|
EXPECT_EQ(current.mipIndex, nextIndex.mipIndex);
|
||||||
EXPECT_EQ(current.layerIndex, nextIndex.layerIndex);
|
EXPECT_EQ(current.layerIndex, nextIndex.layerIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EXPECT_FALSE(iter.hasNext());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ImageIndexTest, IteratorCube)
|
TEST(ImageIndexTest, IteratorCube)
|
||||||
@ -64,6 +66,8 @@ TEST(ImageIndexTest, IteratorCube)
|
|||||||
EXPECT_TRUE(nextIndex.hasLayer());
|
EXPECT_TRUE(nextIndex.hasLayer());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EXPECT_FALSE(iter.hasNext());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ImageIndexTest, Iterator3D)
|
TEST(ImageIndexTest, Iterator3D)
|
||||||
@ -85,6 +89,8 @@ TEST(ImageIndexTest, Iterator3D)
|
|||||||
EXPECT_TRUE(nextIndex.hasLayer());
|
EXPECT_TRUE(nextIndex.hasLayer());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EXPECT_FALSE(iter.hasNext());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ImageIndexTest, Iterator2DArray)
|
TEST(ImageIndexTest, Iterator2DArray)
|
||||||
@ -109,6 +115,8 @@ TEST(ImageIndexTest, Iterator2DArray)
|
|||||||
EXPECT_TRUE(nextIndex.hasLayer());
|
EXPECT_TRUE(nextIndex.hasLayer());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EXPECT_FALSE(iter.hasNext());
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -243,9 +243,9 @@ void Shader::compile(Compiler *compiler)
|
|||||||
std::stringstream sourceStream;
|
std::stringstream sourceStream;
|
||||||
|
|
||||||
std::string sourcePath;
|
std::string sourcePath;
|
||||||
int additionalOptions =
|
ShCompileOptions additionalOptions =
|
||||||
mImplementation->prepareSourceAndReturnOptions(&sourceStream, &sourcePath);
|
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
|
// 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
|
// 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);
|
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
|
// 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
|
// From GL_EXT_texture_norm16
|
||||||
// | Internal format | R | G | B | A |S | Format | Type | Component type | SRGB | Texture supported | Renderable | Filterable |
|
// | 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/Preprocessor.cpp',
|
||||||
'../compiler/preprocessor/Token.cpp',
|
'../compiler/preprocessor/Token.cpp',
|
||||||
'../compiler/preprocessor/Tokenizer.cpp',
|
'../compiler/preprocessor/Tokenizer.cpp',
|
||||||
|
'../compiler/translator/AddAndTrueToLoopCondition.cpp',
|
||||||
'../compiler/translator/AddDefaultReturnStatements.cpp',
|
'../compiler/translator/AddDefaultReturnStatements.cpp',
|
||||||
'../compiler/translator/ArrayReturnValueToOutParameter.cpp',
|
'../compiler/translator/ArrayReturnValueToOutParameter.cpp',
|
||||||
'../compiler/translator/ASTMetadataHLSL.cpp',
|
'../compiler/translator/ASTMetadataHLSL.cpp',
|
||||||
'../compiler/translator/blocklayout.cpp',
|
'../compiler/translator/blocklayout.cpp',
|
||||||
'../compiler/translator/blocklayoutHLSL.cpp',
|
'../compiler/translator/blocklayoutHLSL.cpp',
|
||||||
|
'../compiler/translator/BreakVariableAliasingInInnerLoops.cpp',
|
||||||
'../compiler/translator/BuiltInFunctionEmulator.cpp',
|
'../compiler/translator/BuiltInFunctionEmulator.cpp',
|
||||||
'../compiler/translator/BuiltInFunctionEmulatorGLSL.cpp',
|
'../compiler/translator/BuiltInFunctionEmulatorGLSL.cpp',
|
||||||
'../compiler/translator/BuiltInFunctionEmulatorHLSL.cpp',
|
'../compiler/translator/BuiltInFunctionEmulatorHLSL.cpp',
|
||||||
@ -41,11 +43,8 @@ UNIFIED_SOURCES += [
|
|||||||
'../compiler/translator/CallDAG.cpp',
|
'../compiler/translator/CallDAG.cpp',
|
||||||
'../compiler/translator/CodeGen.cpp',
|
'../compiler/translator/CodeGen.cpp',
|
||||||
'../compiler/translator/Compiler.cpp',
|
'../compiler/translator/Compiler.cpp',
|
||||||
|
'../compiler/translator/ConstantUnion.cpp',
|
||||||
'../compiler/translator/DeferGlobalInitializers.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/Diagnostics.cpp',
|
||||||
'../compiler/translator/DirectiveHandler.cpp',
|
'../compiler/translator/DirectiveHandler.cpp',
|
||||||
'../compiler/translator/EmulatePrecision.cpp',
|
'../compiler/translator/EmulatePrecision.cpp',
|
||||||
@ -72,6 +71,7 @@ UNIFIED_SOURCES += [
|
|||||||
'../compiler/translator/ParseContext.cpp',
|
'../compiler/translator/ParseContext.cpp',
|
||||||
'../compiler/translator/PoolAlloc.cpp',
|
'../compiler/translator/PoolAlloc.cpp',
|
||||||
'../compiler/translator/PruneEmptyDeclarations.cpp',
|
'../compiler/translator/PruneEmptyDeclarations.cpp',
|
||||||
|
'../compiler/translator/QualifierTypes.cpp',
|
||||||
'../compiler/translator/RecordConstantPrecision.cpp',
|
'../compiler/translator/RecordConstantPrecision.cpp',
|
||||||
'../compiler/translator/RegenerateStructNames.cpp',
|
'../compiler/translator/RegenerateStructNames.cpp',
|
||||||
'../compiler/translator/RemoveDynamicIndexing.cpp',
|
'../compiler/translator/RemoveDynamicIndexing.cpp',
|
||||||
@ -92,8 +92,6 @@ UNIFIED_SOURCES += [
|
|||||||
'../compiler/translator/StructureHLSL.cpp',
|
'../compiler/translator/StructureHLSL.cpp',
|
||||||
'../compiler/translator/SymbolTable.cpp',
|
'../compiler/translator/SymbolTable.cpp',
|
||||||
'../compiler/translator/TextureFunctionHLSL.cpp',
|
'../compiler/translator/TextureFunctionHLSL.cpp',
|
||||||
'../compiler/translator/timing/RestrictFragmentShaderTiming.cpp',
|
|
||||||
'../compiler/translator/timing/RestrictVertexShaderTiming.cpp',
|
|
||||||
'../compiler/translator/TranslatorESSL.cpp',
|
'../compiler/translator/TranslatorESSL.cpp',
|
||||||
'../compiler/translator/TranslatorGLSL.cpp',
|
'../compiler/translator/TranslatorGLSL.cpp',
|
||||||
'../compiler/translator/TranslatorHLSL.cpp',
|
'../compiler/translator/TranslatorHLSL.cpp',
|
||||||
|
@ -86,17 +86,6 @@ QueryT CastStateValue(GLenum pname, NativeT value)
|
|||||||
|
|
||||||
} // anonymous namespace
|
} // 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>
|
template <typename QueryT>
|
||||||
void CastStateValues(Context *context, GLenum nativeType, GLenum pname,
|
void CastStateValues(Context *context, GLenum nativeType, GLenum pname,
|
||||||
unsigned int numParams, QueryT *outParams)
|
unsigned int numParams, QueryT *outParams)
|
||||||
|
@ -23,7 +23,33 @@ class Context;
|
|||||||
template <typename GLType>
|
template <typename GLType>
|
||||||
struct GLTypeToGLenum
|
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
|
// The GL state query API types are: bool, int, uint, float, int64
|
||||||
|
@ -23,8 +23,8 @@ class BufferImpl : angle::NonCopyable
|
|||||||
public:
|
public:
|
||||||
virtual ~BufferImpl() { }
|
virtual ~BufferImpl() { }
|
||||||
|
|
||||||
virtual gl::Error setData(const void *data, size_t size, GLenum usage) = 0;
|
virtual gl::Error setData(GLenum target, 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 setSubData(GLenum target, const void *data, size_t size, size_t offset) = 0;
|
||||||
virtual gl::Error copySubData(BufferImpl *source,
|
virtual gl::Error copySubData(BufferImpl *source,
|
||||||
GLintptr sourceOffset,
|
GLintptr sourceOffset,
|
||||||
GLintptr destOffset,
|
GLintptr destOffset,
|
||||||
|
@ -21,8 +21,8 @@ class MockBufferImpl : public BufferImpl
|
|||||||
public:
|
public:
|
||||||
~MockBufferImpl() { destructor(); }
|
~MockBufferImpl() { destructor(); }
|
||||||
|
|
||||||
MOCK_METHOD3(setData, gl::Error(const void*, size_t, GLenum));
|
MOCK_METHOD4(setData, gl::Error(GLenum, const void *, size_t, GLenum));
|
||||||
MOCK_METHOD3(setSubData, gl::Error(const void*, size_t, size_t));
|
MOCK_METHOD4(setSubData, gl::Error(GLenum, const void *, size_t, size_t));
|
||||||
MOCK_METHOD4(copySubData, gl::Error(BufferImpl *, GLintptr, GLintptr, GLsizeiptr));
|
MOCK_METHOD4(copySubData, gl::Error(BufferImpl *, GLintptr, GLintptr, GLsizeiptr));
|
||||||
MOCK_METHOD2(map, gl::Error(GLenum, GLvoid **));
|
MOCK_METHOD2(map, gl::Error(GLenum, GLvoid **));
|
||||||
MOCK_METHOD4(mapRange, gl::Error(size_t, size_t, GLbitfield, GLvoid **));
|
MOCK_METHOD4(mapRange, gl::Error(size_t, size_t, GLbitfield, GLvoid **));
|
||||||
|
@ -22,8 +22,8 @@ class ShaderImpl : angle::NonCopyable
|
|||||||
virtual ~ShaderImpl() { }
|
virtual ~ShaderImpl() { }
|
||||||
|
|
||||||
// Returns additional ShCompile options.
|
// Returns additional ShCompile options.
|
||||||
virtual int prepareSourceAndReturnOptions(std::stringstream *sourceStream,
|
virtual ShCompileOptions prepareSourceAndReturnOptions(std::stringstream *sourceStream,
|
||||||
std::string *sourcePath) = 0;
|
std::string *sourcePath) = 0;
|
||||||
// Returns success for compiling on the driver. Returns success.
|
// Returns success for compiling on the driver. Returns success.
|
||||||
virtual bool postTranslateCompile(gl::Compiler *compiler, std::string *infoLog) = 0;
|
virtual bool postTranslateCompile(gl::Compiler *compiler, std::string *infoLog) = 0;
|
||||||
|
|
||||||
|
@ -136,7 +136,8 @@ gl::Error HLSLCompiler::initialize()
|
|||||||
|
|
||||||
if (!mD3DCompilerModule)
|
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"));
|
mD3DCompileFunc = reinterpret_cast<pD3DCompile>(GetProcAddress(mD3DCompilerModule, "D3DCompile"));
|
||||||
@ -155,7 +156,7 @@ gl::Error HLSLCompiler::initialize()
|
|||||||
|
|
||||||
if (mD3DCompileFunc == nullptr)
|
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;
|
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