• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "include/core/SkSize.h"
15 #include "src/sksl/SkSLAnalysis.h"
16 #include "src/sksl/SkSLContext.h"
17 #include "src/sksl/SkSLInliner.h"
18 #include "src/sksl/SkSLParsedModule.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_LASTFRAGCOLOR_BUILTIN       10008
28 #define SK_MAIN_COORDS_BUILTIN         10009
29 #define SK_INPUT_COLOR_BUILTIN         10010
30 #define SK_DEST_COLOR_BUILTIN          10011
31 #define SK_SECONDARYFRAGCOLOR_BUILTIN  10012
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_POSITION_BUILTIN                0
37 
38 class SkBitSet;
39 class SkSLCompileBench;
40 
41 namespace SkSL {
42 
43 namespace dsl {
44     class DSLCore;
45     class DSLWriter;
46 }
47 
48 class ExternalFunction;
49 class FunctionDeclaration;
50 class ProgramUsage;
51 
52 struct LoadedModule {
53     ProgramKind                                  fKind;
54     std::shared_ptr<SymbolTable>                 fSymbols;
55     std::vector<std::unique_ptr<ProgramElement>> fElements;
56 };
57 
58 /**
59  * Main compiler entry point. This is a traditional compiler design which first parses the .sksl
60  * file into an abstract syntax tree (a tree of ASTNodes), then performs semantic analysis to
61  * produce a Program (a tree of IRNodes), then feeds the Program into a CodeGenerator to produce
62  * compiled output.
63  *
64  * See the README for information about SkSL.
65  */
66 class SK_API Compiler {
67 public:
68     inline static constexpr const char FRAGCOLOR_NAME[] = "sk_FragColor";
69     inline static constexpr const char RTADJUST_NAME[]  = "sk_RTAdjust";
70     inline static constexpr const char PERVERTEX_NAME[] = "sk_PerVertex";
71     inline static constexpr const char POISON_TAG[]     = "<POISON>";
72 
73     /**
74      * Gets a float4 that adjusts the position from Skia device coords to normalized device coords,
75      * used to populate sk_RTAdjust.  Assuming the transformed position, pos, is a homogeneous
76      * float4, the vec, v, is applied as such:
77      * float4((pos.xy * v.xz) + sk_Position.ww * v.yw, 0, pos.w);
78      */
GetRTAdjustVector(SkISize rtDims,bool flipY)79     static std::array<float, 4> GetRTAdjustVector(SkISize rtDims, bool flipY) {
80         std::array<float, 4> result;
81         result[0] = 2.f/rtDims.width();
82         result[2] = 2.f/rtDims.height();
83         result[1] = -1.f;
84         result[3] = -1.f;
85         if (flipY) {
86             result[2] = -result[2];
87             result[3] = -result[3];
88         }
89         return result;
90     }
91 
92     /**
93      * Uniform values  by the compiler to implement origin-neutral dFdy, sk_Clockwise, and
94      * sk_FragCoord.
95      */
GetRTFlipVector(int rtHeight,bool flipY)96     static std::array<float, 2> GetRTFlipVector(int rtHeight, bool flipY) {
97         std::array<float, 2> result;
98         result[0] = flipY ? rtHeight : 0.f;
99         result[1] = flipY ?     -1.f : 1.f;
100         return result;
101     }
102 
103     struct OptimizationContext {
104         // nodes we have already reported errors for and should not error on again
105         std::unordered_set<const IRNode*> fSilences;
106         // true if we have updated the CFG during this pass
107         bool fUpdated = false;
108         // true if we need to completely regenerate the CFG
109         bool fNeedsRescan = false;
110         // Metadata about function and variable usage within the program
111         ProgramUsage* fUsage = nullptr;
112         // Nodes which we can't throw away until the end of optimization
113         StatementArray fOwnedStatements;
114     };
115 
116     Compiler(const ShaderCapsClass* caps);
117 
118     ~Compiler();
119 
120     Compiler(const Compiler&) = delete;
121     Compiler& operator=(const Compiler&) = delete;
122 
123     /**
124      * Allows optimization settings to be unilaterally overridden. This is meant to allow tools like
125      * Viewer or Nanobench to override the compiler's ProgramSettings and ShaderCaps for debugging.
126      */
127     enum class OverrideFlag {
128         kDefault,
129         kOff,
130         kOn,
131     };
EnableOptimizer(OverrideFlag flag)132     static void EnableOptimizer(OverrideFlag flag) { sOptimizer = flag; }
EnableInliner(OverrideFlag flag)133     static void EnableInliner(OverrideFlag flag) { sInliner = flag; }
134 
135     /**
136      * If fExternalFunctions is supplied in the settings, those values are registered in the symbol
137      * table of the Program, but ownership is *not* transferred. It is up to the caller to keep them
138      * alive.
139      */
140     std::unique_ptr<Program> convertProgram(
141             ProgramKind kind,
142             String text,
143             Program::Settings settings);
144 
145     std::unique_ptr<Expression> convertIdentifier(int line, skstd::string_view name);
146 
147     bool toSPIRV(Program& program, OutputStream& out);
148 
149     bool toSPIRV(Program& program, String* out);
150 
151     bool toGLSL(Program& program, OutputStream& out);
152 
153     bool toGLSL(Program& program, String* out);
154 
155     bool toHLSL(Program& program, String* out);
156 
157     bool toMetal(Program& program, OutputStream& out);
158 
159     bool toMetal(Program& program, String* out);
160 
161     void handleError(skstd::string_view msg, PositionInfo pos);
162 
163     String errorText(bool showCount = true);
164 
errorReporter()165     ErrorReporter& errorReporter() { return *fContext->fErrors; }
166 
errorCount()167     int errorCount() const { return fContext->fErrors->errorCount(); }
168 
169     void writeErrorCount();
170 
resetErrors()171     void resetErrors() {
172         fErrorText.clear();
173         this->errorReporter().resetErrorCount();
174     }
175 
context()176     Context& context() {
177         return *fContext;
178     }
179 
180     // When  SKSL_STANDALONE, fPath is used. (fData, fSize) will be (nullptr, 0)
181     // When !SKSL_STANDALONE, fData and fSize are used. fPath will be nullptr.
182     struct ModuleData {
183         const char*    fPath;
184 
185         const uint8_t* fData;
186         size_t         fSize;
187     };
188 
MakeModulePath(const char * path)189     static ModuleData MakeModulePath(const char* path) {
190         return ModuleData{path, /*fData=*/nullptr, /*fSize=*/0};
191     }
MakeModuleData(const uint8_t * data,size_t size)192     static ModuleData MakeModuleData(const uint8_t* data, size_t size) {
193         return ModuleData{/*fPath=*/nullptr, data, size};
194     }
195 
196     LoadedModule loadModule(ProgramKind kind, ModuleData data, std::shared_ptr<SymbolTable> base,
197                             bool dehydrate);
198     ParsedModule parseModule(ProgramKind kind, ModuleData data, const ParsedModule& base);
199 
200     const ParsedModule& moduleForProgramKind(ProgramKind kind);
201 
202 private:
203     class CompilerErrorReporter : public ErrorReporter {
204     public:
CompilerErrorReporter(Compiler * compiler)205         CompilerErrorReporter(Compiler* compiler)
206             : fCompiler(*compiler) {}
207 
handleError(skstd::string_view msg,PositionInfo pos)208         void handleError(skstd::string_view msg, PositionInfo pos) override {
209             fCompiler.handleError(msg, pos);
210         }
211 
212     private:
213         Compiler& fCompiler;
214     };
215 
216     const ParsedModule& loadGPUModule();
217     const ParsedModule& loadFragmentModule();
218     const ParsedModule& loadVertexModule();
219     const ParsedModule& loadPublicModule();
220     const ParsedModule& loadRuntimeShaderModule();
221 
222     std::shared_ptr<SymbolTable> makeRootSymbolTable();
223     std::shared_ptr<SymbolTable> makePrivateSymbolTable(std::shared_ptr<SymbolTable> parent);
224 
225     /** Optimize every function in the program. */
226     bool optimize(Program& program);
227 
228     /** Performs final checks to confirm that a fully-assembled/optimized is valid. */
229     bool finalize(Program& program);
230 
231     /** Optimize the module. */
232     bool optimize(LoadedModule& module);
233 
234     /** Flattens out function calls when it is safe to do so. */
235     bool runInliner(const std::vector<std::unique_ptr<ProgramElement>>& elements,
236                     std::shared_ptr<SymbolTable> symbols,
237                     ProgramUsage* usage);
238 
239     CompilerErrorReporter fErrorReporter;
240     std::shared_ptr<Context> fContext;
241 
242     ParsedModule fRootModule;                // Core types
243 
244     ParsedModule fPrivateModule;             // [Root] + Internal types
245     ParsedModule fGPUModule;                 // [Private] + GPU intrinsics, helper functions
246     ParsedModule fVertexModule;              // [GPU] + Vertex stage decls
247     ParsedModule fFragmentModule;            // [GPU] + Fragment stage decls
248 
249     ParsedModule fPublicModule;              // [Root] + Public features
250     ParsedModule fRuntimeShaderModule;       // [Public] + Runtime shader decls
251 
252     // holds ModifiersPools belonging to the core includes for lifetime purposes
253     ModifiersPool fCoreModifiers;
254 
255     Mangler fMangler;
256     Inliner fInliner;
257     // This is the current symbol table of the code we are processing, and therefore changes during
258     // compilation
259     std::shared_ptr<SymbolTable> fSymbolTable;
260 
261     String fErrorText;
262 
263     static OverrideFlag sOptimizer;
264     static OverrideFlag sInliner;
265 
266     friend class AutoSource;
267     friend class ::SkSLCompileBench;
268     friend class DSLParser;
269     friend class ThreadContext;
270     friend class dsl::DSLCore;
271 };
272 
273 }  // namespace SkSL
274 
275 #endif
276