1 | /* |
2 | * Copyright 2016 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/SkSLHCodeGenerator.h" |
9 | |
10 | #include "src/sksl/SkSLParser.h" |
11 | #include "src/sksl/SkSLUtil.h" |
12 | #include "src/sksl/ir/SkSLEnum.h" |
13 | #include "src/sksl/ir/SkSLFunctionDeclaration.h" |
14 | #include "src/sksl/ir/SkSLFunctionDefinition.h" |
15 | #include "src/sksl/ir/SkSLSection.h" |
16 | #include "src/sksl/ir/SkSLVarDeclarations.h" |
17 | |
18 | #include <set> |
19 | |
20 | namespace SkSL { |
21 | |
22 | HCodeGenerator::HCodeGenerator(const Context* context, const Program* program, |
23 | ErrorReporter* errors, String name, OutputStream* out) |
24 | : INHERITED(program, errors, out) |
25 | , fContext(*context) |
26 | , fName(std::move(name)) |
27 | , fFullName(String::printf("Gr%s" , fName.c_str())) |
28 | , fSectionAndParameterHelper(program, *errors) {} |
29 | |
30 | String HCodeGenerator::ParameterType(const Context& context, const Type& type, |
31 | const Layout& layout) { |
32 | Layout::CType ctype = ParameterCType(context, type, layout); |
33 | if (ctype != Layout::CType::kDefault) { |
34 | return Layout::CTypeToStr(ctype); |
35 | } |
36 | return type.name(); |
37 | } |
38 | |
39 | Layout::CType HCodeGenerator::ParameterCType(const Context& context, const Type& type, |
40 | const Layout& layout) { |
41 | if (layout.fCType != Layout::CType::kDefault) { |
42 | return layout.fCType; |
43 | } |
44 | if (type.kind() == Type::kNullable_Kind) { |
45 | return ParameterCType(context, type.componentType(), layout); |
46 | } else if (type == *context.fFloat_Type || type == *context.fHalf_Type) { |
47 | return Layout::CType::kFloat; |
48 | } else if (type == *context.fInt_Type || |
49 | type == *context.fShort_Type || |
50 | type == *context.fByte_Type) { |
51 | return Layout::CType::kInt32; |
52 | } else if (type == *context.fFloat2_Type || type == *context.fHalf2_Type) { |
53 | return Layout::CType::kSkPoint; |
54 | } else if (type == *context.fInt2_Type || |
55 | type == *context.fShort2_Type || |
56 | type == *context.fByte2_Type) { |
57 | return Layout::CType::kSkIPoint; |
58 | } else if (type == *context.fInt4_Type || |
59 | type == *context.fShort4_Type || |
60 | type == *context.fByte4_Type) { |
61 | return Layout::CType::kSkIRect; |
62 | } else if (type == *context.fFloat4_Type || type == *context.fHalf4_Type) { |
63 | return Layout::CType::kSkRect; |
64 | } else if (type == *context.fFloat3x3_Type || type == *context.fHalf3x3_Type) { |
65 | return Layout::CType::kSkMatrix; |
66 | } else if (type == *context.fFloat4x4_Type || type == *context.fHalf4x4_Type) { |
67 | return Layout::CType::kSkM44; |
68 | } else if (type.kind() == Type::kSampler_Kind) { |
69 | return Layout::CType::kGrSurfaceProxyView; |
70 | } else if (type == *context.fFragmentProcessor_Type) { |
71 | return Layout::CType::kGrFragmentProcessor; |
72 | } |
73 | return Layout::CType::kDefault; |
74 | } |
75 | |
76 | String HCodeGenerator::FieldType(const Context& context, const Type& type, |
77 | const Layout& layout) { |
78 | if (type.kind() == Type::kSampler_Kind) { |
79 | return "TextureSampler" ; |
80 | } else if (type == *context.fFragmentProcessor_Type) { |
81 | // we don't store fragment processors in fields, they get registered via |
82 | // registerChildProcessor instead |
83 | SkASSERT(false); |
84 | return "<error>" ; |
85 | } |
86 | return ParameterType(context, type, layout); |
87 | } |
88 | |
89 | String HCodeGenerator::AccessType(const Context& context, const Type& type, |
90 | const Layout& layout) { |
91 | static const std::set<String> primitiveTypes = { "int32_t" , "float" , "bool" , "SkPMColor" }; |
92 | |
93 | String fieldType = FieldType(context, type, layout); |
94 | bool isPrimitive = primitiveTypes.find(fieldType) != primitiveTypes.end(); |
95 | if (isPrimitive) { |
96 | return fieldType; |
97 | } else { |
98 | return String::printf("const %s&" , fieldType.c_str()); |
99 | } |
100 | } |
101 | |
102 | void HCodeGenerator::writef(const char* s, va_list va) { |
103 | static constexpr int BUFFER_SIZE = 1024; |
104 | va_list copy; |
105 | va_copy(copy, va); |
106 | char buffer[BUFFER_SIZE]; |
107 | int length = vsnprintf(buffer, BUFFER_SIZE, s, va); |
108 | if (length < BUFFER_SIZE) { |
109 | fOut->write(buffer, length); |
110 | } else { |
111 | std::unique_ptr<char[]> heap(new char[length + 1]); |
112 | vsprintf(heap.get(), s, copy); |
113 | fOut->write(heap.get(), length); |
114 | } |
115 | va_end(copy); |
116 | } |
117 | |
118 | void HCodeGenerator::writef(const char* s, ...) { |
119 | va_list va; |
120 | va_start(va, s); |
121 | this->writef(s, va); |
122 | va_end(va); |
123 | } |
124 | |
125 | bool HCodeGenerator::writeSection(const char* name, const char* prefix) { |
126 | const Section* s = fSectionAndParameterHelper.getSection(name); |
127 | if (s) { |
128 | this->writef("%s%s" , prefix, s->fText.c_str()); |
129 | return true; |
130 | } |
131 | return false; |
132 | } |
133 | |
134 | void HCodeGenerator::(const char* separator) { |
135 | // super-simple parse, just assume the last token before a comma is the name of a parameter |
136 | // (which is true as long as there are no multi-parameter template types involved). Will replace |
137 | // this with something more robust if the need arises. |
138 | const Section* section = fSectionAndParameterHelper.getSection(CONSTRUCTOR_PARAMS_SECTION); |
139 | if (section) { |
140 | const char* s = section->fText.c_str(); |
141 | #define BUFFER_SIZE 64 |
142 | char lastIdentifier[BUFFER_SIZE]; |
143 | int lastIdentifierLength = 0; |
144 | bool foundBreak = false; |
145 | while (*s) { |
146 | char c = *s; |
147 | ++s; |
148 | if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || |
149 | c == '_') { |
150 | if (foundBreak) { |
151 | lastIdentifierLength = 0; |
152 | foundBreak = false; |
153 | } |
154 | SkASSERT(lastIdentifierLength < BUFFER_SIZE); |
155 | lastIdentifier[lastIdentifierLength] = c; |
156 | ++lastIdentifierLength; |
157 | } else { |
158 | foundBreak = true; |
159 | if (c == ',') { |
160 | SkASSERT(lastIdentifierLength < BUFFER_SIZE); |
161 | lastIdentifier[lastIdentifierLength] = 0; |
162 | this->writef("%s%s" , separator, lastIdentifier); |
163 | separator = ", " ; |
164 | } else if (c != ' ' && c != '\t' && c != '\n' && c != '\r') { |
165 | lastIdentifierLength = 0; |
166 | } |
167 | } |
168 | } |
169 | if (lastIdentifierLength) { |
170 | SkASSERT(lastIdentifierLength < BUFFER_SIZE); |
171 | lastIdentifier[lastIdentifierLength] = 0; |
172 | this->writef("%s%s" , separator, lastIdentifier); |
173 | } |
174 | } |
175 | } |
176 | |
177 | void HCodeGenerator::writeMake() { |
178 | const char* separator; |
179 | if (!this->writeSection(MAKE_SECTION)) { |
180 | this->writef(" static std::unique_ptr<GrFragmentProcessor> Make(" ); |
181 | separator = "" ; |
182 | for (const auto& param : fSectionAndParameterHelper.getParameters()) { |
183 | this->writef("%s%s %s" , separator, ParameterType(fContext, param->fType, |
184 | param->fModifiers.fLayout).c_str(), |
185 | String(param->fName).c_str()); |
186 | separator = ", " ; |
187 | } |
188 | this->writeSection(CONSTRUCTOR_PARAMS_SECTION, separator); |
189 | this->writef(") {\n" |
190 | " return std::unique_ptr<GrFragmentProcessor>(new %s(" , |
191 | fFullName.c_str()); |
192 | separator = "" ; |
193 | for (const auto& param : fSectionAndParameterHelper.getParameters()) { |
194 | if (param->fType.nonnullable() == *fContext.fFragmentProcessor_Type || |
195 | param->fType.nonnullable().kind() == Type::kSampler_Kind) { |
196 | this->writef("%sstd::move(%s)" , separator, String(param->fName).c_str()); |
197 | } else { |
198 | this->writef("%s%s" , separator, String(param->fName).c_str()); |
199 | } |
200 | separator = ", " ; |
201 | } |
202 | this->writeExtraConstructorParams(separator); |
203 | this->writef("));\n" |
204 | " }\n" ); |
205 | } |
206 | } |
207 | |
208 | void HCodeGenerator::failOnSection(const char* section, const char* msg) { |
209 | std::vector<const Section*> s = fSectionAndParameterHelper.getSections(section); |
210 | if (s.size()) { |
211 | fErrors.error(s[0]->fOffset, String("@" ) + section + " " + msg); |
212 | } |
213 | } |
214 | |
215 | void HCodeGenerator::writeConstructor() { |
216 | if (this->writeSection(CONSTRUCTOR_SECTION)) { |
217 | const char* msg = "may not be present when constructor is overridden" ; |
218 | this->failOnSection(CONSTRUCTOR_CODE_SECTION, msg); |
219 | this->failOnSection(CONSTRUCTOR_PARAMS_SECTION, msg); |
220 | this->failOnSection(INITIALIZERS_SECTION, msg); |
221 | this->failOnSection(OPTIMIZATION_FLAGS_SECTION, msg); |
222 | return; |
223 | } |
224 | this->writef(" %s(" , fFullName.c_str()); |
225 | const char* separator = "" ; |
226 | for (const auto& param : fSectionAndParameterHelper.getParameters()) { |
227 | this->writef("%s%s %s" , separator, ParameterType(fContext, param->fType, |
228 | param->fModifiers.fLayout).c_str(), |
229 | String(param->fName).c_str()); |
230 | separator = ", " ; |
231 | } |
232 | this->writeSection(CONSTRUCTOR_PARAMS_SECTION, separator); |
233 | this->writef(")\n" |
234 | " : INHERITED(k%s_ClassID" , fFullName.c_str()); |
235 | if (!this->writeSection(OPTIMIZATION_FLAGS_SECTION, ", (OptimizationFlags) " )) { |
236 | this->writef(", kNone_OptimizationFlags" ); |
237 | } |
238 | this->writef(")" ); |
239 | this->writeSection(INITIALIZERS_SECTION, "\n , " ); |
240 | const auto transforms = fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION); |
241 | for (size_t i = 0; i < transforms.size(); ++i) { |
242 | const Section& s = *transforms[i]; |
243 | String field = CoordTransformName(s.fArgument.c_str(), i); |
244 | if (s.fArgument.size()) { |
245 | this->writef("\n , %s(%s, %s.proxy(), %s.origin())" , field.c_str(), s.fText.c_str(), |
246 | FieldName(s.fArgument.c_str()).c_str(), |
247 | FieldName(s.fArgument.c_str()).c_str()); |
248 | } |
249 | else { |
250 | this->writef("\n , %s(%s)" , field.c_str(), s.fText.c_str()); |
251 | } |
252 | } |
253 | for (const auto& param : fSectionAndParameterHelper.getParameters()) { |
254 | String nameString(param->fName); |
255 | const char* name = nameString.c_str(); |
256 | const Type& type = param->fType.nonnullable(); |
257 | if (type.kind() == Type::kSampler_Kind) { |
258 | this->writef("\n , %s(std::move(%s)" , FieldName(name).c_str(), name); |
259 | for (const Section* s : fSectionAndParameterHelper.getSections( |
260 | SAMPLER_PARAMS_SECTION)) { |
261 | if (s->fArgument == name) { |
262 | this->writef(", %s" , s->fText.c_str()); |
263 | } |
264 | } |
265 | this->writef(")" ); |
266 | } else if (type == *fContext.fFragmentProcessor_Type) { |
267 | // do nothing |
268 | } else { |
269 | this->writef("\n , %s(%s)" , FieldName(name).c_str(), name); |
270 | } |
271 | } |
272 | this->writef(" {\n" ); |
273 | this->writeSection(CONSTRUCTOR_CODE_SECTION); |
274 | int samplerCount = 0; |
275 | for (const auto& param : fSectionAndParameterHelper.getParameters()) { |
276 | if (param->fType.kind() == Type::kSampler_Kind) { |
277 | ++samplerCount; |
278 | } else if (param->fType.nonnullable() == *fContext.fFragmentProcessor_Type) { |
279 | if (param->fType.kind() == Type::kNullable_Kind) { |
280 | this->writef(" if (%s) {\n" , String(param->fName).c_str()); |
281 | } else { |
282 | this->writef(" SkASSERT(%s);" , String(param->fName).c_str()); |
283 | } |
284 | this->writef(" %s_index = this->numChildProcessors();" , |
285 | FieldName(String(param->fName).c_str()).c_str()); |
286 | if (fSectionAndParameterHelper.hasCoordOverrides(*param)) { |
287 | this->writef(" %s->setSampledWithExplicitCoords(true);" , |
288 | String(param->fName).c_str()); |
289 | } |
290 | this->writef(" this->registerChildProcessor(std::move(%s));" , |
291 | String(param->fName).c_str()); |
292 | if (param->fType.kind() == Type::kNullable_Kind) { |
293 | this->writef(" }" ); |
294 | } |
295 | } |
296 | } |
297 | if (samplerCount) { |
298 | this->writef(" this->setTextureSamplerCnt(%d);" , samplerCount); |
299 | } |
300 | for (size_t i = 0; i < transforms.size(); ++i) { |
301 | const Section& s = *transforms[i]; |
302 | String field = CoordTransformName(s.fArgument.c_str(), i); |
303 | this->writef(" this->addCoordTransform(&%s);\n" , field.c_str()); |
304 | } |
305 | this->writef(" }\n" ); |
306 | } |
307 | |
308 | void HCodeGenerator::writeFields() { |
309 | this->writeSection(FIELDS_SECTION); |
310 | const auto transforms = fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION); |
311 | for (size_t i = 0; i < transforms.size(); ++i) { |
312 | const Section& s = *transforms[i]; |
313 | this->writef(" GrCoordTransform %s;\n" , |
314 | CoordTransformName(s.fArgument.c_str(), i).c_str()); |
315 | } |
316 | for (const auto& param : fSectionAndParameterHelper.getParameters()) { |
317 | String name = FieldName(String(param->fName).c_str()); |
318 | if (param->fType.nonnullable() == *fContext.fFragmentProcessor_Type) { |
319 | this->writef(" int %s_index = -1;\n" , name.c_str()); |
320 | } else { |
321 | this->writef(" %s %s;\n" , FieldType(fContext, param->fType, |
322 | param->fModifiers.fLayout).c_str(), |
323 | name.c_str()); |
324 | } |
325 | } |
326 | } |
327 | |
328 | String HCodeGenerator::(const Program& program, ErrorReporter& errors) { |
329 | SymbolTable types(&errors); |
330 | Parser parser(program.fSource->c_str(), program.fSource->length(), types, errors); |
331 | for (;;) { |
332 | Token = parser.nextRawToken(); |
333 | switch (header.fKind) { |
334 | case Token::WHITESPACE: |
335 | break; |
336 | case Token::BLOCK_COMMENT: |
337 | return String(program.fSource->c_str() + header.fOffset, header.fLength); |
338 | default: |
339 | return "" ; |
340 | } |
341 | } |
342 | } |
343 | |
344 | bool HCodeGenerator::generateCode() { |
345 | this->writef("%s\n" , GetHeader(fProgram, fErrors).c_str()); |
346 | this->writef(kFragmentProcessorHeader, fFullName.c_str()); |
347 | this->writef("#ifndef %s_DEFINED\n" |
348 | "#define %s_DEFINED\n" , |
349 | fFullName.c_str(), |
350 | fFullName.c_str()); |
351 | this->writef("#include \"include/core/SkTypes.h\"\n" ); |
352 | this->writef("#include \"include/core/SkM44.h\"\n" ); |
353 | this->writeSection(HEADER_SECTION); |
354 | this->writef("\n" |
355 | "#include \"src/gpu/GrCoordTransform.h\"\n" |
356 | "#include \"src/gpu/GrFragmentProcessor.h\"\n" ); |
357 | this->writef("class %s : public GrFragmentProcessor {\n" |
358 | "public:\n" , |
359 | fFullName.c_str()); |
360 | for (const auto& p : fProgram) { |
361 | if (ProgramElement::kEnum_Kind == p.fKind && !((Enum&) p).fBuiltin) { |
362 | this->writef("%s\n" , ((Enum&) p).code().c_str()); |
363 | } |
364 | } |
365 | this->writeSection(CLASS_SECTION); |
366 | this->writeMake(); |
367 | this->writef(" %s(const %s& src);\n" |
368 | " std::unique_ptr<GrFragmentProcessor> clone() const override;\n" |
369 | " const char* name() const override { return \"%s\"; }\n" , |
370 | fFullName.c_str(), fFullName.c_str(), fName.c_str()); |
371 | this->writeFields(); |
372 | this->writef("private:\n" ); |
373 | this->writeConstructor(); |
374 | this->writef(" GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;\n" |
375 | " void onGetGLSLProcessorKey(const GrShaderCaps&," |
376 | "GrProcessorKeyBuilder*) const override;\n" |
377 | " bool onIsEqual(const GrFragmentProcessor&) const override;\n" ); |
378 | for (const auto& param : fSectionAndParameterHelper.getParameters()) { |
379 | if (param->fType.kind() == Type::kSampler_Kind) { |
380 | this->writef(" const TextureSampler& onTextureSampler(int) const override;" ); |
381 | break; |
382 | } |
383 | } |
384 | this->writef(" GR_DECLARE_FRAGMENT_PROCESSOR_TEST\n" ); |
385 | this->writef(" typedef GrFragmentProcessor INHERITED;\n" |
386 | "};\n" ); |
387 | this->writeSection(HEADER_END_SECTION); |
388 | this->writef("#endif\n" ); |
389 | return 0 == fErrors.errorCount(); |
390 | } |
391 | |
392 | } // namespace |
393 | |