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 "include/core/SkSize.h" 12 #include "include/core/SkTypes.h" 13 #include "src/sksl/SkSLContext.h" // IWYU pragma: keep 14 #include "src/sksl/SkSLErrorReporter.h" 15 #include "src/sksl/SkSLPosition.h" 16 #include "src/sksl/ir/SkSLProgramElement.h" 17 #include "src/sksl/ir/SkSLSymbolTable.h" 18 19 #include <array> 20 #include <cstdint> 21 #include <memory> 22 #include <string> 23 #include <string_view> 24 #include <type_traits> 25 #include <vector> 26 27 constexpr int SK_FRAGCOLOR_BUILTIN = 10001; 28 constexpr int SK_LASTFRAGCOLOR_BUILTIN = 10008; 29 constexpr int SK_SECONDARYFRAGCOLOR_BUILTIN = 10012; 30 constexpr int SK_FRAGCOORD_BUILTIN = 15; 31 constexpr int SK_CLOCKWISE_BUILTIN = 17; 32 constexpr int SK_SAMPLEMASKIN_BUILTIN = 20; 33 constexpr int SK_SAMPLEMASK_BUILTIN = 10020; 34 35 constexpr int SK_VERTEXID_BUILTIN = 42; 36 constexpr int SK_INSTANCEID_BUILTIN = 43; 37 constexpr int SK_POSITION_BUILTIN = 0; 38 constexpr int SK_POINTSIZE_BUILTIN = 1; 39 40 constexpr int SK_NUMWORKGROUPS_BUILTIN = 24; 41 constexpr int SK_WORKGROUPID_BUILTIN = 26; 42 constexpr int SK_LOCALINVOCATIONID_BUILTIN = 27; 43 constexpr int SK_GLOBALINVOCATIONID_BUILTIN = 28; 44 constexpr int SK_LOCALINVOCATIONINDEX_BUILTIN = 29; 45 46 namespace SkSL { 47 48 class Inliner; 49 class Pool; 50 struct ProgramConfig; 51 class ProgramUsage; 52 enum class ProgramKind : int8_t; 53 struct Program; 54 struct ProgramSettings; 55 56 struct Module { 57 const Module* fParent = nullptr; 58 std::unique_ptr<SymbolTable> fSymbols; 59 std::vector<std::unique_ptr<ProgramElement>> fElements; 60 }; 61 62 /** 63 * Main compiler entry point. The compiler parses the SkSL text directly into a tree of IRNodes, 64 * while performing basic optimizations such as constant-folding and dead-code elimination. Then the 65 * Program is passed into a CodeGenerator to produce compiled output. 66 * 67 * See the README for information about SkSL. 68 */ 69 class SK_API Compiler { 70 public: 71 inline static constexpr const char FRAGCOLOR_NAME[] = "sk_FragColor"; 72 inline static constexpr const char RTADJUST_NAME[] = "sk_RTAdjust"; 73 inline static constexpr const char POSITION_NAME[] = "sk_Position"; 74 inline static constexpr const char POISON_TAG[] = "<POISON>"; 75 76 /** 77 * Gets a float4 that adjusts the position from Skia device coords to normalized device coords, 78 * used to populate sk_RTAdjust. Assuming the transformed position, pos, is a homogeneous 79 * float4, the vec, v, is applied as such: 80 * float4((pos.xy * v.xz) + sk_Position.ww * v.yw, 0, pos.w); 81 */ GetRTAdjustVector(SkISize rtDims,bool flipY)82 static std::array<float, 4> GetRTAdjustVector(SkISize rtDims, bool flipY) { 83 std::array<float, 4> result; 84 result[0] = 2.f/rtDims.width(); 85 result[2] = 2.f/rtDims.height(); 86 result[1] = -1.f; 87 result[3] = -1.f; 88 if (flipY) { 89 result[2] = -result[2]; 90 result[3] = -result[3]; 91 } 92 return result; 93 } 94 95 /** 96 * Uniform values used by the compiler to implement origin-neutral dFdy, sk_Clockwise, and 97 * sk_FragCoord. 98 */ GetRTFlipVector(int rtHeight,bool flipY)99 static std::array<float, 2> GetRTFlipVector(int rtHeight, bool flipY) { 100 std::array<float, 2> result; 101 result[0] = flipY ? rtHeight : 0.f; 102 result[1] = flipY ? -1.f : 1.f; 103 return result; 104 } 105 106 Compiler(); 107 ~Compiler(); 108 109 Compiler(const Compiler&) = delete; 110 Compiler& operator=(const Compiler&) = delete; 111 112 /** 113 * Allows optimization settings to be unilaterally overridden. This is meant to allow tools like 114 * Viewer or Nanobench to override the compiler's ProgramSettings and ShaderCaps for debugging. 115 */ 116 enum class OverrideFlag { 117 kDefault, 118 kOff, 119 kOn, 120 }; EnableOptimizer(OverrideFlag flag)121 static void EnableOptimizer(OverrideFlag flag) { sOptimizer = flag; } EnableInliner(OverrideFlag flag)122 static void EnableInliner(OverrideFlag flag) { sInliner = flag; } 123 124 std::unique_ptr<Program> convertProgram(ProgramKind kind, 125 std::string programSource, 126 const ProgramSettings& settings); 127 128 void handleError(std::string_view msg, Position pos); 129 130 std::string errorText(bool showCount = true); 131 errorReporter()132 ErrorReporter& errorReporter() { return *fContext->fErrors; } 133 errorCount()134 int errorCount() const { return fContext->fErrors->errorCount(); } 135 136 void writeErrorCount(); 137 resetErrors()138 void resetErrors() { 139 fErrorText.clear(); 140 this->errorReporter().resetErrorCount(); 141 } 142 context()143 Context& context() const { 144 return *fContext; 145 } 146 globalSymbols()147 SymbolTable* globalSymbols() { 148 return fGlobalSymbols.get(); 149 } 150 symbolTable()151 SymbolTable* symbolTable() { 152 return fContext->fSymbolTable; 153 } 154 155 std::unique_ptr<Module> compileModule(ProgramKind kind, 156 const char* moduleName, 157 std::string moduleSource, 158 const Module* parentModule, 159 bool shouldInline); 160 161 /** Optimize a module at minification time, before writing it out. */ 162 bool optimizeModuleBeforeMinifying(ProgramKind kind, Module& module, bool shrinkSymbols); 163 164 const Module* moduleForProgramKind(ProgramKind kind); 165 166 /** Run the inliner on a program which was compiled earlier (with inlining turned off). */ 167 void runInliner(Program& program); 168 169 private: 170 class CompilerErrorReporter : public ErrorReporter { 171 public: CompilerErrorReporter(Compiler * compiler)172 CompilerErrorReporter(Compiler* compiler) 173 : fCompiler(*compiler) {} 174 handleError(std::string_view msg,Position pos)175 void handleError(std::string_view msg, Position pos) override { 176 fCompiler.handleError(msg, pos); 177 } 178 179 private: 180 Compiler& fCompiler; 181 }; 182 183 /** Updates ProgramSettings to eliminate contradictions and to honor the ProgramKind. */ 184 static void FinalizeSettings(ProgramSettings* settings, ProgramKind kind); 185 186 /** Prepares the Context for compilation of a program or module. */ 187 void initializeContext(const SkSL::Module* module, 188 ProgramKind kind, 189 ProgramSettings settings, 190 std::string_view source, 191 bool isModule); 192 193 /** Cleans up the Context post-compilation. */ 194 void cleanupContext(); 195 196 /** 197 * Returns all global elements (functions and global variables) as a self-contained Program. 198 * The optional source string is retained as the program's source. 199 */ 200 std::unique_ptr<SkSL::Program> releaseProgram( 201 std::unique_ptr<std::string> source, 202 std::vector<std::unique_ptr<SkSL::ProgramElement>> programElements); 203 204 /** Optimize every function in the program. */ 205 bool optimize(Program& program); 206 207 /** Performs final checks to confirm that a fully-assembled/optimized is valid. */ 208 bool finalize(Program& program); 209 210 /** Optimize a module at Skia runtime, after loading it. */ 211 bool optimizeModuleAfterLoading(ProgramKind kind, Module& module); 212 213 /** Flattens out function calls when it is safe to do so. */ 214 bool runInliner(Inliner* inliner, 215 const std::vector<std::unique_ptr<ProgramElement>>& elements, 216 SymbolTable* symbols, 217 ProgramUsage* usage); 218 219 CompilerErrorReporter fErrorReporter; 220 std::shared_ptr<Context> fContext; 221 std::unique_ptr<SymbolTable> fGlobalSymbols; 222 std::unique_ptr<ProgramConfig> fConfig; 223 std::unique_ptr<Pool> fPool; 224 225 std::string fErrorText; 226 227 static OverrideFlag sOptimizer; 228 static OverrideFlag sInliner; 229 230 friend class Parser; 231 friend class ThreadContext; 232 }; 233 234 } // namespace SkSL 235 236 #endif 237