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