blob: 21f4f2842cee839b2a7fcfd8fef1f4d5d857e853 [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"
11#include "ir/SkSLFunctionDeclaration.h"
12#include "ir/SkSLFunctionDefinition.h"
13#include "ir/SkSLSection.h"
14#include "ir/SkSLVarDeclarations.h"
15
16namespace SkSL {
17
Ethan Nicholasc9472af2017-10-10 16:30:21 -040018HCodeGenerator::HCodeGenerator(const Context* context, const Program* program,
19 ErrorReporter* errors, String name, OutputStream* out)
Ethan Nicholas762466e2017-06-29 10:03:38 -040020: INHERITED(program, errors, out)
Ethan Nicholasc9472af2017-10-10 16:30:21 -040021, fContext(*context)
Ethan Nicholas762466e2017-06-29 10:03:38 -040022, fName(std::move(name))
23, fFullName(String::printf("Gr%s", fName.c_str()))
24, fSectionAndParameterHelper(*program, *errors) {}
25
Ethan Nicholasc9472af2017-10-10 16:30:21 -040026String HCodeGenerator::ParameterType(const Context& context, const Type& type) {
27 if (type == *context.fFloat_Type || type == *context.fHalf_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -040028 return "float";
Ethan Nicholasc9472af2017-10-10 16:30:21 -040029 } else if (type == *context.fFloat2_Type || type == *context.fHalf2_Type) {
Ethan Nicholas762466e2017-06-29 10:03:38 -040030 return "SkPoint";
Ethan Nicholasc9472af2017-10-10 16:30:21 -040031 } else if (type == *context.fInt4_Type || type == *context.fShort4_Type) {
Ethan Nicholas762466e2017-06-29 10:03:38 -040032 return "SkIRect";
Ethan Nicholasc9472af2017-10-10 16:30:21 -040033 } else if (type == *context.fFloat4_Type || type == *context.fHalf4_Type) {
Ethan Nicholas762466e2017-06-29 10:03:38 -040034 return "SkRect";
Ethan Nicholasc9472af2017-10-10 16:30:21 -040035 } else if (type == *context.fFloat4x4_Type || type == *context.fHalf4x4_Type) {
Ethan Nicholas762466e2017-06-29 10:03:38 -040036 return "SkMatrix44";
37 } else if (type.kind() == Type::kSampler_Kind) {
38 return "sk_sp<GrTextureProxy>";
Ethan Nicholasc9472af2017-10-10 16:30:21 -040039 } else if (type == *context.fFragmentProcessor_Type) {
40 return "std::unique_ptr<GrFragmentProcessor>";
Ethan Nicholas762466e2017-06-29 10:03:38 -040041 }
42 return type.name();
43}
44
Ethan Nicholasc9472af2017-10-10 16:30:21 -040045String HCodeGenerator::FieldType(const Context& context, const Type& type) {
Ethan Nicholas762466e2017-06-29 10:03:38 -040046 if (type.kind() == Type::kSampler_Kind) {
47 return "TextureSampler";
Ethan Nicholasc9472af2017-10-10 16:30:21 -040048 } else if (type == *context.fFragmentProcessor_Type) {
49 // we don't store fragment processors in fields, they get registered via
50 // registerChildProcessor instead
51 ASSERT(false);
52 return "<error>";
Ethan Nicholas762466e2017-06-29 10:03:38 -040053 }
Ethan Nicholasc9472af2017-10-10 16:30:21 -040054 return ParameterType(context, type);
Ethan Nicholas762466e2017-06-29 10:03:38 -040055}
56
57void HCodeGenerator::writef(const char* s, va_list va) {
58 static constexpr int BUFFER_SIZE = 1024;
Ethan Nicholas9fb036f2017-07-05 16:19:09 -040059 va_list copy;
60 va_copy(copy, va);
Ethan Nicholas762466e2017-06-29 10:03:38 -040061 char buffer[BUFFER_SIZE];
62 int length = vsnprintf(buffer, BUFFER_SIZE, s, va);
63 if (length < BUFFER_SIZE) {
64 fOut->write(buffer, length);
65 } else {
66 std::unique_ptr<char[]> heap(new char[length + 1]);
Ethan Nicholas9fb036f2017-07-05 16:19:09 -040067 vsprintf(heap.get(), s, copy);
Ethan Nicholas762466e2017-06-29 10:03:38 -040068 fOut->write(heap.get(), length);
69 }
70}
71
72void HCodeGenerator::writef(const char* s, ...) {
73 va_list va;
74 va_start(va, s);
75 this->writef(s, va);
76 va_end(va);
77}
78
79bool HCodeGenerator::writeSection(const char* name, const char* prefix) {
Ethan Nicholas68990be2017-07-13 09:36:52 -040080 const Section* s = fSectionAndParameterHelper.getSection(name);
81 if (s) {
82 this->writef("%s%s", prefix, s->fText.c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -040083 return true;
84 }
85 return false;
86}
87
88void HCodeGenerator::writeExtraConstructorParams(const char* separator) {
89 // super-simple parse, just assume the last token before a comma is the name of a parameter
90 // (which is true as long as there are no multi-parameter template types involved). Will replace
91 // this with something more robust if the need arises.
Ethan Nicholas68990be2017-07-13 09:36:52 -040092 const Section* section = fSectionAndParameterHelper.getSection(CONSTRUCTOR_PARAMS_SECTION);
93 if (section) {
94 const char* s = section->fText.c_str();
Ethan Nicholas762466e2017-06-29 10:03:38 -040095 #define BUFFER_SIZE 64
96 char lastIdentifier[BUFFER_SIZE];
97 int lastIdentifierLength = 0;
98 bool foundBreak = false;
99 while (*s) {
100 char c = *s;
101 ++s;
102 if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
103 c == '_') {
104 if (foundBreak) {
105 lastIdentifierLength = 0;
106 foundBreak = false;
107 }
108 ASSERT(lastIdentifierLength < BUFFER_SIZE);
109 lastIdentifier[lastIdentifierLength] = c;
110 ++lastIdentifierLength;
111 } else {
112 foundBreak = true;
113 if (c == ',') {
114 ASSERT(lastIdentifierLength < BUFFER_SIZE);
115 lastIdentifier[lastIdentifierLength] = 0;
116 this->writef("%s%s", separator, lastIdentifier);
117 separator = ", ";
118 } else if (c != ' ' && c != '\t' && c != '\n' && c != '\r') {
119 lastIdentifierLength = 0;
120 }
121 }
122 }
123 if (lastIdentifierLength) {
124 ASSERT(lastIdentifierLength < BUFFER_SIZE);
125 lastIdentifier[lastIdentifierLength] = 0;
126 this->writef("%s%s", separator, lastIdentifier);
127 }
128 }
129}
130
131void HCodeGenerator::writeMake() {
132 const char* separator;
133 if (!this->writeSection(MAKE_SECTION)) {
Brian Salomonaff329b2017-08-11 09:40:37 -0400134 this->writef(" static std::unique_ptr<GrFragmentProcessor> Make(");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400135 separator = "";
Ethan Nicholas68990be2017-07-13 09:36:52 -0400136 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
Ethan Nicholasc9472af2017-10-10 16:30:21 -0400137 this->writef("%s%s %s", separator, ParameterType(fContext, param->fType).c_str(),
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700138 String(param->fName).c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -0400139 separator = ", ";
140 }
141 this->writeSection(CONSTRUCTOR_PARAMS_SECTION, separator);
142 this->writef(") {\n"
Brian Salomonaff329b2017-08-11 09:40:37 -0400143 " return std::unique_ptr<GrFragmentProcessor>(new %s(",
Ethan Nicholas762466e2017-06-29 10:03:38 -0400144 fFullName.c_str());
145 separator = "";
Ethan Nicholas68990be2017-07-13 09:36:52 -0400146 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
Ethan Nicholasc9472af2017-10-10 16:30:21 -0400147 if (param->fType == *fContext.fFragmentProcessor_Type) {
148 this->writef("%s%s->clone()", separator, String(param->fName).c_str());
149 } else {
150 this->writef("%s%s", separator, String(param->fName).c_str());
151 }
Ethan Nicholas762466e2017-06-29 10:03:38 -0400152 separator = ", ";
153 }
154 this->writeExtraConstructorParams(separator);
155 this->writef("));\n"
156 " }\n");
157 }
158}
159
Ethan Nicholas68990be2017-07-13 09:36:52 -0400160void HCodeGenerator::failOnSection(const char* section, const char* msg) {
161 std::vector<const Section*> s = fSectionAndParameterHelper.getSections(section);
162 if (s.size()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700163 fErrors.error(s[0]->fOffset, String("@") + section + " " + msg);
Ethan Nicholas68990be2017-07-13 09:36:52 -0400164 }
165}
166
Ethan Nicholas762466e2017-06-29 10:03:38 -0400167void HCodeGenerator::writeConstructor() {
168 if (this->writeSection(CONSTRUCTOR_SECTION)) {
Ethan Nicholas68990be2017-07-13 09:36:52 -0400169 const char* msg = "may not be present when constructor is overridden";
170 this->failOnSection(CONSTRUCTOR_CODE_SECTION, msg);
171 this->failOnSection(CONSTRUCTOR_PARAMS_SECTION, msg);
172 this->failOnSection(COORD_TRANSFORM_SECTION, msg);
173 this->failOnSection(INITIALIZERS_SECTION, msg);
174 this->failOnSection(OPTIMIZATION_FLAGS_SECTION, msg);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400175 }
176 this->writef(" %s(", fFullName.c_str());
177 const char* separator = "";
Ethan Nicholas68990be2017-07-13 09:36:52 -0400178 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
Ethan Nicholasc9472af2017-10-10 16:30:21 -0400179 this->writef("%s%s %s", separator, ParameterType(fContext, param->fType).c_str(),
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700180 String(param->fName).c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -0400181 separator = ", ";
182 }
183 this->writeSection(CONSTRUCTOR_PARAMS_SECTION, separator);
184 this->writef(")\n"
Ethan Nicholasabff9562017-10-09 10:54:08 -0400185 " : INHERITED(k%s_ClassID", fFullName.c_str());
186 if (!this->writeSection(OPTIMIZATION_FLAGS_SECTION, ", (OptimizationFlags) ")) {
187 this->writef(", kNone_OptimizationFlags");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400188 }
189 this->writef(")");
190 this->writeSection(INITIALIZERS_SECTION, "\n , ");
Ethan Nicholas68990be2017-07-13 09:36:52 -0400191 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700192 String nameString(param->fName);
193 const char* name = nameString.c_str();
Ethan Nicholas762466e2017-06-29 10:03:38 -0400194 if (param->fType.kind() == Type::kSampler_Kind) {
Ethan Nicholas68990be2017-07-13 09:36:52 -0400195 this->writef("\n , %s(std::move(%s)", FieldName(name).c_str(), name);
196 for (const Section* s : fSectionAndParameterHelper.getSections(
197 SAMPLER_PARAMS_SECTION)) {
198 if (s->fArgument == name) {
199 this->writef(", %s", s->fText.c_str());
200 }
201 }
202 this->writef(")");
Ethan Nicholasc9472af2017-10-10 16:30:21 -0400203 } else if (param->fType == *fContext.fFragmentProcessor_Type) {
204 // do nothing
Ethan Nicholas762466e2017-06-29 10:03:38 -0400205 } else {
206 this->writef("\n , %s(%s)", FieldName(name).c_str(), name);
207 }
208 }
Ethan Nicholas68990be2017-07-13 09:36:52 -0400209 for (const Section* s : fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION)) {
210 String field = FieldName(s->fArgument.c_str());
211 this->writef("\n , %sCoordTransform(%s, %s.proxy())", field.c_str(), s->fText.c_str(),
212 field.c_str());
213 }
Ethan Nicholas762466e2017-06-29 10:03:38 -0400214 this->writef(" {\n");
215 this->writeSection(CONSTRUCTOR_CODE_SECTION);
Ethan Nicholas68990be2017-07-13 09:36:52 -0400216 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400217 if (param->fType.kind() == Type::kSampler_Kind) {
218 this->writef(" this->addTextureSampler(&%s);\n",
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700219 FieldName(String(param->fName).c_str()).c_str());
Ethan Nicholasc9472af2017-10-10 16:30:21 -0400220 } else if (param->fType == *fContext.fFragmentProcessor_Type) {
221 this->writef(" this->registerChildProcessor(std::move(%s));",
222 String(param->fName).c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -0400223 }
224 }
Ethan Nicholas68990be2017-07-13 09:36:52 -0400225 for (const Section* s : fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION)) {
226 String field = FieldName(s->fArgument.c_str());
227 this->writef(" this->addCoordTransform(&%sCoordTransform);\n", field.c_str());
228 }
Ethan Nicholasabff9562017-10-09 10:54:08 -0400229 this->writef(" }\n");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400230}
231
232void HCodeGenerator::writeFields() {
233 this->writeSection(FIELDS_SECTION);
Ethan Nicholas68990be2017-07-13 09:36:52 -0400234 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
Ethan Nicholasc9472af2017-10-10 16:30:21 -0400235 if (param->fType == *fContext.fFragmentProcessor_Type) {
236 continue;
237 }
238 this->writef(" %s %s;\n", FieldType(fContext, param->fType).c_str(),
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700239 FieldName(String(param->fName).c_str()).c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -0400240 }
Ethan Nicholas68990be2017-07-13 09:36:52 -0400241 for (const Section* s : fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION)) {
242 this->writef(" GrCoordTransform %sCoordTransform;\n",
243 FieldName(s->fArgument.c_str()).c_str());
244 }
Ethan Nicholas762466e2017-06-29 10:03:38 -0400245}
246
247bool HCodeGenerator::generateCode() {
248 this->writef(kFragmentProcessorHeader, fFullName.c_str());
249 this->writef("#ifndef %s_DEFINED\n"
Ethan Nicholas9fb036f2017-07-05 16:19:09 -0400250 "#define %s_DEFINED\n",
251 fFullName.c_str(),
252 fFullName.c_str());
Ethan Nicholasceb4d482017-07-10 15:40:20 -0400253 this->writef("#include \"SkTypes.h\"\n"
254 "#if SK_SUPPORT_GPU\n");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400255 this->writeSection(HEADER_SECTION);
Ethan Nicholas9fb036f2017-07-05 16:19:09 -0400256 this->writef("#include \"GrFragmentProcessor.h\"\n"
Brian Osman1cb41712017-10-19 12:54:52 -0400257 "#include \"GrCoordTransform.h\"\n");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400258 this->writef("class %s : public GrFragmentProcessor {\n"
259 "public:\n",
260 fFullName.c_str());
261 this->writeSection(CLASS_SECTION);
Ethan Nicholas68990be2017-07-13 09:36:52 -0400262 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
Ethan Nicholasc9472af2017-10-10 16:30:21 -0400263 if (param->fType.kind() == Type::kSampler_Kind ||
264 param->fType.kind() == Type::kOther_Kind) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400265 continue;
266 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700267 String nameString(param->fName);
268 const char* name = nameString.c_str();
Ethan Nicholas9fb036f2017-07-05 16:19:09 -0400269 this->writef(" %s %s() const { return %s; }\n",
Ethan Nicholasc9472af2017-10-10 16:30:21 -0400270 FieldType(fContext, param->fType).c_str(), name, FieldName(name).c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -0400271 }
272 this->writeMake();
Ethan Nicholasf57c0d62017-07-31 11:18:22 -0400273 this->writef(" %s(const %s& src);\n"
Brian Salomonaff329b2017-08-11 09:40:37 -0400274 " std::unique_ptr<GrFragmentProcessor> clone() const override;\n"
Ethan Nicholasf57c0d62017-07-31 11:18:22 -0400275 " const char* name() const override { return \"%s\"; }\n"
Ethan Nicholas762466e2017-06-29 10:03:38 -0400276 "private:\n",
Ethan Nicholasf57c0d62017-07-31 11:18:22 -0400277 fFullName.c_str(), fFullName.c_str(), fName.c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -0400278 this->writeConstructor();
279 this->writef(" GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;\n"
280 " void onGetGLSLProcessorKey(const GrShaderCaps&,"
281 "GrProcessorKeyBuilder*) const override;\n"
282 " bool onIsEqual(const GrFragmentProcessor&) const override;\n"
Brian Salomon0c26a9d2017-07-06 10:09:38 -0400283 " GR_DECLARE_FRAGMENT_PROCESSOR_TEST\n");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400284 this->writeFields();
285 this->writef(" typedef GrFragmentProcessor INHERITED;\n"
Ethan Nicholas9fb036f2017-07-05 16:19:09 -0400286 "};\n");
287 this->writeSection(HEADER_END_SECTION);
Ethan Nicholasceb4d482017-07-10 15:40:20 -0400288 this->writef("#endif\n"
289 "#endif\n");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400290 return 0 == fErrors.errorCount();
291}
292
293} // namespace