Flutter Engine
The Flutter Engine
Namespaces | Classes | Typedefs | Enumerations | Functions | Variables
SkSL Namespace Reference

Namespaces

namespace  Analysis
 
namespace  Constructor
 
namespace  Intrinsics
 
namespace  PipelineStage
 
namespace  RP
 
namespace  String
 
namespace  SwizzleComponent
 
namespace  Transform
 

Classes

class  AliasType
 
class  AnyConstructor
 
class  ArrayType
 
class  AtomicType
 
class  AutoAttachPoolToThread
 
class  AutoOutputStream
 
class  AutoProgramConfig
 
class  BinaryExpression
 
class  Block
 
class  BreakStatement
 
class  BuiltinTypes
 
class  ChildCall
 
class  CodeGenerator
 
struct  CoercionCost
 
struct  CompactEntry
 
class  Compiler
 
class  ConstantFolder
 
class  ConstructorArray
 
class  ConstructorArrayCast
 
class  ConstructorCompound
 
class  ConstructorCompoundCast
 
class  ConstructorDiagonalMatrix
 
class  ConstructorMatrixResize
 
class  ConstructorScalarCast
 
class  ConstructorSplat
 
class  ConstructorStruct
 
class  Context
 
class  ContinueStatement
 
class  CountReturnsWithLimit
 
class  DebugTrace
 
class  DebugTracePriv
 
class  DiscardStatement
 
class  DoStatement
 
class  EmptyExpression
 
class  ErrorReporter
 
class  Expression
 
class  ExpressionArray
 
class  ExpressionStatement
 
class  ExtendedVariable
 
class  Extension
 
struct  Field
 
class  FieldAccess
 
class  FieldSymbol
 
class  FileOutputStream
 
struct  ForLoopPositions
 
class  ForStatement
 
struct  FullEntry
 
class  FunctionCall
 
struct  FunctionDebugInfo
 
class  FunctionDeclaration
 
class  FunctionDefinition
 
class  FunctionPrototype
 
class  FunctionReference
 
class  GenericType
 
class  GlobalVarDeclaration
 
class  GLSLCodeGenerator
 
class  IfStatement
 
class  IndexExpression
 
struct  InlineCandidate
 
class  InlineCandidateAnalyzer
 
struct  InlineCandidateList
 
class  Inliner
 
class  InterfaceBlock
 
struct  IRHelpers
 
class  IRNode
 
struct  Layout
 
class  Lexer
 
class  Literal
 
class  LiteralType
 
struct  LoopUnrollInfo
 
class  Mangler
 
class  MatrixType
 
class  MemoryLayout
 
class  MemoryPool
 
class  MetalCodeGenerator
 
class  MethodReference
 
class  ModifierFlags
 
struct  Modifiers
 
class  ModifiersDeclaration
 
struct  Module
 
class  ModuleLoader
 
class  MultiArgumentConstructor
 
class  NoOpErrorReporter
 
class  Nop
 
class  Operator
 
class  OutputStream
 
class  Parser
 
class  PointerLValue
 
class  Poison
 
class  Pool
 
class  Poolable
 
class  Position
 
class  PostfixExpression
 
class  PrefixExpression
 
struct  Program
 
struct  ProgramConfig
 
class  ProgramElement
 
struct  ProgramInterface
 
struct  ProgramSettings
 
class  ProgramUsage
 
class  ProgramVisitor
 
struct  ProgramVisitorTypes
 
class  ProgramWriter
 
struct  ProgramWriterTypes
 
class  ReturnStatement
 
class  SamplerType
 
class  SampleUsage
 
class  ScalarType
 
class  Setting
 
struct  ShaderCaps
 
class  ShaderCapsFactory
 
class  SingleArgumentConstructor
 
class  SkSLDebugTracePlayer
 
struct  SlotDebugInfo
 
class  SPIRVCodeGenerator
 
class  Statement
 
class  StringStream
 
class  StructDefinition
 
class  StructType
 
class  SwitchCase
 
class  SwitchStatement
 
class  Swizzle
 
class  SwizzleLValue
 
class  Symbol
 
class  SymbolTable
 
class  TernaryExpression
 
class  TestingOnly_AbortErrorReporter
 
class  TextureType
 
struct  Token
 
class  TProgramVisitor
 
class  TraceHook
 
struct  TraceInfo
 
class  Tracer
 
class  Type
 
class  TypeReference
 
struct  UniformInfo
 
class  VarDeclaration
 
class  Variable
 
class  VariableReference
 
class  VectorType
 
class  WGSLCodeGenerator
 

Typedefs

using IntrinsicArguments = std::array< const Expression *, 3 >
 
using CoalesceFn = double(*)(double, double, double)
 
using FinalizeFn = double(*)(double)
 
using CompareFn = bool(*)(double, double)
 
using EvaluateFn = double(*)(double, double, double)
 
using LayoutFlags = SkEnumBitMask< SkSL::LayoutFlag >
 
using ComponentArray = skia_private::FixedArray< 4, int8_t >
 
using StatementArray = skia_private::STArray< 2, std::unique_ptr< Statement > >
 
using IntrinsicMap = skia_private::THashMap< std::string_view, IntrinsicKind >
 
using State = uint16_t
 
using IndexEntry = int16_t
 
using BuiltinTypePtr = const std::unique_ptr< Type > BuiltinTypes::*
 

Enumerations

enum class  Version { k100 , k300 }
 
enum class  FieldAccessOwnerKind : int8_t { kDefault , kAnonymousInterfaceBlock }
 
enum class  ProgramElementKind {
  kExtension = 0 , kFunction , kFunctionPrototype , kGlobalVar ,
  kInterfaceBlock , kModifiers , kStructDefinition , kFirst = kExtension ,
  kLast = kStructDefinition
}
 
enum class  SymbolKind {
  kExternal = (int) ProgramElementKind::kLast + 1 , kField , kFunctionDeclaration , kType ,
  kVariable , kFirst = kExternal , kLast = kVariable
}
 
enum class  StatementKind {
  kBlock = (int) SymbolKind::kLast + 1 , kBreak , kContinue , kDiscard ,
  kDo , kExpression , kFor , kIf ,
  kNop , kReturn , kSwitch , kSwitchCase ,
  kVarDeclaration , kFirst = kBlock , kLast = kVarDeclaration
}
 
enum class  ExpressionKind {
  kBinary = (int) StatementKind::kLast + 1 , kChildCall , kConstructorArray , kConstructorArrayCast ,
  kConstructorCompound , kConstructorCompoundCast , kConstructorDiagonalMatrix , kConstructorMatrixResize ,
  kConstructorScalarCast , kConstructorSplat , kConstructorStruct , kEmpty ,
  kFieldAccess , kFunctionReference , kFunctionCall , kIndex ,
  kLiteral , kMethodReference , kPoison , kPostfix ,
  kPrefix , kSetting , kSwizzle , kTernary ,
  kTypeReference , kVariableReference , kFirst = kBinary , kLast = kVariableReference
}
 
enum class  LayoutFlag : int {
  kNone = 0 , kAll = ~0 , kOriginUpperLeft = 1 << 0 , kPushConstant = 1 << 1 ,
  kBlendSupportAllEquations = 1 << 2 , kColor = 1 << 3 , kLocation = 1 << 4 , kOffset = 1 << 5 ,
  kBinding = 1 << 6 , kTexture = 1 << 7 , kSampler = 1 << 8 , kIndex = 1 << 9 ,
  kSet = 1 << 10 , kBuiltin = 1 << 11 , kInputAttachmentIndex = 1 << 12 , kVulkan = 1 << 13 ,
  kMetal = 1 << 14 , kWebGPU = 1 << 15 , kDirect3D = 1 << 16 , kAllBackends = kVulkan | kMetal | kWebGPU | kDirect3D ,
  kRGBA8 = 1 << 17 , kRGBA32F = 1 << 18 , kR32F = 1 << 19 , kAllPixelFormats = kRGBA8 | kRGBA32F | kR32F ,
  kLocalSizeX = 1 << 20 , kLocalSizeY = 1 << 21 , kLocalSizeZ = 1 << 22
}
 
enum class  ModifierFlag : int {
  kNone = 0 , kFlat = 1 << 0 , kNoPerspective = 1 << 1 , kConst = 1 << 2 ,
  kUniform = 1 << 3 , kIn = 1 << 4 , kOut = 1 << 5 , kHighp = 1 << 6 ,
  kMediump = 1 << 7 , kLowp = 1 << 8 , kReadOnly = 1 << 9 , kWriteOnly = 1 << 10 ,
  kBuffer = 1 << 11 , kPixelLocal = 1 << 12 , kWorkgroup = 1 << 13 , kExport = 1 << 14 ,
  kES3 = 1 << 15 , kPure = 1 << 16 , kInline = 1 << 17 , kNoInline = 1 << 18
}
 
enum class  VariableStorage : int8_t { kGlobal , kInterfaceBlock , kLocal , kParameter }
 
enum class  VariableRefKind : int8_t { kRead , kWrite , kReadWrite , kPointer }
 
enum class  GLSLGeneration {
  k110 , k100es = k110 , k130 , k140 ,
  k150 , k330 , k300es = k330 , k400 ,
  k420 , k310es , k320es
}
 
enum  IntrinsicKind : int8_t { kNotIntrinsic = -1 , SKSL_INTRINSIC_LIST }
 
enum class  ModuleName {
  sksl_shared , sksl_compute , sksl_frag , sksl_gpu ,
  sksl_public , sksl_rt_shader , sksl_vert , sksl_graphite_frag ,
  sksl_graphite_frag_es2 , sksl_graphite_vert , sksl_graphite_vert_es2
}
 
enum class  OperatorKind : uint8_t {
  PLUS , MINUS , STAR , SLASH ,
  PERCENT , SHL , SHR , LOGICALNOT ,
  LOGICALAND , LOGICALOR , LOGICALXOR , BITWISENOT ,
  BITWISEAND , BITWISEOR , BITWISEXOR , EQ ,
  EQEQ , NEQ , LT , GT ,
  LTEQ , GTEQ , PLUSEQ , MINUSEQ ,
  STAREQ , SLASHEQ , PERCENTEQ , SHLEQ ,
  SHREQ , BITWISEANDEQ , BITWISEOREQ , BITWISEXOREQ ,
  PLUSPLUS , MINUSMINUS , COMMA
}
 
enum class  OperatorPrecedence : uint8_t {
  kParentheses = 1 , kPostfix = 2 , kPrefix = 3 , kMultiplicative = 4 ,
  kAdditive = 5 , kShift = 6 , kRelational = 7 , kEquality = 8 ,
  kBitwiseAnd = 9 , kBitwiseXor = 10 , kBitwiseOr = 11 , kLogicalAnd = 12 ,
  kLogicalXor = 13 , kLogicalOr = 14 , kTernary = 15 , kAssignment = 16 ,
  kSequence = 17 , kExpression = kSequence , kStatement = 18
}
 
enum class  ProgramKind : int8_t {
  kFragment , kVertex , kCompute , kGraphiteFragment ,
  kGraphiteVertex , kGraphiteFragmentES2 , kGraphiteVertexES2 , kRuntimeColorFilter ,
  kRuntimeShader , kRuntimeBlender , kPrivateRuntimeColorFilter , kPrivateRuntimeShader ,
  kPrivateRuntimeBlender , kMeshVertex , kMeshFragment
}
 

Functions

static int calculate_count (double start, double end, double delta, bool forwards, bool inclusive)
 
static int count_returns_at_end_of_control_flow (const FunctionDefinition &funcDef)
 
static bool contains_matching_data (const ProgramUsage &a, const ProgramUsage &b)
 
static bool is_abs (Expression &expr)
 
bool is_sk_position (const Expression &expr)
 
bool is_sk_samplemask (const Expression &expr)
 
bool ToGLSL (Program &program, const ShaderCaps *caps, OutputStream &out)
 
bool ToGLSL (Program &program, const ShaderCaps *caps, std::string *out)
 
bool ToHLSL (Program &program, const ShaderCaps *caps, OutputStream &out)
 
bool ToHLSL (Program &program, const ShaderCaps *caps, std::string *out)
 
static const char * operator_name (Operator op)
 
static bool pass_by_reference (const Type &type, ModifierFlags flags)
 
static bool needs_address_space (const Type &type, ModifierFlags modifiers)
 
static bool is_buffer (const InterfaceBlock &block)
 
static bool is_readonly (const InterfaceBlock &block)
 
static bool is_compute_builtin (const Variable &var)
 
static bool is_input (const Variable &var)
 
static bool is_output (const Variable &var)
 
static bool is_uniforms (const Variable &var)
 
static bool is_threadgroup (const Variable &var)
 
static bool is_in_globals (const Variable &var)
 
static bool is_block_ending_with_return (const Statement *stmt)
 
bool ToMetal (Program &program, const ShaderCaps *caps, OutputStream &out)
 
bool ToMetal (Program &program, const ShaderCaps *caps, std::string *out)
 
std::unique_ptr< RP::ProgramMakeRasterPipelineProgram (const SkSL::Program &program, const FunctionDefinition &function, DebugTracePriv *debugTrace, bool writeTraceOps)
 
static bool is_float (const Type &type)
 
static bool is_signed (const Type &type)
 
static bool is_unsigned (const Type &type)
 
static bool is_bool (const Type &type)
 
template<typename T >
static T pick_by_type (const Type &type, T ifFloat, T ifInt, T ifUInt, T ifBool)
 
static bool is_out (ModifierFlags f)
 
static bool is_in (ModifierFlags f)
 
static bool is_control_flow_op (SpvOp_ op)
 
static bool is_globally_reachable_op (SpvOp_ op)
 
static SpvImageFormat layout_flags_to_image_format (LayoutFlags flags)
 
static SpvStorageClass_ get_storage_class_for_global_variable (const Variable &var, SpvStorageClass_ fallbackStorageClass)
 
static SpvStorageClass_ get_storage_class (const Expression &expr)
 
static bool types_match (const Type &a, const Type &b)
 
static bool is_vardecl_compile_time_constant (const VarDeclaration &varDecl)
 
static SymbolTableget_top_level_symbol_table (const FunctionDeclaration &anyFunc)
 
bool ToSPIRV (Program &program, const ShaderCaps *caps, OutputStream &out)
 
bool ToSPIRV (Program &program, const ShaderCaps *caps, std::string *out)
 
bool SPIRVtoHLSL (const std::string &, std::string *)
 
static bool is_nontrivial_expression (const Expression &expr)
 
static bool binary_op_is_ambiguous_in_wgsl (Operator op)
 
static bool all_arguments_constant (const ExpressionArray &arguments)
 
bool ToWGSL (Program &program, const ShaderCaps *caps, OutputStream &out)
 
bool ToWGSL (Program &program, const ShaderCaps *caps, std::string *out)
 
static bool call_signature_is_valid (const Context &context, const Variable &child, const ExpressionArray &arguments)
 
static std::unique_ptr< Expressionconvert_compound_constructor (const Context &context, Position pos, const Type &type, ExpressionArray args)
 
static std::unique_ptr< Expressioncast_constant_array (const Context &context, Position pos, const Type &destType, std::unique_ptr< Expression > constCtor)
 
static bool is_safe_to_eliminate (const Type &type, const Expression &arg)
 
static const Expressionmake_splat_from_arguments (const Type &type, const ExpressionArray &args)
 
static std::unique_ptr< Expressioncast_constant_composite (const Context &context, Position pos, const Type &destType, std::unique_ptr< Expression > constCtor)
 
static bool arguments_match_field_types (const ExpressionArray &args, const Type &type)
 
static std::unique_ptr< Expressionextract_field (Position pos, const ConstructorStruct &ctor, int fieldIndex)
 
static bool is_vardecl_block_initializer (const Statement *stmt)
 
static bool is_simple_initializer (const Statement *stmt)
 
static void hoist_vardecl_symbols_into_outer_scope (const Context &context, const Block &initBlock, SymbolTable *innerSymbols, SymbolTable *hoistedSymbols)
 
static bool has_compile_time_constant_arguments (const ExpressionArray &arguments)
 
template<typename T >
static void type_check_expression (const Expression &expr)
 
template<>
void type_check_expression< float > (const Expression &expr)
 
template<>
void type_check_expression< SKSL_INT > (const Expression &expr)
 
template<>
void type_check_expression< bool > (const Expression &expr)
 
static std::unique_ptr< Expressioncoalesce_n_way_vector (const Expression *arg0, const Expression *arg1, double startingState, const Type &returnType, CoalesceFn coalesce, FinalizeFn finalize)
 
template<typename T >
static std::unique_ptr< Expressioncoalesce_vector (const IntrinsicArguments &arguments, double startingState, const Type &returnType, CoalesceFn coalesce, FinalizeFn finalize)
 
template<typename T >
static std::unique_ptr< Expressioncoalesce_pairwise_vectors (const IntrinsicArguments &arguments, double startingState, const Type &returnType, CoalesceFn coalesce, FinalizeFn finalize)
 
static std::unique_ptr< Expressionoptimize_comparison (const Context &context, const IntrinsicArguments &arguments, CompareFn compare)
 
static std::unique_ptr< Expressionevaluate_n_way_intrinsic (const Context &context, const Expression *arg0, const Expression *arg1, const Expression *arg2, const Type &returnType, EvaluateFn eval)
 
template<typename T >
static std::unique_ptr< Expressionevaluate_intrinsic (const Context &context, const IntrinsicArguments &arguments, const Type &returnType, EvaluateFn eval)
 
static std::unique_ptr< Expressionevaluate_intrinsic_numeric (const Context &context, const IntrinsicArguments &arguments, const Type &returnType, EvaluateFn eval)
 
static std::unique_ptr< Expressionevaluate_pairwise_intrinsic (const Context &context, const IntrinsicArguments &arguments, const Type &returnType, EvaluateFn eval)
 
static std::unique_ptr< Expressionevaluate_3_way_intrinsic (const Context &context, const IntrinsicArguments &arguments, const Type &returnType, EvaluateFn eval)
 
template<typename T1 , typename T2 >
static double pun_value (double val)
 
static void extract_matrix (const Expression *expr, float mat[16])
 
static std::unique_ptr< Expressionoptimize_intrinsic_call (const Context &context, Position pos, IntrinsicKind intrinsic, const ExpressionArray &argArray, const Type &returnType)
 
static bool argument_and_parameter_flags_match (const Expression &argument, const Variable &parameter)
 
static CoercionCost call_cost (const Context &context, const FunctionDeclaration &function, const ExpressionArray &arguments)
 
static std::string build_argument_type_list (SkSpan< const std::unique_ptr< Expression > > arguments)
 
static bool check_modifiers (const Context &context, Position pos, ModifierFlags modifierFlags)
 
static bool check_return_type (const Context &context, Position pos, const Type &returnType)
 
static bool check_parameters (const Context &context, TArray< std::unique_ptr< Variable > > &parameters, ModifierFlags modifierFlags, IntrinsicKind intrinsicKind)
 
static bool type_is_valid_for_color (const Type &type)
 
static bool type_is_valid_for_coords (const Type &type)
 
static bool check_main_signature (const Context &context, Position pos, const Type &returnType, TArray< std::unique_ptr< Variable > > &parameters)
 
static int find_generic_index (const Type &concreteType, const Type &genericType, bool allowNarrowing)
 
static bool type_generically_matches (const Type &concreteType, const Type &maybeGenericType)
 
static bool parameters_match (SkSpan< const std::unique_ptr< Variable > > params, SkSpan< Variable *const > otherParams)
 
static bool find_existing_declaration (const Context &context, Position pos, ModifierFlags modifierFlags, IntrinsicKind intrinsicKind, std::string_view name, TArray< std::unique_ptr< Variable > > &parameters, Position returnTypePos, const Type *returnType, FunctionDeclaration **outExistingDecl)
 
static void append_rtadjust_fixup_to_vertex_main (const Context &context, const FunctionDeclaration &decl, Block &body)
 
static std::unique_ptr< Statementreplace_empty_with_nop (std::unique_ptr< Statement > stmt, bool isEmpty)
 
static bool index_out_of_range (const Context &context, Position pos, SKSL_INT index, const Expression &base)
 
static std::optional< intfind_rt_adjust_index (SkSpan< const Field > fields)
 
static ExpressionArray negate_operands (const Context &context, Position pos, const ExpressionArray &operands)
 
static double negate_value (double value)
 
static double bitwise_not_value (double value)
 
static std::unique_ptr< Expressionapply_to_elements (const Context &context, Position pos, const Expression &expr, double(*fn)(double))
 
static std::unique_ptr< Expressionsimplify_negation (const Context &context, Position pos, const Expression &originalExpr)
 
static std::unique_ptr< Expressionnegate_operand (const Context &context, Position pos, std::unique_ptr< Expression > value)
 
static std::unique_ptr< Expressionlogical_not_operand (const Context &context, Position pos, std::unique_ptr< Expression > operand)
 
static std::unique_ptr< Expressionbitwise_not_operand (const Context &context, Position pos, std::unique_ptr< Expression > operand)
 
static TArray< const SwitchCase * > find_duplicate_case_values (const StatementArray &cases)
 
static void remove_break_statements (std::unique_ptr< Statement > &stmt)
 
static bool block_for_case (Statement *caseBlock, SwitchCase *caseToCapture)
 
static bool validate_swizzle_domain (const ComponentArray &fields)
 
static char mask_char (int8_t component)
 
static std::unique_ptr< Expressionoptimize_constructor_swizzle (const Context &context, Position pos, const ConstructorCompound &base, ComponentArray components)
 
static bool is_vec_or_mat (const Type &type)
 
static std::unique_ptr< Expressioneliminate_no_op_boolean (Position pos, const Expression &left, Operator op, const Expression &right)
 
static std::unique_ptr< Expressionshort_circuit_boolean (Position pos, const Expression &left, Operator op, const Expression &right)
 
static std::unique_ptr< Expressionsimplify_constant_equality (const Context &context, Position pos, const Expression &left, Operator op, const Expression &right)
 
static std::unique_ptr< Expressionsimplify_matrix_multiplication (const Context &context, Position pos, const Expression &left, const Expression &right, int leftColumns, int leftRows, int rightColumns, int rightRows)
 
static std::unique_ptr< Expressionsimplify_matrix_times_matrix (const Context &context, Position pos, const Expression &left, const Expression &right)
 
static std::unique_ptr< Expressionsimplify_vector_times_matrix (const Context &context, Position pos, const Expression &left, const Expression &right)
 
static std::unique_ptr< Expressionsimplify_matrix_times_vector (const Context &context, Position pos, const Expression &left, const Expression &right)
 
static std::unique_ptr< Expressionsimplify_componentwise (const Context &context, Position pos, const Expression &left, Operator op, const Expression &right)
 
static std::unique_ptr< Expressionsplat_scalar (const Context &context, const Expression &scalar, const Type &type)
 
static std::unique_ptr< Expressioncast_expression (const Context &context, Position pos, const Expression &expr, const Type &type)
 
static std::unique_ptr< Expressionzero_expression (const Context &context, Position pos, const Type &type)
 
static std::unique_ptr< Expressionnegate_expression (const Context &context, Position pos, const Expression &expr, const Type &type)
 
static bool contains_constant_zero (const Expression &expr)
 
static bool is_constant_diagonal (const Expression &expr, double value)
 
static bool is_constant_value (const Expression &expr, double value)
 
static std::unique_ptr< Expressionmake_reciprocal_expression (const Context &context, const Expression &right)
 
static bool error_on_divide_by_zero (const Context &context, Position pos, Operator op, const Expression &right)
 
static bool is_scalar_op_matrix (const Expression &left, const Expression &right)
 
static bool is_matrix_op_scalar (const Expression &left, const Expression &right)
 
static std::unique_ptr< Expressionsimplify_arithmetic (const Context &context, Position pos, const Expression &left, Operator op, const Expression &right, const Type &resultType)
 
static std::unique_ptr< Expressionone_over_scalar (const Context &context, const Expression &right)
 
static std::unique_ptr< Expressionsimplify_matrix_division (const Context &context, Position pos, const Expression &left, Operator op, const Expression &right, const Type &resultType)
 
static std::unique_ptr< Expressionfold_expression (Position pos, double result, const Type *resultType)
 
static std::unique_ptr< Expressionfold_two_constants (const Context &context, Position pos, const Expression *left, Operator op, const Expression *right, const Type &resultType)
 
static bool argument_needs_scratch_variable (const Expression *arg, const Variable *param, const ProgramUsage &usage)
 
static const FunctionDeclarationcandidate_func (const InlineCandidate &candidate)
 
const IntrinsicMapGetIntrinsicMap ()
 
IntrinsicKind FindIntrinsicKind (std::string_view functionName)
 
static State get_transition (uint8_t transition, State state)
 
std::string GetModuleData (ModuleName name, const char *filename)
 
static std::unique_ptr< Modulecompile_and_shrink (SkSL::Compiler *compiler, ProgramKind kind, const char *moduleName, std::string moduleSource, const Module *parent)
 
static ModifierFlags parse_modifier_token (Token::Kind token)
 
static bool is_whitespace (Token::Kind kind)
 
static Position range_of_at_least_one_char (int start, int end)
 
static MemoryPoolget_thread_local_memory_pool ()
 
static void set_thread_local_memory_pool (MemoryPool *memPool)
 
bool stod (std::string_view s, SKSL_FLOAT *value)
 
bool stoi (std::string_view s, SKSL_INT *value)
 
void write_stringstream (const StringStream &s, OutputStream &out)
 
bool type_to_sksltype (const Context &context, const Type &type, SkSLType *outType)
 
static bool dead_function_predicate (const ProgramElement *element, ProgramUsage *usage)
 
static bool is_dead_variable (const ProgramElement &element, ProgramUsage *usage, bool onlyPrivateGlobals)
 
static bool eliminate_dead_local_variables (const Context &context, SkSpan< std::unique_ptr< ProgramElement > > elements, ProgramUsage *usage)
 
static void eliminate_empty_statements (SkSpan< std::unique_ptr< ProgramElement > > elements)
 
static void eliminate_unnecessary_braces (SkSpan< std::unique_ptr< ProgramElement > > elements)
 
static void eliminate_unreachable_code (SkSpan< std::unique_ptr< ProgramElement > > elements, ProgramUsage *usage)
 
static bool contains_builtin_struct (const ProgramUsage &usage)
 
static void get_struct_definitions_from_module (Program &program, const Module &module, std::vector< const ProgramElement * > *addedStructDefs)
 
static void strip_export_flag (Context &context, const FunctionDeclaration *funcDecl, SymbolTable *symbols)
 

Variables

static constexpr int kLoopTerminationLimit = 100000
 
static constexpr char kDeterminant2 []
 
static constexpr char kDeterminant3 []
 
static constexpr char kDeterminant4 []
 
static constexpr char kInverse2 []
 
static constexpr char kInverse3 []
 
static constexpr char kInverse4 []
 
static constexpr char kInverse2x2 []
 
static constexpr char kInverse3x3 []
 
static constexpr char kInverse4x4 []
 
static const int32_t SKSL_MAGIC = 0x001F0000
 
static constexpr char kInverse2x2 []
 
static constexpr char kInverse3x3 []
 
static constexpr char kInverse4x4 []
 
static constexpr int kMaxStructDepth = 8
 
static constexpr Layout kDefaultLayout
 
static constexpr int kDefaultInlineThreshold = 50
 
static constexpr int kVariableSlotLimit = 100000
 
static constexpr uint8_t kInvalidChar = 18
 
static constexpr uint8_t kMappings [118]
 
static constexpr FullEntry kFull []
 
static constexpr CompactEntry kCompact []
 
static constexpr IndexEntry kIndices []
 
static const uint8_t kAccepts [427]
 
static constexpr BuiltinTypePtr kRootTypes []
 
static constexpr BuiltinTypePtr kPrivateTypes []
 
static constexpr int kMaxParseDepth = 50
 
static thread_local MemoryPoolsMemPool = nullptr
 

Typedef Documentation

◆ BuiltinTypePtr

using SkSL::BuiltinTypePtr = typedef const std::unique_ptr<Type> BuiltinTypes::*

Definition at line 20 of file SkSLModuleLoader.h.

◆ CoalesceFn

using SkSL::CoalesceFn = typedef double (*)(double, double, double)

Definition at line 81 of file SkSLFunctionCall.cpp.

◆ CompareFn

using SkSL::CompareFn = typedef bool (*)(double, double)

Definition at line 174 of file SkSLFunctionCall.cpp.

◆ ComponentArray

using SkSL::ComponentArray = typedef skia_private::FixedArray<4, int8_t>

Represents the components of a vector swizzle.

Definition at line 46 of file SkSLSwizzle.h.

◆ EvaluateFn

using SkSL::EvaluateFn = typedef double (*)(double, double, double)

Definition at line 204 of file SkSLFunctionCall.cpp.

◆ FinalizeFn

using SkSL::FinalizeFn = typedef double (*)(double)

Definition at line 82 of file SkSLFunctionCall.cpp.

◆ IndexEntry

using SkSL::IndexEntry = typedef int16_t

Definition at line 24 of file SkSLLexer.cpp.

◆ IntrinsicArguments

using SkSL::IntrinsicArguments = typedef std::array<const Expression*, 3>

Definition at line 51 of file SkSLFunctionCall.cpp.

◆ IntrinsicMap

using SkSL::IntrinsicMap = typedef skia_private::THashMap<std::string_view, IntrinsicKind>

Definition at line 135 of file SkSLIntrinsicList.h.

◆ LayoutFlags

Definition at line 68 of file SkSLLayout.h.

◆ State

using SkSL::State = typedef uint16_t

Definition at line 14 of file SkSLLexer.cpp.

◆ StatementArray

using SkSL::StatementArray = typedef skia_private::STArray<2, std::unique_ptr<Statement> >

Definition at line 32 of file SkSLDefines.h.

Enumeration Type Documentation

◆ ExpressionKind

enum class SkSL::ExpressionKind
strong
Enumerator
kBinary 
kChildCall 
kConstructorArray 
kConstructorArrayCast 
kConstructorCompound 
kConstructorCompoundCast 
kConstructorDiagonalMatrix 
kConstructorMatrixResize 
kConstructorScalarCast 
kConstructorSplat 
kConstructorStruct 
kEmpty 
kFieldAccess 
kFunctionReference 
kFunctionCall 
kIndex 
kLiteral 
kMethodReference 
kPoison 
kPostfix 
kPrefix 
kSetting 
kSwizzle 
kTernary 
kTypeReference 
kVariableReference 
kFirst 
kLast 

Definition at line 62 of file SkSLIRNode.h.

62 {
63 kBinary = (int) StatementKind::kLast + 1,
64 kChildCall,
65 kConstructorArray,
66 kConstructorArrayCast,
67 kConstructorCompound,
68 kConstructorCompoundCast,
69 kConstructorDiagonalMatrix,
70 kConstructorMatrixResize,
71 kConstructorScalarCast,
72 kConstructorSplat,
73 kConstructorStruct,
74 kEmpty,
75 kFieldAccess,
76 kFunctionReference,
77 kFunctionCall,
78 kIndex,
79 kLiteral,
80 kMethodReference,
81 kPoison,
82 kPostfix,
83 kPrefix,
84 kSetting,
85 kSwizzle,
86 kTernary,
87 kTypeReference,
88 kVariableReference,
89
90 kFirst = kBinary,
91 kLast = kVariableReference
92};

◆ FieldAccessOwnerKind

enum class SkSL::FieldAccessOwnerKind : int8_t
strong
Enumerator
kDefault 
kAnonymousInterfaceBlock 

Definition at line 29 of file SkSLFieldAccess.h.

29 : int8_t {
31 // this field access is to a field of an anonymous interface block (and thus, the field name
32 // is actually in global scope, so only the field name needs to be written in GLSL)
34};
@ kDefault

◆ GLSLGeneration

enum class SkSL::GLSLGeneration
strong
Enumerator
k110 

Desktop GLSL 1.10 and ES2 shading language (based on desktop GLSL 1.20)

k100es 
k130 

Desktop GLSL 1.30

k140 

Desktop GLSL 1.40

k150 

Desktop GLSL 1.50

k330 

Desktop GLSL 3.30, and ES GLSL 3.00

k300es 
k400 

Desktop GLSL 4.00

k420 

Desktop GLSL 4.20

k310es 

ES GLSL 3.10 only TODO Make GLSLCap objects to make this more granular

k320es 

ES GLSL 3.20

Definition at line 15 of file SkSLGLSL.h.

15 {
16 /**
17 * Desktop GLSL 1.10 and ES2 shading language (based on desktop GLSL 1.20)
18 */
19 k110,
20 k100es = k110,
21 /**
22 * Desktop GLSL 1.30
23 */
24 k130,
25 /**
26 * Desktop GLSL 1.40
27 */
28 k140,
29 /**
30 * Desktop GLSL 1.50
31 */
32 k150,
33 /**
34 * Desktop GLSL 3.30, and ES GLSL 3.00
35 */
36 k330,
37 k300es = k330,
38 /**
39 * Desktop GLSL 4.00
40 */
41 k400,
42 /**
43 * Desktop GLSL 4.20
44 */
45 k420,
46 /**
47 * ES GLSL 3.10 only TODO Make GLSLCap objects to make this more granular
48 */
49 k310es,
50 /**
51 * ES GLSL 3.20
52 */
53 k320es,
54};

