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_PROGRAM 9 #define SKSL_PROGRAM 10 11 #include <vector> 12 #include <memory> 13 14 #include "include/private/SkTHash.h" 15 #include "src/sksl/SkSLAnalysis.h" 16 #include "src/sksl/ir/SkSLBoolLiteral.h" 17 #include "src/sksl/ir/SkSLExpression.h" 18 #include "src/sksl/ir/SkSLFloatLiteral.h" 19 #include "src/sksl/ir/SkSLIntLiteral.h" 20 #include "src/sksl/ir/SkSLModifiers.h" 21 #include "src/sksl/ir/SkSLProgramElement.h" 22 #include "src/sksl/ir/SkSLSymbolTable.h" 23 24 #ifdef SK_VULKAN 25 #include "src/gpu/vk/GrVkCaps.h" 26 #endif 27 28 // name of the render target width uniform 29 #define SKSL_RTWIDTH_NAME "u_skRTWidth" 30 31 // name of the render target height uniform 32 #define SKSL_RTHEIGHT_NAME "u_skRTHeight" 33 34 namespace SkSL { 35 36 class Context; 37 class Pool; 38 39 /** 40 * Side-car class holding mutable information about a Program's IR 41 */ 42 class ProgramUsage { 43 public: 44 struct VariableCounts { int fRead = 0; int fWrite = 0; }; 45 VariableCounts get(const Variable&) const; 46 bool isDead(const Variable&) const; 47 48 int get(const FunctionDeclaration&) const; 49 50 void replace(const Expression* oldExpr, const Expression* newExpr); 51 void add(const Statement* stmt); 52 void remove(const Expression* expr); 53 void remove(const Statement* stmt); 54 void remove(const ProgramElement& element); 55 56 SkTHashMap<const Variable*, VariableCounts> fVariableCounts; 57 SkTHashMap<const FunctionDeclaration*, int> fCallCounts; 58 }; 59 60 /** 61 * Represents a fully-digested program, ready for code generation. 62 */ 63 struct Program { 64 struct Settings { 65 struct Value { ValueProgram::Settings::Value66 Value(bool b) 67 : fKind(kBool_Kind) 68 , fValue(b) {} 69 ValueProgram::Settings::Value70 Value(int i) 71 : fKind(kInt_Kind) 72 , fValue(i) {} 73 ValueProgram::Settings::Value74 Value(unsigned int i) 75 : fKind(kInt_Kind) 76 , fValue(i) {} 77 ValueProgram::Settings::Value78 Value(float f) 79 : fKind(kFloat_Kind) 80 , fValueF(f) {} 81 literalProgram::Settings::Value82 std::unique_ptr<Expression> literal(const Context& context, int offset) const { 83 switch (fKind) { 84 case Program::Settings::Value::kBool_Kind: 85 return std::unique_ptr<Expression>(new BoolLiteral(context, 86 offset, 87 fValue)); 88 case Program::Settings::Value::kInt_Kind: 89 return std::unique_ptr<Expression>(new IntLiteral(context, 90 offset, 91 fValue)); 92 case Program::Settings::Value::kFloat_Kind: 93 return std::unique_ptr<Expression>(new FloatLiteral(context, 94 offset, 95 fValueF)); 96 default: 97 SkASSERT(false); 98 return nullptr; 99 } 100 } 101 102 enum { 103 kBool_Kind, 104 kInt_Kind, 105 kFloat_Kind, 106 } fKind; 107 108 union { 109 int fValue; // for kBool_Kind and kInt_Kind 110 float fValueF; // for kFloat_Kind 111 }; 112 }; 113 114 // if false, sk_FragCoord is exactly the same as gl_FragCoord. If true, the y coordinate 115 // must be flipped. 116 bool fFlipY = false; 117 // if false, sk_FragCoord is exactly the same as gl_FragCoord. If true, the w coordinate 118 // must be inversed. 119 bool fInverseW = false; 120 // If true the destination fragment color is read sk_FragColor. It must be declared inout. 121 bool fFragColorIsInOut = false; 122 // if true, Setting objects (e.g. sk_Caps.fbFetchSupport) should be replaced with their 123 // constant equivalents during compilation 124 bool fReplaceSettings = true; 125 // if true, all halfs are forced to be floats 126 bool fForceHighPrecision = false; 127 // if true, add -0.5 bias to LOD of all texture lookups 128 bool fSharpenTextures = false; 129 // if the program needs to create an RTHeight uniform, this is its offset in the uniform 130 // buffer 131 int fRTHeightOffset = -1; 132 // if the program needs to create an RTHeight uniform and is creating spriv, this is the 133 // binding and set number of the uniform buffer. 134 int fRTHeightBinding = -1; 135 int fRTHeightSet = -1; 136 // If true, remove any uncalled functions other than main(). Note that a function which 137 // starts out being used may end up being uncalled after optimization. 138 bool fRemoveDeadFunctions = true; 139 // Functions larger than this (measured in IR nodes) will not be inlined. The default value 140 // is arbitrary. A value of zero will disable the inliner entirely. 141 int fInlineThreshold = 49; 142 // true to enable optimization passes 143 bool fOptimize = true; 144 // If true, implicit conversions to lower precision numeric types are allowed 145 // (eg, float to half) 146 bool fAllowNarrowingConversions = false; 147 // If true, then Debug code will run SPIR-V output through the validator to ensure its 148 // correctness 149 bool fValidateSPIRV = true; 150 }; 151 152 struct Inputs { 153 // if true, this program requires the render target width uniform to be defined 154 bool fRTWidth; 155 156 // if true, this program requires the render target height uniform to be defined 157 bool fRTHeight; 158 159 // if true, this program must be recompiled if the flipY setting changes. If false, the 160 // program will compile to the same code regardless of the flipY setting. 161 bool fFlipY; 162 resetProgram::Inputs163 void reset() { 164 fRTWidth = false; 165 fRTHeight = false; 166 fFlipY = false; 167 } 168 isEmptyProgram::Inputs169 bool isEmpty() { 170 return !fRTWidth && !fRTHeight && !fFlipY; 171 } 172 }; 173 174 enum Kind { 175 kFragment_Kind, 176 kVertex_Kind, 177 kGeometry_Kind, 178 kFragmentProcessor_Kind, 179 kPipelineStage_Kind, 180 kGeneric_Kind, 181 }; 182 ProgramProgram183 Program(Kind kind, 184 std::unique_ptr<String> source, 185 Settings settings, 186 const ShaderCapsClass* caps, 187 std::shared_ptr<Context> context, 188 std::vector<std::unique_ptr<ProgramElement>> elements, 189 std::unique_ptr<ModifiersPool> modifiers, 190 std::shared_ptr<SymbolTable> symbols, 191 std::unique_ptr<Pool> pool, 192 Inputs inputs) 193 : fKind(kind) 194 , fSource(std::move(source)) 195 , fSettings(settings) 196 , fCaps(caps) 197 , fContext(context) 198 , fSymbols(symbols) 199 , fPool(std::move(pool)) 200 , fInputs(inputs) 201 , fElements(std::move(elements)) 202 , fModifiers(std::move(modifiers)) { 203 fUsage = Analysis::GetUsage(*this); 204 } 205 ~ProgramProgram206 ~Program() { 207 // Some or all of the program elements are in the pool. To free them safely, we must attach 208 // the pool before destroying any program elements. (Otherwise, we may accidentally call 209 // delete on a pooled node.) 210 fPool->attachToThread(); 211 fElements.clear(); 212 fContext.reset(); 213 fSymbols.reset(); 214 fModifiers.reset(); 215 fPool->detachFromThread(); 216 } 217 elementsProgram218 const std::vector<std::unique_ptr<ProgramElement>>& elements() const { return fElements; } 219 220 Kind fKind; 221 std::unique_ptr<String> fSource; 222 Settings fSettings; 223 const ShaderCapsClass* fCaps; 224 std::shared_ptr<Context> fContext; 225 // it's important to keep fElements defined after (and thus destroyed before) fSymbols, 226 // because destroying elements can modify reference counts in symbols 227 std::shared_ptr<SymbolTable> fSymbols; 228 std::unique_ptr<Pool> fPool; 229 Inputs fInputs; 230 231 private: 232 std::vector<std::unique_ptr<ProgramElement>> fElements; 233 std::unique_ptr<ModifiersPool> fModifiers; 234 std::unique_ptr<ProgramUsage> fUsage; 235 236 friend class Compiler; 237 friend class Inliner; // fUsage 238 friend class SPIRVCodeGenerator; // fModifiers 239 }; 240 241 } // namespace SkSL 242 243 #endif 244