• 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 "src/gpu/vk/GrVkTexture.h"
9 
10 #include "src/gpu/GrTexturePriv.h"
11 #include "src/gpu/vk/GrVkDescriptorSet.h"
12 #include "src/gpu/vk/GrVkGpu.h"
13 #include "src/gpu/vk/GrVkImageView.h"
14 #include "src/gpu/vk/GrVkTextureRenderTarget.h"
15 #include "src/gpu/vk/GrVkUtil.h"
16 
17 #include "include/gpu/vk/GrVkTypes.h"
18 
19 #define VK_CALL(GPU, X) GR_VK_CALL(GPU->vkInterface(), X)
20 
21 // Because this class is virtually derived from GrSurface we must explicitly call its constructor.
GrVkTexture(GrVkGpu * gpu,SkBudgeted budgeted,SkISize dimensions,const GrVkImageInfo & info,sk_sp<GrVkImageLayout> layout,const GrVkImageView * view,GrMipMapsStatus mipMapsStatus)22 GrVkTexture::GrVkTexture(GrVkGpu* gpu,
23                          SkBudgeted budgeted,
24                          SkISize dimensions,
25                          const GrVkImageInfo& info,
26                          sk_sp<GrVkImageLayout> layout,
27                          const GrVkImageView* view,
28                          GrMipMapsStatus mipMapsStatus)
29         : GrSurface(gpu, dimensions, info.fProtected)
30         , GrVkImage(info, std::move(layout), GrBackendObjectOwnership::kOwned)
31         , INHERITED(gpu, dimensions, info.fProtected, GrTextureType::k2D, mipMapsStatus)
32         , fTextureView(view)
33         , fDescSetCache(kMaxCachedDescSets) {
34     SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == info.fLevelCount));
35     // We don't support creating external GrVkTextures
36     SkASSERT(!info.fYcbcrConversionInfo.isValid() || !info.fYcbcrConversionInfo.fExternalFormat);
37     this->registerWithCache(budgeted);
38     if (GrVkFormatIsCompressed(info.fFormat)) {
39         this->setReadOnly();
40     }
41 }
42 
GrVkTexture(GrVkGpu * gpu,SkISize dimensions,const GrVkImageInfo & info,sk_sp<GrVkImageLayout> layout,const GrVkImageView * view,GrMipMapsStatus mipMapsStatus,GrBackendObjectOwnership ownership,GrWrapCacheable cacheable,GrIOType ioType,bool isExternal)43 GrVkTexture::GrVkTexture(GrVkGpu* gpu, SkISize dimensions, const GrVkImageInfo& info,
44                          sk_sp<GrVkImageLayout> layout, const GrVkImageView* view,
45                          GrMipMapsStatus mipMapsStatus, GrBackendObjectOwnership ownership,
46                          GrWrapCacheable cacheable, GrIOType ioType, bool isExternal)
47         : GrSurface(gpu, dimensions, info.fProtected)
48         , GrVkImage(info, std::move(layout), ownership)
49         , INHERITED(gpu, dimensions, info.fProtected,
50                     isExternal ? GrTextureType::kExternal : GrTextureType::k2D, mipMapsStatus)
51         , fTextureView(view)
52         , fDescSetCache(kMaxCachedDescSets) {
53     SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == info.fLevelCount));
54     if (ioType == kRead_GrIOType) {
55         this->setReadOnly();
56     }
57     this->registerWithCacheWrapped(cacheable);
58 }
59 
60 // Because this class is virtually derived from GrSurface we must explicitly call its constructor.
GrVkTexture(GrVkGpu * gpu,SkISize dimensions,const GrVkImageInfo & info,sk_sp<GrVkImageLayout> layout,const GrVkImageView * view,GrMipMapsStatus mipMapsStatus,GrBackendObjectOwnership ownership)61 GrVkTexture::GrVkTexture(GrVkGpu* gpu,
62                          SkISize dimensions,
63                          const GrVkImageInfo& info,
64                          sk_sp<GrVkImageLayout> layout,
65                          const GrVkImageView* view,
66                          GrMipMapsStatus mipMapsStatus,
67                          GrBackendObjectOwnership ownership)
68         : GrSurface(gpu, dimensions, info.fProtected)
69         , GrVkImage(info, layout, ownership)
70         , INHERITED(gpu, dimensions, info.fProtected, GrTextureType::k2D, mipMapsStatus)
71         , fTextureView(view)
72         , fDescSetCache(kMaxCachedDescSets) {
73     SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == info.fLevelCount));
74     // Since this ctor is only called from GrVkTextureRenderTarget, we can't have a ycbcr conversion
75     // since we don't support that on render targets.
76     SkASSERT(!info.fYcbcrConversionInfo.isValid());
77 }
78 
MakeNewTexture(GrVkGpu * gpu,SkBudgeted budgeted,SkISize dimensions,const GrVkImage::ImageDesc & imageDesc,GrMipMapsStatus mipMapsStatus)79 sk_sp<GrVkTexture> GrVkTexture::MakeNewTexture(GrVkGpu* gpu, SkBudgeted budgeted,
80                                                SkISize dimensions,
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(
91             gpu, info.fImage, info.fFormat, GrVkImageView::kColor_Type, info.fLevelCount,
92             info.fYcbcrConversionInfo);
93     if (!imageView) {
94         GrVkImage::DestroyImageInfo(gpu, &info);
95         return nullptr;
96     }
97     sk_sp<GrVkImageLayout> layout(new GrVkImageLayout(info.fImageLayout));
98 
99     return sk_sp<GrVkTexture>(new GrVkTexture(gpu, budgeted, dimensions, info, std::move(layout),
100                                               imageView, mipMapsStatus));
101 }
102 
MakeWrappedTexture(GrVkGpu * gpu,SkISize dimensions,GrWrapOwnership wrapOwnership,GrWrapCacheable cacheable,GrIOType ioType,const GrVkImageInfo & info,sk_sp<GrVkImageLayout> layout)103 sk_sp<GrVkTexture> GrVkTexture::MakeWrappedTexture(GrVkGpu* gpu,
104                                                    SkISize dimensions,
105                                                    GrWrapOwnership wrapOwnership,
106                                                    GrWrapCacheable cacheable,
107                                                    GrIOType ioType,
108                                                    const GrVkImageInfo& info,
109                                                    sk_sp<GrVkImageLayout> layout) {
110     // Adopted textures require both image and allocation because we're responsible for freeing
111     SkASSERT(VK_NULL_HANDLE != info.fImage &&
112              (kBorrow_GrWrapOwnership == wrapOwnership || VK_NULL_HANDLE != info.fAlloc.fMemory));
113 
114     const GrVkImageView* imageView = GrVkImageView::Create(
115             gpu, info.fImage, info.fFormat, GrVkImageView::kColor_Type, info.fLevelCount,
116             info.fYcbcrConversionInfo);
117     if (!imageView) {
118         return nullptr;
119     }
120 
121     GrMipMapsStatus mipMapsStatus = info.fLevelCount > 1 ? GrMipMapsStatus::kValid
122                                                          : GrMipMapsStatus::kNotAllocated;
123 
124     GrBackendObjectOwnership ownership = kBorrow_GrWrapOwnership == wrapOwnership
125             ? GrBackendObjectOwnership::kBorrowed : GrBackendObjectOwnership::kOwned;
126     bool isExternal = info.fYcbcrConversionInfo.isValid() &&
127                       (info.fYcbcrConversionInfo.fExternalFormat != 0);
128     return sk_sp<GrVkTexture>(new GrVkTexture(gpu, dimensions, info, std::move(layout), imageView,
129                                               mipMapsStatus, ownership, cacheable, ioType,
130                                               isExternal));
131 }
132 
~GrVkTexture()133 GrVkTexture::~GrVkTexture() {
134     // either release or abandon should have been called by the owner of this object.
135     SkASSERT(!fTextureView);
136 }
137 
onRelease()138 void GrVkTexture::onRelease() {
139     // We're about to be severed from our GrVkResource. If there are "finish" idle procs we have to
140     // decide who will handle them. If the resource is still tied to a command buffer we let it
141     // handle them. Otherwise, we handle them.
142     if (this->hasResource() && this->resource()->isOwnedByCommandBuffer()) {
143         this->removeFinishIdleProcs();
144     }
145 
146     // we create this and don't hand it off, so we should always destroy it
147     if (fTextureView) {
148         fTextureView->unref(this->getVkGpu());
149         fTextureView = nullptr;
150     }
151 
152     fDescSetCache.reset();
153 
154     this->releaseImage(this->getVkGpu());
155 
156     INHERITED::onRelease();
157 }
158 
159 struct GrVkTexture::DescriptorCacheEntry {
DescriptorCacheEntryGrVkTexture::DescriptorCacheEntry160     DescriptorCacheEntry(const GrVkDescriptorSet* fDescSet, GrVkGpu* gpu)
161             : fDescriptorSet(fDescSet), fGpu(gpu) {}
~DescriptorCacheEntryGrVkTexture::DescriptorCacheEntry162     ~DescriptorCacheEntry() {
163         if (fDescriptorSet) {
164             fDescriptorSet->recycle(fGpu);
165         }
166     }
167 
168     const GrVkDescriptorSet* fDescriptorSet;
169     GrVkGpu* fGpu;
170 };
171 
onAbandon()172 void GrVkTexture::onAbandon() {
173     // We're about to be severed from our GrVkResource. If there are "finish" idle procs we have to
174     // decide who will handle them. If the resource is still tied to a command buffer we let it
175     // handle them. Otherwise, we handle them.
176     if (this->hasResource() && this->resource()->isOwnedByCommandBuffer()) {
177         this->removeFinishIdleProcs();
178     }
179 
180     // we create this and don't hand it off, so we should always destroy it
181     if (fTextureView) {
182         fTextureView->unref(this->getVkGpu());
183         fTextureView = nullptr;
184     }
185 
186     fDescSetCache.reset();
187 
188     this->releaseImage(this->getVkGpu());
189     INHERITED::onAbandon();
190 }
191 
getBackendTexture() const192 GrBackendTexture GrVkTexture::getBackendTexture() const {
193     return GrBackendTexture(this->width(), this->height(), fInfo, this->grVkImageLayout());
194 }
195 
getVkGpu() const196 GrVkGpu* GrVkTexture::getVkGpu() const {
197     SkASSERT(!this->wasDestroyed());
198     return static_cast<GrVkGpu*>(this->getGpu());
199 }
200 
textureView()201 const GrVkImageView* GrVkTexture::textureView() {
202     return fTextureView;
203 }
204 
addIdleProc(sk_sp<GrRefCntedCallback> idleProc,IdleState type)205 void GrVkTexture::addIdleProc(sk_sp<GrRefCntedCallback> idleProc, IdleState type) {
206     INHERITED::addIdleProc(idleProc, type);
207     if (type == IdleState::kFinished) {
208         if (auto* resource = this->resource()) {
209             resource->addIdleProc(this, std::move(idleProc));
210         }
211     }
212 }
213 
callIdleProcsOnBehalfOfResource()214 void GrVkTexture::callIdleProcsOnBehalfOfResource() {
215     // If we got here then the resource is being removed from its last command buffer and the
216     // texture is idle in the cache. Any kFlush idle procs should already have been called. So
217     // the texture and resource should have the same set of procs.
218     SkASSERT(this->resource());
219     SkASSERT(this->resource()->idleProcCnt() == fIdleProcs.count());
220 #ifdef SK_DEBUG
221     for (int i = 0; i < fIdleProcs.count(); ++i) {
222         SkASSERT(fIdleProcs[i] == this->resource()->idleProc(i));
223     }
224 #endif
225     fIdleProcs.reset();
226     this->resource()->resetIdleProcs();
227 }
228 
willRemoveLastRef()229 void GrVkTexture::willRemoveLastRef() {
230     if (!fIdleProcs.count()) {
231         return;
232     }
233     // This is called when the GrTexture is purgeable. However, we need to check whether the
234     // Resource is still owned by any command buffers. If it is then it will call the proc.
235     auto* resource = this->hasResource() ? this->resource() : nullptr;
236     bool callFinishProcs = !resource || !resource->isOwnedByCommandBuffer();
237     if (callFinishProcs) {
238         // Everything must go!
239         fIdleProcs.reset();
240         if (resource) {
241             resource->resetIdleProcs();
242         }
243     } else {
244         // The procs that should be called on flush but not finish are those that are owned
245         // by the GrVkTexture and not the Resource. We do this by copying the resource's array
246         // and thereby dropping refs to procs we own but the resource does not.
247         SkASSERT(resource);
248         fIdleProcs.reset(resource->idleProcCnt());
249         for (int i = 0; i < fIdleProcs.count(); ++i) {
250             fIdleProcs[i] = resource->idleProc(i);
251         }
252     }
253 }
254 
removeFinishIdleProcs()255 void GrVkTexture::removeFinishIdleProcs() {
256     // This should only be called by onRelease/onAbandon when we have already checked for a
257     // resource.
258     const auto* resource = this->resource();
259     SkASSERT(resource);
260     SkSTArray<4, sk_sp<GrRefCntedCallback>> procsToKeep;
261     int resourceIdx = 0;
262     // The idle procs that are common between the GrVkTexture and its Resource should be found in
263     // the same order.
264     for (int i = 0; i < fIdleProcs.count(); ++i) {
265         if (fIdleProcs[i] == resource->idleProc(resourceIdx)) {
266             ++resourceIdx;
267         } else {
268             procsToKeep.push_back(fIdleProcs[i]);
269         }
270     }
271     SkASSERT(resourceIdx == resource->idleProcCnt());
272     fIdleProcs = procsToKeep;
273 }
274 
cachedSingleDescSet(GrSamplerState state)275 const GrVkDescriptorSet* GrVkTexture::cachedSingleDescSet(GrSamplerState state) {
276     if (std::unique_ptr<DescriptorCacheEntry>* e = fDescSetCache.find(state)) {
277         return (*e)->fDescriptorSet;
278     }
279     return nullptr;
280 }
281 
addDescriptorSetToCache(const GrVkDescriptorSet * descSet,GrSamplerState state)282 void GrVkTexture::addDescriptorSetToCache(const GrVkDescriptorSet* descSet, GrSamplerState state) {
283     SkASSERT(!fDescSetCache.find(state));
284     descSet->ref();
285     fDescSetCache.insert(state,
286                          std::unique_ptr<DescriptorCacheEntry>(
287                                  new DescriptorCacheEntry(descSet, this->getVkGpu())));
288 }
289