• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 namespace SkSL {
19 
HCodeGenerator(const Context * context,const Program * program,ErrorReporter * errors,String name,OutputStream * out)20 HCodeGenerator::HCodeGenerator(const Context* context, const Program* program,
21                                ErrorReporter* errors, String name, OutputStream* out)
22 : INHERITED(program, errors, out)
23 , fContext(*context)
24 , fName(std::move(name))
25 , fFullName(String::printf("Gr%s", fName.c_str()))
26 , fSectionAndParameterHelper(*program, *errors) {}
27 
ParameterType(const Context & context,const Type & type,const Layout & layout)28 String HCodeGenerator::ParameterType(const Context& context, const Type& type,
29                                      const Layout& layout) {
30     if (layout.fCType != "") {
31         return layout.fCType;
32     } else if (type == *context.fFloat_Type || type == *context.fHalf_Type) {
33         return "float";
34     } else if (type == *context.fFloat2_Type || type == *context.fHalf2_Type) {
35         return "SkPoint";
36     } else if (type == *context.fInt4_Type || type == *context.fShort4_Type) {
37         return "SkIRect";
38     } else if (type == *context.fFloat4_Type || type == *context.fHalf4_Type) {
39         return "SkRect";
40     } else if (type == *context.fFloat4x4_Type || type == *context.fHalf4x4_Type) {
41         return "SkMatrix44";
42     } else if (type.kind() == Type::kSampler_Kind) {
43         return "sk_sp<GrTextureProxy>";
44     } else if (type == *context.fFragmentProcessor_Type) {
45         return "std::unique_ptr<GrFragmentProcessor>";
46     }
47     return type.name();
48 }
49 
FieldType(const Context & context,const Type & type,const Layout & layout)50 String HCodeGenerator::FieldType(const Context& context, const Type& type,
51                                  const Layout& layout) {
52     if (type.kind() == Type::kSampler_Kind) {
53         return "TextureSampler";
54     } else if (type == *context.fFragmentProcessor_Type) {
55         // we don't store fragment processors in fields, they get registered via
56         // registerChildProcessor instead
57         ASSERT(false);
58         return "<error>";
59     }
60     return ParameterType(context, type, layout);
61 }
62 
writef(const char * s,va_list va)63 void HCodeGenerator::writef(const char* s, va_list va) {
64     static constexpr int BUFFER_SIZE = 1024;
65     va_list copy;
66     va_copy(copy, va);
67     char buffer[BUFFER_SIZE];
68     int length = vsnprintf(buffer, BUFFER_SIZE, s, va);
69     if (length < BUFFER_SIZE) {
70         fOut->write(buffer, length);
71     } else {
72         std::unique_ptr<char[]> heap(new char[length + 1]);
73         vsprintf(heap.get(), s, copy);
74         fOut->write(heap.get(), length);
75     }
76 }
77 
writef(const char * s,...)78 void HCodeGenerator::writef(const char* s, ...) {
79     va_list va;
80     va_start(va, s);
81     this->writef(s, va);
82     va_end(va);
83 }
84 
writeSection(const char * name,const char * prefix)85 bool HCodeGenerator::writeSection(const char* name, const char* prefix) {
86     const Section* s = fSectionAndParameterHelper.getSection(name);
87     if (s) {
88         this->writef("%s%s", prefix, s->fText.c_str());
89         return true;
90     }
91     return false;
92 }
93 
writeExtraConstructorParams(const char * separator)94 void HCodeGenerator::writeExtraConstructorParams(const char* separator) {
95     // super-simple parse, just assume the last token before a comma is the name of a parameter
96     // (which is true as long as there are no multi-parameter template types involved). Will replace
97     // this with something more robust if the need arises.
98     const Section* section = fSectionAndParameterHelper.getSection(CONSTRUCTOR_PARAMS_SECTION);
99     if (section) {
100         const char* s = section->fText.c_str();
101         #define BUFFER_SIZE 64
102         char lastIdentifier[BUFFER_SIZE];
103         int lastIdentifierLength = 0;
104         bool foundBreak = false;
105         while (*s) {
106             char c = *s;
107             ++s;
108             if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
109                 c == '_') {
110                 if (foundBreak) {
111                     lastIdentifierLength = 0;
112                     foundBreak = false;
113                 }
114                 ASSERT(lastIdentifierLength < BUFFER_SIZE);
115                 lastIdentifier[lastIdentifierLength] = c;
116                 ++lastIdentifierLength;
117             } else {
118                 foundBreak = true;
119                 if (c == ',') {
120                     ASSERT(lastIdentifierLength < BUFFER_SIZE);
121                     lastIdentifier[lastIdentifierLength] = 0;
122                     this->writef("%s%s", separator, lastIdentifier);
123                     separator = ", ";
124                 } else if (c != ' ' && c != '\t' && c != '\n' && c != '\r') {
125                     lastIdentifierLength = 0;
126                 }
127             }
128         }
129         if (lastIdentifierLength) {
130             ASSERT(lastIdentifierLength < BUFFER_SIZE);
131             lastIdentifier[lastIdentifierLength] = 0;
132             this->writef("%s%s", separator, lastIdentifier);
133         }
134     }
135 }
136 
writeMake()137 void HCodeGenerator::writeMake() {
138     const char* separator;
139     if (!this->writeSection(MAKE_SECTION)) {
140         this->writef("    static std::unique_ptr<GrFragmentProcessor> Make(");
141         separator = "";
142         for (const auto& param : fSectionAndParameterHelper.getParameters()) {
143             this->writef("%s%s %s", separator, ParameterType(fContext, param->fType,
144                                                              param->fModifiers.fLayout).c_str(),
145                          String(param->fName).c_str());
146             separator = ", ";
147         }
148         this->writeSection(CONSTRUCTOR_PARAMS_SECTION, separator);
149         this->writef(") {\n"
150                      "        return std::unique_ptr<GrFragmentProcessor>(new %s(",
151                      fFullName.c_str());
152         separator = "";
153         for (const auto& param : fSectionAndParameterHelper.getParameters()) {
154             if (param->fType == *fContext.fFragmentProcessor_Type) {
155                 this->writef("%sstd::move(%s)", separator, String(param->fName).c_str());
156             } else {
157                 this->writef("%s%s", separator, String(param->fName).c_str());
158             }
159             separator = ", ";
160         }
161         this->writeExtraConstructorParams(separator);
162         this->writef("));\n"
163                      "    }\n");
164     }
165 }
166 
failOnSection(const char * section,const char * msg)167 void HCodeGenerator::failOnSection(const char* section, const char* msg) {
168     std::vector<const Section*> s = fSectionAndParameterHelper.getSections(section);
169     if (s.size()) {
170         fErrors.error(s[0]->fOffset, String("@") + section + " " + msg);
171     }
172 }
173 
writeConstructor()174 void HCodeGenerator::writeConstructor() {
175     if (this->writeSection(CONSTRUCTOR_SECTION)) {
176         const char* msg = "may not be present when constructor is overridden";
177         this->failOnSection(CONSTRUCTOR_CODE_SECTION, msg);
178         this->failOnSection(CONSTRUCTOR_PARAMS_SECTION, msg);
179         this->failOnSection(COORD_TRANSFORM_SECTION, msg);
180         this->failOnSection(INITIALIZERS_SECTION, msg);
181         this->failOnSection(OPTIMIZATION_FLAGS_SECTION, msg);
182     }
183     this->writef("    %s(", fFullName.c_str());
184     const char* separator = "";
185     for (const auto& param : fSectionAndParameterHelper.getParameters()) {
186         this->writef("%s%s %s", separator, ParameterType(fContext, param->fType,
187                                                          param->fModifiers.fLayout).c_str(),
188                      String(param->fName).c_str());
189         separator = ", ";
190     }
191     this->writeSection(CONSTRUCTOR_PARAMS_SECTION, separator);
192     this->writef(")\n"
193                  "    : INHERITED(k%s_ClassID", fFullName.c_str());
194     if (!this->writeSection(OPTIMIZATION_FLAGS_SECTION, ", (OptimizationFlags) ")) {
195         this->writef(", kNone_OptimizationFlags");
196     }
197     this->writef(")");
198     this->writeSection(INITIALIZERS_SECTION, "\n    , ");
199     for (const auto& param : fSectionAndParameterHelper.getParameters()) {
200         String nameString(param->fName);
201         const char* name = nameString.c_str();
202         if (param->fType.kind() == Type::kSampler_Kind) {
203             this->writef("\n    , %s(std::move(%s)", FieldName(name).c_str(), name);
204             for (const Section* s : fSectionAndParameterHelper.getSections(
205                                                                           SAMPLER_PARAMS_SECTION)) {
206                 if (s->fArgument == name) {
207                     this->writef(", %s", s->fText.c_str());
208                 }
209             }
210             this->writef(")");
211         } else if (param->fType == *fContext.fFragmentProcessor_Type) {
212             // do nothing
213         } else {
214             this->writef("\n    , %s(%s)", FieldName(name).c_str(), name);
215         }
216     }
217     for (const Section* s : fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION)) {
218         String field = FieldName(s->fArgument.c_str());
219         this->writef("\n    , %sCoordTransform(%s, %s.proxy())", field.c_str(), s->fText.c_str(),
220                      field.c_str());
221     }
222     this->writef(" {\n");
223     this->writeSection(CONSTRUCTOR_CODE_SECTION);
224     for (const auto& param : fSectionAndParameterHelper.getParameters()) {
225         if (param->fType.kind() == Type::kSampler_Kind) {
226             this->writef("        this->addTextureSampler(&%s);\n",
227                          FieldName(String(param->fName).c_str()).c_str());
228         } else if (param->fType == *fContext.fFragmentProcessor_Type) {
229             this->writef("        this->registerChildProcessor(std::move(%s));",
230                          String(param->fName).c_str());
231         }
232     }
233     for (const Section* s : fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION)) {
234         String field = FieldName(s->fArgument.c_str());
235         this->writef("        this->addCoordTransform(&%sCoordTransform);\n", field.c_str());
236     }
237     this->writef("    }\n");
238 }
239 
writeFields()240 void HCodeGenerator::writeFields() {
241     this->writeSection(FIELDS_SECTION);
242     for (const auto& param : fSectionAndParameterHelper.getParameters()) {
243         if (param->fType == *fContext.fFragmentProcessor_Type) {
244             continue;
245         }
246         this->writef("    %s %s;\n", FieldType(fContext, param->fType,
247                                                param->fModifiers.fLayout).c_str(),
248                      FieldName(String(param->fName).c_str()).c_str());
249     }
250     for (const Section* s : fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION)) {
251         this->writef("    GrCoordTransform %sCoordTransform;\n",
252                      FieldName(s->fArgument.c_str()).c_str());
253     }
254 }
255 
GetHeader(const Program & program,ErrorReporter & errors)256 String HCodeGenerator::GetHeader(const Program& program, ErrorReporter& errors) {
257     SymbolTable types(&errors);
258     Parser parser(program.fSource->c_str(), program.fSource->length(), types, errors);
259     for (;;) {
260         Token header = parser.nextRawToken();
261         switch (header.fKind) {
262             case Token::WHITESPACE:
263                 break;
264             case Token::BLOCK_COMMENT:
265                 return String(program.fSource->c_str() + header.fOffset, header.fLength);
266             default:
267                 return "";
268         }
269     }
270 }
271 
generateCode()272 bool HCodeGenerator::generateCode() {
273     this->writef("%s\n", GetHeader(fProgram, fErrors).c_str());
274     this->writef(kFragmentProcessorHeader, fFullName.c_str());
275     this->writef("#ifndef %s_DEFINED\n"
276                  "#define %s_DEFINED\n",
277                  fFullName.c_str(),
278                  fFullName.c_str());
279     this->writef("#include \"SkTypes.h\"\n"
280                  "#if SK_SUPPORT_GPU\n");
281     this->writeSection(HEADER_SECTION);
282     this->writef("#include \"GrFragmentProcessor.h\"\n"
283                  "#include \"GrCoordTransform.h\"\n");
284     this->writef("class %s : public GrFragmentProcessor {\n"
285                  "public:\n",
286                  fFullName.c_str());
287     for (const auto& p : fProgram.fElements) {
288         if (ProgramElement::kEnum_Kind == p->fKind && !((Enum&) *p).fBuiltin) {
289             this->writef("%s\n", p->description().c_str());
290         }
291     }
292     this->writeSection(CLASS_SECTION);
293     for (const auto& param : fSectionAndParameterHelper.getParameters()) {
294         if (param->fType.kind() == Type::kSampler_Kind ||
295             param->fType.kind() == Type::kOther_Kind) {
296             continue;
297         }
298         String nameString(param->fName);
299         const char* name = nameString.c_str();
300         this->writef("    %s %s() const { return %s; }\n",
301                      FieldType(fContext, param->fType, param->fModifiers.fLayout).c_str(), name,
302                      FieldName(name).c_str());
303     }
304     this->writeMake();
305     this->writef("    %s(const %s& src);\n"
306                  "    std::unique_ptr<GrFragmentProcessor> clone() const override;\n"
307                  "    const char* name() const override { return \"%s\"; }\n"
308                  "private:\n",
309                  fFullName.c_str(), fFullName.c_str(), fName.c_str());
310     this->writeConstructor();
311     this->writef("    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;\n"
312                  "    void onGetGLSLProcessorKey(const GrShaderCaps&,"
313                                                 "GrProcessorKeyBuilder*) const override;\n"
314                  "    bool onIsEqual(const GrFragmentProcessor&) const override;\n"
315                  "    GR_DECLARE_FRAGMENT_PROCESSOR_TEST\n");
316     this->writeFields();
317     this->writef("    typedef GrFragmentProcessor INHERITED;\n"
318                 "};\n");
319     this->writeSection(HEADER_END_SECTION);
320     this->writef("#endif\n"
321                  "#endif\n");
322     return 0 == fErrors.errorCount();
323 }
324 
325 } // namespace
326