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