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 #ifndef SKSL_COMPILER
9 #define SKSL_COMPILER
10 
11 #include <set>
12 #include <unordered_set>
13 #include <vector>
14 #include "src/sksl/SkSLASTFile.h"
15 #include "src/sksl/SkSLAnalysis.h"
16 #include "src/sksl/SkSLContext.h"
17 #include "src/sksl/SkSLErrorReporter.h"
18 #include "src/sksl/SkSLInliner.h"
19 #include "src/sksl/ir/SkSLProgram.h"
20 #include "src/sksl/ir/SkSLSymbolTable.h"
21 
22 #if !defined(SKSL_STANDALONE) && SK_SUPPORT_GPU
23 #include "src/gpu/GrShaderVar.h"
24 #endif
25 
26 #define SK_FRAGCOLOR_BUILTIN           10001
27 #define SK_IN_BUILTIN                  10002
28 #define SK_OUT_BUILTIN                 10007
29 #define SK_LASTFRAGCOLOR_BUILTIN       10008
30 #define SK_MAIN_COORDS_BUILTIN         10009
31 #define SK_INPUT_COLOR_BUILTIN         10010
32 #define SK_FRAGCOORD_BUILTIN              15
33 #define SK_CLOCKWISE_BUILTIN              17
34 #define SK_VERTEXID_BUILTIN               42
35 #define SK_INSTANCEID_BUILTIN             43
36 #define SK_INVOCATIONID_BUILTIN            8
37 #define SK_POSITION_BUILTIN                0
38 
39 class SkBitSet;
40 class SkSLCompileBench;
41 
42 namespace SkSL {
43 
44 namespace dsl {
45     class DSLWriter;
46 }
47 
48 class ExternalFunction;
49 class FunctionDeclaration;
50 class IRGenerator;
51 class IRIntrinsicMap;
52 class ProgramUsage;
53 
54 struct LoadedModule {
55     ProgramKind                                  fKind;
56     std::shared_ptr<SymbolTable>                 fSymbols;
57     std::vector<std::unique_ptr<ProgramElement>> fElements;
58 };
59 
60 struct ParsedModule {
61     std::shared_ptr<SymbolTable>    fSymbols;
62     std::shared_ptr<IRIntrinsicMap> fIntrinsics;
63 };
64 
65 /**
66  * Main compiler entry point. This is a traditional compiler design which first parses the .sksl
67  * file into an abstract syntax tree (a tree of ASTNodes), then performs semantic analysis to
68  * produce a Program (a tree of IRNodes), then feeds the Program into a CodeGenerator to produce
69  * compiled output.
70  *
71  * See the README for information about SkSL.
72  */
73 class SK_API Compiler : public ErrorReporter {
74 public:
75     static constexpr const char FRAGCOLOR_NAME[]  = "sk_FragColor";
76     static constexpr const char RTADJUST_NAME[]  = "sk_RTAdjust";
77     static constexpr const char PERVERTEX_NAME[] = "sk_PerVertex";
78 
79     struct OptimizationContext {
80         // nodes we have already reported errors for and should not error on again
81         std::unordered_set<const IRNode*> fSilences;
82         // true if we have updated the CFG during this pass
83         bool fUpdated = false;
84         // true if we need to completely regenerate the CFG
85         bool fNeedsRescan = false;
86         // Metadata about function and variable usage within the program
87         ProgramUsage* fUsage = nullptr;
88         // Nodes which we can't throw away until the end of optimization
89         StatementArray fOwnedStatements;
90     };
91 
92     Compiler(const ShaderCapsClass* caps);
93 
94     ~Compiler() override;
95 
96     Compiler(const Compiler&) = delete;
97     Compiler& operator=(const Compiler&) = delete;
98 
99     /**
100      * Allows optimization settings to be unilaterally overridden. This is meant to allow tools like
101      * Viewer or Nanobench to override the compiler's ProgramSettings and ShaderCaps for debugging.
102      */
103     enum class OverrideFlag {
104         kDefault,
105         kOff,
106         kOn,
107     };
EnableOptimizer(OverrideFlag flag)108     static void EnableOptimizer(OverrideFlag flag) { sOptimizer = flag; }
EnableInliner(OverrideFlag flag)109     static void EnableInliner(OverrideFlag flag) { sInliner = flag; }
110 
111     /**
112      * If externalFunctions is supplied, those values are registered in the symbol table of the
113      * Program, but ownership is *not* transferred. It is up to the caller to keep them alive.
114      */
115     std::unique_ptr<Program> convertProgram(
116             ProgramKind kind,
117             String text,
118             const Program::Settings& settings,
119             const std::vector<std::unique_ptr<ExternalFunction>>* externalFunctions = nullptr);
120 
121     bool toSPIRV(Program& program, OutputStream& out);
122 
123     bool toSPIRV(Program& program, String* out);
124 
125     bool toGLSL(Program& program, OutputStream& out);
126 
127     bool toGLSL(Program& program, String* out);
128 
129     bool toHLSL(Program& program, String* out);
130 
131     bool toMetal(Program& program, OutputStream& out);
132 
133     bool toMetal(Program& program, String* out);
134 
135 #if defined(SKSL_STANDALONE) || GR_TEST_UTILS
136     bool toCPP(Program& program, String name, OutputStream& out);
137 
138     bool toDSLCPP(Program& program, String name, OutputStream& out);
139 
140     bool toH(Program& program, String name, OutputStream& out);
141 #endif
142 
143     void error(int offset, String msg) override;
144 
145     String errorText(bool showCount = true);
146 
147     void writeErrorCount();
148 
errorCount()149     int errorCount() override {
150         return fErrorCount;
151     }
152 
153     void setErrorCount(int c) override;
154 
context()155     Context& context() {
156         return *fContext;
157     }
158 
159     // When  SKSL_STANDALONE, fPath is used. (fData, fSize) will be (nullptr, 0)
160     // When !SKSL_STANDALONE, fData and fSize are used. fPath will be nullptr.
161     struct ModuleData {
162         const char*    fPath;
163 
164         const uint8_t* fData;
165         size_t         fSize;
166     };
167 
MakeModulePath(const char * path)168     static ModuleData MakeModulePath(const char* path) {
169         return ModuleData{path, /*fData=*/nullptr, /*fSize=*/0};
170     }
MakeModuleData(const uint8_t * data,size_t size)171     static ModuleData MakeModuleData(const uint8_t* data, size_t size) {
172         return ModuleData{/*fPath=*/nullptr, data, size};
173     }
174 
175     LoadedModule loadModule(ProgramKind kind, ModuleData data, std::shared_ptr<SymbolTable> base,
176                             bool dehydrate);
177     ParsedModule parseModule(ProgramKind kind, ModuleData data, const ParsedModule& base);
178 
irGenerator()179     IRGenerator& irGenerator() {
180         return *fIRGenerator;
181     }
182 
183     const ParsedModule& moduleForProgramKind(ProgramKind kind);
184 
185 private:
186     const ParsedModule& loadGPUModule();
187     const ParsedModule& loadFragmentModule();
188     const ParsedModule& loadVertexModule();
189     const ParsedModule& loadFPModule();
190     const ParsedModule& loadGeometryModule();
191     const ParsedModule& loadPublicModule();
192     const ParsedModule& loadRuntimeColorFilterModule();
193     const ParsedModule& loadRuntimeShaderModule();
194 
195     /** Verifies that @if and @switch statements were actually optimized away. */
196     void verifyStaticTests(const Program& program);
197 
198     /** Optimize every function in the program. */
199     bool optimize(Program& program);
200 
201     /** Optimize the module. */
202     bool optimize(LoadedModule& module);
203 
204     /** Eliminates unused functions from a Program, according to the stats in ProgramUsage. */
205     bool removeDeadFunctions(Program& program, ProgramUsage* usage);
206 
207     /** Eliminates unreferenced variables from a Program, according to the stats in ProgramUsage. */
208     bool removeDeadGlobalVariables(Program& program, ProgramUsage* usage);
209     bool removeDeadLocalVariables(Program& program, ProgramUsage* usage);
210 
211     Position position(int offset);
212 
213     std::shared_ptr<Context> fContext;
214 
215     std::shared_ptr<SymbolTable> fRootSymbolTable;
216     std::shared_ptr<SymbolTable> fPrivateSymbolTable;
217 
218     ParsedModule fRootModule;                // Core types
219 
220     ParsedModule fPrivateModule;             // [Root] + Internal types
221     ParsedModule fGPUModule;                 // [Private] + GPU intrinsics, helper functions
222     ParsedModule fVertexModule;              // [GPU] + Vertex stage decls
223     ParsedModule fFragmentModule;            // [GPU] + Fragment stage decls
224     ParsedModule fGeometryModule;            // [GPU] + Geometry stage decls
225     ParsedModule fFPModule;                  // [GPU] + FP features
226 
227     ParsedModule fPublicModule;              // [Root] + Public features
228     ParsedModule fRuntimeColorFilterModule;  // [Public] + Runtime shader decls
229     ParsedModule fRuntimeShaderModule;       // [Public] + Runtime color filter decls
230 
231     // holds ModifiersPools belonging to the core includes for lifetime purposes
232     ModifiersPool fCoreModifiers;
233 
234     Inliner fInliner;
235     std::unique_ptr<IRGenerator> fIRGenerator;
236 
237     const String* fSource = nullptr;
238     int fErrorCount = 0;
239     String fErrorText;
240     std::vector<size_t> fErrorTextLength;
241 
242     static OverrideFlag sOptimizer;
243     static OverrideFlag sInliner;
244 
245     friend class AutoSource;
246     friend class ::SkSLCompileBench;
247     friend class dsl::DSLWriter;
248 };
249 
250 }  // namespace SkSL
251 
252 #endif
253