blob: 7c40983eadb0ebc45ea4911b7740a8ba0de39a08 [file] [log] [blame]
Ethan Nicholas1e6e9192021-09-30 12:47:04 -04001/*
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 Stiles71766372021-10-06 15:54:55 -040010#include "include/private/SkSLProgramKind.h"
Ethan Nicholas1e6e9192021-09-30 12:47:04 -040011#include "src/sksl/SkSLCompiler.h"
12#include "src/sksl/SkSLContext.h"
13#include "src/sksl/SkSLIntrinsicMap.h"
Ethan Nicholasc8452722021-10-07 10:47:32 -040014#include "src/sksl/SkSLThreadContext.h"
Ethan Nicholas17807552021-10-01 09:42:36 -040015#include "src/sksl/analysis/SkSLProgramVisitor.h"
Ethan Nicholas1e6e9192021-09-30 12:47:04 -040016#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);
Ethan Nicholasc8452722021-10-07 10:47:32 -040070 for (auto& e : ThreadContext::ProgramElements()) {
Ethan Nicholas1e6e9192021-09-30 12:47:04 -040071 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