Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
GrVkOpsRenderPass.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2016 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
9
11#include "include/core/SkRect.h"
32
33using namespace skia_private;
34
35/////////////////////////////////////////////////////////////////////////////
36
37void get_vk_load_store_ops(GrLoadOp loadOpIn, GrStoreOp storeOpIn,
38 VkAttachmentLoadOp* loadOp, VkAttachmentStoreOp* storeOp) {
39 switch (loadOpIn) {
40 case GrLoadOp::kLoad:
42 break;
45 break;
48 break;
49 default:
50 SK_ABORT("Invalid LoadOp");
52 }
53
54 switch (storeOpIn) {
57 break;
60 break;
61 default:
62 SK_ABORT("Invalid StoreOp");
64 }
65}
66
68
69void GrVkOpsRenderPass::setAttachmentLayouts(LoadFromResolve loadFromResolve) {
70 bool withStencil = fCurrentRenderPass->hasStencilAttachment();
71 bool withResolve = fCurrentRenderPass->hasResolveAttachment();
72
73 if (fSelfDependencyFlags == SelfDependencyFlags::kForInputAttachment) {
74 // We need to use the GENERAL layout in this case since we'll be using texture barriers
75 // with an input attachment.
81 fFramebuffer->colorAttachment()->setImageLayout(
82 fGpu, VK_IMAGE_LAYOUT_GENERAL, dstAccess, dstStages, false);
83 } else {
84 // Change layout of our render target so it can be used as the color attachment.
85 // TODO: If we know that we will never be blending or loading the attachment we could drop
86 // the VK_ACCESS_COLOR_ATTACHMENT_READ_BIT.
87 fFramebuffer->colorAttachment()->setImageLayout(
88 fGpu,
92 false);
93 }
94
95 if (withResolve) {
96 GrVkImage* resolveAttachment = fFramebuffer->resolveAttachment();
97 SkASSERT(resolveAttachment);
98 if (loadFromResolve == LoadFromResolve::kLoad) {
99 // We need input access to do the shader read and color read access to do the attachment
100 // load.
101 VkAccessFlags dstAccess =
105 resolveAttachment->setImageLayout(fGpu,
107 dstAccess,
108 dstStages,
109 false);
110 } else {
111 resolveAttachment->setImageLayout(
112 fGpu,
116 false);
117 }
118 }
119
120 // If we are using a stencil attachment we also need to update its layout
121 if (withStencil) {
122 auto* vkStencil = fFramebuffer->stencilAttachment();
123 SkASSERT(vkStencil);
124
125 // We need the write and read access bits since we may load and store the stencil.
126 // The initial load happens in the VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT so we
127 // wait there.
128 vkStencil->setImageLayout(fGpu,
133 false);
134 }
135}
136
137// The RenderArea bounds we pass into BeginRenderPass must have a start x value that is a multiple
138// of the granularity. The width must also be a multiple of the granularity or eaqual to the width
139// the the entire attachment. Similar requirements for the y and height components.
141 const SkIRect& srcBounds,
142 const VkExtent2D& granularity,
143 int maxWidth,
144 int maxHeight) {
145 // Adjust Width
146 if ((0 != granularity.width && 1 != granularity.width)) {
147 // Start with the right side of rect so we know if we end up going pass the maxWidth.
148 int rightAdj = srcBounds.fRight % granularity.width;
149 if (rightAdj != 0) {
150 rightAdj = granularity.width - rightAdj;
151 }
152 dstBounds->fRight = srcBounds.fRight + rightAdj;
153 if (dstBounds->fRight > maxWidth) {
154 dstBounds->fRight = maxWidth;
155 dstBounds->fLeft = 0;
156 } else {
157 dstBounds->fLeft = srcBounds.fLeft - srcBounds.fLeft % granularity.width;
158 }
159 } else {
160 dstBounds->fLeft = srcBounds.fLeft;
161 dstBounds->fRight = srcBounds.fRight;
162 }
163
164 // Adjust height
165 if ((0 != granularity.height && 1 != granularity.height)) {
166 // Start with the bottom side of rect so we know if we end up going pass the maxHeight.
167 int bottomAdj = srcBounds.fBottom % granularity.height;
168 if (bottomAdj != 0) {
169 bottomAdj = granularity.height - bottomAdj;
170 }
171 dstBounds->fBottom = srcBounds.fBottom + bottomAdj;
172 if (dstBounds->fBottom > maxHeight) {
173 dstBounds->fBottom = maxHeight;
174 dstBounds->fTop = 0;
175 } else {
176 dstBounds->fTop = srcBounds.fTop - srcBounds.fTop % granularity.height;
177 }
178 } else {
179 dstBounds->fTop = srcBounds.fTop;
180 dstBounds->fBottom = srcBounds.fBottom;
181 }
182}
183
184bool GrVkOpsRenderPass::beginRenderPass(const VkClearValue& clearColor,
185 LoadFromResolve loadFromResolve) {
186 this->setAttachmentLayouts(loadFromResolve);
187
188 bool firstSubpassUsesSecondaryCB =
189 loadFromResolve != LoadFromResolve::kLoad && SkToBool(fCurrentSecondaryCommandBuffer);
190
191 bool useFullBounds = fCurrentRenderPass->hasResolveAttachment() &&
193
194 auto dimensions = fFramebuffer->colorAttachment()->dimensions();
195
196 auto nativeBounds = GrNativeRect::MakeIRectRelativeTo(
197 fOrigin,
198 dimensions.height(), useFullBounds ? SkIRect::MakeSize(dimensions) : fBounds);
199
200 // The bounds we use for the render pass should be of the granularity supported
201 // by the device.
202 const VkExtent2D& granularity = fCurrentRenderPass->granularity();
203 SkIRect adjustedBounds;
204 if ((0 != granularity.width && 1 != granularity.width) ||
205 (0 != granularity.height && 1 != granularity.height)) {
206 adjust_bounds_to_granularity(&adjustedBounds,
207 nativeBounds,
208 granularity,
209 dimensions.width(),
210 dimensions.height());
211 } else {
212 adjustedBounds = nativeBounds;
213 }
214
215 if (!fGpu->beginRenderPass(fCurrentRenderPass, fFramebuffer, &clearColor, fRenderTarget,
216 adjustedBounds, firstSubpassUsesSecondaryCB)) {
217 if (fCurrentSecondaryCommandBuffer) {
218 fCurrentSecondaryCommandBuffer->end(fGpu);
219 }
220 fCurrentRenderPass = nullptr;
221 return false;
222 }
223
224 if (loadFromResolve == LoadFromResolve::kLoad) {
225 this->loadResolveIntoMSAA(adjustedBounds);
226 }
227
228 return true;
229}
230
231bool GrVkOpsRenderPass::init(const GrOpsRenderPass::LoadAndStoreInfo& colorInfo,
232 const GrOpsRenderPass::LoadAndStoreInfo& resolveInfo,
233 const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo) {
234 VkAttachmentLoadOp loadOp;
235 VkAttachmentStoreOp storeOp;
236 get_vk_load_store_ops(colorInfo.fLoadOp, colorInfo.fStoreOp, &loadOp, &storeOp);
237 GrVkRenderPass::LoadStoreOps vkColorOps(loadOp, storeOp);
238
239 get_vk_load_store_ops(resolveInfo.fLoadOp, resolveInfo.fStoreOp, &loadOp, &storeOp);
240 GrVkRenderPass::LoadStoreOps vkResolveOps(loadOp, storeOp);
241
242 get_vk_load_store_ops(stencilInfo.fLoadOp, stencilInfo.fStoreOp, &loadOp, &storeOp);
243 GrVkRenderPass::LoadStoreOps vkStencilOps(loadOp, storeOp);
244
245 GrVkResourceProvider::CompatibleRPHandle rpHandle = fFramebuffer->compatibleRenderPassHandle();
246 SkASSERT(rpHandle.isValid());
247 fCurrentRenderPass = fGpu->resourceProvider().findRenderPass(rpHandle,
248 vkColorOps,
249 vkResolveOps,
250 vkStencilOps);
251
252 if (!fCurrentRenderPass) {
253 return false;
254 }
255
257 SkASSERT(fGpu->cmdPool());
258 fCurrentSecondaryCommandBuffer = fGpu->cmdPool()->findOrCreateSecondaryCommandBuffer(fGpu);
259 if (!fCurrentSecondaryCommandBuffer) {
260 fCurrentRenderPass = nullptr;
261 return false;
262 }
263 fCurrentSecondaryCommandBuffer->begin(fGpu, fFramebuffer.get(), fCurrentRenderPass);
264 }
265
266 VkClearValue vkClearColor;
267 vkClearColor.color.float32[0] = colorInfo.fClearColor[0];
268 vkClearColor.color.float32[1] = colorInfo.fClearColor[1];
269 vkClearColor.color.float32[2] = colorInfo.fClearColor[2];
270 vkClearColor.color.float32[3] = colorInfo.fClearColor[3];
271
272 return this->beginRenderPass(vkClearColor, fLoadFromResolve);
273}
274
275bool GrVkOpsRenderPass::initWrapped() {
276 SkASSERT(fFramebuffer->isExternal());
277 fCurrentRenderPass = fFramebuffer->externalRenderPass();
278 SkASSERT(fCurrentRenderPass);
279 fCurrentRenderPass->ref();
280
281 fCurrentSecondaryCommandBuffer = fFramebuffer->externalCommandBuffer();
282 if (!fCurrentSecondaryCommandBuffer) {
283 return false;
284 }
285 return true;
286}
287
291
292GrGpu* GrVkOpsRenderPass::gpu() { return fGpu; }
293
294GrVkCommandBuffer* GrVkOpsRenderPass::currentCommandBuffer() {
295 if (fCurrentSecondaryCommandBuffer) {
296 return fCurrentSecondaryCommandBuffer.get();
297 }
298 // We checked this when we setup the GrVkOpsRenderPass and it should not have changed while we
299 // are still using this object.
301 return fGpu->currentCommandBuffer();
302}
303
304void GrVkOpsRenderPass::loadResolveIntoMSAA(const SkIRect& nativeBounds) {
305 fGpu->loadMSAAFromResolve(this->currentCommandBuffer(), *fCurrentRenderPass,
306 fFramebuffer->colorAttachment(), fFramebuffer->resolveAttachment(),
307 nativeBounds);
308 fGpu->currentCommandBuffer()->nexSubpass(fGpu, SkToBool(fCurrentSecondaryCommandBuffer));
309
310 // If we loaded the resolve attachment, then we would have set the image layout to be
311 // VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL so that it could be used at the start as an input
312 // attachment. However, when we switched to the main subpass it will transition the layout
313 // internally to VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL. Thus we need to update our tracking
314 // of the layout to match the new layout.
315 SkASSERT(fFramebuffer->resolveAttachment());
317}
318
320 if (!fRenderTarget) {
321 return;
322 }
323 if (!fCurrentRenderPass) {
324 SkASSERT(fGpu->isDeviceLost());
325 return;
326 }
327
328 // We don't want to actually submit the secondary command buffer if it is wrapped.
329 if (this->wrapsSecondaryCommandBuffer()) {
330 // We pass the ownership of the GrVkSecondaryCommandBuffer to the external framebuffer
331 // since it's lifetime matches the lifetime we need to keep the GrManagedResources on the
332 // GrVkSecondaryCommandBuffer alive.
334 std::move(fCurrentSecondaryCommandBuffer));
335 return;
336 }
337
338 if (fCurrentSecondaryCommandBuffer) {
339 fGpu->submitSecondaryCommandBuffer(std::move(fCurrentSecondaryCommandBuffer));
340 }
341 fGpu->endRenderPass(fRenderTarget, fOrigin, fBounds);
342}
343
345 sk_sp<GrVkFramebuffer> framebuffer,
346 GrSurfaceOrigin origin,
347 const SkIRect& bounds,
348 const GrOpsRenderPass::LoadAndStoreInfo& colorInfo,
350 const GrOpsRenderPass::LoadAndStoreInfo& resolveInfo,
352 GrVkRenderPass::LoadFromResolve loadFromResolve,
353 const TArray<GrSurfaceProxy*, true>& sampledProxies) {
355 SkASSERT(fGpu == rt->getContext()->priv().getGpu());
356
357#ifdef SK_DEBUG
358 fIsActive = true;
359#endif
360
361 // We check to make sure the GrVkGpu has a valid current command buffer instead of each time we
362 // access it. If the command buffer is valid here should be valid throughout the use of the
363 // render pass since nothing should trigger a submit while this render pass is active.
364 if (!fGpu->currentCommandBuffer()) {
365 return false;
366 }
367
368 this->INHERITED::set(rt, origin);
369
370 for (int i = 0; i < sampledProxies.size(); ++i) {
371 if (sampledProxies[i]->isInstantiated()) {
372 SkASSERT(sampledProxies[i]->asTextureProxy());
373 GrVkTexture* vkTex = static_cast<GrVkTexture*>(sampledProxies[i]->peekTexture());
374 SkASSERT(vkTex);
375 GrVkImage* texture = vkTex->textureImage();
377 texture->setImageLayout(
380 }
381 }
382
383 SkASSERT(framebuffer);
384 fFramebuffer = std::move(framebuffer);
385
386 SkASSERT(bounds.isEmpty() ||
387 SkIRect::MakeSize(fFramebuffer->colorAttachment()->dimensions()).contains(bounds));
388 fBounds = bounds;
389
390 fSelfDependencyFlags = selfDepFlags;
391 fLoadFromResolve = loadFromResolve;
392
393 if (this->wrapsSecondaryCommandBuffer()) {
394 return this->initWrapped();
395 }
396
397 return this->init(colorInfo, resolveInfo, stencilInfo);
398}
399
401 if (fCurrentSecondaryCommandBuffer) {
402 // The active GrVkCommandPool on the GrVkGpu should still be the same pool we got the
403 // secondary command buffer from since we haven't submitted any work yet.
404 SkASSERT(fGpu->cmdPool());
405 fCurrentSecondaryCommandBuffer.release()->recycle(fGpu->cmdPool());
406 }
407 if (fCurrentRenderPass) {
408 fCurrentRenderPass->unref();
409 fCurrentRenderPass = nullptr;
410 }
411 fCurrentCBIsEmpty = true;
412
413 fRenderTarget = nullptr;
414 fFramebuffer.reset();
415
416 fSelfDependencyFlags = GrVkRenderPass::SelfDependencyFlags::kNone;
417
418 fLoadFromResolve = LoadFromResolve::kNo;
419 fOverridePipelinesForResolveLoad = false;
420
421#ifdef SK_DEBUG
422 fIsActive = false;
423#endif
424}
425
426bool GrVkOpsRenderPass::wrapsSecondaryCommandBuffer() const {
427 return fFramebuffer->isExternal();
428}
429
430////////////////////////////////////////////////////////////////////////////////
431
432void GrVkOpsRenderPass::onClearStencilClip(const GrScissorState& scissor, bool insideStencilMask) {
433 if (!fCurrentRenderPass) {
434 SkASSERT(fGpu->isDeviceLost());
435 return;
436 }
437
438 GrAttachment* sb = fFramebuffer->stencilAttachment();
439 // this should only be called internally when we know we have a
440 // stencil buffer.
441 SkASSERT(sb);
442 int stencilBitCount = GrBackendFormatStencilBits(sb->backendFormat());
443
444 // The contract with the callers does not guarantee that we preserve all bits in the stencil
445 // during this clear. Thus we will clear the entire stencil to the desired value.
446
447 VkClearDepthStencilValue vkStencilColor;
448 memset(&vkStencilColor, 0, sizeof(VkClearDepthStencilValue));
449 if (insideStencilMask) {
450 vkStencilColor.stencil = (1 << (stencilBitCount - 1));
451 } else {
452 vkStencilColor.stencil = 0;
453 }
454
455 VkClearRect clearRect;
456 // Flip rect if necessary
457 SkIRect vkRect;
458 if (!scissor.enabled()) {
459 vkRect.setXYWH(0, 0, sb->width(), sb->height());
460 } else if (kBottomLeft_GrSurfaceOrigin != fOrigin) {
461 vkRect = scissor.rect();
462 } else {
463 vkRect.setLTRB(scissor.rect().fLeft, sb->height() - scissor.rect().fBottom,
464 scissor.rect().fRight, sb->height() - scissor.rect().fTop);
465 }
466
467 clearRect.rect.offset = { vkRect.fLeft, vkRect.fTop };
468 clearRect.rect.extent = { (uint32_t)vkRect.width(), (uint32_t)vkRect.height() };
469
470 clearRect.baseArrayLayer = 0;
471 clearRect.layerCount = 1;
472
473 uint32_t stencilIndex;
474 SkAssertResult(fCurrentRenderPass->stencilAttachmentIndex(&stencilIndex));
475
476 VkClearAttachment attachment;
478 attachment.colorAttachment = 0; // this value shouldn't matter
479 attachment.clearValue.depthStencil = vkStencilColor;
480
481 this->currentCommandBuffer()->clearAttachments(fGpu, 1, &attachment, 1, &clearRect);
482 fCurrentCBIsEmpty = false;
483}
484
485void GrVkOpsRenderPass::onClear(const GrScissorState& scissor, std::array<float, 4> color) {
486 if (!fCurrentRenderPass) {
487 SkASSERT(fGpu->isDeviceLost());
488 return;
489 }
490
491 VkClearColorValue vkColor = {{color[0], color[1], color[2], color[3]}};
492
493 // If we end up in a situation where we are calling clear without a scissior then in general it
494 // means we missed an opportunity higher up the stack to set the load op to be a clear. However,
495 // there are situations where higher up we couldn't discard the previous ops and set a clear
496 // load op (e.g. if we needed to execute a wait op). Thus we also have the empty check here.
497 // TODO: Make the waitOp a RenderTask instead so we can clear out the OpsTask for a clear. We
498 // can then reenable this assert assuming we can't get messed up by a waitOp.
499 //SkASSERT(!fCurrentCBIsEmpty || scissor);
500
501 auto dimensions = fFramebuffer->colorAttachment()->dimensions();
502 // We always do a sub rect clear with clearAttachments since we are inside a render pass
503 VkClearRect clearRect;
504 // Flip rect if necessary
505 SkIRect vkRect;
506 if (!scissor.enabled()) {
507 vkRect.setSize(dimensions);
508 } else if (kBottomLeft_GrSurfaceOrigin != fOrigin) {
509 vkRect = scissor.rect();
510 } else {
511 vkRect.setLTRB(scissor.rect().fLeft, dimensions.height() - scissor.rect().fBottom,
512 scissor.rect().fRight, dimensions.height() - scissor.rect().fTop);
513 }
514 clearRect.rect.offset = { vkRect.fLeft, vkRect.fTop };
515 clearRect.rect.extent = { (uint32_t)vkRect.width(), (uint32_t)vkRect.height() };
516 clearRect.baseArrayLayer = 0;
517 clearRect.layerCount = 1;
518
519 uint32_t colorIndex;
520 SkAssertResult(fCurrentRenderPass->colorAttachmentIndex(&colorIndex));
521
522 VkClearAttachment attachment;
524 attachment.colorAttachment = colorIndex;
525 attachment.clearValue.color = vkColor;
526
527 this->currentCommandBuffer()->clearAttachments(fGpu, 1, &attachment, 1, &clearRect);
528 fCurrentCBIsEmpty = false;
529}
530
531////////////////////////////////////////////////////////////////////////////////
532
533void GrVkOpsRenderPass::addAdditionalRenderPass(bool mustUseSecondaryCommandBuffer) {
534 SkASSERT(!this->wrapsSecondaryCommandBuffer());
535
536 bool withResolve = fFramebuffer->resolveAttachment();
537 bool withStencil = fFramebuffer->stencilAttachment();
538
539 // If we have a resolve attachment we must do a resolve load in the new render pass since we
540 // broke up the original one. GrProgramInfos were made without any knowledge that the render
541 // pass may be split up. Thus they may try to make VkPipelines that only use one subpass. We
542 // need to override that to make sure they are compatible with the extra load subpass.
543 fOverridePipelinesForResolveLoad |=
544 withResolve && fCurrentRenderPass->loadFromResolve() != LoadFromResolve::kLoad;
545
550 LoadFromResolve loadFromResolve = LoadFromResolve::kNo;
551 if (withResolve) {
553 loadFromResolve = LoadFromResolve::kLoad;
554 }
557
558 SkASSERT(fCurrentRenderPass);
559 fCurrentRenderPass->unref();
560 fCurrentRenderPass = nullptr;
561
562 GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(fRenderTarget);
563 auto fb = vkRT->getFramebuffer(withResolve, withStencil, fSelfDependencyFlags, loadFromResolve);
564 if (!fb) {
565 return;
566 }
567 fFramebuffer = sk_ref_sp(fb);
568
569 SkASSERT(fFramebuffer);
570 const GrVkResourceProvider::CompatibleRPHandle& rpHandle =
571 fFramebuffer->compatibleRenderPassHandle();
572 SkASSERT(rpHandle.isValid());
573
574 fCurrentRenderPass = fGpu->resourceProvider().findRenderPass(rpHandle,
575 vkColorOps,
576 vkResolveOps,
577 vkStencilOps);
578
579 if (!fCurrentRenderPass) {
580 return;
581 }
582
584 mustUseSecondaryCommandBuffer) {
585 SkASSERT(fGpu->cmdPool());
586 fCurrentSecondaryCommandBuffer = fGpu->cmdPool()->findOrCreateSecondaryCommandBuffer(fGpu);
587 if (!fCurrentSecondaryCommandBuffer) {
588 fCurrentRenderPass = nullptr;
589 return;
590 }
591 fCurrentSecondaryCommandBuffer->begin(fGpu, fFramebuffer.get(), fCurrentRenderPass);
592 }
593
594 VkClearValue vkClearColor;
595 memset(&vkClearColor, 0, sizeof(VkClearValue));
596
597 this->beginRenderPass(vkClearColor, loadFromResolve);
598}
599
601 if (!fCurrentRenderPass) {
602 SkASSERT(fGpu->isDeviceLost());
603 return;
604 }
605 if (fCurrentSecondaryCommandBuffer) {
606 fCurrentSecondaryCommandBuffer->end(fGpu);
607 fGpu->submitSecondaryCommandBuffer(std::move(fCurrentSecondaryCommandBuffer));
608 }
609 fGpu->endRenderPass(fRenderTarget, fOrigin, fBounds);
610
611 // We pass in true here to signal that after the upload we need to set the upload textures
612 // layout back to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL.
613 state->doUpload(upload, true);
614
615 this->addAdditionalRenderPass(false);
616}
617
618////////////////////////////////////////////////////////////////////////////////
619
621 if (fCurrentSecondaryCommandBuffer && !this->wrapsSecondaryCommandBuffer()) {
622 fCurrentSecondaryCommandBuffer->end(fGpu);
623 }
624}
625
626bool GrVkOpsRenderPass::onBindPipeline(const GrProgramInfo& programInfo, const SkRect& drawBounds) {
627 if (!fCurrentRenderPass) {
628 SkASSERT(fGpu->isDeviceLost());
629 return false;
630 }
631
632 SkRect rtRect = SkRect::Make(fBounds);
633 if (rtRect.intersect(drawBounds)) {
634 rtRect.roundOut(&fCurrentPipelineBounds);
635 } else {
636 fCurrentPipelineBounds.setEmpty();
637 }
638
639 GrVkCommandBuffer* currentCB = this->currentCommandBuffer();
640 SkASSERT(fCurrentRenderPass);
641
642 VkRenderPass compatibleRenderPass = fCurrentRenderPass->vkRenderPass();
643 fCurrentPipelineState = fGpu->resourceProvider().findOrCreateCompatiblePipelineState(
644 fRenderTarget, programInfo, compatibleRenderPass, fOverridePipelinesForResolveLoad);
645 if (!fCurrentPipelineState) {
646 return false;
647 }
648
649 fCurrentPipelineState->bindPipeline(fGpu, currentCB);
650
651 // Both the 'programInfo' and this renderPass have an origin. Since they come from the
652 // same place (i.e., the target renderTargetProxy) they had best agree.
653 SkASSERT(programInfo.origin() == fOrigin);
654
655 auto colorAttachment = fFramebuffer->colorAttachment();
656 if (!fCurrentPipelineState->setAndBindUniforms(fGpu, colorAttachment->dimensions(), programInfo,
657 currentCB)) {
658 return false;
659 }
660
661 if (!programInfo.pipeline().isScissorTestEnabled()) {
662 // "Disable" scissor by setting it to the full pipeline bounds.
664 fGpu, currentCB, colorAttachment->dimensions(), fOrigin,
665 fCurrentPipelineBounds);
666 }
667 GrVkPipeline::SetDynamicViewportState(fGpu, currentCB, colorAttachment->dimensions());
669 programInfo.pipeline().writeSwizzle(),
670 programInfo.pipeline().getXferProcessor());
671
672 return true;
673}
674
676 SkIRect combinedScissorRect;
677 if (!combinedScissorRect.intersect(fCurrentPipelineBounds, scissor)) {
678 combinedScissorRect = SkIRect::MakeEmpty();
679 }
680 GrVkPipeline::SetDynamicScissorRectState(fGpu, this->currentCommandBuffer(),
681 fFramebuffer->colorAttachment()->dimensions(),
682 fOrigin, combinedScissorRect);
683}
684
685#ifdef SK_DEBUG
686void check_sampled_texture(GrTexture* tex, GrAttachment* colorAttachment, GrVkGpu* gpu) {
687 SkASSERT(!tex->isProtected() || (colorAttachment->isProtected() && gpu->protectedContext()));
688 auto vkTex = static_cast<GrVkTexture*>(tex)->textureImage();
689 SkASSERT(vkTex->currentLayout() == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
690}
691#endif
692
694 const GrSurfaceProxy* const geomProcTextures[],
695 const GrPipeline& pipeline) {
696#ifdef SK_DEBUG
697 SkASSERT(fCurrentPipelineState);
698 auto colorAttachment = fFramebuffer->colorAttachment();
699 for (int i = 0; i < geomProc.numTextureSamplers(); ++i) {
700 check_sampled_texture(geomProcTextures[i]->peekTexture(), colorAttachment, fGpu);
701 }
702 pipeline.visitTextureEffects([&](const GrTextureEffect& te) {
703 check_sampled_texture(te.texture(), colorAttachment, fGpu);
704 });
705 if (GrTexture* dstTexture = pipeline.peekDstTexture()) {
706 check_sampled_texture(dstTexture, colorAttachment, fGpu);
707 }
708#endif
709 if (!fCurrentPipelineState->setAndBindTextures(fGpu, geomProc, pipeline, geomProcTextures,
710 this->currentCommandBuffer())) {
711 return false;
712 }
713 if (fSelfDependencyFlags == SelfDependencyFlags::kForInputAttachment) {
714 // We bind the color attachment as an input attachment
715 auto ds = fFramebuffer->colorAttachment()->inputDescSetForBlending(fGpu);
716 if (!ds) {
717 return false;
718 }
719 return fCurrentPipelineState->setAndBindInputAttachment(fGpu, std::move(ds),
720 this->currentCommandBuffer());
721 }
722 return true;
723}
724
726 sk_sp<const GrBuffer> instanceBuffer,
727 sk_sp<const GrBuffer> vertexBuffer,
728 GrPrimitiveRestart primRestart) {
729 SkASSERT(GrPrimitiveRestart::kNo == primRestart);
730 if (!fCurrentRenderPass) {
731 SkASSERT(fGpu->isDeviceLost());
732 return;
733 }
734 SkASSERT(fCurrentPipelineState);
735 SkASSERT(!fGpu->caps()->usePrimitiveRestart()); // Ignore primitiveRestart parameter.
736
737 GrVkCommandBuffer* currCmdBuf = this->currentCommandBuffer();
738 SkASSERT(currCmdBuf);
739
740 // There is no need to put any memory barriers to make sure host writes have finished here.
741 // When a command buffer is submitted to a queue, there is an implicit memory barrier that
742 // occurs for all host writes. Additionally, BufferMemoryBarriers are not allowed inside of
743 // an active RenderPass.
744
745 // Here our vertex and instance inputs need to match the same 0-based bindings they were
746 // assigned in GrVkPipeline. That is, vertex first (if any) followed by instance.
747 uint32_t binding = 0;
748 if (vertexBuffer) {
749 SkDEBUGCODE(auto* gpuVertexBuffer = static_cast<const GrGpuBuffer*>(vertexBuffer.get()));
750 SkASSERT(!gpuVertexBuffer->isCpuBuffer());
751 SkASSERT(!gpuVertexBuffer->isMapped());
752 currCmdBuf->bindInputBuffer(fGpu, binding++, std::move(vertexBuffer));
753 }
754 if (instanceBuffer) {
755 SkDEBUGCODE(auto* gpuInstanceBuffer =
756 static_cast<const GrGpuBuffer*>(instanceBuffer.get()));
757 SkASSERT(!gpuInstanceBuffer->isCpuBuffer());
758 SkASSERT(!gpuInstanceBuffer->isMapped());
759 currCmdBuf->bindInputBuffer(fGpu, binding++, std::move(instanceBuffer));
760 }
761 if (indexBuffer) {
762 SkDEBUGCODE(auto* gpuIndexBuffer = static_cast<const GrGpuBuffer*>(indexBuffer.get()));
763 SkASSERT(!gpuIndexBuffer->isCpuBuffer());
764 SkASSERT(!gpuIndexBuffer->isMapped());
765 currCmdBuf->bindIndexBuffer(fGpu, std::move(indexBuffer));
766 }
767}
768
770 int baseInstance,
771 int vertexCount, int baseVertex) {
772 if (!fCurrentRenderPass) {
773 SkASSERT(fGpu->isDeviceLost());
774 return;
775 }
776 SkASSERT(fCurrentPipelineState);
777 this->currentCommandBuffer()->draw(fGpu, vertexCount, instanceCount, baseVertex, baseInstance);
778 fGpu->stats()->incNumDraws();
779 fCurrentCBIsEmpty = false;
780}
781
782void GrVkOpsRenderPass::onDrawIndexedInstanced(int indexCount, int baseIndex, int instanceCount,
783 int baseInstance, int baseVertex) {
784 if (!fCurrentRenderPass) {
785 SkASSERT(fGpu->isDeviceLost());
786 return;
787 }
788 SkASSERT(fCurrentPipelineState);
789 this->currentCommandBuffer()->drawIndexed(fGpu, indexCount, instanceCount,
790 baseIndex, baseVertex, baseInstance);
791 fGpu->stats()->incNumDraws();
792 fCurrentCBIsEmpty = false;
793}
794
795void GrVkOpsRenderPass::onDrawIndirect(const GrBuffer* drawIndirectBuffer, size_t offset,
796 int drawCount) {
797 SkASSERT(!drawIndirectBuffer->isCpuBuffer());
798 if (!fCurrentRenderPass) {
799 SkASSERT(fGpu->isDeviceLost());
800 return;
801 }
802 const GrVkCaps& caps = fGpu->vkCaps();
804 SkASSERT(fCurrentPipelineState);
805
806 const uint32_t maxDrawCount = caps.maxDrawIndirectDrawCount();
807 uint32_t remainingDraws = drawCount;
808 const size_t stride = sizeof(GrDrawIndirectCommand);
809 while (remainingDraws >= 1) {
810 uint32_t currDrawCount = std::min(remainingDraws, maxDrawCount);
811 this->currentCommandBuffer()->drawIndirect(
812 fGpu, sk_ref_sp(drawIndirectBuffer), offset, currDrawCount, stride);
813 remainingDraws -= currDrawCount;
814 offset += stride * currDrawCount;
815 fGpu->stats()->incNumDraws();
816 }
817 fCurrentCBIsEmpty = false;
818}
819
820void GrVkOpsRenderPass::onDrawIndexedIndirect(const GrBuffer* drawIndirectBuffer, size_t offset,
821 int drawCount) {
822 SkASSERT(!drawIndirectBuffer->isCpuBuffer());
823 if (!fCurrentRenderPass) {
824 SkASSERT(fGpu->isDeviceLost());
825 return;
826 }
827 const GrVkCaps& caps = fGpu->vkCaps();
829 SkASSERT(fCurrentPipelineState);
830 const uint32_t maxDrawCount = caps.maxDrawIndirectDrawCount();
831 uint32_t remainingDraws = drawCount;
832 const size_t stride = sizeof(GrDrawIndexedIndirectCommand);
833 while (remainingDraws >= 1) {
834 uint32_t currDrawCount = std::min(remainingDraws, maxDrawCount);
835 this->currentCommandBuffer()->drawIndexedIndirect(
836 fGpu, sk_ref_sp(drawIndirectBuffer), offset, currDrawCount, stride);
837 remainingDraws -= currDrawCount;
838 offset += stride * currDrawCount;
839 fGpu->stats()->incNumDraws();
840 }
841 fCurrentCBIsEmpty = false;
842}
843
844////////////////////////////////////////////////////////////////////////////////
845
846void GrVkOpsRenderPass::onExecuteDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler> drawable) {
847 if (!fCurrentRenderPass) {
848 SkASSERT(fGpu->isDeviceLost());
849 return;
850 }
851
852 VkRect2D bounds;
853 bounds.offset = { 0, 0 };
854 bounds.extent = { 0, 0 };
855
856 if (!fCurrentSecondaryCommandBuffer) {
857 fGpu->endRenderPass(fRenderTarget, fOrigin, fBounds);
858 this->addAdditionalRenderPass(true);
859 // We may have failed to start a new render pass
860 if (!fCurrentRenderPass) {
861 SkASSERT(fGpu->isDeviceLost());
862 return;
863 }
864 }
865 SkASSERT(fCurrentSecondaryCommandBuffer);
866
867 GrVkDrawableInfo vkInfo;
868 vkInfo.fSecondaryCommandBuffer = fCurrentSecondaryCommandBuffer->vkCommandBuffer();
869 vkInfo.fCompatibleRenderPass = fCurrentRenderPass->vkRenderPass();
870 SkAssertResult(fCurrentRenderPass->colorAttachmentIndex(&vkInfo.fColorAttachmentIndex));
871 vkInfo.fFormat = fFramebuffer->colorAttachment()->imageFormat();
872 vkInfo.fDrawBounds = &bounds;
873#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
874 vkInfo.fFromSwapchainOrAndroidWindow =
875 fFramebuffer->colorAttachment()->vkImageInfo().fPartOfSwapchainOrAndroidWindow;
876#endif //SK_BUILD_FOR_ANDROID_FRAMEWORK
877
879
880 // After we draw into the command buffer via the drawable, cached state we have may be invalid.
881 this->currentCommandBuffer()->invalidateState();
882 // Also assume that the drawable produced output.
883 fCurrentCBIsEmpty = false;
884
885 drawable->draw(info);
886 fGpu->addDrawable(std::move(drawable));
887}
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
int GrBackendFormatStencilBits(const GrBackendFormat &format)
std::function< void(GrDeferredTextureUploadWritePixelsFn &)> GrDeferredTextureUploadFn
GrPrimitiveRestart
Definition GrTypesPriv.h:55
GrStoreOp
GrLoadOp
GrSurfaceOrigin
Definition GrTypes.h:147
@ kBottomLeft_GrSurfaceOrigin
Definition GrTypes.h:149
void adjust_bounds_to_granularity(SkIRect *dstBounds, const SkIRect &srcBounds, const VkExtent2D &granularity, int maxWidth, int maxHeight)
void get_vk_load_store_ops(GrLoadOp loadOpIn, GrStoreOp storeOpIn, VkAttachmentLoadOp *loadOp, VkAttachmentStoreOp *storeOp)
SkColor4f color
#define SkAssertResult(cond)
Definition SkAssert.h:123
#define SK_ABORT(message,...)
Definition SkAssert.h:70
#define SkASSERT(cond)
Definition SkAssert.h:116
#define SkDEBUGCODE(...)
Definition SkDebug.h:23
sk_sp< T > sk_ref_sp(T *obj)
Definition SkRefCnt.h:381
static constexpr bool SkToBool(const T &x)
Definition SkTo.h:35
virtual bool isCpuBuffer() const =0
bool nativeDrawIndirectSupport() const
Definition GrCaps.h:84
bool usePrimitiveRestart() const
Definition GrCaps.h:112
GrDirectContextPriv priv()
const GrDirectContext * getContext() const
void incNumDraws()
Definition GrGpu.h:541
Definition GrGpu.h:62
Stats * stats()
Definition GrGpu.h:551
const GrCaps * caps() const
Definition GrGpu.h:73
void set(GrRenderTarget *rt, GrSurfaceOrigin origin)
GrSurfaceOrigin fOrigin
GrRenderTarget * fRenderTarget
const skgpu::Swizzle & writeSwizzle() const
Definition GrPipeline.h:197
bool isScissorTestEnabled() const
Definition GrPipeline.h:163
void visitTextureEffects(const std::function< void(const GrTextureEffect &)> &) const
GrTexture * peekDstTexture() const
Definition GrPipeline.h:145
const GrXferProcessor & getXferProcessor() const
Definition GrPipeline.h:116
GrSurfaceOrigin origin() const
const GrPipeline & pipeline() const
bool enabled() const
const SkIRect & rect() const
virtual GrBackendFormat backendFormat() const =0
SkISize dimensions() const
Definition GrSurface.h:27
bool isProtected() const
Definition GrSurface.h:87
int height() const
Definition GrSurface.h:37
int width() const
Definition GrSurface.h:32
GrTexture * texture() const
bool mustLoadFullImageWithDiscardableMSAA() const
Definition GrVkCaps.h:259
bool preferPrimaryOverSecondaryCommandBuffers() const
Definition GrVkCaps.h:173
uint32_t maxDrawIndirectDrawCount() const
Definition GrVkCaps.h:203
void bindIndexBuffer(GrVkGpu *gpu, sk_sp< const GrBuffer > buffer)
void drawIndexed(const GrVkGpu *gpu, uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance)
void clearAttachments(const GrVkGpu *gpu, int numAttachments, const VkClearAttachment *attachments, int numRects, const VkClearRect *clearRects)
void bindInputBuffer(GrVkGpu *gpu, uint32_t binding, sk_sp< const GrBuffer > buffer)
void drawIndirect(const GrVkGpu *gpu, sk_sp< const GrBuffer > indirectBuffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride)
void draw(const GrVkGpu *gpu, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance)
void drawIndexedIndirect(const GrVkGpu *gpu, sk_sp< const GrBuffer > indirectBuffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride)
std::unique_ptr< GrVkSecondaryCommandBuffer > findOrCreateSecondaryCommandBuffer(GrVkGpu *gpu)
void returnExternalGrSecondaryCommandBuffer(std::unique_ptr< GrVkSecondaryCommandBuffer >)
GrVkResourceProvider::CompatibleRPHandle compatibleRenderPassHandle() const
const GrVkRenderPass * externalRenderPass() const
GrVkImage * resolveAttachment()
GrVkImage * colorAttachment()
std::unique_ptr< GrVkSecondaryCommandBuffer > externalCommandBuffer()
GrVkImage * stencilAttachment()
bool isExternal() const
const GrVkCaps & vkCaps() const
Definition GrVkGpu.h:61
bool loadMSAAFromResolve(GrVkCommandBuffer *commandBuffer, const GrVkRenderPass &renderPass, GrAttachment *dst, GrVkImage *src, const SkIRect &srcRect)
Definition GrVkGpu.cpp:1516
void addDrawable(std::unique_ptr< SkDrawable::GpuDrawHandler > drawable)
Definition GrVkGpu.cpp:2769
bool beginRenderPass(const GrVkRenderPass *, sk_sp< const GrVkFramebuffer >, const VkClearValue *colorClear, const GrSurface *, const SkIRect &renderPassBounds, bool forSecondaryCB)
Definition GrVkGpu.cpp:2637
void endRenderPass(GrRenderTarget *target, GrSurfaceOrigin origin, const SkIRect &bounds)
Definition GrVkGpu.cpp:2667
GrVkResourceProvider & resourceProvider()
Definition GrVkGpu.h:83
GrVkCommandPool * cmdPool() const
Definition GrVkGpu.h:74
bool isDeviceLost() const override
Definition GrVkGpu.h:66
GrVkPrimaryCommandBuffer * currentCommandBuffer() const
Definition GrVkGpu.h:85
bool protectedContext() const
Definition GrVkGpu.h:81
void submitSecondaryCommandBuffer(std::unique_ptr< GrVkSecondaryCommandBuffer >)
Definition GrVkGpu.cpp:2699
void setImageLayout(const GrVkGpu *gpu, VkImageLayout newLayout, VkAccessFlags dstAccessMask, VkPipelineStageFlags dstStageMask, bool byRegion)
Definition GrVkImage.h:143
VkFormat imageFormat() const
Definition GrVkImage.h:82
void updateImageLayout(VkImageLayout newLayout)
Definition GrVkImage.h:170
gr_rp< const GrVkDescriptorSet > inputDescSetForBlending(GrVkGpu *gpu)
const GrVkImageInfo & vkImageInfo() const
Definition GrVkImage.h:81
void onDrawIndexedInstanced(int indexCount, int baseIndex, int instanceCount, int baseInstance, int baseVertex) override
bool set(GrRenderTarget *, sk_sp< GrVkFramebuffer >, GrSurfaceOrigin, const SkIRect &bounds, const GrOpsRenderPass::LoadAndStoreInfo &, const GrOpsRenderPass::StencilLoadAndStoreInfo &, const GrOpsRenderPass::LoadAndStoreInfo &resolveInfo, GrVkRenderPass::SelfDependencyFlags selfDepFlags, GrVkRenderPass::LoadFromResolve loadFromResolve, const skia_private::TArray< GrSurfaceProxy *, true > &sampledProxies)
void onClearStencilClip(const GrScissorState &scissor, bool insideStencilMask) override
void onBindBuffers(sk_sp< const GrBuffer > indexBuffer, sk_sp< const GrBuffer > instanceBuffer, sk_sp< const GrBuffer > vertexBuffer, GrPrimitiveRestart) override
void onDrawIndexedIndirect(const GrBuffer *drawIndirectBuffer, size_t offset, int drawCount) override
void onSetScissorRect(const SkIRect &) override
void onDrawIndirect(const GrBuffer *drawIndirectBuffer, size_t offset, int drawCount) override
GrGpu * gpu() override
bool onBindTextures(const GrGeometryProcessor &, const GrSurfaceProxy *const geomProcTextures[], const GrPipeline &) override
void onDrawInstanced(int instanceCount, int baseInstance, int vertexCount, int baseVertex) override
bool onBindPipeline(const GrProgramInfo &, const SkRect &drawBounds) override
void onExecuteDrawable(std::unique_ptr< SkDrawable::GpuDrawHandler >) override
void onClear(const GrScissorState &scissor, std::array< float, 4 > color) override
void inlineUpload(GrOpFlushState *state, GrDeferredTextureUploadFn &upload) override
bool setAndBindTextures(GrVkGpu *, const GrGeometryProcessor &, const GrPipeline &, const GrSurfaceProxy *const geomProcTextures[], GrVkCommandBuffer *)
bool setAndBindUniforms(GrVkGpu *, SkISize colorAttachmentDimensions, const GrProgramInfo &, GrVkCommandBuffer *)
void bindPipeline(const GrVkGpu *gpu, GrVkCommandBuffer *commandBuffer)
bool setAndBindInputAttachment(GrVkGpu *, gr_rp< const GrVkDescriptorSet > inputDescSet, GrVkCommandBuffer *)
static void SetDynamicScissorRectState(GrVkGpu *, GrVkCommandBuffer *, SkISize colorAttachmentDimensions, GrSurfaceOrigin, const SkIRect &scissorRect)
static void SetDynamicBlendConstantState(GrVkGpu *, GrVkCommandBuffer *, const skgpu::Swizzle &writeSwizzle, const GrXferProcessor &)
static void SetDynamicViewportState(GrVkGpu *, GrVkCommandBuffer *, SkISize colorAttachmentDimensions)
void nexSubpass(GrVkGpu *gpu, bool forSecondaryCB)
bool colorAttachmentIndex(uint32_t *index) const
const VkExtent2D & granularity() const
LoadFromResolve loadFromResolve() const
bool stencilAttachmentIndex(uint32_t *index) const
bool hasStencilAttachment() const
VkRenderPass vkRenderPass() const
bool hasResolveAttachment() const
const GrVkFramebuffer * getFramebuffer(bool withResolve, bool withStencil, SelfDependencyFlags selfDepFlags, LoadFromResolve)
GrVkPipelineState * findOrCreateCompatiblePipelineState(GrRenderTarget *, const GrProgramInfo &, VkRenderPass compatibleRenderPass, bool overrideSubpassForResolveLoad)
const GrVkRenderPass * findRenderPass(GrVkRenderTarget *target, const GrVkRenderPass::LoadStoreOps &colorOps, const GrVkRenderPass::LoadStoreOps &resolveOps, const GrVkRenderPass::LoadStoreOps &stencilOps, CompatibleRPHandle *compatibleHandle, bool withResolve, bool withStencil, SelfDependencyFlags selfDepFlags, LoadFromResolve)
GrVkImage * textureImage() const
Definition GrVkTexture.h:50
T * get() const
Definition SkRefCnt.h:303
void reset(T *ptr=nullptr)
Definition SkRefCnt.h:310
int size() const
Definition SkTArray.h:416
AtkStateType state
FlTexture * texture
Point offset
static SkIRect MakeIRectRelativeTo(GrSurfaceOrigin origin, int rtHeight, SkIRect devRect)
std::array< float, 4 > fClearColor
VkRect2D * fDrawBounds
Definition GrVkTypes.h:89
VkFormat fFormat
Definition GrVkTypes.h:88
uint32_t fColorAttachmentIndex
Definition GrVkTypes.h:86
VkRenderPass fCompatibleRenderPass
Definition GrVkTypes.h:87
VkCommandBuffer fSecondaryCommandBuffer
Definition GrVkTypes.h:85
bool intersect(const SkIRect &r)
Definition SkRect.h:513
int32_t fBottom
larger y-axis bounds
Definition SkRect.h:36
constexpr int32_t height() const
Definition SkRect.h:165
int32_t fTop
smaller y-axis bounds
Definition SkRect.h:34
static constexpr SkIRect MakeSize(const SkISize &size)
Definition SkRect.h:66
static constexpr SkIRect MakeEmpty()
Definition SkRect.h:45
constexpr int32_t width() const
Definition SkRect.h:158
void setEmpty()
Definition SkRect.h:242
void setXYWH(int32_t x, int32_t y, int32_t width, int32_t height)
Definition SkRect.h:268
int32_t fLeft
smaller x-axis bounds
Definition SkRect.h:33
void setLTRB(int32_t left, int32_t top, int32_t right, int32_t bottom)
Definition SkRect.h:253
bool contains(int32_t x, int32_t y) const
Definition SkRect.h:463
int32_t fRight
larger x-axis bounds
Definition SkRect.h:35
void setSize(SkISize size)
Definition SkRect.h:282
static SkRect Make(const SkISize &size)
Definition SkRect.h:669
bool intersect(const SkRect &r)
Definition SkRect.cpp:114
void roundOut(SkIRect *dst) const
Definition SkRect.h:1241
VkImageAspectFlags aspectMask
VkClearValue clearValue
uint32_t colorAttachment
VkRect2D rect
uint32_t layerCount
uint32_t baseArrayLayer
uint32_t width
uint32_t height
VkExtent2D extent
VkOffset2D offset
VkClearColorValue color
VkClearDepthStencilValue depthStencil
VkFlags VkPipelineStageFlags
@ VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
@ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
@ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
@ VK_IMAGE_LAYOUT_GENERAL
VkFlags VkAccessFlags
@ VK_IMAGE_ASPECT_COLOR_BIT
@ VK_IMAGE_ASPECT_STENCIL_BIT
@ VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT
@ VK_ACCESS_INPUT_ATTACHMENT_READ_BIT
@ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
@ VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
@ VK_ACCESS_SHADER_READ_BIT
@ VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
VkAttachmentLoadOp
@ VK_ATTACHMENT_LOAD_OP_CLEAR
@ VK_ATTACHMENT_LOAD_OP_LOAD
@ VK_ATTACHMENT_LOAD_OP_DONT_CARE
VkAttachmentStoreOp
@ VK_ATTACHMENT_STORE_OP_DONT_CARE
@ VK_ATTACHMENT_STORE_OP_STORE
@ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
@ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
@ VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT