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