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