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 "GrVkResourceProvider.h"
9 
10 #include "GrSamplerParams.h"
11 #include "GrVkCommandBuffer.h"
12 #include "GrVkCopyPipeline.h"
13 #include "GrVkPipeline.h"
14 #include "GrVkRenderTarget.h"
15 #include "GrVkSampler.h"
16 #include "GrVkUniformBuffer.h"
17 #include "GrVkUtil.h"
18 
19 #ifdef SK_TRACE_VK_RESOURCES
20 GrVkResource::Trace GrVkResource::fTrace;
21 uint32_t GrVkResource::fKeyCounter = 0;
22 #endif
23 
GrVkResourceProvider(GrVkGpu * gpu)24 GrVkResourceProvider::GrVkResourceProvider(GrVkGpu* gpu)
25     : fGpu(gpu)
26     , fPipelineCache(VK_NULL_HANDLE) {
27     fPipelineStateCache = new PipelineStateCache(gpu);
28 }
29 
~GrVkResourceProvider()30 GrVkResourceProvider::~GrVkResourceProvider() {
31     SkASSERT(0 == fRenderPassArray.count());
32     SkASSERT(VK_NULL_HANDLE == fPipelineCache);
33     delete fPipelineStateCache;
34 }
35 
init()36 void GrVkResourceProvider::init() {
37     VkPipelineCacheCreateInfo createInfo;
38     memset(&createInfo, 0, sizeof(VkPipelineCacheCreateInfo));
39     createInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
40     createInfo.pNext = nullptr;
41     createInfo.flags = 0;
42     createInfo.initialDataSize = 0;
43     createInfo.pInitialData = nullptr;
44     VkResult result = GR_VK_CALL(fGpu->vkInterface(),
45                                  CreatePipelineCache(fGpu->device(), &createInfo, nullptr,
46                                                      &fPipelineCache));
47     SkASSERT(VK_SUCCESS == result);
48     if (VK_SUCCESS != result) {
49         fPipelineCache = VK_NULL_HANDLE;
50     }
51 
52     // Init uniform descriptor objects
53     fDescriptorSetManagers.emplace_back(fGpu, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
54     SkASSERT(1 == fDescriptorSetManagers.count());
55     fUniformDSHandle = GrVkDescriptorSetManager::Handle(0);
56 }
57 
createPipeline(const GrPipeline & pipeline,const GrStencilSettings & stencil,const GrPrimitiveProcessor & primProc,VkPipelineShaderStageCreateInfo * shaderStageInfo,int shaderStageCount,GrPrimitiveType primitiveType,const GrVkRenderPass & renderPass,VkPipelineLayout layout)58 GrVkPipeline* GrVkResourceProvider::createPipeline(const GrPipeline& pipeline,
59                                                    const GrStencilSettings& stencil,
60                                                    const GrPrimitiveProcessor& primProc,
61                                                    VkPipelineShaderStageCreateInfo* shaderStageInfo,
62                                                    int shaderStageCount,
63                                                    GrPrimitiveType primitiveType,
64                                                    const GrVkRenderPass& renderPass,
65                                                    VkPipelineLayout layout) {
66 
67     return GrVkPipeline::Create(fGpu, pipeline, stencil, primProc, shaderStageInfo,
68                                 shaderStageCount, primitiveType, renderPass, layout,
69                                 fPipelineCache);
70 }
71 
findOrCreateCopyPipeline(const GrVkRenderTarget * dst,VkPipelineShaderStageCreateInfo * shaderStageInfo,VkPipelineLayout pipelineLayout)72 GrVkCopyPipeline* GrVkResourceProvider::findOrCreateCopyPipeline(
73         const GrVkRenderTarget* dst,
74         VkPipelineShaderStageCreateInfo* shaderStageInfo,
75         VkPipelineLayout pipelineLayout) {
76     // Find or Create a compatible pipeline
77     GrVkCopyPipeline* pipeline = nullptr;
78     for (int i = 0; i < fCopyPipelines.count() && !pipeline; ++i) {
79         if (fCopyPipelines[i]->isCompatible(*dst->simpleRenderPass())) {
80             pipeline = fCopyPipelines[i];
81         }
82     }
83     if (!pipeline) {
84         pipeline = GrVkCopyPipeline::Create(fGpu, shaderStageInfo,
85                                             pipelineLayout,
86                                             dst->numColorSamples(),
87                                             *dst->simpleRenderPass(),
88                                             fPipelineCache);
89         fCopyPipelines.push_back(pipeline);
90     }
91     SkASSERT(pipeline);
92     pipeline->ref();
93     return pipeline;
94 }
95 
96 // To create framebuffers, we first need to create a simple RenderPass that is
97 // only used for framebuffer creation. When we actually render we will create
98 // RenderPasses as needed that are compatible with the framebuffer.
99 const GrVkRenderPass*
findCompatibleRenderPass(const GrVkRenderTarget & target,CompatibleRPHandle * compatibleHandle)100 GrVkResourceProvider::findCompatibleRenderPass(const GrVkRenderTarget& target,
101                                                CompatibleRPHandle* compatibleHandle) {
102     for (int i = 0; i < fRenderPassArray.count(); ++i) {
103         if (fRenderPassArray[i].isCompatible(target)) {
104             const GrVkRenderPass* renderPass = fRenderPassArray[i].getCompatibleRenderPass();
105             renderPass->ref();
106             if (compatibleHandle) {
107                 *compatibleHandle = CompatibleRPHandle(i);
108             }
109             return renderPass;
110         }
111     }
112 
113     const GrVkRenderPass* renderPass =
114         fRenderPassArray.emplace_back(fGpu, target).getCompatibleRenderPass();
115     renderPass->ref();
116 
117     if (compatibleHandle) {
118         *compatibleHandle = CompatibleRPHandle(fRenderPassArray.count() - 1);
119     }
120     return renderPass;
121 }
122 
123 const GrVkRenderPass*
findCompatibleRenderPass(const CompatibleRPHandle & compatibleHandle)124 GrVkResourceProvider::findCompatibleRenderPass(const CompatibleRPHandle& compatibleHandle) {
125     SkASSERT(compatibleHandle.isValid() && compatibleHandle.toIndex() < fRenderPassArray.count());
126     int index = compatibleHandle.toIndex();
127     const GrVkRenderPass* renderPass = fRenderPassArray[index].getCompatibleRenderPass();
128     renderPass->ref();
129     return renderPass;
130 }
131 
findRenderPass(const GrVkRenderTarget & target,const GrVkRenderPass::LoadStoreOps & colorOps,const GrVkRenderPass::LoadStoreOps & stencilOps,CompatibleRPHandle * compatibleHandle)132 const GrVkRenderPass* GrVkResourceProvider::findRenderPass(
133                                                      const GrVkRenderTarget& target,
134                                                      const GrVkRenderPass::LoadStoreOps& colorOps,
135                                                      const GrVkRenderPass::LoadStoreOps& stencilOps,
136                                                      CompatibleRPHandle* compatibleHandle) {
137     GrVkResourceProvider::CompatibleRPHandle tempRPHandle;
138     GrVkResourceProvider::CompatibleRPHandle* pRPHandle = compatibleHandle ? compatibleHandle
139                                                                            : &tempRPHandle;
140     *pRPHandle = target.compatibleRenderPassHandle();
141 
142     // This will get us the handle to (and possible create) the compatible set for the specific
143     // GrVkRenderPass we are looking for.
144     this->findCompatibleRenderPass(target, compatibleHandle);
145     return this->findRenderPass(*pRPHandle, colorOps, stencilOps);
146 }
147 
148 const GrVkRenderPass*
findRenderPass(const CompatibleRPHandle & compatibleHandle,const GrVkRenderPass::LoadStoreOps & colorOps,const GrVkRenderPass::LoadStoreOps & stencilOps)149 GrVkResourceProvider::findRenderPass(const CompatibleRPHandle& compatibleHandle,
150                                      const GrVkRenderPass::LoadStoreOps& colorOps,
151                                      const GrVkRenderPass::LoadStoreOps& stencilOps) {
152     SkASSERT(compatibleHandle.isValid() && compatibleHandle.toIndex() < fRenderPassArray.count());
153     CompatibleRenderPassSet& compatibleSet = fRenderPassArray[compatibleHandle.toIndex()];
154     const GrVkRenderPass* renderPass = compatibleSet.getRenderPass(fGpu,
155                                                                    colorOps,
156                                                                    stencilOps);
157     renderPass->ref();
158     return renderPass;
159 }
160 
findOrCreateCompatibleDescriptorPool(VkDescriptorType type,uint32_t count)161 GrVkDescriptorPool* GrVkResourceProvider::findOrCreateCompatibleDescriptorPool(
162                                                             VkDescriptorType type, uint32_t count) {
163     return new GrVkDescriptorPool(fGpu, type, count);
164 }
165 
findOrCreateCompatibleSampler(const GrSamplerParams & params,uint32_t mipLevels)166 GrVkSampler* GrVkResourceProvider::findOrCreateCompatibleSampler(const GrSamplerParams& params,
167                                                                  uint32_t mipLevels) {
168     GrVkSampler* sampler = fSamplers.find(GrVkSampler::GenerateKey(params, mipLevels));
169     if (!sampler) {
170         sampler = GrVkSampler::Create(fGpu, params, mipLevels);
171         fSamplers.add(sampler);
172     }
173     SkASSERT(sampler);
174     sampler->ref();
175     return sampler;
176 }
177 
findOrCreateCompatiblePipelineState(const GrPipeline & pipeline,const GrPrimitiveProcessor & proc,GrPrimitiveType primitiveType,const GrVkRenderPass & renderPass)178 sk_sp<GrVkPipelineState> GrVkResourceProvider::findOrCreateCompatiblePipelineState(
179                                                                  const GrPipeline& pipeline,
180                                                                  const GrPrimitiveProcessor& proc,
181                                                                  GrPrimitiveType primitiveType,
182                                                                  const GrVkRenderPass& renderPass) {
183     return fPipelineStateCache->refPipelineState(pipeline, proc, primitiveType, renderPass);
184 }
185 
getSamplerDescriptorSetHandle(const GrVkUniformHandler & uniformHandler,GrVkDescriptorSetManager::Handle * handle)186 void GrVkResourceProvider::getSamplerDescriptorSetHandle(const GrVkUniformHandler& uniformHandler,
187                                                          GrVkDescriptorSetManager::Handle* handle) {
188     SkASSERT(handle);
189     for (int i = 0; i < fDescriptorSetManagers.count(); ++i) {
190         if (fDescriptorSetManagers[i].isCompatible(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
191                                                    &uniformHandler)) {
192            *handle = GrVkDescriptorSetManager::Handle(i);
193            return;
194         }
195     }
196 
197     fDescriptorSetManagers.emplace_back(fGpu, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
198                                         &uniformHandler);
199     *handle = GrVkDescriptorSetManager::Handle(fDescriptorSetManagers.count() - 1);
200 }
201 
getSamplerDescriptorSetHandle(const SkTArray<uint32_t> & visibilities,GrVkDescriptorSetManager::Handle * handle)202 void GrVkResourceProvider::getSamplerDescriptorSetHandle(const SkTArray<uint32_t>& visibilities,
203                                                          GrVkDescriptorSetManager::Handle* handle) {
204     SkASSERT(handle);
205     for (int i = 0; i < fDescriptorSetManagers.count(); ++i) {
206         if (fDescriptorSetManagers[i].isCompatible(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
207                                                    visibilities)) {
208             *handle = GrVkDescriptorSetManager::Handle(i);
209             return;
210         }
211     }
212 
213     fDescriptorSetManagers.emplace_back(fGpu, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
214                                         visibilities);
215     *handle = GrVkDescriptorSetManager::Handle(fDescriptorSetManagers.count() - 1);
216 }
217 
getUniformDSLayout() const218 VkDescriptorSetLayout GrVkResourceProvider::getUniformDSLayout() const {
219     SkASSERT(fUniformDSHandle.isValid());
220     return fDescriptorSetManagers[fUniformDSHandle.toIndex()].layout();
221 }
222 
getSamplerDSLayout(const GrVkDescriptorSetManager::Handle & handle) const223 VkDescriptorSetLayout GrVkResourceProvider::getSamplerDSLayout(
224         const GrVkDescriptorSetManager::Handle& handle) const {
225     SkASSERT(handle.isValid());
226     return fDescriptorSetManagers[handle.toIndex()].layout();
227 }
228 
getUniformDescriptorSet()229 const GrVkDescriptorSet* GrVkResourceProvider::getUniformDescriptorSet() {
230     SkASSERT(fUniformDSHandle.isValid());
231     return fDescriptorSetManagers[fUniformDSHandle.toIndex()].getDescriptorSet(fGpu,
232                                                                                fUniformDSHandle);
233 }
234 
getSamplerDescriptorSet(const GrVkDescriptorSetManager::Handle & handle)235 const GrVkDescriptorSet* GrVkResourceProvider::getSamplerDescriptorSet(
236         const GrVkDescriptorSetManager::Handle& handle) {
237     SkASSERT(handle.isValid());
238     return fDescriptorSetManagers[handle.toIndex()].getDescriptorSet(fGpu, handle);
239 }
240 
recycleDescriptorSet(const GrVkDescriptorSet * descSet,const GrVkDescriptorSetManager::Handle & handle)241 void GrVkResourceProvider::recycleDescriptorSet(const GrVkDescriptorSet* descSet,
242                                                 const GrVkDescriptorSetManager::Handle& handle) {
243     SkASSERT(descSet);
244     SkASSERT(handle.isValid());
245     int managerIdx = handle.toIndex();
246     SkASSERT(managerIdx < fDescriptorSetManagers.count());
247     fDescriptorSetManagers[managerIdx].recycleDescriptorSet(descSet);
248 }
249 
findOrCreatePrimaryCommandBuffer()250 GrVkPrimaryCommandBuffer* GrVkResourceProvider::findOrCreatePrimaryCommandBuffer() {
251     GrVkPrimaryCommandBuffer* cmdBuffer = nullptr;
252     int count = fAvailableCommandBuffers.count();
253     if (count > 0) {
254         cmdBuffer = fAvailableCommandBuffers[count - 1];
255         SkASSERT(cmdBuffer->finished(fGpu));
256         fAvailableCommandBuffers.removeShuffle(count - 1);
257     } else {
258         cmdBuffer = GrVkPrimaryCommandBuffer::Create(fGpu, fGpu->cmdPool());
259     }
260     fActiveCommandBuffers.push_back(cmdBuffer);
261     cmdBuffer->ref();
262     return cmdBuffer;
263 }
264 
checkCommandBuffers()265 void GrVkResourceProvider::checkCommandBuffers() {
266     for (int i = fActiveCommandBuffers.count()-1; i >= 0; --i) {
267         if (fActiveCommandBuffers[i]->finished(fGpu)) {
268             GrVkPrimaryCommandBuffer* cmdBuffer = fActiveCommandBuffers[i];
269             cmdBuffer->reset(fGpu);
270             fAvailableCommandBuffers.push_back(cmdBuffer);
271             fActiveCommandBuffers.removeShuffle(i);
272         }
273     }
274 }
275 
findOrCreateSecondaryCommandBuffer()276 GrVkSecondaryCommandBuffer* GrVkResourceProvider::findOrCreateSecondaryCommandBuffer() {
277     GrVkSecondaryCommandBuffer* cmdBuffer = nullptr;
278     int count = fAvailableSecondaryCommandBuffers.count();
279     if (count > 0) {
280         cmdBuffer = fAvailableSecondaryCommandBuffers[count-1];
281         fAvailableSecondaryCommandBuffers.removeShuffle(count - 1);
282     } else {
283         cmdBuffer = GrVkSecondaryCommandBuffer::Create(fGpu, fGpu->cmdPool());
284     }
285     return cmdBuffer;
286 }
287 
recycleSecondaryCommandBuffer(GrVkSecondaryCommandBuffer * cb)288 void GrVkResourceProvider::recycleSecondaryCommandBuffer(GrVkSecondaryCommandBuffer* cb) {
289     cb->reset(fGpu);
290     fAvailableSecondaryCommandBuffers.push_back(cb);
291 }
292 
findOrCreateStandardUniformBufferResource()293 const GrVkResource* GrVkResourceProvider::findOrCreateStandardUniformBufferResource() {
294     const GrVkResource* resource = nullptr;
295     int count = fAvailableUniformBufferResources.count();
296     if (count > 0) {
297         resource = fAvailableUniformBufferResources[count - 1];
298         fAvailableUniformBufferResources.removeShuffle(count - 1);
299     } else {
300         resource = GrVkUniformBuffer::CreateResource(fGpu, GrVkUniformBuffer::kStandardSize);
301     }
302     return resource;
303 }
304 
recycleStandardUniformBufferResource(const GrVkResource * resource)305 void GrVkResourceProvider::recycleStandardUniformBufferResource(const GrVkResource* resource) {
306     fAvailableUniformBufferResources.push_back(resource);
307 }
308 
destroyResources(bool deviceLost)309 void GrVkResourceProvider::destroyResources(bool deviceLost) {
310     // release our active command buffers
311     for (int i = 0; i < fActiveCommandBuffers.count(); ++i) {
312         SkASSERT(deviceLost || fActiveCommandBuffers[i]->finished(fGpu));
313         SkASSERT(fActiveCommandBuffers[i]->unique());
314         fActiveCommandBuffers[i]->reset(fGpu);
315         fActiveCommandBuffers[i]->unref(fGpu);
316     }
317     fActiveCommandBuffers.reset();
318     // release our available command buffers
319     for (int i = 0; i < fAvailableCommandBuffers.count(); ++i) {
320         SkASSERT(deviceLost || fAvailableCommandBuffers[i]->finished(fGpu));
321         SkASSERT(fAvailableCommandBuffers[i]->unique());
322         fAvailableCommandBuffers[i]->unref(fGpu);
323     }
324     fAvailableCommandBuffers.reset();
325 
326     // release our available secondary command buffers
327     for (int i = 0; i < fAvailableSecondaryCommandBuffers.count(); ++i) {
328         SkASSERT(fAvailableSecondaryCommandBuffers[i]->unique());
329         fAvailableSecondaryCommandBuffers[i]->unref(fGpu);
330     }
331     fAvailableSecondaryCommandBuffers.reset();
332 
333     // Release all copy pipelines
334     for (int i = 0; i < fCopyPipelines.count(); ++i) {
335         fCopyPipelines[i]->unref(fGpu);
336     }
337 
338     // loop over all render pass sets to make sure we destroy all the internal VkRenderPasses
339     for (int i = 0; i < fRenderPassArray.count(); ++i) {
340         fRenderPassArray[i].releaseResources(fGpu);
341     }
342     fRenderPassArray.reset();
343 
344     // Iterate through all store GrVkSamplers and unref them before resetting the hash.
345     SkTDynamicHash<GrVkSampler, uint16_t>::Iter iter(&fSamplers);
346     for (; !iter.done(); ++iter) {
347         (*iter).unref(fGpu);
348     }
349     fSamplers.reset();
350 
351     fPipelineStateCache->release();
352 
353     GR_VK_CALL(fGpu->vkInterface(), DestroyPipelineCache(fGpu->device(), fPipelineCache, nullptr));
354     fPipelineCache = VK_NULL_HANDLE;
355 
356     // We must release/destroy all command buffers and pipeline states before releasing the
357     // GrVkDescriptorSetManagers
358     for (int i = 0; i < fDescriptorSetManagers.count(); ++i) {
359         fDescriptorSetManagers[i].release(fGpu);
360     }
361     fDescriptorSetManagers.reset();
362 
363     // release our uniform buffers
364     for (int i = 0; i < fAvailableUniformBufferResources.count(); ++i) {
365         SkASSERT(fAvailableUniformBufferResources[i]->unique());
366         fAvailableUniformBufferResources[i]->unref(fGpu);
367     }
368     fAvailableUniformBufferResources.reset();
369 }
370 
abandonResources()371 void GrVkResourceProvider::abandonResources() {
372     // release our active command buffers
373     for (int i = 0; i < fActiveCommandBuffers.count(); ++i) {
374         SkASSERT(fActiveCommandBuffers[i]->finished(fGpu));
375         SkASSERT(fActiveCommandBuffers[i]->unique());
376         fActiveCommandBuffers[i]->unrefAndAbandon();
377     }
378     fActiveCommandBuffers.reset();
379     // release our available command buffers
380     for (int i = 0; i < fAvailableCommandBuffers.count(); ++i) {
381         SkASSERT(fAvailableCommandBuffers[i]->finished(fGpu));
382         SkASSERT(fAvailableCommandBuffers[i]->unique());
383         fAvailableCommandBuffers[i]->unrefAndAbandon();
384     }
385     fAvailableCommandBuffers.reset();
386 
387     // release our available secondary command buffers
388     for (int i = 0; i < fAvailableSecondaryCommandBuffers.count(); ++i) {
389         SkASSERT(fAvailableSecondaryCommandBuffers[i]->unique());
390         fAvailableSecondaryCommandBuffers[i]->unrefAndAbandon();
391     }
392     fAvailableSecondaryCommandBuffers.reset();
393 
394     // Abandon all copy pipelines
395     for (int i = 0; i < fCopyPipelines.count(); ++i) {
396         fCopyPipelines[i]->unrefAndAbandon();
397     }
398 
399     // loop over all render pass sets to make sure we destroy all the internal VkRenderPasses
400     for (int i = 0; i < fRenderPassArray.count(); ++i) {
401         fRenderPassArray[i].abandonResources();
402     }
403     fRenderPassArray.reset();
404 
405     // Iterate through all store GrVkSamplers and unrefAndAbandon them before resetting the hash.
406     SkTDynamicHash<GrVkSampler, uint16_t>::Iter iter(&fSamplers);
407     for (; !iter.done(); ++iter) {
408         (*iter).unrefAndAbandon();
409     }
410     fSamplers.reset();
411 
412     fPipelineStateCache->abandon();
413 
414     fPipelineCache = VK_NULL_HANDLE;
415 
416     // We must abandon all command buffers and pipeline states before abandoning the
417     // GrVkDescriptorSetManagers
418     for (int i = 0; i < fDescriptorSetManagers.count(); ++i) {
419         fDescriptorSetManagers[i].abandon();
420     }
421     fDescriptorSetManagers.reset();
422 
423     // release our uniform buffers
424     for (int i = 0; i < fAvailableUniformBufferResources.count(); ++i) {
425         SkASSERT(fAvailableUniformBufferResources[i]->unique());
426         fAvailableUniformBufferResources[i]->unrefAndAbandon();
427     }
428     fAvailableUniformBufferResources.reset();
429 }
430 
431 ////////////////////////////////////////////////////////////////////////////////
432 
CompatibleRenderPassSet(const GrVkGpu * gpu,const GrVkRenderTarget & target)433 GrVkResourceProvider::CompatibleRenderPassSet::CompatibleRenderPassSet(
434                                                                      const GrVkGpu* gpu,
435                                                                      const GrVkRenderTarget& target)
436     : fLastReturnedIndex(0) {
437     fRenderPasses.emplace_back(new GrVkRenderPass());
438     fRenderPasses[0]->initSimple(gpu, target);
439 }
440 
isCompatible(const GrVkRenderTarget & target) const441 bool GrVkResourceProvider::CompatibleRenderPassSet::isCompatible(
442                                                              const GrVkRenderTarget& target) const {
443     // The first GrVkRenderpass should always exists since we create the basic load store
444     // render pass on create
445     SkASSERT(fRenderPasses[0]);
446     return fRenderPasses[0]->isCompatible(target);
447 }
448 
getRenderPass(const GrVkGpu * gpu,const GrVkRenderPass::LoadStoreOps & colorOps,const GrVkRenderPass::LoadStoreOps & stencilOps)449 GrVkRenderPass* GrVkResourceProvider::CompatibleRenderPassSet::getRenderPass(
450                                                    const GrVkGpu* gpu,
451                                                    const GrVkRenderPass::LoadStoreOps& colorOps,
452                                                    const GrVkRenderPass::LoadStoreOps& stencilOps) {
453     for (int i = 0; i < fRenderPasses.count(); ++i) {
454         int idx = (i + fLastReturnedIndex) % fRenderPasses.count();
455         if (fRenderPasses[idx]->equalLoadStoreOps(colorOps, stencilOps)) {
456             fLastReturnedIndex = idx;
457             return fRenderPasses[idx];
458         }
459     }
460     GrVkRenderPass* renderPass = fRenderPasses.emplace_back(new GrVkRenderPass());
461     renderPass->init(gpu, *this->getCompatibleRenderPass(), colorOps, stencilOps);
462     fLastReturnedIndex = fRenderPasses.count() - 1;
463     return renderPass;
464 }
465 
releaseResources(const GrVkGpu * gpu)466 void GrVkResourceProvider::CompatibleRenderPassSet::releaseResources(const GrVkGpu* gpu) {
467     for (int i = 0; i < fRenderPasses.count(); ++i) {
468         if (fRenderPasses[i]) {
469             fRenderPasses[i]->unref(gpu);
470             fRenderPasses[i] = nullptr;
471         }
472     }
473 }
474 
abandonResources()475 void GrVkResourceProvider::CompatibleRenderPassSet::abandonResources() {
476     for (int i = 0; i < fRenderPasses.count(); ++i) {
477         if (fRenderPasses[i]) {
478             fRenderPasses[i]->unrefAndAbandon();
479             fRenderPasses[i] = nullptr;
480         }
481     }
482 }
483