[graphite] Finally, allocate uniform data in an arena

Bug: skia:12701
Change-Id: Ib02db7160599d3c15a01597c746ce5131f2998e0
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/526298
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
This commit is contained in:
Robert Phillips 2022-04-11 14:39:15 -04:00 committed by SkCQ
parent d271a2330e
commit cd692a6bb0
9 changed files with 50 additions and 46 deletions

View File

@ -15,6 +15,7 @@
class SkTextureDataBlock;
class SkUniformDataBlock;
class SkUniformDataBlockPassThrough; // TODO: remove
namespace skgpu::graphite {
@ -30,7 +31,7 @@ class Task;
class TaskGraph;
template<typename StorageT, typename BaseT> class PipelineDataCache;
using UniformDataCache = PipelineDataCache<std::unique_ptr<SkUniformDataBlock>, SkUniformDataBlock>;
using UniformDataCache = PipelineDataCache<SkUniformDataBlockPassThrough, SkUniformDataBlock>;
using TextureDataCache = PipelineDataCache<std::unique_ptr<SkTextureDataBlock>, SkTextureDataBlock>;
class Recorder final {

View File

@ -370,7 +370,7 @@ namespace {
#ifdef SK_GRAPHITE_ENABLED
void add_blendshader_uniform_data(SkShaderCodeDictionary* dict,
void add_blendshader_uniform_data(const SkShaderCodeDictionary* dict,
SkBlendMode bm,
SkPipelineDataGatherer* gatherer) {
VALIDATE_UNIFORMS(gatherer, dict, kBlendShader)

View File

@ -26,12 +26,16 @@ void SkPipelineDataGatherer::checkReset() {
}
#endif // SK_DEBUG
std::unique_ptr<SkUniformDataBlock> SkUniformDataBlock::Make(const SkUniformDataBlock& other,
SkArenaAlloc* /* arena */) {
char* newMem = new char[other.size()];
memcpy(newMem, other.data(), other.size());
////////////////////////////////////////////////////////////////////////////////////////////////////
SkUniformDataBlock* SkUniformDataBlock::Make(const SkUniformDataBlock& other,
SkArenaAlloc* arena) {
static constexpr size_t kUniformAlignment = alignof(void*);
char* mem = static_cast<char*>(arena->makeBytesAlignedTo(other.size(), kUniformAlignment));
memcpy(mem, other.data(), other.size());
return std::make_unique<SkUniformDataBlock>(SkSpan<const char>(newMem, other.size()), true);
return arena->make([&](void* ptr) {
return new (ptr) SkUniformDataBlock(SkSpan<const char>(mem, other.size()));
});
}
uint32_t SkUniformDataBlock::hash() const {

View File

@ -28,15 +28,10 @@ class SkUniform;
class SkUniformDataBlock {
public:
static std::unique_ptr<SkUniformDataBlock> Make(const SkUniformDataBlock&, SkArenaAlloc*);
static SkUniformDataBlock* Make(const SkUniformDataBlock&, SkArenaAlloc*);
SkUniformDataBlock(SkSpan<const char> data, bool ownMem) : fData(data), fOwnMem(ownMem) {}
SkUniformDataBlock(SkSpan<const char> data) : fData(data) {}
SkUniformDataBlock() = default;
~SkUniformDataBlock() {
if (fOwnMem) {
delete [] fData.data();
}
}
const char* data() const { return fData.data(); }
size_t size() const { return fData.size(); }
@ -51,10 +46,21 @@ public:
private:
SkSpan<const char> fData;
};
// This is only required until the uniform data is stored in the arena. Once there this
// class will never delete the data referenced w/in the span
bool fOwnMem = false;
// We would like to store just a "const SkUniformDataBlock*" in the UniformDataCache but, until
// the TextureDataCache is switched over to storing its data in an arena, whatever is held in
// the cache must interoperate w/ std::unique_ptr (i.e., have a get() function).
// TODO: remove this class
class SkUniformDataBlockPassThrough {
public:
SkUniformDataBlockPassThrough() = default;
SkUniformDataBlockPassThrough(SkUniformDataBlock* udb) : fUDB(udb) {}
SkUniformDataBlock* get() const { return fUDB; }
private:
SkUniformDataBlock* fUDB = nullptr;
};
#ifdef SK_GRAPHITE_ENABLED
@ -155,9 +161,9 @@ public:
void write(const SkRect& rect) { fUniformManager.write(rect); }
void write(SkPoint point) { fUniformManager.write(point); }
void write(const float* floats, int count) { fUniformManager.write(floats, count); }
void write(float something) { fUniformManager.write(&something, 1); }
void write(int something) { fUniformManager.write(something); }
void write(skgpu::graphite::float2 something) { fUniformManager.write(something); }
void write(float f) { fUniformManager.write(&f, 1); }
void write(int i) { fUniformManager.write(i); }
void write(skgpu::graphite::float2 v) { fUniformManager.write(v); }
bool hasUniforms() const { return fUniformManager.size(); }

View File

@ -200,7 +200,7 @@ public:
return {};
}
const SkUniformDataBlock *udb = fUniformDataCache->lookup(uIndex);
const SkUniformDataBlock* udb = fUniformDataCache->lookup(uIndex);
SkASSERT(udb);
if (fBindings.find(uIndex.asUInt()) == fBindings.end()) {

View File

@ -140,7 +140,7 @@ private:
// A UniformDataCache lives for the entire duration of a Recorder. As such it has a greater
// likelihood of overflowing a uint32_t index.
using UniformDataCache = PipelineDataCache<std::unique_ptr<SkUniformDataBlock>, SkUniformDataBlock>;
using UniformDataCache = PipelineDataCache<SkUniformDataBlockPassThrough, SkUniformDataBlock>;
// A TextureDataCache only lives for a single Recording. When a Recording is snapped it is pulled
// off of the Recorder and goes with the Recording as a record of the required Textures and

View File

@ -509,7 +509,7 @@ UniformManager::UniformManager(Layout layout) : fLayout(layout) {
}
SkUniformDataBlock UniformManager::peekData() const {
return SkUniformDataBlock(SkMakeSpan(fStorage.begin(), fStorage.count()), false);
return SkUniformDataBlock(SkMakeSpan(fStorage.begin(), fStorage.count()));
}
void UniformManager::reset() {
@ -598,16 +598,16 @@ void UniformManager::write(const float* floats, int count) {
this->write(kType, count, floats);
}
void UniformManager::write(int something) {
void UniformManager::write(int i) {
static const SkSLType kType = SkSLType::kInt;
SkDEBUGCODE(this->checkExpected(kType, 1);)
this->write(kType, 1, &something);
this->write(kType, 1, &i);
}
void UniformManager::write(float2 something) {
void UniformManager::write(float2 v) {
static const SkSLType kType = SkSLType::kFloat2;
SkDEBUGCODE(this->checkExpected(kType, 1);)
this->write(kType, 1, &something);
this->write(kType, 1, &v);
}
} // namespace skgpu::graphite

View File

@ -30,6 +30,7 @@ enum class Layout {
kMetal, /** This is our own self-imposed layout we use for Metal. */
};
// TODO: This is only used in the SkPipelineDataGatherer - maybe hide it better.
class UniformManager {
public:
UniformManager(Layout layout);

View File

@ -16,14 +16,6 @@
using namespace skgpu::graphite;
namespace {
std::unique_ptr<SkUniformDataBlock> make_udb(const char* data, size_t size) {
return std::make_unique<SkUniformDataBlock>(SkMakeSpan(data, size), false);
}
} // anonymous namespace
DEF_GRAPHITE_TEST_FOR_CONTEXTS(PipelineDataCacheTest, reporter, context) {
std::unique_ptr<Recorder> recorder = context->makeRecorder();
@ -46,13 +38,13 @@ DEF_GRAPHITE_TEST_FOR_CONTEXTS(PipelineDataCacheTest, reporter, context) {
static const char kMemory1[kSize] = {
7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22
};
std::unique_ptr<SkUniformDataBlock> udb1 = make_udb(kMemory1, kSize);
SkUniformDataBlock udb1(SkMakeSpan(kMemory1, kSize));
UniformDataCache::Index id1;
{
id1 = cache->insert(*udb1);
id1 = cache->insert(udb1);
REPORTER_ASSERT(reporter, id1.isValid());
const SkUniformDataBlock* lookup = cache->lookup(id1);
REPORTER_ASSERT(reporter, *lookup == *udb1);
REPORTER_ASSERT(reporter, *lookup == udb1);
REPORTER_ASSERT(reporter, cache->count() == 1);
}
@ -62,13 +54,13 @@ DEF_GRAPHITE_TEST_FOR_CONTEXTS(PipelineDataCacheTest, reporter, context) {
static const char kMemory2[kSize] = {
7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22
};
std::unique_ptr<SkUniformDataBlock> udb2 = make_udb(kMemory2, kSize);
UniformDataCache::Index id2 = cache->insert(*udb2);
SkUniformDataBlock udb2(SkMakeSpan(kMemory2, kSize));
UniformDataCache::Index id2 = cache->insert(udb2);
REPORTER_ASSERT(reporter, id2.isValid());
REPORTER_ASSERT(reporter, id2 == id1);
const SkUniformDataBlock* lookup = cache->lookup(id2);
REPORTER_ASSERT(reporter, *lookup == *udb1);
REPORTER_ASSERT(reporter, *lookup == *udb2);
REPORTER_ASSERT(reporter, *lookup == udb1);
REPORTER_ASSERT(reporter, *lookup == udb2);
REPORTER_ASSERT(reporter, cache->count() == 1);
}
@ -78,13 +70,13 @@ DEF_GRAPHITE_TEST_FOR_CONTEXTS(PipelineDataCacheTest, reporter, context) {
static const char kMemory3[kSize] = {
6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21
};
std::unique_ptr<SkUniformDataBlock> udb3 = make_udb(kMemory3, kSize);
UniformDataCache::Index id3 = cache->insert(*udb3);
SkUniformDataBlock udb3(SkMakeSpan(kMemory3, kSize));
UniformDataCache::Index id3 = cache->insert(udb3);
REPORTER_ASSERT(reporter, id3.isValid());
REPORTER_ASSERT(reporter, id3 != id1);
const SkUniformDataBlock* lookup = cache->lookup(id3);
REPORTER_ASSERT(reporter, *lookup == *udb3);
REPORTER_ASSERT(reporter, *lookup != *udb1);
REPORTER_ASSERT(reporter, *lookup == udb3);
REPORTER_ASSERT(reporter, *lookup != udb1);
REPORTER_ASSERT(reporter, cache->count() == 2);
}