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