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