blob: 819b85a515f98907c995e1d2857b09cff6c7d1ed [file] [log] [blame]
Ethan Nicholas762466e2017-06-29 10:03:38 -04001/*
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"
Ethan Nicholasaae47c82017-11-10 15:34:03 -050011#include "ir/SkSLEnum.h"
Ethan Nicholas762466e2017-06-29 10:03:38 -040012#include "ir/SkSLFunctionDeclaration.h"
13#include "ir/SkSLFunctionDefinition.h"
14#include "ir/SkSLSection.h"
15#include "ir/SkSLVarDeclarations.h"
16
17namespace SkSL {
18
Ethan Nicholasc9472af2017-10-10 16:30:21 -040019HCodeGenerator::HCodeGenerator(const Context* context, const Program* program,
20 ErrorReporter* errors, String name, OutputStream* out)
Ethan Nicholas762466e2017-06-29 10:03:38 -040021: INHERITED(program, errors, out)
Ethan Nicholasc9472af2017-10-10 16:30:21 -040022, fContext(*context)
Ethan Nicholas762466e2017-06-29 10:03:38 -040023, fName(std::move(name))
24, fFullName(String::printf("Gr%s", fName.c_str()))
25, fSectionAndParameterHelper(*program, *errors) {}
26
Ethan Nicholasd608c092017-10-26 09:30:08 -040027String HCodeGenerator::ParameterType(const Context& context, const Type& type,
28 const Layout& layout) {
29 if (layout.fCType != "") {
30 return layout.fCType;
31 } else if (type == *context.fFloat_Type || type == *context.fHalf_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -040032 return "float";
Ethan Nicholasc9472af2017-10-10 16:30:21 -040033 } else if (type == *context.fFloat2_Type || type == *context.fHalf2_Type) {
Ethan Nicholas762466e2017-06-29 10:03:38 -040034 return "SkPoint";
Ethan Nicholasc9472af2017-10-10 16:30:21 -040035 } else if (type == *context.fInt4_Type || type == *context.fShort4_Type) {
Ethan Nicholas762466e2017-06-29 10:03:38 -040036 return "SkIRect";
Ethan Nicholasc9472af2017-10-10 16:30:21 -040037 } else if (type == *context.fFloat4_Type || type == *context.fHalf4_Type) {
Ethan Nicholas762466e2017-06-29 10:03:38 -040038 return "SkRect";
Ethan Nicholasc9472af2017-10-10 16:30:21 -040039 } else if (type == *context.fFloat4x4_Type || type == *context.fHalf4x4_Type) {
Ethan Nicholas762466e2017-06-29 10:03:38 -040040 return "SkMatrix44";
41 } else if (type.kind() == Type::kSampler_Kind) {
42 return "sk_sp<GrTextureProxy>";
Ethan Nicholasc9472af2017-10-10 16:30:21 -040043 } else if (type == *context.fFragmentProcessor_Type) {
44 return "std::unique_ptr<GrFragmentProcessor>";
Ethan Nicholas762466e2017-06-29 10:03:38 -040045 }
46 return type.name();
47}
48
Ethan Nicholasd608c092017-10-26 09:30:08 -040049String HCodeGenerator::FieldType(const Context& context, const Type& type,
50 const Layout& layout) {
Ethan Nicholas762466e2017-06-29 10:03:38 -040051 if (type.kind() == Type::kSampler_Kind) {
52 return "TextureSampler";
Ethan Nicholasc9472af2017-10-10 16:30:21 -040053 } else if (type == *context.fFragmentProcessor_Type) {
54 // we don't store fragment processors in fields, they get registered via
55 // registerChildProcessor instead
56 ASSERT(false);
57 return "<error>";
Ethan Nicholas762466e2017-06-29 10:03:38 -040058 }
Ethan Nicholasd608c092017-10-26 09:30:08 -040059 return ParameterType(context, type, layout);
Ethan Nicholas762466e2017-06-29 10:03:38 -040060}
61
62void HCodeGenerator::writef(const char* s, va_list va) {
63 static constexpr int BUFFER_SIZE = 1024;
Ethan Nicholas9fb036f2017-07-05 16:19:09 -040064 va_list copy;
65 va_copy(copy, va);
Ethan Nicholas762466e2017-06-29 10:03:38 -040066 char buffer[BUFFER_SIZE];
67 int length = vsnprintf(buffer, BUFFER_SIZE, s, va);
68 if (length < BUFFER_SIZE) {
69 fOut->write(buffer, length);
70 } else {
71 std::unique_ptr<char[]> heap(new char[length + 1]);
Ethan Nicholas9fb036f2017-07-05 16:19:09 -040072 vsprintf(heap.get(), s, copy);
Ethan Nicholas762466e2017-06-29 10:03:38 -040073 fOut->write(heap.get(), length);
74 }
75}
76
77void HCodeGenerator::writef(const char* s, ...) {
78 va_list va;
79 va_start(va, s);
80 this->writef(s, va);
81 va_end(va);
82}
83
84bool HCodeGenerator::writeSection(const char* name, const char* prefix) {
Ethan Nicholas68990be2017-07-13 09:36:52 -040085 const Section* s = fSectionAndParameterHelper.getSection(name);
86 if (s) {
87 this->writef("%s%s", prefix, s->fText.c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -040088 return true;
89 }
90 return false;
91}
92
93void HCodeGenerator::writeExtraConstructorParams(const char* separator) {
94 // super-simple parse, just assume the last token before a comma is the name of a parameter
95 // (which is true as long as there are no multi-parameter template types involved). Will replace
96 // this with something more robust if the need arises.
Ethan Nicholas68990be2017-07-13 09:36:52 -040097 const Section* section = fSectionAndParameterHelper.getSection(CONSTRUCTOR_PARAMS_SECTION);
98 if (section) {
99 const char* s = section->fText.c_str();
Ethan Nicholas762466e2017-06-29 10:03:38 -0400100 #define BUFFER_SIZE 64
101 char lastIdentifier[BUFFER_SIZE];
102 int lastIdentifierLength = 0;
103 bool foundBreak = false;
104 while (*s) {
105 char c = *s;
106 ++s;
107 if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
108 c == '_') {
109 if (foundBreak) {
110 lastIdentifierLength = 0;
111 foundBreak = false;
112 }
113 ASSERT(lastIdentifierLength < BUFFER_SIZE);
114 lastIdentifier[lastIdentifierLength] = c;
115 ++lastIdentifierLength;
116 } else {
117 foundBreak = true;
118 if (c == ',') {
119 ASSERT(lastIdentifierLength < BUFFER_SIZE);
120 lastIdentifier[lastIdentifierLength] = 0;
121 this->writef("%s%s", separator, lastIdentifier);
122 separator = ", ";
123 } else if (c != ' ' && c != '\t' && c != '\n' && c != '\r') {
124 lastIdentifierLength = 0;
125 }
126 }
127 }
128 if (lastIdentifierLength) {
129 ASSERT(lastIdentifierLength < BUFFER_SIZE);
130 lastIdentifier[lastIdentifierLength] = 0;
131 this->writef("%s%s", separator, lastIdentifier);
132 }
133 }
134}
135
136void HCodeGenerator::writeMake() {
137 const char* separator;
138 if (!this->writeSection(MAKE_SECTION)) {
Brian Salomonaff329b2017-08-11 09:40:37 -0400139 this->writef(" static std::unique_ptr<GrFragmentProcessor> Make(");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400140 separator = "";
Ethan Nicholas68990be2017-07-13 09:36:52 -0400141 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
Ethan Nicholasd608c092017-10-26 09:30:08 -0400142 this->writef("%s%s %s", separator, ParameterType(fContext, param->fType,
143 param->fModifiers.fLayout).c_str(),
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700144 String(param->fName).c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -0400145 separator = ", ";
146 }
147 this->writeSection(CONSTRUCTOR_PARAMS_SECTION, separator);
148 this->writef(") {\n"
Brian Salomonaff329b2017-08-11 09:40:37 -0400149 " return std::unique_ptr<GrFragmentProcessor>(new %s(",
Ethan Nicholas762466e2017-06-29 10:03:38 -0400150 fFullName.c_str());
151 separator = "";
Ethan Nicholas68990be2017-07-13 09:36:52 -0400152 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
Ethan Nicholasc9472af2017-10-10 16:30:21 -0400153 if (param->fType == *fContext.fFragmentProcessor_Type) {
Robert Phillips7a59f232017-11-08 15:31:30 -0500154 this->writef("%sstd::move(%s)", separator, String(param->fName).c_str());
Ethan Nicholasc9472af2017-10-10 16:30:21 -0400155 } else {
156 this->writef("%s%s", separator, String(param->fName).c_str());
157 }
Ethan Nicholas762466e2017-06-29 10:03:38 -0400158 separator = ", ";
159 }
160 this->writeExtraConstructorParams(separator);
161 this->writef("));\n"
162 " }\n");
163 }
164}
165
Ethan Nicholas68990be2017-07-13 09:36:52 -0400166void HCodeGenerator::failOnSection(const char* section, const char* msg) {
167 std::vector<const Section*> s = fSectionAndParameterHelper.getSections(section);
168 if (s.size()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700169 fErrors.error(s[0]->fOffset, String("@") + section + " " + msg);
Ethan Nicholas68990be2017-07-13 09:36:52 -0400170 }
171}
172
Ethan Nicholas762466e2017-06-29 10:03:38 -0400173void HCodeGenerator::writeConstructor() {
174 if (this->writeSection(CONSTRUCTOR_SECTION)) {
Ethan Nicholas68990be2017-07-13 09:36:52 -0400175 const char* msg = "may not be present when constructor is overridden";
176 this->failOnSection(CONSTRUCTOR_CODE_SECTION, msg);
177 this->failOnSection(CONSTRUCTOR_PARAMS_SECTION, msg);
178 this->failOnSection(COORD_TRANSFORM_SECTION, msg);
179 this->failOnSection(INITIALIZERS_SECTION, msg);
180 this->failOnSection(OPTIMIZATION_FLAGS_SECTION, msg);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400181 }
182 this->writef(" %s(", fFullName.c_str());
183 const char* separator = "";
Ethan Nicholas68990be2017-07-13 09:36:52 -0400184 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
Ethan Nicholasd608c092017-10-26 09:30:08 -0400185 this->writef("%s%s %s", separator, ParameterType(fContext, param->fType,
186 param->fModifiers.fLayout).c_str(),
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700187 String(param->fName).c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -0400188 separator = ", ";
189 }
190 this->writeSection(CONSTRUCTOR_PARAMS_SECTION, separator);
191 this->writef(")\n"
Ethan Nicholasabff9562017-10-09 10:54:08 -0400192 " : INHERITED(k%s_ClassID", fFullName.c_str());
193 if (!this->writeSection(OPTIMIZATION_FLAGS_SECTION, ", (OptimizationFlags) ")) {
194 this->writef(", kNone_OptimizationFlags");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400195 }
196 this->writef(")");
197 this->writeSection(INITIALIZERS_SECTION, "\n , ");
Ethan Nicholas68990be2017-07-13 09:36:52 -0400198 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700199 String nameString(param->fName);
200 const char* name = nameString.c_str();
Ethan Nicholas762466e2017-06-29 10:03:38 -0400201 if (param->fType.kind() == Type::kSampler_Kind) {
Ethan Nicholas68990be2017-07-13 09:36:52 -0400202 this->writef("\n , %s(std::move(%s)", FieldName(name).c_str(), name);
203 for (const Section* s : fSectionAndParameterHelper.getSections(
204 SAMPLER_PARAMS_SECTION)) {
205 if (s->fArgument == name) {
206 this->writef(", %s", s->fText.c_str());
207 }
208 }
209 this->writef(")");
Ethan Nicholasc9472af2017-10-10 16:30:21 -0400210 } else if (param->fType == *fContext.fFragmentProcessor_Type) {
211 // do nothing
Ethan Nicholas762466e2017-06-29 10:03:38 -0400212 } else {
213 this->writef("\n , %s(%s)", FieldName(name).c_str(), name);
214 }
215 }
Ethan Nicholas68990be2017-07-13 09:36:52 -0400216 for (const Section* s : fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION)) {
217 String field = FieldName(s->fArgument.c_str());
218 this->writef("\n , %sCoordTransform(%s, %s.proxy())", field.c_str(), s->fText.c_str(),
219 field.c_str());
220 }
Ethan Nicholas762466e2017-06-29 10:03:38 -0400221 this->writef(" {\n");
222 this->writeSection(CONSTRUCTOR_CODE_SECTION);
Ethan Nicholas68990be2017-07-13 09:36:52 -0400223 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400224 if (param->fType.kind() == Type::kSampler_Kind) {
225 this->writef(" this->addTextureSampler(&%s);\n",
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700226 FieldName(String(param->fName).c_str()).c_str());
Ethan Nicholasc9472af2017-10-10 16:30:21 -0400227 } else if (param->fType == *fContext.fFragmentProcessor_Type) {
228 this->writef(" this->registerChildProcessor(std::move(%s));",
229 String(param->fName).c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -0400230 }
231 }
Ethan Nicholas68990be2017-07-13 09:36:52 -0400232 for (const Section* s : fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION)) {
233 String field = FieldName(s->fArgument.c_str());
234 this->writef(" this->addCoordTransform(&%sCoordTransform);\n", field.c_str());
235 }
Ethan Nicholasabff9562017-10-09 10:54:08 -0400236 this->writef(" }\n");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400237}
238
239void HCodeGenerator::writeFields() {
240 this->writeSection(FIELDS_SECTION);
Ethan Nicholas68990be2017-07-13 09:36:52 -0400241 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
Ethan Nicholasc9472af2017-10-10 16:30:21 -0400242 if (param->fType == *fContext.fFragmentProcessor_Type) {
243 continue;
244 }
Ethan Nicholasd608c092017-10-26 09:30:08 -0400245 this->writef(" %s %s;\n", FieldType(fContext, param->fType,
246 param->fModifiers.fLayout).c_str(),
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700247 FieldName(String(param->fName).c_str()).c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -0400248 }
Ethan Nicholas68990be2017-07-13 09:36:52 -0400249 for (const Section* s : fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION)) {
250 this->writef(" GrCoordTransform %sCoordTransform;\n",
251 FieldName(s->fArgument.c_str()).c_str());
252 }
Ethan Nicholas762466e2017-06-29 10:03:38 -0400253}
254
255bool HCodeGenerator::generateCode() {
256 this->writef(kFragmentProcessorHeader, fFullName.c_str());
257 this->writef("#ifndef %s_DEFINED\n"
Ethan Nicholas9fb036f2017-07-05 16:19:09 -0400258 "#define %s_DEFINED\n",
259 fFullName.c_str(),
260 fFullName.c_str());
Ethan Nicholasceb4d482017-07-10 15:40:20 -0400261 this->writef("#include \"SkTypes.h\"\n"
262 "#if SK_SUPPORT_GPU\n");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400263 this->writeSection(HEADER_SECTION);
Ethan Nicholas9fb036f2017-07-05 16:19:09 -0400264 this->writef("#include \"GrFragmentProcessor.h\"\n"
Brian Osman1cb41712017-10-19 12:54:52 -0400265 "#include \"GrCoordTransform.h\"\n");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400266 this->writef("class %s : public GrFragmentProcessor {\n"
267 "public:\n",
268 fFullName.c_str());
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500269 for (const auto& p : fProgram.fElements) {
270 if (ProgramElement::kEnum_Kind == p->fKind && !((Enum&) *p).fBuiltin) {
271 this->writef("%s\n", p->description().c_str());
272 }
273 }
Ethan Nicholase9d172a2017-11-20 12:12:24 -0500274 this->writeSection(CLASS_SECTION);
Ethan Nicholas68990be2017-07-13 09:36:52 -0400275 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
Ethan Nicholasc9472af2017-10-10 16:30:21 -0400276 if (param->fType.kind() == Type::kSampler_Kind ||
277 param->fType.kind() == Type::kOther_Kind) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400278 continue;
279 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700280 String nameString(param->fName);
281 const char* name = nameString.c_str();
Ethan Nicholas9fb036f2017-07-05 16:19:09 -0400282 this->writef(" %s %s() const { return %s; }\n",
Ethan Nicholasd608c092017-10-26 09:30:08 -0400283 FieldType(fContext, param->fType, param->fModifiers.fLayout).c_str(), name,
284 FieldName(name).c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -0400285 }
286 this->writeMake();
Ethan Nicholasf57c0d62017-07-31 11:18:22 -0400287 this->writef(" %s(const %s& src);\n"
Brian Salomonaff329b2017-08-11 09:40:37 -0400288 " std::unique_ptr<GrFragmentProcessor> clone() const override;\n"
Ethan Nicholasf57c0d62017-07-31 11:18:22 -0400289 " const char* name() const override { return \"%s\"; }\n"
Ethan Nicholas762466e2017-06-29 10:03:38 -0400290 "private:\n",
Ethan Nicholasf57c0d62017-07-31 11:18:22 -0400291 fFullName.c_str(), fFullName.c_str(), fName.c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -0400292 this->writeConstructor();
293 this->writef(" GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;\n"
294 " void onGetGLSLProcessorKey(const GrShaderCaps&,"
295 "GrProcessorKeyBuilder*) const override;\n"
296 " bool onIsEqual(const GrFragmentProcessor&) const override;\n"
Brian Salomon0c26a9d2017-07-06 10:09:38 -0400297 " GR_DECLARE_FRAGMENT_PROCESSOR_TEST\n");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400298 this->writeFields();
299 this->writef(" typedef GrFragmentProcessor INHERITED;\n"
Ethan Nicholas9fb036f2017-07-05 16:19:09 -0400300 "};\n");
301 this->writeSection(HEADER_END_SECTION);
Ethan Nicholasceb4d482017-07-10 15:40:20 -0400302 this->writef("#endif\n"
303 "#endif\n");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400304 return 0 == fErrors.errorCount();
305}
306
307} // namespace