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