• 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 struct ShaderCaps;
52 
53 struct LoadedModule {
54     ProgramKind                                  fKind;
55     std::shared_ptr<SymbolTable>                 fSymbols;
56     std::vector<std::unique_ptr<ProgramElement>> fElements;
57 };
58 
59 /**
60  * Main compiler entry point. The compiler parses the SkSL text directly into a tree of IRNodes,
61  * while performing basic optimizations such as constant-folding and dead-code elimination. Then the
62  * Program is passed into a CodeGenerator to produce 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 ShaderCaps* 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             std::string text,
143             Program::Settings settings);
144 
145     std::unique_ptr<Expression> convertIdentifier(int line, std::string_view name);
146 
147     bool toSPIRV(Program& program, OutputStream& out);
148 
149     bool toSPIRV(Program& program, std::string* out);
150 
151     bool toGLSL(Program& program, OutputStream& out);
152 
153     bool toGLSL(Program& program, std::string* out);
154 
155     bool toHLSL(Program& program, OutputStream& out);
156 
157     bool toHLSL(Program& program, std::string* out);
158 
159     bool toMetal(Program& program, OutputStream& out);
160 
161     bool toMetal(Program& program, std::string* out);
162 
163     void handleError(std::string_view msg, PositionInfo pos);
164 
165     std::string errorText(bool showCount = true);
166 
errorReporter()167     ErrorReporter& errorReporter() { return *fContext->fErrors; }
168 
errorCount()169     int errorCount() const { return fContext->fErrors->errorCount(); }
170 
171     void writeErrorCount();
172 
resetErrors()173     void resetErrors() {
174         fErrorText.clear();
175         this->errorReporter().resetErrorCount();
176     }
177 
context()178     Context& context() const {
179         return *fContext;
180     }
181 
symbolTable()182     std::shared_ptr<SymbolTable> symbolTable() const {
183         return fSymbolTable;
184     }
185 
186     // When  SKSL_STANDALONE, fPath is used. (fData, fSize) will be (nullptr, 0)
187     // When !SKSL_STANDALONE, fData and fSize are used. fPath will be nullptr.
188     struct ModuleData {
189         const char*    fPath;
190 
191         const uint8_t* fData;
192         size_t         fSize;
193     };
194 
MakeModulePath(const char * path)195     static ModuleData MakeModulePath(const char* path) {
196         return ModuleData{path, /*fData=*/nullptr, /*fSize=*/0};
197     }
MakeModuleData(const uint8_t * data,size_t size)198     static ModuleData MakeModuleData(const uint8_t* data, size_t size) {
199         return ModuleData{/*fPath=*/nullptr, data, size};
200     }
201 
202     LoadedModule loadModule(ProgramKind kind, ModuleData data, std::shared_ptr<SymbolTable> base,
203                             bool dehydrate);
204     ParsedModule parseModule(ProgramKind kind, ModuleData data, const ParsedModule& base);
205 
206     const ParsedModule& moduleForProgramKind(ProgramKind kind);
207 
208 private:
209     class CompilerErrorReporter : public ErrorReporter {
210     public:
CompilerErrorReporter(Compiler * compiler)211         CompilerErrorReporter(Compiler* compiler)
212             : fCompiler(*compiler) {}
213 
handleError(std::string_view msg,PositionInfo pos)214         void handleError(std::string_view msg, PositionInfo pos) override {
215             fCompiler.handleError(msg, pos);
216         }
217 
218     private:
219         Compiler& fCompiler;
220     };
221 
222     const ParsedModule& loadGPUModule();
223     const ParsedModule& loadFragmentModule();
224     const ParsedModule& loadVertexModule();
225     const ParsedModule& loadPublicModule();
226     const ParsedModule& loadRuntimeShaderModule();
227 
228     std::shared_ptr<SymbolTable> makeRootSymbolTable() const;
229     std::shared_ptr<SymbolTable> makeGLSLRootSymbolTable() const;
230     std::shared_ptr<SymbolTable> makePrivateSymbolTable(std::shared_ptr<SymbolTable> parent);
231 
232     /** Optimize every function in the program. */
233     bool optimize(Program& program);
234 
235     /** Performs final checks to confirm that a fully-assembled/optimized is valid. */
236     bool finalize(Program& program);
237 
238     /** Optimize the module. */
239     bool optimize(LoadedModule& module);
240 
241     /** Flattens out function calls when it is safe to do so. */
242     bool runInliner(const std::vector<std::unique_ptr<ProgramElement>>& elements,
243                     std::shared_ptr<SymbolTable> symbols,
244                     ProgramUsage* usage);
245 
246     CompilerErrorReporter fErrorReporter;
247     std::shared_ptr<Context> fContext;
248 
249     ParsedModule fRootModule;                // Core types
250 
251     ParsedModule fPrivateModule;             // [Root] + Internal types
252     ParsedModule fGPUModule;                 // [Private] + GPU intrinsics, helper functions
253     ParsedModule fVertexModule;              // [GPU] + Vertex stage decls
254     ParsedModule fFragmentModule;            // [GPU] + Fragment stage decls
255 
256     ParsedModule fPublicModule;              // [Root] + Public features
257     ParsedModule fRuntimeShaderModule;       // [Public] + Runtime shader decls
258 
259     // holds ModifiersPools belonging to the core includes for lifetime purposes
260     ModifiersPool fCoreModifiers;
261 
262     Mangler fMangler;
263     Inliner fInliner;
264     // This is the current symbol table of the code we are processing, and therefore changes during
265     // compilation
266     std::shared_ptr<SymbolTable> fSymbolTable;
267 
268     std::string fErrorText;
269 
270     static OverrideFlag sOptimizer;
271     static OverrideFlag sInliner;
272 
273     friend class AutoSource;
274     friend class ::SkSLCompileBench;
275     friend class DSLParser;
276     friend class Rehydrator;
277     friend class ThreadContext;
278     friend class dsl::DSLCore;
279 };
280 
281 }  // namespace SkSL
282 
283 #endif
284