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 "GrVkRenderTarget.h"
9
10 #include "GrRenderTargetPriv.h"
11 #include "GrVkCommandBuffer.h"
12 #include "GrVkFramebuffer.h"
13 #include "GrVkGpu.h"
14 #include "GrVkImageView.h"
15 #include "GrVkResourceProvider.h"
16 #include "GrVkUtil.h"
17
18 #define VK_CALL(GPU, X) GR_VK_CALL(GPU->vkInterface(), X)
19
20 // We're virtually derived from GrSurface (via GrRenderTarget) so its
21 // constructor must be explicitly called.
GrVkRenderTarget(GrVkGpu * gpu,const GrSurfaceDesc & desc,GrGpuResource::LifeCycle lifeCycle,const GrVkImage::Resource * imageResource,const GrVkImage::Resource * msaaResource,const GrVkImageView * colorAttachmentView,const GrVkImageView * resolveAttachmentView)22 GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu,
23 const GrSurfaceDesc& desc,
24 GrGpuResource::LifeCycle lifeCycle,
25 const GrVkImage::Resource* imageResource,
26 const GrVkImage::Resource* msaaResource,
27 const GrVkImageView* colorAttachmentView,
28 const GrVkImageView* resolveAttachmentView)
29 : GrSurface(gpu, lifeCycle, desc)
30 , GrVkImage(imageResource)
31 // for the moment we only support 1:1 color to stencil
32 , GrRenderTarget(gpu, lifeCycle, desc, kUnified_SampleConfig)
33 , fFramebuffer(nullptr)
34 , fColorAttachmentView(colorAttachmentView)
35 , fMSAAImageResource(msaaResource)
36 , fResolveAttachmentView(resolveAttachmentView)
37 , fCachedSimpleRenderPass(nullptr) {
38 SkASSERT(desc.fSampleCnt);
39 // The plus 1 is to account for the resolve texture.
40 fColorValuesPerPixel = desc.fSampleCnt + 1; // TODO: this still correct?
41 this->createFramebuffer(gpu);
42 this->registerWithCache();
43 msaaResource->ref();
44 }
45
46 // We're virtually derived from GrSurface (via GrRenderTarget) so its
47 // constructor must be explicitly called.
GrVkRenderTarget(GrVkGpu * gpu,const GrSurfaceDesc & desc,GrGpuResource::LifeCycle lifeCycle,const GrVkImage::Resource * imageResource,const GrVkImage::Resource * msaaResource,const GrVkImageView * colorAttachmentView,const GrVkImageView * resolveAttachmentView,Derived)48 GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu,
49 const GrSurfaceDesc& desc,
50 GrGpuResource::LifeCycle lifeCycle,
51 const GrVkImage::Resource* imageResource,
52 const GrVkImage::Resource* msaaResource,
53 const GrVkImageView* colorAttachmentView,
54 const GrVkImageView* resolveAttachmentView,
55 Derived)
56 : GrSurface(gpu, lifeCycle, desc)
57 , GrVkImage(imageResource)
58 // for the moment we only support 1:1 color to stencil
59 , GrRenderTarget(gpu, lifeCycle, desc, kUnified_SampleConfig)
60 , fFramebuffer(nullptr)
61 , fColorAttachmentView(colorAttachmentView)
62 , fMSAAImageResource(msaaResource)
63 , fResolveAttachmentView(resolveAttachmentView)
64 , fCachedSimpleRenderPass(nullptr) {
65 SkASSERT(desc.fSampleCnt);
66 // The plus 1 is to account for the resolve texture.
67 fColorValuesPerPixel = desc.fSampleCnt + 1; // TODO: this still correct?
68 this->createFramebuffer(gpu);
69 msaaResource->ref();
70 }
71
72 // We're virtually derived from GrSurface (via GrRenderTarget) so its
73 // constructor must be explicitly called.
GrVkRenderTarget(GrVkGpu * gpu,const GrSurfaceDesc & desc,GrGpuResource::LifeCycle lifeCycle,const GrVkImage::Resource * imageResource,const GrVkImageView * colorAttachmentView)74 GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu,
75 const GrSurfaceDesc& desc,
76 GrGpuResource::LifeCycle lifeCycle,
77 const GrVkImage::Resource* imageResource,
78 const GrVkImageView* colorAttachmentView)
79 : GrSurface(gpu, lifeCycle, desc)
80 , GrVkImage(imageResource)
81 , GrRenderTarget(gpu, lifeCycle, desc, kUnified_SampleConfig)
82 , fFramebuffer(nullptr)
83 , fColorAttachmentView(colorAttachmentView)
84 , fMSAAImageResource(nullptr)
85 , fResolveAttachmentView(nullptr)
86 , fCachedSimpleRenderPass(nullptr) {
87 SkASSERT(!desc.fSampleCnt);
88 fColorValuesPerPixel = 1;
89 this->createFramebuffer(gpu);
90 this->registerWithCache();
91 }
92
93 // We're virtually derived from GrSurface (via GrRenderTarget) so its
94 // constructor must be explicitly called.
GrVkRenderTarget(GrVkGpu * gpu,const GrSurfaceDesc & desc,GrGpuResource::LifeCycle lifeCycle,const GrVkImage::Resource * imageResource,const GrVkImageView * colorAttachmentView,Derived)95 GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu,
96 const GrSurfaceDesc& desc,
97 GrGpuResource::LifeCycle lifeCycle,
98 const GrVkImage::Resource* imageResource,
99 const GrVkImageView* colorAttachmentView,
100 Derived)
101 : GrSurface(gpu, lifeCycle, desc)
102 , GrVkImage(imageResource)
103 , GrRenderTarget(gpu, lifeCycle, desc, kUnified_SampleConfig)
104 , fFramebuffer(nullptr)
105 , fColorAttachmentView(colorAttachmentView)
106 , fMSAAImageResource(nullptr)
107 , fResolveAttachmentView(nullptr)
108 , fCachedSimpleRenderPass(nullptr) {
109 SkASSERT(!desc.fSampleCnt);
110 fColorValuesPerPixel = 1;
111 this->createFramebuffer(gpu);
112 }
113
114 GrVkRenderTarget*
Create(GrVkGpu * gpu,const GrSurfaceDesc & desc,GrGpuResource::LifeCycle lifeCycle,const GrVkImage::Resource * imageResource)115 GrVkRenderTarget::Create(GrVkGpu* gpu,
116 const GrSurfaceDesc& desc,
117 GrGpuResource::LifeCycle lifeCycle,
118 const GrVkImage::Resource* imageResource) {
119 VkFormat pixelFormat;
120 GrPixelConfigToVkFormat(desc.fConfig, &pixelFormat);
121
122 VkImage colorImage;
123
124 // create msaa surface if necessary
125 const GrVkImage::Resource* msaaResource = nullptr;
126 const GrVkImageView* resolveAttachmentView = nullptr;
127 if (desc.fSampleCnt) {
128 GrVkImage::ImageDesc msImageDesc;
129 msImageDesc.fImageType = VK_IMAGE_TYPE_2D;
130 msImageDesc.fFormat = pixelFormat;
131 msImageDesc.fWidth = desc.fWidth;
132 msImageDesc.fHeight = desc.fHeight;
133 msImageDesc.fLevels = 1;
134 msImageDesc.fSamples = desc.fSampleCnt;
135 msImageDesc.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
136 msImageDesc.fUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
137 msImageDesc.fMemProps = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
138
139 msaaResource = GrVkImage::CreateResource(gpu, msImageDesc);
140
141 if (!msaaResource) {
142 return nullptr;
143 }
144
145 // Set color attachment image
146 colorImage = msaaResource->fImage;
147
148 // Create Resolve attachment view
149 resolveAttachmentView = GrVkImageView::Create(gpu, imageResource->fImage, pixelFormat,
150 GrVkImageView::kColor_Type);
151 if (!resolveAttachmentView) {
152 msaaResource->unref(gpu);
153 return nullptr;
154 }
155 } else {
156 // Set color attachment image
157 colorImage = imageResource->fImage;
158 }
159
160 // Get color attachment view
161 const GrVkImageView* colorAttachmentView = GrVkImageView::Create(gpu, colorImage, pixelFormat,
162 GrVkImageView::kColor_Type);
163 if (!colorAttachmentView) {
164 if (msaaResource) {
165 resolveAttachmentView->unref(gpu);
166 msaaResource->unref(gpu);
167 }
168 return NULL;
169 }
170
171 GrVkRenderTarget* texRT;
172 if (msaaResource) {
173 texRT = new GrVkRenderTarget(gpu, desc, lifeCycle, imageResource, msaaResource,
174 colorAttachmentView, resolveAttachmentView);
175 msaaResource->unref(gpu);
176 } else {
177 texRT = new GrVkRenderTarget(gpu, desc, lifeCycle, imageResource,
178 colorAttachmentView);
179 }
180
181 return texRT;
182 }
183
184 GrVkRenderTarget*
CreateNewRenderTarget(GrVkGpu * gpu,const GrSurfaceDesc & desc,GrGpuResource::LifeCycle lifeCycle,const GrVkImage::ImageDesc & imageDesc)185 GrVkRenderTarget::CreateNewRenderTarget(GrVkGpu* gpu,
186 const GrSurfaceDesc& desc,
187 GrGpuResource::LifeCycle lifeCycle,
188 const GrVkImage::ImageDesc& imageDesc) {
189 SkASSERT(imageDesc.fUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
190
191 const GrVkImage::Resource* imageResource = GrVkImage::CreateResource(gpu, imageDesc);
192 if (!imageResource) {
193 return nullptr;
194 }
195
196 GrVkRenderTarget* rt = GrVkRenderTarget::Create(gpu, desc, lifeCycle, imageResource);
197 // Create() will increment the refCount of the image resource if it succeeds
198 imageResource->unref(gpu);
199
200 return rt;
201 }
202
203 GrVkRenderTarget*
CreateWrappedRenderTarget(GrVkGpu * gpu,const GrSurfaceDesc & desc,GrGpuResource::LifeCycle lifeCycle,const GrVkImage::Resource * imageResource)204 GrVkRenderTarget::CreateWrappedRenderTarget(GrVkGpu* gpu,
205 const GrSurfaceDesc& desc,
206 GrGpuResource::LifeCycle lifeCycle,
207 const GrVkImage::Resource* imageResource) {
208 SkASSERT(imageResource);
209
210 // Note: we assume the caller will unref the imageResource
211 // Create() will increment the refCount, and we'll unref when we're done with it
212 return GrVkRenderTarget::Create(gpu, desc, lifeCycle, imageResource);
213 }
214
completeStencilAttachment()215 bool GrVkRenderTarget::completeStencilAttachment() {
216 this->createFramebuffer(this->getVkGpu());
217 return true;
218 }
219
createFramebuffer(GrVkGpu * gpu)220 void GrVkRenderTarget::createFramebuffer(GrVkGpu* gpu) {
221 if (fFramebuffer) {
222 fFramebuffer->unref(gpu);
223 }
224 if (fCachedSimpleRenderPass) {
225 fCachedSimpleRenderPass->unref(gpu);
226 }
227
228 // Vulkan requires us to create a compatible renderpass before we can create our framebuffer,
229 // so we use this to get a (cached) basic renderpass, only for creation.
230 fCachedSimpleRenderPass = gpu->resourceProvider().findOrCreateCompatibleRenderPass(*this);
231
232 // Stencil attachment view is stored in the base RT stencil attachment
233 const GrVkImageView* stencilView = this->stencilAttachmentView();
234 fFramebuffer = GrVkFramebuffer::Create(gpu, this->width(), this->height(),
235 fCachedSimpleRenderPass, fColorAttachmentView,
236 fResolveAttachmentView, stencilView);
237 SkASSERT(fFramebuffer);
238 }
239
getAttachmentsDescriptor(GrVkRenderPass::AttachmentsDescriptor * desc,GrVkRenderPass::AttachmentFlags * attachmentFlags) const240 void GrVkRenderTarget::getAttachmentsDescriptor(
241 GrVkRenderPass::AttachmentsDescriptor* desc,
242 GrVkRenderPass::AttachmentFlags* attachmentFlags) const {
243 int colorSamples = this->numColorSamples();
244 VkFormat colorFormat;
245 GrPixelConfigToVkFormat(this->config(), &colorFormat);
246 desc->fColor.fFormat = colorFormat;
247 desc->fColor.fSamples = colorSamples ? colorSamples : 1;
248 *attachmentFlags = GrVkRenderPass::kColor_AttachmentFlag;
249 uint32_t attachmentCount = 1;
250 if (colorSamples > 0) {
251 desc->fResolve.fFormat = colorFormat;
252 desc->fResolve.fSamples = 1;
253 *attachmentFlags |= GrVkRenderPass::kResolve_AttachmentFlag;
254 ++attachmentCount;
255 }
256
257 const GrStencilAttachment* stencil = this->renderTargetPriv().getStencilAttachment();
258 if (stencil) {
259 const GrVkStencilAttachment* vkStencil = static_cast<const GrVkStencilAttachment*>(stencil);
260 desc->fStencil.fFormat = vkStencil->vkFormat();
261 desc->fStencil.fSamples = vkStencil->numSamples() ? vkStencil->numSamples() : 1;
262 // Currently in vulkan stencil and color attachments must all have same number of samples
263 SkASSERT(desc->fColor.fSamples == desc->fStencil.fSamples);
264 *attachmentFlags |= GrVkRenderPass::kStencil_AttachmentFlag;
265 ++attachmentCount;
266 }
267 desc->fAttachmentCount = attachmentCount;
268 }
269
~GrVkRenderTarget()270 GrVkRenderTarget::~GrVkRenderTarget() {
271 // either release or abandon should have been called by the owner of this object.
272 SkASSERT(!fMSAAImageResource);
273 SkASSERT(!fResolveAttachmentView);
274 SkASSERT(!fColorAttachmentView);
275 SkASSERT(!fFramebuffer);
276 SkASSERT(!fCachedSimpleRenderPass);
277 }
278
addResources(GrVkCommandBuffer & commandBuffer) const279 void GrVkRenderTarget::addResources(GrVkCommandBuffer& commandBuffer) const {
280 commandBuffer.addResource(this->framebuffer());
281 commandBuffer.addResource(this->resource());
282 commandBuffer.addResource(this->colorAttachmentView());
283 if (this->msaaImageResource()) {
284 commandBuffer.addResource(this->msaaImageResource());
285 commandBuffer.addResource(this->resolveAttachmentView());
286 }
287 if (this->stencilImageResource()) {
288 commandBuffer.addResource(this->stencilImageResource());
289 commandBuffer.addResource(this->stencilAttachmentView());
290 }
291 }
292
releaseInternalObjects()293 void GrVkRenderTarget::releaseInternalObjects() {
294 GrVkGpu* gpu = this->getVkGpu();
295
296 if (fMSAAImageResource) {
297 fMSAAImageResource->unref(gpu);
298 fMSAAImageResource = nullptr;
299 }
300
301 if (fResolveAttachmentView) {
302 fResolveAttachmentView->unref(gpu);
303 fResolveAttachmentView = nullptr;
304 }
305 if (fColorAttachmentView) {
306 fColorAttachmentView->unref(gpu);
307 fColorAttachmentView = nullptr;
308 }
309 if (fFramebuffer) {
310 fFramebuffer->unref(gpu);
311 fFramebuffer = nullptr;
312 }
313 if (fCachedSimpleRenderPass) {
314 fCachedSimpleRenderPass->unref(gpu);
315 fCachedSimpleRenderPass = nullptr;
316 }
317 }
318
abandonInternalObjects()319 void GrVkRenderTarget::abandonInternalObjects() {
320 if (fMSAAImageResource) {
321 fMSAAImageResource->unrefAndAbandon();
322 fMSAAImageResource = nullptr;
323 }
324
325 if (fResolveAttachmentView) {
326 fResolveAttachmentView->unrefAndAbandon();
327 fResolveAttachmentView = nullptr;
328 }
329 if (fColorAttachmentView) {
330 fColorAttachmentView->unrefAndAbandon();
331 fColorAttachmentView = nullptr;
332 }
333 if (fFramebuffer) {
334 fFramebuffer->unrefAndAbandon();
335 fFramebuffer = nullptr;
336 }
337 if (fCachedSimpleRenderPass) {
338 fCachedSimpleRenderPass->unrefAndAbandon();
339 fCachedSimpleRenderPass = nullptr;
340 }
341 }
342
onRelease()343 void GrVkRenderTarget::onRelease() {
344 this->releaseInternalObjects();
345 if (this->shouldFreeResources()) {
346 this->releaseImage(this->getVkGpu());
347 } else {
348 this->abandonImage();
349 }
350
351 GrRenderTarget::onRelease();
352 }
353
onAbandon()354 void GrVkRenderTarget::onAbandon() {
355 this->abandonInternalObjects();
356 this->abandonImage();
357 GrRenderTarget::onAbandon();
358 }
359
360
getRenderTargetHandle() const361 GrBackendObject GrVkRenderTarget::getRenderTargetHandle() const {
362 // Currently just passing back the pointer to the main Image::Resource as the handle
363 return (GrBackendObject)&fResource;
364 }
365
stencilImageResource() const366 const GrVkImage::Resource* GrVkRenderTarget::stencilImageResource() const {
367 const GrStencilAttachment* stencil = this->renderTargetPriv().getStencilAttachment();
368 if (stencil) {
369 const GrVkStencilAttachment* vkStencil = static_cast<const GrVkStencilAttachment*>(stencil);
370 return vkStencil->imageResource();
371 }
372
373 return nullptr;
374 }
375
stencilAttachmentView() const376 const GrVkImageView* GrVkRenderTarget::stencilAttachmentView() const {
377 const GrStencilAttachment* stencil = this->renderTargetPriv().getStencilAttachment();
378 if (stencil) {
379 const GrVkStencilAttachment* vkStencil = static_cast<const GrVkStencilAttachment*>(stencil);
380 return vkStencil->stencilView();
381 }
382
383 return nullptr;
384 }
385
386
getVkGpu() const387 GrVkGpu* GrVkRenderTarget::getVkGpu() const {
388 SkASSERT(!this->wasDestroyed());
389 return static_cast<GrVkGpu*>(this->getGpu());
390 }
391
392