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

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

View File

@ -497,7 +497,7 @@ config("angle_util_config") {
} }
} }
static_library("angle_util") { shared_library("angle_util") {
sources = rebase_path(util_gypi.util_sources, ".", "util") 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",

View File

@ -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);

View File

@ -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

View File

@ -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',

View File

@ -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"

View File

@ -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',

View File

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

View File

@ -0,0 +1,20 @@
//
// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Rewrite condition in for and while loops to work around driver bug on Intel Mac.
#ifndef COMPILER_TRANSLATOR_ADDANDTRUETOLOOPCONDITION_H_
#define COMPILER_TRANSLATOR_ADDANDTRUETOLOOPCONDITION_H_
class TIntermNode;
namespace sh
{
void AddAndTrueToLoopCondition(TIntermNode *root);
} // namespace sh
#endif // COMPILER_TRANSLATOR_ADDANDTRUETOLOOPCONDITION_H_

View File

@ -54,48 +54,13 @@ class AddDefaultReturnStatementsTraverser : private TIntermTraverser
return true; 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);

View File

@ -167,12 +167,11 @@ bool ArrayReturnValueToOutParameterTraverser::visitBranch(Visit visit, TIntermBr
// Instead of returning a value, assign to the out parameter and then return. // 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);

View File

@ -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";

View File

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

View File

@ -0,0 +1,23 @@
//
// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// BreakVariableAliasingInInnerLoops.h: To optimize simple assignments, the HLSL compiler frontend
// may record a variable as aliasing another. Sometimes the alias information gets garbled
// so we work around this issue by breaking the aliasing chain in inner loops.
#ifndef COMPILER_TRANSLATOR_BREAKVARIABLEALIASINGININNERLOOPS_H_
#define COMPILER_TRANSLATOR_BREAKVARIABLEALIASINGININNERLOOPS_H_
class TIntermNode;
namespace sh
{
void BreakVariableAliasingInInnerLoops(TIntermNode *root);
} // namespace sh
#endif // COMPILER_TRANSLATOR_BREAKVARIABLEALIASINGININNERLOOPS_H_

View File

@ -11,32 +11,14 @@
#include "compiler/translator/SymbolTable.h" #include "compiler/translator/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"

View File

@ -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.

View File

@ -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))
{ {

View File

@ -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;

View File

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

View File

@ -9,77 +9,18 @@
#include <assert.h> #include <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;
}; };

View File

@ -101,10 +101,8 @@ bool DeferGlobalInitializersTraverser::visitBinary(Visit visit, TIntermBinary *n
// Deferral is done also in any cases where the variable has not been constant folded, // 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.

View File

@ -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")

View File

@ -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;
} }

View File

@ -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;

View File

@ -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);
}
} }
} }

View File

@ -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

View File

@ -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 &parameter, FloatTypeUnaryFunc builtinFunc, TInfoSink &infoSink, TConstantUnion *result) const; void foldFloatTypeUnary(const TConstantUnion &parameter,
FloatTypeUnaryFunc builtinFunc,
TConstantUnion *result) const;
TIntermConstantUnion(const TIntermConstantUnion &node); // Note: not deleted, just private! 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(); }

View File

@ -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;
} }

View File

@ -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;

View File

@ -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.
// //

View File

@ -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;

View File

@ -16,20 +16,21 @@ struct TVectorFields
}; };
// //
// Set of helper functions to help parse and build the tree. // Set of helper functions to help build the tree.
// //
class TInfoSink;
class TIntermediate 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_

View File

@ -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;
} }

View File

@ -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;

View File

@ -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.

View File

@ -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

View File

@ -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(

View File

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

View File

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

View File

@ -92,21 +92,15 @@ TIntermBinary *CreateIndexDirectBaseSymbolNode(const TType &indexedType,
const int index, 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.

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -1,36 +0,0 @@
//
// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#ifndef COMPILER_TRANSLATOR_RENAMEFUNCTION_H_
#define COMPILER_TRANSLATOR_RENAMEFUNCTION_H_
#include "compiler/translator/IntermNode.h"
//
// Renames a function, including its declaration and any calls to it.
//
class RenameFunction : public TIntermTraverser
{
public:
RenameFunction(const TString& oldFunctionName, const TString& newFunctionName)
: TIntermTraverser(true, false, false)
, mOldFunctionName(oldFunctionName)
, mNewFunctionName(newFunctionName) {}
bool visitAggregate(Visit visit, TIntermAggregate *node) override
{
TOperator op = node->getOp();
if ((op == EOpFunction || op == EOpFunctionCall) && node->getName() == mOldFunctionName)
node->setName(mNewFunctionName);
return true;
}
private:
const TString mOldFunctionName;
const TString mNewFunctionName;
};
#endif // COMPILER_TRANSLATOR_RENAMEFUNCTION_H_

View File

@ -102,8 +102,8 @@ class DoWhileRewriter : public TIntermTraverser
TIntermAggregate *breakBlock = new TIntermAggregate(EOpSequence); 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);

View File

@ -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);
} }

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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.

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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;
} }