◆ IntrinsicKind

enum SkSL::IntrinsicKind : int8_t
Enumerator
kNotIntrinsic 
SKSL_INTRINSIC_LIST 

Definition at line 128 of file SkSLIntrinsicList.h.

128 : int8_t {
129 kNotIntrinsic = -1,
131};
#define SKSL_INTRINSIC_LIST

◆ LayoutFlag

enum class SkSL::LayoutFlag : int
strong
Enumerator
kNone 
kAll 
kOriginUpperLeft 
kPushConstant 
kBlendSupportAllEquations 
kColor 
kLocation 
kOffset 
kBinding 
kTexture 
kSampler 
kIndex 
kSet 
kBuiltin 
kInputAttachmentIndex 
kVulkan 
kMetal 
kWebGPU 
kDirect3D 
kAllBackends 
kRGBA8 
kRGBA32F 
kR32F 
kAllPixelFormats 
kLocalSizeX 
kLocalSizeY 
kLocalSizeZ 

Definition at line 20 of file SkSLLayout.h.

20 : int {
21 kNone = 0,
22 kAll = ~0,
23
24 kOriginUpperLeft = 1 << 0,
25 kPushConstant = 1 << 1,
27 kColor = 1 << 3,
28
29 // These flags indicate if the qualifier appeared, regardless of the accompanying value.
30 kLocation = 1 << 4,
31 kOffset = 1 << 5,
32 kBinding = 1 << 6,
33 kTexture = 1 << 7,
34 kSampler = 1 << 8,
35 kIndex = 1 << 9,
36 kSet = 1 << 10,
37 kBuiltin = 1 << 11,
38 kInputAttachmentIndex = 1 << 12,
39
40 // These flags indicate the backend type; only one at most can be set.
41 kVulkan = 1 << 13,
42 kMetal = 1 << 14,
43 kWebGPU = 1 << 15,
44 kDirect3D = 1 << 16,
45
47
48 // These flags indicate the pixel format; only one at most can be set.
49 // (https://www.khronos.org/opengl/wiki/Layout_Qualifier_(GLSL)#Image_formats)
50 kRGBA8 = 1 << 17,
51 kRGBA32F = 1 << 18,
52 kR32F = 1 << 19,
53
55
56 // The local invocation size of a compute program.
57 kLocalSizeX = 1 << 20,
58 kLocalSizeY = 1 << 21,
59 kLocalSizeZ = 1 << 22,
60};
static constexpr SkColor kColor
Definition: CanvasTest.cpp:265
static constexpr uint64_t kOffset
Definition: DrawPass.cpp:53
@ kVulkan
Definition: embedder.h:86
@ kMetal
Definition: embedder.h:85
@ kNone
Definition: layer.h:53

◆ ModifierFlag

enum class SkSL::ModifierFlag : int
strong
Enumerator
kNone 
kFlat 
kNoPerspective 
kConst 
kUniform 
kIn 
kOut 
kHighp 
kMediump 
kLowp 
kReadOnly 
kWriteOnly 
kBuffer 
kPixelLocal 
kWorkgroup 
kExport 
kES3 
kPure 
kInline 
kNoInline 

Definition at line 21 of file SkSLModifierFlags.h.

21 : int {
22 kNone = 0,
23 // Real GLSL modifiers
24 kFlat = 1 << 0,
25 kNoPerspective = 1 << 1,
26 kConst = 1 << 2,
27 kUniform = 1 << 3,
28 kIn = 1 << 4,
29 kOut = 1 << 5,
30 kHighp = 1 << 6,
31 kMediump = 1 << 7,
32 kLowp = 1 << 8,
33 kReadOnly = 1 << 9,
34 kWriteOnly = 1 << 10,
35 kBuffer = 1 << 11,
36 kPixelLocal = 1 << 12,
37 // Corresponds to the GLSL 'shared' modifier. Only allowed in a compute program.
38 kWorkgroup = 1 << 13,
39 // SkSL extensions, not present in GLSL
40 kExport = 1 << 14,
41 kES3 = 1 << 15,
42 kPure = 1 << 16,
43 kInline = 1 << 17,
44 kNoInline = 1 << 18,
45};

◆ ModuleName

enum class SkSL::ModuleName
strong
Enumerator
sksl_shared 
sksl_compute 
sksl_frag 
sksl_gpu 
sksl_public 
sksl_rt_shader 
sksl_vert 
sksl_graphite_frag 
sksl_graphite_frag_es2 
sksl_graphite_vert 
sksl_graphite_vert_es2 

Definition at line 15 of file SkSLModuleData.h.

◆ OperatorKind

enum class SkSL::OperatorKind : uint8_t
strong
Enumerator
PLUS 
MINUS 
STAR 
SLASH 
PERCENT 
SHL 
SHR 
LOGICALNOT 
LOGICALAND 
LOGICALOR 
LOGICALXOR 
BITWISENOT 
BITWISEAND 
BITWISEOR 
BITWISEXOR 
EQ 
EQEQ 
NEQ 
LT 
GT 
LTEQ 
GTEQ 
PLUSEQ 
MINUSEQ 
STAREQ 
SLASHEQ 
PERCENTEQ 
SHLEQ 
SHREQ 
BITWISEANDEQ 
BITWISEOREQ 
BITWISEXOREQ 
PLUSPLUS 
MINUSMINUS 
COMMA 

Definition at line 19 of file SkSLOperator.h.

19 : uint8_t {
20 PLUS,
21 MINUS,
22 STAR,
23 SLASH,
24 PERCENT,
25 SHL,
26 SHR,
35 EQ,
36 EQEQ,
37 NEQ,
38 LT,
39 GT,
40 LTEQ,
41 GTEQ,
42 PLUSEQ,
43 MINUSEQ,
44 STAREQ,
45 SLASHEQ,
47 SHLEQ,
48 SHREQ,
54 COMMA
55};
#define COMMA

◆ OperatorPrecedence

enum class SkSL::OperatorPrecedence : uint8_t
strong
Enumerator
kParentheses 
kPostfix 
kPrefix 
kMultiplicative 
kAdditive 
kShift 
kRelational 
kEquality 
kBitwiseAnd 
kBitwiseXor 
kBitwiseOr 
kLogicalAnd 
kLogicalXor 
kLogicalOr 
kTernary 
kAssignment 
kSequence 
kExpression 
kStatement 

Definition at line 57 of file SkSLOperator.h.

57 : uint8_t {
58 kParentheses = 1,
59 kPostfix = 2,
60 kPrefix = 3,
62 kAdditive = 5,
63 kShift = 6,
64 kRelational = 7,
65 kEquality = 8,
66 kBitwiseAnd = 9,
67 kBitwiseXor = 10,
68 kBitwiseOr = 11,
69 kLogicalAnd = 12,
70 kLogicalXor = 13,
71 kLogicalOr = 14,
72 kTernary = 15,
73 kAssignment = 16,
74 kSequence = 17, // a comma-separated sequence
75 kExpression = kSequence, // a top-level expression, anywhere in a statement
76 kStatement = 18, // a standalone expression-statement
77};
constexpr int kShift

◆ ProgramElementKind

enum class SkSL::ProgramElementKind
strong
Enumerator
kExtension 
kFunction 
kFunctionPrototype 
kGlobalVar 
kInterfaceBlock 
kModifiers 
kStructDefinition 
kFirst 
kLast 

Definition at line 19 of file SkSLIRNode.h.

◆ ProgramKind

enum class SkSL::ProgramKind : int8_t
strong

SkSL supports several different program kinds.

Enumerator
kFragment 
kVertex 
kCompute 
kGraphiteFragment 
kGraphiteVertex 
kGraphiteFragmentES2 
kGraphiteVertexES2 
kRuntimeColorFilter 
kRuntimeShader 
kRuntimeBlender 
kPrivateRuntimeColorFilter 
kPrivateRuntimeShader 
kPrivateRuntimeBlender 
kMeshVertex 
kMeshFragment 

Definition at line 18 of file SkSLProgramKind.h.

18 : int8_t {
19 kFragment,
20 kVertex,
21 kCompute,
26 kRuntimeColorFilter, // Runtime effect only suitable as SkColorFilter
27 kRuntimeShader, // " " " " " SkShader
28 kRuntimeBlender, // " " " " " SkBlender
29 kPrivateRuntimeColorFilter, // Runtime color filter with public restrictions lifted
30 kPrivateRuntimeShader, // Runtime shader " " " "
31 kPrivateRuntimeBlender, // Runtime blender " " " "
32 kMeshVertex, // Vertex portion of a custom mesh
33 kMeshFragment, // Fragment " " " " "
34};

◆ StatementKind

enum class SkSL::StatementKind
strong
Enumerator
kBlock 
kBreak 
kContinue 
kDiscard 
kDo 
kExpression 
kFor 
kIf 
kNop 
kReturn 
kSwitch 
kSwitchCase 
kVarDeclaration 
kFirst 
kLast 

Definition at line 43 of file SkSLIRNode.h.

43 {
44 kBlock = (int) SymbolKind::kLast + 1,
45 kBreak,
46 kContinue,
47 kDiscard,
48 kDo,
49 kExpression,
50 kFor,
51 kIf,
52 kNop,
53 kReturn,
54 kSwitch,
55 kSwitchCase,
56 kVarDeclaration,
57
58 kFirst = kBlock,
59 kLast = kVarDeclaration,
60};

◆ SymbolKind

enum class SkSL::SymbolKind
strong
Enumerator
kExternal 
kField 
kFunctionDeclaration 
kType 
kVariable 
kFirst 
kLast 

Definition at line 32 of file SkSLIRNode.h.

32 {
33 kExternal = (int) ProgramElementKind::kLast + 1,
34 kField,
35 kFunctionDeclaration,
36 kType,
37 kVariable,
38
39 kFirst = kExternal,
40 kLast = kVariable
41};

◆ VariableRefKind

enum class SkSL::VariableRefKind : int8_t
strong
Enumerator
kRead 
kWrite 
kReadWrite 
kPointer 

Definition at line 25 of file SkSLVariableReference.h.

25 : int8_t {
26 kRead,
27 kWrite,
28 kReadWrite,
29 // taking the address of a variable - we consider this a read & write but don't complain if
30 // the variable was not previously assigned
32};

◆ VariableStorage

enum class SkSL::VariableStorage : int8_t
strong
Enumerator
kGlobal 
kInterfaceBlock 
kLocal 
kParameter 

Definition at line 36 of file SkSLVariable.h.

◆ Version

enum class SkSL::Version
strong
Enumerator
k100 

Desktop GLSL 1.10, GLSL ES 1.00, WebGL 1.0

k300 

Desktop GLSL 3.30, GLSL ES 3.00, WebGL 2.0

Definition at line 13 of file SkSLVersion.h.

13 {
14 /**
15 * Desktop GLSL 1.10, GLSL ES 1.00, WebGL 1.0
16 */
17 k100,
18
19 /**
20 * Desktop GLSL 3.30, GLSL ES 3.00, WebGL 2.0
21 */
22 k300,
23};

Function Documentation

◆ all_arguments_constant()

static bool SkSL::all_arguments_constant ( const ExpressionArray arguments)
static

Definition at line 2820 of file SkSLWGSLCodeGenerator.cpp.

2820 {
2821 // Returns true if all arguments in the ExpressionArray are compile-time constants. If we are
2822 // calling an intrinsic and all of its inputs are constant, but we didn't constant-fold it, this
2823 // generally indicates that constant-folding resulted in an infinity or nan. The WGSL compiler
2824 // will reject such an expression with a compile-time error. We can dodge the error, taking on
2825 // the risk of indeterminate behavior instead, by replacing one of the constant values with a
2826 // scratch let-variable. (skia:14385)
2827 for (const std::unique_ptr<Expression>& arg : arguments) {
2828 if (!ConstantFolder::GetConstantValueOrNull(*arg)) {
2829 return false;
2830 }
2831 }
2832 return true;
2833}

◆ append_rtadjust_fixup_to_vertex_main()

static void SkSL::append_rtadjust_fixup_to_vertex_main ( const Context context,
const FunctionDeclaration decl,
Block body 
)
static

Definition at line 43 of file SkSLFunctionDefinition.cpp.

45 {
46 // If this program uses RTAdjust...
47 if (const SkSL::Symbol* rtAdjust = context.fSymbolTable->find(Compiler::RTADJUST_NAME)) {
48 // ...append a line to the end of the function body which fixes up sk_Position.
49 struct AppendRTAdjustFixupHelper : public IRHelpers {
50 AppendRTAdjustFixupHelper(const Context& ctx, const SkSL::Symbol* rtAdjust)
51 : IRHelpers(ctx)
52 , fRTAdjust(rtAdjust) {
53 fSkPositionField = &fContext.fSymbolTable->find(Compiler::POSITION_NAME)
54 ->as<FieldSymbol>();
55 }
56
57 std::unique_ptr<Expression> Pos() const {
58 return Field(&fSkPositionField->owner(), fSkPositionField->fieldIndex());
59 }
60
61 std::unique_ptr<Expression> Adjust() const {
62 return fRTAdjust->instantiate(fContext, Position());
63 }
64
65 std::unique_ptr<Statement> makeFixupStmt() const {
66 // sk_Position = float4(sk_Position.xy * rtAdjust.xz + sk_Position.ww * rtAdjust.yw,
67 // 0,
68 // sk_Position.w);
69 return Assign(
70 Pos(),
75 Float(0.0),
76 Swizzle(Pos(), {SwizzleComponent::W})));
77 }
78
79 const FieldSymbol* fSkPositionField;
80 const SkSL::Symbol* fRTAdjust;
81 };
82
83 AppendRTAdjustFixupHelper helper(context, rtAdjust);
84 body.children().push_back(helper.makeFixupStmt());
85 }
86}
const Context & fContext
static const SkScalar Y
Definition: StrokeBench.cpp:55
#define W
Definition: aaa.cpp:17
#define Z
const StatementArray & children() const
Definition: SkSLBlock.h:71
SymbolTable * fSymbolTable
Definition: SkSLContext.h:48
const Symbol * find(std::string_view name) const
std::unique_ptr< Expression > Swizzle(std::unique_ptr< Expression > base, ComponentArray c) const
Definition: SkSLIRHelpers.h:55
std::unique_ptr< Expression > Add(std::unique_ptr< Expression > l, std::unique_ptr< Expression > r) const
Definition: SkSLIRHelpers.h:78
std::unique_ptr< Expression > Field(const Variable *var, int idx) const
Definition: SkSLIRHelpers.h:50
std::unique_ptr< Expression > Mul(std::unique_ptr< Expression > l, std::unique_ptr< Expression > r) const
Definition: SkSLIRHelpers.h:73
std::unique_ptr< Expression > CtorXYZW(std::unique_ptr< Expression > xy, std::unique_ptr< Expression > z, std::unique_ptr< Expression > w) const
Definition: SkSLIRHelpers.h:91
std::unique_ptr< Expression > Float(float value) const
Definition: SkSLIRHelpers.h:83
std::unique_ptr< Statement > Assign(std::unique_ptr< Expression > l, std::unique_ptr< Expression > r) const

◆ apply_to_elements()

static std::unique_ptr< Expression > SkSL::apply_to_elements ( const Context context,
Position  pos,
const Expression expr,
double(*)(double)  fn 
)
static

Definition at line 43 of file SkSLPrefixExpression.cpp.

46 {
47 const Type& elementType = expr.type().componentType();
48
49 double values[16];
50 size_t numSlots = expr.type().slotCount();
51 if (numSlots > std::size(values)) {
52 // The expression has more slots than we expected.
53 return nullptr;
54 }
55
56 for (size_t index = 0; index < numSlots; ++index) {
57 if (std::optional<double> slotValue = expr.getConstantValue(index)) {
58 values[index] = fn(*slotValue);
59 if (elementType.checkForOutOfRangeLiteral(context, values[index], pos)) {
60 // We can't simplify the expression if the new value is out-of-range for the type.
61 return nullptr;
62 }
63 } else {
64 // There's a non-constant element; we can't simplify this expression.
65 return nullptr;
66 }
67 }
68 return ConstructorCompound::MakeFromConstants(context, pos, expr.type(), values);
69}
SkPoint pos
const Type & type() const
virtual std::optional< double > getConstantValue(int n) const
virtual const Type & componentType() const
Definition: SkSLType.h:404
virtual size_t slotCount() const
Definition: SkSLType.h:457
bool checkForOutOfRangeLiteral(const Context &context, const Expression &expr) const
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259

◆ argument_and_parameter_flags_match()

static bool SkSL::argument_and_parameter_flags_match ( const Expression argument,
const Variable parameter 
)
static

Definition at line 1021 of file SkSLFunctionCall.cpp.

1022 {
1023 // If the function parameter has a pixel format, the argument being passed in must have a
1024 // matching pixel format.
1025 LayoutFlags paramPixelFormat = parameter.layout().fFlags & LayoutFlag::kAllPixelFormats;
1026 if (paramPixelFormat != LayoutFlag::kNone) {
1027 // The only SkSL type that supports pixel-format qualifiers is a storage texture.
1028 if (parameter.type().isStorageTexture()) {
1029 // Storage textures are opaquely typed, so there's no way to specify one other than by
1030 // directly accessing a variable.
1031 if (!argument.is<VariableReference>()) {
1032 return false;
1033 }
1034
1035 // The variable's pixel-format flags must match. (Only one pixel-format bit can be set.)
1036 const Variable& var = *argument.as<VariableReference>().variable();
1037 if ((var.layout().fFlags & LayoutFlag::kAllPixelFormats) != paramPixelFormat) {
1038 return false;
1039 }
1040 }
1041 }
1042
1043 // The only other supported parameter flags are `const` and `in/out`, which do not allow
1044 // multiple overloads.
1045 return true;
1046}
bool is() const
Definition: SkSLIRNode.h:124
const T & as() const
Definition: SkSLIRNode.h:133
const Type & type() const
Definition: SkSLSymbol.h:42
bool isStorageTexture() const
Definition: SkSLType.h:371
virtual const Layout & layout() const
LayoutFlags fFlags
Definition: SkSLLayout.h:112

◆ argument_needs_scratch_variable()

static bool SkSL::argument_needs_scratch_variable ( const Expression arg,
const Variable param,
const ProgramUsage usage 
)
static

Definition at line 518 of file SkSLInliner.cpp.

520 {
521 // If the parameter isn't written to within the inline function ...
522 const ProgramUsage::VariableCounts& paramUsage = usage.get(*param);
523 if (!paramUsage.fWrite) {
524 // ... and can be inlined trivially (e.g. a swizzle, or a constant array index),
525 // or any expression without side effects that is only accessed at most once...
526 if ((paramUsage.fRead > 1) ? Analysis::IsTrivialExpression(*arg)
527 : !Analysis::HasSideEffects(*arg)) {
528 // ... we don't need to copy it at all! We can just use the existing expression.
529 return false;
530 }
531 }
532 // We need a scratch variable.
533 return true;
534}
bool IsTrivialExpression(const Expression &expr)
bool HasSideEffects(const Expression &expr)
static void usage(char *argv0)

◆ arguments_match_field_types()

static bool SkSL::arguments_match_field_types ( const ExpressionArray args,
const Type type 
)
static

Definition at line 62 of file SkSLConstructorStruct.cpp.

63 {
64 SkASSERT(type.fields().size() == SkToSizeT(args.size()));
65
66 for (int index = 0; index < args.size(); ++index) {
67 const std::unique_ptr<Expression>& argument = args[index];
68 const Field& field = type.fields()[index];
69 if (!argument->type().matches(*field.fType)) {
70 return false;
71 }
72 }
73
74 return true;
75}
#define SkASSERT(cond)
Definition: SkAssert.h:116
constexpr size_t SkToSizeT(S x)
Definition: SkTo.h:31
GLenum type
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
const Type * fType
Definition: SkSLType.h:88

◆ binary_op_is_ambiguous_in_wgsl()

static bool SkSL::binary_op_is_ambiguous_in_wgsl ( Operator  op)
static

Definition at line 2536 of file SkSLWGSLCodeGenerator.cpp.

2536 {
2537 // WGSL always requires parentheses for some operators which are deemed to be ambiguous.
2538 // (8.19. Operator Precedence and Associativity)
2539 switch (op.kind()) {
2540 case OperatorKind::LOGICALOR:
2541 case OperatorKind::LOGICALAND:
2542 case OperatorKind::BITWISEOR:
2543 case OperatorKind::BITWISEAND:
2544 case OperatorKind::BITWISEXOR:
2545 case OperatorKind::SHL:
2546 case OperatorKind::SHR:
2547 case OperatorKind::LT:
2548 case OperatorKind::GT:
2549 case OperatorKind::LTEQ:
2550 case OperatorKind::GTEQ:
2551 return true;
2552
2553 default:
2554 return false;
2555 }
2556}
Kind kind() const
Definition: SkSLOperator.h:85

◆ bitwise_not_operand()

static std::unique_ptr< Expression > SkSL::bitwise_not_operand ( const Context context,
Position  pos,
std::unique_ptr< Expression operand 
)
static

Definition at line 198 of file SkSLPrefixExpression.cpp.

200 {
201 SkASSERT(operand->type().componentType().isInteger());
202
203 const Expression* value = ConstantFolder::GetConstantValueForVariable(*operand);
204
205 switch (value->kind()) {
206 case Expression::Kind::kLiteral:
207 case Expression::Kind::kConstructorSplat:
208 case Expression::Kind::kConstructorCompound: {
209 // Convert ~vecN(1, 2, ...) to vecN(~1, ~2, ...).
210 if (std::unique_ptr<Expression> expr = apply_to_elements(context, pos, *value,
212 return expr;
213 }
214 break;
215 }
216 case Expression::Kind::kPrefix: {
217 // Convert `~(~expression)` into `expression`.
218 PrefixExpression& prefix = operand->as<PrefixExpression>();
219 if (prefix.getOperator().kind() == Operator::Kind::BITWISENOT) {
220 prefix.operand()->fPosition = pos;
221 return std::move(prefix.operand());
222 }
223 break;
224 }
225 default:
226 break;
227 }
228
229 // No simplified form; convert expression to Prefix(BITWISENOT, expression).
230 return std::make_unique<PrefixExpression>(pos, Operator::Kind::BITWISENOT, std::move(operand));
231}
uint8_t value
static double bitwise_not_value(double value)
static std::unique_ptr< Expression > apply_to_elements(const Context &context, Position pos, const Expression &expr, double(*fn)(double))

◆ bitwise_not_value()

static double SkSL::bitwise_not_value ( double  value)
static

Definition at line 39 of file SkSLPrefixExpression.cpp.

39 {
40 return ~static_cast<SKSL_INT>(value);
41}

◆ block_for_case()

static bool SkSL::block_for_case ( Statement caseBlock,
SwitchCase caseToCapture 
)
static

Definition at line 84 of file SkSLSwitchStatement.cpp.

84 {
85 // This function reduces a switch to the matching case (or cases, if fallthrough occurs) when
86 // the switch-value is known and no conditional breaks exist. If conversion is not possible,
87 // false is returned and no changes are made. Conversion can fail if the switch contains
88 // conditional breaks.
89 //
90 // We have to be careful to not move any of the pointers until after we're sure we're going to
91 // succeed, so before we make any changes at all, we check the switch-cases to decide on a plan
92 // of action.
93 //
94 // First, we identify the code that would be run if the switch's value matches `caseToCapture`.
95 StatementArray& cases = caseBlock->as<Block>().children();
96 auto iter = cases.begin();
97 for (; iter != cases.end(); ++iter) {
98 const SwitchCase& sc = (*iter)->as<SwitchCase>();
99 if (&sc == caseToCapture) {
100 break;
101 }
102 }
103
104 // Next, walk forward through the rest of the switch. If we find a conditional break, we're
105 // stuck and can't simplify at all. If we find an unconditional break, we have a range of
106 // statements that we can use for simplification.
107 auto startIter = iter;
108 bool removeBreakStatements = false;
109 for (; iter != cases.end(); ++iter) {
110 std::unique_ptr<Statement>& stmt = (*iter)->as<SwitchCase>().statement();
112 // We can't reduce switch-cases to a block when they have conditional exits.
113 return false;
114 }
116 // We found an unconditional exit. We can use this block, but we'll need to strip
117 // out the break statement if there is one.
118 removeBreakStatements = true;
119 ++iter;
120 break;
121 }
122 }
123
124 // We fell off the bottom of the switch or encountered a break. Next, we must strip down
125 // `caseBlock` to hold only the statements needed to execute `caseToCapture`. To do this, we
126 // eliminate the SwitchCase elements. This converts each `case n: stmt;` element into just
127 // `stmt;`. While doing this, we also move the elements to the front of the array if they
128 // weren't already there.
129 int numElements = SkToInt(std::distance(startIter, iter));
130 for (int index = 0; index < numElements; ++index, ++startIter) {
131 cases[index] = std::move((*startIter)->as<SwitchCase>().statement());
132 }
133
134 // Next, we shrink the statement array to destroy the excess statements.
135 cases.pop_back_n(cases.size() - numElements);
136
137 // If we found an unconditional break at the end, we need to eliminate that break.
138 if (removeBreakStatements) {
140 }
141
142 // We've stripped down `caseBlock` to contain only the captured case. Return true.
143 return true;
144}
constexpr int SkToInt(S x)
Definition: SkTo.h:29
void pop_back_n(int n)
Definition: SkTArray.h:330
int size() const
Definition: SkTArray.h:421
bool SwitchCaseContainsUnconditionalExit(const Statement &stmt)
bool SwitchCaseContainsConditionalExit(const Statement &stmt)
static void remove_break_statements(std::unique_ptr< Statement > &stmt)

◆ build_argument_type_list()

static std::string SkSL::build_argument_type_list ( SkSpan< const std::unique_ptr< Expression > >  arguments)
static

Definition at line 1107 of file SkSLFunctionCall.cpp.

1107 {
1108 std::string result = "(";
1109 auto separator = SkSL::String::Separator();
1110 for (const std::unique_ptr<Expression>& arg : arguments) {
1111 result += separator();
1112 result += arg->type().displayName();
1113 }
1114 return result + ")";
1115}
GAsyncResult * result
std::string void void auto Separator()
Definition: SkSLString.h:30

◆ calculate_count()

static int SkSL::calculate_count ( double  start,
double  end,
double  delta,
bool  forwards,
bool  inclusive 
)
static

Definition at line 38 of file SkSLGetLoopUnrollInfo.cpp.

38 {
39 if ((forwards && start > end) || (!forwards && start < end)) {
40 // The loop starts in a completed state (the start has already advanced past the end).
41 return 0;
42 }
43 if ((delta == 0.0) || forwards != (delta > 0.0)) {
44 // The loop does not progress toward a completed state, and will never terminate.
46 }
47 double iterations = sk_ieee_double_divide(end - start, delta);
48 double count = std::ceil(iterations);
49 if (inclusive && (count == iterations)) {
50 count += 1.0;
51 }
53 // The loop runs for more iterations than we can safely unroll.
55 }
56 return (int)count;
57}
int count
Definition: FontMgrTest.cpp:50
static constexpr double sk_ieee_double_divide(double numer, double denom)
glong glong end
static constexpr int kLoopTerminationLimit
SINT bool isfinite(const Vec< N, T > &v)
Definition: SkVx.h:1003
SIN Vec< N, float > ceil(const Vec< N, float > &x)
Definition: SkVx.h:702

◆ call_cost()

static CoercionCost SkSL::call_cost ( const Context context,
const FunctionDeclaration function,
const ExpressionArray arguments 
)
static

Used to determine the best overload for a function call by calculating the cost of coercing the arguments of the function to the required types. Cost has no particular meaning other than "lower costs are preferred". Returns CoercionCost::Impossible() if the call is not valid. This is never called for functions with only one definition.

Definition at line 1054 of file SkSLFunctionCall.cpp.

1056 {
1057 // Strict-ES2 programs can never call an `$es3` function.
1058 if (context.fConfig->strictES2Mode() && function.modifierFlags().isES3()) {
1059 return CoercionCost::Impossible();
1060 }
1061 // Functions with the wrong number of parameters are never a match.
1062 if (function.parameters().size() != SkToSizeT(arguments.size())) {
1063 return CoercionCost::Impossible();
1064 }
1065 // If the arguments cannot be coerced to the parameter types, the function is never a match.
1066 FunctionDeclaration::ParamTypes types;
1067 const Type* ignored;
1068 if (!function.determineFinalTypes(arguments, &types, &ignored)) {
1069 return CoercionCost::Impossible();
1070 }
1071 // If the arguments do not match the parameter types due to mismatched modifiers, the function
1072 // is never a match.
1073 for (int i = 0; i < arguments.size(); i++) {
1074 const Expression& arg = *arguments[i];
1075 const Variable& param = *function.parameters()[i];
1076 if (!argument_and_parameter_flags_match(arg, param)) {
1077 return CoercionCost::Impossible();
1078 }
1079 }
1080 // Return the sum of coercion costs of each argument.
1081 CoercionCost total = CoercionCost::Free();
1082 for (int i = 0; i < arguments.size(); i++) {
1083 total = total + arguments[i]->coercionCost(*types[i]);
1084 }
1085 return total;
1086}
ProgramConfig * fConfig
Definition: SkSLContext.h:33
Dart_NativeFunction function
Definition: fuchsia.cc:51
static bool argument_and_parameter_flags_match(const Expression &argument, const Variable &parameter)
static void Free(FreeList *free_list, uword address, intptr_t size, bool is_protected)

◆ call_signature_is_valid()

static bool SkSL::call_signature_is_valid ( const Context context,
const Variable child,
const ExpressionArray arguments 
)
static

Definition at line 39 of file SkSLChildCall.cpp.

41 {
42 const Type* half4 = context.fTypes.fHalf4.get();
43 const Type* float2 = context.fTypes.fFloat2.get();
44
45 auto params = [&]() -> STArray<2, const Type*> {
46 switch (child.type().typeKind()) {
47 case Type::TypeKind::kBlender: return { half4, half4 };
48 case Type::TypeKind::kColorFilter: return { half4 };
49 case Type::TypeKind::kShader: return { float2 };
50 default:
52 }
53 }();
54
55 if (params.size() != arguments.size()) {
56 return false;
57 }
58 for (int i = 0; i < arguments.size(); i++) {
59 if (!arguments[i]->type().matches(*params[i])) {
60 return false;
61 }
62 }
63 return true;
64}
#define SkUNREACHABLE
Definition: SkAssert.h:135
const std::unique_ptr< Type > fFloat2
const std::unique_ptr< Type > fHalf4
const BuiltinTypes & fTypes
Definition: SkSLContext.h:30
TypeKind typeKind() const
Definition: SkSLType.h:283
const EmbeddedViewParams * params
Vec< 4, uint16_t > half4
Definition: SkVx.h:1176
Definition: SkVx.h:83

◆ candidate_func()

static const FunctionDeclaration & SkSL::candidate_func ( const InlineCandidate candidate)
static

Definition at line 964 of file SkSLInliner.cpp.

964 {
965 return (*candidate.fCandidateExpr)->as<FunctionCall>().function();
966}
std::unique_ptr< Expression > * fCandidateExpr

◆ cast_constant_array()

static std::unique_ptr< Expression > SkSL::cast_constant_array ( const Context context,
Position  pos,
const Type destType,
std::unique_ptr< Expression constCtor 
)
static

Definition at line 22 of file SkSLConstructorArrayCast.cpp.

25 {
26 const Type& scalarType = destType.componentType();
27
28 // Create a ConstructorArray(...) which typecasts each argument inside.
29 auto inputArgs = constCtor->as<ConstructorArray>().argumentSpan();
30 ExpressionArray typecastArgs;
31 typecastArgs.reserve_exact(inputArgs.size());
32 for (std::unique_ptr<Expression>& arg : inputArgs) {
33 Position argPos = arg->fPosition;
34 if (arg->type().isScalar()) {
35 typecastArgs.push_back(ConstructorScalarCast::Make(context, argPos, scalarType,
36 std::move(arg)));
37 } else {
38 typecastArgs.push_back(ConstructorCompoundCast::Make(context, argPos, scalarType,
39 std::move(arg)));
40 }
41 }
42
43 return ConstructorArray::Make(context, pos, destType, std::move(typecastArgs));
44}
const T & as() const
Definition: SkSLType.h:210
void reserve_exact(int n)
Definition: SkTArray.h:181
SK_API sk_sp< SkDocument > Make(SkWStream *dst, const SkSerialProcs *=nullptr, std::function< void(const SkPicture *)> onEndPage=nullptr)

◆ cast_constant_composite()

