| /* |
| * Copyright 2021 Google LLC. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "include/private/SkSLModifiers.h" |
| |
| #include "include/core/SkTypes.h" |
| #include "include/sksl/SkSLErrorReporter.h" |
| #include "include/sksl/SkSLPosition.h" |
| #include "src/base/SkMathPriv.h" |
| #include "src/sksl/SkSLContext.h" |
| |
| namespace SkSL { |
| |
| bool Modifiers::checkPermitted(const Context& context, |
| Position pos, |
| int permittedModifierFlags, |
| int permittedLayoutFlags) const { |
| static constexpr struct { Modifiers::Flag flag; const char* name; } kModifierFlags[] = { |
| { Modifiers::kConst_Flag, "const" }, |
| { Modifiers::kIn_Flag, "in" }, |
| { Modifiers::kOut_Flag, "out" }, |
| { Modifiers::kUniform_Flag, "uniform" }, |
| { Modifiers::kFlat_Flag, "flat" }, |
| { Modifiers::kNoPerspective_Flag, "noperspective" }, |
| { Modifiers::kPure_Flag, "$pure" }, |
| { Modifiers::kInline_Flag, "inline" }, |
| { Modifiers::kNoInline_Flag, "noinline" }, |
| { Modifiers::kHighp_Flag, "highp" }, |
| { Modifiers::kMediump_Flag, "mediump" }, |
| { Modifiers::kLowp_Flag, "lowp" }, |
| { Modifiers::kExport_Flag, "$export" }, |
| { Modifiers::kES3_Flag, "$es3" }, |
| { Modifiers::kWorkgroup_Flag, "workgroup" }, |
| { Modifiers::kReadOnly_Flag, "readonly" }, |
| { Modifiers::kWriteOnly_Flag, "writeonly" }, |
| { Modifiers::kBuffer_Flag, "buffer" }, |
| }; |
| |
| bool success = true; |
| int modifierFlags = fFlags; |
| for (const auto& f : kModifierFlags) { |
| if (modifierFlags & f.flag) { |
| if (!(permittedModifierFlags & f.flag)) { |
| context.fErrors->error(pos, "'" + std::string(f.name) + "' is not permitted here"); |
| success = false; |
| } |
| modifierFlags &= ~f.flag; |
| } |
| } |
| SkASSERT(modifierFlags == 0); |
| |
| int backendFlags = fLayout.fFlags & Layout::kAllBackendFlagsMask; |
| if (SkPopCount(backendFlags) > 1) { |
| context.fErrors->error(pos, "only one backend qualifier can be used"); |
| success = false; |
| } |
| |
| static constexpr struct { Layout::Flag flag; const char* name; } kLayoutFlags[] = { |
| { Layout::kOriginUpperLeft_Flag, "origin_upper_left"}, |
| { Layout::kPushConstant_Flag, "push_constant"}, |
| { Layout::kBlendSupportAllEquations_Flag, "blend_support_all_equations"}, |
| { Layout::kColor_Flag, "color"}, |
| { Layout::kLocation_Flag, "location"}, |
| { Layout::kOffset_Flag, "offset"}, |
| { Layout::kBinding_Flag, "binding"}, |
| { Layout::kTexture_Flag, "texture"}, |
| { Layout::kSampler_Flag, "sampler"}, |
| { Layout::kIndex_Flag, "index"}, |
| { Layout::kSet_Flag, "set"}, |
| { Layout::kBuiltin_Flag, "builtin"}, |
| { Layout::kInputAttachmentIndex_Flag, "input_attachment_index"}, |
| { Layout::kSPIRV_Flag, "spirv"}, |
| { Layout::kMetal_Flag, "metal"}, |
| { Layout::kGL_Flag, "gl"}, |
| { Layout::kWGSL_Flag, "wgsl"}, |
| }; |
| |
| int layoutFlags = fLayout.fFlags; |
| if ((layoutFlags & (Layout::kTexture_Flag | Layout::kSampler_Flag)) && |
| layoutFlags & Layout::kBinding_Flag) { |
| context.fErrors->error(pos, "'binding' modifier cannot coexist with 'texture'/'sampler'"); |
| success = false; |
| } |
| // The `texture` and `sampler` flags are only allowed when explicitly targeting Metal and WGSL |
| if (!(layoutFlags & (Layout::kMetal_Flag | Layout::kWGSL_Flag))) { |
| permittedLayoutFlags &= ~Layout::kTexture_Flag; |
| permittedLayoutFlags &= ~Layout::kSampler_Flag; |
| } |
| // The `set` flag is not allowed when explicitly targeting Metal and GLSL. It is currently |
| // allowed when no backend flag is present. |
| // TODO(skia:14023): Further restrict the `set` flag to SPIR-V and WGSL |
| if (layoutFlags & (Layout::kMetal_Flag | Layout::kGL_Flag)) { |
| permittedLayoutFlags &= ~Layout::kSet_Flag; |
| } |
| // TODO(skia:14023): Restrict the `push_constant` flag to SPIR-V and WGSL |
| |
| for (const auto& lf : kLayoutFlags) { |
| if (layoutFlags & lf.flag) { |
| if (!(permittedLayoutFlags & lf.flag)) { |
| context.fErrors->error(pos, "layout qualifier '" + std::string(lf.name) + |
| "' is not permitted here"); |
| success = false; |
| } |
| layoutFlags &= ~lf.flag; |
| } |
| } |
| SkASSERT(layoutFlags == 0); |
| return success; |
| } |
| |
| } // namespace SkSL |