View File

@ -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;

View File

@ -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:

View File

@ -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)

View File

@ -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:

View File

@ -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;

View File

@ -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;

View File

@ -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)

View File

@ -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();
} }
}; };

View File

@ -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())
{ {

View File

@ -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 =

View File

@ -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;

View File

@ -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;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,31 +0,0 @@
//
// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#ifndef COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPHOUTPUT_H_
#define COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPHOUTPUT_H_
#include "compiler/translator/depgraph/DependencyGraph.h"
#include "compiler/translator/InfoSink.h"
class TDependencyGraphOutput : public TDependencyGraphTraverser
{
public:
TDependencyGraphOutput(TInfoSinkBase& sink) : mSink(sink) {}
void visitSymbol(TGraphSymbol* symbol) override;
void visitArgument(TGraphArgument* parameter) override;
void visitFunctionCall(TGraphFunctionCall* functionCall) override;
void visitSelection(TGraphSelection* selection) override;
void visitLoop(TGraphLoop* loop) override;
void visitLogicalOp(TGraphLogicalOp* logicalOp) override;
void outputAllSpanningTrees(TDependencyGraph& graph);
private:
void outputIndentation();
TInfoSinkBase& mSink;
};
#endif // COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPHOUTPUT_H_

View File

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

View File

@ -80,6 +80,7 @@ WHICH GENERATES THE GLSL ES PARSER (glslang_tab.cpp AND glslang_tab.h).
TIntermCase* intermCase; 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

View File

@ -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;

View File

@ -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;

View File

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

View File

@ -1,39 +0,0 @@
//
// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#ifndef COMPILER_TRANSLATOR_TIMING_RESTRICTFRAGMENTSHADERTIMING_H_
#define COMPILER_TRANSLATOR_TIMING_RESTRICTFRAGMENTSHADERTIMING_H_
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/depgraph/DependencyGraph.h"
class TInfoSinkBase;
class RestrictFragmentShaderTiming : TDependencyGraphTraverser
{
public:
RestrictFragmentShaderTiming(TInfoSinkBase &sink);
void enforceRestrictions(const TDependencyGraph &graph);
int numErrors() const { return mNumErrors; }
void visitArgument(TGraphArgument *parameter) override;
void visitSelection(TGraphSelection *selection) override;
void visitLoop(TGraphLoop *loop) override;
void visitLogicalOp(TGraphLogicalOp *logicalOp) override;
private:
void beginError(const TIntermNode *node);
void validateUserDefinedFunctionCallUsage(const TDependencyGraph &graph);
bool isSamplingOp(const TIntermAggregate *intermFunctionCall) const;
TInfoSinkBase &mSink;
int mNumErrors;
typedef std::set<TString> StringSet;
StringSet mSamplingOps;
};
#endif // COMPILER_TRANSLATOR_TIMING_RESTRICTFRAGMENTSHADERTIMING_H_

View File

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

View File

@ -1,32 +0,0 @@
//
// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#ifndef COMPILER_TRANSLATOR_TIMING_RESTRICTVERTEXSHADERTIMING_H_
#define COMPILER_TRANSLATOR_TIMING_RESTRICTVERTEXSHADERTIMING_H_
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/InfoSink.h"
class TInfoSinkBase;
class RestrictVertexShaderTiming : public TIntermTraverser {
public:
RestrictVertexShaderTiming(TInfoSinkBase& sink)
: TIntermTraverser(true, false, false)
, mSink(sink)
, mNumErrors(0) {}
void enforceRestrictions(TIntermNode* root) { root->traverse(this); }
int numErrors() { return mNumErrors; }
void visitSymbol(TIntermSymbol *) override;
private:
TInfoSinkBase& mSink;
int mNumErrors;
};
#endif // COMPILER_TRANSLATOR_TIMING_RESTRICTVERTEXSHADERTIMING_H_

View File

@ -278,9 +278,9 @@ InterpolationType GetInterpolationType(TQualifier qualifier)
} }
} }
TType ConvertShaderVariableTypeToTType(sh::GLenum type) TType GetShaderVariableBasicType(const sh::ShaderVariable &var)
{ {
switch (type) switch (var.type)
{ {
case GL_FLOAT: 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

View File

@ -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_

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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();

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -716,7 +716,7 @@ static InternalFormatInfoMap BuildInternalFormatInfoMap()
AddDepthStencilFormat(&map, GL_STENCIL_INDEX8, 0, 8, 0, GL_STENCIL, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, RequireES<2>, RequireES<2>, NeverSupported); 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 |

View File

@ -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',

View File

@ -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)

View File

@ -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

View File

@ -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,

View File

@ -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 **));

View File

@ -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;

View File

@ -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