blob: 548d38d2cd3a16b21ccd5545f9d07b0c9bc0e911 [file] [log] [blame]
/*
* 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