blob: 1bfd9b10e1f7e610277e073113e22796ab3e7693 [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;
51 char buffer[BUFFER_SIZE];
52 int length = vsnprintf(buffer, BUFFER_SIZE, s, va);
53 if (length < BUFFER_SIZE) {
54 fOut->write(buffer, length);
55 } else {
56 std::unique_ptr<char[]> heap(new char[length + 1]);
57 vsprintf(heap.get(), s, va);
58 fOut->write(heap.get(), length);
59 }
60}
61
62void HCodeGenerator::writef(const char* s, ...) {
63 va_list va;
64 va_start(va, s);
65 this->writef(s, va);
66 va_end(va);
67}
68
69bool HCodeGenerator::writeSection(const char* name, const char* prefix) {
70 const auto found = fSectionAndParameterHelper.fSections.find(String(name));
71 if (found != fSectionAndParameterHelper.fSections.end()) {
72 this->writef("%s%s", prefix, found->second->fText.c_str());
73 return true;
74 }
75 return false;
76}
77
78void HCodeGenerator::writeExtraConstructorParams(const char* separator) {
79 // super-simple parse, just assume the last token before a comma is the name of a parameter
80 // (which is true as long as there are no multi-parameter template types involved). Will replace
81 // this with something more robust if the need arises.
82 const auto found = fSectionAndParameterHelper.fSections.find(
83 String(CONSTRUCTOR_PARAMS_SECTION));
84 if (found != fSectionAndParameterHelper.fSections.end()) {
85 const char* s = found->second->fText.c_str();
86 #define BUFFER_SIZE 64
87 char lastIdentifier[BUFFER_SIZE];
88 int lastIdentifierLength = 0;
89 bool foundBreak = false;
90 while (*s) {
91 char c = *s;
92 ++s;
93 if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
94 c == '_') {
95 if (foundBreak) {
96 lastIdentifierLength = 0;
97 foundBreak = false;
98 }
99 ASSERT(lastIdentifierLength < BUFFER_SIZE);
100 lastIdentifier[lastIdentifierLength] = c;
101 ++lastIdentifierLength;
102 } else {
103 foundBreak = true;
104 if (c == ',') {
105 ASSERT(lastIdentifierLength < BUFFER_SIZE);
106 lastIdentifier[lastIdentifierLength] = 0;
107 this->writef("%s%s", separator, lastIdentifier);
108 separator = ", ";
109 } else if (c != ' ' && c != '\t' && c != '\n' && c != '\r') {
110 lastIdentifierLength = 0;
111 }
112 }
113 }
114 if (lastIdentifierLength) {
115 ASSERT(lastIdentifierLength < BUFFER_SIZE);
116 lastIdentifier[lastIdentifierLength] = 0;
117 this->writef("%s%s", separator, lastIdentifier);
118 }
119 }
120}
121
122void HCodeGenerator::writeMake() {
123 const char* separator;
124 if (!this->writeSection(MAKE_SECTION)) {
125 this->writef(" static sk_sp<GrFragmentProcessor> Make(");
126 separator = "";
127 for (const auto& param : fSectionAndParameterHelper.fParameters) {
128 this->writef("%s%s %s", separator, ParameterType(param->fType).c_str(),
129 param->fName.c_str());
130 separator = ", ";
131 }
132 this->writeSection(CONSTRUCTOR_PARAMS_SECTION, separator);
133 this->writef(") {\n"
134 " return sk_sp<GrFragmentProcessor>(new %s(",
135 fFullName.c_str());
136 separator = "";
137 for (const auto& param : fSectionAndParameterHelper.fParameters) {
138 this->writef("%s%s", separator, param->fName.c_str());
139 separator = ", ";
140 }
141 this->writeExtraConstructorParams(separator);
142 this->writef("));\n"
143 " }\n");
144 }
145}
146
147void HCodeGenerator::writeConstructor() {
148 if (this->writeSection(CONSTRUCTOR_SECTION)) {
149 return;
150 }
151 this->writef(" %s(", fFullName.c_str());
152 const char* separator = "";
153 for (const auto& param : fSectionAndParameterHelper.fParameters) {
154 this->writef("%s%s %s", separator, ParameterType(param->fType).c_str(),
155 param->fName.c_str());
156 separator = ", ";
157 }
158 this->writeSection(CONSTRUCTOR_PARAMS_SECTION, separator);
159 this->writef(")\n"
160 " : INHERITED(");
161 if (!this->writeSection(OPTIMIZATION_FLAGS_SECTION, "(OptimizationFlags) ")) {
162 this->writef("kNone_OptimizationFlags");
163 }
164 this->writef(")");
165 this->writeSection(INITIALIZERS_SECTION, "\n , ");
166 for (const auto& param : fSectionAndParameterHelper.fParameters) {
167 const char* name = param->fName.c_str();
168 if (param->fType.kind() == Type::kSampler_Kind) {
169 this->writef("\n , %s(resourceProvider, std::move(%s))", FieldName(name).c_str(),
170 name);
171 } else {
172 this->writef("\n , %s(%s)", FieldName(name).c_str(), name);
173 }
174 }
175 this->writef(" {\n");
176 this->writeSection(CONSTRUCTOR_CODE_SECTION);
177 for (const auto& param : fSectionAndParameterHelper.fParameters) {
178 if (param->fType.kind() == Type::kSampler_Kind) {
179 this->writef(" this->addTextureSampler(&%s);\n",
180 FieldName(param->fName.c_str()).c_str());
181 }
182 }
183 this->writef(" this->initClassID<%s>();\n"
184 " }\n",
185 fFullName.c_str());
186}
187
188void HCodeGenerator::writeFields() {
189 this->writeSection(FIELDS_SECTION);
190 for (const auto& param : fSectionAndParameterHelper.fParameters) {
191 const char* name = param->fName.c_str();
192 this->writef(" %s %s;\n", FieldType(param->fType).c_str(), FieldName(name).c_str());
193 }
194}
195
196bool HCodeGenerator::generateCode() {
197 this->writef(kFragmentProcessorHeader, fFullName.c_str());
198 this->writef("#ifndef %s_DEFINED\n"
199 "#define %s_DEFINED\n"
200 "#include \"GrFragmentProcessor.h\"\n"
201 "#include \"GrCoordTransform.h\"\n"
202 "#include \"effects/GrProxyMove.h\"\n",
203 fFullName.c_str(), fFullName.c_str());
204 this->writeSection(HEADER_SECTION);
205 this->writef("class %s : public GrFragmentProcessor {\n"
206 "public:\n",
207 fFullName.c_str());
208 this->writeSection(CLASS_SECTION);
209 for (const auto& param : fSectionAndParameterHelper.fParameters) {
210 if (param->fType.kind() == Type::kSampler_Kind) {
211 continue;
212 }
213 const char* name = param->fName.c_str();
214 this->writef("%s %s() const { return %s; }\n",
215 FieldType(param->fType).c_str(), name, FieldName(name).c_str());
216 }
217 this->writeMake();
218 this->writef(" const char* name() const override { return \"%s\"; }\n"
219 "private:\n",
220 fName.c_str());
221 this->writeConstructor();
222 this->writef(" GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;\n"
223 " void onGetGLSLProcessorKey(const GrShaderCaps&,"
224 "GrProcessorKeyBuilder*) const override;\n"
225 " bool onIsEqual(const GrFragmentProcessor&) const override;\n"
226 " GR_DECLARE_FRAGMENT_PROCESSOR_TEST;\n");
227 this->writeFields();
228 this->writef(" typedef GrFragmentProcessor INHERITED;\n"
229 "};\n"
230 "#endif\n");
231 return 0 == fErrors.errorCount();
232}
233
234} // namespace