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