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