blob: 0acd33404f9eb21244a7bb118b695c3b7b8e1c18 [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
Ethan Nicholas130fb3f2018-02-01 12:14:34 -050010#include "SkSLParser.h"
Ethan Nicholas762466e2017-06-29 10:03:38 -040011#include "SkSLUtil.h"
Ethan Nicholasaae47c82017-11-10 15:34:03 -050012#include "ir/SkSLEnum.h"
Ethan Nicholas762466e2017-06-29 10:03:38 -040013#include "ir/SkSLFunctionDeclaration.h"
14#include "ir/SkSLFunctionDefinition.h"
15#include "ir/SkSLSection.h"
16#include "ir/SkSLVarDeclarations.h"
17
18namespace SkSL {
19
Ethan Nicholasc9472af2017-10-10 16:30:21 -040020HCodeGenerator::HCodeGenerator(const Context* context, const Program* program,
21 ErrorReporter* errors, String name, OutputStream* out)
Ethan Nicholas762466e2017-06-29 10:03:38 -040022: INHERITED(program, errors, out)
Ethan Nicholasc9472af2017-10-10 16:30:21 -040023, fContext(*context)
Ethan Nicholas762466e2017-06-29 10:03:38 -040024, fName(std::move(name))
25, fFullName(String::printf("Gr%s", fName.c_str()))
26, fSectionAndParameterHelper(*program, *errors) {}
27
Ethan Nicholasd608c092017-10-26 09:30:08 -040028String HCodeGenerator::ParameterType(const Context& context, const Type& type,
29 const Layout& layout) {
30 if (layout.fCType != "") {
31 return layout.fCType;
32 } else if (type == *context.fFloat_Type || type == *context.fHalf_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -040033 return "float";
Ethan Nicholasc9472af2017-10-10 16:30:21 -040034 } else if (type == *context.fFloat2_Type || type == *context.fHalf2_Type) {
Ethan Nicholas762466e2017-06-29 10:03:38 -040035 return "SkPoint";
Ruiqi Maob609e6d2018-07-17 10:19:38 -040036 } else if (type == *context.fInt4_Type ||
37 type == *context.fShort4_Type ||
38 type == *context.fByte4_Type) {
Ethan Nicholas762466e2017-06-29 10:03:38 -040039 return "SkIRect";
Ethan Nicholasc9472af2017-10-10 16:30:21 -040040 } else if (type == *context.fFloat4_Type || type == *context.fHalf4_Type) {
Ethan Nicholas762466e2017-06-29 10:03:38 -040041 return "SkRect";
Ethan Nicholasc9472af2017-10-10 16:30:21 -040042 } else if (type == *context.fFloat4x4_Type || type == *context.fHalf4x4_Type) {
Ethan Nicholas762466e2017-06-29 10:03:38 -040043 return "SkMatrix44";
44 } else if (type.kind() == Type::kSampler_Kind) {
45 return "sk_sp<GrTextureProxy>";
Ethan Nicholasc9472af2017-10-10 16:30:21 -040046 } else if (type == *context.fFragmentProcessor_Type) {
47 return "std::unique_ptr<GrFragmentProcessor>";
Ethan Nicholas762466e2017-06-29 10:03:38 -040048 }
49 return type.name();
50}
51
Ethan Nicholasd608c092017-10-26 09:30:08 -040052String HCodeGenerator::FieldType(const Context& context, const Type& type,
53 const Layout& layout) {
Ethan Nicholas762466e2017-06-29 10:03:38 -040054 if (type.kind() == Type::kSampler_Kind) {
55 return "TextureSampler";
Ethan Nicholasc9472af2017-10-10 16:30:21 -040056 } else if (type == *context.fFragmentProcessor_Type) {
57 // we don't store fragment processors in fields, they get registered via
58 // registerChildProcessor instead
Ethan Nicholasd9d33c32018-06-12 11:05:59 -040059 SkASSERT(false);
Ethan Nicholasc9472af2017-10-10 16:30:21 -040060 return "<error>";
Ethan Nicholas762466e2017-06-29 10:03:38 -040061 }
Ethan Nicholasd608c092017-10-26 09:30:08 -040062 return ParameterType(context, type, layout);
Ethan Nicholas762466e2017-06-29 10:03:38 -040063}
64
65void HCodeGenerator::writef(const char* s, va_list va) {
66 static constexpr int BUFFER_SIZE = 1024;
Ethan Nicholas9fb036f2017-07-05 16:19:09 -040067 va_list copy;
68 va_copy(copy, va);
Ethan Nicholas762466e2017-06-29 10:03:38 -040069 char buffer[BUFFER_SIZE];
70 int length = vsnprintf(buffer, BUFFER_SIZE, s, va);
71 if (length < BUFFER_SIZE) {
72 fOut->write(buffer, length);
73 } else {
74 std::unique_ptr<char[]> heap(new char[length + 1]);
Ethan Nicholas9fb036f2017-07-05 16:19:09 -040075 vsprintf(heap.get(), s, copy);
Ethan Nicholas762466e2017-06-29 10:03:38 -040076 fOut->write(heap.get(), length);
77 }
78}
79
80void HCodeGenerator::writef(const char* s, ...) {
81 va_list va;
82 va_start(va, s);
83 this->writef(s, va);
84 va_end(va);
85}
86
87bool HCodeGenerator::writeSection(const char* name, const char* prefix) {
Ethan Nicholas68990be2017-07-13 09:36:52 -040088 const Section* s = fSectionAndParameterHelper.getSection(name);
89 if (s) {
90 this->writef("%s%s", prefix, s->fText.c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -040091 return true;
92 }
93 return false;
94}
95
96void HCodeGenerator::writeExtraConstructorParams(const char* separator) {
97 // super-simple parse, just assume the last token before a comma is the name of a parameter
98 // (which is true as long as there are no multi-parameter template types involved). Will replace
99 // this with something more robust if the need arises.
Ethan Nicholas68990be2017-07-13 09:36:52 -0400100 const Section* section = fSectionAndParameterHelper.getSection(CONSTRUCTOR_PARAMS_SECTION);
101 if (section) {
102 const char* s = section->fText.c_str();
Ethan Nicholas762466e2017-06-29 10:03:38 -0400103 #define BUFFER_SIZE 64
104 char lastIdentifier[BUFFER_SIZE];
105 int lastIdentifierLength = 0;
106 bool foundBreak = false;
107 while (*s) {
108 char c = *s;
109 ++s;
110 if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
111 c == '_') {
112 if (foundBreak) {
113 lastIdentifierLength = 0;
114 foundBreak = false;
115 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400116 SkASSERT(lastIdentifierLength < BUFFER_SIZE);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400117 lastIdentifier[lastIdentifierLength] = c;
118 ++lastIdentifierLength;
119 } else {
120 foundBreak = true;
121 if (c == ',') {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400122 SkASSERT(lastIdentifierLength < BUFFER_SIZE);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400123 lastIdentifier[lastIdentifierLength] = 0;
124 this->writef("%s%s", separator, lastIdentifier);
125 separator = ", ";
126 } else if (c != ' ' && c != '\t' && c != '\n' && c != '\r') {
127 lastIdentifierLength = 0;
128 }
129 }
130 }
131 if (lastIdentifierLength) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400132 SkASSERT(lastIdentifierLength < BUFFER_SIZE);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400133 lastIdentifier[lastIdentifierLength] = 0;
134 this->writef("%s%s", separator, lastIdentifier);
135 }
136 }
137}
138
139void HCodeGenerator::writeMake() {
140 const char* separator;
141 if (!this->writeSection(MAKE_SECTION)) {
Brian Salomonaff329b2017-08-11 09:40:37 -0400142 this->writef(" static std::unique_ptr<GrFragmentProcessor> Make(");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400143 separator = "";
Ethan Nicholas68990be2017-07-13 09:36:52 -0400144 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
Ethan Nicholasd608c092017-10-26 09:30:08 -0400145 this->writef("%s%s %s", separator, ParameterType(fContext, param->fType,
146 param->fModifiers.fLayout).c_str(),
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700147 String(param->fName).c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -0400148 separator = ", ";
149 }
150 this->writeSection(CONSTRUCTOR_PARAMS_SECTION, separator);
151 this->writef(") {\n"
Brian Salomonaff329b2017-08-11 09:40:37 -0400152 " return std::unique_ptr<GrFragmentProcessor>(new %s(",
Ethan Nicholas762466e2017-06-29 10:03:38 -0400153 fFullName.c_str());
154 separator = "";
Ethan Nicholas68990be2017-07-13 09:36:52 -0400155 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
Ethan Nicholasc9472af2017-10-10 16:30:21 -0400156 if (param->fType == *fContext.fFragmentProcessor_Type) {
Robert Phillips7a59f232017-11-08 15:31:30 -0500157 this->writef("%sstd::move(%s)", separator, String(param->fName).c_str());
Ethan Nicholasc9472af2017-10-10 16:30:21 -0400158 } else {
159 this->writef("%s%s", separator, String(param->fName).c_str());
160 }
Ethan Nicholas762466e2017-06-29 10:03:38 -0400161 separator = ", ";
162 }
163 this->writeExtraConstructorParams(separator);
164 this->writef("));\n"
165 " }\n");
166 }
167}
168
Ethan Nicholas68990be2017-07-13 09:36:52 -0400169void HCodeGenerator::failOnSection(const char* section, const char* msg) {
170 std::vector<const Section*> s = fSectionAndParameterHelper.getSections(section);
171 if (s.size()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700172 fErrors.error(s[0]->fOffset, String("@") + section + " " + msg);
Ethan Nicholas68990be2017-07-13 09:36:52 -0400173 }
174}
175
Ethan Nicholas762466e2017-06-29 10:03:38 -0400176void HCodeGenerator::writeConstructor() {
177 if (this->writeSection(CONSTRUCTOR_SECTION)) {
Ethan Nicholas68990be2017-07-13 09:36:52 -0400178 const char* msg = "may not be present when constructor is overridden";
179 this->failOnSection(CONSTRUCTOR_CODE_SECTION, msg);
180 this->failOnSection(CONSTRUCTOR_PARAMS_SECTION, msg);
Ethan Nicholas68990be2017-07-13 09:36:52 -0400181 this->failOnSection(INITIALIZERS_SECTION, msg);
182 this->failOnSection(OPTIMIZATION_FLAGS_SECTION, msg);
Robert Phillips1e8501e2018-03-23 15:00:20 -0400183 return;
Ethan Nicholas762466e2017-06-29 10:03:38 -0400184 }
185 this->writef(" %s(", fFullName.c_str());
186 const char* separator = "";
Ethan Nicholas68990be2017-07-13 09:36:52 -0400187 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
Ethan Nicholasd608c092017-10-26 09:30:08 -0400188 this->writef("%s%s %s", separator, ParameterType(fContext, param->fType,
189 param->fModifiers.fLayout).c_str(),
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700190 String(param->fName).c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -0400191 separator = ", ";
192 }
193 this->writeSection(CONSTRUCTOR_PARAMS_SECTION, separator);
194 this->writef(")\n"
Ethan Nicholasabff9562017-10-09 10:54:08 -0400195 " : INHERITED(k%s_ClassID", fFullName.c_str());
196 if (!this->writeSection(OPTIMIZATION_FLAGS_SECTION, ", (OptimizationFlags) ")) {
197 this->writef(", kNone_OptimizationFlags");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400198 }
199 this->writef(")");
200 this->writeSection(INITIALIZERS_SECTION, "\n , ");
Ethan Nicholas68990be2017-07-13 09:36:52 -0400201 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700202 String nameString(param->fName);
203 const char* name = nameString.c_str();
Ethan Nicholas762466e2017-06-29 10:03:38 -0400204 if (param->fType.kind() == Type::kSampler_Kind) {
Ethan Nicholas68990be2017-07-13 09:36:52 -0400205 this->writef("\n , %s(std::move(%s)", FieldName(name).c_str(), name);
206 for (const Section* s : fSectionAndParameterHelper.getSections(
207 SAMPLER_PARAMS_SECTION)) {
208 if (s->fArgument == name) {
209 this->writef(", %s", s->fText.c_str());
210 }
211 }
212 this->writef(")");
Ethan Nicholasc9472af2017-10-10 16:30:21 -0400213 } else if (param->fType == *fContext.fFragmentProcessor_Type) {
214 // do nothing
Ethan Nicholas762466e2017-06-29 10:03:38 -0400215 } else {
216 this->writef("\n , %s(%s)", FieldName(name).c_str(), name);
217 }
218 }
Ethan Nicholas68990be2017-07-13 09:36:52 -0400219 for (const Section* s : fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION)) {
220 String field = FieldName(s->fArgument.c_str());
221 this->writef("\n , %sCoordTransform(%s, %s.proxy())", field.c_str(), s->fText.c_str(),
222 field.c_str());
223 }
Ethan Nicholas762466e2017-06-29 10:03:38 -0400224 this->writef(" {\n");
225 this->writeSection(CONSTRUCTOR_CODE_SECTION);
Brian Salomonf7dcd762018-07-30 14:48:15 -0400226 int samplerCount = 0;
Ethan Nicholas68990be2017-07-13 09:36:52 -0400227 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400228 if (param->fType.kind() == Type::kSampler_Kind) {
Brian Salomonf7dcd762018-07-30 14:48:15 -0400229 ++samplerCount;
Ethan Nicholasc9472af2017-10-10 16:30:21 -0400230 } else if (param->fType == *fContext.fFragmentProcessor_Type) {
231 this->writef(" this->registerChildProcessor(std::move(%s));",
232 String(param->fName).c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -0400233 }
234 }
Brian Salomonf7dcd762018-07-30 14:48:15 -0400235 if (samplerCount) {
236 this->writef(" this->setTextureSamplerCnt(%d);", samplerCount);
237 }
Ethan Nicholas68990be2017-07-13 09:36:52 -0400238 for (const Section* s : fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION)) {
239 String field = FieldName(s->fArgument.c_str());
240 this->writef(" this->addCoordTransform(&%sCoordTransform);\n", field.c_str());
241 }
Ethan Nicholasabff9562017-10-09 10:54:08 -0400242 this->writef(" }\n");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400243}
244
245void HCodeGenerator::writeFields() {
246 this->writeSection(FIELDS_SECTION);
Ethan Nicholas68990be2017-07-13 09:36:52 -0400247 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
Ethan Nicholasc9472af2017-10-10 16:30:21 -0400248 if (param->fType == *fContext.fFragmentProcessor_Type) {
249 continue;
250 }
Ethan Nicholasd608c092017-10-26 09:30:08 -0400251 this->writef(" %s %s;\n", FieldType(fContext, param->fType,
252 param->fModifiers.fLayout).c_str(),
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700253 FieldName(String(param->fName).c_str()).c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -0400254 }
Ethan Nicholas68990be2017-07-13 09:36:52 -0400255 for (const Section* s : fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION)) {
256 this->writef(" GrCoordTransform %sCoordTransform;\n",
257 FieldName(s->fArgument.c_str()).c_str());
258 }
Ethan Nicholas762466e2017-06-29 10:03:38 -0400259}
260
Ethan Nicholas130fb3f2018-02-01 12:14:34 -0500261String HCodeGenerator::GetHeader(const Program& program, ErrorReporter& errors) {
262 SymbolTable types(&errors);
263 Parser parser(program.fSource->c_str(), program.fSource->length(), types, errors);
264 for (;;) {
265 Token header = parser.nextRawToken();
266 switch (header.fKind) {
267 case Token::WHITESPACE:
268 break;
269 case Token::BLOCK_COMMENT:
270 return String(program.fSource->c_str() + header.fOffset, header.fLength);
271 default:
272 return "";
273 }
274 }
275}
276
Ethan Nicholas762466e2017-06-29 10:03:38 -0400277bool HCodeGenerator::generateCode() {
Ethan Nicholas130fb3f2018-02-01 12:14:34 -0500278 this->writef("%s\n", GetHeader(fProgram, fErrors).c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -0400279 this->writef(kFragmentProcessorHeader, fFullName.c_str());
280 this->writef("#ifndef %s_DEFINED\n"
Ethan Nicholas9fb036f2017-07-05 16:19:09 -0400281 "#define %s_DEFINED\n",
282 fFullName.c_str(),
283 fFullName.c_str());
Greg Daniel3e8c3452018-04-06 10:37:55 -0400284 this->writef("#include \"SkTypes.h\"\n");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400285 this->writeSection(HEADER_SECTION);
Ethan Nicholas9fb036f2017-07-05 16:19:09 -0400286 this->writef("#include \"GrFragmentProcessor.h\"\n"
Brian Osman1cb41712017-10-19 12:54:52 -0400287 "#include \"GrCoordTransform.h\"\n");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400288 this->writef("class %s : public GrFragmentProcessor {\n"
289 "public:\n",
290 fFullName.c_str());
Ethan Nicholas3c6ae622018-04-24 13:06:09 -0400291 for (const auto& p : fProgram) {
292 if (ProgramElement::kEnum_Kind == p.fKind && !((Enum&) p).fBuiltin) {
293 this->writef("%s\n", p.description().c_str());
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500294 }
295 }
Ethan Nicholase9d172a2017-11-20 12:12:24 -0500296 this->writeSection(CLASS_SECTION);
Ethan Nicholas68990be2017-07-13 09:36:52 -0400297 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
Ethan Nicholasc9472af2017-10-10 16:30:21 -0400298 if (param->fType.kind() == Type::kSampler_Kind ||
299 param->fType.kind() == Type::kOther_Kind) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400300 continue;
301 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700302 String nameString(param->fName);
303 const char* name = nameString.c_str();
Ethan Nicholas9fb036f2017-07-05 16:19:09 -0400304 this->writef(" %s %s() const { return %s; }\n",
Ethan Nicholasd608c092017-10-26 09:30:08 -0400305 FieldType(fContext, param->fType, param->fModifiers.fLayout).c_str(), name,
306 FieldName(name).c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -0400307 }
308 this->writeMake();
Ethan Nicholasf57c0d62017-07-31 11:18:22 -0400309 this->writef(" %s(const %s& src);\n"
Brian Salomonaff329b2017-08-11 09:40:37 -0400310 " std::unique_ptr<GrFragmentProcessor> clone() const override;\n"
Ethan Nicholasf57c0d62017-07-31 11:18:22 -0400311 " const char* name() const override { return \"%s\"; }\n"
Ethan Nicholas762466e2017-06-29 10:03:38 -0400312 "private:\n",
Ethan Nicholasf57c0d62017-07-31 11:18:22 -0400313 fFullName.c_str(), fFullName.c_str(), fName.c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -0400314 this->writeConstructor();
315 this->writef(" GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;\n"
316 " void onGetGLSLProcessorKey(const GrShaderCaps&,"
317 "GrProcessorKeyBuilder*) const override;\n"
Brian Salomonf7dcd762018-07-30 14:48:15 -0400318 " bool onIsEqual(const GrFragmentProcessor&) const override;\n");
319 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
320 if (param->fType.kind() == Type::kSampler_Kind) {
321 this->writef(" const TextureSampler& onTextureSampler(int) const override;");
322 break;
323 }
324 }
325 this->writef(" GR_DECLARE_FRAGMENT_PROCESSOR_TEST\n");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400326 this->writeFields();
327 this->writef(" typedef GrFragmentProcessor INHERITED;\n"
Ethan Nicholas9fb036f2017-07-05 16:19:09 -0400328 "};\n");
329 this->writeSection(HEADER_END_SECTION);
Greg Daniel3e8c3452018-04-06 10:37:55 -0400330 this->writef("#endif\n");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400331 return 0 == fErrors.errorCount();
332}
333
334} // namespace