1 /* 2 * Copyright 2022 Google LLC 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 SkShaderCodeDictionary_DEFINED 9 #define SkShaderCodeDictionary_DEFINED 10 11 #include <array> 12 #include <unordered_map> 13 #include <vector> 14 #include "include/core/SkSpan.h" 15 #include "include/private/SkSpinlock.h" 16 #include "include/private/SkUniquePaintParamsID.h" 17 #include "src/core/SkArenaAlloc.h" 18 #include "src/core/SkPaintParamsKey.h" 19 #include "src/core/SkUniform.h" 20 21 class SkShaderInfo { 22 public: 23 struct SnippetEntry; 24 using GenerateGlueCodeForEntry = std::string (*)(const std::string& resultName, 25 int entryIndex, // for uniform name mangling 26 const SnippetEntry&, 27 const std::vector<std::string>& childNames, 28 int indent); 29 30 struct SnippetEntry { 31 SkSpan<const SkUniform> fUniforms; 32 const char* fStaticFunctionName; 33 const char* fStaticSkSL; 34 GenerateGlueCodeForEntry fGlueCodeGenerator; 35 int fNumChildren; 36 }; 37 add(const SnippetEntry & entry)38 void add(const SnippetEntry& entry) { 39 fEntries.push_back(entry); 40 } 41 42 // TODO: writing to color should be a property of the SnippetEntries and accumulated as the 43 // entries are added. _Not_ set manually via 'setWritesColor'. setWritesColor()44 void setWritesColor() { fWritesColor = true; } writesColor()45 bool writesColor() const { return fWritesColor; } 46 47 #if SK_SUPPORT_GPU && defined(SK_GRAPHITE_ENABLED) && defined(SK_METAL) 48 std::string toSkSL() const; 49 #endif 50 51 private: 52 std::string emitGlueCodeForEntry(int* entryIndex, std::string* result, int indent) const; 53 54 std::vector<SnippetEntry> fEntries; 55 bool fWritesColor = false; 56 }; 57 58 class SkShaderCodeDictionary { 59 public: 60 SkShaderCodeDictionary(); 61 62 struct Entry { 63 public: uniqueIDEntry64 SkUniquePaintParamsID uniqueID() const { 65 SkASSERT(fUniqueID.isValid()); 66 return fUniqueID; 67 } paintParamsKeyEntry68 const SkPaintParamsKey* paintParamsKey() const { return fKey.get(); } 69 70 private: 71 friend class SkShaderCodeDictionary; 72 EntryEntry73 Entry(std::unique_ptr<SkPaintParamsKey> key) : fKey(std::move(key)) {} 74 setUniqueIDEntry75 void setUniqueID(uint32_t newID) { 76 SkASSERT(!fUniqueID.isValid()); 77 fUniqueID = SkUniquePaintParamsID(newID); 78 } 79 80 SkUniquePaintParamsID fUniqueID; // fixed-size (uint32_t) unique ID assigned to a key 81 std::unique_ptr<SkPaintParamsKey> fKey; // variable-length paint key descriptor 82 }; 83 84 const Entry* findOrCreate(std::unique_ptr<SkPaintParamsKey>) SK_EXCLUDES(fSpinLock); 85 86 const Entry* lookup(SkUniquePaintParamsID) const SK_EXCLUDES(fSpinLock); 87 88 SkSpan<const SkUniform> getUniforms(SkBuiltInCodeSnippetID) const; 89 const SkShaderInfo::SnippetEntry* getEntry(SkBuiltInCodeSnippetID) const; 90 91 void getShaderInfo(SkUniquePaintParamsID, SkShaderInfo*); 92 maxCodeSnippetID()93 int maxCodeSnippetID() const { 94 return static_cast<int>(SkBuiltInCodeSnippetID::kLast) + fUserDefinedCodeSnippets.size(); 95 } 96 97 // TODO: this is still experimental but, most likely, it will need to be made thread-safe 98 // It returns the code snippet ID to use to identify the supplied user-defined code 99 // TODO: add hooks for user to actually provide code. 100 int addUserDefinedSnippet(); 101 102 private: 103 Entry* makeEntry(std::unique_ptr<SkPaintParamsKey>); 104 105 struct Hash { 106 size_t operator()(const SkPaintParamsKey*) const; 107 }; 108 109 std::array<SkShaderInfo::SnippetEntry, kBuiltInCodeSnippetIDCount> fBuiltInCodeSnippets; 110 std::vector<SkShaderInfo::SnippetEntry> fUserDefinedCodeSnippets; 111 112 // TODO: can we do something better given this should have write-seldom/read-often behavior? 113 mutable SkSpinlock fSpinLock; 114 115 std::unordered_map<const SkPaintParamsKey*, Entry*, Hash> fHash SK_GUARDED_BY(fSpinLock); 116 std::vector<Entry*> fEntryVector SK_GUARDED_BY(fSpinLock); 117 118 SkArenaAlloc fArena{256}; 119 }; 120 121 #endif // SkShaderCodeDictionary_DEFINED 122