Implement simple pipeline transition cache

Avoids the need to hash PipelineState when we can guess the pipeline that will be used next. This could very easily be optimised in the future with generational, usage-based caching if necessary.
This commit is contained in:
Billy Laws 2022-09-14 23:13:00 +01:00
parent 302b2fcc3f
commit 388cff3353
4 changed files with 37 additions and 6 deletions

View File

@ -505,13 +505,27 @@ namespace skyline::gpu::interconnect::maxwell3d {
Pipeline::Pipeline(InterconnectContext &ctx, const PackedPipelineState &packedState, const std::array<ShaderBinary, engine::PipelineCount> &shaderBinaries, span<TextureView *> colorAttachments, TextureView *depthAttachment) Pipeline::Pipeline(InterconnectContext &ctx, const PackedPipelineState &packedState, const std::array<ShaderBinary, engine::PipelineCount> &shaderBinaries, span<TextureView *> colorAttachments, TextureView *depthAttachment)
: shaderStages{MakePipelineShaders(ctx, packedState, shaderBinaries)}, : shaderStages{MakePipelineShaders(ctx, packedState, shaderBinaries)},
descriptorSetLayoutBindings{MakePipelineDescriptorSetLayoutBindings(shaderStages)}, descriptorSetLayoutBindings{MakePipelineDescriptorSetLayoutBindings(shaderStages)},
compiledPipeline{MakeCompiledPipeline(ctx, packedState, shaderStages, descriptorSetLayoutBindings, colorAttachments, depthAttachment)} { compiledPipeline{MakeCompiledPipeline(ctx, packedState, shaderStages, descriptorSetLayoutBindings, colorAttachments, depthAttachment)},
sourcePackedState{packedState} {
} }
Pipeline *Pipeline::LookupNext(const PackedPipelineState &packedState) { Pipeline *Pipeline::LookupNext(const PackedPipelineState &packedState) {
auto it{std::find_if(transitionCache.begin(), transitionCache.end(), [&packedState](auto pipeline) {
if (pipeline && pipeline->sourcePackedState == packedState)
return true;
else
return false;
})};
if (it != transitionCache.end())
return *it;
return nullptr; return nullptr;
} }
void Pipeline::AddTransition(const PackedPipelineState &packedState, Pipeline *next) {} void Pipeline::AddTransition(Pipeline *next) {
transitionCache[transitionCacheNextIdx] = next;
transitionCacheNextIdx = (transitionCacheNextIdx + 1) % transitionCache.size();
}
} }

View File

@ -32,12 +32,17 @@ namespace skyline::gpu::interconnect::maxwell3d {
std::vector<vk::DescriptorSetLayoutBinding> descriptorSetLayoutBindings; std::vector<vk::DescriptorSetLayoutBinding> descriptorSetLayoutBindings;
cache::GraphicsPipelineCache::CompiledPipeline compiledPipeline; cache::GraphicsPipelineCache::CompiledPipeline compiledPipeline;
std::array<Pipeline *, 4> transitionCache{};
size_t transitionCacheNextIdx{};
public: public:
PackedPipelineState sourcePackedState;
Pipeline(InterconnectContext &ctx, const PackedPipelineState &packedState, const std::array<ShaderBinary, engine::PipelineCount> &shaderBinaries, span<TextureView *> colorAttachments, TextureView *depthAttachment); Pipeline(InterconnectContext &ctx, const PackedPipelineState &packedState, const std::array<ShaderBinary, engine::PipelineCount> &shaderBinaries, span<TextureView *> colorAttachments, TextureView *depthAttachment);
Pipeline *LookupNext(const PackedPipelineState &packedState); Pipeline *LookupNext(const PackedPipelineState &packedState);
void AddTransition(const PackedPipelineState &packedState, Pipeline *next); void AddTransition(Pipeline *next);
}; };
class PipelineManager { class PipelineManager {

View File

@ -294,6 +294,15 @@ namespace skyline::gpu::interconnect::maxwell3d {
entry->cache.insert({blockMapping.data() + blockOffset, CacheEntry{binary, hash}}); entry->cache.insert({blockMapping.data() + blockOffset, CacheEntry{binary, hash}});
} }
// TODO: this needs to be checked every draw irresspective of pipeline dirtiness
bool PipelineStageState::Refresh(InterconnectContext &ctx) {
std::scoped_lock lock{trapMutex};
if (entry && entry->dirty)
return true;
return false;
}
PipelineStageState::~PipelineStageState() { PipelineStageState::~PipelineStageState() {
std::scoped_lock lock{trapMutex}; std::scoped_lock lock{trapMutex};
//for (const auto &mirror : mirrorMap) //for (const auto &mirror : mirrorMap)
@ -504,10 +513,11 @@ namespace skyline::gpu::interconnect::maxwell3d {
pipeline = newPipeline; pipeline = newPipeline;
return; return;
} }
} }
auto newPipeline{pipelineManager.FindOrCreate(ctx, packedState, shaderBinaries, colorAttachments, depthAttachment)}; auto newPipeline{pipelineManager.FindOrCreate(ctx, packedState, shaderBinaries, colorAttachments, depthAttachment)};
pipeline->AddTransition(packedState, newPipeline); if (pipeline)
pipeline->AddTransition(newPipeline);
pipeline = newPipeline; pipeline = newPipeline;
} }

View File

@ -55,7 +55,7 @@ namespace skyline::gpu::interconnect::maxwell3d {
void Flush(InterconnectContext &ctx, PackedPipelineState &packedState); void Flush(InterconnectContext &ctx, PackedPipelineState &packedState);
}; };
class PipelineStageState : dirty::ManualDirty { class PipelineStageState : dirty::RefreshableManualDirty {
public: public:
struct EngineRegisters { struct EngineRegisters {
const engine::Pipeline &pipeline; const engine::Pipeline &pipeline;
@ -100,6 +100,8 @@ namespace skyline::gpu::interconnect::maxwell3d {
~PipelineStageState(); ~PipelineStageState();
void Flush(InterconnectContext &ctx); void Flush(InterconnectContext &ctx);
bool Refresh(InterconnectContext &ctx);
}; };
class VertexInputState : dirty::ManualDirty { class VertexInputState : dirty::ManualDirty {