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 "GrVkGpuCommandBuffer.h"
9
10#include "GrFixedClip.h"
11#include "GrMesh.h"
12#include "GrOpFlushState.h"
13#include "GrPipeline.h"
14#include "GrRenderTargetPriv.h"
15#include "GrTexturePriv.h"
16#include "GrVkCommandBuffer.h"
17#include "GrVkGpu.h"
18#include "GrVkPipeline.h"
19#include "GrVkRenderPass.h"
20#include "GrVkRenderTarget.h"
21#include "GrVkResourceProvider.h"
22#include "GrVkTexture.h"
23#include "SkRect.h"
24
25void get_vk_load_store_ops(const GrGpuCommandBuffer::LoadAndStoreInfo& info,
26                           VkAttachmentLoadOp* loadOp, VkAttachmentStoreOp* storeOp) {
27    switch (info.fLoadOp) {
28        case GrGpuCommandBuffer::LoadOp::kLoad:
29            *loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
30            break;
31        case GrGpuCommandBuffer::LoadOp::kClear:
32            *loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
33            break;
34        case GrGpuCommandBuffer::LoadOp::kDiscard:
35            *loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
36            break;
37        default:
38            SK_ABORT("Invalid LoadOp");
39            *loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
40    }
41
42    switch (info.fStoreOp) {
43        case GrGpuCommandBuffer::StoreOp::kStore:
44            *storeOp = VK_ATTACHMENT_STORE_OP_STORE;
45            break;
46        case GrGpuCommandBuffer::StoreOp::kDiscard:
47            *storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
48            break;
49        default:
50            SK_ABORT("Invalid StoreOp");
51            *storeOp = VK_ATTACHMENT_STORE_OP_STORE;
52    }
53}
54
55GrVkGpuCommandBuffer::GrVkGpuCommandBuffer(GrVkGpu* gpu,
56                                           const LoadAndStoreInfo& colorInfo,
57                                           const LoadAndStoreInfo& stencilInfo)
58    : fGpu(gpu)
59    , fRenderTarget(nullptr)
60    , fClearColor(GrColor4f::FromGrColor(colorInfo.fClearColor))
61    , fLastPipelineState(nullptr) {
62
63    get_vk_load_store_ops(colorInfo, &fVkColorLoadOp, &fVkColorStoreOp);
64
65    get_vk_load_store_ops(stencilInfo, &fVkStencilLoadOp, &fVkStencilStoreOp);
66
67    fCurrentCmdInfo = -1;
68}
69
70void GrVkGpuCommandBuffer::init(GrVkRenderTarget* target) {
71    SkASSERT(!fRenderTarget);
72    fRenderTarget = target;
73
74    GrVkRenderPass::LoadStoreOps vkColorOps(fVkColorLoadOp, fVkColorStoreOp);
75    GrVkRenderPass::LoadStoreOps vkStencilOps(fVkStencilLoadOp, fVkStencilStoreOp);
76
77    CommandBufferInfo& cbInfo = fCommandBufferInfos.push_back();
78    SkASSERT(fCommandBufferInfos.count() == 1);
79    fCurrentCmdInfo = 0;
80
81    const GrVkResourceProvider::CompatibleRPHandle& rpHandle = target->compatibleRenderPassHandle();
82    if (rpHandle.isValid()) {
83        cbInfo.fRenderPass = fGpu->resourceProvider().findRenderPass(rpHandle,
84                                                                     vkColorOps,
85                                                                     vkStencilOps);
86    } else {
87        cbInfo.fRenderPass = fGpu->resourceProvider().findRenderPass(*target,
88                                                                     vkColorOps,
89                                                                     vkStencilOps);
90    }
91
92    cbInfo.fColorClearValue.color.float32[0] = fClearColor.fRGBA[0];
93    cbInfo.fColorClearValue.color.float32[1] = fClearColor.fRGBA[1];
94    cbInfo.fColorClearValue.color.float32[2] = fClearColor.fRGBA[2];
95    cbInfo.fColorClearValue.color.float32[3] = fClearColor.fRGBA[3];
96
97    cbInfo.fBounds.setEmpty();
98    cbInfo.fIsEmpty = true;
99    cbInfo.fStartsWithClear = false;
100
101    cbInfo.fCommandBuffers.push_back(fGpu->resourceProvider().findOrCreateSecondaryCommandBuffer());
102    cbInfo.currentCmdBuf()->begin(fGpu, target->framebuffer(), cbInfo.fRenderPass);
103}
104
105
106GrVkGpuCommandBuffer::~GrVkGpuCommandBuffer() {
107    for (int i = 0; i < fCommandBufferInfos.count(); ++i) {
108        CommandBufferInfo& cbInfo = fCommandBufferInfos[i];
109        for (int j = 0; j < cbInfo.fCommandBuffers.count(); ++j) {
110            cbInfo.fCommandBuffers[j]->unref(fGpu);
111        }
112        cbInfo.fRenderPass->unref(fGpu);
113    }
114}
115
116GrGpu* GrVkGpuCommandBuffer::gpu() { return fGpu; }
117GrRenderTarget* GrVkGpuCommandBuffer::renderTarget() { return fRenderTarget; }
118
119void GrVkGpuCommandBuffer::end() {
120    if (fCurrentCmdInfo >= 0) {
121        fCommandBufferInfos[fCurrentCmdInfo].currentCmdBuf()->end(fGpu);
122    }
123}
124
125void GrVkGpuCommandBuffer::onSubmit() {
126    if (!fRenderTarget) {
127        return;
128    }
129    // Change layout of our render target so it can be used as the color attachment. Currently
130    // we don't attach the resolve to the framebuffer so no need to change its layout.
131    GrVkImage* targetImage = fRenderTarget->msaaImage() ? fRenderTarget->msaaImage()
132                                                        : fRenderTarget;
133
134    // Change layout of our render target so it can be used as the color attachment
135    targetImage->setImageLayout(fGpu,
136                                VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
137                                VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
138                                VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
139                                false);
140
141    // If we are using a stencil attachment we also need to update its layout
142    if (GrStencilAttachment* stencil = fRenderTarget->renderTargetPriv().getStencilAttachment()) {
143        GrVkStencilAttachment* vkStencil = (GrVkStencilAttachment*)stencil;
144        vkStencil->setImageLayout(fGpu,
145                                  VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
146                                  VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
147                                  VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT,
148                                  VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
149                                  false);
150    }
151
152    for (int i = 0; i < fCommandBufferInfos.count(); ++i) {
153        CommandBufferInfo& cbInfo = fCommandBufferInfos[i];
154
155        for (int j = 0; j < cbInfo.fPreDrawUploads.count(); ++j) {
156            InlineUploadInfo& iuInfo = cbInfo.fPreDrawUploads[j];
157            iuInfo.fFlushState->doUpload(iuInfo.fUpload);
158        }
159
160        // TODO: We can't add this optimization yet since many things create a scratch texture which
161        // adds the discard immediately, but then don't draw to it right away. This causes the
162        // discard to be ignored and we get yelled at for loading uninitialized data. However, once
163        // MDP lands, the discard will get reordered with the rest of the draw commands and we can
164        // re-enable this.
165#if 0
166        if (cbInfo.fIsEmpty && !cbInfo.fStartsWithClear) {
167            // We have sumbitted no actual draw commands to the command buffer and we are not using
168            // the render pass to do a clear so there is no need to submit anything.
169            continue;
170        }
171#endif
172        if (cbInfo.fBounds.intersect(0, 0,
173                                     SkIntToScalar(fRenderTarget->width()),
174                                     SkIntToScalar(fRenderTarget->height()))) {
175            SkIRect iBounds;
176            cbInfo.fBounds.roundOut(&iBounds);
177
178            fGpu->submitSecondaryCommandBuffer(cbInfo.fCommandBuffers, cbInfo.fRenderPass,
179                                               &cbInfo.fColorClearValue, fRenderTarget, iBounds);
180        }
181    }
182}
183
184void GrVkGpuCommandBuffer::discard(GrRenderTarget* rt) {
185    GrVkRenderTarget* target = static_cast<GrVkRenderTarget*>(rt);
186    if (!fRenderTarget) {
187        this->init(target);
188    }
189    SkASSERT(target == fRenderTarget);
190
191    CommandBufferInfo& cbInfo = fCommandBufferInfos[fCurrentCmdInfo];
192    if (cbInfo.fIsEmpty) {
193        // We will change the render pass to do a clear load instead
194        GrVkRenderPass::LoadStoreOps vkColorOps(VK_ATTACHMENT_LOAD_OP_DONT_CARE,
195                                                VK_ATTACHMENT_STORE_OP_STORE);
196        GrVkRenderPass::LoadStoreOps vkStencilOps(VK_ATTACHMENT_LOAD_OP_DONT_CARE,
197                                                  VK_ATTACHMENT_STORE_OP_STORE);
198
199        const GrVkRenderPass* oldRP = cbInfo.fRenderPass;
200
201        const GrVkResourceProvider::CompatibleRPHandle& rpHandle =
202            fRenderTarget->compatibleRenderPassHandle();
203        if (rpHandle.isValid()) {
204            cbInfo.fRenderPass = fGpu->resourceProvider().findRenderPass(rpHandle,
205                                                                         vkColorOps,
206                                                                         vkStencilOps);
207        } else {
208            cbInfo.fRenderPass = fGpu->resourceProvider().findRenderPass(*fRenderTarget,
209                                                                         vkColorOps,
210                                                                         vkStencilOps);
211        }
212
213        SkASSERT(cbInfo.fRenderPass->isCompatible(*oldRP));
214        oldRP->unref(fGpu);
215        cbInfo.fBounds.join(fRenderTarget->getBoundsRect());
216        cbInfo.fStartsWithClear = false;
217    }
218}
219
220void GrVkGpuCommandBuffer::onClearStencilClip(GrRenderTarget* rt, const GrFixedClip& clip,
221                                              bool insideStencilMask) {
222    SkASSERT(!clip.hasWindowRectangles());
223
224    GrVkRenderTarget* target = static_cast<GrVkRenderTarget*>(rt);
225    if (!fRenderTarget) {
226        this->init(target);
227    }
228    SkASSERT(target == fRenderTarget);
229
230    CommandBufferInfo& cbInfo = fCommandBufferInfos[fCurrentCmdInfo];
231
232    GrStencilAttachment* sb = fRenderTarget->renderTargetPriv().getStencilAttachment();
233    // this should only be called internally when we know we have a
234    // stencil buffer.
235    SkASSERT(sb);
236    int stencilBitCount = sb->bits();
237
238    // The contract with the callers does not guarantee that we preserve all bits in the stencil
239    // during this clear. Thus we will clear the entire stencil to the desired value.
240
241    VkClearDepthStencilValue vkStencilColor;
242    memset(&vkStencilColor, 0, sizeof(VkClearDepthStencilValue));
243    if (insideStencilMask) {
244        vkStencilColor.stencil = (1 << (stencilBitCount - 1));
245    } else {
246        vkStencilColor.stencil = 0;
247    }
248
249    VkClearRect clearRect;
250    // Flip rect if necessary
251    SkIRect vkRect;
252    if (!clip.scissorEnabled()) {
253        vkRect.setXYWH(0, 0, fRenderTarget->width(), fRenderTarget->height());
254    } else if (kBottomLeft_GrSurfaceOrigin != fRenderTarget->origin()) {
255        vkRect = clip.scissorRect();
256    } else {
257        const SkIRect& scissor = clip.scissorRect();
258        vkRect.setLTRB(scissor.fLeft, fRenderTarget->height() - scissor.fBottom,
259                       scissor.fRight, fRenderTarget->height() - scissor.fTop);
260    }
261
262    clearRect.rect.offset = { vkRect.fLeft, vkRect.fTop };
263    clearRect.rect.extent = { (uint32_t)vkRect.width(), (uint32_t)vkRect.height() };
264
265    clearRect.baseArrayLayer = 0;
266    clearRect.layerCount = 1;
267
268    uint32_t stencilIndex;
269    SkAssertResult(cbInfo.fRenderPass->stencilAttachmentIndex(&stencilIndex));
270
271    VkClearAttachment attachment;
272    attachment.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
273    attachment.colorAttachment = 0; // this value shouldn't matter
274    attachment.clearValue.depthStencil = vkStencilColor;
275
276    cbInfo.currentCmdBuf()->clearAttachments(fGpu, 1, &attachment, 1, &clearRect);
277    cbInfo.fIsEmpty = false;
278
279    // Update command buffer bounds
280    if (!clip.scissorEnabled()) {
281        cbInfo.fBounds.join(fRenderTarget->getBoundsRect());
282    } else {
283        cbInfo.fBounds.join(SkRect::Make(clip.scissorRect()));
284    }
285}
286
287void GrVkGpuCommandBuffer::onClear(GrRenderTarget* rt, const GrFixedClip& clip, GrColor color) {
288    // parent class should never let us get here with no RT
289    SkASSERT(!clip.hasWindowRectangles());
290
291    GrVkRenderTarget* target = static_cast<GrVkRenderTarget*>(rt);
292    if (!fRenderTarget) {
293        this->init(target);
294    }
295    SkASSERT(target == fRenderTarget);
296
297    CommandBufferInfo& cbInfo = fCommandBufferInfos[fCurrentCmdInfo];
298
299    VkClearColorValue vkColor;
300    GrColorToRGBAFloat(color, vkColor.float32);
301
302    if (cbInfo.fIsEmpty && !clip.scissorEnabled()) {
303        // We will change the render pass to do a clear load instead
304        GrVkRenderPass::LoadStoreOps vkColorOps(VK_ATTACHMENT_LOAD_OP_CLEAR,
305                                                VK_ATTACHMENT_STORE_OP_STORE);
306        GrVkRenderPass::LoadStoreOps vkStencilOps(VK_ATTACHMENT_LOAD_OP_LOAD,
307                                                  VK_ATTACHMENT_STORE_OP_STORE);
308
309        const GrVkRenderPass* oldRP = cbInfo.fRenderPass;
310
311        const GrVkResourceProvider::CompatibleRPHandle& rpHandle =
312            fRenderTarget->compatibleRenderPassHandle();
313        if (rpHandle.isValid()) {
314            cbInfo.fRenderPass = fGpu->resourceProvider().findRenderPass(rpHandle,
315                                                                         vkColorOps,
316                                                                         vkStencilOps);
317        } else {
318            cbInfo.fRenderPass = fGpu->resourceProvider().findRenderPass(*fRenderTarget,
319                                                                         vkColorOps,
320                                                                         vkStencilOps);
321        }
322
323        SkASSERT(cbInfo.fRenderPass->isCompatible(*oldRP));
324        oldRP->unref(fGpu);
325
326        GrColorToRGBAFloat(color, cbInfo.fColorClearValue.color.float32);
327        cbInfo.fStartsWithClear = true;
328
329        // Update command buffer bounds
330        cbInfo.fBounds.join(fRenderTarget->getBoundsRect());
331        return;
332    }
333
334    // We always do a sub rect clear with clearAttachments since we are inside a render pass
335    VkClearRect clearRect;
336    // Flip rect if necessary
337    SkIRect vkRect;
338    if (!clip.scissorEnabled()) {
339        vkRect.setXYWH(0, 0, fRenderTarget->width(), fRenderTarget->height());
340    } else if (kBottomLeft_GrSurfaceOrigin != fRenderTarget->origin()) {
341        vkRect = clip.scissorRect();
342    } else {
343        const SkIRect& scissor = clip.scissorRect();
344        vkRect.setLTRB(scissor.fLeft, fRenderTarget->height() - scissor.fBottom,
345                       scissor.fRight, fRenderTarget->height() - scissor.fTop);
346    }
347    clearRect.rect.offset = { vkRect.fLeft, vkRect.fTop };
348    clearRect.rect.extent = { (uint32_t)vkRect.width(), (uint32_t)vkRect.height() };
349    clearRect.baseArrayLayer = 0;
350    clearRect.layerCount = 1;
351
352    uint32_t colorIndex;
353    SkAssertResult(cbInfo.fRenderPass->colorAttachmentIndex(&colorIndex));
354
355    VkClearAttachment attachment;
356    attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
357    attachment.colorAttachment = colorIndex;
358    attachment.clearValue.color = vkColor;
359
360    cbInfo.currentCmdBuf()->clearAttachments(fGpu, 1, &attachment, 1, &clearRect);
361    cbInfo.fIsEmpty = false;
362
363    // Update command buffer bounds
364    if (!clip.scissorEnabled()) {
365        cbInfo.fBounds.join(fRenderTarget->getBoundsRect());
366    } else {
367        cbInfo.fBounds.join(SkRect::Make(clip.scissorRect()));
368    }
369    return;
370}
371
372void GrVkGpuCommandBuffer::addAdditionalCommandBuffer() {
373    CommandBufferInfo& cbInfo = fCommandBufferInfos[fCurrentCmdInfo];
374    cbInfo.currentCmdBuf()->end(fGpu);
375    cbInfo.fCommandBuffers.push_back(fGpu->resourceProvider().findOrCreateSecondaryCommandBuffer());
376    cbInfo.currentCmdBuf()->begin(fGpu, fRenderTarget->framebuffer(), cbInfo.fRenderPass);
377}
378
379void GrVkGpuCommandBuffer::addAdditionalRenderPass() {
380    fCommandBufferInfos[fCurrentCmdInfo].currentCmdBuf()->end(fGpu);
381
382    CommandBufferInfo& cbInfo = fCommandBufferInfos.push_back();
383    fCurrentCmdInfo++;
384
385    GrVkRenderPass::LoadStoreOps vkColorOps(VK_ATTACHMENT_LOAD_OP_LOAD,
386                                            VK_ATTACHMENT_STORE_OP_STORE);
387    GrVkRenderPass::LoadStoreOps vkStencilOps(VK_ATTACHMENT_LOAD_OP_LOAD,
388                                              VK_ATTACHMENT_STORE_OP_STORE);
389
390    const GrVkResourceProvider::CompatibleRPHandle& rpHandle =
391            fRenderTarget->compatibleRenderPassHandle();
392    if (rpHandle.isValid()) {
393        cbInfo.fRenderPass = fGpu->resourceProvider().findRenderPass(rpHandle,
394                                                                     vkColorOps,
395                                                                     vkStencilOps);
396    } else {
397        cbInfo.fRenderPass = fGpu->resourceProvider().findRenderPass(*fRenderTarget,
398                                                                     vkColorOps,
399                                                                     vkStencilOps);
400    }
401
402    cbInfo.fCommandBuffers.push_back(fGpu->resourceProvider().findOrCreateSecondaryCommandBuffer());
403    // It shouldn't matter what we set the clear color to here since we will assume loading of the
404    // attachment.
405    memset(&cbInfo.fColorClearValue, 0, sizeof(VkClearValue));
406    cbInfo.fBounds.setEmpty();
407    cbInfo.fIsEmpty = true;
408    cbInfo.fStartsWithClear = false;
409
410    cbInfo.currentCmdBuf()->begin(fGpu, fRenderTarget->framebuffer(), cbInfo.fRenderPass);
411}
412
413void GrVkGpuCommandBuffer::inlineUpload(GrOpFlushState* state, GrDrawOp::DeferredUploadFn& upload,
414                                        GrRenderTarget* rt) {
415    GrVkRenderTarget* target = static_cast<GrVkRenderTarget*>(rt);
416    if (!fRenderTarget) {
417        this->init(target);
418    }
419    if (!fCommandBufferInfos[fCurrentCmdInfo].fIsEmpty) {
420        this->addAdditionalRenderPass();
421    }
422    fCommandBufferInfos[fCurrentCmdInfo].fPreDrawUploads.emplace_back(state, upload);
423}
424
425////////////////////////////////////////////////////////////////////////////////
426
427void GrVkGpuCommandBuffer::bindGeometry(const GrPrimitiveProcessor& primProc,
428                                        const GrNonInstancedMesh& mesh) {
429    CommandBufferInfo& cbInfo = fCommandBufferInfos[fCurrentCmdInfo];
430    // There is no need to put any memory barriers to make sure host writes have finished here.
431    // When a command buffer is submitted to a queue, there is an implicit memory barrier that
432    // occurs for all host writes. Additionally, BufferMemoryBarriers are not allowed inside of
433    // an active RenderPass.
434    SkASSERT(!mesh.vertexBuffer()->isCPUBacked());
435    GrVkVertexBuffer* vbuf;
436    vbuf = (GrVkVertexBuffer*)mesh.vertexBuffer();
437    SkASSERT(vbuf);
438    SkASSERT(!vbuf->isMapped());
439
440    cbInfo.currentCmdBuf()->bindVertexBuffer(fGpu, vbuf);
441
442    if (mesh.isIndexed()) {
443        SkASSERT(!mesh.indexBuffer()->isCPUBacked());
444        GrVkIndexBuffer* ibuf = (GrVkIndexBuffer*)mesh.indexBuffer();
445        SkASSERT(ibuf);
446        SkASSERT(!ibuf->isMapped());
447
448        cbInfo.currentCmdBuf()->bindIndexBuffer(fGpu, ibuf);
449    }
450}
451
452sk_sp<GrVkPipelineState> GrVkGpuCommandBuffer::prepareDrawState(
453                                                               const GrPipeline& pipeline,
454                                                               const GrPrimitiveProcessor& primProc,
455                                                               GrPrimitiveType primitiveType) {
456    CommandBufferInfo& cbInfo = fCommandBufferInfos[fCurrentCmdInfo];
457    SkASSERT(cbInfo.fRenderPass);
458
459    sk_sp<GrVkPipelineState> pipelineState =
460        fGpu->resourceProvider().findOrCreateCompatiblePipelineState(pipeline,
461                                                                     primProc,
462                                                                     primitiveType,
463                                                                     *cbInfo.fRenderPass);
464    if (!pipelineState) {
465        return pipelineState;
466    }
467
468    if (!cbInfo.fIsEmpty &&
469        fLastPipelineState && fLastPipelineState != pipelineState.get() &&
470        fGpu->vkCaps().newSecondaryCBOnPipelineChange()) {
471        this->addAdditionalCommandBuffer();
472    }
473    fLastPipelineState = pipelineState.get();
474
475    pipelineState->setData(fGpu, primProc, pipeline);
476
477    pipelineState->bind(fGpu, cbInfo.currentCmdBuf());
478
479    GrVkPipeline::SetDynamicState(fGpu, cbInfo.currentCmdBuf(), pipeline);
480
481    return pipelineState;
482}
483
484static void prepare_sampled_images(const GrProcessor& processor, GrVkGpu* gpu) {
485    for (int i = 0; i < processor.numTextureSamplers(); ++i) {
486        const GrProcessor::TextureSampler& sampler = processor.textureSampler(i);
487        GrVkTexture* vkTexture = static_cast<GrVkTexture*>(sampler.texture());
488        SkASSERT(vkTexture);
489
490        // We may need to resolve the texture first if it is also a render target
491        GrVkRenderTarget* texRT = static_cast<GrVkRenderTarget*>(vkTexture->asRenderTarget());
492        if (texRT) {
493            gpu->onResolveRenderTarget(texRT);
494        }
495
496        const GrSamplerParams& params = sampler.params();
497        // Check if we need to regenerate any mip maps
498        if (GrSamplerParams::kMipMap_FilterMode == params.filterMode()) {
499            if (vkTexture->texturePriv().mipMapsAreDirty()) {
500                gpu->generateMipmap(vkTexture);
501                vkTexture->texturePriv().dirtyMipMaps(false);
502            }
503        }
504
505        // TODO: If we ever decide to create the secondary command buffers ahead of time before we
506        // are actually going to submit them, we will need to track the sampled images and delay
507        // adding the layout change/barrier until we are ready to submit.
508        vkTexture->setImageLayout(gpu,
509                                  VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
510                                  VK_ACCESS_SHADER_READ_BIT,
511                                  VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
512                                  false);
513    }
514}
515
516void GrVkGpuCommandBuffer::onDraw(const GrPipeline& pipeline,
517                                  const GrPrimitiveProcessor& primProc,
518                                  const GrMesh* meshes,
519                                  int meshCount,
520                                  const SkRect& bounds) {
521    GrVkRenderTarget* target = static_cast<GrVkRenderTarget*>(pipeline.getRenderTarget());
522    if (!fRenderTarget) {
523        this->init(target);
524    }
525    SkASSERT(target == fRenderTarget);
526
527    if (!meshCount) {
528        return;
529    }
530    prepare_sampled_images(primProc, fGpu);
531    GrFragmentProcessor::Iter iter(pipeline);
532    while (const GrFragmentProcessor* fp = iter.next()) {
533        prepare_sampled_images(*fp, fGpu);
534    }
535    prepare_sampled_images(pipeline.getXferProcessor(), fGpu);
536
537    GrPrimitiveType primitiveType = meshes[0].primitiveType();
538    sk_sp<GrVkPipelineState> pipelineState = this->prepareDrawState(pipeline,
539                                                                    primProc,
540                                                                    primitiveType);
541    if (!pipelineState) {
542        return;
543    }
544
545    CommandBufferInfo& cbInfo = fCommandBufferInfos[fCurrentCmdInfo];
546
547    for (int i = 0; i < meshCount; ++i) {
548        const GrMesh& mesh = meshes[i];
549        GrMesh::Iterator iter;
550        const GrNonInstancedMesh* nonIdxMesh = iter.init(mesh);
551        do {
552            if (nonIdxMesh->primitiveType() != primitiveType) {
553                // Technically we don't have to call this here (since there is a safety check in
554                // pipelineState:setData but this will allow for quicker freeing of resources if the
555                // pipelineState sits in a cache for a while.
556                pipelineState->freeTempResources(fGpu);
557                SkDEBUGCODE(pipelineState = nullptr);
558                primitiveType = nonIdxMesh->primitiveType();
559                pipelineState = this->prepareDrawState(pipeline,
560                                                       primProc,
561                                                       primitiveType);
562                if (!pipelineState) {
563                    return;
564                }
565            }
566            SkASSERT(pipelineState);
567            this->bindGeometry(primProc, *nonIdxMesh);
568
569            if (nonIdxMesh->isIndexed()) {
570                cbInfo.currentCmdBuf()->drawIndexed(fGpu,
571                                                   nonIdxMesh->indexCount(),
572                                                   1,
573                                                   nonIdxMesh->startIndex(),
574                                                   nonIdxMesh->startVertex(),
575                                                   0);
576            } else {
577                cbInfo.currentCmdBuf()->draw(fGpu,
578                                            nonIdxMesh->vertexCount(),
579                                            1,
580                                            nonIdxMesh->startVertex(),
581                                            0);
582            }
583            cbInfo.fIsEmpty = false;
584
585            fGpu->stats()->incNumDraws();
586        } while ((nonIdxMesh = iter.next()));
587    }
588
589    // Update command buffer bounds
590    cbInfo.fBounds.join(bounds);
591
592    // Technically we don't have to call this here (since there is a safety check in
593    // pipelineState:setData but this will allow for quicker freeing of resources if the
594    // pipelineState sits in a cache for a while.
595    pipelineState->freeTempResources(fGpu);
596}
597
598