blob: eb8263187f51bbf2d5af6ca1e5915bc9f51a4db8 [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
18HCodeGenerator::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
25String HCodeGenerator::ParameterType(const Type& type) {
Ethan Nicholas8aa45692017-09-20 11:24:15 -040026 if (type.name() == "float" || type.name() == "half") {
Ethan Nicholasf7b88202017-09-18 14:10:39 -040027 return "float";
Ethan Nicholas8aa45692017-09-20 11:24:15 -040028 } else if (type.name() == "float2" || type.name() == "half2") {
Ethan Nicholas762466e2017-06-29 10:03:38 -040029 return "SkPoint";
Ethan Nicholasf7b88202017-09-18 14:10:39 -040030 } else if (type.name() == "int4" || type.name() == "short4") {
Ethan Nicholas762466e2017-06-29 10:03:38 -040031 return "SkIRect";
Ethan Nicholas8aa45692017-09-20 11:24:15 -040032 } else if (type.name() == "float4" || type.name() == "half4") {
Ethan Nicholas762466e2017-06-29 10:03:38 -040033 return "SkRect";
Ethan Nicholas8aa45692017-09-20 11:24:15 -040034 } else if (type.name() == "float4x4" || type.name() == "half4x4") {
Ethan Nicholas762466e2017-06-29 10:03:38 -040035 return "SkMatrix44";
36 } else if (type.kind() == Type::kSampler_Kind) {
37 return "sk_sp<GrTextureProxy>";
Ethan Nicholas5b5f0962017-09-11 13:50:14 -070038 } else if (type.name() == "colorSpaceXform") {
Ethan Nicholas762466e2017-06-29 10:03:38 -040039 return "sk_sp<GrColorSpaceXform>";
40 }
41 return type.name();
42}
43
44String HCodeGenerator::FieldType(const Type& type) {
45 if (type.kind() == Type::kSampler_Kind) {
46 return "TextureSampler";
47 }
48 return ParameterType(type);
49}
50
51void HCodeGenerator::writef(const char* s, va_list va) {
52 static constexpr int BUFFER_SIZE = 1024;
Ethan Nicholas9fb036f2017-07-05 16:19:09 -040053 va_list copy;
54 va_copy(copy, va);
Ethan Nicholas762466e2017-06-29 10:03:38 -040055 char buffer[BUFFER_SIZE];
56 int length = vsnprintf(buffer, BUFFER_SIZE, s, va);
57 if (length < BUFFER_SIZE) {
58 fOut->write(buffer, length);
59 } else {
60 std::unique_ptr<char[]> heap(new char[length + 1]);
Ethan Nicholas9fb036f2017-07-05 16:19:09 -040061 vsprintf(heap.get(), s, copy);
Ethan Nicholas762466e2017-06-29 10:03:38 -040062 fOut->write(heap.get(), length);
63 }
64}
65
66void HCodeGenerator::writef(const char* s, ...) {
67 va_list va;
68 va_start(va, s);
69 this->writef(s, va);
70 va_end(va);
71}
72
73bool HCodeGenerator::writeSection(const char* name, const char* prefix) {
Ethan Nicholas68990be2017-07-13 09:36:52 -040074 const Section* s = fSectionAndParameterHelper.getSection(name);
75 if (s) {
76 this->writef("%s%s", prefix, s->fText.c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -040077 return true;
78 }
79 return false;
80}
81
82void HCodeGenerator::writeExtraConstructorParams(const char* separator) {
83 // super-simple parse, just assume the last token before a comma is the name of a parameter
84 // (which is true as long as there are no multi-parameter template types involved). Will replace
85 // this with something more robust if the need arises.
Ethan Nicholas68990be2017-07-13 09:36:52 -040086 const Section* section = fSectionAndParameterHelper.getSection(CONSTRUCTOR_PARAMS_SECTION);
87 if (section) {
88 const char* s = section->fText.c_str();
Ethan Nicholas762466e2017-06-29 10:03:38 -040089 #define BUFFER_SIZE 64
90 char lastIdentifier[BUFFER_SIZE];
91 int lastIdentifierLength = 0;
92 bool foundBreak = false;
93 while (*s) {
94 char c = *s;
95 ++s;
96 if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
97 c == '_') {
98 if (foundBreak) {
99 lastIdentifierLength = 0;
100 foundBreak = false;
101 }
102 ASSERT(lastIdentifierLength < BUFFER_SIZE);
103 lastIdentifier[lastIdentifierLength] = c;
104 ++lastIdentifierLength;
105 } else {
106 foundBreak = true;
107 if (c == ',') {
108 ASSERT(lastIdentifierLength < BUFFER_SIZE);
109 lastIdentifier[lastIdentifierLength] = 0;
110 this->writef("%s%s", separator, lastIdentifier);
111 separator = ", ";
112 } else if (c != ' ' && c != '\t' && c != '\n' && c != '\r') {
113 lastIdentifierLength = 0;
114 }
115 }
116 }
117 if (lastIdentifierLength) {
118 ASSERT(lastIdentifierLength < BUFFER_SIZE);
119 lastIdentifier[lastIdentifierLength] = 0;
120 this->writef("%s%s", separator, lastIdentifier);
121 }
122 }
123}
124
125void HCodeGenerator::writeMake() {
126 const char* separator;
127 if (!this->writeSection(MAKE_SECTION)) {
Brian Salomonaff329b2017-08-11 09:40:37 -0400128 this->writef(" static std::unique_ptr<GrFragmentProcessor> Make(");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400129 separator = "";
Ethan Nicholas68990be2017-07-13 09:36:52 -0400130 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400131 this->writef("%s%s %s", separator, ParameterType(param->fType).c_str(),
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700132 String(param->fName).c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -0400133 separator = ", ";
134 }
135 this->writeSection(CONSTRUCTOR_PARAMS_SECTION, separator);
136 this->writef(") {\n"
Brian Salomonaff329b2017-08-11 09:40:37 -0400137 " return std::unique_ptr<GrFragmentProcessor>(new %s(",
Ethan Nicholas762466e2017-06-29 10:03:38 -0400138 fFullName.c_str());
139 separator = "";
Ethan Nicholas68990be2017-07-13 09:36:52 -0400140 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700141 this->writef("%s%s", separator, String(param->fName).c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -0400142 separator = ", ";
143 }
144 this->writeExtraConstructorParams(separator);
145 this->writef("));\n"
146 " }\n");
147 }
148}
149
Ethan Nicholas68990be2017-07-13 09:36:52 -0400150void HCodeGenerator::failOnSection(const char* section, const char* msg) {
151 std::vector<const Section*> s = fSectionAndParameterHelper.getSections(section);
152 if (s.size()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700153 fErrors.error(s[0]->fOffset, String("@") + section + " " + msg);
Ethan Nicholas68990be2017-07-13 09:36:52 -0400154 }
155}
156
Ethan Nicholas762466e2017-06-29 10:03:38 -0400157void HCodeGenerator::writeConstructor() {
158 if (this->writeSection(CONSTRUCTOR_SECTION)) {
Ethan Nicholas68990be2017-07-13 09:36:52 -0400159 const char* msg = "may not be present when constructor is overridden";
160 this->failOnSection(CONSTRUCTOR_CODE_SECTION, msg);
161 this->failOnSection(CONSTRUCTOR_PARAMS_SECTION, msg);
162 this->failOnSection(COORD_TRANSFORM_SECTION, msg);
163 this->failOnSection(INITIALIZERS_SECTION, msg);
164 this->failOnSection(OPTIMIZATION_FLAGS_SECTION, msg);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400165 }
166 this->writef(" %s(", fFullName.c_str());
167 const char* separator = "";
Ethan Nicholas68990be2017-07-13 09:36:52 -0400168 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400169 this->writef("%s%s %s", separator, ParameterType(param->fType).c_str(),
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700170 String(param->fName).c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -0400171 separator = ", ";
172 }
173 this->writeSection(CONSTRUCTOR_PARAMS_SECTION, separator);
174 this->writef(")\n"
Ethan Nicholasabff9562017-10-09 10:54:08 -0400175 " : INHERITED(k%s_ClassID", fFullName.c_str());
176 if (!this->writeSection(OPTIMIZATION_FLAGS_SECTION, ", (OptimizationFlags) ")) {
177 this->writef(", kNone_OptimizationFlags");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400178 }
179 this->writef(")");
180 this->writeSection(INITIALIZERS_SECTION, "\n , ");
Ethan Nicholas68990be2017-07-13 09:36:52 -0400181 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700182 String nameString(param->fName);
183 const char* name = nameString.c_str();
Ethan Nicholas762466e2017-06-29 10:03:38 -0400184 if (param->fType.kind() == Type::kSampler_Kind) {
Ethan Nicholas68990be2017-07-13 09:36:52 -0400185 this->writef("\n , %s(std::move(%s)", FieldName(name).c_str(), name);
186 for (const Section* s : fSectionAndParameterHelper.getSections(
187 SAMPLER_PARAMS_SECTION)) {
188 if (s->fArgument == name) {
189 this->writef(", %s", s->fText.c_str());
190 }
191 }
192 this->writef(")");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400193 } else {
194 this->writef("\n , %s(%s)", FieldName(name).c_str(), name);
195 }
196 }
Ethan Nicholas68990be2017-07-13 09:36:52 -0400197 for (const Section* s : fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION)) {
198 String field = FieldName(s->fArgument.c_str());
199 this->writef("\n , %sCoordTransform(%s, %s.proxy())", field.c_str(), s->fText.c_str(),
200 field.c_str());
201 }
Ethan Nicholas762466e2017-06-29 10:03:38 -0400202 this->writef(" {\n");
203 this->writeSection(CONSTRUCTOR_CODE_SECTION);
Ethan Nicholas68990be2017-07-13 09:36:52 -0400204 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400205 if (param->fType.kind() == Type::kSampler_Kind) {
206 this->writef(" this->addTextureSampler(&%s);\n",
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700207 FieldName(String(param->fName).c_str()).c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -0400208 }
209 }
Ethan Nicholas68990be2017-07-13 09:36:52 -0400210 for (const Section* s : fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION)) {
211 String field = FieldName(s->fArgument.c_str());
212 this->writef(" this->addCoordTransform(&%sCoordTransform);\n", field.c_str());
213 }
Ethan Nicholasabff9562017-10-09 10:54:08 -0400214 this->writef(" }\n");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400215}
216
217void HCodeGenerator::writeFields() {
218 this->writeSection(FIELDS_SECTION);
Ethan Nicholas68990be2017-07-13 09:36:52 -0400219 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700220 this->writef(" %s %s;\n", FieldType(param->fType).c_str(),
221 FieldName(String(param->fName).c_str()).c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -0400222 }
Ethan Nicholas68990be2017-07-13 09:36:52 -0400223 for (const Section* s : fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION)) {
224 this->writef(" GrCoordTransform %sCoordTransform;\n",
225 FieldName(s->fArgument.c_str()).c_str());
226 }
Ethan Nicholas762466e2017-06-29 10:03:38 -0400227}
228
229bool HCodeGenerator::generateCode() {
230 this->writef(kFragmentProcessorHeader, fFullName.c_str());
231 this->writef("#ifndef %s_DEFINED\n"
Ethan Nicholas9fb036f2017-07-05 16:19:09 -0400232 "#define %s_DEFINED\n",
233 fFullName.c_str(),
234 fFullName.c_str());
Ethan Nicholasceb4d482017-07-10 15:40:20 -0400235 this->writef("#include \"SkTypes.h\"\n"
236 "#if SK_SUPPORT_GPU\n");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400237 this->writeSection(HEADER_SECTION);
Ethan Nicholas9fb036f2017-07-05 16:19:09 -0400238 this->writef("#include \"GrFragmentProcessor.h\"\n"
239 "#include \"GrCoordTransform.h\"\n"
Brian Salomon71603cc2017-07-27 22:23:39 -0400240 "#include \"GrColorSpaceXform.h\"\n");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400241 this->writef("class %s : public GrFragmentProcessor {\n"
242 "public:\n",
243 fFullName.c_str());
244 this->writeSection(CLASS_SECTION);
Ethan Nicholas68990be2017-07-13 09:36:52 -0400245 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400246 if (param->fType.kind() == Type::kSampler_Kind) {
247 continue;
248 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700249 String nameString(param->fName);
250 const char* name = nameString.c_str();
Ethan Nicholas9fb036f2017-07-05 16:19:09 -0400251 this->writef(" %s %s() const { return %s; }\n",
Ethan Nicholas762466e2017-06-29 10:03:38 -0400252 FieldType(param->fType).c_str(), name, FieldName(name).c_str());
253 }
254 this->writeMake();
Ethan Nicholasf57c0d62017-07-31 11:18:22 -0400255 this->writef(" %s(const %s& src);\n"
Brian Salomonaff329b2017-08-11 09:40:37 -0400256 " std::unique_ptr<GrFragmentProcessor> clone() const override;\n"
Ethan Nicholasf57c0d62017-07-31 11:18:22 -0400257 " const char* name() const override { return \"%s\"; }\n"
Ethan Nicholas762466e2017-06-29 10:03:38 -0400258 "private:\n",
Ethan Nicholasf57c0d62017-07-31 11:18:22 -0400259 fFullName.c_str(), fFullName.c_str(), fName.c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -0400260 this->writeConstructor();
261 this->writef(" GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;\n"
262 " void onGetGLSLProcessorKey(const GrShaderCaps&,"
263 "GrProcessorKeyBuilder*) const override;\n"
264 " bool onIsEqual(const GrFragmentProcessor&) const override;\n"
Brian Salomon0c26a9d2017-07-06 10:09:38 -0400265 " GR_DECLARE_FRAGMENT_PROCESSOR_TEST\n");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400266 this->writeFields();
267 this->writef(" typedef GrFragmentProcessor INHERITED;\n"
Ethan Nicholas9fb036f2017-07-05 16:19:09 -0400268 "};\n");
269 this->writeSection(HEADER_END_SECTION);
Ethan Nicholasceb4d482017-07-10 15:40:20 -0400270 this->writef("#endif\n"
271 "#endif\n");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400272 return 0 == fErrors.errorCount();
273}
274
275} // namespace