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