• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 * Copyright 2015 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/GrVkCommandBuffer.h"
9 
10 #include "include/core/SkRect.h"
11 #include "src/gpu/vk/GrVkCommandPool.h"
12 #include "src/gpu/vk/GrVkFramebuffer.h"
13 #include "src/gpu/vk/GrVkGpu.h"
14 #include "src/gpu/vk/GrVkImage.h"
15 #include "src/gpu/vk/GrVkImageView.h"
16 #include "src/gpu/vk/GrVkIndexBuffer.h"
17 #include "src/gpu/vk/GrVkPipeline.h"
18 #include "src/gpu/vk/GrVkPipelineState.h"
19 #include "src/gpu/vk/GrVkPipelineState.h"
20 #include "src/gpu/vk/GrVkRenderPass.h"
21 #include "src/gpu/vk/GrVkRenderTarget.h"
22 #include "src/gpu/vk/GrVkTransferBuffer.h"
23 #include "src/gpu/vk/GrVkUtil.h"
24 #include "src/gpu/vk/GrVkVertexBuffer.h"
25 
invalidateState()26 void GrVkCommandBuffer::invalidateState() {
27     for (auto& boundInputBuffer : fBoundInputBuffers) {
28         boundInputBuffer = VK_NULL_HANDLE;
29     }
30     fBoundIndexBuffer = VK_NULL_HANDLE;
31 
32     memset(&fCachedViewport, 0, sizeof(VkViewport));
33     fCachedViewport.width = - 1.0f; // Viewport must have a width greater than 0
34 
35     memset(&fCachedScissor, 0, sizeof(VkRect2D));
36     fCachedScissor.offset.x = -1; // Scissor offset must be greater that 0 to be valid
37 
38     for (int i = 0; i < 4; ++i) {
39         fCachedBlendConstant[i] = -1.0;
40     }
41 }
42 
freeGPUData(GrVkGpu * gpu) const43 void GrVkCommandBuffer::freeGPUData(GrVkGpu* gpu) const {
44     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
45     SkASSERT(!fIsActive);
46     for (int i = 0; i < fTrackedResources.count(); ++i) {
47         fTrackedResources[i]->notifyRemovedFromCommandBuffer();
48         fTrackedResources[i]->unref(gpu);
49     }
50 
51     for (int i = 0; i < fTrackedRecycledResources.count(); ++i) {
52         fTrackedRecycledResources[i]->notifyRemovedFromCommandBuffer();
53         fTrackedRecycledResources[i]->recycle(const_cast<GrVkGpu*>(gpu));
54     }
55 
56     if (!this->isWrapped()) {
57         GR_VK_CALL(gpu->vkInterface(), FreeCommandBuffers(gpu->device(), fCmdPool->vkCommandPool(),
58                                                           1, &fCmdBuffer));
59     }
60 
61     this->onFreeGPUData(gpu);
62 }
63 
abandonGPUData() const64 void GrVkCommandBuffer::abandonGPUData() const {
65     SkDEBUGCODE(fResourcesReleased = true;)
66     for (int i = 0; i < fTrackedResources.count(); ++i) {
67         fTrackedResources[i]->notifyRemovedFromCommandBuffer();
68         fTrackedResources[i]->unrefAndAbandon();
69     }
70 
71     for (int i = 0; i < fTrackedRecycledResources.count(); ++i) {
72         fTrackedRecycledResources[i]->notifyRemovedFromCommandBuffer();
73         // We don't recycle resources when abandoning them.
74         fTrackedRecycledResources[i]->unrefAndAbandon();
75     }
76 
77     this->onAbandonGPUData();
78 }
79 
releaseResources(GrVkGpu * gpu)80 void GrVkCommandBuffer::releaseResources(GrVkGpu* gpu) {
81     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
82     SkDEBUGCODE(fResourcesReleased = true;)
83     SkASSERT(!fIsActive);
84     for (int i = 0; i < fTrackedResources.count(); ++i) {
85         fTrackedResources[i]->notifyRemovedFromCommandBuffer();
86         fTrackedResources[i]->unref(gpu);
87     }
88     for (int i = 0; i < fTrackedRecycledResources.count(); ++i) {
89         fTrackedRecycledResources[i]->notifyRemovedFromCommandBuffer();
90         fTrackedRecycledResources[i]->recycle(const_cast<GrVkGpu*>(gpu));
91     }
92 
93     if (++fNumResets > kNumRewindResetsBeforeFullReset) {
94         fTrackedResources.reset();
95         fTrackedRecycledResources.reset();
96         fTrackedResources.setReserve(kInitialTrackedResourcesCount);
97         fTrackedRecycledResources.setReserve(kInitialTrackedResourcesCount);
98         fNumResets = 0;
99     } else {
100         fTrackedResources.rewind();
101         fTrackedRecycledResources.rewind();
102     }
103 
104     this->invalidateState();
105 
106     this->onReleaseResources(gpu);
107 }
108 
109 ////////////////////////////////////////////////////////////////////////////////
110 // CommandBuffer commands
111 ////////////////////////////////////////////////////////////////////////////////
112 
pipelineBarrier(const GrVkGpu * gpu,const GrVkResource * resource,VkPipelineStageFlags srcStageMask,VkPipelineStageFlags dstStageMask,bool byRegion,BarrierType barrierType,void * barrier)113 void GrVkCommandBuffer::pipelineBarrier(const GrVkGpu* gpu,
114                                         const GrVkResource* resource,
115                                         VkPipelineStageFlags srcStageMask,
116                                         VkPipelineStageFlags dstStageMask,
117                                         bool byRegion,
118                                         BarrierType barrierType,
119                                         void* barrier) {
120     SkASSERT(!this->isWrapped());
121     SkASSERT(fIsActive);
122     // For images we can have barriers inside of render passes but they require us to add more
123     // support in subpasses which need self dependencies to have barriers inside them. Also, we can
124     // never have buffer barriers inside of a render pass. For now we will just assert that we are
125     // not in a render pass.
126     SkASSERT(!fActiveRenderPass);
127 
128     if (barrierType == kBufferMemory_BarrierType) {
129         const VkBufferMemoryBarrier* barrierPtr = reinterpret_cast<VkBufferMemoryBarrier*>(barrier);
130         fBufferBarriers.push_back(*barrierPtr);
131     } else {
132         SkASSERT(barrierType == kImageMemory_BarrierType);
133         const VkImageMemoryBarrier* barrierPtr = reinterpret_cast<VkImageMemoryBarrier*>(barrier);
134         // We need to check if we are adding a pipeline barrier that covers part of the same
135         // subresource range as a barrier that is already in current batch. If it does, then we must
136         // submit the first batch because the vulkan spec does not define a specific ordering for
137         // barriers submitted in the same batch.
138         // TODO: Look if we can gain anything by merging barriers together instead of submitting
139         // the old ones.
140         for (int i = 0; i < fImageBarriers.count(); ++i) {
141             VkImageMemoryBarrier& currentBarrier = fImageBarriers[i];
142             if (barrierPtr->image == currentBarrier.image) {
143                 const VkImageSubresourceRange newRange = barrierPtr->subresourceRange;
144                 const VkImageSubresourceRange oldRange = currentBarrier.subresourceRange;
145                 SkASSERT(newRange.aspectMask == oldRange.aspectMask);
146                 SkASSERT(newRange.baseArrayLayer == oldRange.baseArrayLayer);
147                 SkASSERT(newRange.layerCount == oldRange.layerCount);
148                 uint32_t newStart = newRange.baseMipLevel;
149                 uint32_t newEnd = newRange.baseMipLevel + newRange.levelCount - 1;
150                 uint32_t oldStart = oldRange.baseMipLevel;
151                 uint32_t oldEnd = oldRange.baseMipLevel + oldRange.levelCount - 1;
152                 if (SkTMax(newStart, oldStart) <= SkTMin(newEnd, oldEnd)) {
153                     this->submitPipelineBarriers(gpu);
154                     break;
155                 }
156             }
157         }
158         fImageBarriers.push_back(*barrierPtr);
159     }
160     fBarriersByRegion |= byRegion;
161 
162     fSrcStageMask = fSrcStageMask | srcStageMask;
163     fDstStageMask = fDstStageMask | dstStageMask;
164 
165     fHasWork = true;
166     if (resource) {
167         this->addResource(resource);
168     }
169 }
170 
submitPipelineBarriers(const GrVkGpu * gpu)171 void GrVkCommandBuffer::submitPipelineBarriers(const GrVkGpu* gpu) {
172     SkASSERT(fIsActive);
173 
174     // Currently we never submit a pipeline barrier without at least one memory barrier.
175     if (fBufferBarriers.count() || fImageBarriers.count()) {
176         // For images we can have barriers inside of render passes but they require us to add more
177         // support in subpasses which need self dependencies to have barriers inside them. Also, we
178         // can never have buffer barriers inside of a render pass. For now we will just assert that
179         // we are not in a render pass.
180         SkASSERT(!fActiveRenderPass);
181         SkASSERT(!this->isWrapped());
182         SkASSERT(fSrcStageMask && fDstStageMask);
183 
184         VkDependencyFlags dependencyFlags = fBarriersByRegion ? VK_DEPENDENCY_BY_REGION_BIT : 0;
185         GR_VK_CALL(gpu->vkInterface(), CmdPipelineBarrier(
186                 fCmdBuffer, fSrcStageMask, fDstStageMask, dependencyFlags, 0, nullptr,
187                 fBufferBarriers.count(), fBufferBarriers.begin(),
188                 fImageBarriers.count(), fImageBarriers.begin()));
189         fBufferBarriers.reset();
190         fImageBarriers.reset();
191         fBarriersByRegion = false;
192         fSrcStageMask = 0;
193         fDstStageMask = 0;
194     }
195     SkASSERT(!fBufferBarriers.count());
196     SkASSERT(!fImageBarriers.count());
197     SkASSERT(!fBarriersByRegion);
198     SkASSERT(!fSrcStageMask);
199     SkASSERT(!fDstStageMask);
200 }
201 
202 
bindInputBuffer(GrVkGpu * gpu,uint32_t binding,const GrVkVertexBuffer * vbuffer)203 void GrVkCommandBuffer::bindInputBuffer(GrVkGpu* gpu, uint32_t binding,
204                                         const GrVkVertexBuffer* vbuffer) {
205     VkBuffer vkBuffer = vbuffer->buffer();
206     SkASSERT(VK_NULL_HANDLE != vkBuffer);
207     SkASSERT(binding < kMaxInputBuffers);
208     // TODO: once vbuffer->offset() no longer always returns 0, we will need to track the offset
209     // to know if we can skip binding or not.
210     if (vkBuffer != fBoundInputBuffers[binding]) {
211         VkDeviceSize offset = vbuffer->offset();
212         GR_VK_CALL(gpu->vkInterface(), CmdBindVertexBuffers(fCmdBuffer,
213                                                             binding,
214                                                             1,
215                                                             &vkBuffer,
216                                                             &offset));
217         fBoundInputBuffers[binding] = vkBuffer;
218         this->addResource(vbuffer->resource());
219     }
220 }
221 
bindIndexBuffer(GrVkGpu * gpu,const GrVkIndexBuffer * ibuffer)222 void GrVkCommandBuffer::bindIndexBuffer(GrVkGpu* gpu, const GrVkIndexBuffer* ibuffer) {
223     VkBuffer vkBuffer = ibuffer->buffer();
224     SkASSERT(VK_NULL_HANDLE != vkBuffer);
225     // TODO: once ibuffer->offset() no longer always returns 0, we will need to track the offset
226     // to know if we can skip binding or not.
227     if (vkBuffer != fBoundIndexBuffer) {
228         GR_VK_CALL(gpu->vkInterface(), CmdBindIndexBuffer(fCmdBuffer,
229                                                           vkBuffer,
230                                                           ibuffer->offset(),
231                                                           VK_INDEX_TYPE_UINT16));
232         fBoundIndexBuffer = vkBuffer;
233         this->addResource(ibuffer->resource());
234     }
235 }
236 
clearAttachments(const GrVkGpu * gpu,int numAttachments,const VkClearAttachment * attachments,int numRects,const VkClearRect * clearRects)237 void GrVkCommandBuffer::clearAttachments(const GrVkGpu* gpu,
238                                          int numAttachments,
239                                          const VkClearAttachment* attachments,
240                                          int numRects,
241                                          const VkClearRect* clearRects) {
242     SkASSERT(fIsActive);
243     SkASSERT(fActiveRenderPass);
244     SkASSERT(numAttachments > 0);
245     SkASSERT(numRects > 0);
246 
247     this->addingWork(gpu);
248 
249 #ifdef SK_DEBUG
250     for (int i = 0; i < numAttachments; ++i) {
251         if (attachments[i].aspectMask == VK_IMAGE_ASPECT_COLOR_BIT) {
252             uint32_t testIndex;
253             SkAssertResult(fActiveRenderPass->colorAttachmentIndex(&testIndex));
254             SkASSERT(testIndex == attachments[i].colorAttachment);
255         }
256     }
257 #endif
258     GR_VK_CALL(gpu->vkInterface(), CmdClearAttachments(fCmdBuffer,
259                                                        numAttachments,
260                                                        attachments,
261                                                        numRects,
262                                                        clearRects));
263 }
264 
bindDescriptorSets(const GrVkGpu * gpu,GrVkPipelineState * pipelineState,VkPipelineLayout layout,uint32_t firstSet,uint32_t setCount,const VkDescriptorSet * descriptorSets,uint32_t dynamicOffsetCount,const uint32_t * dynamicOffsets)265 void GrVkCommandBuffer::bindDescriptorSets(const GrVkGpu* gpu,
266                                            GrVkPipelineState* pipelineState,
267                                            VkPipelineLayout layout,
268                                            uint32_t firstSet,
269                                            uint32_t setCount,
270                                            const VkDescriptorSet* descriptorSets,
271                                            uint32_t dynamicOffsetCount,
272                                            const uint32_t* dynamicOffsets) {
273     SkASSERT(fIsActive);
274     GR_VK_CALL(gpu->vkInterface(), CmdBindDescriptorSets(fCmdBuffer,
275                                                          VK_PIPELINE_BIND_POINT_GRAPHICS,
276                                                          layout,
277                                                          firstSet,
278                                                          setCount,
279                                                          descriptorSets,
280                                                          dynamicOffsetCount,
281                                                          dynamicOffsets));
282 }
283 
bindPipeline(const GrVkGpu * gpu,const GrVkPipeline * pipeline)284 void GrVkCommandBuffer::bindPipeline(const GrVkGpu* gpu, const GrVkPipeline* pipeline) {
285     SkASSERT(fIsActive);
286     GR_VK_CALL(gpu->vkInterface(), CmdBindPipeline(fCmdBuffer,
287                                                    VK_PIPELINE_BIND_POINT_GRAPHICS,
288                                                    pipeline->pipeline()));
289     this->addResource(pipeline);
290 }
291 
drawIndexed(const GrVkGpu * gpu,uint32_t indexCount,uint32_t instanceCount,uint32_t firstIndex,int32_t vertexOffset,uint32_t firstInstance)292 void GrVkCommandBuffer::drawIndexed(const GrVkGpu* gpu,
293                                     uint32_t indexCount,
294                                     uint32_t instanceCount,
295                                     uint32_t firstIndex,
296                                     int32_t vertexOffset,
297                                     uint32_t firstInstance) {
298     SkASSERT(fIsActive);
299     SkASSERT(fActiveRenderPass);
300     this->addingWork(gpu);
301     GR_VK_CALL(gpu->vkInterface(), CmdDrawIndexed(fCmdBuffer,
302                                                   indexCount,
303                                                   instanceCount,
304                                                   firstIndex,
305                                                   vertexOffset,
306                                                   firstInstance));
307 }
308 
draw(const GrVkGpu * gpu,uint32_t vertexCount,uint32_t instanceCount,uint32_t firstVertex,uint32_t firstInstance)309 void GrVkCommandBuffer::draw(const GrVkGpu* gpu,
310                              uint32_t vertexCount,
311                              uint32_t instanceCount,
312                              uint32_t firstVertex,
313                              uint32_t firstInstance) {
314     SkASSERT(fIsActive);
315     SkASSERT(fActiveRenderPass);
316     this->addingWork(gpu);
317     GR_VK_CALL(gpu->vkInterface(), CmdDraw(fCmdBuffer,
318                                            vertexCount,
319                                            instanceCount,
320                                            firstVertex,
321                                            firstInstance));
322 }
323 
setViewport(const GrVkGpu * gpu,uint32_t firstViewport,uint32_t viewportCount,const VkViewport * viewports)324 void GrVkCommandBuffer::setViewport(const GrVkGpu* gpu,
325                                     uint32_t firstViewport,
326                                     uint32_t viewportCount,
327                                     const VkViewport* viewports) {
328     SkASSERT(fIsActive);
329     SkASSERT(1 == viewportCount);
330     if (memcmp(viewports, &fCachedViewport, sizeof(VkViewport))) {
331         GR_VK_CALL(gpu->vkInterface(), CmdSetViewport(fCmdBuffer,
332                                                       firstViewport,
333                                                       viewportCount,
334                                                       viewports));
335         fCachedViewport = viewports[0];
336     }
337 }
338 
setScissor(const GrVkGpu * gpu,uint32_t firstScissor,uint32_t scissorCount,const VkRect2D * scissors)339 void GrVkCommandBuffer::setScissor(const GrVkGpu* gpu,
340                                    uint32_t firstScissor,
341                                    uint32_t scissorCount,
342                                    const VkRect2D* scissors) {
343     SkASSERT(fIsActive);
344     SkASSERT(1 == scissorCount);
345     if (memcmp(scissors, &fCachedScissor, sizeof(VkRect2D))) {
346         GR_VK_CALL(gpu->vkInterface(), CmdSetScissor(fCmdBuffer,
347                                                      firstScissor,
348                                                      scissorCount,
349                                                      scissors));
350         fCachedScissor = scissors[0];
351     }
352 }
353 
setBlendConstants(const GrVkGpu * gpu,const float blendConstants[4])354 void GrVkCommandBuffer::setBlendConstants(const GrVkGpu* gpu,
355                                           const float blendConstants[4]) {
356     SkASSERT(fIsActive);
357     if (memcmp(blendConstants, fCachedBlendConstant, 4 * sizeof(float))) {
358         GR_VK_CALL(gpu->vkInterface(), CmdSetBlendConstants(fCmdBuffer, blendConstants));
359         memcpy(fCachedBlendConstant, blendConstants, 4 * sizeof(float));
360     }
361 }
362 
addingWork(const GrVkGpu * gpu)363 void GrVkCommandBuffer::addingWork(const GrVkGpu* gpu) {
364     this->submitPipelineBarriers(gpu);
365     fHasWork = true;
366 }
367 
368 ///////////////////////////////////////////////////////////////////////////////
369 // PrimaryCommandBuffer
370 ////////////////////////////////////////////////////////////////////////////////
~GrVkPrimaryCommandBuffer()371 GrVkPrimaryCommandBuffer::~GrVkPrimaryCommandBuffer() {
372     // Should have ended any render pass we're in the middle of
373     SkASSERT(!fActiveRenderPass);
374 }
375 
Create(const GrVkGpu * gpu,GrVkCommandPool * cmdPool)376 GrVkPrimaryCommandBuffer* GrVkPrimaryCommandBuffer::Create(const GrVkGpu* gpu,
377                                                            GrVkCommandPool* cmdPool) {
378     const VkCommandBufferAllocateInfo cmdInfo = {
379         VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,   // sType
380         nullptr,                                          // pNext
381         cmdPool->vkCommandPool(),                         // commandPool
382         VK_COMMAND_BUFFER_LEVEL_PRIMARY,                  // level
383         1                                                 // bufferCount
384     };
385 
386     VkCommandBuffer cmdBuffer;
387     VkResult err = GR_VK_CALL(gpu->vkInterface(), AllocateCommandBuffers(gpu->device(),
388                                                                          &cmdInfo,
389                                                                          &cmdBuffer));
390     if (err) {
391         return nullptr;
392     }
393     return new GrVkPrimaryCommandBuffer(cmdBuffer, cmdPool);
394 }
395 
begin(const GrVkGpu * gpu)396 void GrVkPrimaryCommandBuffer::begin(const GrVkGpu* gpu) {
397     SkASSERT(!fIsActive);
398     VkCommandBufferBeginInfo cmdBufferBeginInfo;
399     memset(&cmdBufferBeginInfo, 0, sizeof(VkCommandBufferBeginInfo));
400     cmdBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
401     cmdBufferBeginInfo.pNext = nullptr;
402     cmdBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
403     cmdBufferBeginInfo.pInheritanceInfo = nullptr;
404 
405     GR_VK_CALL_ERRCHECK(gpu->vkInterface(), BeginCommandBuffer(fCmdBuffer,
406                                                                &cmdBufferBeginInfo));
407     fIsActive = true;
408 }
409 
end(GrVkGpu * gpu)410 void GrVkPrimaryCommandBuffer::end(GrVkGpu* gpu) {
411     SkASSERT(fIsActive);
412     SkASSERT(!fActiveRenderPass);
413 
414     this->submitPipelineBarriers(gpu);
415 
416     GR_VK_CALL_ERRCHECK(gpu->vkInterface(), EndCommandBuffer(fCmdBuffer));
417     this->invalidateState();
418     fIsActive = false;
419     fHasWork = false;
420 }
421 
beginRenderPass(const GrVkGpu * gpu,const GrVkRenderPass * renderPass,const VkClearValue clearValues[],const GrVkRenderTarget & target,const SkIRect & bounds,bool forSecondaryCB)422 void GrVkPrimaryCommandBuffer::beginRenderPass(const GrVkGpu* gpu,
423                                                const GrVkRenderPass* renderPass,
424                                                const VkClearValue clearValues[],
425                                                const GrVkRenderTarget& target,
426                                                const SkIRect& bounds,
427                                                bool forSecondaryCB) {
428     SkASSERT(fIsActive);
429     SkASSERT(!fActiveRenderPass);
430     SkASSERT(renderPass->isCompatible(target));
431 
432     this->addingWork(gpu);
433 
434     VkRenderPassBeginInfo beginInfo;
435     VkRect2D renderArea;
436     renderArea.offset = { bounds.fLeft , bounds.fTop };
437     renderArea.extent = { (uint32_t)bounds.width(), (uint32_t)bounds.height() };
438 
439     memset(&beginInfo, 0, sizeof(VkRenderPassBeginInfo));
440     beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
441     beginInfo.pNext = nullptr;
442     beginInfo.renderPass = renderPass->vkRenderPass();
443     beginInfo.framebuffer = target.framebuffer()->framebuffer();
444     beginInfo.renderArea = renderArea;
445     beginInfo.clearValueCount = renderPass->clearValueCount();
446     beginInfo.pClearValues = clearValues;
447 
448     VkSubpassContents contents = forSecondaryCB ? VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS
449                                                 : VK_SUBPASS_CONTENTS_INLINE;
450 
451     GR_VK_CALL(gpu->vkInterface(), CmdBeginRenderPass(fCmdBuffer, &beginInfo, contents));
452     fActiveRenderPass = renderPass;
453     this->addResource(renderPass);
454     target.addResources(*this);
455 }
456 
endRenderPass(const GrVkGpu * gpu)457 void GrVkPrimaryCommandBuffer::endRenderPass(const GrVkGpu* gpu) {
458     SkASSERT(fIsActive);
459     SkASSERT(fActiveRenderPass);
460     this->addingWork(gpu);
461     GR_VK_CALL(gpu->vkInterface(), CmdEndRenderPass(fCmdBuffer));
462     fActiveRenderPass = nullptr;
463 }
464 
executeCommands(const GrVkGpu * gpu,std::unique_ptr<GrVkSecondaryCommandBuffer> buffer)465 void GrVkPrimaryCommandBuffer::executeCommands(const GrVkGpu* gpu,
466                                                std::unique_ptr<GrVkSecondaryCommandBuffer> buffer) {
467     // The Vulkan spec allows secondary command buffers to be executed on a primary command buffer
468     // if the command pools both were created from were created with the same queue family. However,
469     // we currently always create them from the same pool.
470     SkASSERT(buffer->commandPool() == fCmdPool);
471     SkASSERT(fIsActive);
472     SkASSERT(!buffer->fIsActive);
473     SkASSERT(fActiveRenderPass);
474     SkASSERT(fActiveRenderPass->isCompatible(*buffer->fActiveRenderPass));
475 
476     this->addingWork(gpu);
477 
478     GR_VK_CALL(gpu->vkInterface(), CmdExecuteCommands(fCmdBuffer, 1, &buffer->fCmdBuffer));
479     fSecondaryCommandBuffers.push_back(std::move(buffer));
480     // When executing a secondary command buffer all state (besides render pass state) becomes
481     // invalidated and must be reset. This includes bound buffers, pipelines, dynamic state, etc.
482     this->invalidateState();
483 }
484 
submit_to_queue(const GrVkInterface * interface,VkQueue queue,VkFence fence,uint32_t waitCount,const VkSemaphore * waitSemaphores,const VkPipelineStageFlags * waitStages,uint32_t commandBufferCount,const VkCommandBuffer * commandBuffers,uint32_t signalCount,const VkSemaphore * signalSemaphores,GrProtected protectedContext)485 static void submit_to_queue(const GrVkInterface* interface,
486                             VkQueue queue,
487                             VkFence fence,
488                             uint32_t waitCount,
489                             const VkSemaphore* waitSemaphores,
490                             const VkPipelineStageFlags* waitStages,
491                             uint32_t commandBufferCount,
492                             const VkCommandBuffer* commandBuffers,
493                             uint32_t signalCount,
494                             const VkSemaphore* signalSemaphores,
495                             GrProtected protectedContext) {
496     VkProtectedSubmitInfo protectedSubmitInfo;
497     if (protectedContext == GrProtected::kYes) {
498         memset(&protectedSubmitInfo, 0, sizeof(VkProtectedSubmitInfo));
499         protectedSubmitInfo.sType = VK_STRUCTURE_TYPE_PROTECTED_SUBMIT_INFO;
500         protectedSubmitInfo.pNext = nullptr;
501         protectedSubmitInfo.protectedSubmit = VK_TRUE;
502     }
503 
504     VkSubmitInfo submitInfo;
505     memset(&submitInfo, 0, sizeof(VkSubmitInfo));
506     submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
507     submitInfo.pNext = protectedContext == GrProtected::kYes ? &protectedSubmitInfo : nullptr;
508     submitInfo.waitSemaphoreCount = waitCount;
509     submitInfo.pWaitSemaphores = waitSemaphores;
510     submitInfo.pWaitDstStageMask = waitStages;
511     submitInfo.commandBufferCount = commandBufferCount;
512     submitInfo.pCommandBuffers = commandBuffers;
513     submitInfo.signalSemaphoreCount = signalCount;
514     submitInfo.pSignalSemaphores = signalSemaphores;
515     GR_VK_CALL_ERRCHECK(interface, QueueSubmit(queue, 1, &submitInfo, fence));
516 }
517 
submitToQueue(const GrVkGpu * gpu,VkQueue queue,GrVkGpu::SyncQueue sync,SkTArray<GrVkSemaphore::Resource * > & signalSemaphores,SkTArray<GrVkSemaphore::Resource * > & waitSemaphores)518 void GrVkPrimaryCommandBuffer::submitToQueue(
519         const GrVkGpu* gpu,
520         VkQueue queue,
521         GrVkGpu::SyncQueue sync,
522         SkTArray<GrVkSemaphore::Resource*>& signalSemaphores,
523         SkTArray<GrVkSemaphore::Resource*>& waitSemaphores) {
524     SkASSERT(!fIsActive);
525 
526     VkResult err;
527     if (VK_NULL_HANDLE == fSubmitFence) {
528         VkFenceCreateInfo fenceInfo;
529         memset(&fenceInfo, 0, sizeof(VkFenceCreateInfo));
530         fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
531         err = GR_VK_CALL(gpu->vkInterface(), CreateFence(gpu->device(), &fenceInfo, nullptr,
532                                                          &fSubmitFence));
533         SkASSERT(!err);
534     } else {
535         GR_VK_CALL(gpu->vkInterface(), ResetFences(gpu->device(), 1, &fSubmitFence));
536     }
537 
538     int signalCount = signalSemaphores.count();
539     int waitCount = waitSemaphores.count();
540 
541     if (0 == signalCount && 0 == waitCount) {
542         // This command buffer has no dependent semaphores so we can simply just submit it to the
543         // queue with no worries.
544         submit_to_queue(gpu->vkInterface(), queue, fSubmitFence, 0, nullptr, nullptr, 1,
545                         &fCmdBuffer, 0, nullptr,
546                         gpu->protectedContext() ? GrProtected::kYes : GrProtected::kNo);
547     } else {
548         SkTArray<VkSemaphore> vkSignalSems(signalCount);
549         for (int i = 0; i < signalCount; ++i) {
550             if (signalSemaphores[i]->shouldSignal()) {
551                 this->addResource(signalSemaphores[i]);
552                 vkSignalSems.push_back(signalSemaphores[i]->semaphore());
553             }
554         }
555 
556         SkTArray<VkSemaphore> vkWaitSems(waitCount);
557         SkTArray<VkPipelineStageFlags> vkWaitStages(waitCount);
558         for (int i = 0; i < waitCount; ++i) {
559             if (waitSemaphores[i]->shouldWait()) {
560                 this->addResource(waitSemaphores[i]);
561                 vkWaitSems.push_back(waitSemaphores[i]->semaphore());
562                 vkWaitStages.push_back(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
563             }
564         }
565         submit_to_queue(gpu->vkInterface(), queue, fSubmitFence, vkWaitSems.count(),
566                         vkWaitSems.begin(), vkWaitStages.begin(), 1, &fCmdBuffer,
567                         vkSignalSems.count(), vkSignalSems.begin(),
568                         gpu->protectedContext() ? GrProtected::kYes : GrProtected::kNo);
569         for (int i = 0; i < signalCount; ++i) {
570             signalSemaphores[i]->markAsSignaled();
571         }
572         for (int i = 0; i < waitCount; ++i) {
573             waitSemaphores[i]->markAsWaited();
574         }
575     }
576 
577     if (GrVkGpu::kForce_SyncQueue == sync) {
578         err = GR_VK_CALL(gpu->vkInterface(),
579                          WaitForFences(gpu->device(), 1, &fSubmitFence, true, UINT64_MAX));
580         if (VK_TIMEOUT == err) {
581             SkDebugf("Fence failed to signal: %d\n", err);
582             SK_ABORT("failing");
583         }
584         SkASSERT(!err);
585 
586         fFinishedProcs.reset();
587 
588         // Destroy the fence
589         GR_VK_CALL(gpu->vkInterface(), DestroyFence(gpu->device(), fSubmitFence, nullptr));
590         fSubmitFence = VK_NULL_HANDLE;
591     }
592 }
593 
finished(const GrVkGpu * gpu)594 bool GrVkPrimaryCommandBuffer::finished(const GrVkGpu* gpu) {
595     SkASSERT(!fIsActive);
596     if (VK_NULL_HANDLE == fSubmitFence) {
597         return true;
598     }
599 
600     VkResult err = GR_VK_CALL(gpu->vkInterface(), GetFenceStatus(gpu->device(), fSubmitFence));
601     switch (err) {
602         case VK_SUCCESS:
603             return true;
604 
605         case VK_NOT_READY:
606             return false;
607 
608         default:
609             SkDebugf("Error getting fence status: %d\n", err);
610             SK_ABORT("failing");
611             break;
612     }
613 
614     return false;
615 }
616 
addFinishedProc(sk_sp<GrRefCntedCallback> finishedProc)617 void GrVkPrimaryCommandBuffer::addFinishedProc(sk_sp<GrRefCntedCallback> finishedProc) {
618     fFinishedProcs.push_back(std::move(finishedProc));
619 }
620 
onReleaseResources(GrVkGpu * gpu)621 void GrVkPrimaryCommandBuffer::onReleaseResources(GrVkGpu* gpu) {
622     for (int i = 0; i < fSecondaryCommandBuffers.count(); ++i) {
623         fSecondaryCommandBuffers[i]->releaseResources(gpu);
624     }
625     fFinishedProcs.reset();
626 }
627 
recycleSecondaryCommandBuffers(GrVkGpu * gpu)628 void GrVkPrimaryCommandBuffer::recycleSecondaryCommandBuffers(GrVkGpu* gpu) {
629     for (int i = 0; i < fSecondaryCommandBuffers.count(); ++i) {
630         SkASSERT(fSecondaryCommandBuffers[i]->commandPool() == fCmdPool);
631         fSecondaryCommandBuffers[i].release()->recycle(gpu);
632     }
633     fSecondaryCommandBuffers.reset();
634 }
635 
copyImage(const GrVkGpu * gpu,GrVkImage * srcImage,VkImageLayout srcLayout,GrVkImage * dstImage,VkImageLayout dstLayout,uint32_t copyRegionCount,const VkImageCopy * copyRegions)636 void GrVkPrimaryCommandBuffer::copyImage(const GrVkGpu* gpu,
637                                          GrVkImage* srcImage,
638                                          VkImageLayout srcLayout,
639                                          GrVkImage* dstImage,
640                                          VkImageLayout dstLayout,
641                                          uint32_t copyRegionCount,
642                                          const VkImageCopy* copyRegions) {
643     SkASSERT(fIsActive);
644     SkASSERT(!fActiveRenderPass);
645     this->addingWork(gpu);
646     this->addResource(srcImage->resource());
647     this->addResource(dstImage->resource());
648     GR_VK_CALL(gpu->vkInterface(), CmdCopyImage(fCmdBuffer,
649                                                 srcImage->image(),
650                                                 srcLayout,
651                                                 dstImage->image(),
652                                                 dstLayout,
653                                                 copyRegionCount,
654                                                 copyRegions));
655 }
656 
blitImage(const GrVkGpu * gpu,const GrVkResource * srcResource,VkImage srcImage,VkImageLayout srcLayout,const GrVkResource * dstResource,VkImage dstImage,VkImageLayout dstLayout,uint32_t blitRegionCount,const VkImageBlit * blitRegions,VkFilter filter)657 void GrVkPrimaryCommandBuffer::blitImage(const GrVkGpu* gpu,
658                                          const GrVkResource* srcResource,
659                                          VkImage srcImage,
660                                          VkImageLayout srcLayout,
661                                          const GrVkResource* dstResource,
662                                          VkImage dstImage,
663                                          VkImageLayout dstLayout,
664                                          uint32_t blitRegionCount,
665                                          const VkImageBlit* blitRegions,
666                                          VkFilter filter) {
667     SkASSERT(fIsActive);
668     SkASSERT(!fActiveRenderPass);
669     this->addingWork(gpu);
670     this->addResource(srcResource);
671     this->addResource(dstResource);
672     GR_VK_CALL(gpu->vkInterface(), CmdBlitImage(fCmdBuffer,
673                                                 srcImage,
674                                                 srcLayout,
675                                                 dstImage,
676                                                 dstLayout,
677                                                 blitRegionCount,
678                                                 blitRegions,
679                                                 filter));
680 }
681 
blitImage(const GrVkGpu * gpu,const GrVkImage & srcImage,const GrVkImage & dstImage,uint32_t blitRegionCount,const VkImageBlit * blitRegions,VkFilter filter)682 void GrVkPrimaryCommandBuffer::blitImage(const GrVkGpu* gpu,
683                                          const GrVkImage& srcImage,
684                                          const GrVkImage& dstImage,
685                                          uint32_t blitRegionCount,
686                                          const VkImageBlit* blitRegions,
687                                          VkFilter filter) {
688     this->blitImage(gpu,
689                     srcImage.resource(),
690                     srcImage.image(),
691                     srcImage.currentLayout(),
692                     dstImage.resource(),
693                     dstImage.image(),
694                     dstImage.currentLayout(),
695                     blitRegionCount,
696                     blitRegions,
697                     filter);
698 }
699 
700 
copyImageToBuffer(const GrVkGpu * gpu,GrVkImage * srcImage,VkImageLayout srcLayout,GrVkTransferBuffer * dstBuffer,uint32_t copyRegionCount,const VkBufferImageCopy * copyRegions)701 void GrVkPrimaryCommandBuffer::copyImageToBuffer(const GrVkGpu* gpu,
702                                                  GrVkImage* srcImage,
703                                                  VkImageLayout srcLayout,
704                                                  GrVkTransferBuffer* dstBuffer,
705                                                  uint32_t copyRegionCount,
706                                                  const VkBufferImageCopy* copyRegions) {
707     SkASSERT(fIsActive);
708     SkASSERT(!fActiveRenderPass);
709     this->addingWork(gpu);
710     this->addResource(srcImage->resource());
711     this->addResource(dstBuffer->resource());
712     GR_VK_CALL(gpu->vkInterface(), CmdCopyImageToBuffer(fCmdBuffer,
713                                                         srcImage->image(),
714                                                         srcLayout,
715                                                         dstBuffer->buffer(),
716                                                         copyRegionCount,
717                                                         copyRegions));
718 }
719 
copyBufferToImage(const GrVkGpu * gpu,GrVkTransferBuffer * srcBuffer,GrVkImage * dstImage,VkImageLayout dstLayout,uint32_t copyRegionCount,const VkBufferImageCopy * copyRegions)720 void GrVkPrimaryCommandBuffer::copyBufferToImage(const GrVkGpu* gpu,
721                                                  GrVkTransferBuffer* srcBuffer,
722                                                  GrVkImage* dstImage,
723                                                  VkImageLayout dstLayout,
724                                                  uint32_t copyRegionCount,
725                                                  const VkBufferImageCopy* copyRegions) {
726     SkASSERT(fIsActive);
727     SkASSERT(!fActiveRenderPass);
728     this->addingWork(gpu);
729     this->addResource(srcBuffer->resource());
730     this->addResource(dstImage->resource());
731     GR_VK_CALL(gpu->vkInterface(), CmdCopyBufferToImage(fCmdBuffer,
732                                                         srcBuffer->buffer(),
733                                                         dstImage->image(),
734                                                         dstLayout,
735                                                         copyRegionCount,
736                                                         copyRegions));
737 }
738 
739 
copyBuffer(GrVkGpu * gpu,GrVkBuffer * srcBuffer,GrVkBuffer * dstBuffer,uint32_t regionCount,const VkBufferCopy * regions)740 void GrVkPrimaryCommandBuffer::copyBuffer(GrVkGpu* gpu,
741                                           GrVkBuffer* srcBuffer,
742                                           GrVkBuffer* dstBuffer,
743                                           uint32_t regionCount,
744                                           const VkBufferCopy* regions) {
745     SkASSERT(fIsActive);
746     SkASSERT(!fActiveRenderPass);
747     this->addingWork(gpu);
748 #ifdef SK_DEBUG
749     for (uint32_t i = 0; i < regionCount; ++i) {
750         const VkBufferCopy& region = regions[i];
751         SkASSERT(region.size > 0);
752         SkASSERT(region.srcOffset < srcBuffer->size());
753         SkASSERT(region.dstOffset < dstBuffer->size());
754         SkASSERT(region.srcOffset + region.size <= srcBuffer->size());
755         SkASSERT(region.dstOffset + region.size <= dstBuffer->size());
756     }
757 #endif
758     this->addResource(srcBuffer->resource());
759     this->addResource(dstBuffer->resource());
760     GR_VK_CALL(gpu->vkInterface(), CmdCopyBuffer(fCmdBuffer,
761                                                  srcBuffer->buffer(),
762                                                  dstBuffer->buffer(),
763                                                  regionCount,
764                                                  regions));
765 }
766 
updateBuffer(GrVkGpu * gpu,GrVkBuffer * dstBuffer,VkDeviceSize dstOffset,VkDeviceSize dataSize,const void * data)767 void GrVkPrimaryCommandBuffer::updateBuffer(GrVkGpu* gpu,
768                                             GrVkBuffer* dstBuffer,
769                                             VkDeviceSize dstOffset,
770                                             VkDeviceSize dataSize,
771                                             const void* data) {
772     SkASSERT(fIsActive);
773     SkASSERT(!fActiveRenderPass);
774     SkASSERT(0 == (dstOffset & 0x03));   // four byte aligned
775     // TODO: handle larger transfer sizes
776     SkASSERT(dataSize <= 65536);
777     SkASSERT(0 == (dataSize & 0x03));    // four byte aligned
778     this->addingWork(gpu);
779     this->addResource(dstBuffer->resource());
780     GR_VK_CALL(gpu->vkInterface(), CmdUpdateBuffer(fCmdBuffer,
781                                                    dstBuffer->buffer(),
782                                                    dstOffset,
783                                                    dataSize,
784                                                    (const uint32_t*) data));
785 }
786 
clearColorImage(const GrVkGpu * gpu,GrVkImage * image,const VkClearColorValue * color,uint32_t subRangeCount,const VkImageSubresourceRange * subRanges)787 void GrVkPrimaryCommandBuffer::clearColorImage(const GrVkGpu* gpu,
788                                                GrVkImage* image,
789                                                const VkClearColorValue* color,
790                                                uint32_t subRangeCount,
791                                                const VkImageSubresourceRange* subRanges) {
792     SkASSERT(fIsActive);
793     SkASSERT(!fActiveRenderPass);
794     this->addingWork(gpu);
795     this->addResource(image->resource());
796     GR_VK_CALL(gpu->vkInterface(), CmdClearColorImage(fCmdBuffer,
797                                                       image->image(),
798                                                       image->currentLayout(),
799                                                       color,
800                                                       subRangeCount,
801                                                       subRanges));
802 }
803 
clearDepthStencilImage(const GrVkGpu * gpu,GrVkImage * image,const VkClearDepthStencilValue * color,uint32_t subRangeCount,const VkImageSubresourceRange * subRanges)804 void GrVkPrimaryCommandBuffer::clearDepthStencilImage(const GrVkGpu* gpu,
805                                                       GrVkImage* image,
806                                                       const VkClearDepthStencilValue* color,
807                                                       uint32_t subRangeCount,
808                                                       const VkImageSubresourceRange* subRanges) {
809     SkASSERT(fIsActive);
810     SkASSERT(!fActiveRenderPass);
811     this->addingWork(gpu);
812     this->addResource(image->resource());
813     GR_VK_CALL(gpu->vkInterface(), CmdClearDepthStencilImage(fCmdBuffer,
814                                                              image->image(),
815                                                              image->currentLayout(),
816                                                              color,
817                                                              subRangeCount,
818                                                              subRanges));
819 }
820 
resolveImage(GrVkGpu * gpu,const GrVkImage & srcImage,const GrVkImage & dstImage,uint32_t regionCount,const VkImageResolve * regions)821 void GrVkPrimaryCommandBuffer::resolveImage(GrVkGpu* gpu,
822                                             const GrVkImage& srcImage,
823                                             const GrVkImage& dstImage,
824                                             uint32_t regionCount,
825                                             const VkImageResolve* regions) {
826     SkASSERT(fIsActive);
827     SkASSERT(!fActiveRenderPass);
828 
829     this->addingWork(gpu);
830     this->addResource(srcImage.resource());
831     this->addResource(dstImage.resource());
832 
833     GR_VK_CALL(gpu->vkInterface(), CmdResolveImage(fCmdBuffer,
834                                                    srcImage.image(),
835                                                    srcImage.currentLayout(),
836                                                    dstImage.image(),
837                                                    dstImage.currentLayout(),
838                                                    regionCount,
839                                                    regions));
840 }
841 
onFreeGPUData(GrVkGpu * gpu) const842 void GrVkPrimaryCommandBuffer::onFreeGPUData(GrVkGpu* gpu) const {
843     SkASSERT(!fActiveRenderPass);
844     // Destroy the fence, if any
845     if (VK_NULL_HANDLE != fSubmitFence) {
846         GR_VK_CALL(gpu->vkInterface(), DestroyFence(gpu->device(), fSubmitFence, nullptr));
847     }
848     for (const auto& buffer : fSecondaryCommandBuffers) {
849         buffer->freeGPUData(gpu);
850     }
851 }
852 
onAbandonGPUData() const853 void GrVkPrimaryCommandBuffer::onAbandonGPUData() const {
854     SkASSERT(!fActiveRenderPass);
855     for (const auto& buffer : fSecondaryCommandBuffers) {
856         buffer->abandonGPUData();
857     }
858 }
859 
860 ///////////////////////////////////////////////////////////////////////////////
861 // SecondaryCommandBuffer
862 ////////////////////////////////////////////////////////////////////////////////
863 
Create(const GrVkGpu * gpu,GrVkCommandPool * cmdPool)864 GrVkSecondaryCommandBuffer* GrVkSecondaryCommandBuffer::Create(const GrVkGpu* gpu,
865                                                                GrVkCommandPool* cmdPool) {
866     SkASSERT(cmdPool);
867     const VkCommandBufferAllocateInfo cmdInfo = {
868         VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,   // sType
869         nullptr,                                          // pNext
870         cmdPool->vkCommandPool(),                         // commandPool
871         VK_COMMAND_BUFFER_LEVEL_SECONDARY,                // level
872         1                                                 // bufferCount
873     };
874 
875     VkCommandBuffer cmdBuffer;
876     VkResult err = GR_VK_CALL(gpu->vkInterface(), AllocateCommandBuffers(gpu->device(),
877                                                                          &cmdInfo,
878                                                                          &cmdBuffer));
879     if (err) {
880         return nullptr;
881     }
882     return new GrVkSecondaryCommandBuffer(cmdBuffer, cmdPool);
883 }
884 
Create(VkCommandBuffer cmdBuffer)885 GrVkSecondaryCommandBuffer* GrVkSecondaryCommandBuffer::Create(VkCommandBuffer cmdBuffer) {
886     return new GrVkSecondaryCommandBuffer(cmdBuffer, nullptr);
887 }
888 
begin(const GrVkGpu * gpu,const GrVkFramebuffer * framebuffer,const GrVkRenderPass * compatibleRenderPass)889 void GrVkSecondaryCommandBuffer::begin(const GrVkGpu* gpu, const GrVkFramebuffer* framebuffer,
890                                        const GrVkRenderPass* compatibleRenderPass) {
891     SkASSERT(!fIsActive);
892     SkASSERT(compatibleRenderPass);
893     fActiveRenderPass = compatibleRenderPass;
894 
895     if (!this->isWrapped()) {
896         VkCommandBufferInheritanceInfo inheritanceInfo;
897         memset(&inheritanceInfo, 0, sizeof(VkCommandBufferInheritanceInfo));
898         inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
899         inheritanceInfo.pNext = nullptr;
900         inheritanceInfo.renderPass = fActiveRenderPass->vkRenderPass();
901         inheritanceInfo.subpass = 0; // Currently only using 1 subpass for each render pass
902         inheritanceInfo.framebuffer = framebuffer ? framebuffer->framebuffer() : VK_NULL_HANDLE;
903         inheritanceInfo.occlusionQueryEnable = false;
904         inheritanceInfo.queryFlags = 0;
905         inheritanceInfo.pipelineStatistics = 0;
906 
907         VkCommandBufferBeginInfo cmdBufferBeginInfo;
908         memset(&cmdBufferBeginInfo, 0, sizeof(VkCommandBufferBeginInfo));
909         cmdBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
910         cmdBufferBeginInfo.pNext = nullptr;
911         cmdBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT |
912                 VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
913         cmdBufferBeginInfo.pInheritanceInfo = &inheritanceInfo;
914 
915         GR_VK_CALL_ERRCHECK(gpu->vkInterface(), BeginCommandBuffer(fCmdBuffer,
916                                                                    &cmdBufferBeginInfo));
917     }
918     fIsActive = true;
919 }
920 
end(GrVkGpu * gpu)921 void GrVkSecondaryCommandBuffer::end(GrVkGpu* gpu) {
922     SkASSERT(fIsActive);
923     if (!this->isWrapped()) {
924         GR_VK_CALL_ERRCHECK(gpu->vkInterface(), EndCommandBuffer(fCmdBuffer));
925     }
926     this->invalidateState();
927     fIsActive = false;
928     fHasWork = false;
929 }
930 
recycle(GrVkGpu * gpu)931 void GrVkSecondaryCommandBuffer::recycle(GrVkGpu* gpu) {
932     if (this->isWrapped()) {
933         this->freeGPUData(gpu);
934         delete this;
935     } else {
936         fCmdPool->recycleSecondaryCommandBuffer(this);
937     }
938 }
939 
940