blob: a4a5c9a6ace22f7f547aa492aa52c08a2b8cf4c8 [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.fColorSpaceXform_Type) {
Ethan Nicholas762466e2017-06-29 10:03:38 -040040 return "sk_sp<GrColorSpaceXform>";
Ethan Nicholasc9472af2017-10-10 16:30:21 -040041 } else if (type == *context.fFragmentProcessor_Type) {
42 return "std::unique_ptr<GrFragmentProcessor>";
Ethan Nicholas762466e2017-06-29 10:03:38 -040043 }
44 return type.name();
45}
46
Ethan Nicholasc9472af2017-10-10 16:30:21 -040047String HCodeGenerator::FieldType(const Context& context, const Type& type) {
Ethan Nicholas762466e2017-06-29 10:03:38 -040048 if (type.kind() == Type::kSampler_Kind) {
49 return "TextureSampler";
Ethan Nicholasc9472af2017-10-10 16:30:21 -040050 } else if (type == *context.fFragmentProcessor_Type) {
51 // we don't store fragment processors in fields, they get registered via
52 // registerChildProcessor instead
53 ASSERT(false);
54 return "<error>";
Ethan Nicholas762466e2017-06-29 10:03:38 -040055 }
Ethan Nicholasc9472af2017-10-10 16:30:21 -040056 return ParameterType(context, type);
Ethan Nicholas762466e2017-06-29 10:03:38 -040057}
58
59void HCodeGenerator::writef(const char* s, va_list va) {
60 static constexpr int BUFFER_SIZE = 1024;
Ethan Nicholas9fb036f2017-07-05 16:19:09 -040061 va_list copy;
62 va_copy(copy, va);
Ethan Nicholas762466e2017-06-29 10:03:38 -040063 char buffer[BUFFER_SIZE];
64 int length = vsnprintf(buffer, BUFFER_SIZE, s, va);
65 if (length < BUFFER_SIZE) {
66 fOut->write(buffer, length);
67 } else {
68 std::unique_ptr<char[]> heap(new char[length + 1]);
Ethan Nicholas9fb036f2017-07-05 16:19:09 -040069 vsprintf(heap.get(), s, copy);
Ethan Nicholas762466e2017-06-29 10:03:38 -040070 fOut->write(heap.get(), length);
71 }
72}
73
74void HCodeGenerator::writef(const char* s, ...) {
75 va_list va;
76 va_start(va, s);
77 this->writef(s, va);
78 va_end(va);
79}
80
81bool HCodeGenerator::writeSection(const char* name, const char* prefix) {
Ethan Nicholas68990be2017-07-13 09:36:52 -040082 const Section* s = fSectionAndParameterHelper.getSection(name);
83 if (s) {
84 this->writef("%s%s", prefix, s->fText.c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -040085 return true;
86 }
87 return false;
88}
89
90void HCodeGenerator::writeExtraConstructorParams(const char* separator) {
91 // super-simple parse, just assume the last token before a comma is the name of a parameter
92 // (which is true as long as there are no multi-parameter template types involved). Will replace
93 // this with something more robust if the need arises.
Ethan Nicholas68990be2017-07-13 09:36:52 -040094 const Section* section = fSectionAndParameterHelper.getSection(CONSTRUCTOR_PARAMS_SECTION);
95 if (section) {
96 const char* s = section->fText.c_str();
Ethan Nicholas762466e2017-06-29 10:03:38 -040097 #define BUFFER_SIZE 64
98 char lastIdentifier[BUFFER_SIZE];
99 int lastIdentifierLength = 0;
100 bool foundBreak = false;
101 while (*s) {
102 char c = *s;
103 ++s;
104 if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
105 c == '_') {
106 if (foundBreak) {
107 lastIdentifierLength = 0;
108 foundBreak = false;
109 }
110 ASSERT(lastIdentifierLength < BUFFER_SIZE);
111 lastIdentifier[lastIdentifierLength] = c;
112 ++lastIdentifierLength;
113 } else {
114 foundBreak = true;
115 if (c == ',') {
116 ASSERT(lastIdentifierLength < BUFFER_SIZE);
117 lastIdentifier[lastIdentifierLength] = 0;
118 this->writef("%s%s", separator, lastIdentifier);
119 separator = ", ";
120 } else if (c != ' ' && c != '\t' && c != '\n' && c != '\r') {
121 lastIdentifierLength = 0;
122 }
123 }
124 }
125 if (lastIdentifierLength) {
126 ASSERT(lastIdentifierLength < BUFFER_SIZE);
127 lastIdentifier[lastIdentifierLength] = 0;
128 this->writef("%s%s", separator, lastIdentifier);
129 }
130 }
131}
132
133void HCodeGenerator::writeMake() {
134 const char* separator;
135 if (!this->writeSection(MAKE_SECTION)) {
Brian Salomonaff329b2017-08-11 09:40:37 -0400136 this->writef(" static std::unique_ptr<GrFragmentProcessor> Make(");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400137 separator = "";
Ethan Nicholas68990be2017-07-13 09:36:52 -0400138 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
Ethan Nicholasc9472af2017-10-10 16:30:21 -0400139 this->writef("%s%s %s", separator, ParameterType(fContext, param->fType).c_str(),
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700140 String(param->fName).c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -0400141 separator = ", ";
142 }
143 this->writeSection(CONSTRUCTOR_PARAMS_SECTION, separator);
144 this->writef(") {\n"
Brian Salomonaff329b2017-08-11 09:40:37 -0400145 " return std::unique_ptr<GrFragmentProcessor>(new %s(",
Ethan Nicholas762466e2017-06-29 10:03:38 -0400146 fFullName.c_str());
147 separator = "";
Ethan Nicholas68990be2017-07-13 09:36:52 -0400148 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
Ethan Nicholasc9472af2017-10-10 16:30:21 -0400149 if (param->fType == *fContext.fFragmentProcessor_Type) {
150 this->writef("%s%s->clone()", separator, String(param->fName).c_str());
151 } else {
152 this->writef("%s%s", separator, String(param->fName).c_str());
153 }
Ethan Nicholas762466e2017-06-29 10:03:38 -0400154 separator = ", ";
155 }
156 this->writeExtraConstructorParams(separator);
157 this->writef("));\n"
158 " }\n");
159 }
160}
161
Ethan Nicholas68990be2017-07-13 09:36:52 -0400162void HCodeGenerator::failOnSection(const char* section, const char* msg) {
163 std::vector<const Section*> s = fSectionAndParameterHelper.getSections(section);
164 if (s.size()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700165 fErrors.error(s[0]->fOffset, String("@") + section + " " + msg);
Ethan Nicholas68990be2017-07-13 09:36:52 -0400166 }
167}
168
Ethan Nicholas762466e2017-06-29 10:03:38 -0400169void HCodeGenerator::writeConstructor() {
170 if (this->writeSection(CONSTRUCTOR_SECTION)) {
Ethan Nicholas68990be2017-07-13 09:36:52 -0400171 const char* msg = "may not be present when constructor is overridden";
172 this->failOnSection(CONSTRUCTOR_CODE_SECTION, msg);
173 this->failOnSection(CONSTRUCTOR_PARAMS_SECTION, msg);
174 this->failOnSection(COORD_TRANSFORM_SECTION, msg);
175 this->failOnSection(INITIALIZERS_SECTION, msg);
176 this->failOnSection(OPTIMIZATION_FLAGS_SECTION, msg);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400177 }
178 this->writef(" %s(", fFullName.c_str());
179 const char* separator = "";
Ethan Nicholas68990be2017-07-13 09:36:52 -0400180 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
Ethan Nicholasc9472af2017-10-10 16:30:21 -0400181 this->writef("%s%s %s", separator, ParameterType(fContext, param->fType).c_str(),
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700182 String(param->fName).c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -0400183 separator = ", ";
184 }
185 this->writeSection(CONSTRUCTOR_PARAMS_SECTION, separator);
186 this->writef(")\n"
Ethan Nicholasabff9562017-10-09 10:54:08 -0400187 " : INHERITED(k%s_ClassID", fFullName.c_str());
188 if (!this->writeSection(OPTIMIZATION_FLAGS_SECTION, ", (OptimizationFlags) ")) {
189 this->writef(", kNone_OptimizationFlags");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400190 }
191 this->writef(")");
192 this->writeSection(INITIALIZERS_SECTION, "\n , ");
Ethan Nicholas68990be2017-07-13 09:36:52 -0400193 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700194 String nameString(param->fName);
195 const char* name = nameString.c_str();
Ethan Nicholas762466e2017-06-29 10:03:38 -0400196 if (param->fType.kind() == Type::kSampler_Kind) {
Ethan Nicholas68990be2017-07-13 09:36:52 -0400197 this->writef("\n , %s(std::move(%s)", FieldName(name).c_str(), name);
198 for (const Section* s : fSectionAndParameterHelper.getSections(
199 SAMPLER_PARAMS_SECTION)) {
200 if (s->fArgument == name) {
201 this->writef(", %s", s->fText.c_str());
202 }
203 }
204 this->writef(")");
Ethan Nicholasc9472af2017-10-10 16:30:21 -0400205 } else if (param->fType == *fContext.fFragmentProcessor_Type) {
206 // do nothing
Ethan Nicholas762466e2017-06-29 10:03:38 -0400207 } else {
208 this->writef("\n , %s(%s)", FieldName(name).c_str(), name);
209 }
210 }
Ethan Nicholas68990be2017-07-13 09:36:52 -0400211 for (const Section* s : fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION)) {
212 String field = FieldName(s->fArgument.c_str());
213 this->writef("\n , %sCoordTransform(%s, %s.proxy())", field.c_str(), s->fText.c_str(),
214 field.c_str());
215 }
Ethan Nicholas762466e2017-06-29 10:03:38 -0400216 this->writef(" {\n");
217 this->writeSection(CONSTRUCTOR_CODE_SECTION);
Ethan Nicholas68990be2017-07-13 09:36:52 -0400218 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400219 if (param->fType.kind() == Type::kSampler_Kind) {
220 this->writef(" this->addTextureSampler(&%s);\n",
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700221 FieldName(String(param->fName).c_str()).c_str());
Ethan Nicholasc9472af2017-10-10 16:30:21 -0400222 } else if (param->fType == *fContext.fFragmentProcessor_Type) {
223 this->writef(" this->registerChildProcessor(std::move(%s));",
224 String(param->fName).c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -0400225 }
226 }
Ethan Nicholas68990be2017-07-13 09:36:52 -0400227 for (const Section* s : fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION)) {
228 String field = FieldName(s->fArgument.c_str());
229 this->writef(" this->addCoordTransform(&%sCoordTransform);\n", field.c_str());
230 }
Ethan Nicholasabff9562017-10-09 10:54:08 -0400231 this->writef(" }\n");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400232}
233
234void HCodeGenerator::writeFields() {
235 this->writeSection(FIELDS_SECTION);
Ethan Nicholas68990be2017-07-13 09:36:52 -0400236 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
Ethan Nicholasc9472af2017-10-10 16:30:21 -0400237 if (param->fType == *fContext.fFragmentProcessor_Type) {
238 continue;
239 }
240 this->writef(" %s %s;\n", FieldType(fContext, param->fType).c_str(),
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700241 FieldName(String(param->fName).c_str()).c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -0400242 }
Ethan Nicholas68990be2017-07-13 09:36:52 -0400243 for (const Section* s : fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION)) {
244 this->writef(" GrCoordTransform %sCoordTransform;\n",
245 FieldName(s->fArgument.c_str()).c_str());
246 }
Ethan Nicholas762466e2017-06-29 10:03:38 -0400247}
248
249bool HCodeGenerator::generateCode() {
250 this->writef(kFragmentProcessorHeader, fFullName.c_str());
251 this->writef("#ifndef %s_DEFINED\n"
Ethan Nicholas9fb036f2017-07-05 16:19:09 -0400252 "#define %s_DEFINED\n",
253 fFullName.c_str(),
254 fFullName.c_str());
Ethan Nicholasceb4d482017-07-10 15:40:20 -0400255 this->writef("#include \"SkTypes.h\"\n"
256 "#if SK_SUPPORT_GPU\n");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400257 this->writeSection(HEADER_SECTION);
Ethan Nicholas9fb036f2017-07-05 16:19:09 -0400258 this->writef("#include \"GrFragmentProcessor.h\"\n"
259 "#include \"GrCoordTransform.h\"\n"
Brian Salomon71603cc2017-07-27 22:23:39 -0400260 "#include \"GrColorSpaceXform.h\"\n");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400261 this->writef("class %s : public GrFragmentProcessor {\n"
262 "public:\n",
263 fFullName.c_str());
264 this->writeSection(CLASS_SECTION);
Ethan Nicholas68990be2017-07-13 09:36:52 -0400265 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
Ethan Nicholasc9472af2017-10-10 16:30:21 -0400266 if (param->fType.kind() == Type::kSampler_Kind ||
267 param->fType.kind() == Type::kOther_Kind) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400268 continue;
269 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700270 String nameString(param->fName);
271 const char* name = nameString.c_str();
Ethan Nicholas9fb036f2017-07-05 16:19:09 -0400272 this->writef(" %s %s() const { return %s; }\n",
Ethan Nicholasc9472af2017-10-10 16:30:21 -0400273 FieldType(fContext, param->fType).c_str(), name, FieldName(name).c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -0400274 }
275 this->writeMake();
Ethan Nicholasf57c0d62017-07-31 11:18:22 -0400276 this->writef(" %s(const %s& src);\n"
Brian Salomonaff329b2017-08-11 09:40:37 -0400277 " std::unique_ptr<GrFragmentProcessor> clone() const override;\n"
Ethan Nicholasf57c0d62017-07-31 11:18:22 -0400278 " const char* name() const override { return \"%s\"; }\n"
Ethan Nicholas762466e2017-06-29 10:03:38 -0400279 "private:\n",
Ethan Nicholasf57c0d62017-07-31 11:18:22 -0400280 fFullName.c_str(), fFullName.c_str(), fName.c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -0400281 this->writeConstructor();
282 this->writef(" GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;\n"
283 " void onGetGLSLProcessorKey(const GrShaderCaps&,"
284 "GrProcessorKeyBuilder*) const override;\n"
285 " bool onIsEqual(const GrFragmentProcessor&) const override;\n"
Brian Salomon0c26a9d2017-07-06 10:09:38 -0400286 " GR_DECLARE_FRAGMENT_PROCESSOR_TEST\n");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400287 this->writeFields();
288 this->writef(" typedef GrFragmentProcessor INHERITED;\n"
Ethan Nicholas9fb036f2017-07-05 16:19:09 -0400289 "};\n");
290 this->writeSection(HEADER_END_SECTION);
Ethan Nicholasceb4d482017-07-10 15:40:20 -0400291 this->writef("#endif\n"
292 "#endif\n");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400293 return 0 == fErrors.errorCount();
294}
295
296} // namespace