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