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