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