• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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