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