1 /*
2 * Copyright 2017 Google Inc.
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 "src/sksl/ir/SkSLSetting.h"
9
10 #include "include/sksl/SkSLErrorReporter.h"
11 #include "src/sksl/SkSLProgramSettings.h"
12 #include "src/sksl/ir/SkSLLiteral.h"
13 #include "src/sksl/ir/SkSLVariableReference.h"
14
15 namespace SkSL {
16
17 // Helper classes for converting caps fields to Expressions and Types in the CapsLookupTable.
18 namespace {
19
20 class CapsLookupMethod {
21 public:
~CapsLookupMethod()22 virtual ~CapsLookupMethod() {}
23 virtual const Type* type(const Context& context) const = 0;
24 virtual std::unique_ptr<Expression> value(const Context& context) const = 0;
25 };
26
27 class BoolCapsLookup : public CapsLookupMethod {
28 public:
29 using CapsFn = bool (ShaderCapsClass::*)() const;
30
BoolCapsLookup(const CapsFn & fn)31 BoolCapsLookup(const CapsFn& fn) : fGetCap(fn) {}
32
type(const Context & context) const33 const Type* type(const Context& context) const override {
34 return context.fTypes.fBool.get();
35 }
value(const Context & context) const36 std::unique_ptr<Expression> value(const Context& context) const override {
37 return Literal::MakeBool(context, /*line=*/-1, (context.fCaps.*fGetCap)());
38 }
39
40 private:
41 CapsFn fGetCap;
42 };
43
44 class IntCapsLookup : public CapsLookupMethod {
45 public:
46 using CapsFn = int (ShaderCapsClass::*)() const;
47
IntCapsLookup(const CapsFn & fn)48 IntCapsLookup(const CapsFn& fn) : fGetCap(fn) {}
49
type(const Context & context) const50 const Type* type(const Context& context) const override {
51 return context.fTypes.fInt.get();
52 }
value(const Context & context) const53 std::unique_ptr<Expression> value(const Context& context) const override {
54 return Literal::MakeInt(context, /*line=*/-1, (context.fCaps.*fGetCap)());
55 }
56
57 private:
58 CapsFn fGetCap;
59 };
60
61 class CapsLookupTable {
62 public:
63 using Pair = std::pair<const char*, CapsLookupMethod*>;
64
CapsLookupTable(std::initializer_list<Pair> capsLookups)65 CapsLookupTable(std::initializer_list<Pair> capsLookups) {
66 for (auto& entry : capsLookups) {
67 fMap[entry.first] = std::unique_ptr<CapsLookupMethod>(entry.second);
68 }
69 }
70
lookup(skstd::string_view name) const71 const CapsLookupMethod* lookup(skstd::string_view name) const {
72 auto iter = fMap.find(name);
73 return (iter != fMap.end()) ? iter->second.get() : nullptr;
74 }
75
76 private:
77 std::unordered_map<skstd::string_view, std::unique_ptr<CapsLookupMethod>> fMap;
78 };
79
caps_lookup_table()80 static const CapsLookupTable& caps_lookup_table() {
81 // Create a lookup table that converts strings into the equivalent ShaderCapsClass methods.
82 static CapsLookupTable* sCapsLookupTable = new CapsLookupTable({
83 #define CAP(T, name) CapsLookupTable::Pair{#name, new T##CapsLookup{&ShaderCapsClass::name}}
84 CAP(Bool, fbFetchSupport),
85 CAP(Bool, fbFetchNeedsCustomOutput),
86 CAP(Bool, flatInterpolationSupport),
87 CAP(Bool, noperspectiveInterpolationSupport),
88 CAP(Bool, externalTextureSupport),
89 CAP(Bool, mustEnableAdvBlendEqs),
90 CAP(Bool, mustDeclareFragmentShaderOutput),
91 CAP(Bool, mustDoOpBetweenFloorAndAbs),
92 CAP(Bool, mustGuardDivisionEvenAfterExplicitZeroCheck),
93 CAP(Bool, atan2ImplementedAsAtanYOverX),
94 CAP(Bool, canUseAnyFunctionInShader),
95 CAP(Bool, floatIs32Bits),
96 CAP(Bool, integerSupport),
97 CAP(Bool, builtinFMASupport),
98 CAP(Bool, builtinDeterminantSupport),
99 CAP(Bool, rewriteMatrixVectorMultiply),
100 #undef CAP
101 });
102 return *sCapsLookupTable;
103 }
104
105 } // namespace
106
get_type(const Context & context,int line,skstd::string_view name)107 static const Type* get_type(const Context& context, int line, skstd::string_view name) {
108 if (const CapsLookupMethod* caps = caps_lookup_table().lookup(name)) {
109 return caps->type(context);
110 }
111
112 context.fErrors->error(line, "unknown capability flag '" + name + "'");
113 return nullptr;
114 }
115
get_value(const Context & context,int line,const skstd::string_view & name)116 static std::unique_ptr<Expression> get_value(const Context& context, int line,
117 const skstd::string_view& name) {
118 if (const CapsLookupMethod* caps = caps_lookup_table().lookup(name)) {
119 return caps->value(context);
120 }
121
122 context.fErrors->error(line, "unknown capability flag '" + name + "'");
123 return nullptr;
124 }
125
Convert(const Context & context,int line,const skstd::string_view & name)126 std::unique_ptr<Expression> Setting::Convert(const Context& context, int line,
127 const skstd::string_view& name) {
128 SkASSERT(context.fConfig);
129
130 if (context.fConfig->fSettings.fReplaceSettings) {
131 // Insert the settings value directly into the IR.
132 return get_value(context, line, name);
133 }
134
135 // Generate a Setting IRNode.
136 const Type* type = get_type(context, line, name);
137 return type ? std::make_unique<Setting>(line, name, type) : nullptr;
138 }
139
140 } // namespace SkSL
141