1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2021 Google LLC 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "src/sksl/SkSLConstantFolder.h" 9cb93a386Sopenharmony_ci#include "src/sksl/SkSLProgramSettings.h" 10cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLConstructorCompound.h" 11cb93a386Sopenharmony_ci 12cb93a386Sopenharmony_ci#include <algorithm> 13cb93a386Sopenharmony_ci#include <numeric> 14cb93a386Sopenharmony_ci 15cb93a386Sopenharmony_cinamespace SkSL { 16cb93a386Sopenharmony_ci 17cb93a386Sopenharmony_cistd::unique_ptr<Expression> ConstructorCompound::Make(const Context& context, 18cb93a386Sopenharmony_ci int line, 19cb93a386Sopenharmony_ci const Type& type, 20cb93a386Sopenharmony_ci ExpressionArray args) { 21cb93a386Sopenharmony_ci SkASSERT(type.isAllowedInES2(context)); 22cb93a386Sopenharmony_ci 23cb93a386Sopenharmony_ci // A scalar "composite" type with a single scalar argument is a no-op and can be eliminated. 24cb93a386Sopenharmony_ci // (Pedantically, this isn't a composite at all, but it's harmless to allow and simplifies 25cb93a386Sopenharmony_ci // call sites which need to narrow a vector and may sometimes end up with a scalar.) 26cb93a386Sopenharmony_ci if (type.isScalar() && args.size() == 1 && args.front()->type() == type) { 27cb93a386Sopenharmony_ci return std::move(args.front()); 28cb93a386Sopenharmony_ci } 29cb93a386Sopenharmony_ci 30cb93a386Sopenharmony_ci // The type must be a vector or matrix, and all the arguments must have matching component type. 31cb93a386Sopenharmony_ci SkASSERT(type.isVector() || type.isMatrix()); 32cb93a386Sopenharmony_ci SkASSERT(std::all_of(args.begin(), args.end(), [&](const std::unique_ptr<Expression>& arg) { 33cb93a386Sopenharmony_ci const Type& argType = arg->type(); 34cb93a386Sopenharmony_ci return (argType.isScalar() || argType.isVector() || argType.isMatrix()) && 35cb93a386Sopenharmony_ci (argType.componentType() == type.componentType()); 36cb93a386Sopenharmony_ci })); 37cb93a386Sopenharmony_ci 38cb93a386Sopenharmony_ci // The slot count of the combined argument list must match the composite type's slot count. 39cb93a386Sopenharmony_ci SkASSERT(type.slotCount() == 40cb93a386Sopenharmony_ci std::accumulate(args.begin(), args.end(), /*initial value*/ (size_t)0, 41cb93a386Sopenharmony_ci [](size_t n, const std::unique_ptr<Expression>& arg) { 42cb93a386Sopenharmony_ci return n + arg->type().slotCount(); 43cb93a386Sopenharmony_ci })); 44cb93a386Sopenharmony_ci 45cb93a386Sopenharmony_ci if (context.fConfig->fSettings.fOptimize) { 46cb93a386Sopenharmony_ci // Find ConstructorCompounds embedded inside other ConstructorCompounds and flatten them. 47cb93a386Sopenharmony_ci // - float4(float2(1, 2), 3, 4) --> float4(1, 2, 3, 4) 48cb93a386Sopenharmony_ci // - float4(w, float3(sin(x), cos(y), tan(z))) --> float4(w, sin(x), cos(y), tan(z)) 49cb93a386Sopenharmony_ci // - mat2(float2(a, b), float2(c, d)) --> mat2(a, b, c, d) 50cb93a386Sopenharmony_ci 51cb93a386Sopenharmony_ci // See how many fields we would have if composite constructors were flattened out. 52cb93a386Sopenharmony_ci size_t fields = 0; 53cb93a386Sopenharmony_ci for (const std::unique_ptr<Expression>& arg : args) { 54cb93a386Sopenharmony_ci fields += arg->is<ConstructorCompound>() 55cb93a386Sopenharmony_ci ? arg->as<ConstructorCompound>().arguments().size() 56cb93a386Sopenharmony_ci : 1; 57cb93a386Sopenharmony_ci } 58cb93a386Sopenharmony_ci 59cb93a386Sopenharmony_ci // If we added up more fields than we're starting with, we found at least one input that can 60cb93a386Sopenharmony_ci // be flattened out. 61cb93a386Sopenharmony_ci if (fields > args.size()) { 62cb93a386Sopenharmony_ci ExpressionArray flattened; 63cb93a386Sopenharmony_ci flattened.reserve_back(fields); 64cb93a386Sopenharmony_ci for (std::unique_ptr<Expression>& arg : args) { 65cb93a386Sopenharmony_ci // For non-ConstructorCompound fields, move them over as-is. 66cb93a386Sopenharmony_ci if (!arg->is<ConstructorCompound>()) { 67cb93a386Sopenharmony_ci flattened.push_back(std::move(arg)); 68cb93a386Sopenharmony_ci continue; 69cb93a386Sopenharmony_ci } 70cb93a386Sopenharmony_ci // For ConstructorCompound fields, move over their inner arguments individually. 71cb93a386Sopenharmony_ci ConstructorCompound& compositeCtor = arg->as<ConstructorCompound>(); 72cb93a386Sopenharmony_ci for (std::unique_ptr<Expression>& innerArg : compositeCtor.arguments()) { 73cb93a386Sopenharmony_ci flattened.push_back(std::move(innerArg)); 74cb93a386Sopenharmony_ci } 75cb93a386Sopenharmony_ci } 76cb93a386Sopenharmony_ci args = std::move(flattened); 77cb93a386Sopenharmony_ci } 78cb93a386Sopenharmony_ci } 79cb93a386Sopenharmony_ci 80cb93a386Sopenharmony_ci // Replace constant variables with their corresponding values, so `float2(one, two)` can 81cb93a386Sopenharmony_ci // compile down to `float2(1.0, 2.0)` (the latter is a compile-time constant). 82cb93a386Sopenharmony_ci for (std::unique_ptr<Expression>& arg : args) { 83cb93a386Sopenharmony_ci arg = ConstantFolder::MakeConstantValueForVariable(std::move(arg)); 84cb93a386Sopenharmony_ci } 85cb93a386Sopenharmony_ci 86cb93a386Sopenharmony_ci return std::make_unique<ConstructorCompound>(line, type, std::move(args)); 87cb93a386Sopenharmony_ci} 88cb93a386Sopenharmony_ci 89cb93a386Sopenharmony_ci} // namespace SkSL 90