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