static std::unique_ptr< Expression > SkSL::cast_constant_composite ( const Context context,
Position  pos,
const Type destType,
std::unique_ptr< Expression constCtor 
)
static

Definition at line 25 of file SkSLConstructorCompoundCast.cpp.

28 {
29 const Type& scalarType = destType.componentType();
30
31 // We generate nicer code for splats and diagonal matrices by handling them separately instead
32 // of relying on the constant-subexpression code below. This is not truly necessary but it makes
33 // our output look a little better; human beings prefer `half4(0)` to `half4(0, 0, 0, 0)`.
34 if (constCtor->is<ConstructorSplat>()) {
35 // This is a typecast of a splat containing a constant value, e.g. `half4(7)`. We can
36 // replace it with a splat of a different type, e.g. `int4(7)`.
37 ConstructorSplat& splat = constCtor->as<ConstructorSplat>();
39 context, pos, destType,
40 ConstructorScalarCast::Make(context, pos, scalarType, std::move(splat.argument())));
41 }
42
43 if (constCtor->is<ConstructorDiagonalMatrix>() && destType.isMatrix()) {
44 // This is a typecast of a constant diagonal matrix, e.g. `float3x3(2)`. We can replace it
45 // with a diagonal matrix of a different type, e.g. `half3x3(2)`.
46 ConstructorDiagonalMatrix& matrixCtor = constCtor->as<ConstructorDiagonalMatrix>();
48 context, pos, destType,
49 ConstructorScalarCast::Make(context, pos, scalarType,
50 std::move(matrixCtor.argument())));
51 }
52
53 // Create a compound Constructor(literal, ...) which typecasts each scalar value inside.
54 size_t numSlots = destType.slotCount();
55 SkASSERT(numSlots == constCtor->type().slotCount());
56
57 double typecastArgs[16];
58 SkASSERT(numSlots <= std::size(typecastArgs));
59 for (size_t index = 0; index < numSlots; ++index) {
60 std::optional<double> slotVal = constCtor->getConstantValue(index);
61 if (scalarType.checkForOutOfRangeLiteral(context, *slotVal, constCtor->fPosition)) {
62 // We've reported an error because the literal is out of range for this type. Zero out
63 // the value to avoid a cascade of errors.
64 *slotVal = 0.0;
65 }
66 typecastArgs[index] = *slotVal;
67 }
68
69 return ConstructorCompound::MakeFromConstants(context, pos, destType, typecastArgs);
70}
std::unique_ptr< Expression > & argument()
virtual bool isMatrix() const
Definition: SkSLType.h:528

◆ cast_expression()

static std::unique_ptr< Expression > SkSL::cast_expression ( const Context context,
Position  pos,
const Expression expr,
const Type type 
)
static

Definition at line 279 of file SkSLConstantFolder.cpp.

282 {
283 SkASSERT(type.componentType().matches(expr.type().componentType()));
284 if (expr.type().isScalar()) {
285 if (type.isMatrix()) {
286 return ConstructorDiagonalMatrix::Make(context, pos, type, expr.clone());
287 }
288 if (type.isVector()) {
289 return ConstructorSplat::Make(context, pos, type, expr.clone());
290 }
291 }
292 if (type.matches(expr.type())) {
293 return expr.clone(pos);
294 }
295 // We can't cast matrices into vectors or vice-versa.
296 return nullptr;
297}
virtual std::unique_ptr< Expression > clone(Position pos) const =0
virtual bool isScalar() const
Definition: SkSLType.h:512

◆ check_main_signature()

static bool SkSL::check_main_signature ( const Context context,
Position  pos,
const Type returnType,
TArray< std::unique_ptr< Variable > > &  parameters 
)
static

Definition at line 132 of file SkSLFunctionDeclaration.cpp.

133 {
134 ErrorReporter& errors = *context.fErrors;
135 ProgramKind kind = context.fConfig->fKind;
136
137 auto typeIsValidForAttributes = [](const Type& type) {
138 return type.isStruct() && type.name() == "Attributes";
139 };
140
141 auto typeIsValidForVaryings = [](const Type& type) {
142 return type.isStruct() && type.name() == "Varyings";
143 };
144
145 auto paramIsCoords = [&](int idx) {
146 const Variable& p = *parameters[idx];
147 return type_is_valid_for_coords(p.type()) && p.modifierFlags() == ModifierFlag::kNone;
148 };
149
150 auto paramIsColor = [&](int idx) {
151 const Variable& p = *parameters[idx];
152 return type_is_valid_for_color(p.type()) && p.modifierFlags() == ModifierFlag::kNone;
153 };
154
155 auto paramIsConstInAttributes = [&](int idx) {
156 const Variable& p = *parameters[idx];
157 return typeIsValidForAttributes(p.type()) && p.modifierFlags() == ModifierFlag::kConst;
158 };
159
160 auto paramIsConstInVaryings = [&](int idx) {
161 const Variable& p = *parameters[idx];
162 return typeIsValidForVaryings(p.type()) && p.modifierFlags() == ModifierFlag::kConst;
163 };
164
165 auto paramIsOutColor = [&](int idx) {
166 const Variable& p = *parameters[idx];
167 return type_is_valid_for_color(p.type()) && p.modifierFlags() == ModifierFlag::kOut;
168 };
169
170 switch (kind) {
171 case ProgramKind::kRuntimeColorFilter:
172 case ProgramKind::kPrivateRuntimeColorFilter: {
173 // (half4|float4) main(half4|float4)
174 if (!type_is_valid_for_color(returnType)) {
175 errors.error(pos, "'main' must return: 'vec4', 'float4', or 'half4'");
176 return false;
177 }
178 bool validParams = (parameters.size() == 1 && paramIsColor(0));
179 if (!validParams) {
180 errors.error(pos, "'main' parameter must be 'vec4', 'float4', or 'half4'");
181 return false;
182 }
183 break;
184 }
185 case ProgramKind::kRuntimeShader:
186 case ProgramKind::kPrivateRuntimeShader: {
187 // (half4|float4) main(float2)
188 if (!type_is_valid_for_color(returnType)) {
189 errors.error(pos, "'main' must return: 'vec4', 'float4', or 'half4'");
190 return false;
191 }
192 if (!(parameters.size() == 1 && paramIsCoords(0))) {
193 errors.error(pos, "'main' parameter must be 'float2' or 'vec2'");
194 return false;
195 }
196 break;
197 }
198 case ProgramKind::kRuntimeBlender:
199 case ProgramKind::kPrivateRuntimeBlender: {
200 // (half4|float4) main(half4|float4, half4|float4)
201 if (!type_is_valid_for_color(returnType)) {
202 errors.error(pos, "'main' must return: 'vec4', 'float4', or 'half4'");
203 return false;
204 }
205 if (!(parameters.size() == 2 && paramIsColor(0) && paramIsColor(1))) {
206 errors.error(pos, "'main' parameters must be (vec4|float4|half4, "
207 "vec4|float4|half4)");
208 return false;
209 }
210 break;
211 }
212 case ProgramKind::kMeshVertex: {
213 // Varyings main(const Attributes)
214 if (!typeIsValidForVaryings(returnType)) {
215 errors.error(pos, "'main' must return 'Varyings'.");
216 return false;
217 }
218 if (!(parameters.size() == 1 && paramIsConstInAttributes(0))) {
219 errors.error(pos, "'main' parameter must be 'const Attributes'.");
220 return false;
221 }
222 break;
223 }
224 case ProgramKind::kMeshFragment: {
225 // float2 main(const Varyings) -or- float2 main(const Varyings, out half4|float4)
226 if (!type_is_valid_for_coords(returnType)) {
227 errors.error(pos, "'main' must return: 'vec2' or 'float2'");
228 return false;
229 }
230 if (!((parameters.size() == 1 && paramIsConstInVaryings(0)) ||
231 (parameters.size() == 2 && paramIsConstInVaryings(0) && paramIsOutColor(1)))) {
232 errors.error(pos,
233 "'main' parameters must be (const Varyings, (out (half4|float4))?)");
234 return false;
235 }
236 break;
237 }
238 case ProgramKind::kFragment:
239 case ProgramKind::kGraphiteFragment:
240 case ProgramKind::kGraphiteFragmentES2: {
241 bool validParams = (parameters.size() == 0) ||
242 (parameters.size() == 1 && paramIsCoords(0));
243 if (!validParams) {
244 errors.error(pos, "shader 'main' must be main() or main(float2)");
245 return false;
246 }
247 break;
248 }
249 case ProgramKind::kVertex:
250 case ProgramKind::kGraphiteVertex:
251 case ProgramKind::kGraphiteVertexES2:
252 case ProgramKind::kCompute:
253 if (!returnType.matches(*context.fTypes.fVoid)) {
254 errors.error(pos, "'main' must return 'void'");
255 return false;
256 }
257 if (parameters.size()) {
258 errors.error(pos, "shader 'main' must have zero parameters");
259 return false;
260 }
261 break;
262 }
263 return true;
264}
const std::unique_ptr< Type > fVoid
ErrorReporter * fErrors
Definition: SkSLContext.h:36
bool matches(const Type &other) const
Definition: SkSLType.h:269
static bool type_is_valid_for_coords(const Type &type)
static bool type_is_valid_for_color(const Type &type)

◆ check_modifiers()

static bool SkSL::check_modifiers ( const Context context,
Position  pos,
ModifierFlags  modifierFlags 
)
static

Definition at line 38 of file SkSLFunctionDeclaration.cpp.

38 {
39 const ModifierFlags permitted = ModifierFlag::kInline |
40 ModifierFlag::kNoInline |
41 (context.fConfig->fIsBuiltinCode ? ModifierFlag::kES3 |
42 ModifierFlag::kPure |
43 ModifierFlag::kExport
45 modifierFlags.checkPermittedFlags(context, pos, permitted);
46 if (modifierFlags.isInline() && modifierFlags.isNoInline()) {
47 context.fErrors->error(pos, "functions cannot be both 'inline' and 'noinline'");
48 return false;
49 }
50 return true;
51}
void error(Position position, std::string_view msg)
bool checkPermittedFlags(const Context &context, Position pos, ModifierFlags permittedModifierFlags) const

◆ check_parameters()

static bool SkSL::check_parameters ( const Context context,
TArray< std::unique_ptr< Variable > > &  parameters,
ModifierFlags  modifierFlags,
IntrinsicKind  intrinsicKind 
)
static

Definition at line 71 of file SkSLFunctionDeclaration.cpp.

74 {
75 // Check modifiers on each function parameter.
76 for (auto& param : parameters) {
77 const Type& type = param->type();
78 ModifierFlags permittedFlags = ModifierFlag::kConst | ModifierFlag::kIn;
79 LayoutFlags permittedLayoutFlags = LayoutFlag::kNone;
80 if (!type.isOpaque()) {
81 permittedFlags |= ModifierFlag::kOut;
82 }
83 if (type.isStorageTexture()) {
84 // We allow `readonly`, `writeonly` and `layout(pixel-format)` on storage textures.
85 permittedFlags |= ModifierFlag::kReadOnly | ModifierFlag::kWriteOnly;
86 permittedLayoutFlags |= LayoutFlag::kAllPixelFormats;
87
88 // Intrinsics are allowed to accept any pixel format, but user code must explicitly
89 // specify a pixel format like `layout(rgba32f)`.
90 if (intrinsicKind == kNotIntrinsic &&
91 !(param->layout().fFlags & LayoutFlag::kAllPixelFormats)) {
92 context.fErrors->error(param->fPosition, "storage texture parameters must specify "
93 "a pixel format layout-qualifier");
94 return false;
95 }
96 }
97 param->modifierFlags().checkPermittedFlags(context, param->modifiersPosition(),
98 permittedFlags);
99 param->layout().checkPermittedLayout(context, param->modifiersPosition(),
100 permittedLayoutFlags);
101 // Only the (builtin) declarations of 'sample' are allowed to have shader/colorFilter or FP
102 // parameters. You can pass other opaque types to functions safely; this restriction is
103 // specific to "child" objects.
104 if (type.isEffectChild() && !context.fConfig->fIsBuiltinCode) {
105 context.fErrors->error(param->fPosition, "parameters of type '" + type.displayName() +
106 "' not allowed");
107 return false;
108 }
109
110 // Pure functions should not change any state, and should be safe to eliminate if their
111 // result is not used; this is incompatible with out-parameters, so we forbid it here.
112 // (We don't exhaustively guard against pure functions changing global state in other ways,
113 // though, since they aren't allowed in user code.)
114 if (modifierFlags.isPure() && (param->modifierFlags() & ModifierFlag::kOut)) {
115 context.fErrors->error(param->modifiersPosition(),
116 "pure functions cannot have out parameters");
117 return false;
118 }
119 }
120 return true;
121}

◆ check_return_type()

static bool SkSL::check_return_type ( const Context context,
Position  pos,
const Type returnType 
)
static

Definition at line 53 of file SkSLFunctionDeclaration.cpp.

53 {
54 ErrorReporter& errors = *context.fErrors;
55 if (returnType.isArray()) {
56 errors.error(pos, "functions may not return type '" + returnType.displayName() + "'");
57 return false;
58 }
59 if (context.fConfig->strictES2Mode() && returnType.isOrContainsArray()) {
60 errors.error(pos, "functions may not return structs containing arrays");
61 return false;
62 }
63 if (!context.fConfig->fIsBuiltinCode && returnType.componentType().isOpaque()) {
64 errors.error(pos, "functions may not return opaque type '" + returnType.displayName() +
65 "'");
66 return false;
67 }
68 return true;
69}
virtual bool isArray() const
Definition: SkSLType.h:532
virtual bool isOrContainsArray() const
Definition: SkSLType.h:578
bool isOpaque() const
Definition: SkSLType.h:353
std::string displayName() const
Definition: SkSLType.h:234

◆ coalesce_n_way_vector()

static std::unique_ptr< Expression > SkSL::coalesce_n_way_vector ( const Expression arg0,
const Expression arg1,
double  startingState,
const Type returnType,
CoalesceFn  coalesce,
FinalizeFn  finalize 
)
static

Definition at line 84 of file SkSLFunctionCall.cpp.

89 {
90 // Takes up to two vector or scalar arguments and coalesces them in sequence:
91 // scalar = startingState;
92 // scalar = coalesce(scalar, arg0.x, arg1.x);
93 // scalar = coalesce(scalar, arg0.y, arg1.y);
94 // scalar = coalesce(scalar, arg0.z, arg1.z);
95 // scalar = coalesce(scalar, arg0.w, arg1.w);
96 // scalar = finalize(scalar);
97 //
98 // If an argument is null, zero is passed to the coalesce function. If the arguments are a mix
99 // of scalars and vectors, the scalars are interpreted as a vector containing the same value for
100 // every component.
101
102 Position pos = arg0->fPosition;
103 double minimumValue = returnType.componentType().minimumValue();
104 double maximumValue = returnType.componentType().maximumValue();
105
106 const Type& vecType = arg0->type().isVector() ? arg0->type() :
107 (arg1 && arg1->type().isVector()) ? arg1->type() :
108 arg0->type();
109 SkASSERT( arg0->type().componentType().matches(vecType.componentType()));
110 SkASSERT(!arg1 || arg1->type().componentType().matches(vecType.componentType()));
111
112 double value = startingState;
113 int arg0Index = 0;
114 int arg1Index = 0;
115 for (int index = 0; index < vecType.columns(); ++index) {
116 std::optional<double> arg0Value = arg0->getConstantValue(arg0Index);
117 arg0Index += arg0->type().isVector() ? 1 : 0;
118 SkASSERT(arg0Value.has_value());
119
120 std::optional<double> arg1Value = 0.0;
121 if (arg1) {
122 arg1Value = arg1->getConstantValue(arg1Index);
123 arg1Index += arg1->type().isVector() ? 1 : 0;
124 SkASSERT(arg1Value.has_value());
125 }
126
127 value = coalesce(value, *arg0Value, *arg1Value);
128
129 if (value >= minimumValue && value <= maximumValue) {
130 // This result will fit inside the return type.
131 } else {
132 // The value is outside the float range or is NaN (all if-checks fail); do not optimize.
133 return nullptr;
134 }
135 }
136
137 if (finalize) {
138 value = finalize(value);
139 }
140
141 return Literal::Make(pos, value, &returnType);
142}
Position fPosition
Definition: SkSLIRNode.h:109
virtual bool isVector() const
Definition: SkSLType.h:524
virtual int columns() const
Definition: SkSLType.h:429
virtual double maximumValue() const
Definition: SkSLType.h:449
virtual double minimumValue() const
Definition: SkSLType.h:444

◆ coalesce_pairwise_vectors()

template<typename T >
static std::unique_ptr< Expression > SkSL::coalesce_pairwise_vectors ( const IntrinsicArguments arguments,
double  startingState,
const Type returnType,
CoalesceFn  coalesce,
FinalizeFn  finalize 
)
static

Definition at line 159 of file SkSLFunctionCall.cpp.

163 {
164 SkASSERT(arguments[0]);
165 SkASSERT(arguments[1]);
166 SkASSERT(!arguments[2]);
167 type_check_expression<T>(*arguments[0]);
168 type_check_expression<T>(*arguments[1]);
169
170 return coalesce_n_way_vector(arguments[0], arguments[1],
171 startingState, returnType, coalesce, finalize);
172}
static std::unique_ptr< Expression > coalesce_n_way_vector(const Expression *arg0, const Expression *arg1, double startingState, const Type &returnType, CoalesceFn coalesce, FinalizeFn finalize)

◆ coalesce_vector()

template<typename T >
static std::unique_ptr< Expression > SkSL::coalesce_vector ( const IntrinsicArguments arguments,
double  startingState,
const Type returnType,
CoalesceFn  coalesce,
FinalizeFn  finalize 
)
static

Definition at line 145 of file SkSLFunctionCall.cpp.

149 {
150 SkASSERT(arguments[0]);
151 SkASSERT(!arguments[1]);
152 type_check_expression<T>(*arguments[0]);
153
154 return coalesce_n_way_vector(arguments[0], /*arg1=*/nullptr,
155 startingState, returnType, coalesce, finalize);
156}

◆ compile_and_shrink()

static std::unique_ptr< Module > SkSL::compile_and_shrink ( SkSL::Compiler compiler,
ProgramKind  kind,
const char *  moduleName,
std::string  moduleSource,
const Module parent 
)
static

Definition at line 147 of file SkSLModuleLoader.cpp.

151 {
152 std::unique_ptr<Module> m = compiler->compileModule(kind,
154 std::move(moduleSource),
155 parent,
156 /*shouldInline=*/true);
157 if (!m) {
158 SK_ABORT("Unable to load module %s", moduleName);
159 }
160
161 // We can eliminate FunctionPrototypes without changing the meaning of the module; the function
162 // declaration is still safely in the symbol table. This only impacts our ability to recreate
163 // the input verbatim, which we don't care about at runtime.
164 m->fElements.erase(std::remove_if(m->fElements.begin(), m->fElements.end(),
165 [](const std::unique_ptr<ProgramElement>& element) {
166 switch (element->kind()) {
167 case ProgramElement::Kind::kFunction:
168 case ProgramElement::Kind::kGlobalVar:
169 case ProgramElement::Kind::kInterfaceBlock:
170 case ProgramElement::Kind::kStructDefinition:
171 // We need to preserve these.
172 return false;
173
174 case ProgramElement::Kind::kFunctionPrototype:
175 // These are already in the symbol table; the
176 // ProgramElement isn't needed anymore.
177 return true;
178
179 default:
180 SkDEBUGFAILF("Unsupported element: %s\n",
181 element->description().c_str());
182 return false;
183 }
184 }),
185 m->fElements.end());
186
187 m->fElements.shrink_to_fit();
188 return m;
189}
#define SK_ABORT(message,...)
Definition: SkAssert.h:70

◆ contains_builtin_struct()

static bool SkSL::contains_builtin_struct ( const ProgramUsage usage)
static

Definition at line 27 of file SkSLFindAndDeclareBuiltinStructs.cpp.

27 {
28 for (const auto& [symbol, count] : usage.fStructCounts) {
29 const Type& type = symbol->as<Type>();
30 if (type.isBuiltin()) {
31 return true;
32 }
33 }
34 return false;
35}

◆ contains_constant_zero()

static bool SkSL::contains_constant_zero ( const Expression expr)
static

Definition at line 343 of file SkSLConstantFolder.cpp.

343 {
344 int numSlots = expr.type().slotCount();
345 for (int index = 0; index < numSlots; ++index) {
346 std::optional<double> slotVal = expr.getConstantValue(index);
347 if (slotVal.has_value() && *slotVal == 0.0) {
348 return true;
349 }
350 }
351 return false;
352}

◆ contains_matching_data()

static bool SkSL::contains_matching_data ( const ProgramUsage a,
const ProgramUsage b 
)
static

Definition at line 220 of file SkSLProgramUsage.cpp.

220 {
221 constexpr bool kReportMismatch = false;
222
223 for (const auto& [varA, varCountA] : a.fVariableCounts) {
224 // Skip variable entries with zero reported usage.
225 if (!varCountA.fVarExists && !varCountA.fRead && !varCountA.fWrite) {
226 continue;
227 }
228 // Find the matching variable in the other map and ensure that its counts match.
229 const ProgramUsage::VariableCounts* varCountB = b.fVariableCounts.find(varA);
230 if (!varCountB || 0 != memcmp(&varCountA, varCountB, sizeof(varCountA))) {
231 if constexpr (kReportMismatch) {
232 SkDebugf("VariableCounts mismatch: '%.*s' (E%d R%d W%d != E%d R%d W%d)\n",
233 (int)varA->name().size(), varA->name().data(),
234 varCountA.fVarExists,
235 varCountA.fRead,
236 varCountA.fWrite,
237 varCountB ? varCountB->fVarExists : 0,
238 varCountB ? varCountB->fRead : 0,
239 varCountB ? varCountB->fWrite : 0);
240 }
241 return false;
242 }
243 }
244
245 for (const auto& [callA, callCountA] : a.fCallCounts) {
246 // Skip function-call entries with zero reported usage.
247 if (!callCountA) {
248 continue;
249 }
250 // Find the matching function in the other map and ensure that its call-count matches.
251 const int* callCountB = b.fCallCounts.find(callA);
252 if (!callCountB || callCountA != *callCountB) {
253 if constexpr (kReportMismatch) {
254 SkDebugf("CallCounts mismatch: '%.*s' (%d != %d)\n",
255 (int)callA->name().size(), callA->name().data(),
256 callCountA,
257 callCountB ? *callCountB : 0);
258 }
259 return false;
260 }
261 }
262
263 for (const auto& [structA, structCountA] : a.fStructCounts) {
264 // Skip struct entries with zero reported usage.
265 if (!structCountA) {
266 continue;
267 }
268 // Find the matching struct in the other map and ensure that its usage-count matches.
269 const int* structCountB = b.fStructCounts.find(structA);
270 if (!structCountB || structCountA != *structCountB) {
271 if constexpr (kReportMismatch) {
272 SkDebugf("StructCounts mismatch: '%.*s' (%d != %d)\n",
273 (int)structA->name().size(), structA->name().data(),
274 structCountA,
275 structCountB ? *structCountB : 0);
276 }
277 return false;
278 }
279 }
280
281 // Every non-zero entry in A has a matching non-zero entry in B.
282 return true;
283}
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
static bool b
struct MyStruct a[10]

◆ convert_compound_constructor()

static std::unique_ptr< Expression > SkSL::convert_compound_constructor ( const Context context,
Position  pos,
const Type type,
ExpressionArray  args 
)
static

Definition at line 28 of file SkSLConstructor.cpp.

31 {
32 SkASSERT(type.isVector() || type.isMatrix());
33
34 // The meaning of a compound constructor containing a single argument varies significantly in
35 // GLSL/SkSL, depending on the argument type.
36 if (args.size() == 1) {
37 std::unique_ptr<Expression>& argument = args.front();
38 if (type.isVector() && argument->type().isVector() &&
39 argument->type().componentType().matches(type.componentType()) &&
40 argument->type().slotCount() > type.slotCount()) {
41 // Casting a vector-type into a smaller matching vector-type is a slice in GLSL.
42 // We don't allow those casts in SkSL; recommend a swizzle instead.
43 // Only `.xy` and `.xyz` are valid recommendations here, because `.x` would imply a
44 // scalar(vector) cast, and nothing has more slots than `.xyzw`.
45 const char* swizzleHint;
46 switch (type.slotCount()) {
47 case 2: swizzleHint = "; use '.xy' instead"; break;
48 case 3: swizzleHint = "; use '.xyz' instead"; break;
49 default: swizzleHint = ""; SkDEBUGFAIL("unexpected slicing cast"); break;
50 }
51
52 context.fErrors->error(pos, "'" + argument->type().displayName() +
53 "' is not a valid parameter to '" + type.displayName() + "' constructor" +
54 swizzleHint);
55 return nullptr;
56 }
57
58 if (argument->type().isScalar()) {
59 // A constructor containing a single scalar is a splat (for vectors) or diagonal matrix
60 // (for matrices). It's legal regardless of the scalar's type, so synthesize an explicit
61 // conversion to the proper type. (This cast is a no-op if it's unnecessary; it can fail
62 // if we're casting a literal that exceeds the limits of the type.)
63 std::unique_ptr<Expression> typecast = ConstructorScalarCast::Convert(
64 context, pos, type.componentType(), std::move(args));
65 if (!typecast) {
66 return nullptr;
67 }
68
69 // Matrix-from-scalar creates a diagonal matrix; vector-from-scalar creates a splat.
70 return type.isMatrix()
71 ? ConstructorDiagonalMatrix::Make(context, pos, type, std::move(typecast))
72 : ConstructorSplat::Make(context, pos, type, std::move(typecast));
73 } else if (argument->type().isVector()) {
74 // A vector constructor containing a single vector with the same number of columns is a
75 // cast (e.g. float3 -> int3).
76 if (type.isVector() && argument->type().columns() == type.columns()) {
77 return ConstructorCompoundCast::Make(context, pos, type, std::move(argument));
78 }
79 } else if (argument->type().isMatrix()) {
80 // A matrix constructor containing a single matrix can be a resize, typecast, or both.
81 // GLSL lumps these into one category, but internally SkSL keeps them distinct.
82 if (type.isMatrix()) {
83 // First, handle type conversion. If the component types differ, synthesize the
84 // destination type with the argument's rows/columns. (This will be a no-op if it's
85 // already the right type.)
86 const Type& typecastType = type.componentType().toCompound(
87 context,
88 argument->type().columns(),
89 argument->type().rows());
90 argument = ConstructorCompoundCast::Make(context, pos, typecastType,
91 std::move(argument));
92
93 // Casting a matrix type into another matrix type is a resize.
94 return ConstructorMatrixResize::Make(context, pos, type,
95 std::move(argument));
96 }
97
98 // A vector constructor containing a single matrix can be compound construction if the
99 // matrix is 2x2 and the vector is 4-slot.
100 if (type.isVector() && type.columns() == 4 && argument->type().slotCount() == 4) {
101 // Casting a 2x2 matrix to a vector is a form of compound construction.
102 // First, reshape the matrix into a 4-slot vector of the same type.
103 const Type& vectorType = argument->type().componentType().toCompound(context,
104 /*columns=*/4,
105 /*rows=*/1);
106 std::unique_ptr<Expression> vecCtor =
107 ConstructorCompound::Make(context, pos, vectorType, std::move(args));
108
109 // Then, add a typecast to the result expression to ensure the types match.
110 // This will be a no-op if no typecasting is needed.
111 return ConstructorCompoundCast::Make(context, pos, type, std::move(vecCtor));
112 }
113 }
114 }
115
116 // For more complex cases, we walk the argument list and fix up the arguments as needed.
117 int expected = type.rows() * type.columns();
118 int actual = 0;
119 for (std::unique_ptr<Expression>& arg : args) {
120 if (!arg->type().isScalar() && !arg->type().isVector()) {
121 context.fErrors->error(pos, "'" + arg->type().displayName() +
122 "' is not a valid parameter to '" + type.displayName() + "' constructor");
123 return nullptr;
124 }
125
126 // Rely on Constructor::Convert to force this subexpression to the proper type. If it's a
127 // literal, this will make sure it's the right type of literal. If an expression of matching
128 // type, the expression will be returned as-is. If it's an expression of mismatched type,
129 // this adds a cast.
130 const Type& ctorType = type.componentType().toCompound(context, arg->type().columns(),
131 /*rows=*/1);
132 ExpressionArray ctorArg;
133 ctorArg.push_back(std::move(arg));
134 arg = Constructor::Convert(context, pos, ctorType, std::move(ctorArg));
135 if (!arg) {
136 return nullptr;
137 }
138 actual += ctorType.columns();
139 }
140
141 if (actual != expected) {
142 context.fErrors->error(pos, "invalid arguments to '" + type.displayName() +
143 "' constructor (expected " + std::to_string(expected) +
144 " scalars, but found " + std::to_string(actual) + ")");
145 return nullptr;
146 }
147
148 return ConstructorCompound::Make(context, pos, type, std::move(args));
149}
#define SkDEBUGFAIL(message)
Definition: SkAssert.h:118
std::unique_ptr< Expression > Convert(const Context &context, Position pos, const Type &type, ExpressionArray args)
Definition: ref_ptr.h:256
static SkString to_string(int n)
Definition: nanobench.cpp:119

◆ count_returns_at_end_of_control_flow()

static int SkSL::count_returns_at_end_of_control_flow ( const FunctionDefinition funcDef)
static

Definition at line 23 of file SkSLGetReturnComplexity.cpp.

23 {
24 class CountReturnsAtEndOfControlFlow : public ProgramVisitor {
25 public:
26 CountReturnsAtEndOfControlFlow(const FunctionDefinition& funcDef) {
27 this->visitProgramElement(funcDef);
28 }
29
30 bool visitExpression(const Expression& expr) override {
31 // Do not recurse into expressions.
32 return false;
33 }
34
35 bool visitStatement(const Statement& stmt) override {
36 switch (stmt.kind()) {
37 case Statement::Kind::kBlock: {
38 // Check only the last statement of a block.
39 const auto& block = stmt.as<Block>();
40 return block.children().size() &&
41 this->visitStatement(*block.children().back());
42 }
43 case Statement::Kind::kSwitch:
44 case Statement::Kind::kDo:
45 case Statement::Kind::kFor:
46 // Don't introspect switches or loop structures at all.
47 return false;
48
49 case Statement::Kind::kReturn:
50 ++fNumReturns;
51 [[fallthrough]];
52
53 default:
54 return INHERITED::visitStatement(stmt);
55 }
56 }
57
58 int fNumReturns = 0;
59 using INHERITED = ProgramVisitor;
60 };
61
62 return CountReturnsAtEndOfControlFlow{funcDef}.fNumReturns;
63}
#define INHERITED(method,...)
Definition: SkRecorder.cpp:128
virtual bool visitStatement(typename T::Statement &statement)
virtual bool visitExpression(typename T::Expression &expression)
virtual bool visitProgramElement(typename T::ProgramElement &programElement)

◆ dead_function_predicate()

static bool SkSL::dead_function_predicate ( const ProgramElement element,
ProgramUsage usage 
)
static

Definition at line 25 of file SkSLEliminateDeadFunctions.cpp.

25 {
26 if (!element->is<FunctionDefinition>()) {
27 return false;
28 }
29 const FunctionDefinition& fn = element->as<FunctionDefinition>();
30 if (fn.declaration().isMain() || usage->get(fn.declaration()) > 0) {
31 return false;
32 }
33 // This function is about to be eliminated by remove_if; update ProgramUsage accordingly.
34 usage->remove(*element);
35 return true;
36}

◆ eliminate_dead_local_variables()

static bool SkSL::eliminate_dead_local_variables ( const Context context,
SkSpan< std::unique_ptr< ProgramElement > >  elements,
ProgramUsage usage 
)
static

Definition at line 39 of file SkSLEliminateDeadLocalVariables.cpp.

41 {
42 class DeadLocalVariableEliminator : public ProgramWriter {
43 public:
44 DeadLocalVariableEliminator(const Context& context, ProgramUsage* usage)
45 : fContext(context)
46 , fUsage(usage) {}
47
48 using ProgramWriter::visitProgramElement;
49
50 bool visitExpressionPtr(std::unique_ptr<Expression>& expr) override {
51 if (expr->is<BinaryExpression>()) {
52 // Search for expressions of the form `deadVar = anyExpression`.
53 BinaryExpression& binary = expr->as<BinaryExpression>();
54 if (VariableReference* assignedVar = binary.isAssignmentIntoVariable()) {
55 if (fDeadVariables.contains(assignedVar->variable())) {
56 // Replace `deadVar = anyExpression` with `anyExpression`.
57 fUsage->remove(expr.get());
58 expr = std::move(binary.right());
59 fUsage->add(expr.get());
60
61 // If `anyExpression` is now a lone ExpressionStatement, it's highly likely
62 // that we can eliminate it entirely. This flag will let us know to check.
63 fAssignmentWasEliminated = true;
64
65 // Re-process the newly cleaned-up expression. This lets us fully clean up
66 // gnarly assignments like `a = b = 123;` where both `a` and `b` are dead,
67 // or silly double-assignments like `a = a = 123;`.
68 return this->visitExpressionPtr(expr);
69 }
70 }
71 }
72 if (expr->is<VariableReference>()) {
73 SkASSERT(!fDeadVariables.contains(expr->as<VariableReference>().variable()));
74 }
75 return INHERITED::visitExpressionPtr(expr);
76 }
77
78 bool visitStatementPtr(std::unique_ptr<Statement>& stmt) override {
79 if (stmt->is<VarDeclaration>()) {
80 VarDeclaration& varDecl = stmt->as<VarDeclaration>();
81 const Variable* var = varDecl.var();
82 ProgramUsage::VariableCounts* counts = fUsage->fVariableCounts.find(var);
84 SkASSERT(counts->fVarExists);
85 if (CanEliminate(var, *counts)) {
86 fDeadVariables.add(var);
87 if (var->initialValue()) {
88 // The variable has an initial-value expression, which might have side
89 // effects. ExpressionStatement::Make will preserve side effects, but
90 // replaces pure expressions with Nop.
91 fUsage->remove(stmt.get());
92 stmt = ExpressionStatement::Make(fContext, std::move(varDecl.value()));
93 fUsage->add(stmt.get());
94 } else {
95 // The variable has no initial-value and can be cleanly eliminated.
96 fUsage->remove(stmt.get());
97 stmt = Nop::Make();
98 }
99 fMadeChanges = true;
100
101 // Re-process the newly cleaned-up statement. This lets us fully clean up
102 // gnarly assignments like `a = b = 123;` where both `a` and `b` are dead,
103 // or silly double-assignments like `a = a = 123;`.
104 return this->visitStatementPtr(stmt);
105 }
106 }
107
108 bool result = INHERITED::visitStatementPtr(stmt);
109
110 // If we eliminated an assignment above, we may have left behind an inert
111 // ExpressionStatement.
112 if (fAssignmentWasEliminated) {
113 fAssignmentWasEliminated = false;
114 if (stmt->is<ExpressionStatement>()) {
115 ExpressionStatement& exprStmt = stmt->as<ExpressionStatement>();
116 if (!Analysis::HasSideEffects(*exprStmt.expression())) {
117 // The expression-statement was inert; eliminate it entirely.
118 fUsage->remove(&exprStmt);
119 stmt = Nop::Make();
120 }
121 }
122 }
123
124 return result;
125 }
126
127 static bool CanEliminate(const Variable* var, const ProgramUsage::VariableCounts& counts) {
128 return counts.fVarExists && !counts.fRead && var->storage() == VariableStorage::kLocal;
129 }
130
131 bool fMadeChanges = false;
132 const Context& fContext;
133 ProgramUsage* fUsage;
134 THashSet<const Variable*> fDeadVariables;
135 bool fAssignmentWasEliminated = false;
136
137 using INHERITED = ProgramWriter;
138 };
139
140 DeadLocalVariableEliminator visitor{context, usage};
141
142 for (auto& [var, counts] : usage->fVariableCounts) {
143 if (DeadLocalVariableEliminator::CanEliminate(var, counts)) {
144 // This program contains at least one dead local variable.
145 // Scan the program for any dead local variables and eliminate them all.
146 for (std::unique_ptr<ProgramElement>& pe : elements) {
147 if (pe->is<FunctionDefinition>()) {
148 visitor.visitProgramElement(*pe);
149 }
150 }
151 break;
152 }
153 }
154
155 return visitor.fMadeChanges;
156}
static std::unique_ptr< Statement > Make(const Context &context, std::unique_ptr< Expression > expr)
static std::unique_ptr< Statement > Make()
Definition: SkSLNop.h:26
bool visitExpressionPtr(std::unique_ptr< Expression > &e) override
bool visitStatementPtr(std::unique_ptr< Statement > &s) override
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core counts
Definition: switches.h:239

◆ eliminate_empty_statements()

static void SkSL::eliminate_empty_statements ( SkSpan< std::unique_ptr< ProgramElement > >  elements)
static

Definition at line 27 of file SkSLEliminateEmptyStatements.cpp.

27 {
28 class EmptyStatementEliminator : public ProgramWriter {
29 public:
30 bool visitExpressionPtr(std::unique_ptr<Expression>& expr) override {
31 // We don't need to look inside expressions at all.
32 return false;
33 }
34
35 bool visitStatementPtr(std::unique_ptr<Statement>& stmt) override {
36 // Work from the innermost blocks to the outermost.
37 INHERITED::visitStatementPtr(stmt);
38
39 if (stmt->is<Block>()) {
40 StatementArray& children = stmt->as<Block>().children();
41 auto iter = std::remove_if(children.begin(), children.end(),
42 [](std::unique_ptr<Statement>& stmt) {
43 return stmt->isEmpty();
44 });
45 children.resize(std::distance(children.begin(), iter));
46 }
47
48 // We always check the entire program.
49 return false;
50 }
51
52 using INHERITED = ProgramWriter;
53 };
54
55 for (std::unique_ptr<ProgramElement>& pe : elements) {
56 if (pe->is<FunctionDefinition>()) {
57 EmptyStatementEliminator visitor;
58 visitor.visitStatementPtr(pe->as<FunctionDefinition>().body());
59 }
60 }
61}
skia_private::STArray< 2, std::unique_ptr< Statement > > StatementArray
Definition: SkSLDefines.h:32

◆ eliminate_no_op_boolean()

static std::unique_ptr< Expression > SkSL::eliminate_no_op_boolean ( Position  pos,
const Expression left,
Operator  op,
const Expression right 
)
static

Definition at line 52 of file SkSLConstantFolder.cpp.

55 {
56 bool rightVal = right.as<Literal>().boolValue();
57
58 // Detect no-op Boolean expressions and optimize them away.
59 if ((op.kind() == Operator::Kind::LOGICALAND && rightVal) || // (expr && true) -> (expr)
60 (op.kind() == Operator::Kind::LOGICALOR && !rightVal) || // (expr || false) -> (expr)
61 (op.kind() == Operator::Kind::LOGICALXOR && !rightVal) || // (expr ^^ false) -> (expr)
62 (op.kind() == Operator::Kind::EQEQ && rightVal) || // (expr == true) -> (expr)
63 (op.kind() == Operator::Kind::NEQ && !rightVal)) { // (expr != false) -> (expr)
64
65 return left.clone(pos);
66 }
67
68 return nullptr;
69}
static bool left(const SkPoint &p0, const SkPoint &p1)
static bool right(const SkPoint &p0, const SkPoint &p1)

◆ eliminate_unnecessary_braces()

static void SkSL::eliminate_unnecessary_braces ( SkSpan< std::unique_ptr< ProgramElement > >  elements)
static

Definition at line 31 of file SkSLEliminateUnnecessaryBraces.cpp.

31 {
32 class UnnecessaryBraceEliminator : public ProgramWriter {
33 public:
34 bool visitExpressionPtr(std::unique_ptr<Expression>& expr) override {
35 // We don't need to look inside expressions at all.
36 return false;
37 }
38
39 bool visitStatementPtr(std::unique_ptr<Statement>& stmt) override {
40 // Work from the innermost blocks to the outermost.
41 INHERITED::visitStatementPtr(stmt);
42
43 switch (stmt->kind()) {
44 case StatementKind::kIf: {
45 IfStatement& ifStmt = stmt->as<IfStatement>();
46 EliminateBracesFrom(ifStmt.ifTrue());
47 EliminateBracesFrom(ifStmt.ifFalse());
48 break;
49 }
51 ForStatement& forStmt = stmt->as<ForStatement>();
52 EliminateBracesFrom(forStmt.statement());
53 break;
54 }
55 case StatementKind::kDo: {
56 DoStatement& doStmt = stmt->as<DoStatement>();
57 EliminateBracesFrom(doStmt.statement());
58 break;
59 }
60 default:
61 break;
62 }
63
64 // We always check the entire program.
65 return false;
66 }
67
68 static void EliminateBracesFrom(std::unique_ptr<Statement>& stmt) {
69 if (!stmt || !stmt->is<Block>()) {
70 return;
71 }
72 Block& block = stmt->as<Block>();
73 std::unique_ptr<Statement>* usefulStmt = nullptr;
74 for (std::unique_ptr<Statement>& childStmt : block.children()) {
75 if (childStmt->isEmpty()) {
76 continue;
77 }
78 if (usefulStmt) {
79 // We found two non-empty statements. We can't eliminate braces from
80 // this block.
81 return;
82 }
83 // We found one non-empty statement.
84 usefulStmt = &childStmt;
85 }
86
87 if (!usefulStmt) {
88 // This block held zero useful statements. Replace the block with a nop.
89 stmt = Nop::Make();
90 } else {
91 // This block held one useful statement. Replace the block with that statement.
92 stmt = std::move(*usefulStmt);
93 }
94 }
95
96 using INHERITED = ProgramWriter;
97 };
98
99 for (std::unique_ptr<ProgramElement>& pe : elements) {
100 if (pe->is<FunctionDefinition>()) {
101 UnnecessaryBraceEliminator visitor;
102 visitor.visitStatementPtr(pe->as<FunctionDefinition>().body());
103 }
104 }
105}

