xref: /aosp_15_r20/external/skia/src/sksl/ir/SkSLConstructorArray.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2021 Google LLC
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "src/sksl/ir/SkSLConstructorArray.h"
9 
10 #include "include/core/SkTypes.h"
11 #include "src/sksl/SkSLContext.h"
12 #include "src/sksl/SkSLErrorReporter.h"
13 #include "src/sksl/SkSLProgramSettings.h"
14 #include "src/sksl/SkSLString.h"
15 #include "src/sksl/ir/SkSLConstructorArrayCast.h"
16 #include "src/sksl/ir/SkSLType.h"
17 
18 #include <algorithm>
19 #include <string>
20 
21 namespace SkSL {
22 
Convert(const Context & context,Position pos,const Type & type,ExpressionArray args)23 std::unique_ptr<Expression> ConstructorArray::Convert(const Context& context,
24                                                       Position pos,
25                                                       const Type& type,
26                                                       ExpressionArray args) {
27     SkASSERTF(type.isArray() && type.columns() > 0, "%s", type.description().c_str());
28 
29     // ES2 doesn't support first-class array types.
30     if (context.fConfig->strictES2Mode()) {
31         context.fErrors->error(pos, "construction of array type '" + type.displayName() +
32                 "' is not supported");
33         return nullptr;
34     }
35 
36     // An array of atomics cannot be constructed.
37     if (type.isOrContainsAtomic()) {
38         context.fErrors->error(
39                 pos,
40                 String::printf("construction of array type '%s' with atomic member is not allowed",
41                                type.displayName().c_str()));
42         return nullptr;
43     }
44 
45     // If there is a single argument containing an array of matching size and the types are
46     // coercible, this is actually a cast. i.e., `half[10](myFloat10Array)`. This isn't a GLSL
47     // feature, but the Pipeline stage code generator needs this functionality so that code which
48     // was originally compiled with "allow narrowing conversions" enabled can be later recompiled
49     // without narrowing conversions (we patch over these conversions with an explicit cast).
50     if (args.size() == 1) {
51         const Expression& expr = *args.front();
52         const Type& exprType = expr.type();
53 
54         if (exprType.isArray() && exprType.canCoerceTo(type, /*allowNarrowing=*/true)) {
55             return ConstructorArrayCast::Make(context, pos, type, std::move(args.front()));
56         }
57     }
58 
59     // Check that the number of constructor arguments matches the array size.
60     if (type.columns() != args.size()) {
61         context.fErrors->error(pos, String::printf("invalid arguments to '%s' constructor "
62                 "(expected %d elements, but found %d)", type.displayName().c_str(), type.columns(),
63                 args.size()));
64         return nullptr;
65     }
66 
67     // Convert each constructor argument to the array's component type.
68     const Type& baseType = type.componentType();
69     for (std::unique_ptr<Expression>& argument : args) {
70         argument = baseType.coerceExpression(std::move(argument), context);
71         if (!argument) {
72             return nullptr;
73         }
74     }
75 
76     return ConstructorArray::Make(context, pos, type, std::move(args));
77 }
78 
Make(const Context & context,Position pos,const Type & type,ExpressionArray args)79 std::unique_ptr<Expression> ConstructorArray::Make(const Context& context,
80                                                    Position pos,
81                                                    const Type& type,
82                                                    ExpressionArray args) {
83     SkASSERT(!context.fConfig->strictES2Mode());
84     SkASSERT(type.isAllowedInES2(context));
85     SkASSERT(type.columns() == args.size());
86     SkASSERT(!type.isOrContainsAtomic());
87     SkASSERT(std::all_of(args.begin(), args.end(), [&](const std::unique_ptr<Expression>& arg) {
88         return type.componentType().matches(arg->type());
89     }));
90 
91     return std::make_unique<ConstructorArray>(pos, type, std::move(args));
92 }
93 
94 }  // namespace SkSL
95