• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7 
8 #include "src/gpu/vk/GrVkResourceProvider.h"
9 
10 #include "include/gpu/GrDirectContext.h"
11 #include "src/core/SkTaskGroup.h"
12 #include "src/core/SkTraceEvent.h"
13 #include "src/gpu/GrDirectContextPriv.h"
14 #include "src/gpu/GrSamplerState.h"
15 #include "src/gpu/GrStencilSettings.h"
16 #include "src/gpu/vk/GrVkCommandBuffer.h"
17 #include "src/gpu/vk/GrVkCommandPool.h"
18 #include "src/gpu/vk/GrVkGpu.h"
19 #include "src/gpu/vk/GrVkPipeline.h"
20 #include "src/gpu/vk/GrVkRenderTarget.h"
21 #include "src/gpu/vk/GrVkUtil.h"
22 
GrVkResourceProvider(GrVkGpu * gpu)23 GrVkResourceProvider::GrVkResourceProvider(GrVkGpu* gpu)
24     : fGpu(gpu)
25     , fPipelineCache(VK_NULL_HANDLE) {
26     fPipelineStateCache = sk_make_sp<PipelineStateCache>(gpu);
27 }
28 
~GrVkResourceProvider()29 GrVkResourceProvider::~GrVkResourceProvider() {
30     SkASSERT(0 == fRenderPassArray.count());
31     SkASSERT(0 == fExternalRenderPasses.count());
32     SkASSERT(0 == fMSAALoadPipelines.count());
33     SkASSERT(VK_NULL_HANDLE == fPipelineCache);
34 }
35 
pipelineCache()36 VkPipelineCache GrVkResourceProvider::pipelineCache() {
37     if (fPipelineCache == VK_NULL_HANDLE) {
38         VkPipelineCacheCreateInfo createInfo;
39         memset(&createInfo, 0, sizeof(VkPipelineCacheCreateInfo));
40         createInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
41         createInfo.pNext = nullptr;
42         createInfo.flags = 0;
43 
44         auto persistentCache = fGpu->getContext()->priv().getPersistentCache();
45         sk_sp<SkData> cached;
46         if (persistentCache) {
47             uint32_t key = GrVkGpu::kPipelineCache_PersistentCacheKeyType;
48             sk_sp<SkData> keyData = SkData::MakeWithoutCopy(&key, sizeof(uint32_t));
49             cached = persistentCache->load(*keyData);
50         }
51         bool usedCached = false;
52         if (cached) {
53             uint32_t* cacheHeader = (uint32_t*)cached->data();
54             if (cacheHeader[1] == VK_PIPELINE_CACHE_HEADER_VERSION_ONE) {
55                 // For version one of the header, the total header size is 16 bytes plus
56                 // VK_UUID_SIZE bytes. See Section 9.6 (Pipeline Cache) in the vulkan spec to see
57                 // the breakdown of these bytes.
58                 SkASSERT(cacheHeader[0] == 16 + VK_UUID_SIZE);
59                 const VkPhysicalDeviceProperties& devProps = fGpu->physicalDeviceProperties();
60                 const uint8_t* supportedPipelineCacheUUID = devProps.pipelineCacheUUID;
61                 if (cacheHeader[2] == devProps.vendorID && cacheHeader[3] == devProps.deviceID &&
62                     !memcmp(&cacheHeader[4], supportedPipelineCacheUUID, VK_UUID_SIZE)) {
63                     createInfo.initialDataSize = cached->size();
64                     createInfo.pInitialData = cached->data();
65                     usedCached = true;
66                 }
67             }
68         }
69         if (!usedCached) {
70             createInfo.initialDataSize = 0;
71             createInfo.pInitialData = nullptr;
72         }
73 
74         VkResult result;
75         GR_VK_CALL_RESULT(fGpu, result, CreatePipelineCache(fGpu->device(), &createInfo, nullptr,
76                                                             &fPipelineCache));
77         if (VK_SUCCESS != result) {
78             fPipelineCache = VK_NULL_HANDLE;
79         }
80     }
81     return fPipelineCache;
82 }
83 
init()84 void GrVkResourceProvider::init() {
85     // Init uniform descriptor objects
86     GrVkDescriptorSetManager* dsm = GrVkDescriptorSetManager::CreateUniformManager(fGpu);
87     fDescriptorSetManagers.emplace_back(dsm);
88     SkASSERT(1 == fDescriptorSetManagers.count());
89     fUniformDSHandle = GrVkDescriptorSetManager::Handle(0);
90     dsm = GrVkDescriptorSetManager::CreateInputManager(fGpu);
91     fDescriptorSetManagers.emplace_back(dsm);
92     SkASSERT(2 == fDescriptorSetManagers.count());
93     fInputDSHandle = GrVkDescriptorSetManager::Handle(1);
94 }
95 
makePipeline(const GrProgramInfo & programInfo,VkPipelineShaderStageCreateInfo * shaderStageInfo,int shaderStageCount,VkRenderPass compatibleRenderPass,VkPipelineLayout layout,uint32_t subpass)96 sk_sp<const GrVkPipeline> GrVkResourceProvider::makePipeline(
97         const GrProgramInfo& programInfo,
98         VkPipelineShaderStageCreateInfo* shaderStageInfo,
99         int shaderStageCount,
100         VkRenderPass compatibleRenderPass,
101         VkPipelineLayout layout,
102         uint32_t subpass) {
103     return GrVkPipeline::Make(fGpu, programInfo, shaderStageInfo, shaderStageCount,
104                               compatibleRenderPass, layout, this->pipelineCache(), subpass);
105 }
106 
107 // To create framebuffers, we first need to create a simple RenderPass that is
108 // only used for framebuffer creation. When we actually render we will create
109 // RenderPasses as needed that are compatible with the framebuffer.
110 const GrVkRenderPass*
findCompatibleRenderPass(GrVkRenderTarget * target,CompatibleRPHandle * compatibleHandle,bool withResolve,bool withStencil,SelfDependencyFlags selfDepFlags,LoadFromResolve loadFromResolve)111 GrVkResourceProvider::findCompatibleRenderPass(GrVkRenderTarget* target,
112                                                CompatibleRPHandle* compatibleHandle,
113                                                bool withResolve,
114                                                bool withStencil,
115                                                SelfDependencyFlags selfDepFlags,
116                                                LoadFromResolve loadFromResolve) {
117     // Get attachment information from render target. This includes which attachments the render
118     // target has (color, stencil) and the attachments format and sample count.
119     GrVkRenderPass::AttachmentFlags attachmentFlags;
120     GrVkRenderPass::AttachmentsDescriptor attachmentsDesc;
121     target->getAttachmentsDescriptor(&attachmentsDesc, &attachmentFlags, withResolve, withStencil);
122 
123     return this->findCompatibleRenderPass(&attachmentsDesc, attachmentFlags, selfDepFlags,
124                                           loadFromResolve, compatibleHandle);
125 }
126 
127 const GrVkRenderPass*
findCompatibleRenderPass(GrVkRenderPass::AttachmentsDescriptor * desc,GrVkRenderPass::AttachmentFlags attachmentFlags,SelfDependencyFlags selfDepFlags,LoadFromResolve loadFromResolve,CompatibleRPHandle * compatibleHandle)128 GrVkResourceProvider::findCompatibleRenderPass(GrVkRenderPass::AttachmentsDescriptor* desc,
129                                                GrVkRenderPass::AttachmentFlags attachmentFlags,
130                                                SelfDependencyFlags selfDepFlags,
131                                                LoadFromResolve loadFromResolve,
132                                                CompatibleRPHandle* compatibleHandle) {
133     for (int i = 0; i < fRenderPassArray.count(); ++i) {
134         if (fRenderPassArray[i].isCompatible(*desc, attachmentFlags, selfDepFlags,
135                                              loadFromResolve)) {
136             const GrVkRenderPass* renderPass = fRenderPassArray[i].getCompatibleRenderPass();
137             renderPass->ref();
138             if (compatibleHandle) {
139                 *compatibleHandle = CompatibleRPHandle(i);
140             }
141             return renderPass;
142         }
143     }
144 
145     GrVkRenderPass* renderPass = GrVkRenderPass::CreateSimple(fGpu, desc, attachmentFlags,
146                                                               selfDepFlags, loadFromResolve);
147     if (!renderPass) {
148         return nullptr;
149     }
150     fRenderPassArray.emplace_back(renderPass);
151 
152     if (compatibleHandle) {
153         *compatibleHandle = CompatibleRPHandle(fRenderPassArray.count() - 1);
154     }
155     return renderPass;
156 }
157 
findCompatibleExternalRenderPass(VkRenderPass renderPass,uint32_t colorAttachmentIndex)158 const GrVkRenderPass* GrVkResourceProvider::findCompatibleExternalRenderPass(
159         VkRenderPass renderPass, uint32_t colorAttachmentIndex) {
160     for (int i = 0; i < fExternalRenderPasses.count(); ++i) {
161         if (fExternalRenderPasses[i]->isCompatibleExternalRP(renderPass)) {
162             fExternalRenderPasses[i]->ref();
163 #ifdef SK_DEBUG
164             uint32_t cachedColorIndex;
165             SkASSERT(fExternalRenderPasses[i]->colorAttachmentIndex(&cachedColorIndex));
166             SkASSERT(cachedColorIndex == colorAttachmentIndex);
167 #endif
168             return fExternalRenderPasses[i];
169         }
170     }
171 
172     const GrVkRenderPass* newRenderPass = new GrVkRenderPass(fGpu, renderPass,
173                                                              colorAttachmentIndex);
174     fExternalRenderPasses.push_back(newRenderPass);
175     newRenderPass->ref();
176     return newRenderPass;
177 }
178 
findRenderPass(GrVkRenderTarget * target,const GrVkRenderPass::LoadStoreOps & colorOps,const GrVkRenderPass::LoadStoreOps & resolveOps,const GrVkRenderPass::LoadStoreOps & stencilOps,CompatibleRPHandle * compatibleHandle,bool withResolve,bool withStencil,SelfDependencyFlags selfDepFlags,LoadFromResolve loadFromResolve)179 const GrVkRenderPass* GrVkResourceProvider::findRenderPass(
180         GrVkRenderTarget* target,
181         const GrVkRenderPass::LoadStoreOps& colorOps,
182         const GrVkRenderPass::LoadStoreOps& resolveOps,
183         const GrVkRenderPass::LoadStoreOps& stencilOps,
184         CompatibleRPHandle* compatibleHandle,
185         bool withResolve,
186         bool withStencil,
187         SelfDependencyFlags selfDepFlags,
188         LoadFromResolve loadFromResolve) {
189     GrVkResourceProvider::CompatibleRPHandle tempRPHandle;
190     GrVkResourceProvider::CompatibleRPHandle* pRPHandle = compatibleHandle ? compatibleHandle
191                                                                            : &tempRPHandle;
192     *pRPHandle = target->compatibleRenderPassHandle(withResolve, withStencil, selfDepFlags,
193                                                     loadFromResolve);
194     if (!pRPHandle->isValid()) {
195         return nullptr;
196     }
197 
198     return this->findRenderPass(*pRPHandle, colorOps, resolveOps, stencilOps);
199 }
200 
201 const GrVkRenderPass*
findRenderPass(const CompatibleRPHandle & compatibleHandle,const GrVkRenderPass::LoadStoreOps & colorOps,const GrVkRenderPass::LoadStoreOps & resolveOps,const GrVkRenderPass::LoadStoreOps & stencilOps)202 GrVkResourceProvider::findRenderPass(const CompatibleRPHandle& compatibleHandle,
203                                      const GrVkRenderPass::LoadStoreOps& colorOps,
204                                      const GrVkRenderPass::LoadStoreOps& resolveOps,
205                                      const GrVkRenderPass::LoadStoreOps& stencilOps) {
206     SkASSERT(compatibleHandle.isValid() && compatibleHandle.toIndex() < fRenderPassArray.count());
207     CompatibleRenderPassSet& compatibleSet = fRenderPassArray[compatibleHandle.toIndex()];
208     const GrVkRenderPass* renderPass = compatibleSet.getRenderPass(fGpu,
209                                                                    colorOps,
210                                                                    resolveOps,
211                                                                    stencilOps);
212     if (!renderPass) {
213         return nullptr;
214     }
215     renderPass->ref();
216     return renderPass;
217 }
218 
findOrCreateCompatibleDescriptorPool(VkDescriptorType type,uint32_t count)219 GrVkDescriptorPool* GrVkResourceProvider::findOrCreateCompatibleDescriptorPool(
220                                                             VkDescriptorType type, uint32_t count) {
221     return GrVkDescriptorPool::Create(fGpu, type, count);
222 }
223 
findOrCreateCompatibleSampler(GrSamplerState params,const GrVkYcbcrConversionInfo & ycbcrInfo)224 GrVkSampler* GrVkResourceProvider::findOrCreateCompatibleSampler(
225         GrSamplerState params, const GrVkYcbcrConversionInfo& ycbcrInfo) {
226     GrVkSampler* sampler = fSamplers.find(GrVkSampler::GenerateKey(params, ycbcrInfo));
227     if (!sampler) {
228         sampler = GrVkSampler::Create(fGpu, params, ycbcrInfo);
229         if (!sampler) {
230             return nullptr;
231         }
232         fSamplers.add(sampler);
233     }
234     SkASSERT(sampler);
235     sampler->ref();
236     return sampler;
237 }
238 
findOrCreateCompatibleSamplerYcbcrConversion(const GrVkYcbcrConversionInfo & ycbcrInfo)239 GrVkSamplerYcbcrConversion* GrVkResourceProvider::findOrCreateCompatibleSamplerYcbcrConversion(
240         const GrVkYcbcrConversionInfo& ycbcrInfo) {
241     GrVkSamplerYcbcrConversion* ycbcrConversion =
242             fYcbcrConversions.find(GrVkSamplerYcbcrConversion::GenerateKey(ycbcrInfo));
243     if (!ycbcrConversion) {
244         ycbcrConversion = GrVkSamplerYcbcrConversion::Create(fGpu, ycbcrInfo);
245         if (!ycbcrConversion) {
246             return nullptr;
247         }
248         fYcbcrConversions.add(ycbcrConversion);
249     }
250     SkASSERT(ycbcrConversion);
251     ycbcrConversion->ref();
252     return ycbcrConversion;
253 }
254 
findOrCreateCompatiblePipelineState(GrRenderTarget * renderTarget,const GrProgramInfo & programInfo,VkRenderPass compatibleRenderPass,bool overrideSubpassForResolveLoad)255 GrVkPipelineState* GrVkResourceProvider::findOrCreateCompatiblePipelineState(
256         GrRenderTarget* renderTarget,
257         const GrProgramInfo& programInfo,
258         VkRenderPass compatibleRenderPass,
259         bool overrideSubpassForResolveLoad) {
260     return fPipelineStateCache->findOrCreatePipelineState(renderTarget, programInfo,
261                                                           compatibleRenderPass,
262                                                           overrideSubpassForResolveLoad);
263 }
264 
findOrCreateCompatiblePipelineState(const GrProgramDesc & desc,const GrProgramInfo & programInfo,VkRenderPass compatibleRenderPass,GrThreadSafePipelineBuilder::Stats::ProgramCacheResult * stat)265 GrVkPipelineState* GrVkResourceProvider::findOrCreateCompatiblePipelineState(
266         const GrProgramDesc& desc,
267         const GrProgramInfo& programInfo,
268         VkRenderPass compatibleRenderPass,
269         GrThreadSafePipelineBuilder::Stats::ProgramCacheResult* stat) {
270 
271     auto tmp =  fPipelineStateCache->findOrCreatePipelineState(desc, programInfo,
272                                                                compatibleRenderPass, stat);
273     if (!tmp) {
274         fPipelineStateCache->stats()->incNumPreCompilationFailures();
275     } else {
276         fPipelineStateCache->stats()->incNumPreProgramCacheResult(*stat);
277     }
278 
279     return tmp;
280 }
281 
findOrCreateMSAALoadPipeline(const GrVkRenderPass & renderPass,int numSamples,VkPipelineShaderStageCreateInfo * shaderStageInfo,VkPipelineLayout pipelineLayout)282 sk_sp<const GrVkPipeline> GrVkResourceProvider::findOrCreateMSAALoadPipeline(
283         const GrVkRenderPass& renderPass,
284         int numSamples,
285         VkPipelineShaderStageCreateInfo* shaderStageInfo,
286         VkPipelineLayout pipelineLayout) {
287     // Find or Create a compatible pipeline
288     sk_sp<const GrVkPipeline> pipeline;
289     for (int i = 0; i < fMSAALoadPipelines.count() && !pipeline; ++i) {
290         if (fMSAALoadPipelines[i].fRenderPass->isCompatible(renderPass)) {
291             pipeline = fMSAALoadPipelines[i].fPipeline;
292         }
293     }
294     if (!pipeline) {
295         pipeline = GrVkPipeline::Make(
296                 fGpu,
297                 /*vertexAttribs=*/GrGeometryProcessor::AttributeSet(),
298                 /*instanceAttribs=*/GrGeometryProcessor::AttributeSet(),
299                 GrPrimitiveType::kTriangleStrip,
300                 kTopLeft_GrSurfaceOrigin,
301                 GrStencilSettings(),
302                 numSamples,
303                 /*isHWantialiasState=*/false,
304                 GrXferProcessor::BlendInfo(),
305                 /*isWireframe=*/false,
306                 /*useConservativeRaster=*/false,
307                 /*subpass=*/0,
308                 shaderStageInfo,
309                 /*shaderStageCount=*/2,
310                 renderPass.vkRenderPass(),
311                 pipelineLayout,
312                 /*ownsLayout=*/false,
313                 this->pipelineCache());
314         if (!pipeline) {
315             return nullptr;
316         }
317         fMSAALoadPipelines.push_back({pipeline, &renderPass});
318     }
319     SkASSERT(pipeline);
320     return pipeline;
321 }
322 
getZeroSamplerDescriptorSetHandle(GrVkDescriptorSetManager::Handle * handle)323 void GrVkResourceProvider::getZeroSamplerDescriptorSetHandle(
324         GrVkDescriptorSetManager::Handle* handle) {
325     SkASSERT(handle);
326     for (int i = 0; i < fDescriptorSetManagers.count(); ++i) {
327         if (fDescriptorSetManagers[i]->isZeroSampler()) {
328             *handle = GrVkDescriptorSetManager::Handle(i);
329             return;
330         }
331     }
332 
333     GrVkDescriptorSetManager* dsm =
334             GrVkDescriptorSetManager::CreateZeroSamplerManager(fGpu);
335     fDescriptorSetManagers.emplace_back(dsm);
336     *handle = GrVkDescriptorSetManager::Handle(fDescriptorSetManagers.count() - 1);
337 }
338 
getSamplerDescriptorSetHandle(VkDescriptorType type,const GrVkUniformHandler & uniformHandler,GrVkDescriptorSetManager::Handle * handle)339 void GrVkResourceProvider::getSamplerDescriptorSetHandle(VkDescriptorType type,
340                                                          const GrVkUniformHandler& uniformHandler,
341                                                          GrVkDescriptorSetManager::Handle* handle) {
342     SkASSERT(handle);
343     SkASSERT(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER == type ||
344              VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER == type);
345     for (int i = 0; i < fDescriptorSetManagers.count(); ++i) {
346         if (fDescriptorSetManagers[i]->isCompatible(type, &uniformHandler)) {
347            *handle = GrVkDescriptorSetManager::Handle(i);
348            return;
349         }
350     }
351 
352     GrVkDescriptorSetManager* dsm = GrVkDescriptorSetManager::CreateSamplerManager(fGpu, type,
353                                                                                    uniformHandler);
354     fDescriptorSetManagers.emplace_back(dsm);
355     *handle = GrVkDescriptorSetManager::Handle(fDescriptorSetManagers.count() - 1);
356 }
357 
getUniformDSLayout() const358 VkDescriptorSetLayout GrVkResourceProvider::getUniformDSLayout() const {
359     SkASSERT(fUniformDSHandle.isValid());
360     return fDescriptorSetManagers[fUniformDSHandle.toIndex()]->layout();
361 }
362 
getInputDSLayout() const363 VkDescriptorSetLayout GrVkResourceProvider::getInputDSLayout() const {
364     SkASSERT(fInputDSHandle.isValid());
365     return fDescriptorSetManagers[fInputDSHandle.toIndex()]->layout();
366 }
367 
getSamplerDSLayout(const GrVkDescriptorSetManager::Handle & handle) const368 VkDescriptorSetLayout GrVkResourceProvider::getSamplerDSLayout(
369         const GrVkDescriptorSetManager::Handle& handle) const {
370     SkASSERT(handle.isValid());
371     return fDescriptorSetManagers[handle.toIndex()]->layout();
372 }
373 
getUniformDescriptorSet()374 const GrVkDescriptorSet* GrVkResourceProvider::getUniformDescriptorSet() {
375     SkASSERT(fUniformDSHandle.isValid());
376     return fDescriptorSetManagers[fUniformDSHandle.toIndex()]->getDescriptorSet(fGpu,
377                                                                                 fUniformDSHandle);
378 }
379 
getInputDescriptorSet()380 const GrVkDescriptorSet* GrVkResourceProvider::getInputDescriptorSet() {
381     SkASSERT(fInputDSHandle.isValid());
382     return fDescriptorSetManagers[fInputDSHandle.toIndex()]->getDescriptorSet(fGpu, fInputDSHandle);
383 }
384 
getSamplerDescriptorSet(const GrVkDescriptorSetManager::Handle & handle)385 const GrVkDescriptorSet* GrVkResourceProvider::getSamplerDescriptorSet(
386         const GrVkDescriptorSetManager::Handle& handle) {
387     SkASSERT(handle.isValid());
388     return fDescriptorSetManagers[handle.toIndex()]->getDescriptorSet(fGpu, handle);
389 }
390 
recycleDescriptorSet(const GrVkDescriptorSet * descSet,const GrVkDescriptorSetManager::Handle & handle)391 void GrVkResourceProvider::recycleDescriptorSet(const GrVkDescriptorSet* descSet,
392                                                 const GrVkDescriptorSetManager::Handle& handle) {
393     SkASSERT(descSet);
394     SkASSERT(handle.isValid());
395     int managerIdx = handle.toIndex();
396     SkASSERT(managerIdx < fDescriptorSetManagers.count());
397     fDescriptorSetManagers[managerIdx]->recycleDescriptorSet(descSet);
398 }
399 
findOrCreateCommandPool()400 GrVkCommandPool* GrVkResourceProvider::findOrCreateCommandPool() {
401     SkAutoMutexExclusive lock(fBackgroundMutex);
402     GrVkCommandPool* result;
403     if (fAvailableCommandPools.count()) {
404         result = fAvailableCommandPools.back();
405         fAvailableCommandPools.pop_back();
406     } else {
407         result = GrVkCommandPool::Create(fGpu);
408         if (!result) {
409             return nullptr;
410         }
411     }
412     SkASSERT(result->unique());
413     SkDEBUGCODE(
414         for (const GrVkCommandPool* pool : fActiveCommandPools) {
415             SkASSERT(pool != result);
416         }
417         for (const GrVkCommandPool* pool : fAvailableCommandPools) {
418             SkASSERT(pool != result);
419         }
420     )
421     fActiveCommandPools.push_back(result);
422     result->ref();
423     return result;
424 }
425 
checkCommandBuffers()426 void GrVkResourceProvider::checkCommandBuffers() {
427     // When resetting a command buffer it can trigger client provided procs (e.g. release or
428     // finished) to be called. During these calls the client could trigger us to abandon the vk
429     // context, e.g. if we are in a DEVICE_LOST state. When we abandon the vk context we will
430     // unref all the fActiveCommandPools and reset the array. Since this can happen in the middle
431     // of the loop here, we need to additionally check that fActiveCommandPools still has pools on
432     // each iteration.
433     //
434     // TODO: We really need to have a more robust way to protect us from client proc calls that
435     // happen in the middle of us doing work. This may be just one of many potential pitfalls that
436     // could happen from the client triggering GrDirectContext changes during a proc call.
437     for (int i = fActiveCommandPools.count() - 1; fActiveCommandPools.count() && i >= 0; --i) {
438         GrVkCommandPool* pool = fActiveCommandPools[i];
439         if (!pool->isOpen()) {
440             GrVkPrimaryCommandBuffer* buffer = pool->getPrimaryCommandBuffer();
441             if (buffer->finished(fGpu)) {
442                 fActiveCommandPools.removeShuffle(i);
443                 // This passes ownership of the pool to the backgroundReset call. The pool should
444                 // not be used again from this function.
445                 // TODO: We should see if we can use sk_sps here to make this more explicit.
446                 this->backgroundReset(pool);
447             }
448         }
449     }
450 }
451 
forceSyncAllCommandBuffers()452 void GrVkResourceProvider::forceSyncAllCommandBuffers() {
453     for (int i = fActiveCommandPools.count() - 1; fActiveCommandPools.count() && i >= 0; --i) {
454         GrVkCommandPool* pool = fActiveCommandPools[i];
455         if (!pool->isOpen()) {
456             GrVkPrimaryCommandBuffer* buffer = pool->getPrimaryCommandBuffer();
457             buffer->forceSync(fGpu);
458         }
459     }
460 }
461 
addFinishedProcToActiveCommandBuffers(sk_sp<GrRefCntedCallback> finishedCallback)462 void GrVkResourceProvider::addFinishedProcToActiveCommandBuffers(
463         sk_sp<GrRefCntedCallback> finishedCallback) {
464     for (int i = 0; i < fActiveCommandPools.count(); ++i) {
465         GrVkCommandPool* pool = fActiveCommandPools[i];
466         GrVkPrimaryCommandBuffer* buffer = pool->getPrimaryCommandBuffer();
467         buffer->addFinishedProc(finishedCallback);
468     }
469 }
470 
destroyResources()471 void GrVkResourceProvider::destroyResources() {
472     SkTaskGroup* taskGroup = fGpu->getContext()->priv().getTaskGroup();
473     if (taskGroup) {
474         taskGroup->wait();
475     }
476 
477     // Release all msaa load pipelines
478     fMSAALoadPipelines.reset();
479 
480     // loop over all render pass sets to make sure we destroy all the internal VkRenderPasses
481     for (int i = 0; i < fRenderPassArray.count(); ++i) {
482         fRenderPassArray[i].releaseResources();
483     }
484     fRenderPassArray.reset();
485 
486     for (int i = 0; i < fExternalRenderPasses.count(); ++i) {
487         fExternalRenderPasses[i]->unref();
488     }
489     fExternalRenderPasses.reset();
490 
491     // Iterate through all store GrVkSamplers and unref them before resetting the hash table.
492     fSamplers.foreach([&](auto* elt) { elt->unref(); });
493     fSamplers.reset();
494 
495     fYcbcrConversions.foreach([&](auto* elt) { elt->unref(); });
496     fYcbcrConversions.reset();
497 
498     fPipelineStateCache->release();
499 
500     GR_VK_CALL(fGpu->vkInterface(), DestroyPipelineCache(fGpu->device(), fPipelineCache, nullptr));
501     fPipelineCache = VK_NULL_HANDLE;
502 
503     for (GrVkCommandPool* pool : fActiveCommandPools) {
504         SkASSERT(pool->unique());
505         pool->unref();
506     }
507     fActiveCommandPools.reset();
508 
509     {
510         SkAutoMutexExclusive lock(fBackgroundMutex);
511         for (GrVkCommandPool* pool : fAvailableCommandPools) {
512             SkASSERT(pool->unique());
513             pool->unref();
514         }
515         fAvailableCommandPools.reset();
516     }
517 
518     // We must release/destroy all command buffers and pipeline states before releasing the
519     // GrVkDescriptorSetManagers. Additionally, we must release all uniform buffers since they hold
520     // refs to GrVkDescriptorSets.
521     for (int i = 0; i < fDescriptorSetManagers.count(); ++i) {
522         fDescriptorSetManagers[i]->release(fGpu);
523     }
524     fDescriptorSetManagers.reset();
525 
526 }
527 
releaseUnlockedBackendObjects()528 void GrVkResourceProvider::releaseUnlockedBackendObjects() {
529     SkAutoMutexExclusive lock(fBackgroundMutex);
530     for (GrVkCommandPool* pool : fAvailableCommandPools) {
531         SkASSERT(pool->unique());
532         pool->unref();
533     }
534     fAvailableCommandPools.reset();
535 }
536 
backgroundReset(GrVkCommandPool * pool)537 void GrVkResourceProvider::backgroundReset(GrVkCommandPool* pool) {
538     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
539     SkASSERT(pool->unique());
540     pool->releaseResources();
541     // After releasing resources we may have called a client callback proc which may have
542     // disconnected the GrVkGpu. In that case we do not want to push the pool back onto the cache,
543     // but instead just drop the pool.
544     if (fGpu->disconnected()) {
545         pool->unref();
546         return;
547     }
548     SkTaskGroup* taskGroup = fGpu->getContext()->priv().getTaskGroup();
549     if (taskGroup) {
550         taskGroup->add([this, pool]() {
551             this->reset(pool);
552         });
553     } else {
554         this->reset(pool);
555     }
556 }
557 
reset(GrVkCommandPool * pool)558 void GrVkResourceProvider::reset(GrVkCommandPool* pool) {
559     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
560     SkASSERT(pool->unique());
561     pool->reset(fGpu);
562     SkAutoMutexExclusive lock(fBackgroundMutex);
563     fAvailableCommandPools.push_back(pool);
564 }
565 
storePipelineCacheData()566 void GrVkResourceProvider::storePipelineCacheData() {
567     if (this->pipelineCache() == VK_NULL_HANDLE) {
568         return;
569     }
570     size_t dataSize = 0;
571     VkResult result;
572     GR_VK_CALL_RESULT(fGpu, result, GetPipelineCacheData(fGpu->device(), this->pipelineCache(),
573                                                          &dataSize, nullptr));
574     if (result != VK_SUCCESS) {
575         return;
576     }
577 
578     std::unique_ptr<uint8_t[]> data(new uint8_t[dataSize]);
579 
580     GR_VK_CALL_RESULT(fGpu, result, GetPipelineCacheData(fGpu->device(), this->pipelineCache(),
581                                                          &dataSize, (void*)data.get()));
582     if (result != VK_SUCCESS) {
583         return;
584     }
585 
586     uint32_t key = GrVkGpu::kPipelineCache_PersistentCacheKeyType;
587     sk_sp<SkData> keyData = SkData::MakeWithoutCopy(&key, sizeof(uint32_t));
588 
589     fGpu->getContext()->priv().getPersistentCache()->store(
590             *keyData, *SkData::MakeWithoutCopy(data.get(), dataSize), SkString("VkPipelineCache"));
591 }
592 
593 ////////////////////////////////////////////////////////////////////////////////
594 
CompatibleRenderPassSet(GrVkRenderPass * renderPass)595 GrVkResourceProvider::CompatibleRenderPassSet::CompatibleRenderPassSet(GrVkRenderPass* renderPass)
596         : fLastReturnedIndex(0) {
597     renderPass->ref();
598     fRenderPasses.push_back(renderPass);
599 }
600 
isCompatible(const GrVkRenderPass::AttachmentsDescriptor & attachmentsDescriptor,GrVkRenderPass::AttachmentFlags attachmentFlags,SelfDependencyFlags selfDepFlags,LoadFromResolve loadFromResolve) const601 bool GrVkResourceProvider::CompatibleRenderPassSet::isCompatible(
602         const GrVkRenderPass::AttachmentsDescriptor& attachmentsDescriptor,
603         GrVkRenderPass::AttachmentFlags attachmentFlags,
604         SelfDependencyFlags selfDepFlags,
605         LoadFromResolve loadFromResolve) const {
606     // The first GrVkRenderpass should always exists since we create the basic load store
607     // render pass on create
608     SkASSERT(fRenderPasses[0]);
609     return fRenderPasses[0]->isCompatible(attachmentsDescriptor, attachmentFlags, selfDepFlags,
610                                           loadFromResolve);
611 }
612 
getRenderPass(GrVkGpu * gpu,const GrVkRenderPass::LoadStoreOps & colorOps,const GrVkRenderPass::LoadStoreOps & resolveOps,const GrVkRenderPass::LoadStoreOps & stencilOps)613 GrVkRenderPass* GrVkResourceProvider::CompatibleRenderPassSet::getRenderPass(
614         GrVkGpu* gpu,
615         const GrVkRenderPass::LoadStoreOps& colorOps,
616         const GrVkRenderPass::LoadStoreOps& resolveOps,
617         const GrVkRenderPass::LoadStoreOps& stencilOps) {
618     for (int i = 0; i < fRenderPasses.count(); ++i) {
619         int idx = (i + fLastReturnedIndex) % fRenderPasses.count();
620         if (fRenderPasses[idx]->equalLoadStoreOps(colorOps, resolveOps, stencilOps)) {
621             fLastReturnedIndex = idx;
622             return fRenderPasses[idx];
623         }
624     }
625     GrVkRenderPass* renderPass = GrVkRenderPass::Create(gpu, *this->getCompatibleRenderPass(),
626                                                         colorOps, resolveOps, stencilOps);
627     if (!renderPass) {
628         return nullptr;
629     }
630     fRenderPasses.push_back(renderPass);
631     fLastReturnedIndex = fRenderPasses.count() - 1;
632     return renderPass;
633 }
634 
releaseResources()635 void GrVkResourceProvider::CompatibleRenderPassSet::releaseResources() {
636     for (int i = 0; i < fRenderPasses.count(); ++i) {
637         if (fRenderPasses[i]) {
638             fRenderPasses[i]->unref();
639             fRenderPasses[i] = nullptr;
640         }
641     }
642 }
643 
644