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
highest_filter_mode(GrPixelConfig config)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.
GrVkTexture(GrVkGpu * gpu,SkBudgeted budgeted,const GrSurfaceDesc & desc,const GrVkImageInfo & info,const GrVkImageView * view)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
GrVkTexture(GrVkGpu * gpu,Wrapped,const GrSurfaceDesc & desc,const GrVkImageInfo & info,const GrVkImageView * view,GrVkImage::Wrapped wrapped)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.
GrVkTexture(GrVkGpu * gpu,const GrSurfaceDesc & desc,const GrVkImageInfo & info,const GrVkImageView * view,GrVkImage::Wrapped wrapped)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
CreateNewTexture(GrVkGpu * gpu,SkBudgeted budgeted,const GrSurfaceDesc & desc,const GrVkImage::ImageDesc & imageDesc)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
MakeWrappedTexture(GrVkGpu * gpu,const GrSurfaceDesc & desc,GrWrapOwnership ownership,const GrVkImageInfo * info)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
~GrVkTexture()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
onRelease()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
onAbandon()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
getTextureHandle() const151 GrBackendObject GrVkTexture::getTextureHandle() const {
152 return (GrBackendObject)&fInfo;
153 }
154
getVkGpu() const155 GrVkGpu* GrVkTexture::getVkGpu() const {
156 SkASSERT(!this->wasDestroyed());
157 return static_cast<GrVkGpu*>(this->getGpu());
158 }
159
textureView(bool allowSRGB)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
reallocForMipmap(GrVkGpu * gpu,uint32_t mipLevels)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