◆ eliminate_unreachable_code()

static void SkSL::eliminate_unreachable_code ( SkSpan< std::unique_ptr< ProgramElement > >  elements,
ProgramUsage usage 
)
static

Definition at line 35 of file SkSLEliminateUnreachableCode.cpp.

36 {
37 class UnreachableCodeEliminator : public ProgramWriter {
38 public:
39 UnreachableCodeEliminator(ProgramUsage* usage) : fUsage(usage) {
40 fFoundFunctionExit.push_back(false);
41 fFoundBlockExit.push_back(false);
42 }
43
44 bool visitExpressionPtr(std::unique_ptr<Expression>& expr) override {
45 // We don't need to look inside expressions at all.
46 return false;
47 }
48
49 bool visitStatementPtr(std::unique_ptr<Statement>& stmt) override {
50 if (fFoundFunctionExit.back() || fFoundBlockExit.back()) {
51 // If we already found an exit in this section, anything beyond it is dead code.
52 if (!stmt->is<Nop>()) {
53 // Eliminate the dead statement by substituting a Nop.
54 fUsage->remove(stmt.get());
55 stmt = Nop::Make();
56 }
57 return false;
58 }
59
60 switch (stmt->kind()) {
61 case Statement::Kind::kReturn:
63 // We found a function exit on this path.
64 fFoundFunctionExit.back() = true;
65 break;
66
67 case Statement::Kind::kBreak:
68 // A `break` statement can either be breaking out of a loop or terminating an
69 // individual switch case. We treat both cases the same way: they only apply
70 // to the statements associated with the parent statement (i.e. enclosing loop
71 // block / preceding case label).
73 fFoundBlockExit.back() = true;
74 break;
75
76 case Statement::Kind::kExpression:
78 case Statement::Kind::kVarDeclaration:
79 // These statements don't affect control flow.
80 break;
81
82 case Statement::Kind::kBlock:
83 // Blocks are on the straight-line path and don't affect control flow.
84 return INHERITED::visitStatementPtr(stmt);
85
86 case Statement::Kind::kDo: {
87 // Function-exits are allowed to propagate outside of a do-loop, because it
88 // always executes its body at least once.
89 fFoundBlockExit.push_back(false);
90 bool result = INHERITED::visitStatementPtr(stmt);
91 fFoundBlockExit.pop_back();
92 return result;
93 }
94 case Statement::Kind::kFor: {
95 // Function-exits are not allowed to propagate out, because a for-loop or while-
96 // loop could potentially run zero times.
97 fFoundFunctionExit.push_back(false);
98 fFoundBlockExit.push_back(false);
99 bool result = INHERITED::visitStatementPtr(stmt);
100 fFoundBlockExit.pop_back();
101 fFoundFunctionExit.pop_back();
102 return result;
103 }
104 case Statement::Kind::kIf: {
105 // This statement is conditional and encloses two inner sections of code.
106 // If both sides contain a function-exit or loop-exit, that exit is allowed to
107 // propagate out.
108 IfStatement& ifStmt = stmt->as<IfStatement>();
109
110 fFoundFunctionExit.push_back(false);
111 fFoundBlockExit.push_back(false);
112 bool result = (ifStmt.ifTrue() && this->visitStatementPtr(ifStmt.ifTrue()));
113 bool foundFunctionExitOnTrue = fFoundFunctionExit.back();
114 bool foundLoopExitOnTrue = fFoundBlockExit.back();
115 fFoundFunctionExit.pop_back();
116 fFoundBlockExit.pop_back();
117
118 fFoundFunctionExit.push_back(false);
119 fFoundBlockExit.push_back(false);
120 result |= (ifStmt.ifFalse() && this->visitStatementPtr(ifStmt.ifFalse()));
121 bool foundFunctionExitOnFalse = fFoundFunctionExit.back();
122 bool foundLoopExitOnFalse = fFoundBlockExit.back();
123 fFoundFunctionExit.pop_back();
124 fFoundBlockExit.pop_back();
125
126 fFoundFunctionExit.back() |= foundFunctionExitOnTrue &&
127 foundFunctionExitOnFalse;
128 fFoundBlockExit.back() |= foundLoopExitOnTrue &&
129 foundLoopExitOnFalse;
130 return result;
131 }
132 case Statement::Kind::kSwitch: {
133 // In switch statements we consider unreachable code on a per-case basis.
134 SwitchStatement& sw = stmt->as<SwitchStatement>();
135 bool result = false;
136
137 // Tracks whether we found at least one case that doesn't lead to a return
138 // statement (potentially via fallthrough).
139 bool foundCaseWithoutReturn = false;
140 bool hasDefault = false;
141 for (std::unique_ptr<Statement>& c : sw.cases()) {
142 // We eliminate unreachable code within the statements of the individual
143 // case. Breaks are not allowed to propagate outside the case statement
144 // itself. Function returns are allowed to propagate out only if all cases
145 // have a return AND one of the cases is default (so that we know at least
146 // one of the branches will be taken). This is similar to how we handle if
147 // statements above.
148 fFoundFunctionExit.push_back(false);
149 fFoundBlockExit.push_back(false);
150
151 SwitchCase& sc = c->as<SwitchCase>();
152 result |= this->visitStatementPtr(sc.statement());
153
154 // When considering whether a case has a return we can propagate, we
155 // assume the following:
156 // 1. The default case is always placed last in a switch statement and
157 // it is the last possible label reachable via fallthrough. Thus if
158 // it does not contain a return statement, then we don't propagate a
159 // function return.
160 // 2. In all other cases we prevent the return from propagating only if
161 // we encounter a break statement. If no return or break is found,
162 // we defer the decision to the fallthrough case. We won't propagate
163 // a return unless we eventually encounter a default label.
164 //
165 // See resources/sksl/shared/SwitchWithEarlyReturn.sksl for test cases that
166 // exercise this.
167 if (sc.isDefault()) {
168 foundCaseWithoutReturn |= !fFoundFunctionExit.back();
169 hasDefault = true;
170 } else {
171 // We can only be sure that a case does not lead to a return if it
172 // doesn't fallthrough.
173 foundCaseWithoutReturn |=
174 (!fFoundFunctionExit.back() && fFoundBlockExit.back());
175 }
176
177 fFoundFunctionExit.pop_back();
178 fFoundBlockExit.pop_back();
179 }
180
181 fFoundFunctionExit.back() |= !foundCaseWithoutReturn && hasDefault;
182 return result;
183 }
184 case Statement::Kind::kSwitchCase:
185 // We should never hit this case as switch cases are handled in the previous
186 // case.
188 }
189
190 return false;
191 }
192
193 ProgramUsage* fUsage;
194 STArray<32, bool> fFoundFunctionExit;
195 STArray<32, bool> fFoundBlockExit;
196
197 using INHERITED = ProgramWriter;
198 };
199
200 for (std::unique_ptr<ProgramElement>& pe : elements) {
201 if (pe->is<FunctionDefinition>()) {
202 UnreachableCodeEliminator visitor{usage};
203 visitor.visitStatementPtr(pe->as<FunctionDefinition>().body());
204 }
205 }
206}

◆ error_on_divide_by_zero()

static bool SkSL::error_on_divide_by_zero ( const Context context,
Position  pos,
Operator  op,
const Expression right 
)
static

Definition at line 423 of file SkSLConstantFolder.cpp.

424 {
425 switch (op.kind()) {
426 case Operator::Kind::SLASH:
427 case Operator::Kind::SLASHEQ:
428 case Operator::Kind::PERCENT:
429 case Operator::Kind::PERCENTEQ:
431 context.fErrors->error(pos, "division by zero");
432 return true;
433 }
434 return false;
435 default:
436 return false;
437 }
438}
static bool contains_constant_zero(const Expression &expr)

◆ evaluate_3_way_intrinsic()

static std::unique_ptr< Expression > SkSL::evaluate_3_way_intrinsic ( const Context context,
const IntrinsicArguments arguments,
const Type returnType,
EvaluateFn  eval 
)
static

Definition at line 319 of file SkSLFunctionCall.cpp.

322 {
323 SkASSERT(arguments[0]);
324 SkASSERT(arguments[1]);
325 SkASSERT(arguments[2]);
326 const Type& type = arguments[0]->type().componentType();
327
328 if (type.isFloat()) {
329 type_check_expression<float>(*arguments[0]);
330 type_check_expression<float>(*arguments[1]);
331 type_check_expression<float>(*arguments[2]);
332 } else if (type.isInteger()) {
333 type_check_expression<SKSL_INT>(*arguments[0]);
334 type_check_expression<SKSL_INT>(*arguments[1]);
335 type_check_expression<SKSL_INT>(*arguments[2]);
336 } else {
337 SkDEBUGFAILF("unsupported type %s", type.description().c_str());
338 return nullptr;
339 }
340
341 return evaluate_n_way_intrinsic(context, arguments[0], arguments[1], arguments[2],
342 returnType, eval);
343}
#define SkDEBUGFAILF(fmt,...)
Definition: SkAssert.h:119
void type_check_expression< SKSL_INT >(const Expression &expr)
static std::unique_ptr< Expression > evaluate_n_way_intrinsic(const Context &context, const Expression *arg0, const Expression *arg1, const Expression *arg2, const Type &returnType, EvaluateFn eval)
void type_check_expression< float >(const Expression &expr)

◆ evaluate_intrinsic()

template<typename T >
static std::unique_ptr< Expression > SkSL::evaluate_intrinsic ( const Context context,
const IntrinsicArguments arguments,
const Type returnType,
EvaluateFn  eval 
)
static

Definition at line 264 of file SkSLFunctionCall.cpp.

267 {
268 SkASSERT(arguments[0]);
269 SkASSERT(!arguments[1]);
270 type_check_expression<T>(*arguments[0]);
271
272 return evaluate_n_way_intrinsic(context, arguments[0], /*arg1=*/nullptr, /*arg2=*/nullptr,
273 returnType, eval);
274}

◆ evaluate_intrinsic_numeric()

static std::unique_ptr< Expression > SkSL::evaluate_intrinsic_numeric ( const Context context,
const IntrinsicArguments arguments,
const Type returnType,
EvaluateFn  eval 
)
static

Definition at line 276 of file SkSLFunctionCall.cpp.

279 {
280 SkASSERT(arguments[0]);
281 SkASSERT(!arguments[1]);
282 const Type& type = arguments[0]->type().componentType();
283
284 if (type.isFloat()) {
285 return evaluate_intrinsic<float>(context, arguments, returnType, eval);
286 }
287 if (type.isInteger()) {
288 return evaluate_intrinsic<SKSL_INT>(context, arguments, returnType, eval);
289 }
290
291 SkDEBUGFAILF("unsupported type %s", type.description().c_str());
292 return nullptr;
293}

◆ evaluate_n_way_intrinsic()

static std::unique_ptr< Expression > SkSL::evaluate_n_way_intrinsic ( const Context context,
const Expression arg0,
const Expression arg1,
const Expression arg2,
const Type returnType,
EvaluateFn  eval 
)
static

Definition at line 206 of file SkSLFunctionCall.cpp.

211 {
212 // Takes up to three arguments and evaluates all of them, left-to-right, in tandem.
213 // Equivalent to constructing a new compound value containing the results from:
214 // eval(arg0.x, arg1.x, arg2.x),
215 // eval(arg0.y, arg1.y, arg2.y),
216 // eval(arg0.z, arg1.z, arg2.z),
217 // eval(arg0.w, arg1.w, arg2.w)
218 //
219 // If an argument is null, zero is passed to the evaluation function. If the arguments are a mix
220 // of scalars and compounds, scalars are interpreted as a compound containing the same value for
221 // every component.
222
223 double minimumValue = returnType.componentType().minimumValue();
224 double maximumValue = returnType.componentType().maximumValue();
225 int slots = returnType.slotCount();
226 double array[16];
227
228 int arg0Index = 0;
229 int arg1Index = 0;
230 int arg2Index = 0;
231 for (int index = 0; index < slots; ++index) {
232 std::optional<double> arg0Value = arg0->getConstantValue(arg0Index);
233 arg0Index += arg0->type().isScalar() ? 0 : 1;
234 SkASSERT(arg0Value.has_value());
235
236 std::optional<double> arg1Value = 0.0;
237 if (arg1) {
238 arg1Value = arg1->getConstantValue(arg1Index);
239 arg1Index += arg1->type().isScalar() ? 0 : 1;
240 SkASSERT(arg1Value.has_value());
241 }
242
243 std::optional<double> arg2Value = 0.0;
244 if (arg2) {
245 arg2Value = arg2->getConstantValue(arg2Index);
246 arg2Index += arg2->type().isScalar() ? 0 : 1;
247 SkASSERT(arg2Value.has_value());
248 }
249
250 array[index] = eval(*arg0Value, *arg1Value, *arg2Value);
251
252 if (array[index] >= minimumValue && array[index] <= maximumValue) {
253 // This result will fit inside the return type.
254 } else {
255 // The value is outside the float range or is NaN (all if-checks fail); do not optimize.
256 return nullptr;
257 }
258 }
259
260 return ConstructorCompound::MakeFromConstants(context, arg0->fPosition, returnType, array);
261}

◆ evaluate_pairwise_intrinsic()

static std::unique_ptr< Expression > SkSL::evaluate_pairwise_intrinsic ( const Context context,
const IntrinsicArguments arguments,
const Type returnType,
EvaluateFn  eval 
)
static

Definition at line 295 of file SkSLFunctionCall.cpp.

298 {
299 SkASSERT(arguments[0]);
300 SkASSERT(arguments[1]);
301 SkASSERT(!arguments[2]);
302 const Type& type = arguments[0]->type().componentType();
303
304 if (type.isFloat()) {
305 type_check_expression<float>(*arguments[0]);
306 type_check_expression<float>(*arguments[1]);
307 } else if (type.isInteger()) {
308 type_check_expression<SKSL_INT>(*arguments[0]);
309 type_check_expression<SKSL_INT>(*arguments[1]);
310 } else {
311 SkDEBUGFAILF("unsupported type %s", type.description().c_str());
312 return nullptr;
313 }
314
315 return evaluate_n_way_intrinsic(context, arguments[0], arguments[1], /*arg2=*/nullptr,
316 returnType, eval);
317}

◆ extract_field()

static std::unique_ptr< Expression > SkSL::extract_field ( Position  pos,
const ConstructorStruct ctor,
int  fieldIndex 
)
static

Definition at line 65 of file SkSLFieldAccess.cpp.

67 {
68 // Confirm that the fields that are being removed are side-effect free.
69 const ExpressionArray& args = ctor.arguments();
70 int numFields = args.size();
71 for (int index = 0; index < numFields; ++index) {
72 if (fieldIndex == index) {
73 continue;
74 }
75 if (Analysis::HasSideEffects(*args[index])) {
76 return nullptr;
77 }
78 }
79
80 // Return the desired field.
81 return args[fieldIndex]->clone(pos);
82}
ExpressionArray & arguments()

◆ extract_matrix()

static void SkSL::extract_matrix ( const Expression expr,
float  mat[16] 
)
static

Definition at line 628 of file SkSLFunctionCall.cpp.

628 {
629 size_t numSlots = expr->type().slotCount();
630 for (size_t index = 0; index < numSlots; ++index) {
631 mat[index] = *expr->getConstantValue(index);
632 }
633}

◆ find_duplicate_case_values()

static TArray< const SwitchCase * > SkSL::find_duplicate_case_values ( const StatementArray cases)
static

Definition at line 40 of file SkSLSwitchStatement.cpp.

40 {
41 TArray<const SwitchCase*> duplicateCases;
42 THashSet<SKSL_INT> intValues;
43 bool foundDefault = false;
44
45 for (const std::unique_ptr<Statement>& stmt : cases) {
46 const SwitchCase* sc = &stmt->as<SwitchCase>();
47 if (sc->isDefault()) {
48 if (foundDefault) {
49 duplicateCases.push_back(sc);
50 continue;
51 }
52 foundDefault = true;
53 } else {
54 SKSL_INT value = sc->value();
55 if (intValues.contains(value)) {
56 duplicateCases.push_back(sc);
57 continue;
58 }
59 intValues.add(value);
60 }
61 }
62
63 return duplicateCases;
64}
int64_t SKSL_INT
Definition: SkSLDefines.h:16
SKSL_INT value() const
bool isDefault() const
void add(T item)
Definition: SkTHash.h:592
bool contains(const T &item) const
Definition: SkTHash.h:595

◆ find_existing_declaration()

static bool SkSL::find_existing_declaration ( const Context context,
Position  pos,
ModifierFlags  modifierFlags,
IntrinsicKind  intrinsicKind,
std::string_view  name,
TArray< std::unique_ptr< Variable > > &  parameters,
Position  returnTypePos,
const Type returnType,
FunctionDeclaration **  outExistingDecl 
)
static

Checks for a previously existing declaration of this function, reporting errors if there is an incompatible symbol. Returns true and sets outExistingDecl to point to the existing declaration (or null if none) on success, returns false on error.

Definition at line 346 of file SkSLFunctionDeclaration.cpp.

354 {
355 auto invalidDeclDescription = [&]() -> std::string {
356 TArray<Variable*> paramPtrs;
357 paramPtrs.reserve_exact(parameters.size());
358 for (std::unique_ptr<Variable>& param : parameters) {
359 paramPtrs.push_back(param.get());
360 }
361 return FunctionDeclaration(context,
362 pos,
363 modifierFlags,
364 name,
365 std::move(paramPtrs),
366 returnType,
367 intrinsicKind)
368 .description();
369 };
370
371 ErrorReporter& errors = *context.fErrors;
372 Symbol* entry = context.fSymbolTable->findMutable(name);
373 *outExistingDecl = nullptr;
374 if (entry) {
375 if (!entry->is<FunctionDeclaration>()) {
376 errors.error(pos, "symbol '" + std::string(name) + "' was already defined");
377 return false;
378 }
379 for (FunctionDeclaration* other = &entry->as<FunctionDeclaration>(); other;
380 other = other->mutableNextOverload()) {
381 SkASSERT(name == other->name());
382 if (!parameters_match(parameters, other->parameters())) {
383 continue;
384 }
385 if (!type_generically_matches(*returnType, other->returnType())) {
386 errors.error(returnTypePos, "functions '" + invalidDeclDescription() + "' and '" +
387 other->description() + "' differ only in return type");
388 return false;
389 }
390 for (int i = 0; i < parameters.size(); i++) {
391 if (parameters[i]->modifierFlags() != other->parameters()[i]->modifierFlags() ||
392 parameters[i]->layout() != other->parameters()[i]->layout()) {
393 errors.error(parameters[i]->fPosition,
394 "modifiers on parameter " + std::to_string(i + 1) +
395 " differ between declaration and definition");
396 return false;
397 }
398 }
399 if (other->definition() || other->isIntrinsic() ||
400 modifierFlags != other->modifierFlags()) {
401 errors.error(pos, "duplicate definition of '" + invalidDeclDescription() + "'");
402 return false;
403 }
404 *outExistingDecl = other;
405 break;
406 }
407 if (!*outExistingDecl && entry->as<FunctionDeclaration>().isMain()) {
408 errors.error(pos, "duplicate definition of 'main'");
409 return false;
410 }
411 }
412 return true;
413}
Symbol * findMutable(std::string_view name) const
static bool type_generically_matches(const Type &concreteType, const Type &maybeGenericType)
static bool parameters_match(SkSpan< const std::unique_ptr< Variable > > params, SkSpan< Variable *const > otherParams)
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32

◆ find_generic_index()

static int SkSL::find_generic_index ( const Type concreteType,
const Type genericType,
bool  allowNarrowing 
)
static

Given a concrete type (float3) and a generic type ($genType), returns the index of the concrete type within the generic type's typelist. Returns -1 if there is no match.

Definition at line 270 of file SkSLFunctionDeclaration.cpp.

272 {
273 SkSpan<const Type* const> genericTypes = genericType.coercibleTypes();
274 for (size_t index = 0; index < genericTypes.size(); ++index) {
275 if (concreteType.canCoerceTo(*genericTypes[index], allowNarrowing)) {
276 return index;
277 }
278 }
279 return -1;
280}
virtual SkSpan< const Type *const > coercibleTypes() const
Definition: SkSLType.h:476
bool canCoerceTo(const Type &other, bool allowNarrowing) const
Definition: SkSLType.h:388
constexpr size_t size() const
Definition: SkSpan_impl.h:95

◆ find_rt_adjust_index()

static std::optional< int > SkSL::find_rt_adjust_index ( SkSpan< const Field fields)
static

Definition at line 41 of file SkSLInterfaceBlock.cpp.

41 {
42 for (size_t index = 0; index < fields.size(); ++index) {
43 const SkSL::Field& f = fields[index];
44 if (f.fName == SkSL::Compiler::RTADJUST_NAME) {
45 return index;
46 }
47 }
48
49 return std::nullopt;
50}
static constexpr const char RTADJUST_NAME[]
Definition: SkSLCompiler.h:72

◆ FindIntrinsicKind()

IntrinsicKind SkSL::FindIntrinsicKind ( std::string_view  functionName)

Definition at line 26 of file SkSLIntrinsicList.cpp.

26 {
27 if (skstd::starts_with(functionName, '$')) {
28 functionName.remove_prefix(1);
29 }
30
31 const IntrinsicMap& intrinsicMap = GetIntrinsicMap();
32 IntrinsicKind* kind = intrinsicMap.find(functionName);
33 return kind ? *kind : kNotIntrinsic;
34}
const IntrinsicMap & GetIntrinsicMap()
skia_private::THashMap< std::string_view, IntrinsicKind > IntrinsicMap
constexpr bool starts_with(std::string_view str, std::string_view prefix)
Definition: SkStringView.h:17

◆ fold_expression()

static std::unique_ptr< Expression > SkSL::fold_expression ( Position  pos,
double  result,
const Type resultType 
)
static

Definition at line 653 of file SkSLConstantFolder.cpp.

655 {
656 if (resultType->isNumber()) {
657 if (result >= resultType->minimumValue() && result <= resultType->maximumValue()) {
658 // This result will fit inside its type.
659 } else {
660 // The value is outside the range or is NaN (all if-checks fail); do not optimize.
661 return nullptr;
662 }
663 }
664
665 return Literal::Make(pos, result, resultType);
666}
bool isNumber() const
Definition: SkSLType.h:304

◆ fold_two_constants()

static std::unique_ptr< Expression > SkSL::fold_two_constants ( const Context context,
Position  pos,
const Expression left,
Operator  op,
const Expression right,
const Type resultType 
)
static

Definition at line 668 of file SkSLConstantFolder.cpp.

