• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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