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 "SkSLBoolLiteral.h" 15 #include "SkSLExpression.h" 16 #include "SkSLIntLiteral.h" 17 #include "SkSLModifiers.h" 18 #include "SkSLProgramElement.h" 19 #include "SkSLSymbolTable.h" 20 21 // name of the render target width uniform 22 #define SKSL_RTWIDTH_NAME "u_skRTWidth" 23 24 // name of the render target height uniform 25 #define SKSL_RTHEIGHT_NAME "u_skRTHeight" 26 27 namespace SkSL { 28 29 class Context; 30 31 /** 32 * Represents a fully-digested program, ready for code generation. 33 */ 34 struct Program { 35 struct Settings { 36 struct Value { ValueProgram::Settings::Value37 Value(bool b) 38 : fKind(kBool_Kind) 39 , fValue(b) {} 40 ValueProgram::Settings::Value41 Value(int i) 42 : fKind(kInt_Kind) 43 , fValue(i) {} 44 ValueProgram::Settings::Value45 Value(unsigned int i) 46 : fKind(kInt_Kind) 47 , fValue(i) {} 48 literalProgram::Settings::Value49 std::unique_ptr<Expression> literal(const Context& context, int offset) const { 50 switch (fKind) { 51 case Program::Settings::Value::kBool_Kind: 52 return std::unique_ptr<Expression>(new BoolLiteral(context, 53 offset, 54 fValue)); 55 case Program::Settings::Value::kInt_Kind: 56 return std::unique_ptr<Expression>(new IntLiteral(context, 57 offset, 58 fValue)); 59 default: 60 SkASSERT(false); 61 return nullptr; 62 } 63 } 64 65 enum { 66 kBool_Kind, 67 kInt_Kind, 68 } fKind; 69 70 int fValue; 71 }; 72 73 #ifdef SKSL_STANDALONE 74 const StandaloneShaderCaps* fCaps = &standaloneCaps; 75 #else 76 const GrShaderCaps* fCaps = nullptr; 77 #endif 78 // if false, sk_FragCoord is exactly the same as gl_FragCoord. If true, the y coordinate 79 // must be flipped. 80 bool fFlipY = false; 81 // If true the destination fragment color is read sk_FragColor. It must be declared inout. 82 bool fFragColorIsInOut = false; 83 // if true, Setting objects (e.g. sk_Caps.fbFetchSupport) should be replaced with their 84 // constant equivalents during compilation 85 bool fReplaceSettings = true; 86 // if true, all halfs are forced to be floats 87 bool fForceHighPrecision = false; 88 // if true, add -0.5 bias to LOD of all texture lookups 89 bool fSharpenTextures = false; 90 std::unordered_map<String, Value> fArgs; 91 }; 92 93 struct Inputs { 94 // if true, this program requires the render target width uniform to be defined 95 bool fRTWidth; 96 97 // if true, this program requires the render target height uniform to be defined 98 bool fRTHeight; 99 100 // if true, this program must be recompiled if the flipY setting changes. If false, the 101 // program will compile to the same code regardless of the flipY setting. 102 bool fFlipY; 103 resetProgram::Inputs104 void reset() { 105 fRTWidth = false; 106 fRTHeight = false; 107 fFlipY = false; 108 } 109 isEmptyProgram::Inputs110 bool isEmpty() { 111 return !fRTWidth && !fRTHeight && !fFlipY; 112 } 113 }; 114 115 class iterator { 116 public: 117 ProgramElement& operator*() { 118 if (fIter1 != fEnd1) { 119 return **fIter1; 120 } 121 return **fIter2; 122 } 123 124 iterator& operator++() { 125 if (fIter1 != fEnd1) { 126 ++fIter1; 127 return *this; 128 } 129 ++fIter2; 130 return *this; 131 } 132 133 bool operator==(const iterator& other) const { 134 return fIter1 == other.fIter1 && fIter2 == other.fIter2; 135 } 136 137 bool operator!=(const iterator& other) const { 138 return !(*this == other); 139 } 140 141 private: 142 using inner = std::vector<std::unique_ptr<ProgramElement>>::iterator; 143 iteratorProgram144 iterator(inner begin1, inner end1, inner begin2, inner end2) 145 : fIter1(begin1) 146 , fEnd1(end1) 147 , fIter2(begin2) 148 , fEnd2(end2) {} 149 150 inner fIter1; 151 inner fEnd1; 152 inner fIter2; 153 inner fEnd2; 154 155 friend struct Program; 156 }; 157 158 class const_iterator { 159 public: 160 const ProgramElement& operator*() { 161 if (fIter1 != fEnd1) { 162 return **fIter1; 163 } 164 return **fIter2; 165 } 166 167 const_iterator& operator++() { 168 if (fIter1 != fEnd1) { 169 ++fIter1; 170 return *this; 171 } 172 ++fIter2; 173 return *this; 174 } 175 176 bool operator==(const const_iterator& other) const { 177 return fIter1 == other.fIter1 && fIter2 == other.fIter2; 178 } 179 180 bool operator!=(const const_iterator& other) const { 181 return !(*this == other); 182 } 183 184 private: 185 using inner = std::vector<std::unique_ptr<ProgramElement>>::const_iterator; 186 const_iteratorProgram187 const_iterator(inner begin1, inner end1, inner begin2, inner end2) 188 : fIter1(begin1) 189 , fEnd1(end1) 190 , fIter2(begin2) 191 , fEnd2(end2) {} 192 193 inner fIter1; 194 inner fEnd1; 195 inner fIter2; 196 inner fEnd2; 197 198 friend struct Program; 199 }; 200 201 enum Kind { 202 kFragment_Kind, 203 kVertex_Kind, 204 kGeometry_Kind, 205 kFragmentProcessor_Kind, 206 kPipelineStage_Kind 207 }; 208 ProgramProgram209 Program(Kind kind, 210 std::unique_ptr<String> source, 211 Settings settings, 212 std::shared_ptr<Context> context, 213 std::vector<std::unique_ptr<ProgramElement>>* inheritedElements, 214 std::vector<std::unique_ptr<ProgramElement>> elements, 215 std::shared_ptr<SymbolTable> symbols, 216 Inputs inputs) 217 : fKind(kind) 218 , fSource(std::move(source)) 219 , fSettings(settings) 220 , fContext(context) 221 , fSymbols(symbols) 222 , fInputs(inputs) 223 , fInheritedElements(inheritedElements) 224 , fElements(std::move(elements)) {} 225 beginProgram226 iterator begin() { 227 if (fInheritedElements) { 228 return iterator(fInheritedElements->begin(), fInheritedElements->end(), 229 fElements.begin(), fElements.end()); 230 } 231 return iterator(fElements.begin(), fElements.end(), fElements.end(), fElements.end()); 232 } 233 endProgram234 iterator end() { 235 if (fInheritedElements) { 236 return iterator(fInheritedElements->end(), fInheritedElements->end(), 237 fElements.end(), fElements.end()); 238 } 239 return iterator(fElements.end(), fElements.end(), fElements.end(), fElements.end()); 240 } 241 beginProgram242 const_iterator begin() const { 243 if (fInheritedElements) { 244 return const_iterator(fInheritedElements->begin(), fInheritedElements->end(), 245 fElements.begin(), fElements.end()); 246 } 247 return const_iterator(fElements.begin(), fElements.end(), fElements.end(), fElements.end()); 248 } 249 endProgram250 const_iterator end() const { 251 if (fInheritedElements) { 252 return const_iterator(fInheritedElements->end(), fInheritedElements->end(), 253 fElements.end(), fElements.end()); 254 } 255 return const_iterator(fElements.end(), fElements.end(), fElements.end(), fElements.end()); 256 } 257 258 Kind fKind; 259 std::unique_ptr<String> fSource; 260 Settings fSettings; 261 std::shared_ptr<Context> fContext; 262 // it's important to keep fElements defined after (and thus destroyed before) fSymbols, 263 // because destroying elements can modify reference counts in symbols 264 std::shared_ptr<SymbolTable> fSymbols; 265 Inputs fInputs; 266 bool fIsOptimized = false; 267 268 private: 269 std::vector<std::unique_ptr<ProgramElement>>* fInheritedElements; 270 std::vector<std::unique_ptr<ProgramElement>> fElements; 271 272 friend class Compiler; 273 }; 274 275 } // namespace 276 277 #endif 278