673 {
676 const Type& leftType = left->type();
677 const Type& rightType = right->type();
678
679 // Handle pairs of integer literals.
680 if (left->isIntLiteral() && right->isIntLiteral()) {
681 using SKSL_UINT = uint64_t;
682 SKSL_INT leftVal = left->as<Literal>().intValue();
683 SKSL_INT rightVal = right->as<Literal>().intValue();
684
685 // Note that fold_expression returns null if the result would overflow its type.
686 #define RESULT(Op) fold_expression(pos, (SKSL_INT)(leftVal) Op \
687 (SKSL_INT)(rightVal), &resultType)
688 #define URESULT(Op) fold_expression(pos, (SKSL_INT)((SKSL_UINT)(leftVal) Op \
689 (SKSL_UINT)(rightVal)), &resultType)
690 switch (op.kind()) {
691 case Operator::Kind::PLUS: return URESULT(+);
692 case Operator::Kind::MINUS: return URESULT(-);
693 case Operator::Kind::STAR: return URESULT(*);
694 case Operator::Kind::SLASH:
695 if (leftVal == std::numeric_limits<SKSL_INT>::min() && rightVal == -1) {
696 context.fErrors->error(pos, "arithmetic overflow");
697 return nullptr;
698 }
699 return RESULT(/);
700
701 case Operator::Kind::PERCENT:
702 if (leftVal == std::numeric_limits<SKSL_INT>::min() && rightVal == -1) {
703 context.fErrors->error(pos, "arithmetic overflow");
704 return nullptr;
705 }
706 return RESULT(%);
707
708 case Operator::Kind::BITWISEAND: return RESULT(&);
709 case Operator::Kind::BITWISEOR: return RESULT(|);
710 case Operator::Kind::BITWISEXOR: return RESULT(^);
711 case Operator::Kind::EQEQ: return RESULT(==);
712 case Operator::Kind::NEQ: return RESULT(!=);
713 case Operator::Kind::GT: return RESULT(>);
714 case Operator::Kind::GTEQ: return RESULT(>=);
715 case Operator::Kind::LT: return RESULT(<);
716 case Operator::Kind::LTEQ: return RESULT(<=);
717 case Operator::Kind::SHL:
718 if (rightVal >= 0 && rightVal <= 31) {
719 // Left-shifting a negative (or really, any signed) value is undefined behavior
720 // in C++, but not in GLSL. Do the shift on unsigned values to avoid triggering
721 // an UBSAN error.
722 return URESULT(<<);
723 }
724 context.fErrors->error(pos, "shift value out of range");
725 return nullptr;
726
727 case Operator::Kind::SHR:
728 if (rightVal >= 0 && rightVal <= 31) {
729 return RESULT(>>);
730 }
731 context.fErrors->error(pos, "shift value out of range");
732 return nullptr;
733
734 default:
735 break;
736 }
737 #undef RESULT
738 #undef URESULT
739
740 return nullptr;
741 }
742
743 // Handle pairs of floating-point literals.
744 if (left->isFloatLiteral() && right->isFloatLiteral()) {
745 SKSL_FLOAT leftVal = left->as<Literal>().floatValue();
746 SKSL_FLOAT rightVal = right->as<Literal>().floatValue();
747
748 #define RESULT(Op) fold_expression(pos, leftVal Op rightVal, &resultType)
749 switch (op.kind()) {
750 case Operator::Kind::PLUS: return RESULT(+);
751 case Operator::Kind::MINUS: return RESULT(-);
752 case Operator::Kind::STAR: return RESULT(*);
753 case Operator::Kind::SLASH: return RESULT(/);
754 case Operator::Kind::EQEQ: return RESULT(==);
755 case Operator::Kind::NEQ: return RESULT(!=);
756 case Operator::Kind::GT: return RESULT(>);
757 case Operator::Kind::GTEQ: return RESULT(>=);
758 case Operator::Kind::LT: return RESULT(<);
759 case Operator::Kind::LTEQ: return RESULT(<=);
760 default: break;
761 }
762 #undef RESULT
763
764 return nullptr;
765 }
766
767 // Perform matrix multiplication.
768 if (op.kind() == Operator::Kind::STAR) {
769 if (leftType.isMatrix() && rightType.isMatrix()) {
770 return simplify_matrix_times_matrix(context, pos, *left, *right);
771 }
772 if (leftType.isVector() && rightType.isMatrix()) {
773 return simplify_vector_times_matrix(context, pos, *left, *right);
774 }
775 if (leftType.isMatrix() && rightType.isVector()) {
776 return simplify_matrix_times_vector(context, pos, *left, *right);
777 }
778 }
779
780 // Perform constant folding on pairs of vectors/matrices.
781 if (is_vec_or_mat(leftType) && leftType.matches(rightType)) {
782 return simplify_componentwise(context, pos, *left, op, *right);
783 }
784
785 // Perform constant folding on vectors/matrices against scalars, e.g.: half4(2) + 2
786 if (rightType.isScalar() && is_vec_or_mat(leftType) &&
787 leftType.componentType().matches(rightType)) {
788 return simplify_componentwise(context, pos,
789 *left, op, *splat_scalar(context, *right, left->type()));
790 }
791
792 // Perform constant folding on scalars against vectors/matrices, e.g.: 2 + half4(2)
793 if (leftType.isScalar() && is_vec_or_mat(rightType) &&
794 rightType.componentType().matches(leftType)) {
795 return simplify_componentwise(context, pos,
796 *splat_scalar(context, *left, right->type()), op, *right);
797 }
798
799 // Perform constant folding on pairs of matrices, arrays or structs.
800 if ((leftType.isMatrix() && rightType.isMatrix()) ||
801 (leftType.isArray() && rightType.isArray()) ||
802 (leftType.isStruct() && rightType.isStruct())) {
803 return simplify_constant_equality(context, pos, *left, op, *right);
804 }
805
806 // We aren't able to constant-fold these expressions.
807 return nullptr;
808}
#define RESULT(Op)
#define URESULT(Op)
float SKSL_FLOAT
Definition: SkSLDefines.h:17
virtual bool isStruct() const
Definition: SkSLType.h:540
static float min(float r, float g, float b)
Definition: hsl.cpp:48
static std::unique_ptr< Expression > simplify_matrix_times_matrix(const Context &context, Position pos, const Expression &left, const Expression &right)
static bool is_vec_or_mat(const Type &type)
static std::unique_ptr< Expression > simplify_matrix_times_vector(const Context &context, Position pos, const Expression &left, const Expression &right)
static std::unique_ptr< Expression > simplify_constant_equality(const Context &context, Position pos, const Expression &left, Operator op, const Expression &right)
static std::unique_ptr< Expression > simplify_vector_times_matrix(const Context &context, Position pos, const Expression &left, const Expression &right)
static std::unique_ptr< Expression > simplify_componentwise(const Context &context, Position pos, const Expression &left, Operator op, const Expression &right)
static std::unique_ptr< Expression > splat_scalar(const Context &context, const Expression &scalar, const Type &type)
constexpr bool IsCompileTimeConstant(const T)

◆ get_storage_class()

static SpvStorageClass_ SkSL::get_storage_class ( const Expression expr)
static

Definition at line 3024 of file SkSLSPIRVCodeGenerator.cpp.

3024 {
3025 switch (expr.kind()) {
3026 case Expression::Kind::kVariableReference: {
3027 const Variable& var = *expr.as<VariableReference>().variable();
3028 if (var.storage() != Variable::Storage::kGlobal) {
3030 }
3032 }
3033 case Expression::Kind::kFieldAccess:
3034 return get_storage_class(*expr.as<FieldAccess>().base());
3035 case Expression::Kind::kIndex:
3036 return get_storage_class(*expr.as<IndexExpression>().base());
3037 default:
3039 }
3040}
Kind kind() const
Storage storage() const
Definition: SkSLVariable.h:103
static SpvStorageClass_ get_storage_class(const Expression &expr)
static SpvStorageClass_ get_storage_class_for_global_variable(const Variable &var, SpvStorageClass_ fallbackStorageClass)
@ SpvStorageClassFunction
Definition: spirv.h:134
@ SpvStorageClassPrivate
Definition: spirv.h:133

◆ get_storage_class_for_global_variable()

static SpvStorageClass_ SkSL::get_storage_class_for_global_variable ( const Variable var,
SpvStorageClass_  fallbackStorageClass 
)
static

Definition at line 2983 of file SkSLSPIRVCodeGenerator.cpp.

2984 {
2985 SkASSERT(var.storage() == Variable::Storage::kGlobal);
2986
2987 if (var.type().typeKind() == Type::TypeKind::kSampler ||
2988 var.type().typeKind() == Type::TypeKind::kSeparateSampler ||
2989 var.type().typeKind() == Type::TypeKind::kTexture) {
2991 }
2992
2993 const Layout& layout = var.layout();
2994 ModifierFlags flags = var.modifierFlags();
2995 if (flags & ModifierFlag::kIn) {
2996 SkASSERT(!(layout.fFlags & LayoutFlag::kPushConstant));
2997 return SpvStorageClassInput;
2998 }
2999 if (flags & ModifierFlag::kOut) {
3000 SkASSERT(!(layout.fFlags & LayoutFlag::kPushConstant));
3001 return SpvStorageClassOutput;
3002 }
3003 if (flags.isUniform()) {
3004 if (layout.fFlags & LayoutFlag::kPushConstant) {
3006 }
3008 }
3009 if (flags.isBuffer()) {
3010 // Note: In SPIR-V 1.3, a storage buffer can be declared with the "StorageBuffer"
3011 // storage class and the "Block" decoration and the <1.3 approach we use here ("Uniform"
3012 // storage class and the "BufferBlock" decoration) is deprecated. Since we target SPIR-V
3013 // 1.0, we have to use the deprecated approach which is well supported in Vulkan and
3014 // addresses SkSL use cases (notably SkSL currently doesn't support pointer features that
3015 // would benefit from SPV_KHR_variable_pointers capabilities).
3017 }
3018 if (flags.isWorkgroup()) {
3020 }
3021 return fallbackStorageClass;
3022}
ModifierFlags modifierFlags() const
Definition: SkSLVariable.h:89
FlutterSemanticsFlag flags
@ SpvStorageClassUniformConstant
Definition: spirv.h:127
@ SpvStorageClassPushConstant
Definition: spirv.h:136
@ SpvStorageClassUniform
Definition: spirv.h:129
@ SpvStorageClassInput
Definition: spirv.h:128
@ SpvStorageClassWorkgroup
Definition: spirv.h:131
@ SpvStorageClassOutput
Definition: spirv.h:130

◆ get_struct_definitions_from_module()

static void SkSL::get_struct_definitions_from_module ( Program program,
const Module module,
std::vector< const ProgramElement * > *  addedStructDefs 
)
static

Definition at line 37 of file SkSLFindAndDeclareBuiltinStructs.cpp.

40 {
41 // We want to start at the root module and work our way towards the Program, so that structs
42 // are added to the program in the same order that they appear in the Module hierarchy.
43 if (module.fParent) {
44 get_struct_definitions_from_module(program, *module.fParent, addedStructDefs);
45 }
46
47 // Find StructDefinitions from this Module that are used by the program, and copy them into our
48 // array of shared elements.
49 for (const std::unique_ptr<ProgramElement>& elem : module.fElements) {
50 if (elem->is<StructDefinition>()) {
51 const StructDefinition& structDef = elem->as<StructDefinition>();
52 int* structCount = program.fUsage->fStructCounts.find(&structDef.type());
53 if (structCount && *structCount > 0) {
54 addedStructDefs->push_back(&structDef);
55 }
56 }
57 }
58}
static void get_struct_definitions_from_module(Program &program, const Module &module, std::vector< const ProgramElement * > *addedStructDefs)
const Module * fParent
Definition: SkSLCompiler.h:57
std::vector< std::unique_ptr< ProgramElement > > fElements
Definition: SkSLCompiler.h:59
std::unique_ptr< ProgramUsage > fUsage
Definition: SkSLProgram.h:155

◆ get_thread_local_memory_pool()

static MemoryPool * SkSL::get_thread_local_memory_pool ( )
static

Definition at line 18 of file SkSLPool.cpp.

18 {
19 return sMemPool;
20}
static thread_local MemoryPool * sMemPool
Definition: SkSLPool.cpp:16

◆ get_top_level_symbol_table()

static SymbolTable * SkSL::get_top_level_symbol_table ( const FunctionDeclaration anyFunc)
static

Definition at line 4940 of file SkSLSPIRVCodeGenerator.cpp.

4940 {
4941 return anyFunc.definition()->body()->as<Block>().symbolTable()->fParent;
4942}
const FunctionDefinition * definition() const
std::unique_ptr< Statement > & body()

◆ get_transition()

static State SkSL::get_transition ( uint8_t  transition,
State  state 
)
static

Definition at line 763 of file SkSLLexer.cpp.

763 {
764 IndexEntry index = kIndices[state];
765 if (index < 0) {
766 return kFull[~index].data[transition];
767 }
768 const CompactEntry& entry = kCompact[index];
769 int v = entry.data[transition >> 2];
770 v >>= 2 * (transition & 3);
771 v &= 3;
772 v *= 9;
773 return (entry.values >> v) & 511;
774}
static const uint16_t kIndices[]
AtkStateType state
static constexpr FullEntry kFull[]
Definition: SkSLLexer.cpp:32
static constexpr CompactEntry kCompact[]
Definition: SkSLLexer.cpp:121
int16_t IndexEntry
Definition: SkSLLexer.cpp:24
uint8_t data[18]
Definition: SkSLLexer.cpp:30
State data[71]
Definition: SkSLLexer.cpp:26

◆ GetIntrinsicMap()

const IntrinsicMap & SkSL::GetIntrinsicMap ( )

Definition at line 16 of file SkSLIntrinsicList.cpp.

16 {
17 #define SKSL_INTRINSIC(name) {#name, k_##name##_IntrinsicKind},
18 static const SkNoDestructor<IntrinsicMap> kAllIntrinsics(IntrinsicMap{
20 });
21 #undef SKSL_INTRINSIC
22
23 return *kAllIntrinsics;
24}

◆ GetModuleData()

std::string SkSL::GetModuleData ( ModuleName  name,
const char *  filename 
)

Definition at line 46 of file SkSLModuleDataDefault.cpp.

46 {
47#define M(name) case ModuleName::name: return std::string(SKSL_MINIFIED_##name);
48 switch (name) {
49 M(sksl_shared)
50 M(sksl_compute)
51 M(sksl_frag)
52 M(sksl_gpu)
53 M(sksl_public)
54 M(sksl_rt_shader)
55 M(sksl_vert)
56#if defined(SK_GRAPHITE)
57 M(sksl_graphite_frag)
58 M(sksl_graphite_frag_es2)
59 M(sksl_graphite_vert)
60 M(sksl_graphite_vert_es2)
61#endif
62 default:
64 }
65#undef M
66}
#define M(name)

◆ has_compile_time_constant_arguments()

static bool SkSL::has_compile_time_constant_arguments ( const ExpressionArray arguments)
static

Definition at line 53 of file SkSLFunctionCall.cpp.

53 {
54 for (const std::unique_ptr<Expression>& arg : arguments) {
55 const Expression* expr = ConstantFolder::GetConstantValueForVariable(*arg);
57 return false;
58 }
59 }
60 return true;
61}

◆ hoist_vardecl_symbols_into_outer_scope()

static void SkSL::hoist_vardecl_symbols_into_outer_scope ( const Context context,
const Block initBlock,
SymbolTable innerSymbols,
SymbolTable hoistedSymbols 
)
static

Definition at line 70 of file SkSLForStatement.cpp.

73 {
74 class SymbolHoister : public ProgramVisitor {
75 public:
76 SymbolHoister(const Context& ctx, SymbolTable* innerSym, SymbolTable* hoistSym)
77 : fContext(ctx)
78 , fInnerSymbols(innerSym)
79 , fHoistedSymbols(hoistSym) {}
80
81 bool visitStatement(const Statement& stmt) override {
82 if (stmt.is<VarDeclaration>()) {
83 // Hoist the variable's symbol outside of the initializer block's symbol table, and
84 // into the outer symbol table. If the initializer's symbol table originally had
85 // ownership, transfer it. (If the variable was owned elsewhere, it can keep its
86 // current owner.)
87 Variable* var = stmt.as<VarDeclaration>().var();
88 fInnerSymbols->moveSymbolTo(fHoistedSymbols, var, fContext);
89 return false;
90 }
92 }
93
94 const Context& fContext;
95 SymbolTable* fInnerSymbols;
96 SymbolTable* fHoistedSymbols;
97 };
98
99 SymbolHoister{context, innerSymbols, hoistedSymbols}.visitStatement(initBlock);
100}

◆ index_out_of_range()

static bool SkSL::index_out_of_range ( const Context context,
Position  pos,
SKSL_INT  index,
const Expression base 
)
static

Definition at line 32 of file SkSLIndexExpression.cpp.

33 {
34 if (index >= 0) {
35 if (base.type().columns() == Type::kUnsizedArray) {
36 return false;
37 } else if (index < base.type().columns()) {
38 return false;
39 }
40 }
41 context.fErrors->error(pos, "index " + std::to_string(index) + " out of range for '" +
42 base.type().displayName() + "'");
43 return true;
44}

◆ is_abs()

static bool SkSL::is_abs ( Expression expr)
static

Definition at line 447 of file SkSLGLSLCodeGenerator.cpp.

447 {
448 return expr.is<FunctionCall>() &&
449 expr.as<FunctionCall>().function().intrinsicKind() == k_abs_IntrinsicKind;
450}
const FunctionDeclaration & function() const
IntrinsicKind intrinsicKind() const

◆ is_block_ending_with_return()

static bool SkSL::is_block_ending_with_return ( const Statement stmt)
static

Definition at line 2637 of file SkSLMetalCodeGenerator.cpp.

2637 {
2638 // This function detects (potentially nested) blocks that end in a return statement.
2639 if (!stmt->is<Block>()) {
2640 return false;
2641 }
2642 const StatementArray& block = stmt->as<Block>().children();
2643 for (int index = block.size(); index--; ) {
2644 stmt = block[index].get();
2645 if (stmt->is<ReturnStatement>()) {
2646 return true;
2647 }
2648 if (stmt->is<Block>()) {
2649 return is_block_ending_with_return(stmt);
2650 }
2651 if (!stmt->is<Nop>()) {
2652 break;
2653 }
2654 }
2655 return false;
2656}
static bool is_block_ending_with_return(const Statement *stmt)

◆ is_bool()

static bool SkSL::is_bool ( const Type type)
static

Definition at line 927 of file SkSLSPIRVCodeGenerator.cpp.

927 {
928 return (type.isScalar() || type.isVector()) && type.componentType().isBoolean();
929}

◆ is_buffer()

static bool SkSL::is_buffer ( const InterfaceBlock block)
static

Definition at line 559 of file SkSLMetalCodeGenerator.cpp.

559 {
560 return block.var()->modifierFlags().isBuffer();
561}
Variable * var() const

◆ is_compute_builtin()

static bool SkSL::is_compute_builtin ( const Variable var)
static

Definition at line 1713 of file SkSLMetalCodeGenerator.cpp.

1713 {
1714 switch (var.layout().fBuiltin) {
1720 return true;
1721 default:
1722 break;
1723 }
1724 return false;
1725}
constexpr int SK_WORKGROUPID_BUILTIN
Definition: SkSLCompiler.h:41
constexpr int SK_GLOBALINVOCATIONID_BUILTIN
Definition: SkSLCompiler.h:43
constexpr int SK_LOCALINVOCATIONID_BUILTIN
Definition: SkSLCompiler.h:42
constexpr int SK_NUMWORKGROUPS_BUILTIN
Definition: SkSLCompiler.h:40
constexpr int SK_LOCALINVOCATIONINDEX_BUILTIN
Definition: SkSLCompiler.h:44

◆ is_constant_diagonal()

static bool SkSL::is_constant_diagonal ( const Expression expr,
double  value 
)
static

Definition at line 366 of file SkSLConstantFolder.cpp.

366 {
367 SkASSERT(expr.type().isMatrix());
368 int columns = expr.type().columns();
369 int rows = expr.type().rows();
370 if (columns != rows) {
371 return false;
372 }
373 int slotIdx = 0;
374 for (int c = 0; c < columns; ++c) {
375 for (int r = 0; r < rows; ++r) {
376 double expectation = (c == r) ? value : 0;
377 std::optional<double> slotVal = expr.getConstantValue(slotIdx++);
378 if (!slotVal.has_value() || *slotVal != expectation) {
379 return false;
380 }
381 }
382 }
383 return true;
384}
virtual int rows() const
Definition: SkSLType.h:438

◆ is_constant_value()

static bool SkSL::is_constant_value ( const Expression expr,
double  value 
)
static

Definition at line 387 of file SkSLConstantFolder.cpp.

387 {
388 return expr.type().isMatrix() ? is_constant_diagonal(expr, value)
389 : ConstantFolder::IsConstantSplat(expr, value);
390}
static bool is_constant_diagonal(const Expression &expr, double value)

◆ is_control_flow_op()

static bool SkSL::is_control_flow_op ( SpvOp_  op)
static

Definition at line 961 of file SkSLSPIRVCodeGenerator.cpp.

961 {
962 switch (op) {
963 case SpvOpReturn:
964 case SpvOpReturnValue:
965 case SpvOpKill:
966 case SpvOpSwitch:
967 case SpvOpBranch:
969 return true;
970 default:
971 return false;
972 }
973}
@ SpvOpBranchConditional
Definition: spirv.h:802
@ SpvOpBranch
Definition: spirv.h:801
@ SpvOpReturn
Definition: spirv.h:805
@ SpvOpSwitch
Definition: spirv.h:803
@ SpvOpKill
Definition: spirv.h:804
@ SpvOpReturnValue
Definition: spirv.h:806

◆ is_dead_variable()

static bool SkSL::is_dead_variable ( const ProgramElement element,
ProgramUsage usage,
bool  onlyPrivateGlobals 
)
static

Definition at line 26 of file SkSLEliminateDeadGlobalVariables.cpp.

28 {
29 if (!element.is<GlobalVarDeclaration>()) {
30 return false;
31 }
32 const GlobalVarDeclaration& global = element.as<GlobalVarDeclaration>();
33 const VarDeclaration& varDecl = global.varDeclaration();
34 if (onlyPrivateGlobals && !skstd::starts_with(varDecl.var()->name(), '$')) {
35 return false;
36 }
37 if (!usage->isDead(*varDecl.var())) {
38 return false;
39 }
40 // This declaration is about to be eliminated by remove_if; update ProgramUsage accordingly.
41 usage->remove(&varDecl);
42 return true;
43}

◆ is_float()

static bool SkSL::is_float ( const Type type)
static

Definition at line 914 of file SkSLSPIRVCodeGenerator.cpp.

914 {
915 return (type.isScalar() || type.isVector() || type.isMatrix()) &&
916 type.componentType().isFloat();
917}

◆ is_globally_reachable_op()

static bool SkSL::is_globally_reachable_op ( SpvOp_  op)
static

Definition at line 975 of file SkSLSPIRVCodeGenerator.cpp.

975 {
976 switch (op) {
977 case SpvOpConstant:
981 case SpvOpTypeVoid:
982 case SpvOpTypeInt:
983 case SpvOpTypeFloat:
984 case SpvOpTypeBool:
985 case SpvOpTypeVector:
986 case SpvOpTypeMatrix:
987 case SpvOpTypeArray:
988 case SpvOpTypePointer:
991 case SpvOpTypeStruct:
992 case SpvOpTypeImage:
994 case SpvOpTypeSampler:
995 case SpvOpVariable:
996 case SpvOpFunction:
998 case SpvOpFunctionEnd:
1000 case SpvOpMemoryModel:
1001 case SpvOpCapability:
1002 case SpvOpExtInstImport:
1003 case SpvOpEntryPoint:
1004 case SpvOpSource:
1006 case SpvOpName:
1007 case SpvOpMemberName:
1008 case SpvOpDecorate:
1010 return true;
1011 default:
1012 return false;
1013 }
1014}
@ SpvOpCapability
Definition: spirv.h:589
@ SpvOpSourceExtension
Definition: spirv.h:578
@ SpvOpTypeMatrix
Definition: spirv.h:595
@ SpvOpSource
Definition: spirv.h:577
@ SpvOpTypeBool
Definition: spirv.h:591
@ SpvOpTypeArray
Definition: spirv.h:599
@ SpvOpVariable
Definition: spirv.h:626
@ SpvOpDecorate
Definition: spirv.h:638
@ SpvOpName
Definition: spirv.h:579
@ SpvOpTypeSampler
Definition: spirv.h:597
@ SpvOpExtInstImport
Definition: spirv.h:584
@ SpvOpFunctionParameter
Definition: spirv.h:623
@ SpvOpConstantComposite
Definition: spirv.h:614
@ SpvOpMemoryModel
Definition: spirv.h:586
@ SpvOpTypeImage
Definition: spirv.h:596
@ SpvOpTypeSampledImage
Definition: spirv.h:598
@ SpvOpTypeVector
Definition: spirv.h:594
@ SpvOpFunctionEnd
Definition: spirv.h:624
@ SpvOpEntryPoint
Definition: spirv.h:587
@ SpvOpTypeInt
Definition: spirv.h:592
@ SpvOpMemberName
Definition: spirv.h:580
@ SpvOpTypeFloat
Definition: spirv.h:593
@ SpvOpFunction
Definition: spirv.h:622
@ SpvOpMemberDecorate
Definition: spirv.h:639
@ SpvOpConstantFalse
Definition: spirv.h:612
@ SpvOpConstantTrue
Definition: spirv.h:611
@ SpvOpTypeFunction
Definition: spirv.h:604
@ SpvOpTypeStruct
Definition: spirv.h:601
@ SpvOpExecutionMode
Definition: spirv.h:588
@ SpvOpConstant
Definition: spirv.h:613
@ SpvOpTypeVoid
Definition: spirv.h:590
@ SpvOpTypeRuntimeArray
Definition: spirv.h:600
@ SpvOpTypePointer
Definition: spirv.h:603

◆ is_in()

static bool SkSL::is_in ( ModifierFlags  f)
static

Definition at line 953 of file SkSLSPIRVCodeGenerator.cpp.

953 {
954 if (f & ModifierFlag::kIn) {
955 return true; // `in` and `inout` both count
956 }
957 // If neither in/out flag is set, the type is implicitly `in`.
958 return !SkToBool(f & ModifierFlag::kOut);
959}
static constexpr bool SkToBool(const T &x)
Definition: SkTo.h:35

◆ is_in_globals()

static bool SkSL::is_in_globals ( const Variable var)
static

Definition at line 1759 of file SkSLMetalCodeGenerator.cpp.

1759 {
1760 SkASSERT(var.storage() == VariableStorage::kGlobal);
1761 return !var.modifierFlags().isConst();
1762}

◆ is_input()

static bool SkSL::is_input ( const Variable var)
static

Definition at line 1728 of file SkSLMetalCodeGenerator.cpp.

1728 {
1729 SkASSERT(var.storage() == VariableStorage::kGlobal);
1730 return var.modifierFlags() & ModifierFlag::kIn &&
1731 (var.layout().fBuiltin == -1 || is_compute_builtin(var)) &&
1732 var.type().typeKind() != Type::TypeKind::kTexture;
1733}
static bool is_compute_builtin(const Variable &var)

◆ is_matrix_op_scalar()

static bool SkSL::is_matrix_op_scalar ( const Expression left,
const Expression right 
)
static

Definition at line 476 of file SkSLConstantFolder.cpp.

476 {
478}
static bool is_scalar_op_matrix(const Expression &left, const Expression &right)

◆ is_nontrivial_expression()

static bool SkSL::is_nontrivial_expression ( const Expression expr)
static

Definition at line 2521 of file SkSLWGSLCodeGenerator.cpp.

2521 {
2522 // We consider a "trivial expression" one which we can repeat multiple times in the output
2523 // without being dangerous or spammy. We avoid emitting temporary variables for very trivial
2524 // expressions: literals, unadorned variable references, or constant vectors.
2525 if (expr.is<VariableReference>() || expr.is<Literal>()) {
2526 // Variables and literals are trivial; adding a let-declaration won't simplify anything.
2527 return false;
2528 }
2529 if (expr.type().isVector() && Analysis::IsConstantExpression(expr)) {
2530 // Compile-time constant vectors are also considered trivial; they're short and sweet.
2531 return false;
2532 }
2533 return true;
2534}
bool IsConstantExpression(const Expression &expr)

◆ is_out()

static bool SkSL::is_out ( ModifierFlags  f)
static

Definition at line 949 of file SkSLSPIRVCodeGenerator.cpp.

949 {
950 return SkToBool(f & ModifierFlag::kOut);
951}

◆ is_output()

static bool SkSL::is_output ( const Variable var)
static

Definition at line 1736 of file SkSLMetalCodeGenerator.cpp.

1736 {
1737 SkASSERT(var.storage() == VariableStorage::kGlobal);
1738 // inout vars get written into the Inputs struct, so we exclude them from Outputs
1739 return (var.modifierFlags() & ModifierFlag::kOut) &&
1740 !(var.modifierFlags() & ModifierFlag::kIn) &&
1741 var.layout().fBuiltin == -1 &&
1742 var.type().typeKind() != Type::TypeKind::kTexture;
1743}

◆ is_readonly()

static bool SkSL::is_readonly ( const InterfaceBlock block)
static

Definition at line 564 of file SkSLMetalCodeGenerator.cpp.

564 {
565 return block.var()->modifierFlags().isReadOnly();
566}

◆ is_safe_to_eliminate()

static bool SkSL::is_safe_to_eliminate ( const Type type,
const Expression arg 
)
static

Definition at line 28 of file SkSLConstructorCompound.cpp.

28 {
29 if (type.isScalar()) {
30 // A scalar "compound type" with a single scalar argument is a no-op and can be eliminated.
31 // (Pedantically, this isn't a compound at all, but it's harmless to allow and simplifies
32 // call sites which need to narrow a vector and may sometimes end up with a scalar.)
33 SkASSERTF(arg.type().matches(type), "Creating type '%s' from '%s'",
34 type.description().c_str(), arg.type().description().c_str());
35 return true;
36 }
37 if (type.isVector() && arg.type().matches(type)) {
38 // A vector compound constructor containing a single argument of matching type can trivially
39 // be eliminated.
40 return true;
41 }
42 // This is a meaningful single-argument compound constructor (e.g. vector-from-matrix,
43 // matrix-from-vector).
44 return false;
45}
#define SkASSERTF(cond, fmt,...)
Definition: SkAssert.h:117
std::string description() const override
Definition: SkSLType.h:238

◆ is_scalar_op_matrix()

static bool SkSL::is_scalar_op_matrix ( const Expression left,
const Expression right 
)
static

Definition at line 472 of file SkSLConstantFolder.cpp.

472 {
473 return left.type().isScalar() && right.type().isMatrix();
474}

◆ is_signed()

static bool SkSL::is_signed ( const Type type)
static

Definition at line 919 of file SkSLSPIRVCodeGenerator.cpp.

919 {
920 return (type.isScalar() || type.isVector()) && type.componentType().isSigned();
921}

◆ is_simple_initializer()

static bool SkSL::is_simple_initializer ( const Statement stmt)
static

Definition at line 46 of file SkSLForStatement.cpp.

46 {
47 return !stmt || stmt->isEmpty() || stmt->is<SkSL::VarDeclaration>() ||
49}
virtual bool isEmpty() const
Definition: SkSLStatement.h:32

◆ is_sk_position()

bool SkSL::is_sk_position ( const Expression expr)

Definition at line 1123 of file SkSLGLSLCodeGenerator.cpp.

1123 {
1124 if (!expr.is<FieldAccess>()) {
1125 return false;
1126 }
1127 const FieldAccess& f = expr.as<FieldAccess>();
1128 return f.base()->type().fields()[f.fieldIndex()].fLayout.fBuiltin == SK_POSITION_BUILTIN;
1129}
constexpr int SK_POSITION_BUILTIN
Definition: SkSLCompiler.h:37

◆ is_sk_samplemask()

bool SkSL::is_sk_samplemask ( const Expression expr)

Definition at line 1131 of file SkSLGLSLCodeGenerator.cpp.

1131 {
1132 if (!expr.is<VariableReference>()) {
1133 return false;
1134 }
1135 const VariableReference& v = expr.as<VariableReference>();
1136 return v.variable()->layout().fBuiltin == SK_SAMPLEMASK_BUILTIN;
1137}
constexpr int SK_SAMPLEMASK_BUILTIN
Definition: SkSLCompiler.h:33

◆ is_threadgroup()

static bool SkSL::is_threadgroup ( const Variable var)
static

Definition at line 1753 of file SkSLMetalCodeGenerator.cpp.

1753 {
1754 SkASSERT(var.storage() == VariableStorage::kGlobal);
1755 return var.modifierFlags().isWorkgroup();
1756}
bool isWorkgroup() const

◆ is_uniforms()

static bool SkSL::is_uniforms ( const Variable var)
static

Definition at line 1746 of file SkSLMetalCodeGenerator.cpp.

1746 {
1747 SkASSERT(var.storage() == VariableStorage::kGlobal);
1748 return var.modifierFlags().isUniform() &&
1749 var.type().typeKind() != Type::TypeKind::kSampler;
1750}

◆ is_unsigned()

static bool SkSL::is_unsigned ( const Type type)
static

Definition at line 923 of file SkSLSPIRVCodeGenerator.cpp.

923 {
924 return (type.isScalar() || type.isVector()) && type.componentType().isUnsigned();
925}

◆ is_vardecl_block_initializer()

static bool SkSL::is_vardecl_block_initializer ( const Statement stmt)
static

Definition at line 27 of file SkSLForStatement.cpp.

27 {
28 if (!stmt) {
29 return false;
30 }
31 if (!stmt->is<SkSL::Block>()) {
32 return false;
33 }
34 const SkSL::Block& b = stmt->as<SkSL::Block>();
35 if (b.isScope()) {
36 return false;
37 }
38 for (const auto& child : b.children()) {
39 if (!child->is<SkSL::VarDeclaration>()) {
40 return false;
41 }
42 }
43 return true;
44}

