blob: 351e54e2e0d7e84d09d17b36d3f3ecb2a4bd959b [file] [log] [blame]
/*
* 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 <unordered_map>
#include <vector>
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>);
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<SkUniformBlock*, uint32_t, Hash, Eq> fUniformBlockIDs;
std::vector<std::unique_ptr<SkUniformBlock>> fUniformBlock;
#ifdef SK_DEBUG
void validate() const;
#else
void validate() const {}
#endif
};
} // namespace skgpu
#endif // skgpu_UniformCache_DEFINED