[graphite] Assign indices to pipeline descriptions
Also adds a helper class to upload uniform data the first time it's seen, and then remember the BufferBindInfo for use after sorting. Cq-Include-Trybots: luci.skia.skia.primary:Test-Mac11-Clang-MacMini9.1-GPU-AppleM1-arm64-Release-All-Graphite,Test-Mac11-Clang-MacMini9.1-GPU-AppleM1-arm64-Debug-All-ASAN_Graphite,Build-Mac-Clang-arm64-Release-iOS_Graphite,Build-Mac-Clang-arm64-Release-Graphite,Build-Mac-Clang-arm64-Debug-iOS_Graphite,Build-Mac-Clang-arm64-Debug-Graphite_NoGpu,Build-Mac-Clang-arm64-Debug-Graphite,Build-Mac-Clang-arm64-Debug-ASAN_Graphite Bug: skia:12466 Change-Id: I922166a24c5f8417020c0a3288cddf6043573c79 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/475637 Commit-Queue: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Robert Phillips <robertphillips@google.com> Reviewed-by: Jim Van Verth <jvanverth@google.com>
This commit is contained in:
parent
813d84f69a
commit
660cc2a38f
@ -24,6 +24,7 @@
|
||||
#include "experimental/graphite/src/geom/BoundsManager.h"
|
||||
|
||||
#include "src/core/SkMathPriv.h"
|
||||
#include "src/core/SkTBlockList.h"
|
||||
#include "src/core/SkUtils.h"
|
||||
#include "src/gpu/BufferWriter.h"
|
||||
|
||||
@ -151,11 +152,53 @@ public:
|
||||
|
||||
namespace {
|
||||
|
||||
skgpu::UniformData* lookup(skgpu::Recorder* recorder, uint32_t uniformID) {
|
||||
// TODO: just return a raw 'UniformData*' here
|
||||
sk_sp<skgpu::UniformData> tmp = recorder->uniformCache()->lookup(uniformID);
|
||||
return tmp.get();
|
||||
}
|
||||
class UniformBindingCache {
|
||||
public:
|
||||
UniformBindingCache(DrawBufferManager* bufferMgr, UniformCache* cache)
|
||||
: fBufferMgr(bufferMgr), fCache(cache) {}
|
||||
|
||||
uint32_t addUniforms(sk_sp<UniformData> data) {
|
||||
if (!data) {
|
||||
return UniformCache::kInvalidUniformID;
|
||||
}
|
||||
|
||||
uint32_t index = fCache->insert(data);
|
||||
if (fBindings.find(index) == fBindings.end()) {
|
||||
// First time encountering this data, so upload to the GPU
|
||||
auto [writer, bufferInfo] = fBufferMgr->getUniformWriter(data->dataSize());
|
||||
writer.write(data->data(), data->dataSize());
|
||||
fBindings.insert({index, bufferInfo});
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
BindBufferInfo getBinding(uint32_t uniformIndex) {
|
||||
auto lookup = fBindings.find(uniformIndex);
|
||||
SkASSERT(lookup != fBindings.end());
|
||||
return lookup->second;
|
||||
}
|
||||
|
||||
private:
|
||||
DrawBufferManager* fBufferMgr;
|
||||
UniformCache* fCache;
|
||||
|
||||
std::unordered_map<uint32_t, BindBufferInfo> fBindings;
|
||||
};
|
||||
|
||||
// std::unordered_map implementation for GraphicsPipelineDesc* that de-reference the pointers.
|
||||
struct Hash {
|
||||
size_t operator()(const skgpu::GraphicsPipelineDesc* desc) const noexcept {
|
||||
return skgpu::GraphicsPipelineDesc::Hash()(*desc);
|
||||
}
|
||||
};
|
||||
|
||||
struct Eq {
|
||||
bool operator()(const skgpu::GraphicsPipelineDesc* a,
|
||||
const skgpu::GraphicsPipelineDesc* b) const noexcept {
|
||||
return *a == *b;
|
||||
}
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
@ -199,7 +242,11 @@ std::unique_ptr<DrawPass> DrawPass::Make(Recorder* recorder,
|
||||
|
||||
DrawBufferManager* bufferMgr = recorder->drawBufferManager();
|
||||
UniformCache geometryUniforms;
|
||||
std::unordered_map<uint32_t, BindBufferInfo> geometryUniformBindings;
|
||||
UniformBindingCache geometryUniformBindings(bufferMgr, &geometryUniforms);
|
||||
UniformBindingCache shadingUniformBindings(bufferMgr, recorder->uniformCache());
|
||||
|
||||
SkTBlockList<GraphicsPipelineDesc> pipelineDescs; // pointers to items will not move
|
||||
std::unordered_map<const GraphicsPipelineDesc*, uint32_t, Hash, Eq> pipelineDescToIndex;
|
||||
|
||||
std::vector<SortKey> keys;
|
||||
keys.reserve(draws->renderStepCount()); // will not exceed but may use less with occluded draws
|
||||
@ -218,7 +265,7 @@ std::unique_ptr<DrawPass> DrawPass::Make(Recorder* recorder,
|
||||
uint32_t shadingIndex = UniformCache::kInvalidUniformID;
|
||||
if (draw.fPaintParams.has_value()) {
|
||||
std::tie(shader, shadingUniforms) = ExtractCombo(draw.fPaintParams.value());
|
||||
shadingIndex = recorder->uniformCache()->insert(shadingUniforms);
|
||||
shadingIndex = shadingUniformBindings.addUniforms(shadingUniforms);
|
||||
} // else depth-only
|
||||
|
||||
for (int stepIndex = 0; stepIndex < draw.fRenderer.numRenderSteps(); ++stepIndex) {
|
||||
@ -235,22 +282,23 @@ std::unique_ptr<DrawPass> DrawPass::Make(Recorder* recorder,
|
||||
uint32_t geometryIndex = UniformCache::kInvalidUniformID;
|
||||
if (step->numUniforms() > 0) {
|
||||
// TODO: Get layout from the GPU
|
||||
sk_sp<UniformData> uniforms = step->writeUniforms(Layout::kMetal, draw.fShape);
|
||||
geometryIndex = geometryUniforms.insert(uniforms);
|
||||
|
||||
// Upload the data to the GPU if it's the first time encountered
|
||||
if (geometryUniformBindings.find(geometryIndex) == geometryUniformBindings.end()) {
|
||||
auto [writer, bufferInfo] = bufferMgr->getUniformWriter(uniforms->dataSize());
|
||||
writer.write(uniforms->data(), uniforms->dataSize());
|
||||
geometryUniformBindings.insert({geometryIndex, bufferInfo});
|
||||
}
|
||||
geometryIndex = geometryUniformBindings.addUniforms(
|
||||
step->writeUniforms(Layout::kMetal, draw.fShape));
|
||||
}
|
||||
|
||||
GraphicsPipelineDesc desc;
|
||||
desc.setProgram(step, stepShader);
|
||||
uint32_t pipelineIndex = 0;
|
||||
|
||||
// TODO: Have a map from descriptions to uint32_ts for the SortKey
|
||||
auto pipelineLookup = pipelineDescToIndex.find(&desc);
|
||||
if (pipelineLookup == pipelineDescToIndex.end()) {
|
||||
// Assign new index to first appearance of this pipeline description
|
||||
pipelineIndex = SkTo<uint32_t>(pipelineDescs.count());
|
||||
const GraphicsPipelineDesc& finalDesc = pipelineDescs.push_back(desc);
|
||||
pipelineDescToIndex.insert({&finalDesc, pipelineIndex});
|
||||
} else {
|
||||
// Reuse the existing pipeline description for better batching after sorting
|
||||
pipelineIndex = pipelineLookup->second;
|
||||
}
|
||||
|
||||
keys.push_back({&draw, stepIndex, pipelineIndex, geometryIndex, stepShadingIndex});
|
||||
}
|
||||
@ -301,7 +349,7 @@ std::unique_ptr<DrawPass> DrawPass::Make(Recorder* recorder,
|
||||
|
||||
// Make state changes before accumulating new draw data
|
||||
if (pipelineChange) {
|
||||
// TODO: Look up pipeline description from key's index and record binding it
|
||||
// TODO: Record binding of the pipeline index == key.pipeline()
|
||||
lastPipeline = key.pipeline();
|
||||
lastShadingUniforms = UniformCache::kInvalidUniformID;
|
||||
lastGeometryUniforms = UniformCache::kInvalidUniformID;
|
||||
@ -309,22 +357,16 @@ std::unique_ptr<DrawPass> DrawPass::Make(Recorder* recorder,
|
||||
if (stateChange) {
|
||||
if (key.geometryUniforms() != lastGeometryUniforms) {
|
||||
if (key.geometryUniforms() != UniformCache::kInvalidUniformID) {
|
||||
auto binding = geometryUniformBindings.find(key.geometryUniforms())->second;
|
||||
auto binding = geometryUniformBindings.getBinding(key.geometryUniforms());
|
||||
// TODO: Record bind 'binding' buffer + offset to kRenderStep slot
|
||||
(void) binding;
|
||||
}
|
||||
lastGeometryUniforms = key.geometryUniforms();
|
||||
}
|
||||
if (key.shadingUniforms() != lastShadingUniforms) {
|
||||
// TODO: We should not re-upload the uniforms for every draw that referenced them,
|
||||
// they should be uploaded first time seen in the earlier loop of DrawPass::Make and
|
||||
// then this can lookup the cached BindBufferInfo, similar to geometryUniformBinding
|
||||
auto ud = lookup(recorder, key.shadingUniforms());
|
||||
|
||||
auto [writer, bufferInfo] = bufferMgr->getUniformWriter(ud->dataSize());
|
||||
writer.write(ud->data(), ud->dataSize());
|
||||
// TODO: recording 'bufferInfo' somewhere to allow a later uniform bind call
|
||||
|
||||
auto binding = shadingUniformBindings.getBinding(key.shadingUniforms());
|
||||
// TODO: Record bind 'binding' buffer + offset to kPaint slot
|
||||
(void) binding;
|
||||
lastShadingUniforms = key.shadingUniforms();
|
||||
}
|
||||
if (draw.fClip.scissor() != lastScissor) {
|
||||
|
@ -13,6 +13,8 @@
|
||||
#include "experimental/graphite/src/Attribute.h"
|
||||
#include "experimental/graphite/src/ContextUtils.h"
|
||||
#include "experimental/graphite/src/DrawTypes.h"
|
||||
#include "include/core/SkSpan.h"
|
||||
#include "include/private/SkOpts_spi.h"
|
||||
#include "include/private/SkTArray.h"
|
||||
|
||||
#include <array>
|
||||
@ -28,16 +30,7 @@ class GraphicsPipelineDesc {
|
||||
public:
|
||||
GraphicsPipelineDesc();
|
||||
|
||||
// Returns this as a uint32_t array to be used as a key in the pipeline cache.
|
||||
// TODO: Do we want to do anything here with a tuple or an SkSpan?
|
||||
const uint32_t* asKey() const {
|
||||
return fKey.data();
|
||||
}
|
||||
|
||||
// Gets the number of bytes in asKey(). It will be a 4-byte aligned value.
|
||||
uint32_t keyLength() const {
|
||||
return fKey.size() * sizeof(uint32_t);
|
||||
}
|
||||
SkSpan<const uint32_t> asKey() const { return SkMakeSpan(fKey.data(), fKey.size()); }
|
||||
|
||||
bool operator==(const GraphicsPipelineDesc& that) const {
|
||||
return this->fKey == that.fKey;
|
||||
@ -63,6 +56,12 @@ public:
|
||||
fKey[kWords - 1] = shaderCombo.key();
|
||||
}
|
||||
|
||||
struct Hash {
|
||||
uint32_t operator()(const GraphicsPipelineDesc& desc) const {
|
||||
return SkOpts::hash_fn(desc.fKey.data(), desc.fKey.size() * sizeof(uint32_t), 0);
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
// The key is the RenderStep address and the uint32_t key from Combination
|
||||
static constexpr int kWords = sizeof(uintptr_t) / sizeof(uint32_t) + 1;
|
||||
|
@ -57,13 +57,9 @@ private:
|
||||
private:
|
||||
struct Entry;
|
||||
|
||||
struct DescHash {
|
||||
uint32_t operator()(const GraphicsPipelineDesc& desc) const {
|
||||
return SkOpts::hash_fn(desc.asKey(), desc.keyLength(), 0);
|
||||
}
|
||||
};
|
||||
|
||||
SkLRUCache<const GraphicsPipelineDesc, std::unique_ptr<Entry>, DescHash> fMap;
|
||||
SkLRUCache<const GraphicsPipelineDesc,
|
||||
std::unique_ptr<Entry>,
|
||||
GraphicsPipelineDesc::Hash> fMap;
|
||||
|
||||
ResourceProvider* fResourceProvider;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user