◆ is_vardecl_compile_time_constant()

static bool SkSL::is_vardecl_compile_time_constant ( const VarDeclaration varDecl)
static

Definition at line 4537 of file SkSLSPIRVCodeGenerator.cpp.

4537 {
4538 return varDecl.var()->modifierFlags().isConst() &&
4539 (varDecl.var()->type().isScalar() || varDecl.var()->type().isVector()) &&
4540 (ConstantFolder::GetConstantValueOrNull(*varDecl.value()) ||
4542}
std::unique_ptr< Expression > & value()
Variable * var() const

◆ is_vec_or_mat()

static bool SkSL::is_vec_or_mat ( const Type type)
static

Definition at line 41 of file SkSLConstantFolder.cpp.

41 {
42 switch (type.typeKind()) {
43 case Type::TypeKind::kMatrix:
44 case Type::TypeKind::kVector:
45 return true;
46
47 default:
48 return false;
49 }
50}

◆ is_whitespace()

static bool SkSL::is_whitespace ( Token::Kind  kind)
static

Definition at line 273 of file SkSLParser.cpp.

273 {
274 switch (kind) {
275 case Token::Kind::TK_WHITESPACE:
276 case Token::Kind::TK_LINE_COMMENT:
277 case Token::Kind::TK_BLOCK_COMMENT:
278 return true;
279
280 default:
281 return false;
282 }
283}

◆ layout_flags_to_image_format()

static SpvImageFormat SkSL::layout_flags_to_image_format ( LayoutFlags  flags)
static

Definition at line 1639 of file SkSLSPIRVCodeGenerator.cpp.

1639 {
1640 flags &= LayoutFlag::kAllPixelFormats;
1641 switch (flags.value()) {
1642 case (int)LayoutFlag::kRGBA8:
1643 return SpvImageFormatRgba8;
1644
1645 case (int)LayoutFlag::kRGBA32F:
1646 return SpvImageFormatRgba32f;
1647
1648 case (int)LayoutFlag::kR32F:
1649 return SpvImageFormatR32f;
1650
1651 default:
1652 return SpvImageFormatUnknown;
1653 }
1654
1656}
@ SpvImageFormatUnknown
Definition: spirv.h:165
@ SpvImageFormatRgba32f
Definition: spirv.h:166
@ SpvImageFormatRgba8
Definition: spirv.h:169
@ SpvImageFormatR32f
Definition: spirv.h:168

◆ logical_not_operand()

static std::unique_ptr< Expression > SkSL::logical_not_operand ( const Context context,
Position  pos,
std::unique_ptr< Expression operand 
)
static

Definition at line 151 of file SkSLPrefixExpression.cpp.

153 {
154 const Expression* value = ConstantFolder::GetConstantValueForVariable(*operand);
155 switch (value->kind()) {
156 case Expression::Kind::kLiteral: {
157 // Convert !boolLiteral(true) to boolLiteral(false).
158 SkASSERT(value->type().isBoolean());
159 const Literal& b = value->as<Literal>();
160 return Literal::MakeBool(pos, !b.boolValue(), &operand->type());
161 }
162 case Expression::Kind::kPrefix: {
163 // Convert `!(!expression)` into `expression`.
164 PrefixExpression& prefix = operand->as<PrefixExpression>();
165 if (prefix.getOperator().kind() == Operator::Kind::LOGICALNOT) {
166 prefix.operand()->fPosition = pos;
167 return std::move(prefix.operand());
168 }
169 break;
170 }
171 case Expression::Kind::kBinary: {
172 BinaryExpression& binary = operand->as<BinaryExpression>();
173 std::optional<Operator> replacement;
174 switch (binary.getOperator().kind()) {
175 case OperatorKind::EQEQ: replacement = OperatorKind::NEQ; break;
176 case OperatorKind::NEQ: replacement = OperatorKind::EQEQ; break;
177 case OperatorKind::LT: replacement = OperatorKind::GTEQ; break;
178 case OperatorKind::LTEQ: replacement = OperatorKind::GT; break;
179 case OperatorKind::GT: replacement = OperatorKind::LTEQ; break;
180 case OperatorKind::GTEQ: replacement = OperatorKind::LT; break;
181 default: break;
182 }
183 if (replacement.has_value()) {
184 return BinaryExpression::Make(context, pos, std::move(binary.left()),
185 *replacement, std::move(binary.right()),
186 &binary.type());
187 }
188 break;
189 }
190 default:
191 break;
192 }
193
194 // No simplified form; convert expression to Prefix(LOGICALNOT, expression).
195 return std::make_unique<PrefixExpression>(pos, Operator::Kind::LOGICALNOT, std::move(operand));
196}

◆ make_reciprocal_expression()

static std::unique_ptr< Expression > SkSL::make_reciprocal_expression ( const Context context,
const Expression right 
)
static

Definition at line 396 of file SkSLConstantFolder.cpp.

397 {
398 if (right.type().isMatrix() || !right.type().componentType().isFloat()) {
399 return nullptr;
400 }
401 // Verify that each slot contains a finite, non-zero literal, take its reciprocal.
402 double values[4];
403 int nslots = right.type().slotCount();
404 for (int index = 0; index < nslots; ++index) {
405 std::optional<double> value = right.getConstantValue(index);
406 if (!value) {
407 return nullptr;
408 }
410 if (*value >= -FLT_MAX && *value <= FLT_MAX && *value != 0.0) {
411 // The reciprocal can be represented safely as a finite 32-bit float.
412 values[index] = *value;
413 } else {
414 // The value is outside the 32-bit float range, or is NaN; do not optimize.
415 return nullptr;
416 }
417 }
418 // Turn the expression array into a compound constructor. (If this is a single-slot expression,
419 // this will return the literal as-is.)
420 return ConstructorCompound::MakeFromConstants(context, right.fPosition, right.type(), values);
421}

◆ make_splat_from_arguments()

static const Expression * SkSL::make_splat_from_arguments ( const Type type,
const ExpressionArray args 
)
static

Definition at line 47 of file SkSLConstructorCompound.cpp.

47 {
48 // Splats cannot represent a matrix.
49 if (type.isMatrix()) {
50 return nullptr;
51 }
52 const Expression* splatExpression = nullptr;
53 for (int index = 0; index < args.size(); ++index) {
54 // Arguments must only be scalars or a splat constructors (which can only contain scalars).
55 const Expression* expr;
56 if (args[index]->type().isScalar()) {
57 expr = args[index].get();
58 } else if (args[index]->is<ConstructorSplat>()) {
59 expr = args[index]->as<ConstructorSplat>().argument().get();
60 } else {
61 return nullptr;
62 }
63 // On the first iteration, just remember the expression we encountered.
64 if (index == 0) {
65 splatExpression = expr;
66 continue;
67 }
68 // On subsequent iterations, ensure that the expression we found matches the first one.
69 // (Note that IsSameExpressionTree will always reject an Expression with side effects.)
70 if (!Analysis::IsSameExpressionTree(*expr, *splatExpression)) {
71 return nullptr;
72 }
73 }
74
75 return splatExpression;
76}
bool IsSameExpressionTree(const Expression &left, const Expression &right)

◆ MakeRasterPipelineProgram()

std::unique_ptr< RP::Program > SkSL::MakeRasterPipelineProgram ( const SkSL::Program program,
const FunctionDefinition function,
DebugTracePriv debugTrace,
bool  writeTraceOps 
)

Definition at line 4070 of file SkSLRasterPipelineCodeGenerator.cpp.

4073 {
4074 RP::Generator generator(program, debugTrace, writeTraceOps);
4075 if (!generator.writeProgram(function)) {
4076 return nullptr;
4077 }
4078 return generator.finish();
4079}

◆ mask_char()

static char SkSL::mask_char ( int8_t  component)
static

Definition at line 88 of file SkSLSwizzle.cpp.

88 {
89 switch (component) {
90 case SwizzleComponent::X: return 'x';
91 case SwizzleComponent::Y: return 'y';
92 case SwizzleComponent::Z: return 'z';
93 case SwizzleComponent::W: return 'w';
94 case SwizzleComponent::R: return 'r';
95 case SwizzleComponent::G: return 'g';
96 case SwizzleComponent::B: return 'b';
97 case SwizzleComponent::A: return 'a';
98 case SwizzleComponent::S: return 's';
99 case SwizzleComponent::T: return 't';
100 case SwizzleComponent::P: return 'p';
101 case SwizzleComponent::Q: return 'q';
102 case SwizzleComponent::UL: return 'L';
103 case SwizzleComponent::UT: return 'T';
104 case SwizzleComponent::UR: return 'R';
105 case SwizzleComponent::UB: return 'B';
106 case SwizzleComponent::ZERO: return '0';
107 case SwizzleComponent::ONE: return '1';
108 default: SkUNREACHABLE;
109 }
110}
static const SkScalar X
Definition: StrokeBench.cpp:54
#define R(r)
#define B
#define T
Definition: precompiler.cc:65

◆ needs_address_space()

static bool SkSL::needs_address_space ( const Type type,
ModifierFlags  modifiers 
)
static

Definition at line 554 of file SkSLMetalCodeGenerator.cpp.

554 {
555 return type.isUnsizedArray() || pass_by_reference(type, modifiers);
556}
static bool pass_by_reference(const Type &type, ModifierFlags flags)

◆ negate_expression()

static std::unique_ptr< Expression > SkSL::negate_expression ( const Context context,
Position  pos,
const Expression expr,
const Type type 
)
static

Definition at line 316 of file SkSLConstantFolder.cpp.

319 {
320 std::unique_ptr<Expression> ctor = cast_expression(context, pos, expr, type);
321 return ctor ? PrefixExpression::Make(context, pos, Operator::Kind::MINUS, std::move(ctor))
322 : nullptr;
323}
static std::unique_ptr< Expression > cast_expression(const Context &context, Position pos, const Expression &expr, const Type &type)

◆ negate_operand()

static std::unique_ptr< Expression > SkSL::negate_operand ( const Context context,
Position  pos,
std::unique_ptr< Expression value 
)
static

Definition at line 139 of file SkSLPrefixExpression.cpp.

141 {
142 // Attempt to simplify this negation (e.g. eliminate double negation, literal values)
143 if (std::unique_ptr<Expression> simplified = simplify_negation(context, pos, *value)) {
144 return simplified;
145 }
146
147 // No simplified form; convert expression to Prefix(MINUS, expression).
148 return std::make_unique<PrefixExpression>(pos, Operator::Kind::MINUS, std::move(value));
149}
static std::unique_ptr< Expression > simplify_negation(const Context &context, Position pos, const Expression &originalExpr)

◆ negate_operands()

static ExpressionArray SkSL::negate_operands ( const Context context,
Position  pos,
const ExpressionArray operands 
)
static

Definition at line 122 of file SkSLPrefixExpression.cpp.

124 {
125 ExpressionArray replacement;
126 replacement.reserve_exact(array.size());
127 for (const std::unique_ptr<Expression>& expr : array) {
128 // The logic below is very similar to `negate_operand`, but with different ownership rules.
129 if (std::unique_ptr<Expression> simplified = simplify_negation(context, pos, *expr)) {
130 replacement.push_back(std::move(simplified));
131 } else {
132 replacement.push_back(std::make_unique<PrefixExpression>(pos, Operator::Kind::MINUS,
133 expr->clone()));
134 }
135 }
136 return replacement;
137}

◆ negate_value()

static double SkSL::negate_value ( double  value)
static

Definition at line 35 of file SkSLPrefixExpression.cpp.

35 {
36 return -value;
37}

◆ one_over_scalar()

static std::unique_ptr< Expression > SkSL::one_over_scalar ( const Context context,
const Expression right 
)
static

Definition at line 615 of file SkSLConstantFolder.cpp.

616 {
617 SkASSERT(right.type().isScalar());
618 Position pos = right.fPosition;
619 return BinaryExpression::Make(context, pos,
620 Literal::Make(pos, 1.0, &right.type()),
621 Operator::Kind::SLASH,
622 right.clone());
623}

◆ operator_name()

static const char * SkSL::operator_name ( Operator  op)
static

Definition at line 372 of file SkSLMetalCodeGenerator.cpp.

372 {
373 switch (op.kind()) {
374 case Operator::Kind::LOGICALXOR: return " != ";
375 default: return op.operatorName();
376 }
377}
const char * operatorName() const

◆ optimize_comparison()

static std::unique_ptr< Expression > SkSL::optimize_comparison ( const Context context,
const IntrinsicArguments arguments,
CompareFn  compare 
)
static

Definition at line 176 of file SkSLFunctionCall.cpp.

178 {
179 const Expression* left = arguments[0];
180 const Expression* right = arguments[1];
181 SkASSERT(left);
183 SkASSERT(!arguments[2]);
184
185 const Type& type = left->type();
186 SkASSERT(type.isVector());
187 SkASSERT(type.componentType().isScalar());
188 SkASSERT(type.matches(right->type()));
189
190 double array[4];
191
192 for (int index = 0; index < type.columns(); ++index) {
193 std::optional<double> leftValue = left->getConstantValue(index);
194 std::optional<double> rightValue = right->getConstantValue(index);
195 SkASSERT(leftValue.has_value());
196 SkASSERT(rightValue.has_value());
197 array[index] = compare(*leftValue, *rightValue) ? 1.0 : 0.0;
198 }
199
200 const Type& bvecType = context.fTypes.fBool->toCompound(context, type.columns(), /*rows=*/1);
201 return ConstructorCompound::MakeFromConstants(context, left->fPosition, bvecType, array);
202}
const std::unique_ptr< Type > fBool
int compare(const void *untyped_lhs, const void *untyped_rhs)
Definition: skdiff.h:161

◆ optimize_constructor_swizzle()

static std::unique_ptr< Expression > SkSL::optimize_constructor_swizzle ( const Context context,
Position  pos,
const ConstructorCompound base,
ComponentArray  components 
)
static

Definition at line 120 of file SkSLSwizzle.cpp.

123 {
124 auto baseArguments = base.argumentSpan();
125 std::unique_ptr<Expression> replacement;
126 const Type& exprType = base.type();
127 const Type& componentType = exprType.componentType();
128 int swizzleSize = components.size();
129
130 // Swizzles can duplicate some elements and discard others, e.g.
131 // `half4(1, 2, 3, 4).xxz` --> `half3(1, 1, 3)`. However, there are constraints:
132 // - Expressions with side effects need to occur exactly once, even if they would otherwise be
133 // swizzle-eliminated
134 // - Non-trivial expressions should not be repeated, but elimination is OK.
135 //
136 // Look up the argument for the constructor at each index. This is typically simple but for
137 // weird cases like `half4(bar.yz, half2(foo))`, it can be harder than it seems. This example
138 // would result in:
139 // argMap[0] = {.fArgIndex = 0, .fComponent = 0} (bar.yz .x)
140 // argMap[1] = {.fArgIndex = 0, .fComponent = 1} (bar.yz .y)
141 // argMap[2] = {.fArgIndex = 1, .fComponent = 0} (half2(foo) .x)
142 // argMap[3] = {.fArgIndex = 1, .fComponent = 1} (half2(foo) .y)
143 struct ConstructorArgMap {
144 int8_t fArgIndex;
145 int8_t fComponent;
146 };
147
148 int numConstructorArgs = base.type().columns();
149 ConstructorArgMap argMap[4] = {};
150 int writeIdx = 0;
151 for (int argIdx = 0; argIdx < (int)baseArguments.size(); ++argIdx) {
152 const Expression& arg = *baseArguments[argIdx];
153 const Type& argType = arg.type();
154
155 if (!argType.isScalar() && !argType.isVector()) {
156 return nullptr;
157 }
158
159 int argSlots = argType.slotCount();
160 for (int componentIdx = 0; componentIdx < argSlots; ++componentIdx) {
161 argMap[writeIdx].fArgIndex = argIdx;
162 argMap[writeIdx].fComponent = componentIdx;
163 ++writeIdx;
164 }
165 }
166 SkASSERT(writeIdx == numConstructorArgs);
167
168 // Count up the number of times each constructor argument is used by the swizzle.
169 // `half4(bar.yz, half2(foo)).xwxy` -> { 3, 1 }
170 // - bar.yz is referenced 3 times, by `.x_xy`
171 // - half(foo) is referenced 1 time, by `._w__`
172 int8_t exprUsed[4] = {};
173 for (int8_t c : components) {
174 exprUsed[argMap[c].fArgIndex]++;
175 }
176
177 for (int index = 0; index < numConstructorArgs; ++index) {
178 int8_t constructorArgIndex = argMap[index].fArgIndex;
179 const Expression& baseArg = *baseArguments[constructorArgIndex];
180
181 // Check that non-trivial expressions are not swizzled in more than once.
182 if (exprUsed[constructorArgIndex] > 1 && !Analysis::IsTrivialExpression(baseArg)) {
183 return nullptr;
184 }
185 // Check that side-effect-bearing expressions are swizzled in exactly once.
186 if (exprUsed[constructorArgIndex] != 1 && Analysis::HasSideEffects(baseArg)) {
187 return nullptr;
188 }
189 }
190
191 struct ReorderedArgument {
192 int8_t fArgIndex;
193 ComponentArray fComponents;
194 };
195 STArray<4, ReorderedArgument> reorderedArgs;
196 for (int8_t c : components) {
197 const ConstructorArgMap& argument = argMap[c];
198 const Expression& baseArg = *baseArguments[argument.fArgIndex];
199
200 if (baseArg.type().isScalar()) {
201 // This argument is a scalar; add it to the list as-is.
202 SkASSERT(argument.fComponent == 0);
203 reorderedArgs.push_back({argument.fArgIndex,
204 ComponentArray{}});
205 } else {
206 // This argument is a component from a vector.
207 SkASSERT(baseArg.type().isVector());
208 SkASSERT(argument.fComponent < baseArg.type().columns());
209 if (reorderedArgs.empty() ||
210 reorderedArgs.back().fArgIndex != argument.fArgIndex) {
211 // This can't be combined with the previous argument. Add a new one.
212 reorderedArgs.push_back({argument.fArgIndex,
213 ComponentArray{argument.fComponent}});
214 } else {
215 // Since we know this argument uses components, it should already have at least one
216 // component set.
217 SkASSERT(!reorderedArgs.back().fComponents.empty());
218 // Build up the current argument with one more component.
219 reorderedArgs.back().fComponents.push_back(argument.fComponent);
220 }
221 }
222 }
223
224 // Convert our reordered argument list to an actual array of expressions, with the new order and
225 // any new inner swizzles that need to be applied.
226 ExpressionArray newArgs;
227 newArgs.reserve_exact(swizzleSize);
228 for (const ReorderedArgument& reorderedArg : reorderedArgs) {
229 std::unique_ptr<Expression> newArg = baseArguments[reorderedArg.fArgIndex]->clone();
230
231 if (reorderedArg.fComponents.empty()) {
232 newArgs.push_back(std::move(newArg));
233 } else {
234 newArgs.push_back(Swizzle::Make(context, pos, std::move(newArg),
235 reorderedArg.fComponents));
236 }
237 }
238
239 // Wrap the new argument list in a compound constructor.
240 return ConstructorCompound::Make(context,
241 pos,
242 componentType.toCompound(context, swizzleSize, /*rows=*/1),
243 std::move(newArgs));
244}
const Type & toCompound(const Context &context, int columns, int rows) const
bool empty() const
Definition: SkTArray.h:199
skia_private::FixedArray< 4, int8_t > ComponentArray
Definition: SkSLSwizzle.h:46

◆ optimize_intrinsic_call()

static std::unique_ptr< Expression > SkSL::optimize_intrinsic_call ( const Context context,
Position  pos,
IntrinsicKind  intrinsic,
const ExpressionArray argArray,
const Type returnType 
)
static

Definition at line 635 of file SkSLFunctionCall.cpp.

639 {
640 // Replace constant variables with their literal values.
641 IntrinsicArguments arguments = {};
642 SkASSERT(SkToSizeT(argArray.size()) <= arguments.size());
643 for (int index = 0; index < argArray.size(); ++index) {
644 arguments[index] = ConstantFolder::GetConstantValueForVariable(*argArray[index]);
645 }
646
647 auto Get = [&](int idx, int col) -> float {
648 return *arguments[idx]->getConstantValue(col);
649 };
650
651 switch (intrinsic) {
652 // 8.1 : Angle and Trigonometry Functions
653 case k_radians_IntrinsicKind:
654 return evaluate_intrinsic<float>(context, arguments, returnType,
655 Intrinsics::evaluate_radians);
656 case k_degrees_IntrinsicKind:
657 return evaluate_intrinsic<float>(context, arguments, returnType,
658 Intrinsics::evaluate_degrees);
659 case k_sin_IntrinsicKind:
660 return evaluate_intrinsic<float>(context, arguments, returnType,
661 Intrinsics::evaluate_sin);
662 case k_cos_IntrinsicKind:
663 return evaluate_intrinsic<float>(context, arguments, returnType,
664 Intrinsics::evaluate_cos);
665 case k_tan_IntrinsicKind:
666 return evaluate_intrinsic<float>(context, arguments, returnType,
667 Intrinsics::evaluate_tan);
668 case k_sinh_IntrinsicKind:
669 return evaluate_intrinsic<float>(context, arguments, returnType,
670 Intrinsics::evaluate_sinh);
671 case k_cosh_IntrinsicKind:
672 return evaluate_intrinsic<float>(context, arguments, returnType,
673 Intrinsics::evaluate_cosh);
674 case k_tanh_IntrinsicKind:
675 return evaluate_intrinsic<float>(context, arguments, returnType,
676 Intrinsics::evaluate_tanh);
677 case k_asin_IntrinsicKind:
678 return evaluate_intrinsic<float>(context, arguments, returnType,
679 Intrinsics::evaluate_asin);
680 case k_acos_IntrinsicKind:
681 return evaluate_intrinsic<float>(context, arguments, returnType,
682 Intrinsics::evaluate_acos);
683 case k_atan_IntrinsicKind:
684 if (argArray.size() == 1) {
685 return evaluate_intrinsic<float>(context, arguments, returnType,
686 Intrinsics::evaluate_atan);
687 } else {
688 return evaluate_pairwise_intrinsic(context, arguments, returnType,
689 Intrinsics::evaluate_atan2);
690 }
691 case k_asinh_IntrinsicKind:
692 return evaluate_intrinsic<float>(context, arguments, returnType,
693 Intrinsics::evaluate_asinh);
694
695 case k_acosh_IntrinsicKind:
696 return evaluate_intrinsic<float>(context, arguments, returnType,
697 Intrinsics::evaluate_acosh);
698 case k_atanh_IntrinsicKind:
699 return evaluate_intrinsic<float>(context, arguments, returnType,
700 Intrinsics::evaluate_atanh);
701 // 8.2 : Exponential Functions
702 case k_pow_IntrinsicKind:
703 return evaluate_pairwise_intrinsic(context, arguments, returnType,
704 Intrinsics::evaluate_pow);
705 case k_exp_IntrinsicKind:
706 return evaluate_intrinsic<float>(context, arguments, returnType,
707 Intrinsics::evaluate_exp);
708 case k_log_IntrinsicKind:
709 return evaluate_intrinsic<float>(context, arguments, returnType,
710 Intrinsics::evaluate_log);
711 case k_exp2_IntrinsicKind:
712 return evaluate_intrinsic<float>(context, arguments, returnType,
713 Intrinsics::evaluate_exp2);
714 case k_log2_IntrinsicKind:
715 return evaluate_intrinsic<float>(context, arguments, returnType,
716 Intrinsics::evaluate_log2);
717 case k_sqrt_IntrinsicKind:
718 return evaluate_intrinsic<float>(context, arguments, returnType,
719 Intrinsics::evaluate_sqrt);
720 case k_inversesqrt_IntrinsicKind:
721 return evaluate_intrinsic<float>(context, arguments, returnType,
722 Intrinsics::evaluate_inversesqrt);
723 // 8.3 : Common Functions
724 case k_abs_IntrinsicKind:
725 return evaluate_intrinsic_numeric(context, arguments, returnType,
726 Intrinsics::evaluate_abs);
727 case k_sign_IntrinsicKind:
728 return Intrinsics::evaluate_sign(context, arguments);
729
730 case k_floor_IntrinsicKind:
731 return evaluate_intrinsic<float>(context, arguments, returnType,
732 Intrinsics::evaluate_floor);
733 case k_ceil_IntrinsicKind:
734 return evaluate_intrinsic<float>(context, arguments, returnType,
735 Intrinsics::evaluate_ceil);
736 case k_fract_IntrinsicKind:
737 return evaluate_intrinsic<float>(context, arguments, returnType,
738 Intrinsics::evaluate_fract);
739 case k_mod_IntrinsicKind:
740 return evaluate_pairwise_intrinsic(context, arguments, returnType,
741 Intrinsics::evaluate_mod);
742 case k_min_IntrinsicKind:
743 return evaluate_pairwise_intrinsic(context, arguments, returnType,
744 Intrinsics::evaluate_min);
745 case k_max_IntrinsicKind:
746 return evaluate_pairwise_intrinsic(context, arguments, returnType,
747 Intrinsics::evaluate_max);
748 case k_clamp_IntrinsicKind:
749 return evaluate_3_way_intrinsic(context, arguments, returnType,
750 Intrinsics::evaluate_clamp);
751 case k_fma_IntrinsicKind:
752 return evaluate_3_way_intrinsic(context, arguments, returnType,
753 Intrinsics::evaluate_fma);
754 case k_saturate_IntrinsicKind:
755 return evaluate_intrinsic<float>(context, arguments, returnType,
756 Intrinsics::evaluate_saturate);
757 case k_mix_IntrinsicKind:
758 if (arguments[2]->type().componentType().isBoolean()) {
759 const SkSL::Type& numericType = arguments[0]->type().componentType();
760
761 if (numericType.isFloat()) {
762 type_check_expression<float>(*arguments[0]);
763 type_check_expression<float>(*arguments[1]);
764 } else if (numericType.isInteger()) {
765 type_check_expression<SKSL_INT>(*arguments[0]);
766 type_check_expression<SKSL_INT>(*arguments[1]);
767 } else if (numericType.isBoolean()) {
768 type_check_expression<bool>(*arguments[0]);
769 type_check_expression<bool>(*arguments[1]);
770 } else {
771 SkDEBUGFAILF("unsupported type %s", numericType.description().c_str());
772 return nullptr;
773 }
774 return evaluate_n_way_intrinsic(context, arguments[0], arguments[1], arguments[2],
775 returnType, Intrinsics::evaluate_mix);
776 } else {
777 return evaluate_3_way_intrinsic(context, arguments, returnType,
778 Intrinsics::evaluate_mix);
779 }
780 case k_step_IntrinsicKind:
781 return evaluate_pairwise_intrinsic(context, arguments, returnType,
782 Intrinsics::evaluate_step);
783 case k_smoothstep_IntrinsicKind:
784 return evaluate_3_way_intrinsic(context, arguments, returnType,
785 Intrinsics::evaluate_smoothstep);
786 case k_trunc_IntrinsicKind:
787 return evaluate_intrinsic<float>(context, arguments, returnType,
788 Intrinsics::evaluate_trunc);
789 case k_round_IntrinsicKind: // GLSL `round` documents its rounding mode as unspecified
790 case k_roundEven_IntrinsicKind: // and is allowed to behave identically to `roundEven`.
791 return evaluate_intrinsic<float>(context, arguments, returnType,
792 Intrinsics::evaluate_round);
793 case k_floatBitsToInt_IntrinsicKind:
794 return evaluate_intrinsic<float>(context, arguments, returnType,
795 Intrinsics::evaluate_floatBitsToInt);
796 case k_floatBitsToUint_IntrinsicKind:
797 return evaluate_intrinsic<float>(context, arguments, returnType,
798 Intrinsics::evaluate_floatBitsToUint);
799 case k_intBitsToFloat_IntrinsicKind:
800 return evaluate_intrinsic<SKSL_INT>(context, arguments, returnType,
801 Intrinsics::evaluate_intBitsToFloat);
802 case k_uintBitsToFloat_IntrinsicKind:
803 return evaluate_intrinsic<SKSL_INT>(context, arguments, returnType,
804 Intrinsics::evaluate_uintBitsToFloat);
805 // 8.4 : Floating-Point Pack and Unpack Functions
806 case k_packUnorm2x16_IntrinsicKind: {
807 auto Pack = [&](int n) -> unsigned int {
808 float x = Get(0, n);
809 return (int)std::round(Intrinsics::evaluate_clamp(x, 0.0, 1.0) * 65535.0);
810 };
811 const double packed = ((Pack(0) << 0) & 0x0000FFFF) |
812 ((Pack(1) << 16) & 0xFFFF0000);
813 return ConstructorCompound::MakeFromConstants(context, arguments[0]->fPosition,
814 *context.fTypes.fUInt, &packed);
815 }
816 case k_packSnorm2x16_IntrinsicKind: {
817 auto Pack = [&](int n) -> unsigned int {
818 float x = Get(0, n);
819 return (int)std::round(Intrinsics::evaluate_clamp(x, -1.0, 1.0) * 32767.0);
820 };
821 const double packed = ((Pack(0) << 0) & 0x0000FFFF) |
822 ((Pack(1) << 16) & 0xFFFF0000);
823 return ConstructorCompound::MakeFromConstants(context, arguments[0]->fPosition,
824 *context.fTypes.fUInt, &packed);
825 }
826 case k_packHalf2x16_IntrinsicKind: {
827 auto Pack = [&](int n) -> unsigned int {
828 return SkFloatToHalf(Get(0, n));
829 };
830 const double packed = ((Pack(0) << 0) & 0x0000FFFF) |
831 ((Pack(1) << 16) & 0xFFFF0000);
832 return ConstructorCompound::MakeFromConstants(context, arguments[0]->fPosition,
833 *context.fTypes.fUInt, &packed);
834 }
835 case k_unpackUnorm2x16_IntrinsicKind: {
836 SKSL_INT x = *arguments[0]->getConstantValue(0);
837 uint16_t a = ((x >> 0) & 0x0000FFFF);
838 uint16_t b = ((x >> 16) & 0x0000FFFF);
839 const double unpacked[2] = {double(a) / 65535.0,
840 double(b) / 65535.0};
841 return ConstructorCompound::MakeFromConstants(context, arguments[0]->fPosition,
842 *context.fTypes.fFloat2, unpacked);
843 }
844 case k_unpackSnorm2x16_IntrinsicKind: {
845 SKSL_INT x = *arguments[0]->getConstantValue(0);
846 int16_t a = ((x >> 0) & 0x0000FFFF);
847 int16_t b = ((x >> 16) & 0x0000FFFF);
848 const double unpacked[2] = {Intrinsics::evaluate_clamp(double(a) / 32767.0, -1.0, 1.0),
849 Intrinsics::evaluate_clamp(double(b) / 32767.0, -1.0, 1.0)};
850 return ConstructorCompound::MakeFromConstants(context, arguments[0]->fPosition,
851 *context.fTypes.fFloat2, unpacked);
852 }
853 case k_unpackHalf2x16_IntrinsicKind: {
854 SKSL_INT x = *arguments[0]->getConstantValue(0);
855 uint16_t a = ((x >> 0) & 0x0000FFFF);
856 uint16_t b = ((x >> 16) & 0x0000FFFF);
857 const double unpacked[2] = {SkHalfToFloat(a),
859 return ConstructorCompound::MakeFromConstants(context, arguments[0]->fPosition,
860 *context.fTypes.fFloat2, unpacked);
861 }
862 // 8.5 : Geometric Functions
863 case k_length_IntrinsicKind:
864 return Intrinsics::evaluate_length(arguments);
865
866 case k_distance_IntrinsicKind:
867 return Intrinsics::evaluate_distance(arguments);
868
869 case k_dot_IntrinsicKind:
870 return Intrinsics::evaluate_dot(arguments);
871
872 case k_cross_IntrinsicKind: {
873 auto X = [&](int n) -> float { return Get(0, n); };
874 auto Y = [&](int n) -> float { return Get(1, n); };
875 SkASSERT(arguments[0]->type().columns() == 3); // the vec2 form is not a real intrinsic
876
877 double vec[3] = {X(1) * Y(2) - Y(1) * X(2),
878 X(2) * Y(0) - Y(2) * X(0),
879 X(0) * Y(1) - Y(0) * X(1)};
880 return ConstructorCompound::MakeFromConstants(context, arguments[0]->fPosition,
881 returnType, vec);
882 }
883 case k_normalize_IntrinsicKind:
884 return Intrinsics::evaluate_normalize(context, arguments);
885
886 case k_faceforward_IntrinsicKind:
887 return Intrinsics::evaluate_faceforward(context, arguments);
888
889 case k_reflect_IntrinsicKind:
890 return Intrinsics::evaluate_reflect(context, arguments);
891
892 case k_refract_IntrinsicKind:
893 return Intrinsics::evaluate_refract(context, arguments);
894
895 // 8.6 : Matrix Functions
896 case k_matrixCompMult_IntrinsicKind:
897 return evaluate_pairwise_intrinsic(context, arguments, returnType,
898 Intrinsics::evaluate_matrixCompMult);
899 case k_transpose_IntrinsicKind: {
900 double mat[16];
901 int index = 0;
902 for (int c = 0; c < returnType.columns(); ++c) {
903 for (int r = 0; r < returnType.rows(); ++r) {
904 mat[index++] = Get(0, (returnType.columns() * r) + c);
905 }
906 }
907 return ConstructorCompound::MakeFromConstants(context, arguments[0]->fPosition,
908 returnType, mat);
909 }
910 case k_outerProduct_IntrinsicKind: {
911 double mat[16];
912 int index = 0;
913 for (int c = 0; c < returnType.columns(); ++c) {
914 for (int r = 0; r < returnType.rows(); ++r) {
915 mat[index++] = Get(0, r) * Get(1, c);
916 }
917 }
918 return ConstructorCompound::MakeFromConstants(context, arguments[0]->fPosition,
919 returnType, mat);
920 }
921 case k_determinant_IntrinsicKind: {
922 float mat[16];
923 extract_matrix(arguments[0], mat);
924 float determinant;
925 switch (arguments[0]->type().slotCount()) {
926 case 4:
927 determinant = SkInvert2x2Matrix(mat, /*outMatrix=*/nullptr);
928 break;
929 case 9:
930 determinant = SkInvert3x3Matrix(mat, /*outMatrix=*/nullptr);
931 break;
932 case 16:
933 determinant = SkInvert4x4Matrix(mat, /*outMatrix=*/nullptr);
934 break;
935 default:
936 SkDEBUGFAILF("unsupported type %s", arguments[0]->type().description().c_str());
937 return nullptr;
938 }
939 return Literal::MakeFloat(arguments[0]->fPosition, determinant, &returnType);
940 }
941 case k_inverse_IntrinsicKind: {
942 float mat[16] = {};
943 extract_matrix(arguments[0], mat);
944 switch (arguments[0]->type().slotCount()) {
945 case 4:
946 if (SkInvert2x2Matrix(mat, mat) == 0.0f) {
947 return nullptr;
948 }
949 break;
950 case 9:
951 if (SkInvert3x3Matrix(mat, mat) == 0.0f) {
952 return nullptr;
953 }
954 break;
955 case 16:
956 if (SkInvert4x4Matrix(mat, mat) == 0.0f) {
957 return nullptr;
958 }
959 break;
960 default:
961 SkDEBUGFAILF("unsupported type %s", arguments[0]->type().description().c_str());
962 return nullptr;
963 }
964
965 double dmat[16];
966 std::copy(mat, mat + std::size(mat), dmat);
967 return ConstructorCompound::MakeFromConstants(context, arguments[0]->fPosition,
968 returnType, dmat);
969 }
970 // 8.7 : Vector Relational Functions
971 case k_lessThan_IntrinsicKind:
972 return optimize_comparison(context, arguments, Intrinsics::compare_lessThan);
973
974 case k_lessThanEqual_IntrinsicKind:
975 return optimize_comparison(context, arguments, Intrinsics::compare_lessThanEqual);
976
977 case k_greaterThan_IntrinsicKind:
978 return optimize_comparison(context, arguments, Intrinsics::compare_greaterThan);
979
980 case k_greaterThanEqual_IntrinsicKind:
981 return optimize_comparison(context, arguments, Intrinsics::compare_greaterThanEqual);
982
983 case k_equal_IntrinsicKind:
984 return optimize_comparison(context, arguments, Intrinsics::compare_equal);
985
986 case k_notEqual_IntrinsicKind:
987 return optimize_comparison(context, arguments, Intrinsics::compare_notEqual);
988
989 case k_any_IntrinsicKind:
990 return coalesce_vector<bool>(arguments, /*startingState=*/false, returnType,
991 Intrinsics::coalesce_any,
992 /*finalize=*/nullptr);
993 case k_all_IntrinsicKind:
994 return coalesce_vector<bool>(arguments, /*startingState=*/true, returnType,
995 Intrinsics::coalesce_all,
996 /*finalize=*/nullptr);
997 case k_not_IntrinsicKind:
998 return evaluate_intrinsic<bool>(context, arguments, returnType,
999 Intrinsics::evaluate_not);
1000 default:
1001 return nullptr;
1002 }
1003}
static void round(SkPoint *p)
float SkHalfToFloat(SkHalf h)
Definition: SkHalf.cpp:24
SkHalf SkFloatToHalf(float f)
Definition: SkHalf.cpp:16
SkScalar SkInvert2x2Matrix(const SkScalar inMatrix[4], SkScalar outMatrix[4])
SkScalar SkInvert3x3Matrix(const SkScalar inMatrix[9], SkScalar outMatrix[9])
SkScalar SkInvert4x4Matrix(const SkScalar inMatrix[16], SkScalar outMatrix[16])
static void copy(void *dst, const uint8_t *src, int width, int bpp, int deltaSrc, int offset, const SkPMColor ctable[])
Definition: SkSwizzler.cpp:31
const std::unique_ptr< Type > fUInt
bool isBoolean() const
Definition: SkSLType.h:297
bool isFloat() const
Definition: SkSLType.h:318
bool isInteger() const
Definition: SkSLType.h:339
double x
const GrXPFactory * Get(SkBlendMode mode)
static void * Pack(const T &ctx, SkArenaAlloc *alloc)
static std::unique_ptr< Expression > optimize_comparison(const Context &context, const IntrinsicArguments &arguments, CompareFn compare)
std::array< const Expression *, 3 > IntrinsicArguments
static std::unique_ptr< Expression > evaluate_3_way_intrinsic(const Context &context, const IntrinsicArguments &arguments, const Type &returnType, EvaluateFn eval)
static std::unique_ptr< Expression > evaluate_pairwise_intrinsic(const Context &context, const IntrinsicArguments &arguments, const Type &returnType, EvaluateFn eval)
static std::unique_ptr< Expression > evaluate_intrinsic_numeric(const Context &context, const IntrinsicArguments &arguments, const Type &returnType, EvaluateFn eval)
void type_check_expression< bool >(const Expression &expr)
static void extract_matrix(const Expression *expr, float mat[16])

◆ parameters_match()

static bool SkSL::parameters_match ( SkSpan< const std::unique_ptr< Variable > >  params,
SkSpan< Variable *const >  otherParams 
)
static

Checks a parameter list (params) against the parameters of a function that was declared earlier (otherParams). Returns true if they match, even if the parameters in otherParams contain generic types.

Definition at line 294 of file SkSLFunctionDeclaration.cpp.

295 {
296 // If the param lists are different lengths, they're definitely not a match.
297 if (params.size() != otherParams.size()) {
298 return false;
299 }
300
301 // Figure out a consistent generic index (or bail if we find a contradiction).
302 int genericIndex = -1;
303 for (size_t i = 0; i < params.size(); ++i) {
304 const Type* paramType = &params[i]->type();
305 const Type* otherParamType = &otherParams[i]->type();
306
307 if (otherParamType->isGeneric()) {
308 int genericIndexForThisParam = find_generic_index(*paramType, *otherParamType,
309 /*allowNarrowing=*/false);
310 if (genericIndexForThisParam == -1) {
311 // The type wasn't a match for this generic at all; these params can't be a match.
312 return false;
313 }
314 if (genericIndex != -1 && genericIndex != genericIndexForThisParam) {
315 // The generic index mismatches from what we determined on a previous parameter.
316 return false;
317 }
318 genericIndex = genericIndexForThisParam;
319 }
320 }
321
322 // Now that we've determined a generic index (if we needed one), do a parameter check.
323 for (size_t i = 0; i < params.size(); i++) {
324 const Type* paramType = &params[i]->type();
325 const Type* otherParamType = &otherParams[i]->type();
326
327 // Make generic types concrete.
328 if (otherParamType->isGeneric()) {
329 SkASSERT(genericIndex != -1);
330 SkASSERT(genericIndex < (int)otherParamType->coercibleTypes().size());
331 otherParamType = otherParamType->coercibleTypes()[genericIndex];
332 }
333 // Detect type mismatches.
334 if (!paramType->matches(*otherParamType)) {
335 return false;
336 }
337 }
338 return true;
339}
static int find_generic_index(const Type &concreteType, const Type &genericType, bool allowNarrowing)

◆ parse_modifier_token()

static ModifierFlags SkSL::parse_modifier_token ( Token::Kind  token)
static

Definition at line 77 of file SkSLParser.cpp.

77 {
78 switch (token) {
79 case Token::Kind::TK_UNIFORM: return ModifierFlag::kUniform;
80 case Token::Kind::TK_CONST: return ModifierFlag::kConst;
81 case Token::Kind::TK_IN: return ModifierFlag::kIn;
82 case Token::Kind::TK_OUT: return ModifierFlag::kOut;
83 case Token::Kind::TK_INOUT: return ModifierFlag::kIn | ModifierFlag::kOut;
84 case Token::Kind::TK_FLAT: return ModifierFlag::kFlat;
85 case Token::Kind::TK_NOPERSPECTIVE: return ModifierFlag::kNoPerspective;
86 case Token::Kind::TK_PURE: return ModifierFlag::kPure;
87 case Token::Kind::TK_INLINE: return ModifierFlag::kInline;
88 case Token::Kind::TK_NOINLINE: return ModifierFlag::kNoInline;
89 case Token::Kind::TK_HIGHP: return ModifierFlag::kHighp;
90 case Token::Kind::TK_MEDIUMP: return ModifierFlag::kMediump;
91 case Token::Kind::TK_LOWP: return ModifierFlag::kLowp;
92 case Token::Kind::TK_EXPORT: return ModifierFlag::kExport;
93 case Token::Kind::TK_ES3: return ModifierFlag::kES3;
94 case Token::Kind::TK_WORKGROUP: return ModifierFlag::kWorkgroup;
95 case Token::Kind::TK_READONLY: return ModifierFlag::kReadOnly;
96 case Token::Kind::TK_WRITEONLY: return ModifierFlag::kWriteOnly;
97 case Token::Kind::TK_BUFFER: return ModifierFlag::kBuffer;
98 case Token::Kind::TK_PIXELLOCAL: return ModifierFlag::kPixelLocal;
99 default: return ModifierFlag::kNone;
100 }
101}

◆ pass_by_reference()

static bool SkSL::pass_by_reference ( const Type type,
ModifierFlags  flags 
)
static

Definition at line 549 of file SkSLMetalCodeGenerator.cpp.

549 {
550 return (flags & ModifierFlag::kOut) && !type.isUnsizedArray();
551}

◆ pick_by_type()

template<typename T >
static T SkSL::pick_by_type ( const Type type,
T  ifFloat,
T  ifInt,
T  ifUInt,
T  ifBool 
)
static

Definition at line 932 of file SkSLSPIRVCodeGenerator.cpp.

932 {
933 if (is_float(type)) {
934 return ifFloat;
935 }
936 if (is_signed(type)) {
937 return ifInt;
938 }
939 if (is_unsigned(type)) {
940 return ifUInt;
941 }
942 if (is_bool(type)) {
943 return ifBool;
944 }
945 SkDEBUGFAIL("unrecognized type");
946 return ifFloat;
947}
static bool is_bool(const Type &type)
static bool is_float(const Type &type)
static bool is_unsigned(const Type &type)
static bool is_signed(const Type &type)

◆ pun_value()

template<typename T1 , typename T2 >
static double SkSL::pun_value ( double  val)
static

Definition at line 346 of file SkSLFunctionCall.cpp.

346 {
347 // Interpret `val` as a value of type T1.
348 static_assert(sizeof(T1) == sizeof(T2));
349 T1 inputValue = (T1)val;
350 // Reinterpret those bits as a value of type T2.
351 T2 outputValue;
352 memcpy(&outputValue, &inputValue, sizeof(T2));
353 // Return the value-of-type-T2 as a double. (Non-finite values will prohibit optimization.)
354 return (double)outputValue;
355}

◆ range_of_at_least_one_char()

static Position SkSL::range_of_at_least_one_char ( int  start,
int  end 
)
static

Definition at line 1580 of file SkSLParser.cpp.

1580 {
1581 return Position::Range(start, std::max(end, start + 1));
1582}
static float max(float r, float g, float b)
Definition: hsl.cpp:49

◆ remove_break_statements()

static void SkSL::remove_break_statements ( std::unique_ptr< Statement > &  stmt)
static

Definition at line 66 of file SkSLSwitchStatement.cpp.

66 {
67 class RemoveBreaksWriter : public ProgramWriter {
68 public:
69 bool visitStatementPtr(std::unique_ptr<Statement>& stmt) override {
70 if (stmt->is<BreakStatement>()) {
71 stmt = Nop::Make();
72 return false;
73 }
75 }
76
77 bool visitExpressionPtr(std::unique_ptr<Expression>& expr) override {
78 return false;
79 }
80 };
81 RemoveBreaksWriter{}.visitStatementPtr(stmt);
82}

◆ replace_empty_with_nop()

static std::unique_ptr< Statement > SkSL::replace_empty_with_nop ( std::unique_ptr< Statement stmt,
bool  isEmpty 
)
static

Definition at line 51 of file SkSLIfStatement.cpp.

52 {
53 return (stmt && (!isEmpty || stmt->is<Nop>())) ? std::move(stmt)
54 : Nop::Make();
55}

◆ set_thread_local_memory_pool()

static void SkSL::set_thread_local_memory_pool ( MemoryPool memPool)
static

Definition at line 22 of file SkSLPool.cpp.

22 {
23 sMemPool = memPool;
24}

◆ short_circuit_boolean()

static std::unique_ptr< Expression > SkSL::short_circuit_boolean ( Position  pos,
const Expression left,
Operator  op,
const Expression right 
)
static

Definition at line 71 of file SkSLConstantFolder.cpp.

74 {
75 bool leftVal = left.as<Literal>().boolValue();
76
77 // When the literal is on the left, we can sometimes eliminate the other expression entirely.
78 if ((op.kind() == Operator::Kind::LOGICALAND && !leftVal) || // (false && expr) -> (false)
79 (op.kind() == Operator::Kind::LOGICALOR && leftVal)) { // (true || expr) -> (true)
80
81 return left.clone(pos);
82 }
83
84 // We can't eliminate the right-side expression via short-circuit, but we might still be able to
85 // simplify away a no-op expression.
87}
static std::unique_ptr< Expression > eliminate_no_op_boolean(Position pos, const Expression &left, Operator op, const Expression &right)

◆ simplify_arithmetic()

static std::unique_ptr< Expression > SkSL::simplify_arithmetic ( const Context context,
Position  pos,
const Expression left,
Operator  op,
const Expression right,
const Type resultType 
)
static

Definition at line 480 of file SkSLConstantFolder.cpp.

485 {
486 switch (op.kind()) {
487 case Operator::Kind::PLUS:
489 ConstantFolder::IsConstantSplat(right, 0.0)) { // x + 0
490 if (std::unique_ptr<Expression> expr = cast_expression(context, pos, left,
491 resultType)) {
492 return expr;
493 }
494 }
496 ConstantFolder::IsConstantSplat(left, 0.0)) { // 0 + x
497 if (std::unique_ptr<Expression> expr = cast_expression(context, pos, right,
498 resultType)) {
499 return expr;
500 }
501 }
502 break;
503
504 case Operator::Kind::STAR:
505 if (is_constant_value(right, 1.0)) { // x * 1
506 if (std::unique_ptr<Expression> expr = cast_expression(context, pos, left,
507 resultType)) {
508 return expr;
509 }
510 }
511 if (is_constant_value(left, 1.0)) { // 1 * x
512 if (std::unique_ptr<Expression> expr = cast_expression(context, pos, right,
513 resultType)) {
514 return expr;
515 }
516 }
517 if (is_constant_value(right, 0.0) && !Analysis::HasSideEffects(left)) { // x * 0
518 return zero_expression(context, pos, resultType);
519 }
520 if (is_constant_value(left, 0.0) && !Analysis::HasSideEffects(right)) { // 0 * x
521 return zero_expression(context, pos, resultType);
522 }
523 if (is_constant_value(right, -1.0)) { // x * -1 (to `-x`)
524 if (std::unique_ptr<Expression> expr = negate_expression(context, pos, left,
525 resultType)) {
526 return expr;
527 }
528 }
529 if (is_constant_value(left, -1.0)) { // -1 * x (to `-x`)
530 if (std::unique_ptr<Expression> expr = negate_expression(context, pos, right,
531 resultType)) {
532 return expr;
533 }
534 }
535 break;
536
537 case Operator::Kind::MINUS:
539 ConstantFolder::IsConstantSplat(right, 0.0)) { // x - 0
540 if (std::unique_ptr<Expression> expr = cast_expression(context, pos, left,
541 resultType)) {
542 return expr;
543 }
544 }
546 ConstantFolder::IsConstantSplat(left, 0.0)) { // 0 - x
547 if (std::unique_ptr<Expression> expr = negate_expression(context, pos, right,
548 resultType)) {
549 return expr;
550 }
551 }
552 break;
553
554 case Operator::Kind::SLASH:
556 ConstantFolder::IsConstantSplat(right, 1.0)) { // x / 1
557 if (std::unique_ptr<Expression> expr = cast_expression(context, pos, left,
558 resultType)) {
559 return expr;
560 }
561 }
562 if (!left.type().isMatrix()) { // convert `x / 2` into `x * 0.5`
563 if (std::unique_ptr<Expression> expr = make_reciprocal_expression(context, right)) {
564 return BinaryExpression::Make(context, pos, left.clone(), Operator::Kind::STAR,
565 std::move(expr));
566 }
567 }
568 break;
569
570 case Operator::Kind::PLUSEQ:
571 case Operator::Kind::MINUSEQ:
572 if (ConstantFolder::IsConstantSplat(right, 0.0)) { // x += 0, x -= 0
573 if (std::unique_ptr<Expression> var = cast_expression(context, pos, left,
574 resultType)) {
576 return var;
577 }
578 }
579 break;
580
581 case Operator::Kind::STAREQ:
582 if (is_constant_value(right, 1.0)) { // x *= 1
583 if (std::unique_ptr<Expression> var = cast_expression(context, pos, left,
584 resultType)) {
586 return var;
587 }
588 }
589 break;
590
591 case Operator::Kind::SLASHEQ:
592 if (ConstantFolder::IsConstantSplat(right, 1.0)) { // x /= 1
593 if (std::unique_ptr<Expression> var = cast_expression(context, pos, left,
594 resultType)) {
596 return var;
597 }
598 }
599 if (std::unique_ptr<Expression> expr = make_reciprocal_expression(context, right)) {
600 return BinaryExpression::Make(context, pos, left.clone(), Operator::Kind::STAREQ,
601 std::move(expr));
602 }
603 break;
604
605 default:
606 break;
607 }
608
609 return nullptr;
610}
bool UpdateVariableRefKind(Expression *expr, VariableRefKind kind, ErrorReporter *errors=nullptr)
static std::unique_ptr< Expression > negate_expression(const Context &context, Position pos, const Expression &expr, const Type &type)
static bool is_matrix_op_scalar(const Expression &left, const Expression &right)
static bool is_constant_value(const Expression &expr, double value)
static std::unique_ptr< Expression > make_reciprocal_expression(const Context &context, const Expression &right)
static std::unique_ptr< Expression > zero_expression(const Context &context, Position pos, const Type &type)

