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