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