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 "GrVkTexture.h" 9 10 #include "GrTexturePriv.h" 11 #include "GrVkGpu.h" 12 #include "GrVkImageView.h" 13 #include "GrVkTextureRenderTarget.h" 14 #include "GrVkUtil.h" 15 16 #include "vk/GrVkTypes.h" 17 18 #define VK_CALL(GPU, X) GR_VK_CALL(GPU->vkInterface(), X) 19 20 // This method parallels GrTextureProxy::highestFilterMode 21 static inline GrSamplerState::Filter highest_filter_mode(GrPixelConfig config) { 22 return GrSamplerState::Filter::kMipMap; 23 } 24 25 // Because this class is virtually derived from GrSurface we must explicitly call its constructor. 26 GrVkTexture::GrVkTexture(GrVkGpu* gpu, 27 SkBudgeted budgeted, 28 const GrSurfaceDesc& desc, 29 const GrVkImageInfo& info, 30 const GrVkImageView* view, 31 GrMipMapsStatus mipMapsStatus) 32 : GrSurface(gpu, desc) 33 , GrVkImage(info, GrBackendObjectOwnership::kOwned) 34 , INHERITED(gpu, desc, kTexture2DSampler_GrSLType, highest_filter_mode(desc.fConfig), 35 mipMapsStatus) 36 , fTextureView(view) 37 , fLinearTextureView(nullptr) { 38 SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == info.fLevelCount)); 39 this->registerWithCache(budgeted); 40 } 41 42 GrVkTexture::GrVkTexture(GrVkGpu* gpu, 43 Wrapped, 44 const GrSurfaceDesc& desc, 45 const GrVkImageInfo& info, 46 const GrVkImageView* view, 47 GrMipMapsStatus mipMapsStatus, 48 GrBackendObjectOwnership ownership) 49 : GrSurface(gpu, desc) 50 , GrVkImage(info, ownership) 51 , INHERITED(gpu, desc, kTexture2DSampler_GrSLType, highest_filter_mode(desc.fConfig), 52 mipMapsStatus) 53 , fTextureView(view) 54 , fLinearTextureView(nullptr) { 55 SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == info.fLevelCount)); 56 this->registerWithCacheWrapped(); 57 } 58 59 // Because this class is virtually derived from GrSurface we must explicitly call its constructor. 60 GrVkTexture::GrVkTexture(GrVkGpu* gpu, 61 const GrSurfaceDesc& desc, 62 const GrVkImageInfo& info, 63 const GrVkImageView* view, 64 GrMipMapsStatus mipMapsStatus, 65 GrBackendObjectOwnership ownership) 66 : GrSurface(gpu, desc) 67 , GrVkImage(info, ownership) 68 , INHERITED(gpu, desc, kTexture2DSampler_GrSLType, highest_filter_mode(desc.fConfig), 69 mipMapsStatus) 70 , fTextureView(view) 71 , fLinearTextureView(nullptr) { 72 SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == info.fLevelCount)); 73 } 74 75 sk_sp<GrVkTexture> GrVkTexture::CreateNewTexture(GrVkGpu* gpu, SkBudgeted budgeted, 76 const GrSurfaceDesc& desc, 77 const GrVkImage::ImageDesc& imageDesc, 78 GrMipMapsStatus mipMapsStatus) { 79 SkASSERT(imageDesc.fUsageFlags & VK_IMAGE_USAGE_SAMPLED_BIT); 80 81 GrVkImageInfo info; 82 if (!GrVkImage::InitImageInfo(gpu, imageDesc, &info)) { 83 return nullptr; 84 } 85 86 const GrVkImageView* imageView = GrVkImageView::Create(gpu, info.fImage, info.fFormat, 87 GrVkImageView::kColor_Type, 88 info.fLevelCount); 89 if (!imageView) { 90 GrVkImage::DestroyImageInfo(gpu, &info); 91 return nullptr; 92 } 93 94 return sk_sp<GrVkTexture>(new GrVkTexture(gpu, budgeted, desc, info, imageView, 95 mipMapsStatus)); 96 } 97 98 sk_sp<GrVkTexture> GrVkTexture::MakeWrappedTexture(GrVkGpu* gpu, 99 const GrSurfaceDesc& desc, 100 GrWrapOwnership wrapOwnership, 101 const GrVkImageInfo* info) { 102 SkASSERT(info); 103 // Wrapped textures require both image and allocation (because they can be mapped) 104 SkASSERT(VK_NULL_HANDLE != info->fImage && VK_NULL_HANDLE != info->fAlloc.fMemory); 105 106 const GrVkImageView* imageView = GrVkImageView::Create(gpu, info->fImage, info->fFormat, 107 GrVkImageView::kColor_Type, 108 info->fLevelCount); 109 if (!imageView) { 110 return nullptr; 111 } 112 113 GrMipMapsStatus mipMapsStatus = info->fLevelCount > 1 ? GrMipMapsStatus::kValid 114 : GrMipMapsStatus::kNotAllocated; 115 116 GrBackendObjectOwnership ownership = kBorrow_GrWrapOwnership == wrapOwnership 117 ? GrBackendObjectOwnership::kBorrowed : GrBackendObjectOwnership::kOwned; 118 return sk_sp<GrVkTexture>(new GrVkTexture(gpu, kWrapped, desc, *info, imageView, 119 mipMapsStatus, ownership)); 120 } 121 122 GrVkTexture::~GrVkTexture() { 123 // either release or abandon should have been called by the owner of this object. 124 SkASSERT(!fTextureView); 125 SkASSERT(!fLinearTextureView); 126 } 127 128 void GrVkTexture::onRelease() { 129 // we create this and don't hand it off, so we should always destroy it 130 if (fTextureView) { 131 fTextureView->unref(this->getVkGpu()); 132 fTextureView = nullptr; 133 } 134 135 if (fLinearTextureView) { 136 fLinearTextureView->unref(this->getVkGpu()); 137 fLinearTextureView = nullptr; 138 } 139 140 this->releaseImage(this->getVkGpu()); 141 142 INHERITED::onRelease(); 143 } 144 145 void GrVkTexture::onAbandon() { 146 if (fTextureView) { 147 fTextureView->unrefAndAbandon(); 148 fTextureView = nullptr; 149 } 150 151 if (fLinearTextureView) { 152 fLinearTextureView->unrefAndAbandon(); 153 fLinearTextureView = nullptr; 154 } 155 156 this->abandonImage(); 157 INHERITED::onAbandon(); 158 } 159 160 GrBackendObject GrVkTexture::getTextureHandle() const { 161 return (GrBackendObject)&fInfo; 162 } 163 164 GrBackendTexture GrVkTexture::getBackendTexture() const { 165 return GrBackendTexture(this->width(), this->height(), fInfo); 166 } 167 168 GrVkGpu* GrVkTexture::getVkGpu() const { 169 SkASSERT(!this->wasDestroyed()); 170 return static_cast<GrVkGpu*>(this->getGpu()); 171 } 172 173 const GrVkImageView* GrVkTexture::textureView(bool allowSRGB) { 174 VkFormat linearFormat; 175 if (allowSRGB || !GrVkFormatIsSRGB(fInfo.fFormat, &linearFormat)) { 176 return fTextureView; 177 } 178 179 if (!fLinearTextureView) { 180 fLinearTextureView = GrVkImageView::Create(this->getVkGpu(), fInfo.fImage, 181 linearFormat, GrVkImageView::kColor_Type, 182 fInfo.fLevelCount); 183 SkASSERT(fLinearTextureView); 184 } 185 186 return fLinearTextureView; 187 } 188 189 bool GrVkTexture::reallocForMipmap(GrVkGpu* gpu, uint32_t mipLevels) { 190 if (mipLevels == 1) { 191 // don't need to do anything for a 1x1 texture 192 return false; 193 } 194 195 const GrVkResource* oldResource = this->resource(); 196 197 // We shouldn't realloc something that doesn't belong to us 198 if (fIsBorrowed) { 199 return false; 200 } 201 202 bool renderTarget = SkToBool(this->asRenderTarget()); 203 204 VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_SAMPLED_BIT; 205 if (renderTarget) { 206 usageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; 207 } 208 usageFlags |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; 209 210 GrVkImage::ImageDesc imageDesc; 211 imageDesc.fImageType = VK_IMAGE_TYPE_2D; 212 imageDesc.fFormat = fInfo.fFormat; 213 imageDesc.fWidth = this->width(); 214 imageDesc.fHeight = this->height(); 215 imageDesc.fLevels = mipLevels; 216 imageDesc.fSamples = 1; 217 imageDesc.fImageTiling = VK_IMAGE_TILING_OPTIMAL; 218 imageDesc.fUsageFlags = usageFlags; 219 imageDesc.fMemProps = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; 220 221 GrVkImageInfo info; 222 if (!GrVkImage::InitImageInfo(gpu, imageDesc, &info)) { 223 return false; 224 } 225 226 // have to create a new image view for new resource 227 const GrVkImageView* oldView = fTextureView; 228 VkImage image = info.fImage; 229 const GrVkImageView* textureView = GrVkImageView::Create(gpu, image, info.fFormat, 230 GrVkImageView::kColor_Type, mipLevels); 231 if (!textureView) { 232 GrVkImage::DestroyImageInfo(gpu, &info); 233 return false; 234 } 235 236 if (renderTarget) { 237 GrVkTextureRenderTarget* texRT = static_cast<GrVkTextureRenderTarget*>(this); 238 if (!texRT->updateForMipmap(gpu, info)) { 239 GrVkImage::DestroyImageInfo(gpu, &info); 240 return false; 241 } 242 } 243 244 oldResource->unref(gpu); 245 oldView->unref(gpu); 246 if (fLinearTextureView) { 247 fLinearTextureView->unref(gpu); 248 fLinearTextureView = nullptr; 249 } 250 251 this->setNewResource(info.fImage, info.fAlloc, info.fImageTiling); 252 fTextureView = textureView; 253 fInfo = info; 254 // SetMaxMipMapLevel stores the max level not the number of levels 255 this->texturePriv().setMaxMipMapLevel(mipLevels-1); 256 257 return true; 258 } 259