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