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/SkSLDefines.h" 15 #include "include/private/SkSLModifiers.h" 16 #include "include/private/SkSLProgramElement.h" 17 #include "include/private/SkTHash.h" 18 #include "src/sksl/SkSLAnalysis.h" 19 #include "src/sksl/SkSLProgramSettings.h" 20 #include "src/sksl/ir/SkSLBoolLiteral.h" 21 #include "src/sksl/ir/SkSLExpression.h" 22 #include "src/sksl/ir/SkSLFloatLiteral.h" 23 #include "src/sksl/ir/SkSLIntLiteral.h" 24 #include "src/sksl/ir/SkSLSymbolTable.h" 25 26 #ifdef SK_VULKAN 27 #include "src/gpu/vk/GrVkCaps.h" 28 #endif 29 30 // name of the render target height uniform 31 #define SKSL_RTHEIGHT_NAME "u_skRTHeight" 32 33 namespace SkSL { 34 35 class Context; 36 class Pool; 37 38 /** 39 * Side-car class holding mutable information about a Program's IR 40 */ 41 class ProgramUsage { 42 public: 43 struct VariableCounts { 44 int fDeclared = 0; 45 int fRead = 0; 46 int fWrite = 0; 47 }; 48 VariableCounts get(const Variable&) const; 49 bool isDead(const Variable&) const; 50 51 int get(const FunctionDeclaration&) const; 52 53 void replace(const Expression* oldExpr, const Expression* newExpr); 54 void add(const Statement* stmt); 55 void remove(const Expression* expr); 56 void remove(const Statement* stmt); 57 void remove(const ProgramElement& element); 58 59 SkTHashMap<const Variable*, VariableCounts> fVariableCounts; 60 SkTHashMap<const FunctionDeclaration*, int> fCallCounts; 61 }; 62 63 /** 64 * Represents a fully-digested program, ready for code generation. 65 */ 66 struct Program { 67 using Settings = ProgramSettings; 68 69 struct Inputs { 70 // if true, this program requires the render target height uniform to be defined 71 bool fRTHeight; 72 73 // if true, this program must be recompiled if the flipY setting changes. If false, the 74 // program will compile to the same code regardless of the flipY setting. 75 bool fFlipY; 76 resetProgram::Inputs77 void reset() { 78 fRTHeight = false; 79 fFlipY = false; 80 } 81 isEmptyProgram::Inputs82 bool isEmpty() { 83 return !fRTHeight && !fFlipY; 84 } 85 }; 86 ProgramProgram87 Program(std::unique_ptr<String> source, 88 std::unique_ptr<ProgramConfig> config, 89 std::shared_ptr<Context> context, 90 std::vector<std::unique_ptr<ProgramElement>> elements, 91 std::vector<const ProgramElement*> sharedElements, 92 std::unique_ptr<ModifiersPool> modifiers, 93 std::shared_ptr<SymbolTable> symbols, 94 std::unique_ptr<Pool> pool, 95 Inputs inputs) 96 : fSource(std::move(source)) 97 , fConfig(std::move(config)) 98 , fContext(context) 99 , fSymbols(symbols) 100 , fPool(std::move(pool)) 101 , fInputs(inputs) 102 , fElements(std::move(elements)) 103 , fSharedElements(std::move(sharedElements)) 104 , fModifiers(std::move(modifiers)) { 105 fUsage = Analysis::GetUsage(*this); 106 } 107 ~ProgramProgram108 ~Program() { 109 // Some or all of the program elements are in the pool. To free them safely, we must attach 110 // the pool before destroying any program elements. (Otherwise, we may accidentally call 111 // delete on a pooled node.) 112 if (fPool) { 113 fPool->attachToThread(); 114 } 115 fElements.clear(); 116 fContext.reset(); 117 fSymbols.reset(); 118 fModifiers.reset(); 119 if (fPool) { 120 fPool->detachFromThread(); 121 } 122 } 123 124 class ElementsCollection { 125 public: 126 class iterator { 127 public: 128 const ProgramElement* operator*() { 129 if (fShared != fSharedEnd) { 130 return *fShared; 131 } else { 132 return fOwned->get(); 133 } 134 } 135 136 iterator& operator++() { 137 if (fShared != fSharedEnd) { 138 ++fShared; 139 } else { 140 ++fOwned; 141 } 142 return *this; 143 } 144 145 bool operator==(const iterator& other) const { 146 return fOwned == other.fOwned && fShared == other.fShared; 147 } 148 149 bool operator!=(const iterator& other) const { 150 return !(*this == other); 151 } 152 153 private: 154 using Owned = std::vector<std::unique_ptr<ProgramElement>>::const_iterator; 155 using Shared = std::vector<const ProgramElement*>::const_iterator; 156 friend class ElementsCollection; 157 iteratorProgram158 iterator(Owned owned, Owned ownedEnd, Shared shared, Shared sharedEnd) 159 : fOwned(owned), fOwnedEnd(ownedEnd), fShared(shared), fSharedEnd(sharedEnd) {} 160 161 Owned fOwned; 162 Owned fOwnedEnd; 163 Shared fShared; 164 Shared fSharedEnd; 165 }; 166 beginProgram167 iterator begin() const { 168 return iterator(fProgram.fElements.begin(), fProgram.fElements.end(), 169 fProgram.fSharedElements.begin(), fProgram.fSharedElements.end()); 170 } 171 endProgram172 iterator end() const { 173 return iterator(fProgram.fElements.end(), fProgram.fElements.end(), 174 fProgram.fSharedElements.end(), fProgram.fSharedElements.end()); 175 } 176 177 private: 178 friend struct Program; 179 ElementsCollectionProgram180 ElementsCollection(const Program& program) : fProgram(program) {} 181 const Program& fProgram; 182 }; 183 184 // Can be used to iterate over *all* elements in this Program, both owned and shared (builtin). 185 // The iterator's value type is 'const ProgramElement*', so it's clear that you *must not* 186 // modify anything (as you might be mutating shared data). elementsProgram187 ElementsCollection elements() const { return ElementsCollection(*this); } 188 189 // Can be used to iterate over *just* the elements owned by the Program, not shared builtins. 190 // The iterator's value type is 'std::unique_ptr<ProgramElement>', and mutation is allowed. ownedElementsProgram191 std::vector<std::unique_ptr<ProgramElement>>& ownedElements() { return fElements; } ownedElementsProgram192 const std::vector<std::unique_ptr<ProgramElement>>& ownedElements() const { return fElements; } 193 descriptionProgram194 String description() const { 195 String result; 196 for (const auto& e : this->elements()) { 197 result += e->description(); 198 } 199 return result; 200 } 201 usageProgram202 const ProgramUsage* usage() const { return fUsage.get(); } 203 204 std::unique_ptr<String> fSource; 205 std::unique_ptr<ProgramConfig> fConfig; 206 std::shared_ptr<Context> fContext; 207 // it's important to keep fElements defined after (and thus destroyed before) fSymbols, 208 // because destroying elements can modify reference counts in symbols 209 std::shared_ptr<SymbolTable> fSymbols; 210 std::unique_ptr<Pool> fPool; 211 Inputs fInputs; 212 213 private: 214 std::vector<std::unique_ptr<ProgramElement>> fElements; 215 std::vector<const ProgramElement*> fSharedElements; 216 std::unique_ptr<ModifiersPool> fModifiers; 217 std::unique_ptr<ProgramUsage> fUsage; 218 219 friend class Compiler; 220 friend class Inliner; // fUsage 221 friend class SPIRVCodeGenerator; // fModifiers 222 }; 223 224 } // namespace SkSL 225 226 #endif 227