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