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