◆ simplify_componentwise()

static std::unique_ptr< Expression > SkSL::simplify_componentwise ( const Context context,
Position  pos,
const Expression left,
Operator  op,
const Expression right 
)
static

Definition at line 215 of file SkSLConstantFolder.cpp.

219 {
220 SkASSERT(is_vec_or_mat(left.type()));
221 SkASSERT(left.type().matches(right.type()));
222 const Type& type = left.type();
223
224 // Handle equality operations: == !=
225 if (std::unique_ptr<Expression> result = simplify_constant_equality(context, pos, left, op,
226 right)) {
227 return result;
228 }
229
230 // Handle floating-point arithmetic: + - * /
231 using FoldFn = double (*)(double, double);
232 FoldFn foldFn;
233 switch (op.kind()) {
234 case Operator::Kind::PLUS: foldFn = +[](double a, double b) { return a + b; }; break;
235 case Operator::Kind::MINUS: foldFn = +[](double a, double b) { return a - b; }; break;
236 case Operator::Kind::STAR: foldFn = +[](double a, double b) { return a * b; }; break;
237 case Operator::Kind::SLASH: foldFn = +[](double a, double b) { return a / b; }; break;
238 default:
239 return nullptr;
240 }
241
242 const Type& componentType = type.componentType();
243 SkASSERT(componentType.isNumber());
244
245 double minimumValue = componentType.minimumValue();
246 double maximumValue = componentType.maximumValue();
247
248 double args[16];
249 int numSlots = type.slotCount();
250 for (int i = 0; i < numSlots; i++) {
251 double value = foldFn(*left.getConstantValue(i), *right.getConstantValue(i));
252 if (value < minimumValue || value > maximumValue) {
253 return nullptr;
254 }
255 args[i] = value;
256 }
257 return ConstructorCompound::MakeFromConstants(context, pos, type, args);
258}

◆ simplify_constant_equality()

static std::unique_ptr< Expression > SkSL::simplify_constant_equality ( const Context context,
Position  pos,
const Expression left,
Operator  op,
const Expression right 
)
static

Definition at line 89 of file SkSLConstantFolder.cpp.

93 {
94 if (op.kind() == Operator::Kind::EQEQ || op.kind() == Operator::Kind::NEQ) {
95 bool equality = (op.kind() == Operator::Kind::EQEQ);
96
97 switch (left.compareConstant(right)) {
98 case Expression::ComparisonResult::kNotEqual:
99 equality = !equality;
100 [[fallthrough]];
101
102 case Expression::ComparisonResult::kEqual:
103 return Literal::MakeBool(context, pos, equality);
104
106 break;
107 }
108 }
109 return nullptr;
110}

◆ simplify_matrix_division()

static std::unique_ptr< Expression > SkSL::simplify_matrix_division ( const Context context,
Position  pos,
const Expression left,
Operator  op,
const Expression right,
const Type resultType 
)
static

Definition at line 625 of file SkSLConstantFolder.cpp.

630 {
631 // Convert matrix-over-scalar `x /= y` into `x *= (1.0 / y)`. This generates better
632 // code in SPIR-V and Metal, and should be roughly equivalent elsewhere.
633 switch (op.kind()) {
634 case OperatorKind::SLASH:
635 case OperatorKind::SLASHEQ:
636 if (left.type().isMatrix() && right.type().isScalar()) {
637 Operator multiplyOp = op.isAssignment() ? OperatorKind::STAREQ
638 : OperatorKind::STAR;
639 return BinaryExpression::Make(context, pos,
640 left.clone(),
641 multiplyOp,
642 one_over_scalar(context, right));
643 }
644 break;
645
646 default:
647 break;
648 }
649
650 return nullptr;
651}
bool isAssignment() const
static std::unique_ptr< Expression > one_over_scalar(const Context &context, const Expression &right)

◆ simplify_matrix_multiplication()

static std::unique_ptr< Expression > SkSL::simplify_matrix_multiplication ( const Context context,
Position  pos,
const Expression left,
const Expression right,
int  leftColumns,
int  leftRows,
int  rightColumns,
int  rightRows 
)
static

Definition at line 112 of file SkSLConstantFolder.cpp.

119 {
120 const Type& componentType = left.type().componentType();
121 SkASSERT(componentType.matches(right.type().componentType()));
122
123 // Fetch the left matrix.
124 double leftVals[4][4];
125 for (int c = 0; c < leftColumns; ++c) {
126 for (int r = 0; r < leftRows; ++r) {
127 leftVals[c][r] = *left.getConstantValue((c * leftRows) + r);
128 }
129 }
130 // Fetch the right matrix.
131 double rightVals[4][4];
132 for (int c = 0; c < rightColumns; ++c) {
133 for (int r = 0; r < rightRows; ++r) {
134 rightVals[c][r] = *right.getConstantValue((c * rightRows) + r);
135 }
136 }
137
138 SkASSERT(leftColumns == rightRows);
139 int outColumns = rightColumns,
140 outRows = leftRows;
141
142 double args[16];
143 int argIndex = 0;
144 for (int c = 0; c < outColumns; ++c) {
145 for (int r = 0; r < outRows; ++r) {
146 // Compute a dot product for this position.
147 double val = 0;
148 for (int dotIdx = 0; dotIdx < leftColumns; ++dotIdx) {
149 val += leftVals[dotIdx][r] * rightVals[c][dotIdx];
150 }
151
152 if (val >= -FLT_MAX && val <= FLT_MAX) {
153 args[argIndex++] = val;
154 } else {
155 // The value is outside the 32-bit float range, or is NaN; do not optimize.
156 return nullptr;
157 }
158 }
159 }
160
161 if (outColumns == 1) {
162 // Matrix-times-vector conceptually makes a 1-column N-row matrix, but we return vecN.
163 std::swap(outColumns, outRows);
164 }
165
166 const Type& resultType = componentType.toCompound(context, outColumns, outRows);
167 return ConstructorCompound::MakeFromConstants(context, pos, resultType, args);
168}
void swap(sk_sp< T > &a, sk_sp< T > &b)
Definition: SkRefCnt.h:341

◆ simplify_matrix_times_matrix()

static std::unique_ptr< Expression > SkSL::simplify_matrix_times_matrix ( const Context context,
Position  pos,
const Expression left,
const Expression right 
)
static

Definition at line 170 of file SkSLConstantFolder.cpp.

173 {
174 const Type& leftType = left.type();
175 const Type& rightType = right.type();
176
177 SkASSERT(leftType.isMatrix());
178 SkASSERT(rightType.isMatrix());
179
181 leftType.columns(), leftType.rows(),
182 rightType.columns(), rightType.rows());
183}
static std::unique_ptr< Expression > simplify_matrix_multiplication(const Context &context, Position pos, const Expression &left, const Expression &right, int leftColumns, int leftRows, int rightColumns, int rightRows)

◆ simplify_matrix_times_vector()

static std::unique_ptr< Expression > SkSL::simplify_matrix_times_vector ( const Context context,
Position  pos,
const Expression left,
const Expression right 
)
static

Definition at line 200 of file SkSLConstantFolder.cpp.

203 {
204 const Type& leftType = left.type();
205 const Type& rightType = right.type();
206
207 SkASSERT(leftType.isMatrix());
208 SkASSERT(rightType.isVector());
209
211 leftType.columns(), leftType.rows(),
212 /*rightColumns=*/1, /*rightRows=*/rightType.columns());
213}

◆ simplify_negation()

static std::unique_ptr< Expression > SkSL::simplify_negation ( const Context context,
Position  pos,
const Expression originalExpr 
)
static

Definition at line 71 of file SkSLPrefixExpression.cpp.

73 {
74 const Expression* value = ConstantFolder::GetConstantValueForVariable(originalExpr);
75 switch (value->kind()) {
76 case Expression::Kind::kLiteral:
77 case Expression::Kind::kConstructorSplat:
78 case Expression::Kind::kConstructorCompound: {
79 // Convert `-vecN(literal, ...)` into `vecN(-literal, ...)`.
80 if (std::unique_ptr<Expression> expr = apply_to_elements(context, pos, *value,
81 negate_value)) {
82 return expr;
83 }
84 break;
85 }
86 case Expression::Kind::kPrefix: {
87 // Convert `-(-expression)` into `expression`.
88 const PrefixExpression& prefix = value->as<PrefixExpression>();
89 if (prefix.getOperator().kind() == Operator::Kind::MINUS) {
90 return prefix.operand()->clone(pos);
91 }
92 break;
93 }
94 case Expression::Kind::kConstructorArray:
95 // Convert `-array[N](literal, ...)` into `array[N](-literal, ...)`.
97 const ConstructorArray& ctor = value->as<ConstructorArray>();
98 return ConstructorArray::Make(context, pos, ctor.type(),
99 negate_operands(context, pos, ctor.arguments()));
100 }
101 break;
102
103 case Expression::Kind::kConstructorDiagonalMatrix:
104 // Convert `-matrix(literal)` into `matrix(-literal)`.
106 const ConstructorDiagonalMatrix& ctor = value->as<ConstructorDiagonalMatrix>();
107 if (std::unique_ptr<Expression> simplified = simplify_negation(context,
108 pos,
109 *ctor.argument())) {
110 return ConstructorDiagonalMatrix::Make(context, pos, ctor.type(),
111 std::move(simplified));
112 }
113 }
114 break;
115
116 default:
117 break;
118 }
119 return nullptr;
120}
static ExpressionArray negate_operands(const Context &context, Position pos, const ExpressionArray &operands)
static double negate_value(double value)

◆ simplify_vector_times_matrix()

static std::unique_ptr< Expression > SkSL::simplify_vector_times_matrix ( const Context context,
Position  pos,
const Expression left,
const Expression right 
)
static

Definition at line 185 of file SkSLConstantFolder.cpp.

188 {
189 const Type& leftType = left.type();
190 const Type& rightType = right.type();
191
192 SkASSERT(leftType.isVector());
193 SkASSERT(rightType.isMatrix());
194
196 /*leftColumns=*/leftType.columns(), /*leftRows=*/1,
197 rightType.columns(), rightType.rows());
198}

◆ SPIRVtoHLSL()

bool SkSL::SPIRVtoHLSL ( const std::string &  ,
std::string *   
)

Definition at line 47 of file SkSLSPIRVtoHLSL.cpp.

47{ bool SPIRVtoHLSL(const std::string&, std::string*) { return false; } }
bool SPIRVtoHLSL(const std::string &, std::string *)

◆ splat_scalar()

static std::unique_ptr< Expression > SkSL::splat_scalar ( const Context context,
const Expression scalar,
const Type type 
)
static

Definition at line 260 of file SkSLConstantFolder.cpp.

262 {
263 if (type.isVector()) {
264 return ConstructorSplat::Make(context, scalar.fPosition, type, scalar.clone());
265 }
266 if (type.isMatrix()) {
267 int numSlots = type.slotCount();
268 ExpressionArray splatMatrix;
269 splatMatrix.reserve_exact(numSlots);
270 for (int index = 0; index < numSlots; ++index) {
271 splatMatrix.push_back(scalar.clone());
272 }
273 return ConstructorCompound::Make(context, scalar.fPosition, type, std::move(splatMatrix));
274 }
275 SkDEBUGFAILF("unsupported type %s", type.description().c_str());
276 return nullptr;
277}

◆ stod()

bool SkSL::stod ( std::string_view  s,
SKSL_FLOAT value 
)

Definition at line 58 of file SkSLString.cpp.

58 {
59 std::string str(s.data(), s.size());
60 std::stringstream buffer(str);
61 buffer.imbue(std::locale::classic());
62 buffer >> *value;
63 return !buffer.fail() && std::isfinite(*value);
64}
struct MyStruct s
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126

◆ stoi()

bool SkSL::stoi ( std::string_view  s,
SKSL_INT value 
)

Definition at line 66 of file SkSLString.cpp.

66 {
67 if (s.empty()) {
68 return false;
69 }
70 char suffix = s.back();
71 if (suffix == 'u' || suffix == 'U') {
72 s.remove_suffix(1);
73 }
74 std::string str(s); // s is not null-terminated
75 const char* strEnd = str.data() + str.length();
76 char* p;
77 errno = 0;
78 unsigned long long result = strtoull(str.data(), &p, /*base=*/0);
79 *value = static_cast<SKSL_INT>(result);
80 return p == strEnd && errno == 0 && result <= 0xFFFFFFFF;
81}

◆ strip_export_flag()

static void SkSL::strip_export_flag ( Context context,
const FunctionDeclaration funcDecl,
SymbolTable symbols 
)
static

Definition at line 42 of file SkSLRenamePrivateSymbols.cpp.

44 {
45 // Remove `$export` from every overload of this function.
46 Symbol* mutableSym = symbols->findMutable(funcDecl->name());
47 while (mutableSym) {
48 FunctionDeclaration* mutableDecl = &mutableSym->as<FunctionDeclaration>();
49
50 ModifierFlags flags = mutableDecl->modifierFlags();
51 flags &= ~ModifierFlag::kExport;
52 mutableDecl->setModifierFlags(flags);
53
54 mutableSym = mutableDecl->mutableNextOverload();
55 }
56}
FunctionDeclaration * mutableNextOverload() const
ModifierFlags modifierFlags() const
void setModifierFlags(ModifierFlags m)
std::string_view name() const
Definition: SkSLSymbol.h:51

◆ ToGLSL() [1/2]

bool SkSL::ToGLSL ( Program program,
const ShaderCaps caps,
OutputStream out 
)

Converts a Program into GLSL code.

Definition at line 2034 of file SkSLGLSLCodeGenerator.cpp.

