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
HCodeGenerator(const Context * context,const Program * program,ErrorReporter * errors,String name,OutputStream * out)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
ParameterType(const Context & context,const Type & type,const Layout & layout)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
ParameterCType(const Context & context,const Type & type,const Layout & layout)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
FieldType(const Context & context,const Type & type,const Layout & layout)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
AccessType(const Context & context,const Type & type,const Layout & layout)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
writef(const char * s,va_list va)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
writef(const char * s,...)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
writeSection(const char * name,const char * prefix)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
writeExtraConstructorParams(const char * separator)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
writeMake()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
failOnSection(const char * section,const char * msg)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
writeConstructor()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
writeFields()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
GetHeader(const Program & program,ErrorReporter & errors)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
generateCode()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