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