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