Add ability to write out VkPipelineCache to gpu PersistentCache.
Bug: skia:
Change-Id: Id13d680401f69a074ae0c85f9ceaf3308fccb129
Reviewed-on: https://skia-review.googlesource.com/c/181403
Commit-Queue: Greg Daniel <egdaniel@google.com>
Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
diff --git a/dm/DMSrcSink.cpp b/dm/DMSrcSink.cpp
index 18835ba..46c1675 100644
--- a/dm/DMSrcSink.cpp
+++ b/dm/DMSrcSink.cpp
@@ -1517,6 +1517,9 @@
context->contextPriv().getGpu()->deleteTestingOnlyBackendRenderTarget(backendRT);
}
}
+ if (grOptions.fPersistentCache) {
+ context->storeVkPipelineCacheData();
+ }
return "";
}
diff --git a/include/gpu/GrContext.h b/include/gpu/GrContext.h
index 0be9854..5c3781f 100644
--- a/include/gpu/GrContext.h
+++ b/include/gpu/GrContext.h
@@ -283,6 +283,8 @@
bool supportsDistanceFieldText() const;
+ void storeVkPipelineCacheData();
+
protected:
GrContext(GrBackendApi, int32_t id = SK_InvalidGenID);
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index 14a65fa..88d1ec2 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -397,6 +397,16 @@
fContext->fDrawingManager->flush(proxy);
}
+////////////////////////////////////////////////////////////////////////////////
+
+void GrContext::storeVkPipelineCacheData() {
+ if (fGpu) {
+ fGpu->storeVkPipelineCacheData();
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
// TODO: This will be removed when GrSurfaceContexts are aware of their color types.
// (skbug.com/6718)
static bool valid_premul_config(GrPixelConfig config) {
diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h
index 850934e..c99733d 100644
--- a/src/gpu/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -429,6 +429,8 @@
return 0;
}
+ virtual void storeVkPipelineCacheData() {}
+
protected:
// Handles cases where a surface will be updated without a call to flushRenderTarget.
void didWriteToSurface(GrSurface* surface, GrSurfaceOrigin origin, const SkIRect* bounds,
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index 59764ad..1bb1062 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -170,10 +170,11 @@
VK_CALL(GetPhysicalDeviceProperties(backendContext.fPhysicalDevice, &fPhysDevProps));
VK_CALL(GetPhysicalDeviceMemoryProperties(backendContext.fPhysicalDevice, &fPhysDevMemProps));
+ fResourceProvider.init();
+
fCmdPool = fResourceProvider.findOrCreateCommandPool();
fCurrentCmdBuffer = fCmdPool->getPrimaryCommandBuffer();
SkASSERT(fCurrentCmdBuffer);
- fResourceProvider.init();
fCurrentCmdBuffer->begin(this);
}
@@ -2203,3 +2204,9 @@
return sampler->uniqueID();
}
+void GrVkGpu::storeVkPipelineCacheData() {
+ if (this->getContext()->contextPriv().getPersistentCache()) {
+ this->resourceProvider().storePipelineCacheData();
+ }
+}
+
diff --git a/src/gpu/vk/GrVkGpu.h b/src/gpu/vk/GrVkGpu.h
index 22cf45e..acd814c 100644
--- a/src/gpu/vk/GrVkGpu.h
+++ b/src/gpu/vk/GrVkGpu.h
@@ -57,10 +57,10 @@
VkQueue queue() const { return fQueue; }
uint32_t queueIndex() const { return fQueueIndex; }
GrVkCommandPool* cmdPool() const { return fCmdPool; }
- VkPhysicalDeviceProperties physicalDeviceProperties() const {
+ const VkPhysicalDeviceProperties& physicalDeviceProperties() const {
return fPhysDevProps;
}
- VkPhysicalDeviceMemoryProperties physicalDeviceMemoryProperties() const {
+ const VkPhysicalDeviceMemoryProperties& physicalDeviceMemoryProperties() const {
return fPhysDevMemProps;
}
@@ -166,6 +166,13 @@
uint32_t getExtraSamplerKeyForProgram(const GrSamplerState&,
const GrBackendFormat& format) override;
+ enum PersistentCacheKeyType : uint32_t {
+ kShader_PersistentCacheKeyType = 0,
+ kPipelineCache_PersistentCacheKeyType = 1,
+ };
+
+ void storeVkPipelineCacheData() override;
+
private:
GrVkGpu(GrContext*, const GrContextOptions&, const GrVkBackendContext&,
sk_sp<const GrVkInterface>);
diff --git a/src/gpu/vk/GrVkPipelineStateBuilder.cpp b/src/gpu/vk/GrVkPipelineStateBuilder.cpp
index fab4559..6219277 100644
--- a/src/gpu/vk/GrVkPipelineStateBuilder.cpp
+++ b/src/gpu/vk/GrVkPipelineStateBuilder.cpp
@@ -183,8 +183,10 @@
const SkSL::Program::Inputs& fragInputs,
const SkSL::String& geom,
const SkSL::Program::Inputs& geomInputs) {
+ Desc* desc = static_cast<Desc*>(this->desc());
+
// see loadShadersFromCache for the layout of cache entries
- sk_sp<SkData> key = SkData::MakeWithoutCopy(desc()->asKey(), desc()->keyLength());
+ sk_sp<SkData> key = SkData::MakeWithoutCopy(desc->asKey(), desc->shaderKeyLength());
size_t dataLength = (sizeof(shader_size) + sizeof(SkSL::Program::Inputs)) * 3 + vert.length() +
frag.length() + geom.length();
std::unique_ptr<uint8_t[]> data(new uint8_t[dataLength]);
@@ -276,7 +278,7 @@
sk_sp<SkData> cached;
auto persistentCache = fGpu->getContext()->contextPriv().getPersistentCache();
if (persistentCache) {
- sk_sp<SkData> key = SkData::MakeWithoutCopy(desc->asKey(), desc->keyLength());
+ sk_sp<SkData> key = SkData::MakeWithoutCopy(desc->asKey(), desc->shaderKeyLength());
cached = persistentCache->load(*key);
}
int numShaderStages;
@@ -395,6 +397,12 @@
}
GrProcessorKeyBuilder b(&desc->key());
+
+ b.add32(GrVkGpu::kShader_PersistentCacheKeyType);
+ int keyLength = desc->key().count();
+ SkASSERT(0 == (keyLength % 4));
+ desc->fShaderKeyLength = SkToU32(keyLength);
+
GrVkRenderTarget* vkRT = (GrVkRenderTarget*)pipeline.renderTarget();
vkRT->simpleRenderPass()->genKey(&b);
diff --git a/src/gpu/vk/GrVkPipelineStateBuilder.h b/src/gpu/vk/GrVkPipelineStateBuilder.h
index fc322df..7351789 100644
--- a/src/gpu/vk/GrVkPipelineStateBuilder.h
+++ b/src/gpu/vk/GrVkPipelineStateBuilder.h
@@ -44,7 +44,11 @@
GrPrimitiveType primitiveType,
GrVkGpu* gpu);
+ size_t shaderKeyLength() const { return fShaderKeyLength; }
+
private:
+ size_t fShaderKeyLength;
+
typedef GrProgramDesc INHERITED;
};
diff --git a/src/gpu/vk/GrVkResourceProvider.cpp b/src/gpu/vk/GrVkResourceProvider.cpp
index 060bc87..5ca2330 100644
--- a/src/gpu/vk/GrVkResourceProvider.cpp
+++ b/src/gpu/vk/GrVkResourceProvider.cpp
@@ -36,22 +36,55 @@
delete fPipelineStateCache;
}
-void GrVkResourceProvider::init() {
- VkPipelineCacheCreateInfo createInfo;
- memset(&createInfo, 0, sizeof(VkPipelineCacheCreateInfo));
- createInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
- createInfo.pNext = nullptr;
- createInfo.flags = 0;
- createInfo.initialDataSize = 0;
- createInfo.pInitialData = nullptr;
- VkResult result = GR_VK_CALL(fGpu->vkInterface(),
- CreatePipelineCache(fGpu->device(), &createInfo, nullptr,
- &fPipelineCache));
- SkASSERT(VK_SUCCESS == result);
- if (VK_SUCCESS != result) {
- fPipelineCache = VK_NULL_HANDLE;
- }
+VkPipelineCache GrVkResourceProvider::pipelineCache() {
+ if (fPipelineCache == VK_NULL_HANDLE) {
+ VkPipelineCacheCreateInfo createInfo;
+ memset(&createInfo, 0, sizeof(VkPipelineCacheCreateInfo));
+ createInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
+ createInfo.pNext = nullptr;
+ createInfo.flags = 0;
+ auto persistentCache = fGpu->getContext()->contextPriv().getPersistentCache();
+ sk_sp<SkData> cached;
+ if (persistentCache) {
+ uint32_t key = GrVkGpu::kPipelineCache_PersistentCacheKeyType;
+ sk_sp<SkData> keyData = SkData::MakeWithoutCopy(&key, sizeof(uint32_t));
+ cached = persistentCache->load(*keyData);
+ }
+ bool usedCached = false;
+ if (cached) {
+ uint32_t* cacheHeader = (uint32_t*)cached->data();
+ if (cacheHeader[1] == VK_PIPELINE_CACHE_HEADER_VERSION_ONE) {
+ // For version one of the header, the total header size is 16 bytes plus
+ // VK_UUID_SIZE bytes. See Section 9.6 (Pipeline Cache) in the vulkan spec to see
+ // the breakdown of these bytes.
+ SkASSERT(cacheHeader[0] == 16 + VK_UUID_SIZE);
+ const VkPhysicalDeviceProperties& devProps = fGpu->physicalDeviceProperties();
+ const uint8_t* supportedPipelineCacheUUID = devProps.pipelineCacheUUID;
+ if (cacheHeader[2] == devProps.vendorID && cacheHeader[3] == devProps.deviceID &&
+ !memcmp(&cacheHeader[4], supportedPipelineCacheUUID, VK_UUID_SIZE)) {
+ createInfo.initialDataSize = cached->size();
+ createInfo.pInitialData = cached->data();
+ usedCached = true;
+ }
+ }
+ }
+ if (!usedCached) {
+ createInfo.initialDataSize = 0;
+ createInfo.pInitialData = nullptr;
+ }
+ VkResult result = GR_VK_CALL(fGpu->vkInterface(),
+ CreatePipelineCache(fGpu->device(), &createInfo, nullptr,
+ &fPipelineCache));
+ SkASSERT(VK_SUCCESS == result);
+ if (VK_SUCCESS != result) {
+ fPipelineCache = VK_NULL_HANDLE;
+ }
+ }
+ return fPipelineCache;
+}
+
+void GrVkResourceProvider::init() {
// Init uniform descriptor objects
GrVkDescriptorSetManager* dsm = GrVkDescriptorSetManager::CreateUniformManager(fGpu);
fDescriptorSetManagers.emplace_back(dsm);
@@ -69,7 +102,7 @@
VkPipelineLayout layout) {
return GrVkPipeline::Create(fGpu, primProc, pipeline, stencil, shaderStageInfo,
shaderStageCount, primitiveType, compatibleRenderPass, layout,
- fPipelineCache);
+ this->pipelineCache());
}
GrVkCopyPipeline* GrVkResourceProvider::findOrCreateCopyPipeline(
@@ -88,7 +121,7 @@
pipelineLayout,
dst->numColorSamples(),
*dst->simpleRenderPass(),
- fPipelineCache);
+ this->pipelineCache());
if (!pipeline) {
return nullptr;
}
@@ -491,6 +524,28 @@
fAvailableCommandPools.push_back(pool);
}
+void GrVkResourceProvider::storePipelineCacheData() {
+ size_t dataSize = 0;
+ VkResult result = GR_VK_CALL(fGpu->vkInterface(), GetPipelineCacheData(fGpu->device(),
+ this->pipelineCache(),
+ &dataSize, nullptr));
+ SkASSERT(result == VK_SUCCESS);
+
+ std::unique_ptr<uint8_t[]> data(new uint8_t[dataSize]);
+
+ result = GR_VK_CALL(fGpu->vkInterface(), GetPipelineCacheData(fGpu->device(),
+ this->pipelineCache(),
+ &dataSize,
+ (void*)data.get()));
+ SkASSERT(result == VK_SUCCESS);
+
+ uint32_t key = GrVkGpu::kPipelineCache_PersistentCacheKeyType;
+ sk_sp<SkData> keyData = SkData::MakeWithoutCopy(&key, sizeof(uint32_t));
+
+ fGpu->getContext()->contextPriv().getPersistentCache()->store(
+ *keyData, *SkData::MakeWithoutCopy(data.get(), dataSize));
+}
+
////////////////////////////////////////////////////////////////////////////////
GrVkResourceProvider::CompatibleRenderPassSet::CompatibleRenderPassSet(
diff --git a/src/gpu/vk/GrVkResourceProvider.h b/src/gpu/vk/GrVkResourceProvider.h
index 2eac2b2..97f11b1 100644
--- a/src/gpu/vk/GrVkResourceProvider.h
+++ b/src/gpu/vk/GrVkResourceProvider.h
@@ -156,6 +156,8 @@
// can be reused by the next uniform buffer resource request.
void recycleStandardUniformBufferResource(const GrVkResource*);
+ void storePipelineCacheData();
+
// Destroy any cached resources. To be called before destroying the VkDevice.
// The assumption is that all queues are idle and all command buffers are finished.
// For resource tracing to work properly, this should be called after unrefing all other
@@ -245,6 +247,8 @@
int fLastReturnedIndex;
};
+ VkPipelineCache pipelineCache();
+
GrVkGpu* fGpu;
// Central cache for creating pipelines