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
highest_filter_mode(GrPixelConfig config)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.
GrVkTexture(GrVkGpu * gpu,SkBudgeted budgeted,const GrSurfaceDesc & desc,const GrVkImageInfo & info,const GrVkImageView * view,GrMipMapsStatus mipMapsStatus)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
GrVkTexture(GrVkGpu * gpu,Wrapped,const GrSurfaceDesc & desc,const GrVkImageInfo & info,const GrVkImageView * view,GrMipMapsStatus mipMapsStatus,GrBackendObjectOwnership ownership)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.
GrVkTexture(GrVkGpu * gpu,const GrSurfaceDesc & desc,const GrVkImageInfo & info,const GrVkImageView * view,GrMipMapsStatus mipMapsStatus,GrBackendObjectOwnership ownership)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
CreateNewTexture(GrVkGpu * gpu,SkBudgeted budgeted,const GrSurfaceDesc & desc,const GrVkImage::ImageDesc & imageDesc,GrMipMapsStatus mipMapsStatus)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
MakeWrappedTexture(GrVkGpu * gpu,const GrSurfaceDesc & desc,GrWrapOwnership wrapOwnership,const GrVkImageInfo * info)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
~GrVkTexture()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
onRelease()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
onAbandon()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
getTextureHandle() const160 GrBackendObject GrVkTexture::getTextureHandle() const {
161 return (GrBackendObject)&fInfo;
162 }
163
getBackendTexture() const164 GrBackendTexture GrVkTexture::getBackendTexture() const {
165 return GrBackendTexture(this->width(), this->height(), fInfo);
166 }
167
getVkGpu() const168 GrVkGpu* GrVkTexture::getVkGpu() const {
169 SkASSERT(!this->wasDestroyed());
170 return static_cast<GrVkGpu*>(this->getGpu());
171 }
172
textureView(bool allowSRGB)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
reallocForMipmap(GrVkGpu * gpu,uint32_t mipLevels)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