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