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