[graphite] Add TextureDataCache

This adds caching and uniquifying of SkTextureDataBlocks to parallel
our treatment of SkUniformDataBlocks.

Bug: skia:12701
Change-Id: Ib4474f48b9048daf4b848ccbb339cb42246f184b
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/523418
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
This commit is contained in:
Robert Phillips 2022-03-23 14:14:26 -04:00 committed by SkCQ
parent 7ef299accb
commit a7c2d73690
10 changed files with 82 additions and 59 deletions

View File

@ -13,6 +13,7 @@
#include <vector> #include <vector>
class SkTextureDataBlock;
class SkUniformDataBlock; class SkUniformDataBlock;
namespace skgpu { namespace skgpu {
@ -30,6 +31,7 @@ class TaskGraph;
template<typename DataBlockT> class PipelineDataCache; template<typename DataBlockT> class PipelineDataCache;
using UniformDataCache = PipelineDataCache<SkUniformDataBlock>; using UniformDataCache = PipelineDataCache<SkUniformDataBlock>;
using TextureDataCache = PipelineDataCache<SkTextureDataBlock>;
class Recorder final { class Recorder final {
public: public:
@ -84,6 +86,7 @@ private:
std::unique_ptr<TaskGraph> fGraph; std::unique_ptr<TaskGraph> fGraph;
std::unique_ptr<UniformDataCache> fUniformDataCache; std::unique_ptr<UniformDataCache> fUniformDataCache;
std::unique_ptr<TextureDataCache> fTextureDataCache;
std::unique_ptr<DrawBufferManager> fDrawBufferManager; std::unique_ptr<DrawBufferManager> fDrawBufferManager;
std::vector<Device*> fTrackedDevices; std::vector<Device*> fTrackedDevices;

View File

@ -10,9 +10,13 @@
#include "include/core/SkRefCnt.h" #include "include/core/SkRefCnt.h"
class SkTextureDataBlock;
namespace skgpu { namespace skgpu {
class CommandBuffer; class CommandBuffer;
template<typename DataBlockT> class PipelineDataCache;
using TextureDataCache = PipelineDataCache<SkTextureDataBlock>;
class Recording final { class Recording final {
public: public:
@ -22,9 +26,12 @@ protected:
private: private:
friend class Context; // for access fCommandBuffer friend class Context; // for access fCommandBuffer
friend class Recorder; // for ctor friend class Recorder; // for ctor
Recording(sk_sp<CommandBuffer>); Recording(sk_sp<CommandBuffer>, std::unique_ptr<TextureDataCache>);
sk_sp<CommandBuffer> fCommandBuffer; sk_sp<CommandBuffer> fCommandBuffer;
// The TextureDataCache holds all the Textures and Samplers used in this Recording.
std::unique_ptr<TextureDataCache> fTextureDataCache;
}; };
} // namespace skgpu } // namespace skgpu

View File

@ -31,8 +31,6 @@
#include "src/core/SkPaintParamsKey.h" #include "src/core/SkPaintParamsKey.h"
#include "src/core/SkPipelineData.h" #include "src/core/SkPipelineData.h"
#include "src/core/SkTBlockList.h" #include "src/core/SkTBlockList.h"
#include "src/core/SkUniformData.h"
#include "src/gpu/BufferWriter.h"
#include <algorithm> #include <algorithm>
#include <unordered_map> #include <unordered_map>
@ -300,6 +298,7 @@ std::unique_ptr<DrawPass> DrawPass::Make(Recorder* recorder,
UniformDataCache geometryUniformDataCache; UniformDataCache geometryUniformDataCache;
UniformBindingCache geometryUniformBindings(bufferMgr, &geometryUniformDataCache); UniformBindingCache geometryUniformBindings(bufferMgr, &geometryUniformDataCache);
UniformBindingCache shadingUniformBindings(bufferMgr, recorder->priv().uniformDataCache()); UniformBindingCache shadingUniformBindings(bufferMgr, recorder->priv().uniformDataCache());
TextureDataCache* textureDataCache = recorder->priv().textureDataCache();
std::unordered_map<const GraphicsPipelineDesc*, uint32_t, Hash, Eq> pipelineDescToIndex; std::unordered_map<const GraphicsPipelineDesc*, uint32_t, Hash, Eq> pipelineDescToIndex;
@ -320,13 +319,14 @@ std::unique_ptr<DrawPass> DrawPass::Make(Recorder* recorder,
// and remember the location for re-use on any RenderStep that does shading. // and remember the location for re-use on any RenderStep that does shading.
SkUniquePaintParamsID shaderID; SkUniquePaintParamsID shaderID;
UniformDataCache::Index shadingUniformIndex; UniformDataCache::Index shadingUniformIndex;
TextureDataCache::Index textureBindingIndex; // TODO: fill in the textureBinding field TextureDataCache::Index textureBindingIndex;
if (draw.fPaintParams.has_value()) { if (draw.fPaintParams.has_value()) {
std::unique_ptr<SkPipelineData> pipelineData; std::unique_ptr<SkPipelineData> pipelineData;
std::tie(shaderID, pipelineData) = ExtractPaintData(recorder, &builder, std::tie(shaderID, pipelineData) = ExtractPaintData(recorder, &builder,
draw.fPaintParams.value()); draw.fPaintParams.value());
shadingUniformIndex = shadingUniformBindings.addUniforms( shadingUniformIndex = shadingUniformBindings.addUniforms(
pipelineData->uniformDataBlock()); pipelineData->uniformDataBlock());
textureBindingIndex = textureDataCache->insert(pipelineData->textureDataBlock());
} // else depth-only } // else depth-only
for (int stepIndex = 0; stepIndex < draw.fRenderer.numRenderSteps(); ++stepIndex) { for (int stepIndex = 0; stepIndex < draw.fRenderer.numRenderSteps(); ++stepIndex) {
@ -396,6 +396,7 @@ std::unique_ptr<DrawPass> DrawPass::Make(Recorder* recorder,
// Setting to # render steps ensures the very first time through the loop will bind a pipeline. // Setting to # render steps ensures the very first time through the loop will bind a pipeline.
uint32_t lastPipeline = draws->renderStepCount(); uint32_t lastPipeline = draws->renderStepCount();
UniformDataCache::Index lastShadingUniforms; UniformDataCache::Index lastShadingUniforms;
TextureDataCache::Index lastTextureBindings;
UniformDataCache::Index lastGeometryUniforms; UniformDataCache::Index lastGeometryUniforms;
SkIRect lastScissor = SkIRect::MakeSize(drawPass->fTarget->dimensions()); SkIRect lastScissor = SkIRect::MakeSize(drawPass->fTarget->dimensions());
@ -407,6 +408,8 @@ std::unique_ptr<DrawPass> DrawPass::Make(Recorder* recorder,
key.geometryUniforms() != lastGeometryUniforms; key.geometryUniforms() != lastGeometryUniforms;
const bool shadingUniformChange = key.shadingUniforms().isValid() && const bool shadingUniformChange = key.shadingUniforms().isValid() &&
key.shadingUniforms() != lastShadingUniforms; key.shadingUniforms() != lastShadingUniforms;
const bool textureBindingsChange = key.textureBindings().isValid() &&
key.textureBindings() != lastTextureBindings;
const bool pipelineChange = key.pipeline() != lastPipeline; const bool pipelineChange = key.pipeline() != lastPipeline;
const bool stateChange = geometryUniformChange || const bool stateChange = geometryUniformChange ||
@ -441,6 +444,10 @@ std::unique_ptr<DrawPass> DrawPass::Make(Recorder* recorder,
BindUniformBuffer{binding, UniformSlot::kPaint}); BindUniformBuffer{binding, UniformSlot::kPaint});
lastShadingUniforms = key.shadingUniforms(); lastShadingUniforms = key.shadingUniforms();
} }
if (textureBindingsChange) {
// TODO: add BindTexturesAndSamplers command here
lastTextureBindings = key.textureBindings();
}
if (draw.fClip.scissor() != lastScissor) { if (draw.fClip.scissor() != lastScissor) {
drawPass->fCommands.emplace_back(SetScissor{draw.fClip.scissor()}); drawPass->fCommands.emplace_back(SetScissor{draw.fClip.scissor()});
lastScissor = draw.fClip.scissor(); lastScissor = draw.fClip.scissor();

View File

@ -139,7 +139,7 @@ using UniformDataCache = PipelineDataCache<SkUniformDataBlock>;
// A TextureDataCache only lives for a single Recording. When a Recording is snapped it is pulled // 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 // off of the Recorder and goes with the Recording as a record of the required Textures and
// Samplers. // Samplers.
using TextureDataCache = PipelineDataCache<SkPipelineData::TextureDataBlock>; using TextureDataCache = PipelineDataCache<SkTextureDataBlock>;
} // namespace skgpu } // namespace skgpu

View File

@ -27,7 +27,8 @@ namespace skgpu {
Recorder::Recorder(sk_sp<Gpu> gpu, sk_sp<GlobalCache> globalCache) Recorder::Recorder(sk_sp<Gpu> gpu, sk_sp<GlobalCache> globalCache)
: fGpu(std::move(gpu)) : fGpu(std::move(gpu))
, fGraph(new TaskGraph) , fGraph(new TaskGraph)
, fUniformDataCache(new UniformDataCache) { , fUniformDataCache(new UniformDataCache)
, fTextureDataCache(new TextureDataCache) {
fResourceProvider = fGpu->makeResourceProvider(std::move(globalCache), this->singleOwner()); fResourceProvider = fGpu->makeResourceProvider(std::move(globalCache), this->singleOwner());
fDrawBufferManager.reset(new DrawBufferManager(fResourceProvider.get(), fDrawBufferManager.reset(new DrawBufferManager(fResourceProvider.get(),
@ -48,13 +49,19 @@ std::unique_ptr<Recording> Recorder::snap() {
device->flushPendingWorkToRecorder(); device->flushPendingWorkToRecorder();
} }
// TODO: fulfill all promise images in the TextureDataCache here
// TODO: create all the samplers needed in the TextureDataCache here
auto commandBuffer = fResourceProvider->createCommandBuffer(); auto commandBuffer = fResourceProvider->createCommandBuffer();
fGraph->addCommands(fResourceProvider.get(), commandBuffer.get()); fGraph->addCommands(fResourceProvider.get(), commandBuffer.get());
fDrawBufferManager->transferToCommandBuffer(commandBuffer.get()); fDrawBufferManager->transferToCommandBuffer(commandBuffer.get());
fGraph->reset(); fGraph->reset();
return std::unique_ptr<Recording>(new Recording(std::move(commandBuffer))); std::unique_ptr<Recording> recording(new Recording(std::move(commandBuffer),
std::move(fTextureDataCache)));
fTextureDataCache = std::make_unique<TextureDataCache>();
return recording;
} }
void Recorder::registerDevice(Device* device) { void Recorder::registerDevice(Device* device) {

View File

@ -23,6 +23,10 @@ UniformDataCache* RecorderPriv::uniformDataCache() const {
return fRecorder->fUniformDataCache.get(); return fRecorder->fUniformDataCache.get();
} }
TextureDataCache* RecorderPriv::textureDataCache() const {
return fRecorder->fTextureDataCache.get();
}
const Caps* RecorderPriv::caps() const { const Caps* RecorderPriv::caps() const {
return fRecorder->fGpu->caps(); return fRecorder->fGpu->caps();
} }

View File

@ -18,6 +18,7 @@ public:
ResourceProvider* resourceProvider() const; ResourceProvider* resourceProvider() const;
UniformDataCache* uniformDataCache() const; UniformDataCache* uniformDataCache() const;
TextureDataCache* textureDataCache() const;
DrawBufferManager* drawBufferManager() const; DrawBufferManager* drawBufferManager() const;
const Caps* caps() const; const Caps* caps() const;

View File

@ -8,11 +8,14 @@
#include "experimental/graphite/include/Recording.h" #include "experimental/graphite/include/Recording.h"
#include "experimental/graphite/src/CommandBuffer.h" #include "experimental/graphite/src/CommandBuffer.h"
#include "experimental/graphite/src/PipelineDataCache.h"
namespace skgpu { namespace skgpu {
Recording::Recording(sk_sp<CommandBuffer> commandBuffer) Recording::Recording(sk_sp<CommandBuffer> commandBuffer,
: fCommandBuffer(std::move(commandBuffer)){ std::unique_ptr<TextureDataCache> textureDataCache)
: fCommandBuffer(std::move(commandBuffer))
, fTextureDataCache(std::move(textureDataCache)) {
} }
Recording::~Recording() {} Recording::~Recording() {}

View File

@ -8,10 +8,6 @@
#include "src/core/SkOpts.h" #include "src/core/SkOpts.h"
#include "src/core/SkPipelineData.h" #include "src/core/SkPipelineData.h"
SkPipelineData::SkPipelineData(sk_sp<SkUniformData> initial)
: fUniformDataBlock(std::move(initial)) {
}
void SkPipelineData::add(sk_sp<SkUniformData> uniforms) { void SkPipelineData::add(sk_sp<SkUniformData> uniforms) {
SkASSERT(uniforms && uniforms->count()); SkASSERT(uniforms && uniforms->count());
fUniformDataBlock.add(std::move(uniforms)); fUniformDataBlock.add(std::move(uniforms));
@ -66,14 +62,14 @@ uint32_t SkUniformDataBlock::hash() const {
#ifdef SK_GRAPHITE_ENABLED #ifdef SK_GRAPHITE_ENABLED
static constexpr int kSkFilterModeCount = static_cast<int>(SkFilterMode::kLast) + 1; static constexpr int kSkFilterModeCount = static_cast<int>(SkFilterMode::kLast) + 1;
bool SkPipelineData::TextureDataBlock::TextureInfo::operator==(const TextureInfo& other) const { bool SkTextureDataBlock::TextureInfo::operator==(const TextureInfo& other) const {
return fProxy == other.fProxy && return fProxy == other.fProxy &&
fSamplingOptions == other.fSamplingOptions && fSamplingOptions == other.fSamplingOptions &&
fTileModes[0] == other.fTileModes[0] && fTileModes[0] == other.fTileModes[0] &&
fTileModes[1] == other.fTileModes[1]; fTileModes[1] == other.fTileModes[1];
} }
uint32_t SkPipelineData::TextureDataBlock::TextureInfo::samplerKey() const { uint32_t SkTextureDataBlock::TextureInfo::samplerKey() const {
static_assert(kSkTileModeCount <= 4 && kSkFilterModeCount <= 2); static_assert(kSkTileModeCount <= 4 && kSkFilterModeCount <= 2);
return (static_cast<int>(fTileModes[0]) << 0) | return (static_cast<int>(fTileModes[0]) << 0) |
(static_cast<int>(fTileModes[1]) << 2) | (static_cast<int>(fTileModes[1]) << 2) |
@ -81,7 +77,7 @@ uint32_t SkPipelineData::TextureDataBlock::TextureInfo::samplerKey() const {
(static_cast<int>(fSamplingOptions.mipmap) << 5); (static_cast<int>(fSamplingOptions.mipmap) << 5);
} }
bool SkPipelineData::TextureDataBlock::operator==(const TextureDataBlock& other) const { bool SkTextureDataBlock::operator==(const SkTextureDataBlock& other) const {
if (fTextureData.size() != other.fTextureData.size()) { if (fTextureData.size() != other.fTextureData.size()) {
return false; return false;
} }
@ -95,7 +91,7 @@ bool SkPipelineData::TextureDataBlock::operator==(const TextureDataBlock& other)
return true; return true;
} }
uint32_t SkPipelineData::TextureDataBlock::hash() const { uint32_t SkTextureDataBlock::hash() const {
uint32_t hash = 0; uint32_t hash = 0;
for (auto& d : fTextureData) { for (auto& d : fTextureData) {

View File

@ -51,6 +51,41 @@ private:
std::vector<sk_sp<SkUniformData>> fUniformData; std::vector<sk_sp<SkUniformData>> fUniformData;
}; };
#ifdef SK_GRAPHITE_ENABLED
class SkTextureDataBlock {
public:
struct TextureInfo {
bool operator==(const TextureInfo&) const;
bool operator!=(const TextureInfo& other) const { return !(*this == other); }
uint32_t samplerKey() const;
sk_sp<skgpu::TextureProxy> fProxy;
SkSamplingOptions fSamplingOptions;
SkTileMode fTileModes[2];
};
SkTextureDataBlock() = default;
bool empty() const { return fTextureData.empty(); }
int numTextures() const { return SkTo<int>(fTextureData.size()); }
const TextureInfo& texture(int index) { return fTextureData[index]; }
bool operator==(const SkTextureDataBlock&) const;
bool operator!=(const SkTextureDataBlock& other) const { return !(*this == other); }
uint32_t hash() const;
void add(const SkSamplingOptions& sampling,
const SkTileMode tileModes[2],
sk_sp<skgpu::TextureProxy> proxy) {
fTextureData.push_back({std::move(proxy), sampling, {tileModes[0], tileModes[1]}});
}
private:
std::vector<TextureInfo> fTextureData;
};
#endif // SK_GRAPHITE_ENABLED
// TODO: The current plan for fixing uniform padding is for the SkPipelineData to hold a // TODO: The current plan for fixing uniform padding is for the SkPipelineData to hold a
// persistent uniformManager. A stretch goal for this system would be for this combination // persistent uniformManager. A stretch goal for this system would be for this combination
// to accumulate all the uniforms and then rearrange them to minimize padding. This would, // to accumulate all the uniforms and then rearrange them to minimize padding. This would,
@ -76,7 +111,6 @@ public:
#endif #endif
SkPipelineData() = default; SkPipelineData() = default;
SkPipelineData(sk_sp<SkUniformData> initial);
#ifdef SK_GRAPHITE_ENABLED #ifdef SK_GRAPHITE_ENABLED
void setBlendInfo(const SkPipelineData::BlendInfo& blendInfo) { void setBlendInfo(const SkPipelineData::BlendInfo& blendInfo) {
@ -84,39 +118,6 @@ public:
} }
const BlendInfo& blendInfo() const { return fBlendInfo; } const BlendInfo& blendInfo() const { return fBlendInfo; }
class TextureDataBlock {
public:
struct TextureInfo {
bool operator==(const TextureInfo&) const;
bool operator!=(const TextureInfo& other) const { return !(*this == other); }
uint32_t samplerKey() const;
sk_sp<skgpu::TextureProxy> fProxy;
SkSamplingOptions fSamplingOptions;
SkTileMode fTileModes[2];
};
TextureDataBlock() = default;
bool empty() const { return fTextureData.empty(); }
int numTextures() const { return SkTo<int>(fTextureData.size()); }
const TextureInfo& texture(int index) { return fTextureData[index]; }
bool operator==(const TextureDataBlock&) const;
bool operator!=(const TextureDataBlock& other) const { return !(*this == other); }
uint32_t hash() const;
void add(const SkSamplingOptions& sampling,
const SkTileMode tileModes[2],
sk_sp<skgpu::TextureProxy> proxy) {
fTextureData.push_back({std::move(proxy), sampling, {tileModes[0], tileModes[1]}});
}
private:
std::vector<TextureInfo> fTextureData;
};
void add(const SkSamplingOptions& sampling, void add(const SkSamplingOptions& sampling,
const SkTileMode tileModes[2], const SkTileMode tileModes[2],
sk_sp<skgpu::TextureProxy> proxy) { sk_sp<skgpu::TextureProxy> proxy) {
@ -124,7 +125,7 @@ public:
} }
bool hasTextures() const { return !fTextureDataBlock.empty(); } bool hasTextures() const { return !fTextureDataBlock.empty(); }
const TextureDataBlock& textureDataBlock() { return fTextureDataBlock; } const SkTextureDataBlock& textureDataBlock() { return fTextureDataBlock; }
#endif #endif
void add(sk_sp<SkUniformData>); void add(sk_sp<SkUniformData>);
@ -132,17 +133,11 @@ public:
SkUniformDataBlock& uniformDataBlock() { return fUniformDataBlock; } SkUniformDataBlock& uniformDataBlock() { return fUniformDataBlock; }
// TODO: remove these two once the PipelineDataCache has been split
bool operator==(const SkPipelineData& that) const {
return fUniformDataBlock == that.fUniformDataBlock;
}
uint32_t hash() const { return fUniformDataBlock.hash(); }
private: private:
SkUniformDataBlock fUniformDataBlock; SkUniformDataBlock fUniformDataBlock;
#ifdef SK_GRAPHITE_ENABLED #ifdef SK_GRAPHITE_ENABLED
TextureDataBlock fTextureDataBlock; SkTextureDataBlock fTextureDataBlock;
BlendInfo fBlendInfo; BlendInfo fBlendInfo;
#endif #endif
}; };