1/* 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 "SkSLParser.h" 11#include "SkSLUtil.h" 12#include "ir/SkSLEnum.h" 13#include "ir/SkSLFunctionDeclaration.h" 14#include "ir/SkSLFunctionDefinition.h" 15#include "ir/SkSLSection.h" 16#include "ir/SkSLVarDeclarations.h" 17 18namespace SkSL { 19 20HCodeGenerator::HCodeGenerator(const Context* context, const Program* program, 21 ErrorReporter* errors, String name, OutputStream* out) 22: INHERITED(program, errors, out) 23, fContext(*context) 24, fName(std::move(name)) 25, fFullName(String::printf("Gr%s", fName.c_str())) 26, fSectionAndParameterHelper(*program, *errors) {} 27 28String 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) { 33 return "float"; 34 } else if (type == *context.fFloat2_Type || type == *context.fHalf2_Type) { 35 return "SkPoint"; 36 } else if (type == *context.fInt4_Type || type == *context.fShort4_Type) { 37 return "SkIRect"; 38 } else if (type == *context.fFloat4_Type || type == *context.fHalf4_Type) { 39 return "SkRect"; 40 } else if (type == *context.fFloat4x4_Type || type == *context.fHalf4x4_Type) { 41 return "SkMatrix44"; 42 } else if (type.kind() == Type::kSampler_Kind) { 43 return "sk_sp<GrTextureProxy>"; 44 } else if (type == *context.fFragmentProcessor_Type) { 45 return "std::unique_ptr<GrFragmentProcessor>"; 46 } 47 return type.name(); 48} 49 50String HCodeGenerator::FieldType(const Context& context, const Type& type, 51 const Layout& layout) { 52 if (type.kind() == Type::kSampler_Kind) { 53 return "TextureSampler"; 54 } else if (type == *context.fFragmentProcessor_Type) { 55 // we don't store fragment processors in fields, they get registered via 56 // registerChildProcessor instead 57 ASSERT(false); 58 return "<error>"; 59 } 60 return ParameterType(context, type, layout); 61} 62 63void HCodeGenerator::writef(const char* s, va_list va) { 64 static constexpr int BUFFER_SIZE = 1024; 65 va_list copy; 66 va_copy(copy, va); 67 char buffer[BUFFER_SIZE]; 68 int length = vsnprintf(buffer, BUFFER_SIZE, s, va); 69 if (length < BUFFER_SIZE) { 70 fOut->write(buffer, length); 71 } else { 72 std::unique_ptr<char[]> heap(new char[length + 1]); 73 vsprintf(heap.get(), s, copy); 74 fOut->write(heap.get(), length); 75 } 76} 77 78void HCodeGenerator::writef(const char* s, ...) { 79 va_list va; 80 va_start(va, s); 81 this->writef(s, va); 82 va_end(va); 83} 84 85bool HCodeGenerator::writeSection(const char* name, const char* prefix) { 86 const Section* s = fSectionAndParameterHelper.getSection(name); 87 if (s) { 88 this->writef("%s%s", prefix, s->fText.c_str()); 89 return true; 90 } 91 return false; 92} 93 94void HCodeGenerator::writeExtraConstructorParams(const char* separator) { 95 // super-simple parse, just assume the last token before a comma is the name of a parameter 96 // (which is true as long as there are no multi-parameter template types involved). Will replace 97 // this with something more robust if the need arises. 98 const Section* section = fSectionAndParameterHelper.getSection(CONSTRUCTOR_PARAMS_SECTION); 99 if (section) { 100 const char* s = section->fText.c_str(); 101 #define BUFFER_SIZE 64 102 char lastIdentifier[BUFFER_SIZE]; 103 int lastIdentifierLength = 0; 104 bool foundBreak = false; 105 while (*s) { 106 char c = *s; 107 ++s; 108 if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || 109 c == '_') { 110 if (foundBreak) { 111 lastIdentifierLength = 0; 112 foundBreak = false; 113 } 114 ASSERT(lastIdentifierLength < BUFFER_SIZE); 115 lastIdentifier[lastIdentifierLength] = c; 116 ++lastIdentifierLength; 117 } else { 118 foundBreak = true; 119 if (c == ',') { 120 ASSERT(lastIdentifierLength < BUFFER_SIZE); 121 lastIdentifier[lastIdentifierLength] = 0; 122 this->writef("%s%s", separator, lastIdentifier); 123 separator = ", "; 124 } else if (c != ' ' && c != '\t' && c != '\n' && c != '\r') { 125 lastIdentifierLength = 0; 126 } 127 } 128 } 129 if (lastIdentifierLength) { 130 ASSERT(lastIdentifierLength < BUFFER_SIZE); 131 lastIdentifier[lastIdentifierLength] = 0; 132 this->writef("%s%s", separator, lastIdentifier); 133 } 134 } 135} 136 137void HCodeGenerator::writeMake() { 138 const char* separator; 139 if (!this->writeSection(MAKE_SECTION)) { 140 this->writef(" static std::unique_ptr<GrFragmentProcessor> Make("); 141 separator = ""; 142 for (const auto& param : fSectionAndParameterHelper.getParameters()) { 143 this->writef("%s%s %s", separator, ParameterType(fContext, param->fType, 144 param->fModifiers.fLayout).c_str(), 145 String(param->fName).c_str()); 146 separator = ", "; 147 } 148 this->writeSection(CONSTRUCTOR_PARAMS_SECTION, separator); 149 this->writef(") {\n" 150 " return std::unique_ptr<GrFragmentProcessor>(new %s(", 151 fFullName.c_str()); 152 separator = ""; 153 for (const auto& param : fSectionAndParameterHelper.getParameters()) { 154 if (param->fType == *fContext.fFragmentProcessor_Type) { 155 this->writef("%sstd::move(%s)", separator, String(param->fName).c_str()); 156 } else { 157 this->writef("%s%s", separator, String(param->fName).c_str()); 158 } 159 separator = ", "; 160 } 161 this->writeExtraConstructorParams(separator); 162 this->writef("));\n" 163 " }\n"); 164 } 165} 166 167void HCodeGenerator::failOnSection(const char* section, const char* msg) { 168 std::vector<const Section*> s = fSectionAndParameterHelper.getSections(section); 169 if (s.size()) { 170 fErrors.error(s[0]->fOffset, String("@") + section + " " + msg); 171 } 172} 173 174void HCodeGenerator::writeConstructor() { 175 if (this->writeSection(CONSTRUCTOR_SECTION)) { 176 const char* msg = "may not be present when constructor is overridden"; 177 this->failOnSection(CONSTRUCTOR_CODE_SECTION, msg); 178 this->failOnSection(CONSTRUCTOR_PARAMS_SECTION, msg); 179 this->failOnSection(COORD_TRANSFORM_SECTION, msg); 180 this->failOnSection(INITIALIZERS_SECTION, msg); 181 this->failOnSection(OPTIMIZATION_FLAGS_SECTION, msg); 182 } 183 this->writef(" %s(", fFullName.c_str()); 184 const char* separator = ""; 185 for (const auto& param : fSectionAndParameterHelper.getParameters()) { 186 this->writef("%s%s %s", separator, ParameterType(fContext, param->fType, 187 param->fModifiers.fLayout).c_str(), 188 String(param->fName).c_str()); 189 separator = ", "; 190 } 191 this->writeSection(CONSTRUCTOR_PARAMS_SECTION, separator); 192 this->writef(")\n" 193 " : INHERITED(k%s_ClassID", fFullName.c_str()); 194 if (!this->writeSection(OPTIMIZATION_FLAGS_SECTION, ", (OptimizationFlags) ")) { 195 this->writef(", kNone_OptimizationFlags"); 196 } 197 this->writef(")"); 198 this->writeSection(INITIALIZERS_SECTION, "\n , "); 199 for (const auto& param : fSectionAndParameterHelper.getParameters()) { 200 String nameString(param->fName); 201 const char* name = nameString.c_str(); 202 if (param->fType.kind() == Type::kSampler_Kind) { 203 this->writef("\n , %s(std::move(%s)", FieldName(name).c_str(), name); 204 for (const Section* s : fSectionAndParameterHelper.getSections( 205 SAMPLER_PARAMS_SECTION)) { 206 if (s->fArgument == name) { 207 this->writef(", %s", s->fText.c_str()); 208 } 209 } 210 this->writef(")"); 211 } else if (param->fType == *fContext.fFragmentProcessor_Type) { 212 // do nothing 213 } else { 214 this->writef("\n , %s(%s)", FieldName(name).c_str(), name); 215 } 216 } 217 for (const Section* s : fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION)) { 218 String field = FieldName(s->fArgument.c_str()); 219 this->writef("\n , %sCoordTransform(%s, %s.proxy())", field.c_str(), s->fText.c_str(), 220 field.c_str()); 221 } 222 this->writef(" {\n"); 223 this->writeSection(CONSTRUCTOR_CODE_SECTION); 224 for (const auto& param : fSectionAndParameterHelper.getParameters()) { 225 if (param->fType.kind() == Type::kSampler_Kind) { 226 this->writef(" this->addTextureSampler(&%s);\n", 227 FieldName(String(param->fName).c_str()).c_str()); 228 } else if (param->fType == *fContext.fFragmentProcessor_Type) { 229 this->writef(" this->registerChildProcessor(std::move(%s));", 230 String(param->fName).c_str()); 231 } 232 } 233 for (const Section* s : fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION)) { 234 String field = FieldName(s->fArgument.c_str()); 235 this->writef(" this->addCoordTransform(&%sCoordTransform);\n", field.c_str()); 236 } 237 this->writef(" }\n"); 238} 239 240void HCodeGenerator::writeFields() { 241 this->writeSection(FIELDS_SECTION); 242 for (const auto& param : fSectionAndParameterHelper.getParameters()) { 243 if (param->fType == *fContext.fFragmentProcessor_Type) { 244 continue; 245 } 246 this->writef(" %s %s;\n", FieldType(fContext, param->fType, 247 param->fModifiers.fLayout).c_str(), 248 FieldName(String(param->fName).c_str()).c_str()); 249 } 250 for (const Section* s : fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION)) { 251 this->writef(" GrCoordTransform %sCoordTransform;\n", 252 FieldName(s->fArgument.c_str()).c_str()); 253 } 254} 255 256String HCodeGenerator::GetHeader(const Program& program, ErrorReporter& errors) { 257 SymbolTable types(&errors); 258 Parser parser(program.fSource->c_str(), program.fSource->length(), types, errors); 259 for (;;) { 260 Token header = parser.nextRawToken(); 261 switch (header.fKind) { 262 case Token::WHITESPACE: 263 break; 264 case Token::BLOCK_COMMENT: 265 return String(program.fSource->c_str() + header.fOffset, header.fLength); 266 default: 267 return ""; 268 } 269 } 270} 271 272bool HCodeGenerator::generateCode() { 273 this->writef("%s\n", GetHeader(fProgram, fErrors).c_str()); 274 this->writef(kFragmentProcessorHeader, fFullName.c_str()); 275 this->writef("#ifndef %s_DEFINED\n" 276 "#define %s_DEFINED\n", 277 fFullName.c_str(), 278 fFullName.c_str()); 279 this->writef("#include \"SkTypes.h\"\n" 280 "#if SK_SUPPORT_GPU\n"); 281 this->writeSection(HEADER_SECTION); 282 this->writef("#include \"GrFragmentProcessor.h\"\n" 283 "#include \"GrCoordTransform.h\"\n"); 284 this->writef("class %s : public GrFragmentProcessor {\n" 285 "public:\n", 286 fFullName.c_str()); 287 for (const auto& p : fProgram.fElements) { 288 if (ProgramElement::kEnum_Kind == p->fKind && !((Enum&) *p).fBuiltin) { 289 this->writef("%s\n", p->description().c_str()); 290 } 291 } 292 this->writeSection(CLASS_SECTION); 293 for (const auto& param : fSectionAndParameterHelper.getParameters()) { 294 if (param->fType.kind() == Type::kSampler_Kind || 295 param->fType.kind() == Type::kOther_Kind) { 296 continue; 297 } 298 String nameString(param->fName); 299 const char* name = nameString.c_str(); 300 this->writef(" %s %s() const { return %s; }\n", 301 FieldType(fContext, param->fType, param->fModifiers.fLayout).c_str(), name, 302 FieldName(name).c_str()); 303 } 304 this->writeMake(); 305 this->writef(" %s(const %s& src);\n" 306 " std::unique_ptr<GrFragmentProcessor> clone() const override;\n" 307 " const char* name() const override { return \"%s\"; }\n" 308 "private:\n", 309 fFullName.c_str(), fFullName.c_str(), fName.c_str()); 310 this->writeConstructor(); 311 this->writef(" GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;\n" 312 " void onGetGLSLProcessorKey(const GrShaderCaps&," 313 "GrProcessorKeyBuilder*) const override;\n" 314 " bool onIsEqual(const GrFragmentProcessor&) const override;\n" 315 " GR_DECLARE_FRAGMENT_PROCESSOR_TEST\n"); 316 this->writeFields(); 317 this->writef(" typedef GrFragmentProcessor INHERITED;\n" 318 "};\n"); 319 this->writeSection(HEADER_END_SECTION); 320 this->writef("#endif\n" 321 "#endif\n"); 322 return 0 == fErrors.errorCount(); 323} 324 325} // namespace 326