• 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/private/SkSLModifiers.h"
9 
10 #include "include/core/SkTypes.h"
11 #include "include/sksl/SkSLErrorReporter.h"
12 #include "include/sksl/SkSLPosition.h"
13 #include "src/base/SkMathPriv.h"
14 #include "src/sksl/SkSLContext.h"
15 
16 namespace SkSL {
17 
checkPermitted(const Context & context,Position pos,int permittedModifierFlags,int permittedLayoutFlags) const18 bool Modifiers::checkPermitted(const Context& context,
19                                Position pos,
20                                int permittedModifierFlags,
21                                int permittedLayoutFlags) const {
22     static constexpr struct { Modifiers::Flag flag; const char* name; } kModifierFlags[] = {
23         { Modifiers::kConst_Flag,          "const" },
24         { Modifiers::kIn_Flag,             "in" },
25         { Modifiers::kOut_Flag,            "out" },
26         { Modifiers::kUniform_Flag,        "uniform" },
27         { Modifiers::kFlat_Flag,           "flat" },
28         { Modifiers::kNoPerspective_Flag,  "noperspective" },
29         { Modifiers::kPure_Flag,           "$pure" },
30         { Modifiers::kInline_Flag,         "inline" },
31         { Modifiers::kNoInline_Flag,       "noinline" },
32         { Modifiers::kHighp_Flag,          "highp" },
33         { Modifiers::kMediump_Flag,        "mediump" },
34         { Modifiers::kLowp_Flag,           "lowp" },
35         { Modifiers::kExport_Flag,         "$export" },
36         { Modifiers::kES3_Flag,            "$es3" },
37         { Modifiers::kWorkgroup_Flag,      "workgroup" },
38         { Modifiers::kReadOnly_Flag,       "readonly" },
39         { Modifiers::kWriteOnly_Flag,      "writeonly" },
40         { Modifiers::kBuffer_Flag,         "buffer" },
41     };
42 
43     bool success = true;
44     int modifierFlags = fFlags;
45     for (const auto& f : kModifierFlags) {
46         if (modifierFlags & f.flag) {
47             if (!(permittedModifierFlags & f.flag)) {
48                 context.fErrors->error(pos, "'" + std::string(f.name) + "' is not permitted here");
49                 success = false;
50             }
51             modifierFlags &= ~f.flag;
52         }
53     }
54     SkASSERT(modifierFlags == 0);
55 
56     int backendFlags = fLayout.fFlags & Layout::kAllBackendFlagsMask;
57     if (SkPopCount(backendFlags) > 1) {
58         context.fErrors->error(pos, "only one backend qualifier can be used");
59         success = false;
60     }
61 
62     static constexpr struct { Layout::Flag flag; const char* name; } kLayoutFlags[] = {
63         { Layout::kOriginUpperLeft_Flag,          "origin_upper_left"},
64         { Layout::kPushConstant_Flag,             "push_constant"},
65         { Layout::kBlendSupportAllEquations_Flag, "blend_support_all_equations"},
66         { Layout::kColor_Flag,                    "color"},
67         { Layout::kLocation_Flag,                 "location"},
68         { Layout::kOffset_Flag,                   "offset"},
69         { Layout::kBinding_Flag,                  "binding"},
70         { Layout::kTexture_Flag,                  "texture"},
71         { Layout::kSampler_Flag,                  "sampler"},
72         { Layout::kIndex_Flag,                    "index"},
73         { Layout::kSet_Flag,                      "set"},
74         { Layout::kBuiltin_Flag,                  "builtin"},
75         { Layout::kInputAttachmentIndex_Flag,     "input_attachment_index"},
76         { Layout::kSPIRV_Flag,                    "spirv"},
77         { Layout::kMetal_Flag,                    "metal"},
78         { Layout::kGL_Flag,                       "gl"},
79         { Layout::kWGSL_Flag,                     "wgsl"},
80     };
81 
82     int layoutFlags = fLayout.fFlags;
83     if ((layoutFlags & (Layout::kTexture_Flag | Layout::kSampler_Flag)) &&
84         layoutFlags & Layout::kBinding_Flag) {
85         context.fErrors->error(pos, "'binding' modifier cannot coexist with 'texture'/'sampler'");
86         success = false;
87     }
88     // The `texture` and `sampler` flags are only allowed when explicitly targeting Metal and WGSL
89     if (!(layoutFlags & (Layout::kMetal_Flag | Layout::kWGSL_Flag))) {
90         permittedLayoutFlags &= ~Layout::kTexture_Flag;
91         permittedLayoutFlags &= ~Layout::kSampler_Flag;
92     }
93     // The `set` flag is not allowed when explicitly targeting Metal and GLSL. It is currently
94     // allowed when no backend flag is present.
95     // TODO(skia:14023): Further restrict the `set` flag to SPIR-V and WGSL
96     if (layoutFlags & (Layout::kMetal_Flag | Layout::kGL_Flag)) {
97         permittedLayoutFlags &= ~Layout::kSet_Flag;
98     }
99     // TODO(skia:14023): Restrict the `push_constant` flag to SPIR-V and WGSL
100 
101     for (const auto& lf : kLayoutFlags) {
102         if (layoutFlags & lf.flag) {
103             if (!(permittedLayoutFlags & lf.flag)) {
104                 context.fErrors->error(pos, "layout qualifier '" + std::string(lf.name) +
105                                             "' is not permitted here");
106                 success = false;
107             }
108             layoutFlags &= ~lf.flag;
109         }
110     }
111     SkASSERT(layoutFlags == 0);
112     return success;
113 }
114 
115 } // namespace SkSL
116