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