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