1/* 2 * Copyright 2021 Google LLC. 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 "src/sksl/transform/SkSLTransform.h" 9 10#include "include/private/SkSLProgramKind.h" 11#include "src/sksl/SkSLCompiler.h" 12#include "src/sksl/SkSLContext.h" 13#include "src/sksl/SkSLIntrinsicMap.h" 14#include "src/sksl/SkSLThreadContext.h" 15#include "src/sksl/analysis/SkSLProgramVisitor.h" 16#include "src/sksl/ir/SkSLFunctionDefinition.h" 17#include "src/sksl/ir/SkSLInterfaceBlock.h" 18#include "src/sksl/ir/SkSLVarDeclarations.h" 19 20namespace SkSL { 21 22namespace Transform { 23 24void FindAndDeclareBuiltinVariables(const Context& context, 25 ProgramKind programKind, std::vector<const ProgramElement*>& sharedElements) { 26 class BuiltinVariableScanner : public ProgramVisitor { 27 public: 28 BuiltinVariableScanner(const Context& context) 29 : fContext(context) {} 30 31 void addDeclaringElement(const String& name) { 32 // If this is the *first* time we've seen this builtin, findAndInclude will return 33 // the corresponding ProgramElement. 34 IntrinsicMap& intrinsics = *fContext.fIntrinsics; 35 if (const ProgramElement* decl = intrinsics.findAndInclude(name)) { 36 SkASSERT(decl->is<GlobalVarDeclaration>() || decl->is<InterfaceBlock>()); 37 fNewElements.push_back(decl); 38 } 39 } 40 41 bool visitProgramElement(const ProgramElement& pe) override { 42 if (pe.is<FunctionDefinition>()) { 43 const FunctionDefinition& funcDef = pe.as<FunctionDefinition>(); 44 // We synthesize writes to sk_FragColor if main() returns a color, even if it's 45 // otherwise unreferenced. Check main's return type to see if it's half4. 46 if (funcDef.declaration().isMain() && 47 funcDef.declaration().returnType() == *fContext.fTypes.fHalf4) { 48 fPreserveFragColor = true; 49 } 50 } 51 return INHERITED::visitProgramElement(pe); 52 } 53 54 bool visitExpression(const Expression& e) override { 55 if (e.is<VariableReference>() && e.as<VariableReference>().variable()->isBuiltin()) { 56 this->addDeclaringElement(String(e.as<VariableReference>().variable()->name())); 57 } 58 return INHERITED::visitExpression(e); 59 } 60 61 const Context& fContext; 62 std::vector<const ProgramElement*> fNewElements; 63 bool fPreserveFragColor = false; 64 65 using INHERITED = ProgramVisitor; 66 using INHERITED::visitProgramElement; 67 }; 68 69 BuiltinVariableScanner scanner(context); 70 for (auto& e : ThreadContext::ProgramElements()) { 71 scanner.visitProgramElement(*e); 72 } 73 74 if (scanner.fPreserveFragColor) { 75 // main() returns a half4, so make sure we don't dead-strip sk_FragColor. 76 scanner.addDeclaringElement(Compiler::FRAGCOLOR_NAME); 77 } 78 79 switch (programKind) { 80 case ProgramKind::kFragment: 81 // Vulkan requires certain builtin variables be present, even if they're unused. At one 82 // time, validation errors would result if sk_Clockwise was missing. Now, it's just 83 // (Adreno) driver bugs that drop or corrupt draws if they're missing. 84 scanner.addDeclaringElement("sk_Clockwise"); 85 break; 86 default: 87 break; 88 } 89 90 sharedElements.insert(sharedElements.begin(), scanner.fNewElements.begin(), 91 scanner.fNewElements.end()); 92} 93 94} // namespace Transform 95 96} // namespace SkSL 97