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.
GrVkTexture(GrVkGpu * gpu,SkBudgeted budgeted,const GrSurfaceDesc & desc,const GrVkImageInfo & info,const GrVkImageView * view)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
GrVkTexture(GrVkGpu * gpu,Wrapped,const GrSurfaceDesc & desc,const GrVkImageInfo & info,const GrVkImageView * view,GrVkImage::Wrapped wrapped)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.
GrVkTexture(GrVkGpu * gpu,const GrSurfaceDesc & desc,const GrVkImageInfo & info,const GrVkImageView * view,GrVkImage::Wrapped wrapped)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
CreateNewTexture(GrVkGpu * gpu,SkBudgeted budgeted,const GrSurfaceDesc & desc,const GrVkImage::ImageDesc & imageDesc)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
MakeWrappedTexture(GrVkGpu * gpu,const GrSurfaceDesc & desc,GrWrapOwnership ownership,const GrVkImageInfo * info)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
~GrVkTexture()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
onRelease()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
onAbandon()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
getTextureHandle() const146 GrBackendObject GrVkTexture::getTextureHandle() const {
147 return (GrBackendObject)&fInfo;
148 }
149
detachBackendTexture()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
getVkGpu() const156 GrVkGpu* GrVkTexture::getVkGpu() const {
157 SkASSERT(!this->wasDestroyed());
158 return static_cast<GrVkGpu*>(this->getGpu());
159 }
160
textureView(bool allowSRGB)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
reallocForMipmap(GrVkGpu * gpu,uint32_t mipLevels)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