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