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