blob: 405fb0e6ce974c27197c022c4b517730666279e4 [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) {
26 if (type.fName == "vec2") {
27 return "SkPoint";
28 } else if (type.fName == "ivec4") {
29 return "SkIRect";
30 } else if (type.fName == "vec4") {
31 return "SkRect";
32 } else if (type.fName == "mat4") {
33 return "SkMatrix44";
34 } else if (type.kind() == Type::kSampler_Kind) {
35 return "sk_sp<GrTextureProxy>";
36 } else if (type.fName == "colorSpaceXform") {
37 return "sk_sp<GrColorSpaceXform>";
38 }
39 return type.name();
40}
41
42String HCodeGenerator::FieldType(const Type& type) {
43 if (type.kind() == Type::kSampler_Kind) {
44 return "TextureSampler";
45 }
46 return ParameterType(type);
47}
48
49void HCodeGenerator::writef(const char* s, va_list va) {
50 static constexpr int BUFFER_SIZE = 1024;
Ethan Nicholas9fb036f2017-07-05 16:19:09 -040051 va_list copy;
52 va_copy(copy, va);
Ethan Nicholas762466e2017-06-29 10:03:38 -040053 char buffer[BUFFER_SIZE];
54 int length = vsnprintf(buffer, BUFFER_SIZE, s, va);
55 if (length < BUFFER_SIZE) {
56 fOut->write(buffer, length);
57 } else {
58 std::unique_ptr<char[]> heap(new char[length + 1]);
Ethan Nicholas9fb036f2017-07-05 16:19:09 -040059 vsprintf(heap.get(), s, copy);
Ethan Nicholas762466e2017-06-29 10:03:38 -040060 fOut->write(heap.get(), length);
61 }
62}
63
64void HCodeGenerator::writef(const char* s, ...) {
65 va_list va;
66 va_start(va, s);
67 this->writef(s, va);
68 va_end(va);
69}
70
71bool HCodeGenerator::writeSection(const char* name, const char* prefix) {
72 const auto found = fSectionAndParameterHelper.fSections.find(String(name));
73 if (found != fSectionAndParameterHelper.fSections.end()) {
74 this->writef("%s%s", prefix, found->second->fText.c_str());
75 return true;
76 }
77 return false;
78}
79
80void HCodeGenerator::writeExtraConstructorParams(const char* separator) {
81 // super-simple parse, just assume the last token before a comma is the name of a parameter
82 // (which is true as long as there are no multi-parameter template types involved). Will replace
83 // this with something more robust if the need arises.
84 const auto found = fSectionAndParameterHelper.fSections.find(
85 String(CONSTRUCTOR_PARAMS_SECTION));
86 if (found != fSectionAndParameterHelper.fSections.end()) {
87 const char* s = found->second->fText.c_str();
88 #define BUFFER_SIZE 64
89 char lastIdentifier[BUFFER_SIZE];
90 int lastIdentifierLength = 0;
91 bool foundBreak = false;
92 while (*s) {
93 char c = *s;
94 ++s;
95 if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
96 c == '_') {
97 if (foundBreak) {
98 lastIdentifierLength = 0;
99 foundBreak = false;
100 }
101 ASSERT(lastIdentifierLength < BUFFER_SIZE);
102 lastIdentifier[lastIdentifierLength] = c;
103 ++lastIdentifierLength;
104 } else {
105 foundBreak = true;
106 if (c == ',') {
107 ASSERT(lastIdentifierLength < BUFFER_SIZE);
108 lastIdentifier[lastIdentifierLength] = 0;
109 this->writef("%s%s", separator, lastIdentifier);
110 separator = ", ";
111 } else if (c != ' ' && c != '\t' && c != '\n' && c != '\r') {
112 lastIdentifierLength = 0;
113 }
114 }
115 }
116 if (lastIdentifierLength) {
117 ASSERT(lastIdentifierLength < BUFFER_SIZE);
118 lastIdentifier[lastIdentifierLength] = 0;
119 this->writef("%s%s", separator, lastIdentifier);
120 }
121 }
122}
123
124void HCodeGenerator::writeMake() {
125 const char* separator;
126 if (!this->writeSection(MAKE_SECTION)) {
127 this->writef(" static sk_sp<GrFragmentProcessor> Make(");
128 separator = "";
129 for (const auto& param : fSectionAndParameterHelper.fParameters) {
130 this->writef("%s%s %s", separator, ParameterType(param->fType).c_str(),
131 param->fName.c_str());
132 separator = ", ";
133 }
134 this->writeSection(CONSTRUCTOR_PARAMS_SECTION, separator);
135 this->writef(") {\n"
136 " return sk_sp<GrFragmentProcessor>(new %s(",
137 fFullName.c_str());
138 separator = "";
139 for (const auto& param : fSectionAndParameterHelper.fParameters) {
140 this->writef("%s%s", separator, param->fName.c_str());
141 separator = ", ";
142 }
143 this->writeExtraConstructorParams(separator);
144 this->writef("));\n"
145 " }\n");
146 }
147}
148
149void HCodeGenerator::writeConstructor() {
150 if (this->writeSection(CONSTRUCTOR_SECTION)) {
151 return;
152 }
153 this->writef(" %s(", fFullName.c_str());
154 const char* separator = "";
155 for (const auto& param : fSectionAndParameterHelper.fParameters) {
156 this->writef("%s%s %s", separator, ParameterType(param->fType).c_str(),
157 param->fName.c_str());
158 separator = ", ";
159 }
160 this->writeSection(CONSTRUCTOR_PARAMS_SECTION, separator);
161 this->writef(")\n"
162 " : INHERITED(");
163 if (!this->writeSection(OPTIMIZATION_FLAGS_SECTION, "(OptimizationFlags) ")) {
164 this->writef("kNone_OptimizationFlags");
165 }
166 this->writef(")");
167 this->writeSection(INITIALIZERS_SECTION, "\n , ");
168 for (const auto& param : fSectionAndParameterHelper.fParameters) {
169 const char* name = param->fName.c_str();
170 if (param->fType.kind() == Type::kSampler_Kind) {
Ethan Nicholas9fb036f2017-07-05 16:19:09 -0400171 this->writef("\n , %s(std::move(%s))", FieldName(name).c_str(),
Ethan Nicholas762466e2017-06-29 10:03:38 -0400172 name);
173 } else {
174 this->writef("\n , %s(%s)", FieldName(name).c_str(), name);
175 }
176 }
177 this->writef(" {\n");
178 this->writeSection(CONSTRUCTOR_CODE_SECTION);
179 for (const auto& param : fSectionAndParameterHelper.fParameters) {
180 if (param->fType.kind() == Type::kSampler_Kind) {
181 this->writef(" this->addTextureSampler(&%s);\n",
182 FieldName(param->fName.c_str()).c_str());
183 }
184 }
185 this->writef(" this->initClassID<%s>();\n"
186 " }\n",
187 fFullName.c_str());
188}
189
190void HCodeGenerator::writeFields() {
191 this->writeSection(FIELDS_SECTION);
192 for (const auto& param : fSectionAndParameterHelper.fParameters) {
193 const char* name = param->fName.c_str();
194 this->writef(" %s %s;\n", FieldType(param->fType).c_str(), FieldName(name).c_str());
195 }
196}
197
198bool HCodeGenerator::generateCode() {
199 this->writef(kFragmentProcessorHeader, fFullName.c_str());
200 this->writef("#ifndef %s_DEFINED\n"
Ethan Nicholas9fb036f2017-07-05 16:19:09 -0400201 "#define %s_DEFINED\n",
202 fFullName.c_str(),
203 fFullName.c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -0400204 this->writeSection(HEADER_SECTION);
Ethan Nicholas9fb036f2017-07-05 16:19:09 -0400205 this->writef("#include \"GrFragmentProcessor.h\"\n"
206 "#include \"GrCoordTransform.h\"\n"
207 "#include \"effects/GrProxyMove.h\"\n");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400208 this->writef("class %s : public GrFragmentProcessor {\n"
209 "public:\n",
210 fFullName.c_str());
211 this->writeSection(CLASS_SECTION);
212 for (const auto& param : fSectionAndParameterHelper.fParameters) {
213 if (param->fType.kind() == Type::kSampler_Kind) {
214 continue;
215 }
216 const char* name = param->fName.c_str();
Ethan Nicholas9fb036f2017-07-05 16:19:09 -0400217 this->writef(" %s %s() const { return %s; }\n",
Ethan Nicholas762466e2017-06-29 10:03:38 -0400218 FieldType(param->fType).c_str(), name, FieldName(name).c_str());
219 }
220 this->writeMake();
221 this->writef(" const char* name() const override { return \"%s\"; }\n"
222 "private:\n",
223 fName.c_str());
224 this->writeConstructor();
225 this->writef(" GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;\n"
226 " void onGetGLSLProcessorKey(const GrShaderCaps&,"
227 "GrProcessorKeyBuilder*) const override;\n"
228 " bool onIsEqual(const GrFragmentProcessor&) const override;\n"
Brian Salomon0c26a9d2017-07-06 10:09:38 -0400229 " GR_DECLARE_FRAGMENT_PROCESSOR_TEST\n");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400230 this->writeFields();
231 this->writef(" typedef GrFragmentProcessor INHERITED;\n"
Ethan Nicholas9fb036f2017-07-05 16:19:09 -0400232 "};\n");
233 this->writeSection(HEADER_END_SECTION);
234 this->writef("#endif\n");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400235 return 0 == fErrors.errorCount();
236}
237
238} // namespace