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>
This commit is contained in:
Greg Daniel 2019-01-08 15:49:46 -05:00 committed by Skia Commit-Bot
parent f1202c61de
commit a870b46c79
10 changed files with 124 additions and 22 deletions

View File

@ -1517,6 +1517,9 @@ Error GPUSink::onDraw(const Src& src, SkBitmap* dst, SkWStream*, SkString* log,
context->contextPriv().getGpu()->deleteTestingOnlyBackendRenderTarget(backendRT);
}
}
if (grOptions.fPersistentCache) {
context->storeVkPipelineCacheData();
}
return "";
}

View File

@ -283,6 +283,8 @@ public:
bool supportsDistanceFieldText() const;
void storeVkPipelineCacheData();
protected:
GrContext(GrBackendApi, int32_t id = SK_InvalidGenID);

View File

@ -397,6 +397,16 @@ void GrContextPriv::flush(GrSurfaceProxy* proxy) {
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) {

View File

@ -429,6 +429,8 @@ public:
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,

View File

@ -170,10 +170,11 @@ GrVkGpu::GrVkGpu(GrContext* context, const GrContextOptions& options,
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 @@ uint32_t GrVkGpu::getExtraSamplerKeyForProgram(const GrSamplerState& samplerStat
return sampler->uniqueID();
}
void GrVkGpu::storeVkPipelineCacheData() {
if (this->getContext()->contextPriv().getPersistentCache()) {
this->resourceProvider().storePipelineCacheData();
}
}

View File

@ -57,10 +57,10 @@ public:
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 @@ public:
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>);

View File

@ -183,8 +183,10 @@ void GrVkPipelineStateBuilder::storeShadersInCache(const SkSL::String& vert,
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 @@ GrVkPipelineState* GrVkPipelineStateBuilder::finalize(const GrStencilSettings& s
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 @@ bool GrVkPipelineStateBuilder::Desc::Build(Desc* desc,
}
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);

View File

@ -44,7 +44,11 @@ public:
GrPrimitiveType primitiveType,
GrVkGpu* gpu);
size_t shaderKeyLength() const { return fShaderKeyLength; }
private:
size_t fShaderKeyLength;
typedef GrProgramDesc INHERITED;
};

View File

@ -36,22 +36,55 @@ GrVkResourceProvider::~GrVkResourceProvider() {
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 @@ GrVkPipeline* GrVkResourceProvider::createPipeline(const GrPrimitiveProcessor& p
VkPipelineLayout layout) {
return GrVkPipeline::Create(fGpu, primProc, pipeline, stencil, shaderStageInfo,
shaderStageCount, primitiveType, compatibleRenderPass, layout,
fPipelineCache);
this->pipelineCache());
}
GrVkCopyPipeline* GrVkResourceProvider::findOrCreateCopyPipeline(
@ -88,7 +121,7 @@ GrVkCopyPipeline* GrVkResourceProvider::findOrCreateCopyPipeline(
pipelineLayout,
dst->numColorSamples(),
*dst->simpleRenderPass(),
fPipelineCache);
this->pipelineCache());
if (!pipeline) {
return nullptr;
}
@ -491,6 +524,28 @@ void GrVkResourceProvider::reset(GrVkCommandPool* pool) {
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(

View File

@ -156,6 +156,8 @@ public:
// 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 @@ private:
int fLastReturnedIndex;
};
VkPipelineCache pipelineCache();
GrVkGpu* fGpu;
// Central cache for creating pipelines