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