• 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 "SkSLUtil.h"
11 #include "ir/SkSLFunctionDeclaration.h"
12 #include "ir/SkSLFunctionDefinition.h"
13 #include "ir/SkSLSection.h"
14 #include "ir/SkSLVarDeclarations.h"
15 
16 namespace SkSL {
17 
HCodeGenerator(const Program * program,ErrorReporter * errors,String name,OutputStream * out)18 HCodeGenerator::HCodeGenerator(const Program* program, ErrorReporter* errors, String name,
19                                OutputStream* out)
20 : INHERITED(program, errors, out)
21 , fName(std::move(name))
22 , fFullName(String::printf("Gr%s", fName.c_str()))
23 , fSectionAndParameterHelper(*program, *errors) {}
24 
ParameterType(const Type & type)25 String HCodeGenerator::ParameterType(const Type& type) {
26     if (type.fName == "vec2") {
27         return "SkPoint";
28     } else if (type.fName == "ivec4") {
29         return "SkIRect";
30     } else if (type.fName == "vec4") {
31         return "SkRect";
32     } else if (type.fName == "mat4") {
33         return "SkMatrix44";
34     } else if (type.kind() == Type::kSampler_Kind) {
35         return "sk_sp<GrTextureProxy>";
36     } else if (type.fName == "colorSpaceXform") {
37         return "sk_sp<GrColorSpaceXform>";
38     }
39     return type.name();
40 }
41 
FieldType(const Type & type)42 String HCodeGenerator::FieldType(const Type& type) {
43     if (type.kind() == Type::kSampler_Kind) {
44         return "TextureSampler";
45     }
46     return ParameterType(type);
47 }
48 
writef(const char * s,va_list va)49 void HCodeGenerator::writef(const char* s, va_list va) {
50     static constexpr int BUFFER_SIZE = 1024;
51     va_list copy;
52     va_copy(copy, va);
53     char buffer[BUFFER_SIZE];
54     int length = vsnprintf(buffer, BUFFER_SIZE, s, va);
55     if (length < BUFFER_SIZE) {
56         fOut->write(buffer, length);
57     } else {
58         std::unique_ptr<char[]> heap(new char[length + 1]);
59         vsprintf(heap.get(), s, copy);
60         fOut->write(heap.get(), length);
61     }
62 }
63 
writef(const char * s,...)64 void HCodeGenerator::writef(const char* s, ...) {
65     va_list va;
66     va_start(va, s);
67     this->writef(s, va);
68     va_end(va);
69 }
70 
writeSection(const char * name,const char * prefix)71 bool HCodeGenerator::writeSection(const char* name, const char* prefix) {
72     const Section* s = fSectionAndParameterHelper.getSection(name);
73     if (s) {
74         this->writef("%s%s", prefix, s->fText.c_str());
75         return true;
76     }
77     return false;
78 }
79 
writeExtraConstructorParams(const char * separator)80 void HCodeGenerator::writeExtraConstructorParams(const char* separator) {
81     // super-simple parse, just assume the last token before a comma is the name of a parameter
82     // (which is true as long as there are no multi-parameter template types involved). Will replace
83     // this with something more robust if the need arises.
84     const Section* section = fSectionAndParameterHelper.getSection(CONSTRUCTOR_PARAMS_SECTION);
85     if (section) {
86         const char* s = section->fText.c_str();
87         #define BUFFER_SIZE 64
88         char lastIdentifier[BUFFER_SIZE];
89         int lastIdentifierLength = 0;
90         bool foundBreak = false;
91         while (*s) {
92             char c = *s;
93             ++s;
94             if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
95                 c == '_') {
96                 if (foundBreak) {
97                     lastIdentifierLength = 0;
98                     foundBreak = false;
99                 }
100                 ASSERT(lastIdentifierLength < BUFFER_SIZE);
101                 lastIdentifier[lastIdentifierLength] = c;
102                 ++lastIdentifierLength;
103             } else {
104                 foundBreak = true;
105                 if (c == ',') {
106                     ASSERT(lastIdentifierLength < BUFFER_SIZE);
107                     lastIdentifier[lastIdentifierLength] = 0;
108                     this->writef("%s%s", separator, lastIdentifier);
109                     separator = ", ";
110                 } else if (c != ' ' && c != '\t' && c != '\n' && c != '\r') {
111                     lastIdentifierLength = 0;
112                 }
113             }
114         }
115         if (lastIdentifierLength) {
116             ASSERT(lastIdentifierLength < BUFFER_SIZE);
117             lastIdentifier[lastIdentifierLength] = 0;
118             this->writef("%s%s", separator, lastIdentifier);
119         }
120     }
121 }
122 
writeMake()123 void HCodeGenerator::writeMake() {
124     const char* separator;
125     if (!this->writeSection(MAKE_SECTION)) {
126         this->writef("    static sk_sp<GrFragmentProcessor> Make(");
127         separator = "";
128         for (const auto& param : fSectionAndParameterHelper.getParameters()) {
129             this->writef("%s%s %s", separator, ParameterType(param->fType).c_str(),
130                          param->fName.c_str());
131             separator = ", ";
132         }
133         this->writeSection(CONSTRUCTOR_PARAMS_SECTION, separator);
134         this->writef(") {\n"
135                      "        return sk_sp<GrFragmentProcessor>(new %s(",
136                      fFullName.c_str());
137         separator = "";
138         for (const auto& param : fSectionAndParameterHelper.getParameters()) {
139             this->writef("%s%s", separator, param->fName.c_str());
140             separator = ", ";
141         }
142         this->writeExtraConstructorParams(separator);
143         this->writef("));\n"
144                      "    }\n");
145     }
146 }
147 
failOnSection(const char * section,const char * msg)148 void HCodeGenerator::failOnSection(const char* section, const char* msg) {
149     std::vector<const Section*> s = fSectionAndParameterHelper.getSections(section);
150     if (s.size()) {
151         fErrors.error(s[0]->fPosition, String("@") + section + " " + msg);
152     }
153 }
154 
writeConstructor()155 void HCodeGenerator::writeConstructor() {
156     if (this->writeSection(CONSTRUCTOR_SECTION)) {
157         const char* msg = "may not be present when constructor is overridden";
158         this->failOnSection(CONSTRUCTOR_CODE_SECTION, msg);
159         this->failOnSection(CONSTRUCTOR_PARAMS_SECTION, msg);
160         this->failOnSection(COORD_TRANSFORM_SECTION, msg);
161         this->failOnSection(INITIALIZERS_SECTION, msg);
162         this->failOnSection(OPTIMIZATION_FLAGS_SECTION, msg);
163     }
164     this->writef("    %s(", fFullName.c_str());
165     const char* separator = "";
166     for (const auto& param : fSectionAndParameterHelper.getParameters()) {
167         this->writef("%s%s %s", separator, ParameterType(param->fType).c_str(),
168                      param->fName.c_str());
169         separator = ", ";
170     }
171     this->writeSection(CONSTRUCTOR_PARAMS_SECTION, separator);
172     this->writef(")\n"
173                  "    : INHERITED(");
174     if (!this->writeSection(OPTIMIZATION_FLAGS_SECTION, "(OptimizationFlags) ")) {
175         this->writef("kNone_OptimizationFlags");
176     }
177     this->writef(")");
178     this->writeSection(INITIALIZERS_SECTION, "\n    , ");
179     for (const auto& param : fSectionAndParameterHelper.getParameters()) {
180         const char* name = param->fName.c_str();
181         if (param->fType.kind() == Type::kSampler_Kind) {
182             this->writef("\n    , %s(std::move(%s)", FieldName(name).c_str(), name);
183             for (const Section* s : fSectionAndParameterHelper.getSections(
184                                                                           SAMPLER_PARAMS_SECTION)) {
185                 if (s->fArgument == name) {
186                     this->writef(", %s", s->fText.c_str());
187                 }
188             }
189             this->writef(")");
190         } else {
191             this->writef("\n    , %s(%s)", FieldName(name).c_str(), name);
192         }
193     }
194     for (const Section* s : fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION)) {
195         String field = FieldName(s->fArgument.c_str());
196         this->writef("\n    , %sCoordTransform(%s, %s.proxy())", field.c_str(), s->fText.c_str(),
197                      field.c_str());
198     }
199     this->writef(" {\n");
200     this->writeSection(CONSTRUCTOR_CODE_SECTION);
201     for (const auto& param : fSectionAndParameterHelper.getParameters()) {
202         if (param->fType.kind() == Type::kSampler_Kind) {
203             this->writef("        this->addTextureSampler(&%s);\n",
204                          FieldName(param->fName.c_str()).c_str());
205         }
206     }
207     for (const Section* s : fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION)) {
208         String field = FieldName(s->fArgument.c_str());
209         this->writef("        this->addCoordTransform(&%sCoordTransform);\n", field.c_str());
210     }
211     this->writef("        this->initClassID<%s>();\n"
212                  "    }\n",
213                  fFullName.c_str());
214 }
215 
writeFields()216 void HCodeGenerator::writeFields() {
217     this->writeSection(FIELDS_SECTION);
218     for (const auto& param : fSectionAndParameterHelper.getParameters()) {
219         const char* name = param->fName.c_str();
220         this->writef("    %s %s;\n", FieldType(param->fType).c_str(), FieldName(name).c_str());
221     }
222     for (const Section* s : fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION)) {
223         this->writef("    GrCoordTransform %sCoordTransform;\n",
224                      FieldName(s->fArgument.c_str()).c_str());
225     }
226 }
227 
generateCode()228 bool HCodeGenerator::generateCode() {
229     this->writef(kFragmentProcessorHeader, fFullName.c_str());
230     this->writef("#ifndef %s_DEFINED\n"
231                  "#define %s_DEFINED\n",
232                  fFullName.c_str(),
233                  fFullName.c_str());
234     this->writef("#include \"SkTypes.h\"\n"
235                  "#if SK_SUPPORT_GPU\n");
236     this->writeSection(HEADER_SECTION);
237     this->writef("#include \"GrFragmentProcessor.h\"\n"
238                  "#include \"GrCoordTransform.h\"\n"
239                  "#include \"GrColorSpaceXform.h\"\n"
240                  "#include \"effects/GrProxyMove.h\"\n");
241     this->writef("class %s : public GrFragmentProcessor {\n"
242                  "public:\n",
243                  fFullName.c_str());
244     this->writeSection(CLASS_SECTION);
245     for (const auto& param : fSectionAndParameterHelper.getParameters()) {
246         if (param->fType.kind() == Type::kSampler_Kind) {
247             continue;
248         }
249         const char* name = param->fName.c_str();
250         this->writef("    %s %s() const { return %s; }\n",
251                      FieldType(param->fType).c_str(), name, FieldName(name).c_str());
252     }
253     this->writeMake();
254     this->writef("    const char* name() const override { return \"%s\"; }\n"
255                  "private:\n",
256                  fName.c_str());
257     this->writeConstructor();
258     this->writef("    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;\n"
259                  "    void onGetGLSLProcessorKey(const GrShaderCaps&,"
260                                                 "GrProcessorKeyBuilder*) const override;\n"
261                  "    bool onIsEqual(const GrFragmentProcessor&) const override;\n"
262                  "    GR_DECLARE_FRAGMENT_PROCESSOR_TEST\n");
263     this->writeFields();
264     this->writef("    typedef GrFragmentProcessor INHERITED;\n"
265                 "};\n");
266     this->writeSection(HEADER_END_SECTION);
267     this->writef("#endif\n"
268                  "#endif\n");
269     return 0 == fErrors.errorCount();
270 }
271 
272 } // namespace
273