2034 {
2035 TRACE_EVENT0("skia.shaders", "SkSL::ToGLSL");
2036 SkASSERT(caps != nullptr);
2037
2038 program.fContext->fErrors->setSource(*program.fSource);
2039 GLSLCodeGenerator cg(program.fContext.get(), caps, &program, &out);
2040 bool result = cg.generateCode();
2041 program.fContext->fErrors->setSource(std::string_view());
2042
2043 return result;
2044}
std::shared_ptr< Context > fContext
Definition: SkSLProgram.h:154
std::unique_ptr< std::string > fSource
Definition: SkSLProgram.h:152
#define TRACE_EVENT0(category_group, name)
Definition: trace_event.h:131

◆ ToGLSL() [2/2]

bool SkSL::ToGLSL ( Program program,
const ShaderCaps caps,
std::string *  out 
)

Definition at line 2046 of file SkSLGLSLCodeGenerator.cpp.

2046 {
2048 if (!ToGLSL(program, caps, buffer)) {
2049 return false;
2050 }
2051 *out = buffer.str();
2052 return true;
2053}
bool ToGLSL(Program &program, const ShaderCaps *caps, std::string *out)

◆ ToHLSL() [1/2]

bool SkSL::ToHLSL ( Program program,
const ShaderCaps caps,
OutputStream out 
)

Converts a Program into HLSL code. (SPIRV-Cross must be enabled.)

Definition at line 26 of file SkSLHLSLCodeGenerator.cpp.

26 {
27 TRACE_EVENT0("skia.shaders", "SkSL::ToHLSL");
28 std::string hlsl;
29 if (!ToHLSL(program, caps, &hlsl)) {
30 return false;
31 }
32 out.writeString(hlsl);
33 return true;
34}
bool ToHLSL(Program &program, const ShaderCaps *caps, std::string *out)

◆ ToHLSL() [2/2]

bool SkSL::ToHLSL ( Program program,
const ShaderCaps caps,
std::string *  out 
)

Definition at line 36 of file SkSLHLSLCodeGenerator.cpp.

36 {
37 std::string spirv;
38 if (!ToSPIRV(program, caps, &spirv)) {
39 return false;
40 }
41 if (!SPIRVtoHLSL(spirv, out)) {
42 program.fContext->fErrors->error(Position(), "HLSL cross-compilation not enabled");
43 return false;
44 }
45 return true;
46}
bool ToSPIRV(Program &program, const ShaderCaps *caps, OutputStream &out)

◆ ToMetal() [1/2]

bool SkSL::ToMetal ( Program program,
const ShaderCaps caps,
OutputStream out 
)

Converts a Program into Metal code.

Definition at line 3653 of file SkSLMetalCodeGenerator.cpp.

3653 {
3654 TRACE_EVENT0("skia.shaders", "SkSL::ToMetal");
3655 SkASSERT(caps != nullptr);
3656
3657 program.fContext->fErrors->setSource(*program.fSource);
3658 MetalCodeGenerator cg(program.fContext.get(), caps, &program, &out);
3659 bool result = cg.generateCode();
3660 program.fContext->fErrors->setSource(std::string_view());
3661
3662 return result;
3663}

◆ ToMetal() [2/2]

bool SkSL::ToMetal ( Program program,
const ShaderCaps caps,
std::string *  out 
)

Definition at line 3665 of file SkSLMetalCodeGenerator.cpp.

3665 {
3667 if (!ToMetal(program, caps, buffer)) {
3668 return false;
3669 }
3670 *out = buffer.str();
3671 return true;
3672}
bool ToMetal(Program &program, const ShaderCaps *caps, std::string *out)

◆ ToSPIRV() [1/2]

bool SkSL::ToSPIRV ( Program program,
const ShaderCaps caps,
OutputStream out 
)

Converts a Program into a SPIR-V binary.

Definition at line 5408 of file SkSLSPIRVCodeGenerator.cpp.

5408 {
5409 TRACE_EVENT0("skia.shaders", "SkSL::ToSPIRV");
5410 SkASSERT(caps != nullptr);
5411
5412 program.fContext->fErrors->setSource(*program.fSource);
5413#ifdef SK_ENABLE_SPIRV_VALIDATION
5415 SPIRVCodeGenerator cg(program.fContext.get(), caps, &program, &buffer);
5416 bool result = cg.generateCode();
5417
5418 if (result && program.fConfig->fSettings.fValidateSPIRV) {
5419 std::string_view binary = buffer.str();
5420 result = validate_spirv(*program.fContext->fErrors, binary);
5421 out.write(binary.data(), binary.size());
5422 }
5423#else
5424 SPIRVCodeGenerator cg(program.fContext.get(), caps, &program, &out);
5425 bool result = cg.generateCode();
5426#endif
5427 program.fContext->fErrors->setSource(std::string_view());
5428
5429 return result;
5430}
std::unique_ptr< ProgramConfig > fConfig
Definition: SkSLProgram.h:153

◆ ToSPIRV() [2/2]

bool SkSL::ToSPIRV ( Program program,
const ShaderCaps caps,
std::string *  out 
)

Definition at line 5432 of file SkSLSPIRVCodeGenerator.cpp.

5432 {
5434 if (!ToSPIRV(program, caps, buffer)) {
5435 return false;
5436 }
5437 *out = buffer.str();
5438 return true;
5439}
bool ToSPIRV(Program &program, const ShaderCaps *caps, std::string *out)

◆ ToWGSL() [1/2]

bool SkSL::ToWGSL ( Program program,
const ShaderCaps caps,
OutputStream out 
)

Convert a Program into WGSL code.

Definition at line 4597 of file SkSLWGSLCodeGenerator.cpp.

4597 {
4598 TRACE_EVENT0("skia.shaders", "SkSL::ToWGSL");
4599 SkASSERT(caps != nullptr);
4600
4601 program.fContext->fErrors->setSource(*program.fSource);
4602#ifdef SK_ENABLE_WGSL_VALIDATION
4603 StringStream wgsl;
4604 WGSLCodeGenerator cg(program.fContext.get(), caps, &program, &wgsl);
4605 bool result = cg.generateCode();
4606 if (result) {
4607 std::string wgslString = wgsl.str();
4608 std::string warnings;
4609 result = validate_wgsl(*program.fContext->fErrors, wgslString, &warnings);
4610 if (!warnings.empty()) {
4611 out.writeText("/* Tint reported warnings. */\n\n");
4612 }
4613 out.writeString(wgslString);
4614 }
4615#else
4616 WGSLCodeGenerator cg(program.fContext.get(), caps, &program, &out);
4617 bool result = cg.generateCode();
4618#endif
4619 program.fContext->fErrors->setSource(std::string_view());
4620
4621 return result;
4622}
const std::string & str() const

◆ ToWGSL() [2/2]

bool SkSL::ToWGSL ( Program program,
const ShaderCaps caps,
std::string *  out 
)

Definition at line 4624 of file SkSLWGSLCodeGenerator.cpp.

4624 {
4626 if (!ToWGSL(program, caps, buffer)) {
4627 return false;
4628 }
4629 *out = buffer.str();
4630 return true;
4631}
bool ToWGSL(Program &program, const ShaderCaps *caps, std::string *out)

◆ type_check_expression()

template<typename T >
static void SkSL::type_check_expression ( const Expression expr)
static

◆ type_check_expression< bool >()

template<>
void SkSL::type_check_expression< bool > ( const Expression expr)

Definition at line 77 of file SkSLFunctionCall.cpp.

77 {
79}

◆ type_check_expression< float >()

template<>
void SkSL::type_check_expression< float > ( const Expression expr)

Definition at line 67 of file SkSLFunctionCall.cpp.

67 {
69}

◆ type_check_expression< SKSL_INT >()

template<>
void SkSL::type_check_expression< SKSL_INT > ( const Expression expr)

Definition at line 72 of file SkSLFunctionCall.cpp.

72 {
74}

◆ type_generically_matches()

static bool SkSL::type_generically_matches ( const Type concreteType,
const Type maybeGenericType 
)
static

Returns true if the types match, or if concreteType can be found in maybeGenericType.

Definition at line 283 of file SkSLFunctionDeclaration.cpp.

283 {
284 return maybeGenericType.isGeneric()
285 ? find_generic_index(concreteType, maybeGenericType, /*allowNarrowing=*/false) != -1
286 : concreteType.matches(maybeGenericType);
287}
bool isGeneric() const
Definition: SkSLType.h:500

◆ type_is_valid_for_color()

static bool SkSL::type_is_valid_for_color ( const Type type)
static

Definition at line 123 of file SkSLFunctionDeclaration.cpp.

123 {
124 return type.isVector() && type.columns() == 4 && type.componentType().isFloat();
125}

◆ type_is_valid_for_coords()

static bool SkSL::type_is_valid_for_coords ( const Type type)
static

Definition at line 127 of file SkSLFunctionDeclaration.cpp.

127 {
128 return type.isVector() && type.highPrecision() && type.columns() == 2 &&
129 type.componentType().isFloat();
130}

◆ type_to_sksltype()

bool SkSL::type_to_sksltype ( const Context context,
const Type type,
SkSLType outType 
)

Definition at line 46 of file SkSLUtil.cpp.

46 {
47 // If a new GrSL type is added, this function will need to be updated.
48 static_assert(kSkSLTypeCount == 41);
49
50 if (type.matches(*context.fTypes.fVoid )) { *outType = SkSLType::kVoid; return true; }
51 if (type.matches(*context.fTypes.fBool )) { *outType = SkSLType::kBool; return true; }
52 if (type.matches(*context.fTypes.fBool2 )) { *outType = SkSLType::kBool2; return true; }
53 if (type.matches(*context.fTypes.fBool3 )) { *outType = SkSLType::kBool3; return true; }
54 if (type.matches(*context.fTypes.fBool4 )) { *outType = SkSLType::kBool4; return true; }
55 if (type.matches(*context.fTypes.fShort )) { *outType = SkSLType::kShort; return true; }
56 if (type.matches(*context.fTypes.fShort2 )) { *outType = SkSLType::kShort2; return true; }
57 if (type.matches(*context.fTypes.fShort3 )) { *outType = SkSLType::kShort3; return true; }
58 if (type.matches(*context.fTypes.fShort4 )) { *outType = SkSLType::kShort4; return true; }
59 if (type.matches(*context.fTypes.fUShort )) { *outType = SkSLType::kUShort; return true; }
60 if (type.matches(*context.fTypes.fUShort2 )) { *outType = SkSLType::kUShort2; return true; }
61 if (type.matches(*context.fTypes.fUShort3 )) { *outType = SkSLType::kUShort3; return true; }
62 if (type.matches(*context.fTypes.fUShort4 )) { *outType = SkSLType::kUShort4; return true; }
63 if (type.matches(*context.fTypes.fFloat )) { *outType = SkSLType::kFloat; return true; }
64 if (type.matches(*context.fTypes.fFloat2 )) { *outType = SkSLType::kFloat2; return true; }
65 if (type.matches(*context.fTypes.fFloat3 )) { *outType = SkSLType::kFloat3; return true; }
66 if (type.matches(*context.fTypes.fFloat4 )) { *outType = SkSLType::kFloat4; return true; }
67 if (type.matches(*context.fTypes.fFloat2x2)) { *outType = SkSLType::kFloat2x2; return true; }
68 if (type.matches(*context.fTypes.fFloat3x3)) { *outType = SkSLType::kFloat3x3; return true; }
69 if (type.matches(*context.fTypes.fFloat4x4)) { *outType = SkSLType::kFloat4x4; return true; }
70 if (type.matches(*context.fTypes.fHalf )) { *outType = SkSLType::kHalf; return true; }
71 if (type.matches(*context.fTypes.fHalf2 )) { *outType = SkSLType::kHalf2; return true; }
72 if (type.matches(*context.fTypes.fHalf3 )) { *outType = SkSLType::kHalf3; return true; }
73 if (type.matches(*context.fTypes.fHalf4 )) { *outType = SkSLType::kHalf4; return true; }
74 if (type.matches(*context.fTypes.fHalf2x2 )) { *outType = SkSLType::kHalf2x2; return true; }
75 if (type.matches(*context.fTypes.fHalf3x3 )) { *outType = SkSLType::kHalf3x3; return true; }
76 if (type.matches(*context.fTypes.fHalf4x4 )) { *outType = SkSLType::kHalf4x4; return true; }
77 if (type.matches(*context.fTypes.fInt )) { *outType = SkSLType::kInt; return true; }
78 if (type.matches(*context.fTypes.fInt2 )) { *outType = SkSLType::kInt2; return true; }
79 if (type.matches(*context.fTypes.fInt3 )) { *outType = SkSLType::kInt3; return true; }
80 if (type.matches(*context.fTypes.fInt4 )) { *outType = SkSLType::kInt4; return true; }
81 if (type.matches(*context.fTypes.fUInt )) { *outType = SkSLType::kUInt; return true; }
82 if (type.matches(*context.fTypes.fUInt2 )) { *outType = SkSLType::kUInt2; return true; }
83 if (type.matches(*context.fTypes.fUInt3 )) { *outType = SkSLType::kUInt3; return true; }
84 if (type.matches(*context.fTypes.fUInt4 )) { *outType = SkSLType::kUInt4; return true; }
85 return false;
86}
static const int kSkSLTypeCount
const std::unique_ptr< Type > fInt4
const std::unique_ptr< Type > fHalf2x2
const std::unique_ptr< Type > fUInt2
const std::unique_ptr< Type > fShort3
const std::unique_ptr< Type > fInt2
const std::unique_ptr< Type > fUShort
const std::unique_ptr< Type > fInt
const std::unique_ptr< Type > fFloat2x2
const std::unique_ptr< Type > fFloat4x4
const std::unique_ptr< Type > fShort2
const std::unique_ptr< Type > fShort
const std::unique_ptr< Type > fInt3
const std::unique_ptr< Type > fUInt3
const std::unique_ptr< Type > fUShort4
const std::unique_ptr< Type > fFloat4
const std::unique_ptr< Type > fHalf2
const std::unique_ptr< Type > fUInt4
const std::unique_ptr< Type > fHalf3x3
const std::unique_ptr< Type > fShort4
const std::unique_ptr< Type > fBool2
const std::unique_ptr< Type > fFloat3x3
const std::unique_ptr< Type > fUShort2
const std::unique_ptr< Type > fBool3
const std::unique_ptr< Type > fUShort3
const std::unique_ptr< Type > fHalf3
const std::unique_ptr< Type > fFloat
const std::unique_ptr< Type > fFloat3
const std::unique_ptr< Type > fHalf
const std::unique_ptr< Type > fHalf4x4
const std::unique_ptr< Type > fBool4

◆ types_match()

static bool SkSL::types_match ( const Type a,
const Type b 
)
static

Definition at line 3698 of file SkSLSPIRVCodeGenerator.cpp.

3698 {
3699 if (a.matches(b)) {
3700 return true;
3701 }
3702 return (a.typeKind() == b.typeKind()) &&
3703 (a.isScalar() || a.isVector() || a.isMatrix()) &&
3704 (a.columns() == b.columns() && a.rows() == b.rows()) &&
3705 a.componentType().numberKind() == b.componentType().numberKind();
3706}

◆ validate_swizzle_domain()

static bool SkSL::validate_swizzle_domain ( const ComponentArray fields)
static

Definition at line 34 of file SkSLSwizzle.cpp.

34 {
35 enum SwizzleDomain {
36 kCoordinate,
37 kColor,
38 kUV,
40 };
41
42 std::optional<SwizzleDomain> domain;
43
44 for (int8_t field : fields) {
45 SwizzleDomain fieldDomain;
46 switch (field) {
51 fieldDomain = kCoordinate;
52 break;
57 fieldDomain = kColor;
58 break;
63 fieldDomain = kUV;
64 break;
69 fieldDomain = kRectangle;
70 break;
73 continue;
74 default:
75 return false;
76 }
77
78 if (!domain.has_value()) {
79 domain = fieldDomain;
80 } else if (domain != fieldDomain) {
81 return false;
82 }
83 }
84
85 return true;
86}

◆ write_stringstream()

void SkSL::write_stringstream ( const StringStream s,
OutputStream out 
)

Definition at line 42 of file SkSLUtil.cpp.

42 {
43 out.write(s.str().c_str(), s.str().size());
44}

◆ zero_expression()

static std::unique_ptr< Expression > SkSL::zero_expression ( const Context context,
Position  pos,
const Type type 
)
static

Definition at line 299 of file SkSLConstantFolder.cpp.

301 {
302 std::unique_ptr<Expression> zero = Literal::Make(pos, 0.0, &type.componentType());
303 if (type.isScalar()) {
304 return zero;
305 }
306 if (type.isVector()) {
307 return ConstructorSplat::Make(context, pos, type, std::move(zero));
308 }
309 if (type.isMatrix()) {
310 return ConstructorDiagonalMatrix::Make(context, pos, type, std::move(zero));
311 }
312 SkDEBUGFAILF("unsupported type %s", type.description().c_str());
313 return nullptr;
314}

Variable Documentation

◆ kAccepts

const uint8_t SkSL::kAccepts[427]
static
Initial value:
= {
255, 255, 89, 89, 92, 68, 73, 92, 43, 41, 41, 41, 41, 36, 41, 41, 41, 41, 37, 41,
41, 41, 27, 58, 82, 63, 67, 87, 44, 45, 56, 80, 54, 52, 78, 51, 55, 53, 79, 50,
1, 255, 255, 1, 57, 255, 255, 91, 90, 81, 2, 1, 1, 255, 255, 1, 255, 255, 1, 2,
3, 255, 255, 1, 3, 2, 2, 255, 2, 2, 2, 70, 88, 75, 59, 83, 77, 71, 72, 74,
76, 60, 84, 69, 42, 42, 48, 49, 62, 86, 66, 42, 42, 40, 42, 42, 42, 42, 42, 42,
42, 42, 42, 42, 42, 42, 42, 42, 14, 42, 42, 42, 42, 30, 42, 42, 42, 12, 42, 42,
42, 42, 42, 42, 22, 42, 42, 42, 42, 15, 42, 42, 42, 42, 42, 42, 13, 42, 42, 42,
42, 42, 16, 10, 42, 42, 42, 42, 42, 42, 42, 42, 42, 7, 42, 42, 42, 42, 42, 42,
40, 42, 42, 42, 42, 42, 5, 42, 42, 42, 42, 42, 23, 42, 8, 42, 42, 42, 42, 42,
40, 42, 42, 42, 42, 42, 42, 33, 42, 42, 42, 42, 6, 18, 42, 42, 42, 25, 42, 42,
20, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
32, 42, 42, 42, 35, 42, 42, 42, 42, 42, 42, 34, 42, 42, 42, 42, 42, 42, 42, 42,
42, 42, 42, 42, 42, 42, 26, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 24, 42, 42,
19, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 39, 42, 42,
42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 28, 42, 42, 42,
17, 42, 42, 42, 42, 42, 42, 42, 42, 40, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
42, 42, 42, 42, 42, 42, 42, 40, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
42, 42, 42, 42, 42, 31, 42, 42, 42, 42, 42, 42, 42, 42, 11, 42, 42, 42, 42, 42,
42, 42, 42, 42, 42, 42, 4, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 21, 42,
42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
42, 42, 42, 42, 9, 42, 42, 42, 42, 42, 42, 42, 38, 42, 42, 42, 42, 42, 42, 42,
29, 46, 61, 85, 65, 47, 64,
}

Definition at line 775 of file SkSLLexer.cpp.

◆ kCompact

constexpr CompactEntry SkSL::kCompact[]
staticconstexpr

Definition at line 121 of file SkSLLexer.cpp.

◆ kDefaultInlineThreshold

constexpr int SkSL::kDefaultInlineThreshold = 50
staticconstexpr

Definition at line 38 of file SkSLDefines.h.

◆ kDefaultLayout

constexpr Layout SkSL::kDefaultLayout
staticconstexpr

Definition at line 29 of file SkSLVariable.cpp.

◆ kDeterminant2

constexpr char SkSL::kDeterminant2[]
staticconstexpr
Initial value:
= R"(
float _determinant2(mat2 m) {
return m[0].x*m[1].y - m[0].y*m[1].x;
}
)"

Definition at line 475 of file SkSLGLSLCodeGenerator.cpp.

◆ kDeterminant3

constexpr char SkSL::kDeterminant3[]
staticconstexpr
Initial value:
= R"(
float _determinant3(mat3 m) {
float
a00 = m[0].x, a01 = m[0].y, a02 = m[0].z,
a10 = m[1].x, a11 = m[1].y, a12 = m[1].z,
a20 = m[2].x, a21 = m[2].y, a22 = m[2].z,
b01 = a22*a11 - a12*a21,
b11 =-a22*a10 + a12*a20,
b21 = a21*a10 - a11*a20;
return a00*b01 + a01*b11 + a02*b21;
}
)"

Definition at line 481 of file SkSLGLSLCodeGenerator.cpp.

◆ kDeterminant4

constexpr char SkSL::kDeterminant4[]
staticconstexpr
Initial value:
= R"(
mat4 _determinant4(mat4 m) {
float
a00 = m[0].x, a01 = m[0].y, a02 = m[0].z, a03 = m[0].w,
a10 = m[1].x, a11 = m[1].y, a12 = m[1].z, a13 = m[1].w,
a20 = m[2].x, a21 = m[2].y, a22 = m[2].z, a23 = m[2].w,
a30 = m[3].x, a31 = m[3].y, a32 = m[3].z, a33 = m[3].w,
b00 = a00*a11 - a01*a10,
b01 = a00*a12 - a02*a10,
b02 = a00*a13 - a03*a10,
b03 = a01*a12 - a02*a11,
b04 = a01*a13 - a03*a11,
b05 = a02*a13 - a03*a12,
b06 = a20*a31 - a21*a30,
b07 = a20*a32 - a22*a30,
b08 = a20*a33 - a23*a30,
b09 = a21*a32 - a22*a31,
b10 = a21*a33 - a23*a31,
b11 = a22*a33 - a23*a32;
return b00*b11 - b01*b10 + b02*b09 + b03*b08 - b04*b07 + b05*b06;
}
)"

Definition at line 494 of file SkSLGLSLCodeGenerator.cpp.

◆ kFull

constexpr FullEntry SkSL::kFull[]
staticconstexpr

Definition at line 32 of file SkSLLexer.cpp.

◆ kIndices

constexpr IndexEntry SkSL::kIndices[]
staticconstexpr
Initial value:
= {
0, -1, 1, 1, 0, 2, 0, 3, 4, 5, 6, 7, 8, 6, 9, 10, 11, 12,
6, 13, 14, 15, 6, 16, 0, 17, 0, 0, 0, 0, 18, 0, 19, 0, 0, 0,
20, 0, 0, 21, 22, 23, 24, 24, 25, 26, 27, 0, 28, 0, -2, 29, 30, 31,
32, 32, 33, 34, 34, -3, -4, 35, 36, 36, 0, 0, 0, 37, 38, -5, -5, 0,
0, 39, 40, 0, 0, 41, 0, 42, 0, 43, 0, 0, 44, 44, 0, 0, 45, 0,
0, 46, 47, 44, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
44, 62, 63, 64, 65, 44, -6, 66, 67, 44, 68, 69, 70, 71, 72, 73, 44, 74,
75, 76, 77, 44, -7, 78, 79, 80, 81, 82, 44, 83, 84, 85, 86, 87, 44, 88,
89, 90, 57, 91, 92, 93, -8, 94, 95, 44, 96, 47, 97, 98, 99, 100, 101, 102,
-9, 103, 104, 105, 44, 106, 107, 108, 109, 110, 44, 111, 44, 112, 113, 93, 114, 115,
116, 117, 118, 119, 120, 121, 122, 44, 123, 124, 93, 125, 44, -10, 126, 127, 128, 44,
129, 130, 44, 131, 132, 133, 134, 135, 136, 137, 57, 138, 139, 140, 141, 142, 132, 143,
144, 145, 146, 147, 44, 148, 149, 150, 44, 151, 152, 153, 154, 155, 156, 44, 157, 158,
159, 160, 161, 162, 163, 57, 164, 165, 166, 167, 168, 169, 44, 170, 171, 172, 173, 174,
175, 176, 177, 178, 179, 44, 180, 181, 182, 183, 132, -11, 184, 185, 186, 108, 187, 188,
189, 190, 191, 192, 193, 194, 195, 44, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205,
51, 206, 207, 208, 209, 210, 211, 212, 44, 213, 214, 215, 44, -12, 216, 217, 218, 219,
220, -13, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236,
237, 227, 238, 239, 240, 241, 132, 242, 243, 57, 244, 245, 246, 247, 248, 249, 250, 51,
251, 252, 253, 44, 254, 255, 256, 257, 258, 259, 260, 261, 44, -14, 262, 263, 264, 265,
266, 57, 267, 70, 268, 269, 44, 270, 271, 272, 273, 247, 274, 275, 276, 277, 278, 279,
44, 202, 280, 281, 282, 283, 108, 284, 285, 149, 286, 287, 288, 289, 290, 149, 291, 292,
293, 294, 295, 57, -15, 296, 297, 298, 44, 299, 300, 301, 302, 303, 304, 305, 44, 306,
307, 308, 309, 310, 311, 312, 44, 0, 313, 0, 0, 0, 0,
}

Definition at line 737 of file SkSLLexer.cpp.

◆ kInvalidChar

constexpr uint8_t SkSL::kInvalidChar = 18
staticconstexpr

Definition at line 15 of file SkSLLexer.cpp.

◆ kInverse2

constexpr char SkSL::kInverse2[]
staticconstexpr
Initial value:
= R"(
mat2 _inverse2(mat2 m) {
return mat2(m[1].y, -m[0].y, -m[1].x, m[0].x) / (m[0].x * m[1].y - m[0].y * m[1].x);
}
)"

Definition at line 548 of file SkSLGLSLCodeGenerator.cpp.

◆ kInverse2x2 [1/2]

constexpr char SkSL::kInverse2x2[]
staticconstexpr
Initial value:
= R"(
template <typename T>
matrix<T, 2, 2> mat2_inverse(matrix<T, 2, 2> m) {
return matrix<T, 2, 2>(m[1].y, -m[0].y, -m[1].x, m[0].x) * (1/determinant(m));
}
)"

Definition at line 731 of file SkSLMetalCodeGenerator.cpp.

◆ kInverse2x2 [2/2]

constexpr char SkSL::kInverse2x2[]
staticconstexpr
Initial value:
=
"fn mat2_inverse(m: mat2x2<f32>) -> mat2x2<f32> {"
"\n" "return mat2x2<f32>(m[1].y, -m[0].y, -m[1].x, m[0].x) * (1/determinant(m));"
"\n" "}"
"\n"

Definition at line 3342 of file SkSLWGSLCodeGenerator.cpp.

◆ kInverse3

constexpr char SkSL::kInverse3[]
staticconstexpr
Initial value:
= R"(
mat3 _inverse3(mat3 m) {
float
a00 = m[0].x, a01 = m[0].y, a02 = m[0].z,
a10 = m[1].x, a11 = m[1].y, a12 = m[1].z,
a20 = m[2].x, a21 = m[2].y, a22 = m[2].z,
b01 = a22*a11 - a12*a21,
b11 =-a22*a10 + a12*a20,
b21 = a21*a10 - a11*a20,
det = a00*b01 + a01*b11 + a02*b21;
return mat3(
b01, (-a22*a01 + a02*a21), ( a12*a01 - a02*a11),
b11, ( a22*a00 - a02*a20), (-a12*a00 + a02*a10),
b21, (-a21*a00 + a01*a20), ( a11*a00 - a01*a10)) / det;
}
)"

Definition at line 554 of file SkSLGLSLCodeGenerator.cpp.

◆ kInverse3x3 [1/2]

constexpr char SkSL::kInverse3x3[]
staticconstexpr
Initial value:
= R"(
template <typename T>
matrix<T, 3, 3> mat3_inverse(matrix<T, 3, 3> m) {
T
a00 = m[0].x, a01 = m[0].y, a02 = m[0].z,
a10 = m[1].x, a11 = m[1].y, a12 = m[1].z,
a20 = m[2].x, a21 = m[2].y, a22 = m[2].z,
b01 = a22*a11 - a12*a21,
b11 = -a22*a10 + a12*a20,
b21 = a21*a10 - a11*a20,
det = a00*b01 + a01*b11 + a02*b21;
return matrix<T, 3, 3>(
b01, (-a22*a01 + a02*a21), ( a12*a01 - a02*a11),
b11, ( a22*a00 - a02*a20), (-a12*a00 + a02*a10),
b21, (-a21*a00 + a01*a20), ( a11*a00 - a01*a10)) * (1/det);
}
)"

Definition at line 738 of file SkSLMetalCodeGenerator.cpp.

◆ kInverse3x3 [2/2]

constexpr char SkSL::kInverse3x3[]
staticconstexpr
Initial value:
=
"fn mat3_inverse(m: mat3x3<f32>) -> mat3x3<f32> {"
"\n" "let a00 = m[0].x; let a01 = m[0].y; let a02 = m[0].z;"
"\n" "let a10 = m[1].x; let a11 = m[1].y; let a12 = m[1].z;"
"\n" "let a20 = m[2].x; let a21 = m[2].y; let a22 = m[2].z;"
"\n" "let b01 = a22*a11 - a12*a21;"
"\n" "let b11 = -a22*a10 + a12*a20;"
"\n" "let b21 = a21*a10 - a11*a20;"
"\n" "let det = a00*b01 + a01*b11 + a02*b21;"
"\n" "return mat3x3<f32>(b01, (-a22*a01 + a02*a21), ( a12*a01 - a02*a11),"
"\n" "b11, ( a22*a00 - a02*a20), (-a12*a00 + a02*a10),"
"\n" "b21, (-a21*a00 + a01*a20), ( a11*a00 - a01*a10)) * (1/det);"
"\n" "}"
"\n"

Definition at line 3348 of file SkSLWGSLCodeGenerator.cpp.

◆ kInverse4

constexpr char SkSL::kInverse4[]
staticconstexpr

Definition at line 571 of file SkSLGLSLCodeGenerator.cpp.

◆ kInverse4x4 [1/2]

constexpr char SkSL::kInverse4x4[]
staticconstexpr

Definition at line 756 of file SkSLMetalCodeGenerator.cpp.

◆ kInverse4x4 [2/2]

constexpr char SkSL::kInverse4x4[]
staticconstexpr

Definition at line 3363 of file SkSLWGSLCodeGenerator.cpp.

◆ kLoopTerminationLimit

constexpr int SkSL::kLoopTerminationLimit = 100000
staticconstexpr

Definition at line 36 of file SkSLGetLoopUnrollInfo.cpp.

◆ kMappings

constexpr uint8_t SkSL::kMappings[118]
staticconstexpr
Initial value:
= {
1, 2, 3, 3, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 1, 4, 3, 5, 6, 7, 8, 3, 9, 10, 11, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 22, 22, 23, 23, 24, 25, 26, 27, 28, 29, 3, 30, 30, 31, 32,
33, 30, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 35, 36, 34, 37, 34, 34, 38,
34, 34, 39, 3, 40, 41, 42, 3, 43, 44, 45, 46, 47, 48, 49, 50, 51, 34, 52, 53,
54, 55, 56, 57, 34, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
}

Definition at line 16 of file SkSLLexer.cpp.

◆ kMaxParseDepth

constexpr int SkSL::kMaxParseDepth = 50
staticconstexpr

Definition at line 75 of file SkSLParser.cpp.

◆ kMaxStructDepth

constexpr int SkSL::kMaxStructDepth = 8
staticconstexpr

Definition at line 40 of file SkSLType.cpp.

◆ kPrivateTypes

constexpr BuiltinTypePtr SkSL::kPrivateTypes[]
staticconstexpr
Initial value:
= {
TYPE(Sampler2D), TYPE(SamplerExternalOES), TYPE(Sampler2DRect),
TYPE(SubpassInput), TYPE(SubpassInputMS),
TYPE(Texture2D_sample),
TYPE(Texture2D), TYPE(ReadOnlyTexture2D), TYPE(WriteOnlyTexture2D),
TYPE(GenTexture2D), TYPE(ReadableTexture2D), TYPE(WritableTexture2D),
TYPE(AtomicUInt),
}
#define TYPE(t)
std::function< ProfileSample(void)> Sampler
Sampler is run during SamplingProfiler::SampleRepeatedly. Each platform should implement its version ...

Definition at line 75 of file SkSLModuleLoader.cpp.

◆ kRootTypes

constexpr BuiltinTypePtr SkSL::kRootTypes[]
staticconstexpr

Definition at line 37 of file SkSLModuleLoader.cpp.

◆ kVariableSlotLimit

constexpr int SkSL::kVariableSlotLimit = 100000
staticconstexpr

Definition at line 43 of file SkSLDefines.h.

◆ SKSL_MAGIC

const int32_t SkSL::SKSL_MAGIC = 0x001F0000
static

Definition at line 745 of file SkSLSPIRVCodeGenerator.cpp.

◆ sMemPool

thread_local MemoryPool* SkSL::sMemPool = nullptr
static

Definition at line 16 of file SkSLPool.cpp.