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