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