• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2015 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "src/gpu/vk/GrVkRenderTarget.h"
9 
10 #include "include/gpu/GrBackendSurface.h"
11 #include "include/gpu/GrDirectContext.h"
12 #include "src/gpu/GrBackendSurfaceMutableStateImpl.h"
13 #include "src/gpu/GrDirectContextPriv.h"
14 #include "src/gpu/GrResourceProvider.h"
15 #include "src/gpu/vk/GrVkAttachment.h"
16 #include "src/gpu/vk/GrVkCommandBuffer.h"
17 #include "src/gpu/vk/GrVkDescriptorSet.h"
18 #include "src/gpu/vk/GrVkFramebuffer.h"
19 #include "src/gpu/vk/GrVkGpu.h"
20 #include "src/gpu/vk/GrVkImageView.h"
21 #include "src/gpu/vk/GrVkResourceProvider.h"
22 #include "src/gpu/vk/GrVkUtil.h"
23 
24 #include "include/gpu/vk/GrVkTypes.h"
25 
26 #define VK_CALL(GPU, X) GR_VK_CALL(GPU->vkInterface(), X)
27 
renderpass_features_to_index(bool hasResolve,bool hasStencil,GrVkRenderPass::SelfDependencyFlags selfDepFlags,GrVkRenderPass::LoadFromResolve loadFromReslove)28 static int renderpass_features_to_index(bool hasResolve, bool hasStencil,
29                                         GrVkRenderPass::SelfDependencyFlags selfDepFlags,
30                                         GrVkRenderPass::LoadFromResolve loadFromReslove) {
31     int index = 0;
32     if (hasResolve) {
33         index += 1;
34     }
35     if (hasStencil) {
36         index += 2;
37     }
38     if (selfDepFlags & GrVkRenderPass::SelfDependencyFlags::kForInputAttachment) {
39         index += 4;
40     }
41     if (selfDepFlags & GrVkRenderPass::SelfDependencyFlags::kForNonCoherentAdvBlend) {
42         index += 8;
43     }
44     if (loadFromReslove == GrVkRenderPass::LoadFromResolve::kLoad) {
45         index += 16;
46     }
47     return index;
48 }
49 
50 // We're virtually derived from GrSurface (via GrRenderTarget) so its
51 // constructor must be explicitly called.
GrVkRenderTarget(GrVkGpu * gpu,SkISize dimensions,sk_sp<GrVkAttachment> colorAttachment,sk_sp<GrVkAttachment> resolveAttachment,CreateType createType)52 GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu,
53                                    SkISize dimensions,
54                                    sk_sp<GrVkAttachment> colorAttachment,
55                                    sk_sp<GrVkAttachment> resolveAttachment,
56                                    CreateType createType)
57         : GrSurface(gpu, dimensions,
58                     colorAttachment->isProtected() ? GrProtected::kYes : GrProtected::kNo)
59         // for the moment we only support 1:1 color to stencil
60         , GrRenderTarget(gpu, dimensions, colorAttachment->numSamples(),
61                          colorAttachment->isProtected() ? GrProtected::kYes : GrProtected::kNo)
62         , fColorAttachment(std::move(colorAttachment))
63         , fResolveAttachment(std::move(resolveAttachment))
64         , fCachedFramebuffers() {
65     SkASSERT(fColorAttachment);
66     SkASSERT(!resolveAttachment ||
67              (fResolveAttachment->isProtected() == fColorAttachment->isProtected()));
68     SkASSERT(SkToBool(fColorAttachment->vkUsageFlags() & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT));
69     this->setFlags();
70     if (createType == CreateType::kDirectlyWrapped) {
71         this->registerWithCacheWrapped(GrWrapCacheable::kNo);
72     }
73 }
74 
GrVkRenderTarget(GrVkGpu * gpu,SkISize dimensions,sk_sp<GrVkFramebuffer> externalFramebuffer)75 GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu,
76                                    SkISize dimensions,
77                                    sk_sp<GrVkFramebuffer> externalFramebuffer)
78         : GrSurface(gpu, dimensions,
79                     externalFramebuffer->colorAttachment()->isProtected() ? GrProtected::kYes
80                                                                           : GrProtected::kNo)
81         , GrRenderTarget(gpu, dimensions, 1,
82                          externalFramebuffer->colorAttachment()->isProtected() ? GrProtected::kYes
83                                                                                : GrProtected::kNo)
84         , fCachedFramebuffers()
85         , fExternalFramebuffer(externalFramebuffer) {
86     SkASSERT(fExternalFramebuffer);
87     SkASSERT(!fColorAttachment);
88     SkDEBUGCODE(auto colorAttachment = fExternalFramebuffer->colorAttachment());
89     SkASSERT(colorAttachment);
90     SkASSERT(colorAttachment->numSamples() == 1);
91     SkASSERT(SkToBool(colorAttachment->vkUsageFlags() & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT));
92     SkASSERT(!SkToBool(colorAttachment->vkUsageFlags() & VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT));
93     this->setFlags();
94     this->registerWithCacheWrapped(GrWrapCacheable::kNo);
95 }
96 
setFlags()97 void GrVkRenderTarget::setFlags() {
98     if (this->wrapsSecondaryCommandBuffer()) {
99         return;
100     }
101     GrVkAttachment* nonMSAAAttachment = this->nonMSAAAttachment();
102     if (nonMSAAAttachment && nonMSAAAttachment->supportsInputAttachmentUsage()) {
103         this->setVkRTSupportsInputAttachment();
104     }
105 }
106 
MakeWrappedRenderTarget(GrVkGpu * gpu,SkISize dimensions,int sampleCnt,const GrVkImageInfo & info,sk_sp<GrBackendSurfaceMutableStateImpl> mutableState)107 sk_sp<GrVkRenderTarget> GrVkRenderTarget::MakeWrappedRenderTarget(
108         GrVkGpu* gpu,
109         SkISize dimensions,
110         int sampleCnt,
111         const GrVkImageInfo& info,
112         sk_sp<GrBackendSurfaceMutableStateImpl> mutableState) {
113     SkASSERT(VK_NULL_HANDLE != info.fImage);
114     SkASSERT(1 == info.fLevelCount);
115     SkASSERT(sampleCnt >= 1 && info.fSampleCount >= 1);
116 
117     int wrappedImageSampleCnt = static_cast<int>(info.fSampleCount);
118     if (sampleCnt != wrappedImageSampleCnt && wrappedImageSampleCnt != 1) {
119         return nullptr;
120     }
121 
122     sk_sp<GrVkAttachment> wrappedAttachment =
123             GrVkAttachment::MakeWrapped(gpu, dimensions, info, std::move(mutableState),
124                                         GrAttachment::UsageFlags::kColorAttachment,
125                                         kBorrow_GrWrapOwnership, GrWrapCacheable::kNo);
126     if (!wrappedAttachment) {
127         return nullptr;
128     }
129 
130     sk_sp<GrVkAttachment> colorAttachment;
131     colorAttachment = std::move(wrappedAttachment);
132 
133      if (!colorAttachment) {
134         return nullptr;
135     }
136 
137     GrVkRenderTarget* vkRT = new GrVkRenderTarget(gpu, dimensions, std::move(colorAttachment),
138                                                   nullptr, CreateType::kDirectlyWrapped);
139     return sk_sp<GrVkRenderTarget>(vkRT);
140 }
141 
MakeSecondaryCBRenderTarget(GrVkGpu * gpu,SkISize dimensions,const GrVkDrawableInfo & vkInfo)142 sk_sp<GrVkRenderTarget> GrVkRenderTarget::MakeSecondaryCBRenderTarget(
143         GrVkGpu* gpu, SkISize dimensions, const GrVkDrawableInfo& vkInfo) {
144     const GrVkRenderPass* rp = gpu->resourceProvider().findCompatibleExternalRenderPass(
145             vkInfo.fCompatibleRenderPass, vkInfo.fColorAttachmentIndex);
146     if (!rp) {
147         return nullptr;
148     }
149 
150     if (vkInfo.fSecondaryCommandBuffer == VK_NULL_HANDLE) {
151         return nullptr;
152     }
153 
154     // We only set the few properties of the GrVkImageInfo that we know like layout and format. The
155     // others we keep at the default "null" values.
156     GrVkImageInfo info;
157     info.fImageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
158     info.fFormat = vkInfo.fFormat;
159     info.fImageUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
160                             VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
161 
162     sk_sp<GrBackendSurfaceMutableStateImpl> mutableState(new GrBackendSurfaceMutableStateImpl(
163             VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_QUEUE_FAMILY_IGNORED));
164 
165     sk_sp<GrVkAttachment> colorAttachment =
166         GrVkAttachment::MakeWrapped(gpu, dimensions, info, std::move(mutableState),
167                                     GrAttachment::UsageFlags::kColorAttachment,
168                                     kBorrow_GrWrapOwnership, GrWrapCacheable::kNo, true);
169 
170     std::unique_ptr<GrVkSecondaryCommandBuffer> scb(
171             GrVkSecondaryCommandBuffer::Create(vkInfo.fSecondaryCommandBuffer, rp));
172     if (!scb) {
173         return nullptr;
174     }
175 
176     sk_sp<GrVkFramebuffer> framebuffer(new GrVkFramebuffer(
177             gpu, std::move(colorAttachment), sk_sp<const GrVkRenderPass>(rp),
178             std::move(scb)));
179 
180     GrVkRenderTarget* vkRT = new GrVkRenderTarget(gpu, dimensions, std::move(framebuffer));
181 
182     return sk_sp<GrVkRenderTarget>(vkRT);
183 }
184 
backendFormat() const185 GrBackendFormat GrVkRenderTarget::backendFormat() const {
186     if (this->wrapsSecondaryCommandBuffer()) {
187         return fExternalFramebuffer->colorAttachment()->getBackendFormat();
188     }
189     return fColorAttachment->getBackendFormat();
190 }
191 
nonMSAAAttachment() const192 GrVkAttachment* GrVkRenderTarget::nonMSAAAttachment() const {
193     if (fColorAttachment->numSamples() == 1) {
194         return fColorAttachment.get();
195     } else {
196         return fResolveAttachment.get();
197     }
198 }
199 
dynamicMSAAAttachment()200 GrVkAttachment* GrVkRenderTarget::dynamicMSAAAttachment() {
201     if (fDynamicMSAAAttachment) {
202         return fDynamicMSAAAttachment.get();
203     }
204     const GrVkAttachment* nonMSAAColorAttachment = this->colorAttachment();
205     SkASSERT(nonMSAAColorAttachment->numSamples() == 1);
206 
207     GrVkGpu* gpu = this->getVkGpu();
208     auto rp = gpu->getContext()->priv().resourceProvider();
209 
210     const GrBackendFormat& format = nonMSAAColorAttachment->backendFormat();
211 
212     sk_sp<GrAttachment> msaaAttachment =
213             rp->makeMSAAAttachment(nonMSAAColorAttachment->dimensions(),
214                                    format,
215                                    gpu->caps()->internalMultisampleCount(format),
216                                    GrProtected(nonMSAAColorAttachment->isProtected()));
217     if (!msaaAttachment) {
218         return nullptr;
219     }
220     fDynamicMSAAAttachment =
221             sk_sp<GrVkAttachment>(static_cast<GrVkAttachment*>(msaaAttachment.release()));
222     return fDynamicMSAAAttachment.get();
223 }
224 
msaaAttachment()225 GrVkAttachment* GrVkRenderTarget::msaaAttachment() {
226     return this->colorAttachment()->numSamples() == 1 ? this->dynamicMSAAAttachment()
227                                                       : this->colorAttachment();
228 }
229 
completeStencilAttachment(GrAttachment * stencil,bool useMSAASurface)230 bool GrVkRenderTarget::completeStencilAttachment(GrAttachment* stencil, bool useMSAASurface) {
231     SkASSERT(!this->wrapsSecondaryCommandBuffer());
232     SkASSERT(useMSAASurface == (this->numSamples() > 1));
233     return true;
234 }
235 
externalFramebuffer() const236 sk_sp<GrVkFramebuffer> GrVkRenderTarget::externalFramebuffer() const {
237     return fExternalFramebuffer;
238 }
239 
compatibleRenderPassHandle(bool withResolve,bool withStencil,SelfDependencyFlags selfDepFlags,LoadFromResolve loadFromResolve)240 GrVkResourceProvider::CompatibleRPHandle GrVkRenderTarget::compatibleRenderPassHandle(
241         bool withResolve,
242         bool withStencil,
243         SelfDependencyFlags selfDepFlags,
244         LoadFromResolve loadFromResolve) {
245     SkASSERT(!this->wrapsSecondaryCommandBuffer());
246 
247     const GrVkFramebuffer* fb =
248             this->getFramebuffer(withResolve, withStencil, selfDepFlags, loadFromResolve);
249     if (!fb) {
250         return {};
251     }
252 
253     return fb->compatibleRenderPassHandle();
254 }
255 
getSimpleRenderPass(bool withResolve,bool withStencil,SelfDependencyFlags selfDepFlags,LoadFromResolve loadFromResolve)256 const GrVkRenderPass* GrVkRenderTarget::getSimpleRenderPass(bool withResolve,
257                                                             bool withStencil,
258                                                             SelfDependencyFlags selfDepFlags,
259                                                             LoadFromResolve loadFromResolve) {
260     if (this->wrapsSecondaryCommandBuffer()) {
261          return fExternalFramebuffer->externalRenderPass();
262     }
263 
264     const GrVkFramebuffer* fb =
265             this->getFramebuffer(withResolve, withStencil, selfDepFlags, loadFromResolve);
266     if (!fb) {
267         return nullptr;
268     }
269 
270     return fb->compatibleRenderPass();
271 }
272 
273 std::pair<const GrVkRenderPass*, GrVkResourceProvider::CompatibleRPHandle>
createSimpleRenderPass(bool withResolve,bool withStencil,SelfDependencyFlags selfDepFlags,LoadFromResolve loadFromResolve)274 GrVkRenderTarget::createSimpleRenderPass(bool withResolve,
275                                          bool withStencil,
276                                          SelfDependencyFlags selfDepFlags,
277                                          LoadFromResolve loadFromResolve) {
278     SkASSERT(!this->wrapsSecondaryCommandBuffer());
279 
280     GrVkResourceProvider& rp = this->getVkGpu()->resourceProvider();
281 
282     GrVkResourceProvider::CompatibleRPHandle handle;
283     const GrVkRenderPass* renderPass = rp.findCompatibleRenderPass(
284             this, &handle, withResolve, withStencil, selfDepFlags,
285             loadFromResolve);
286     SkASSERT(!renderPass || handle.isValid());
287     return {renderPass, handle};
288 }
289 
getFramebuffer(bool withResolve,bool withStencil,SelfDependencyFlags selfDepFlags,LoadFromResolve loadFromResolve)290 const GrVkFramebuffer* GrVkRenderTarget::getFramebuffer(bool withResolve,
291                                                         bool withStencil,
292                                                         SelfDependencyFlags selfDepFlags,
293                                                         LoadFromResolve loadFromResolve) {
294     int cacheIndex =
295             renderpass_features_to_index(withResolve, withStencil, selfDepFlags, loadFromResolve);
296     SkASSERT(cacheIndex < GrVkRenderTarget::kNumCachedFramebuffers);
297     if (auto fb = fCachedFramebuffers[cacheIndex]) {
298         return fb.get();
299     }
300 
301     this->createFramebuffer(withResolve, withStencil, selfDepFlags, loadFromResolve);
302     return fCachedFramebuffers[cacheIndex].get();
303 }
304 
createFramebuffer(bool withResolve,bool withStencil,SelfDependencyFlags selfDepFlags,LoadFromResolve loadFromResolve)305 void GrVkRenderTarget::createFramebuffer(bool withResolve,
306                                          bool withStencil,
307                                          SelfDependencyFlags selfDepFlags,
308                                          LoadFromResolve loadFromResolve) {
309     SkASSERT(!this->wrapsSecondaryCommandBuffer());
310     GrVkGpu* gpu = this->getVkGpu();
311 
312     auto[renderPass, compatibleHandle] =
313             this->createSimpleRenderPass(withResolve, withStencil, selfDepFlags, loadFromResolve);
314     if (!renderPass) {
315         return;
316     }
317     SkASSERT(compatibleHandle.isValid());
318 
319     int cacheIndex =
320             renderpass_features_to_index(withResolve, withStencil, selfDepFlags, loadFromResolve);
321     SkASSERT(cacheIndex < GrVkRenderTarget::kNumCachedFramebuffers);
322 
323     GrVkAttachment* resolve = withResolve ? this->resolveAttachment() : nullptr;
324     GrVkAttachment* colorAttachment =
325             withResolve ? this->msaaAttachment() : this->colorAttachment();
326 
327     // Stencil attachment view is stored in the base RT stencil attachment
328     GrVkAttachment* stencil =
329             withStencil ? static_cast<GrVkAttachment*>(this->getStencilAttachment())
330                         : nullptr;
331     fCachedFramebuffers[cacheIndex] =
332             GrVkFramebuffer::Make(gpu, this->dimensions(),
333                                   sk_sp<const GrVkRenderPass>(renderPass),
334                                   colorAttachment, resolve, stencil, compatibleHandle);
335 }
336 
getAttachmentsDescriptor(GrVkRenderPass::AttachmentsDescriptor * desc,GrVkRenderPass::AttachmentFlags * attachmentFlags,bool withResolve,bool withStencil)337 void GrVkRenderTarget::getAttachmentsDescriptor(GrVkRenderPass::AttachmentsDescriptor* desc,
338                                                 GrVkRenderPass::AttachmentFlags* attachmentFlags,
339                                                 bool withResolve,
340                                                 bool withStencil) {
341     SkASSERT(!this->wrapsSecondaryCommandBuffer());
342     const GrVkAttachment* colorAttachment =
343             withResolve ? this->msaaAttachment() : this->colorAttachment();
344 
345     desc->fColor.fFormat = colorAttachment->imageFormat();
346     desc->fColor.fSamples = colorAttachment->numSamples();
347     *attachmentFlags = GrVkRenderPass::kColor_AttachmentFlag;
348     uint32_t attachmentCount = 1;
349 
350     if (withResolve) {
351         desc->fResolve.fFormat = desc->fColor.fFormat;
352         desc->fResolve.fSamples = 1;
353         *attachmentFlags |= GrVkRenderPass::kResolve_AttachmentFlag;
354         ++attachmentCount;
355     }
356 
357     if (withStencil) {
358         const GrAttachment* stencil = this->getStencilAttachment();
359         SkASSERT(stencil);
360         const GrVkAttachment* vkStencil = static_cast<const GrVkAttachment*>(stencil);
361         desc->fStencil.fFormat = vkStencil->imageFormat();
362         desc->fStencil.fSamples = vkStencil->numSamples();
363         SkASSERT(desc->fStencil.fSamples == desc->fColor.fSamples);
364         *attachmentFlags |= GrVkRenderPass::kStencil_AttachmentFlag;
365         ++attachmentCount;
366     }
367     desc->fAttachmentCount = attachmentCount;
368 }
369 
ReconstructAttachmentsDescriptor(const GrVkCaps & vkCaps,const GrProgramInfo & programInfo,GrVkRenderPass::AttachmentsDescriptor * desc,GrVkRenderPass::AttachmentFlags * flags)370 void GrVkRenderTarget::ReconstructAttachmentsDescriptor(const GrVkCaps& vkCaps,
371                                                         const GrProgramInfo& programInfo,
372                                                         GrVkRenderPass::AttachmentsDescriptor* desc,
373                                                         GrVkRenderPass::AttachmentFlags* flags) {
374     VkFormat format;
375     SkAssertResult(programInfo.backendFormat().asVkFormat(&format));
376 
377     desc->fColor.fFormat = format;
378     desc->fColor.fSamples = programInfo.numSamples();
379     *flags = GrVkRenderPass::kColor_AttachmentFlag;
380     uint32_t attachmentCount = 1;
381 
382     if (programInfo.targetSupportsVkResolveLoad() && vkCaps.preferDiscardableMSAAAttachment()) {
383         desc->fResolve.fFormat = desc->fColor.fFormat;
384         desc->fResolve.fSamples = 1;
385         *flags |= GrVkRenderPass::kResolve_AttachmentFlag;
386         ++attachmentCount;
387     }
388 
389     SkASSERT(!programInfo.isStencilEnabled() || programInfo.needsStencil());
390     if (programInfo.needsStencil()) {
391         VkFormat stencilFormat = vkCaps.preferredStencilFormat();
392         desc->fStencil.fFormat = stencilFormat;
393         desc->fStencil.fSamples = programInfo.numSamples();
394         SkASSERT(desc->fStencil.fSamples == desc->fColor.fSamples);
395         *flags |= GrVkRenderPass::kStencil_AttachmentFlag;
396         ++attachmentCount;
397     }
398     desc->fAttachmentCount = attachmentCount;
399 }
400 
~GrVkRenderTarget()401 GrVkRenderTarget::~GrVkRenderTarget() {
402     // either release or abandon should have been called by the owner of this object.
403     SkASSERT(!fColorAttachment);
404     SkASSERT(!fResolveAttachment);
405     SkASSERT(!fDynamicMSAAAttachment);
406 
407     for (int i = 0; i < kNumCachedFramebuffers; ++i) {
408         SkASSERT(!fCachedFramebuffers[i]);
409     }
410 
411     SkASSERT(!fCachedInputDescriptorSet);
412 }
413 
releaseInternalObjects()414 void GrVkRenderTarget::releaseInternalObjects() {
415     fColorAttachment.reset();
416     fResolveAttachment.reset();
417     fDynamicMSAAAttachment.reset();
418 
419     for (int i = 0; i < kNumCachedFramebuffers; ++i) {
420         if (fCachedFramebuffers[i]) {
421             fCachedFramebuffers[i].reset();
422         }
423     }
424 
425     if (fCachedInputDescriptorSet) {
426         fCachedInputDescriptorSet->recycle();
427         fCachedInputDescriptorSet = nullptr;
428     }
429 
430     fExternalFramebuffer.reset();
431 }
432 
onRelease()433 void GrVkRenderTarget::onRelease() {
434     this->releaseInternalObjects();
435     GrRenderTarget::onRelease();
436 }
437 
onAbandon()438 void GrVkRenderTarget::onAbandon() {
439     this->releaseInternalObjects();
440     GrRenderTarget::onAbandon();
441 }
442 
getBackendRenderTarget() const443 GrBackendRenderTarget GrVkRenderTarget::getBackendRenderTarget() const {
444     SkASSERT(!this->wrapsSecondaryCommandBuffer());
445     // This should only get called with a non-released GrVkRenderTargets.
446     SkASSERT(!this->wasDestroyed());
447     // If we have a resolve attachment that is what we return for the backend render target
448     const GrVkAttachment* beAttachment = this->externalAttachment();
449     return GrBackendRenderTarget(beAttachment->width(), beAttachment->height(),
450                                  beAttachment->vkImageInfo(), beAttachment->getMutableState());
451 }
452 
stencilImageResource() const453 const GrManagedResource* GrVkRenderTarget::stencilImageResource() const {
454     SkASSERT(!this->wrapsSecondaryCommandBuffer());
455     const GrAttachment* stencil = this->getStencilAttachment();
456     if (stencil) {
457         const GrVkAttachment* vkStencil = static_cast<const GrVkAttachment*>(stencil);
458         return vkStencil->imageResource();
459     }
460 
461     return nullptr;
462 }
463 
stencilAttachmentView() const464 const GrVkImageView* GrVkRenderTarget::stencilAttachmentView() const {
465     SkASSERT(!this->wrapsSecondaryCommandBuffer());
466     const GrAttachment* stencil = this->getStencilAttachment();
467     if (stencil) {
468         const GrVkAttachment* vkStencil = static_cast<const GrVkAttachment*>(stencil);
469         return vkStencil->framebufferView();
470     }
471 
472     return nullptr;
473 }
474 
getVkGpu() const475 GrVkGpu* GrVkRenderTarget::getVkGpu() const {
476     SkASSERT(!this->wasDestroyed());
477     return static_cast<GrVkGpu*>(this->getGpu());
478 }
479