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 "src/gpu/GrRenderTargetPriv.h"
12 #include "src/gpu/vk/GrVkCommandBuffer.h"
13 #include "src/gpu/vk/GrVkFramebuffer.h"
14 #include "src/gpu/vk/GrVkGpu.h"
15 #include "src/gpu/vk/GrVkImageView.h"
16 #include "src/gpu/vk/GrVkResourceProvider.h"
17 #include "src/gpu/vk/GrVkUtil.h"
18
19 #include "include/gpu/vk/GrVkTypes.h"
20
21 #define VK_CALL(GPU, X) GR_VK_CALL(GPU->vkInterface(), X)
22
23 // We're virtually derived from GrSurface (via GrRenderTarget) so its
24 // constructor must be explicitly called.
GrVkRenderTarget(GrVkGpu * gpu,const GrSurfaceDesc & desc,int sampleCnt,const GrVkImageInfo & info,sk_sp<GrVkImageLayout> layout,const GrVkImageInfo & msaaInfo,sk_sp<GrVkImageLayout> msaaLayout,const GrVkImageView * colorAttachmentView,const GrVkImageView * resolveAttachmentView)25 GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu,
26 const GrSurfaceDesc& desc,
27 int sampleCnt,
28 const GrVkImageInfo& info,
29 sk_sp<GrVkImageLayout> layout,
30 const GrVkImageInfo& msaaInfo,
31 sk_sp<GrVkImageLayout> msaaLayout,
32 const GrVkImageView* colorAttachmentView,
33 const GrVkImageView* resolveAttachmentView)
34 : GrSurface(gpu, {desc.fWidth, desc.fHeight}, desc.fConfig, info.fProtected)
35 , GrVkImage(info, std::move(layout), GrBackendObjectOwnership::kBorrowed)
36 // for the moment we only support 1:1 color to stencil
37 , GrRenderTarget(gpu, {desc.fWidth, desc.fHeight}, desc.fConfig, sampleCnt, info.fProtected)
38 , fColorAttachmentView(colorAttachmentView)
39 , fMSAAImage(new GrVkImage(msaaInfo, std::move(msaaLayout),
40 GrBackendObjectOwnership::kOwned))
41 , fResolveAttachmentView(resolveAttachmentView)
42 , fFramebuffer(nullptr)
43 , fCachedSimpleRenderPass(nullptr) {
44 SkASSERT(info.fProtected == msaaInfo.fProtected);
45 SkASSERT(sampleCnt > 1);
46 this->createFramebuffer(gpu);
47 this->registerWithCacheWrapped(GrWrapCacheable::kNo);
48 }
49
50 // We're virtually derived from GrSurface (via GrRenderTarget) so its
51 // constructor must be explicitly called.
GrVkRenderTarget(GrVkGpu * gpu,const GrSurfaceDesc & desc,int sampleCnt,const GrVkImageInfo & info,sk_sp<GrVkImageLayout> layout,const GrVkImageInfo & msaaInfo,sk_sp<GrVkImageLayout> msaaLayout,const GrVkImageView * colorAttachmentView,const GrVkImageView * resolveAttachmentView,GrBackendObjectOwnership ownership)52 GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu,
53 const GrSurfaceDesc& desc,
54 int sampleCnt,
55 const GrVkImageInfo& info,
56 sk_sp<GrVkImageLayout> layout,
57 const GrVkImageInfo& msaaInfo,
58 sk_sp<GrVkImageLayout> msaaLayout,
59 const GrVkImageView* colorAttachmentView,
60 const GrVkImageView* resolveAttachmentView,
61 GrBackendObjectOwnership ownership)
62 : GrSurface(gpu, {desc.fWidth, desc.fHeight}, desc.fConfig, info.fProtected)
63 , GrVkImage(info, std::move(layout), ownership)
64 // for the moment we only support 1:1 color to stencil
65 , GrRenderTarget(gpu, {desc.fWidth, desc.fHeight}, desc.fConfig, sampleCnt, info.fProtected)
66 , fColorAttachmentView(colorAttachmentView)
67 , fMSAAImage(
68 new GrVkImage(msaaInfo, std::move(msaaLayout), GrBackendObjectOwnership::kOwned))
69 , fResolveAttachmentView(resolveAttachmentView)
70 , fFramebuffer(nullptr)
71 , fCachedSimpleRenderPass(nullptr) {
72 SkASSERT(info.fProtected == msaaInfo.fProtected);
73 SkASSERT(sampleCnt > 1);
74 this->createFramebuffer(gpu);
75 }
76
77 // We're virtually derived from GrSurface (via GrRenderTarget) so its
78 // constructor must be explicitly called.
GrVkRenderTarget(GrVkGpu * gpu,const GrSurfaceDesc & desc,const GrVkImageInfo & info,sk_sp<GrVkImageLayout> layout,const GrVkImageView * colorAttachmentView)79 GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu,
80 const GrSurfaceDesc& desc,
81 const GrVkImageInfo& info,
82 sk_sp<GrVkImageLayout> layout,
83 const GrVkImageView* colorAttachmentView)
84 : GrSurface(gpu, {desc.fWidth, desc.fHeight}, desc.fConfig, info.fProtected)
85 , GrVkImage(info, std::move(layout), GrBackendObjectOwnership::kBorrowed)
86 , GrRenderTarget(gpu, {desc.fWidth, desc.fHeight}, desc.fConfig, 1, info.fProtected)
87 , fColorAttachmentView(colorAttachmentView)
88 , fMSAAImage(nullptr)
89 , fResolveAttachmentView(nullptr)
90 , fFramebuffer(nullptr)
91 , fCachedSimpleRenderPass(nullptr) {
92 this->createFramebuffer(gpu);
93 this->registerWithCacheWrapped(GrWrapCacheable::kNo);
94 }
95
96 // We're virtually derived from GrSurface (via GrRenderTarget) so its
97 // constructor must be explicitly called.
GrVkRenderTarget(GrVkGpu * gpu,const GrSurfaceDesc & desc,const GrVkImageInfo & info,sk_sp<GrVkImageLayout> layout,const GrVkImageView * colorAttachmentView,GrBackendObjectOwnership ownership)98 GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu,
99 const GrSurfaceDesc& desc,
100 const GrVkImageInfo& info,
101 sk_sp<GrVkImageLayout> layout,
102 const GrVkImageView* colorAttachmentView,
103 GrBackendObjectOwnership ownership)
104 : GrSurface(gpu, {desc.fWidth, desc.fHeight}, desc.fConfig, info.fProtected)
105 , GrVkImage(info, std::move(layout), ownership)
106 , GrRenderTarget(gpu, {desc.fWidth, desc.fHeight}, desc.fConfig, 1, info.fProtected)
107 , fColorAttachmentView(colorAttachmentView)
108 , fMSAAImage(nullptr)
109 , fResolveAttachmentView(nullptr)
110 , fFramebuffer(nullptr)
111 , fCachedSimpleRenderPass(nullptr) {
112 this->createFramebuffer(gpu);
113 }
114
GrVkRenderTarget(GrVkGpu * gpu,const GrSurfaceDesc & desc,const GrVkImageInfo & info,sk_sp<GrVkImageLayout> layout,const GrVkRenderPass * renderPass,VkCommandBuffer secondaryCommandBuffer)115 GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu,
116 const GrSurfaceDesc& desc,
117 const GrVkImageInfo& info,
118 sk_sp<GrVkImageLayout> layout,
119 const GrVkRenderPass* renderPass,
120 VkCommandBuffer secondaryCommandBuffer)
121 : GrSurface(gpu, {desc.fWidth, desc.fHeight}, desc.fConfig, info.fProtected)
122 , GrVkImage(info, std::move(layout), GrBackendObjectOwnership::kBorrowed, true)
123 , GrRenderTarget(gpu, {desc.fWidth, desc.fHeight}, desc.fConfig, 1, info.fProtected)
124 , fColorAttachmentView(nullptr)
125 , fMSAAImage(nullptr)
126 , fResolveAttachmentView(nullptr)
127 , fFramebuffer(nullptr)
128 , fCachedSimpleRenderPass(renderPass)
129 , fSecondaryCommandBuffer(secondaryCommandBuffer) {
130 SkASSERT(fSecondaryCommandBuffer != VK_NULL_HANDLE);
131 this->registerWithCacheWrapped(GrWrapCacheable::kNo);
132 }
133
MakeWrappedRenderTarget(GrVkGpu * gpu,const GrSurfaceDesc & desc,int sampleCnt,const GrVkImageInfo & info,sk_sp<GrVkImageLayout> layout)134 sk_sp<GrVkRenderTarget> GrVkRenderTarget::MakeWrappedRenderTarget(GrVkGpu* gpu,
135 const GrSurfaceDesc& desc,
136 int sampleCnt,
137 const GrVkImageInfo& info,
138 sk_sp<GrVkImageLayout> layout) {
139 SkASSERT(VK_NULL_HANDLE != info.fImage);
140
141 SkASSERT(1 == info.fLevelCount);
142 VkFormat pixelFormat = info.fFormat;
143
144 VkImage colorImage;
145
146 // create msaa surface if necessary
147 GrVkImageInfo msInfo;
148 sk_sp<GrVkImageLayout> msLayout;
149 const GrVkImageView* resolveAttachmentView = nullptr;
150 if (sampleCnt > 1) {
151 GrVkImage::ImageDesc msImageDesc;
152 msImageDesc.fImageType = VK_IMAGE_TYPE_2D;
153 msImageDesc.fFormat = pixelFormat;
154 msImageDesc.fWidth = desc.fWidth;
155 msImageDesc.fHeight = desc.fHeight;
156 msImageDesc.fLevels = 1;
157 msImageDesc.fSamples = sampleCnt;
158 msImageDesc.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
159 msImageDesc.fUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
160 VK_IMAGE_USAGE_TRANSFER_DST_BIT |
161 VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
162 msImageDesc.fMemProps = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
163 msImageDesc.fIsProtected = info.fProtected;
164
165 if (!GrVkImage::InitImageInfo(gpu, msImageDesc, &msInfo)) {
166 return nullptr;
167 }
168
169 // Set color attachment image
170 colorImage = msInfo.fImage;
171
172 // Create Resolve attachment view
173 resolveAttachmentView = GrVkImageView::Create(gpu, info.fImage, pixelFormat,
174 GrVkImageView::kColor_Type, 1,
175 GrVkYcbcrConversionInfo());
176 if (!resolveAttachmentView) {
177 GrVkImage::DestroyImageInfo(gpu, &msInfo);
178 return nullptr;
179 }
180 msLayout.reset(new GrVkImageLayout(msInfo.fImageLayout));
181 } else {
182 // Set color attachment image
183 colorImage = info.fImage;
184 }
185
186 // Get color attachment view
187 const GrVkImageView* colorAttachmentView = GrVkImageView::Create(gpu, colorImage, pixelFormat,
188 GrVkImageView::kColor_Type, 1,
189 GrVkYcbcrConversionInfo());
190 if (!colorAttachmentView) {
191 if (sampleCnt > 1) {
192 resolveAttachmentView->unref(gpu);
193 GrVkImage::DestroyImageInfo(gpu, &msInfo);
194 }
195 return nullptr;
196 }
197
198 GrVkRenderTarget* vkRT;
199 if (sampleCnt > 1) {
200 vkRT = new GrVkRenderTarget(gpu, desc, sampleCnt, info, std::move(layout), msInfo,
201 std::move(msLayout), colorAttachmentView,
202 resolveAttachmentView);
203 } else {
204 vkRT = new GrVkRenderTarget(gpu, desc, info, std::move(layout), colorAttachmentView);
205 }
206
207 return sk_sp<GrVkRenderTarget>(vkRT);
208 }
209
MakeSecondaryCBRenderTarget(GrVkGpu * gpu,const GrSurfaceDesc & desc,const GrVkDrawableInfo & vkInfo)210 sk_sp<GrVkRenderTarget> GrVkRenderTarget::MakeSecondaryCBRenderTarget(
211 GrVkGpu* gpu, const GrSurfaceDesc& desc, const GrVkDrawableInfo& vkInfo) {
212 // We only set the few properties of the GrVkImageInfo that we know like layout and format. The
213 // others we keep at the default "null" values.
214 GrVkImageInfo info;
215 info.fImageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
216 info.fFormat = vkInfo.fFormat;
217
218 sk_sp<GrVkImageLayout> layout(new GrVkImageLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL));
219
220 const GrVkRenderPass* rp =
221 gpu->resourceProvider().findCompatibleExternalRenderPass(vkInfo.fCompatibleRenderPass,
222 vkInfo.fColorAttachmentIndex);
223 if (!rp) {
224 return nullptr;
225 }
226
227 if (vkInfo.fSecondaryCommandBuffer == VK_NULL_HANDLE) {
228 return nullptr;
229 }
230
231 GrVkRenderTarget* vkRT = new GrVkRenderTarget(gpu, desc, info, std::move(layout), rp,
232 vkInfo.fSecondaryCommandBuffer);
233
234 return sk_sp<GrVkRenderTarget>(vkRT);
235 }
236
completeStencilAttachment()237 bool GrVkRenderTarget::completeStencilAttachment() {
238 SkASSERT(!this->wrapsSecondaryCommandBuffer());
239 this->createFramebuffer(this->getVkGpu());
240 return true;
241 }
242
createFramebuffer(GrVkGpu * gpu)243 void GrVkRenderTarget::createFramebuffer(GrVkGpu* gpu) {
244 SkASSERT(!this->wrapsSecondaryCommandBuffer());
245 if (fFramebuffer) {
246 fFramebuffer->unref(gpu);
247 }
248 if (fCachedSimpleRenderPass) {
249 fCachedSimpleRenderPass->unref(gpu);
250 }
251
252 // Vulkan requires us to create a compatible renderpass before we can create our framebuffer,
253 // so we use this to get a (cached) basic renderpass, only for creation.
254 fCachedSimpleRenderPass =
255 gpu->resourceProvider().findCompatibleRenderPass(*this, &fCompatibleRPHandle);
256
257 // Stencil attachment view is stored in the base RT stencil attachment
258 const GrVkImageView* stencilView = this->stencilAttachmentView();
259 fFramebuffer = GrVkFramebuffer::Create(gpu, this->width(), this->height(),
260 fCachedSimpleRenderPass, fColorAttachmentView,
261 stencilView);
262 SkASSERT(fFramebuffer);
263 }
264
getAttachmentsDescriptor(GrVkRenderPass::AttachmentsDescriptor * desc,GrVkRenderPass::AttachmentFlags * attachmentFlags) const265 void GrVkRenderTarget::getAttachmentsDescriptor(
266 GrVkRenderPass::AttachmentsDescriptor* desc,
267 GrVkRenderPass::AttachmentFlags* attachmentFlags) const {
268 SkASSERT(!this->wrapsSecondaryCommandBuffer());
269 desc->fColor.fFormat = this->imageFormat();
270 desc->fColor.fSamples = this->numSamples();
271 *attachmentFlags = GrVkRenderPass::kColor_AttachmentFlag;
272 uint32_t attachmentCount = 1;
273
274 const GrStencilAttachment* stencil = this->renderTargetPriv().getStencilAttachment();
275 if (stencil) {
276 const GrVkStencilAttachment* vkStencil = static_cast<const GrVkStencilAttachment*>(stencil);
277 desc->fStencil.fFormat = vkStencil->vkFormat();
278 desc->fStencil.fSamples = vkStencil->numSamples();
279 // Currently in vulkan stencil and color attachments must all have same number of samples
280 SkASSERT(desc->fColor.fSamples == desc->fStencil.fSamples);
281 *attachmentFlags |= GrVkRenderPass::kStencil_AttachmentFlag;
282 ++attachmentCount;
283 }
284 desc->fAttachmentCount = attachmentCount;
285 }
286
~GrVkRenderTarget()287 GrVkRenderTarget::~GrVkRenderTarget() {
288 // either release or abandon should have been called by the owner of this object.
289 SkASSERT(!fMSAAImage);
290 SkASSERT(!fResolveAttachmentView);
291 SkASSERT(!fColorAttachmentView);
292 SkASSERT(!fFramebuffer);
293 SkASSERT(!fCachedSimpleRenderPass);
294 }
295
addResources(GrVkCommandBuffer & commandBuffer) const296 void GrVkRenderTarget::addResources(GrVkCommandBuffer& commandBuffer) const {
297 commandBuffer.addResource(this->framebuffer());
298 commandBuffer.addResource(this->colorAttachmentView());
299 commandBuffer.addResource(this->msaaImageResource() ? this->msaaImageResource()
300 : this->resource());
301 if (this->stencilImageResource()) {
302 commandBuffer.addResource(this->stencilImageResource());
303 commandBuffer.addResource(this->stencilAttachmentView());
304 }
305 }
306
releaseInternalObjects()307 void GrVkRenderTarget::releaseInternalObjects() {
308 GrVkGpu* gpu = this->getVkGpu();
309
310 if (fMSAAImage) {
311 fMSAAImage->releaseImage(gpu);
312 fMSAAImage.reset();
313 }
314
315 if (fResolveAttachmentView) {
316 fResolveAttachmentView->unref(gpu);
317 fResolveAttachmentView = nullptr;
318 }
319 if (fColorAttachmentView) {
320 fColorAttachmentView->unref(gpu);
321 fColorAttachmentView = nullptr;
322 }
323 if (fFramebuffer) {
324 fFramebuffer->unref(gpu);
325 fFramebuffer = nullptr;
326 }
327 if (fCachedSimpleRenderPass) {
328 fCachedSimpleRenderPass->unref(gpu);
329 fCachedSimpleRenderPass = nullptr;
330 }
331 }
332
abandonInternalObjects()333 void GrVkRenderTarget::abandonInternalObjects() {
334 if (fMSAAImage) {
335 fMSAAImage->abandonImage();
336 fMSAAImage.reset();
337 }
338
339 if (fResolveAttachmentView) {
340 fResolveAttachmentView->unrefAndAbandon();
341 fResolveAttachmentView = nullptr;
342 }
343 if (fColorAttachmentView) {
344 fColorAttachmentView->unrefAndAbandon();
345 fColorAttachmentView = nullptr;
346 }
347 if (fFramebuffer) {
348 fFramebuffer->unrefAndAbandon();
349 fFramebuffer = nullptr;
350 }
351 if (fCachedSimpleRenderPass) {
352 fCachedSimpleRenderPass->unrefAndAbandon();
353 fCachedSimpleRenderPass = nullptr;
354 }
355 }
356
onRelease()357 void GrVkRenderTarget::onRelease() {
358 this->releaseInternalObjects();
359 this->releaseImage(this->getVkGpu());
360 GrRenderTarget::onRelease();
361 }
362
onAbandon()363 void GrVkRenderTarget::onAbandon() {
364 this->abandonInternalObjects();
365 this->abandonImage();
366 GrRenderTarget::onAbandon();
367 }
368
369
getBackendRenderTarget() const370 GrBackendRenderTarget GrVkRenderTarget::getBackendRenderTarget() const {
371 SkASSERT(!this->wrapsSecondaryCommandBuffer());
372 return GrBackendRenderTarget(this->width(), this->height(), this->numSamples(), fInfo,
373 this->grVkImageLayout());
374 }
375
stencilImageResource() const376 const GrVkResource* GrVkRenderTarget::stencilImageResource() const {
377 SkASSERT(!this->wrapsSecondaryCommandBuffer());
378 const GrStencilAttachment* stencil = this->renderTargetPriv().getStencilAttachment();
379 if (stencil) {
380 const GrVkStencilAttachment* vkStencil = static_cast<const GrVkStencilAttachment*>(stencil);
381 return vkStencil->imageResource();
382 }
383
384 return nullptr;
385 }
386
stencilAttachmentView() const387 const GrVkImageView* GrVkRenderTarget::stencilAttachmentView() const {
388 SkASSERT(!this->wrapsSecondaryCommandBuffer());
389 const GrStencilAttachment* stencil = this->renderTargetPriv().getStencilAttachment();
390 if (stencil) {
391 const GrVkStencilAttachment* vkStencil = static_cast<const GrVkStencilAttachment*>(stencil);
392 return vkStencil->stencilView();
393 }
394
395 return nullptr;
396 }
397
getVkGpu() const398 GrVkGpu* GrVkRenderTarget::getVkGpu() const {
399 SkASSERT(!this->wasDestroyed());
400 return static_cast<GrVkGpu*>(this->getGpu());
401 }
402