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