Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(310)

Unified Diff: src/gpu/vk/GrVkPipelineStateCache.cpp

Issue 1816153002: Set up cache in vulkan to reuse GrVkPrograms (aka VkPipelines) (Closed) Base URL: https://skia.googlesource.com/skia.git@progSamplers
Patch Set: rebase Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/gpu/vk/GrVkPipelineStateBuilder.cpp ('k') | src/gpu/vk/GrVkPipelineStateDataManager.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/gpu/vk/GrVkPipelineStateCache.cpp
diff --git a/src/gpu/vk/GrVkPipelineStateCache.cpp b/src/gpu/vk/GrVkPipelineStateCache.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f2092af981c91b73ba5f9593ac0535f8b86d37ad
--- /dev/null
+++ b/src/gpu/vk/GrVkPipelineStateCache.cpp
@@ -0,0 +1,249 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrVkResourceProvider.h"
+
+#include "GrVkGpu.h"
+#include "GrProcessor.h"
+#include "GrVkPipelineState.h"
+#include "GrVkPipelineStateBuilder.h"
+#include "SkRTConf.h"
+#include "SkTSearch.h"
+#include "glsl/GrGLSLFragmentProcessor.h"
+#include "glsl/GrGLSLProgramDataManager.h"
+
+#ifdef PIPELINE_STATE_CACHE_STATS
+SK_CONF_DECLARE(bool, c_DisplayCache, "gpu.displayCache", false,
+ "Display pipeline state cache usage.");
+#endif
+
+typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
+
+struct GrVkResourceProvider::PipelineStateCache::Entry {
+
+ Entry() : fPipelineState(nullptr), fLRUStamp(0) {}
+
+ SkAutoTUnref<GrVkPipelineState> fPipelineState;
+ unsigned int fLRUStamp;
+};
+
+struct GrVkResourceProvider::PipelineStateCache::PipelineDescLess {
+ bool operator() (const GrVkPipelineState::Desc& desc, const Entry* entry) {
+ SkASSERT(entry->fPipelineState.get());
+ return GrVkPipelineState::Desc::Less(desc, entry->fPipelineState->getDesc());
+ }
+
+ bool operator() (const Entry* entry, const GrVkPipelineState::Desc& desc) {
+ SkASSERT(entry->fPipelineState.get());
+ return GrVkPipelineState::Desc::Less(entry->fPipelineState->getDesc(), desc);
+ }
+};
+
+GrVkResourceProvider::PipelineStateCache::PipelineStateCache(GrVkGpu* gpu)
+ : fCount(0)
+ , fCurrLRUStamp(0)
+ , fGpu(gpu)
+#ifdef PIPELINE_STATE_CACHE_STATS
+ , fTotalRequests(0)
+ , fCacheMisses(0)
+ , fHashMisses(0)
+#endif
+{
+ for (int i = 0; i < 1 << kHashBits; ++i) {
+ fHashTable[i] = nullptr;
+ }
+}
+
+GrVkResourceProvider::PipelineStateCache::~PipelineStateCache() {
+ SkASSERT(0 == fCount);
+ // dump stats
+#ifdef PIPELINE_STATE_CACHE_STATS
+ if (c_DisplayCache) {
+ SkDebugf("--- Pipeline State Cache ---\n");
+ SkDebugf("Total requests: %d\n", fTotalRequests);
+ SkDebugf("Cache misses: %d\n", fCacheMisses);
+ SkDebugf("Cache miss %%: %f\n", (fTotalRequests > 0) ?
+ 100.f * fCacheMisses / fTotalRequests :
+ 0.f);
+ int cacheHits = fTotalRequests - fCacheMisses;
+ SkDebugf("Hash miss %%: %f\n", (cacheHits > 0) ? 100.f * fHashMisses / cacheHits : 0.f);
+ SkDebugf("---------------------\n");
+ }
+#endif
+}
+
+void GrVkResourceProvider::PipelineStateCache::reset() {
+ for (int i = 0; i < fCount; ++i) {
+ delete fEntries[i];
+ fEntries[i] = nullptr;
+ }
+ fCount = 0;
+
+ // zero out hash table
+ for (int i = 0; i < 1 << kHashBits; i++) {
+ fHashTable[i] = nullptr;
+ }
+
+ fCurrLRUStamp = 0;
+}
+
+void GrVkResourceProvider::PipelineStateCache::abandon() {
+ for (int i = 0; i < fCount; ++i) {
+ SkASSERT(fEntries[i]->fPipelineState.get());
+ fEntries[i]->fPipelineState->abandonGPUResources();
+ }
+ this->reset();
+}
+
+void GrVkResourceProvider::PipelineStateCache::release() {
+ for (int i = 0; i < fCount; ++i) {
+ SkASSERT(fEntries[i]->fPipelineState.get());
+ fEntries[i]->fPipelineState->freeGPUResources(fGpu);
+ }
+ this->reset();
+}
+
+int GrVkResourceProvider::PipelineStateCache::search(const GrVkPipelineState::Desc& desc) const {
+ PipelineDescLess less;
+ return SkTSearch(fEntries, fCount, desc, sizeof(Entry*), less);
+}
+
+GrVkPipelineState* GrVkResourceProvider::PipelineStateCache::refPipelineState(
+ const GrPipeline& pipeline,
+ const GrPrimitiveProcessor& primProc,
+ GrPrimitiveType primiteType,
+ const GrVkRenderPass& renderPass) {
+#ifdef PIPELINE_STATE_CACHE_STATS
+ ++fTotalRequests;
+#endif
+
+ Entry* entry = nullptr;
+
+ // Get GrVkProgramDesc
+ GrVkPipelineState::Desc desc;
+ if (!GrVkProgramDescBuilder::Build(&desc.fProgramDesc,
+ primProc,
+ pipeline,
+ *fGpu->vkCaps().glslCaps())) {
+ GrCapsDebugf(fGpu->caps(), "Failed to build vk program descriptor!\n");
+ return false;
+ }
+
+ // Get vulkan specific descriptor key
+ GrVkPipelineState::BuildStateKey(pipeline, primiteType, &desc.fStateKey);
+ // Get checksum of entire PipelineDesc
+ int keyLength = desc.fStateKey.count();
+ SkASSERT(0 == (keyLength % 4));
+ // Seed the checksum with the checksum of the programDesc then add the vulkan key to it.
+ desc.fChecksum = SkChecksum::Murmur3(desc.fStateKey.begin(), keyLength,
+ desc.fProgramDesc.getChecksum());
+
+ uint32_t hashIdx = desc.fChecksum;
+ hashIdx ^= hashIdx >> 16;
+ if (kHashBits <= 8) {
+ hashIdx ^= hashIdx >> 8;
+ }
+ hashIdx &= ((1 << kHashBits) - 1);
+ Entry* hashedEntry = fHashTable[hashIdx];
+ if (hashedEntry && hashedEntry->fPipelineState->getDesc() == desc) {
+ SkASSERT(hashedEntry->fPipelineState);
+ entry = hashedEntry;
+ }
+
+ int entryIdx;
+ if (nullptr == entry) {
+ entryIdx = this->search(desc);
+ if (entryIdx >= 0) {
+ entry = fEntries[entryIdx];
+#ifdef PIPELINE_STATE_CACHE_STATS
+ ++fHashMisses;
+#endif
+ }
+ }
+
+ if (nullptr == entry) {
+ // We have a cache miss
+#ifdef PIPELINE_STATE_CACHE_STATS
+ ++fCacheMisses;
+#endif
+ GrVkPipelineState* pipelineState =
+ GrVkPipelineStateBuilder::CreatePipelineState(fGpu,
+ pipeline,
+ primProc,
+ primiteType,
+ desc,
+ renderPass);
+ if (nullptr == pipelineState) {
+ return nullptr;
+ }
+ int purgeIdx = 0;
+ if (fCount < kMaxEntries) {
+ entry = new Entry;
+ purgeIdx = fCount++;
+ fEntries[purgeIdx] = entry;
+ } else {
+ SkASSERT(fCount == kMaxEntries);
+ purgeIdx = 0;
+ for (int i = 1; i < kMaxEntries; ++i) {
+ if (fEntries[i]->fLRUStamp < fEntries[purgeIdx]->fLRUStamp) {
+ purgeIdx = i;
+ }
+ }
+ entry = fEntries[purgeIdx];
+ int purgedHashIdx = entry->fPipelineState->getDesc().fChecksum & ((1 << kHashBits) - 1);
+ if (fHashTable[purgedHashIdx] == entry) {
+ fHashTable[purgedHashIdx] = nullptr;
+ }
+ entry->fPipelineState->freeGPUResources(fGpu);
+ }
+ SkASSERT(fEntries[purgeIdx] == entry);
+ entry->fPipelineState.reset(pipelineState);
+ // We need to shift fEntries around so that the entry currently at purgeIdx is placed
+ // just before the entry at ~entryIdx (in order to keep fEntries sorted by descriptor).
+ entryIdx = ~entryIdx;
+ if (entryIdx < purgeIdx) {
+ // Let E and P be the entries at index entryIdx and purgeIdx, respectively.
+ // If the entries array looks like this:
+ // aaaaEbbbbbPccccc
+ // we rearrange it to look like this:
+ // aaaaPEbbbbbccccc
+ size_t copySize = (purgeIdx - entryIdx) * sizeof(Entry*);
+ memmove(fEntries + entryIdx + 1, fEntries + entryIdx, copySize);
+ fEntries[entryIdx] = entry;
+ } else if (purgeIdx < entryIdx) {
+ // If the entries array looks like this:
+ // aaaaPbbbbbEccccc
+ // we rearrange it to look like this:
+ // aaaabbbbbPEccccc
+ size_t copySize = (entryIdx - purgeIdx - 1) * sizeof(Entry*);
+ memmove(fEntries + purgeIdx, fEntries + purgeIdx + 1, copySize);
+ fEntries[entryIdx - 1] = entry;
+ }
+#ifdef SK_DEBUG
+ SkASSERT(fEntries[0]->fPipelineState.get());
+ for (int i = 0; i < fCount - 1; ++i) {
+ SkASSERT(fEntries[i + 1]->fPipelineState.get());
+ const GrVkPipelineState::Desc& a = fEntries[i]->fPipelineState->getDesc();
+ const GrVkPipelineState::Desc& b = fEntries[i + 1]->fPipelineState->getDesc();
+ SkASSERT(GrVkPipelineState::Desc::Less(a, b));
+ SkASSERT(!GrVkPipelineState::Desc::Less(b, a));
+ }
+#endif
+ }
+
+ fHashTable[hashIdx] = entry;
+ entry->fLRUStamp = fCurrLRUStamp;
+
+ if (SK_MaxU32 == fCurrLRUStamp) {
+ // wrap around! just trash our LRU, one time hit.
+ for (int i = 0; i < fCount; ++i) {
+ fEntries[i]->fLRUStamp = 0;
+ }
+ }
+ ++fCurrLRUStamp;
+ return SkRef(entry->fPipelineState.get());
+}
« no previous file with comments | « src/gpu/vk/GrVkPipelineStateBuilder.cpp ('k') | src/gpu/vk/GrVkPipelineStateDataManager.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698