• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "include/sksl/SkSLErrorReporter.h"
9 #include "src/sksl/SkSLProgramSettings.h"
10 #include "src/sksl/ir/SkSLConstructorArray.h"
11 #include "src/sksl/ir/SkSLConstructorArrayCast.h"
12 
13 namespace SkSL {
14 
Convert(const Context & context,int line,const Type & type,ExpressionArray args)15 std::unique_ptr<Expression> ConstructorArray::Convert(const Context& context,
16                                                       int line,
17                                                       const Type& type,
18                                                       ExpressionArray args) {
19     SkASSERTF(type.isArray() && type.columns() > 0, "%s", type.description().c_str());
20 
21     // ES2 doesn't support first-class array types.
22     if (context.fConfig->strictES2Mode()) {
23         context.fErrors->error(line, "construction of array type '" + type.displayName() +
24                                      "' is not supported");
25         return nullptr;
26     }
27 
28     // If there is a single argument containing an array of matching size and the types are
29     // coercible, this is actually a cast. i.e., `half[10](myFloat10Array)`. This isn't a GLSL
30     // feature, but the Pipeline stage code generator needs this functionality so that code which
31     // was originally compiled with "allow narrowing conversions" enabled can be later recompiled
32     // without narrowing conversions (we patch over these conversions with an explicit cast).
33     if (args.size() == 1) {
34         const Expression& expr = *args.front();
35         const Type& exprType = expr.type();
36 
37         if (exprType.isArray() && exprType.canCoerceTo(type, /*allowNarrowing=*/true)) {
38             return ConstructorArrayCast::Make(context, line, type, std::move(args.front()));
39         }
40     }
41 
42     // Check that the number of constructor arguments matches the array size.
43     if (type.columns() != args.count()) {
44         context.fErrors->error(line, String::printf("invalid arguments to '%s' constructor "
45                                                     "(expected %d elements, but found %d)",
46                                                     type.displayName().c_str(), type.columns(),
47                                                     args.count()));
48         return nullptr;
49     }
50 
51     // Convert each constructor argument to the array's component type.
52     const Type& baseType = type.componentType();
53     for (std::unique_ptr<Expression>& argument : args) {
54         argument = baseType.coerceExpression(std::move(argument), context);
55         if (!argument) {
56             return nullptr;
57         }
58     }
59 
60     return ConstructorArray::Make(context, line, type, std::move(args));
61 }
62 
Make(const Context & context,int line,const Type & type,ExpressionArray args)63 std::unique_ptr<Expression> ConstructorArray::Make(const Context& context,
64                                                    int line,
65                                                    const Type& type,
66                                                    ExpressionArray args) {
67     SkASSERT(!context.fConfig->strictES2Mode());
68     SkASSERT(type.isAllowedInES2(context));
69     SkASSERT(type.columns() == args.count());
70     SkASSERT(std::all_of(args.begin(), args.end(), [&](const std::unique_ptr<Expression>& arg) {
71         return type.componentType() == arg->type();
72     }));
73 
74     return std::make_unique<ConstructorArray>(line, type, std::move(args));
75 }
76 
77 }  // namespace SkSL
78