/* * Copyright 2021 Google LLC * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef skgpu_UniformCache_DEFINED #define skgpu_UniformCache_DEFINED #include "include/core/SkRefCnt.h" #include #include class SkUniformBlock; namespace skgpu { class UniformCache { public: static constexpr uint32_t kInvalidUniformID = 0; UniformCache(); // TODO: Revisit the UniformCache::insert and UniformData::Make APIs: // 1. UniformData::Make requires knowing the data size up front, which involves two invocations // of the UniformManager. Ideally, we could align uniforms on the fly into a dynamic buffer. // 2. UniformData stores the offsets for each uniform, but these aren't needed after we've // filled out the buffer. If we remember layout offsets, it should be stored per Combination // or RenderStep that defines the uniform set. // 3. UniformCache's ids are only fundamentally limited by the number of draws that can be // recorded into a DrawPass, which means a very large recording with multiple passes could // exceed uint32_t across all the passes. // 4. The check to know if a UniformData is present in the cache is practically the same for // checking if the data needs to be uploaded to the GPU, so UniformCache could remember the // associated BufferBindInfos as well. // 5. Because UniformCache only cares about the content byte hash/equality, and can memcpy to // the GPU buffer, the cached data contents could all go into a shared byte array, instead of // needing to extend SkRefCnt. // 6. insert() as a name can imply that the value is always added, so we may want a better one. // It can be a little less generic if UniformCache returns id and bind buffer info. On the // other hand unordered_map::insert has the same semantics as this insert, so maybe it's fine // Add the block of uniform data to the cache and return a unique ID that corresponds to its // contents. If an identical block of data is already in the cache, that unique ID is returned. uint32_t insert(std::unique_ptr); SkUniformBlock* lookup(uint32_t uniqueID); // The number of unique UniformBlock objects in the cache size_t count() const { SkASSERT(fUniformBlock.size() == fUniformBlockIDs.size() && fUniformBlock.size() > 0); return fUniformBlock.size() - 1; } private: struct Hash { // This hash operator de-references and hashes the data contents size_t operator()(SkUniformBlock*) const; }; struct Eq { // This equality operator de-references and compares the actual data contents bool operator()(SkUniformBlock*, SkUniformBlock*) const; }; // The UniformBlock's unique ID is only unique w/in a Recorder _not_ globally std::unordered_map fUniformBlockIDs; std::vector> fUniformBlock; #ifdef SK_DEBUG void validate() const; #else void validate() const {} #endif }; } // namespace skgpu #endif // skgpu_UniformCache_DEFINED