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