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
20namespace SkSL {
21
22HCodeGenerator::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
30String 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
39Layout::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::kSkM44;
68 } else if (type.kind() == Type::kSampler_Kind) {
69 return Layout::CType::kGrSurfaceProxyView;
70 } else if (type == *context.fFragmentProcessor_Type) {
71 return Layout::CType::kGrFragmentProcessor;
72 }
73 return Layout::CType::kDefault;
74}
75
76String 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
89String 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
102void 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
118void 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
125bool 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
134void 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
177void 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 param->fType.nonnullable().kind() == Type::kSampler_Kind) {
196 this->writef("%sstd::move(%s)", separator, String(param->fName).c_str());
197 } else {
198 this->writef("%s%s", separator, String(param->fName).c_str());
199 }
200 separator = ", ";
201 }
202 this->writeExtraConstructorParams(separator);
203 this->writef("));\n"
204 " }\n");
205 }
206}
207
208void HCodeGenerator::failOnSection(const char* section, const char* msg) {
209 std::vector<const Section*> s = fSectionAndParameterHelper.getSections(section);
210 if (s.size()) {
211 fErrors.error(s[0]->fOffset, String("@") + section + " " + msg);
212 }
213}
214
215void HCodeGenerator::writeConstructor() {
216 if (this->writeSection(CONSTRUCTOR_SECTION)) {
217 const char* msg = "may not be present when constructor is overridden";
218 this->failOnSection(CONSTRUCTOR_CODE_SECTION, msg);
219 this->failOnSection(CONSTRUCTOR_PARAMS_SECTION, msg);
220 this->failOnSection(INITIALIZERS_SECTION, msg);
221 this->failOnSection(OPTIMIZATION_FLAGS_SECTION, msg);
222 return;
223 }
224 this->writef(" %s(", fFullName.c_str());
225 const char* separator = "";
226 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
227 this->writef("%s%s %s", separator, ParameterType(fContext, param->fType,
228 param->fModifiers.fLayout).c_str(),
229 String(param->fName).c_str());
230 separator = ", ";
231 }
232 this->writeSection(CONSTRUCTOR_PARAMS_SECTION, separator);
233 this->writef(")\n"
234 " : INHERITED(k%s_ClassID", fFullName.c_str());
235 if (!this->writeSection(OPTIMIZATION_FLAGS_SECTION, ", (OptimizationFlags) ")) {
236 this->writef(", kNone_OptimizationFlags");
237 }
238 this->writef(")");
239 this->writeSection(INITIALIZERS_SECTION, "\n , ");
240 const auto transforms = fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION);
241 for (size_t i = 0; i < transforms.size(); ++i) {
242 const Section& s = *transforms[i];
243 String field = CoordTransformName(s.fArgument.c_str(), i);
244 if (s.fArgument.size()) {
245 this->writef("\n , %s(%s, %s.proxy(), %s.origin())", field.c_str(), s.fText.c_str(),
246 FieldName(s.fArgument.c_str()).c_str(),
247 FieldName(s.fArgument.c_str()).c_str());
248 }
249 else {
250 this->writef("\n , %s(%s)", field.c_str(), s.fText.c_str());
251 }
252 }
253 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
254 String nameString(param->fName);
255 const char* name = nameString.c_str();
256 const Type& type = param->fType.nonnullable();
257 if (type.kind() == Type::kSampler_Kind) {
258 this->writef("\n , %s(std::move(%s)", FieldName(name).c_str(), name);
259 for (const Section* s : fSectionAndParameterHelper.getSections(
260 SAMPLER_PARAMS_SECTION)) {
261 if (s->fArgument == name) {
262 this->writef(", %s", s->fText.c_str());
263 }
264 }
265 this->writef(")");
266 } else if (type == *fContext.fFragmentProcessor_Type) {
267 // do nothing
268 } else {
269 this->writef("\n , %s(%s)", FieldName(name).c_str(), name);
270 }
271 }
272 this->writef(" {\n");
273 this->writeSection(CONSTRUCTOR_CODE_SECTION);
274 int samplerCount = 0;
275 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
276 if (param->fType.kind() == Type::kSampler_Kind) {
277 ++samplerCount;
278 } else if (param->fType.nonnullable() == *fContext.fFragmentProcessor_Type) {
279 if (param->fType.kind() == Type::kNullable_Kind) {
280 this->writef(" if (%s) {\n", String(param->fName).c_str());
281 } else {
282 this->writef(" SkASSERT(%s);", String(param->fName).c_str());
283 }
284 this->writef(" %s_index = this->numChildProcessors();",
285 FieldName(String(param->fName).c_str()).c_str());
286 if (fSectionAndParameterHelper.hasCoordOverrides(*param)) {
287 this->writef(" %s->setSampledWithExplicitCoords(true);",
288 String(param->fName).c_str());
289 }
290 this->writef(" this->registerChildProcessor(std::move(%s));",
291 String(param->fName).c_str());
292 if (param->fType.kind() == Type::kNullable_Kind) {
293 this->writef(" }");
294 }
295 }
296 }
297 if (samplerCount) {
298 this->writef(" this->setTextureSamplerCnt(%d);", samplerCount);
299 }
300 for (size_t i = 0; i < transforms.size(); ++i) {
301 const Section& s = *transforms[i];
302 String field = CoordTransformName(s.fArgument.c_str(), i);
303 this->writef(" this->addCoordTransform(&%s);\n", field.c_str());
304 }
305 this->writef(" }\n");
306}
307
308void HCodeGenerator::writeFields() {
309 this->writeSection(FIELDS_SECTION);
310 const auto transforms = fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION);
311 for (size_t i = 0; i < transforms.size(); ++i) {
312 const Section& s = *transforms[i];
313 this->writef(" GrCoordTransform %s;\n",
314 CoordTransformName(s.fArgument.c_str(), i).c_str());
315 }
316 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
317 String name = FieldName(String(param->fName).c_str());
318 if (param->fType.nonnullable() == *fContext.fFragmentProcessor_Type) {
319 this->writef(" int %s_index = -1;\n", name.c_str());
320 } else {
321 this->writef(" %s %s;\n", FieldType(fContext, param->fType,
322 param->fModifiers.fLayout).c_str(),
323 name.c_str());
324 }
325 }
326}
327
328String HCodeGenerator::GetHeader(const Program& program, ErrorReporter& errors) {
329 SymbolTable types(&errors);
330 Parser parser(program.fSource->c_str(), program.fSource->length(), types, errors);
331 for (;;) {
332 Token header = parser.nextRawToken();
333 switch (header.fKind) {
334 case Token::WHITESPACE:
335 break;
336 case Token::BLOCK_COMMENT:
337 return String(program.fSource->c_str() + header.fOffset, header.fLength);
338 default:
339 return "";
340 }
341 }
342}
343
344bool HCodeGenerator::generateCode() {
345 this->writef("%s\n", GetHeader(fProgram, fErrors).c_str());
346 this->writef(kFragmentProcessorHeader, fFullName.c_str());
347 this->writef("#ifndef %s_DEFINED\n"
348 "#define %s_DEFINED\n",
349 fFullName.c_str(),
350 fFullName.c_str());
351 this->writef("#include \"include/core/SkTypes.h\"\n");
352 this->writef("#include \"include/core/SkM44.h\"\n");
353 this->writeSection(HEADER_SECTION);
354 this->writef("\n"
355 "#include \"src/gpu/GrCoordTransform.h\"\n"
356 "#include \"src/gpu/GrFragmentProcessor.h\"\n");
357 this->writef("class %s : public GrFragmentProcessor {\n"
358 "public:\n",
359 fFullName.c_str());
360 for (const auto& p : fProgram) {
361 if (ProgramElement::kEnum_Kind == p.fKind && !((Enum&) p).fBuiltin) {
362 this->writef("%s\n", ((Enum&) p).code().c_str());
363 }
364 }
365 this->writeSection(CLASS_SECTION);
366 this->writeMake();
367 this->writef(" %s(const %s& src);\n"
368 " std::unique_ptr<GrFragmentProcessor> clone() const override;\n"
369 " const char* name() const override { return \"%s\"; }\n",
370 fFullName.c_str(), fFullName.c_str(), fName.c_str());
371 this->writeFields();
372 this->writef("private:\n");
373 this->writeConstructor();
374 this->writef(" GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;\n"
375 " void onGetGLSLProcessorKey(const GrShaderCaps&,"
376 "GrProcessorKeyBuilder*) const override;\n"
377 " bool onIsEqual(const GrFragmentProcessor&) const override;\n");
378 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
379 if (param->fType.kind() == Type::kSampler_Kind) {
380 this->writef(" const TextureSampler& onTextureSampler(int) const override;");
381 break;
382 }
383 }
384 this->writef(" GR_DECLARE_FRAGMENT_PROCESSOR_TEST\n");
385 this->writef(" typedef GrFragmentProcessor INHERITED;\n"
386 "};\n");
387 this->writeSection(HEADER_END_SECTION);
388 this->writef("#endif\n");
389 return 0 == fErrors.errorCount();
390}
391
392} // namespace
393