1 /* 2 * Copyright 2021 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 skgpu_UniformCache_DEFINED 9 #define skgpu_UniformCache_DEFINED 10 11 #include "include/core/SkRefCnt.h" 12 13 #include <unordered_map> 14 #include <vector> 15 16 class SkUniformBlock; 17 18 namespace skgpu { 19 20 21 class UniformCache { 22 public: 23 static constexpr uint32_t kInvalidUniformID = 0; 24 25 UniformCache(); 26 27 // TODO: Revisit the UniformCache::insert and UniformData::Make APIs: 28 // 1. UniformData::Make requires knowing the data size up front, which involves two invocations 29 // of the UniformManager. Ideally, we could align uniforms on the fly into a dynamic buffer. 30 // 2. UniformData stores the offsets for each uniform, but these aren't needed after we've 31 // filled out the buffer. If we remember layout offsets, it should be stored per Combination 32 // or RenderStep that defines the uniform set. 33 // 3. UniformCache's ids are only fundamentally limited by the number of draws that can be 34 // recorded into a DrawPass, which means a very large recording with multiple passes could 35 // exceed uint32_t across all the passes. 36 // 4. The check to know if a UniformData is present in the cache is practically the same for 37 // checking if the data needs to be uploaded to the GPU, so UniformCache could remember the 38 // associated BufferBindInfos as well. 39 // 5. Because UniformCache only cares about the content byte hash/equality, and can memcpy to 40 // the GPU buffer, the cached data contents could all go into a shared byte array, instead of 41 // needing to extend SkRefCnt. 42 // 6. insert() as a name can imply that the value is always added, so we may want a better one. 43 // It can be a little less generic if UniformCache returns id and bind buffer info. On the 44 // other hand unordered_map::insert has the same semantics as this insert, so maybe it's fine 45 46 // Add the block of uniform data to the cache and return a unique ID that corresponds to its 47 // contents. If an identical block of data is already in the cache, that unique ID is returned. 48 uint32_t insert(std::unique_ptr<SkUniformBlock>); 49 50 SkUniformBlock* lookup(uint32_t uniqueID); 51 52 // The number of unique UniformBlock objects in the cache count()53 size_t count() const { 54 SkASSERT(fUniformBlock.size() == fUniformBlockIDs.size() && fUniformBlock.size() > 0); 55 return fUniformBlock.size() - 1; 56 } 57 58 private: 59 struct Hash { 60 // This hash operator de-references and hashes the data contents 61 size_t operator()(SkUniformBlock*) const; 62 }; 63 struct Eq { 64 // This equality operator de-references and compares the actual data contents 65 bool operator()(SkUniformBlock*, SkUniformBlock*) const; 66 }; 67 68 // The UniformBlock's unique ID is only unique w/in a Recorder _not_ globally 69 std::unordered_map<SkUniformBlock*, uint32_t, Hash, Eq> fUniformBlockIDs; 70 std::vector<std::unique_ptr<SkUniformBlock>> fUniformBlock; 71 72 #ifdef SK_DEBUG 73 void validate() const; 74 #else validate()75 void validate() const {} 76 #endif 77 }; 78 79 } // namespace skgpu 80 81 #endif // skgpu_UniformCache_DEFINED 82