blob: 801e3c526b2ebf4a256dfc848306516fb50735ce [file] [log] [blame]
Ethan Nicholas371f6e12021-05-04 14:30:02 -04001/*
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 "src/sksl/ir/SkSLFunctionDeclaration.h"
9
10#include "src/sksl/SkSLCompiler.h"
11#include "src/sksl/SkSLIRGenerator.h"
12#include "src/sksl/ir/SkSLUnresolvedFunction.h"
13
14namespace SkSL {
15
16static bool check_modifiers(const Context& context, int offset, const Modifiers& modifiers) {
17 IRGenerator::CheckModifiers(
18 context,
19 offset,
20 modifiers,
21 Modifiers::kHasSideEffects_Flag | Modifiers::kInline_Flag | Modifiers::kNoInline_Flag,
22 /*permittedLayoutFlags=*/0);
23 if ((modifiers.fFlags & Modifiers::kInline_Flag) &&
24 (modifiers.fFlags & Modifiers::kNoInline_Flag)) {
25 context.fErrors.error(offset, "functions cannot be both 'inline' and 'noinline'");
26 return false;
27 }
28 return true;
29}
30
31static bool check_return_type(const Context& context, int offset, const Type& returnType,
32 bool isBuiltin) {
33 ErrorReporter& errors = context.fErrors;
34 if (returnType.isArray()) {
35 errors.error(offset, "functions may not return type '" + returnType.displayName() + "'");
36 return false;
37 }
38 if (context.fConfig->strictES2Mode() && returnType.isOrContainsArray()) {
39 errors.error(offset, "functions may not return structs containing arrays");
40 return false;
41 }
42 if (!isBuiltin && !returnType.isVoid() && returnType.componentType().isOpaque()) {
43 errors.error(offset, "functions may not return opaque type '" + returnType.displayName() +
44 "'");
45 return false;
46 }
47 return true;
48}
49
John Stiles0b822792021-05-04 17:41:53 -040050static bool check_parameters(const Context& context,
Ethan Nicholas371f6e12021-05-04 14:30:02 -040051 std::vector<std::unique_ptr<Variable>>& parameters, bool isMain,
52 bool isBuiltin) {
53 auto typeIsValidForColor = [&](const Type& type) {
54 return type == *context.fTypes.fHalf4 || type == *context.fTypes.fFloat4;
55 };
56
57 // Check modifiers on each function parameter.
58 for (auto& param : parameters) {
59 IRGenerator::CheckModifiers(context, param->fOffset, param->modifiers(),
60 Modifiers::kConst_Flag | Modifiers::kIn_Flag |
61 Modifiers::kOut_Flag, /*permittedLayoutFlags=*/0);
62 const Type& type = param->type();
63 // Only the (builtin) declarations of 'sample' are allowed to have shader/colorFilter or FP
64 // parameters. You can pass other opaque types to functions safely; this restriction is
65 // specific to "child" objects.
66 if ((type.isEffectChild() || type.isFragmentProcessor()) && !isBuiltin) {
67 context.fErrors.error(param->fOffset, "parameters of type '" + type.displayName() +
68 "' not allowed");
69 return false;
70 }
71
72 Modifiers m = param->modifiers();
73 ProgramKind kind = context.fConfig->fKind;
74 if (isMain && (kind == ProgramKind::kRuntimeColorFilter ||
75 kind == ProgramKind::kRuntimeShader ||
76 kind == ProgramKind::kFragmentProcessor)) {
77 // We verify that the signature is fully correct later. For now, if this is an .fp or
78 // runtime effect of any flavor, a float2 param is supposed to be the coords, and
79 // a half4/float parameter is supposed to be the input color:
80 if (type == *context.fTypes.fFloat2) {
81 m.fLayout.fBuiltin = SK_MAIN_COORDS_BUILTIN;
82 } else if(typeIsValidForColor(type)) {
83 m.fLayout.fBuiltin = SK_INPUT_COLOR_BUILTIN;
84 }
85 if (m.fLayout.fBuiltin) {
John Stiles0b822792021-05-04 17:41:53 -040086 param->setModifiers(context.fModifiersPool->add(m));
Ethan Nicholas371f6e12021-05-04 14:30:02 -040087 }
88 }
89 if (isMain && (kind == ProgramKind::kFragment)) {
90 // For testing purposes, we have .sksl inputs that are treated as both runtime effects
91 // and fragment shaders. To make that work, fragment shaders are allowed to have a
92 // coords parameter. We turn it into sk_FragCoord.
93 if (type == *context.fTypes.fFloat2) {
94 m.fLayout.fBuiltin = SK_FRAGCOORD_BUILTIN;
John Stiles0b822792021-05-04 17:41:53 -040095 param->setModifiers(context.fModifiersPool->add(m));
Ethan Nicholas371f6e12021-05-04 14:30:02 -040096 }
97 }
98 }
99 return true;
100}
101
102static bool check_main_signature(const Context& context, int offset, const Type& returnType,
103 std::vector<std::unique_ptr<Variable>>& parameters,
104 bool isBuiltin) {
105 ErrorReporter& errors = context.fErrors;
106 ProgramKind kind = context.fConfig->fKind;
107
108 auto typeIsValidForColor = [&](const Type& type) {
109 return type == *context.fTypes.fHalf4 || type == *context.fTypes.fFloat4;
110 };
111
112 auto paramIsCoords = [&](int idx) {
113 const Variable& p = *parameters[idx];
114 return p.type() == *context.fTypes.fFloat2 &&
115 p.modifiers().fFlags == 0 &&
116 p.modifiers().fLayout.fBuiltin == (kind == ProgramKind::kFragment
117 ? SK_FRAGCOORD_BUILTIN
118 : SK_MAIN_COORDS_BUILTIN);
119 };
120
121 auto paramIsInputColor = [&](int idx) {
122 return typeIsValidForColor(parameters[idx]->type()) &&
123 parameters[idx]->modifiers().fFlags == 0 &&
124 parameters[idx]->modifiers().fLayout.fBuiltin == SK_INPUT_COLOR_BUILTIN;
125 };
126
127 switch (kind) {
128 case ProgramKind::kRuntimeColorFilter: {
129 // (half4|float4) main(half4|float4)
130 if (!typeIsValidForColor(returnType)) {
131 errors.error(offset, "'main' must return: 'vec4', 'float4', or 'half4'");
132 return false;
133 }
134 bool validParams = (parameters.size() == 1 && paramIsInputColor(0));
135 if (!validParams) {
136 errors.error(offset, "'main' parameter must be 'vec4', 'float4', or 'half4'");
137 return false;
138 }
139 break;
140 }
141 case ProgramKind::kRuntimeShader: {
142 // (half4|float4) main(float2) -or- (half4|float4) main(float2, half4|float4)
143 if (!typeIsValidForColor(returnType)) {
144 errors.error(offset, "'main' must return: 'vec4', 'float4', or 'half4'");
145 return false;
146 }
147 bool validParams =
148 (parameters.size() == 1 && paramIsCoords(0)) ||
149 (parameters.size() == 2 && paramIsCoords(0) && paramIsInputColor(1));
150 if (!validParams) {
151 errors.error(offset, "'main' parameters must be (float2, (vec4|float4|half4)?)");
152 return false;
153 }
154 break;
155 }
156 case ProgramKind::kFragmentProcessor: {
157 if (returnType != *context.fTypes.fHalf4) {
158 errors.error(offset, ".fp 'main' must return 'half4'");
159 return false;
160 }
161 bool validParams = (parameters.size() == 0) ||
162 (parameters.size() == 1 && paramIsCoords(0));
163 if (!validParams) {
164 errors.error(offset, ".fp 'main' must be declared main() or main(float2)");
165 return false;
166 }
167 break;
168 }
169 case ProgramKind::kGeneric:
170 // No rules apply here
171 break;
172 case ProgramKind::kFragment: {
173 bool validParams = (parameters.size() == 0) ||
174 (parameters.size() == 1 && paramIsCoords(0));
175 if (!validParams) {
176 errors.error(offset, "shader 'main' must be main() or main(float2)");
177 return false;
178 }
179 break;
180 }
181 case ProgramKind::kVertex:
182 case ProgramKind::kGeometry:
183 if (parameters.size()) {
184 errors.error(offset, "shader 'main' must have zero parameters");
185 return false;
186 }
187 break;
188 }
189 return true;
190}
191
192/**
193 * Checks for a previously existing declaration of this function, reporting errors if there is an
194 * incompatible symbol. Returns true and sets outExistingDecl to point to the existing declaration
195 * (or null if none) on success, returns false on error.
196 */
197static bool find_existing_declaration(const Context& context, SymbolTable& symbols, int offset,
198 StringFragment name,
199 std::vector<std::unique_ptr<Variable>>& parameters,
200 const Type* returnType, bool isBuiltin,
201 const FunctionDeclaration** outExistingDecl) {
202 ErrorReporter& errors = context.fErrors;
203 const Symbol* entry = symbols[name];
204 *outExistingDecl = nullptr;
205 if (entry) {
206 std::vector<const FunctionDeclaration*> functions;
207 switch (entry->kind()) {
208 case Symbol::Kind::kUnresolvedFunction:
209 functions = entry->as<UnresolvedFunction>().functions();
210 break;
211 case Symbol::Kind::kFunctionDeclaration:
212 functions.push_back(&entry->as<FunctionDeclaration>());
213 break;
214 default:
215 errors.error(offset, "symbol '" + name + "' was already defined");
216 return false;
217 }
218 for (const FunctionDeclaration* other : functions) {
219 SkASSERT(name == other->name());
220 if (parameters.size() != other->parameters().size()) {
221 continue;
222 }
223 bool match = true;
224 for (size_t i = 0; i < parameters.size(); i++) {
225 if (parameters[i]->type() != other->parameters()[i]->type()) {
226 match = false;
227 break;
228 }
229 }
230 if (!match) {
231 continue;
232 }
233 if (*returnType != other->returnType()) {
234 std::vector<const Variable*> paramPtrs;
235 paramPtrs.reserve(parameters.size());
236 for (std::unique_ptr<Variable>& param : parameters) {
237 paramPtrs.push_back(param.get());
238 }
239 FunctionDeclaration invalidDecl(offset,
240 &other->modifiers(),
241 name,
242 std::move(paramPtrs),
243 returnType,
244 isBuiltin);
245 errors.error(offset,
246 "functions '" + invalidDecl.description() + "' and '" +
247 other->description() + "' differ only in return type");
248 return false;
249 }
250 for (size_t i = 0; i < parameters.size(); i++) {
251 if (parameters[i]->modifiers() != other->parameters()[i]->modifiers()) {
252 errors.error(offset,
253 "modifiers on parameter " + to_string((uint64_t)i + 1) +
254 " differ between declaration and definition");
255 return false;
256 }
257 }
258 if (other->definition() && !other->isBuiltin()) {
259 errors.error(offset, "duplicate definition of " + other->description());
260 return false;
261 }
262 *outExistingDecl = other;
263 break;
264 }
265 }
266 return true;
267}
268
269const FunctionDeclaration* FunctionDeclaration::Convert(const Context& context,
John Stiles0b822792021-05-04 17:41:53 -0400270 SymbolTable& symbols, int offset, const Modifiers* modifiers,
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400271 StringFragment name, std::vector<std::unique_ptr<Variable>> parameters,
272 const Type* returnType, bool isBuiltin) {
273 bool isMain = (name == "main");
274
275 const FunctionDeclaration* decl = nullptr;
276 if (!check_modifiers(context, offset, *modifiers) ||
277 !check_return_type(context, offset, *returnType, isBuiltin) ||
John Stiles0b822792021-05-04 17:41:53 -0400278 !check_parameters(context, parameters, isMain, isBuiltin) ||
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400279 (isMain && !check_main_signature(context, offset, *returnType, parameters, isBuiltin)) ||
280 !find_existing_declaration(context, symbols, offset, name, parameters, returnType,
281 isBuiltin, &decl)) {
282 return nullptr;
283 }
284 std::vector<const Variable*> finalParameters;
285 finalParameters.reserve(parameters.size());
286 for (auto& param : parameters) {
287 finalParameters.push_back(symbols.takeOwnershipOfSymbol(std::move(param)));
288 }
289 if (decl) {
290 return decl;
291 }
292 auto result = std::make_unique<FunctionDeclaration>(offset, modifiers, name,
293 std::move(finalParameters), returnType,
294 isBuiltin);
295 return symbols.add(std::move(result));
296}
297
298} // namespace SkSL