Ethan Nicholas | 1e6e919 | 2021-09-30 12:47:04 -0400 | [diff] [blame] | 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 | |
John Stiles | 7176637 | 2021-10-06 15:54:55 -0400 | [diff] [blame] | 10 | #include "include/private/SkSLProgramKind.h" |
Ethan Nicholas | 1e6e919 | 2021-09-30 12:47:04 -0400 | [diff] [blame] | 11 | #include "src/sksl/SkSLCompiler.h" |
| 12 | #include "src/sksl/SkSLContext.h" |
| 13 | #include "src/sksl/SkSLIntrinsicMap.h" |
Ethan Nicholas | c845272 | 2021-10-07 10:47:32 -0400 | [diff] [blame] | 14 | #include "src/sksl/SkSLThreadContext.h" |
Ethan Nicholas | 1780755 | 2021-10-01 09:42:36 -0400 | [diff] [blame] | 15 | #include "src/sksl/analysis/SkSLProgramVisitor.h" |
Ethan Nicholas | 1e6e919 | 2021-09-30 12:47:04 -0400 | [diff] [blame] | 16 | #include "src/sksl/ir/SkSLFunctionDefinition.h" |
| 17 | #include "src/sksl/ir/SkSLInterfaceBlock.h" |
| 18 | #include "src/sksl/ir/SkSLVarDeclarations.h" |
| 19 | |
| 20 | namespace SkSL { |
| 21 | |
| 22 | namespace Transform { |
| 23 | |
| 24 | void 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); |
Ethan Nicholas | c845272 | 2021-10-07 10:47:32 -0400 | [diff] [blame] | 70 | for (auto& e : ThreadContext::ProgramElements()) { |
Ethan Nicholas | 1e6e919 | 2021-09-30 12:47:04 -0400 | [diff] [blame] | 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 |