blob: ca8a2ce601e8e2e0d1d3708d9d6ab58af8cd0094 [file] [log] [blame]
Greg Daniel164a9f02016-02-22 09:56:40 -05001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/gpu/vk/GrVkTexture.h"
Robert Phillipsf95b1752017-08-31 08:56:07 -04009
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "src/gpu/GrTexturePriv.h"
Greg Daniel793c9e82019-10-29 10:07:08 -040011#include "src/gpu/vk/GrVkDescriptorSet.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050012#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"
Greg Daniel164a9f02016-02-22 09:56:40 -050016
Mike Kleinc0bd9f92019-04-23 12:05:21 -050017#include "include/gpu/vk/GrVkTypes.h"
jvanverthfd359ca2016-03-18 11:57:24 -070018
Greg Daniel164a9f02016-02-22 09:56:40 -050019#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.
22GrVkTexture::GrVkTexture(GrVkGpu* gpu,
kkinnunen2e6055b2016-04-22 01:48:29 -070023 SkBudgeted budgeted,
Brian Salomona56a7462020-02-07 14:17:25 -050024 SkISize dimensions,
egdanielb2df0c22016-05-13 11:30:37 -070025 const GrVkImageInfo& info,
Greg Daniel52e16d92018-04-10 09:34:07 -040026 sk_sp<GrVkImageLayout> layout,
Greg Daniel834f1202017-10-09 15:06:20 -040027 const GrVkImageView* view,
Greg Daniel0fc4d2d2017-10-12 11:23:36 -040028 GrMipMapsStatus mipMapsStatus)
Brian Salomona56a7462020-02-07 14:17:25 -050029 : GrSurface(gpu, dimensions, info.fProtected)
Brian Salomon60dd8c72018-07-30 10:24:13 -040030 , GrVkImage(info, std::move(layout), GrBackendObjectOwnership::kOwned)
Brian Salomona56a7462020-02-07 14:17:25 -050031 , INHERITED(gpu, dimensions, info.fProtected, GrTextureType::k2D, mipMapsStatus)
Greg Daniel793c9e82019-10-29 10:07:08 -040032 , fTextureView(view)
33 , fDescSetCache(kMaxCachedDescSets) {
Greg Daniel0fc4d2d2017-10-12 11:23:36 -040034 SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == info.fLevelCount));
Greg Daniela7b7fe02019-09-26 15:18:32 -040035 // We don't support creating external GrVkTextures
36 SkASSERT(!info.fYcbcrConversionInfo.isValid() || !info.fYcbcrConversionInfo.fExternalFormat);
kkinnunen2e6055b2016-04-22 01:48:29 -070037 this->registerWithCache(budgeted);
Jim Van Verthe3671012019-09-18 09:53:31 -040038 if (GrVkFormatIsCompressed(info.fFormat)) {
Jim Van Verth1676cb92019-01-15 13:24:45 -050039 this->setReadOnly();
40 }
kkinnunen2e6055b2016-04-22 01:48:29 -070041}
42
Brian Salomona56a7462020-02-07 14:17:25 -050043GrVkTexture::GrVkTexture(GrVkGpu* gpu, SkISize dimensions, const GrVkImageInfo& info,
Brian Salomonfa2ebea2019-01-24 15:58:58 -050044 sk_sp<GrVkImageLayout> layout, const GrVkImageView* view,
45 GrMipMapsStatus mipMapsStatus, GrBackendObjectOwnership ownership,
Greg Daniela7b7fe02019-09-26 15:18:32 -040046 GrWrapCacheable cacheable, GrIOType ioType, bool isExternal)
Brian Salomona56a7462020-02-07 14:17:25 -050047 : GrSurface(gpu, dimensions, info.fProtected)
Brian Salomon60dd8c72018-07-30 10:24:13 -040048 , GrVkImage(info, std::move(layout), ownership)
Brian Salomona56a7462020-02-07 14:17:25 -050049 , INHERITED(gpu, dimensions, info.fProtected,
Greg Daniela7b7fe02019-09-26 15:18:32 -040050 isExternal ? GrTextureType::kExternal : GrTextureType::k2D, mipMapsStatus)
Greg Daniel793c9e82019-10-29 10:07:08 -040051 , fTextureView(view)
52 , fDescSetCache(kMaxCachedDescSets) {
Greg Daniel0fc4d2d2017-10-12 11:23:36 -040053 SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == info.fLevelCount));
Brian Salomonc67c31c2018-12-06 10:00:03 -050054 if (ioType == kRead_GrIOType) {
55 this->setReadOnly();
56 }
Brian Salomonfa2ebea2019-01-24 15:58:58 -050057 this->registerWithCacheWrapped(cacheable);
Greg Daniel164a9f02016-02-22 09:56:40 -050058}
59
60// Because this class is virtually derived from GrSurface we must explicitly call its constructor.
61GrVkTexture::GrVkTexture(GrVkGpu* gpu,
Brian Salomona56a7462020-02-07 14:17:25 -050062 SkISize dimensions,
egdanielb2df0c22016-05-13 11:30:37 -070063 const GrVkImageInfo& info,
Greg Daniel52e16d92018-04-10 09:34:07 -040064 sk_sp<GrVkImageLayout> layout,
egdanielb2df0c22016-05-13 11:30:37 -070065 const GrVkImageView* view,
Greg Daniel0fc4d2d2017-10-12 11:23:36 -040066 GrMipMapsStatus mipMapsStatus,
67 GrBackendObjectOwnership ownership)
Brian Salomona56a7462020-02-07 14:17:25 -050068 : GrSurface(gpu, dimensions, info.fProtected)
Brian Salomon60dd8c72018-07-30 10:24:13 -040069 , GrVkImage(info, layout, ownership)
Brian Salomona56a7462020-02-07 14:17:25 -050070 , INHERITED(gpu, dimensions, info.fProtected, GrTextureType::k2D, mipMapsStatus)
Greg Daniel793c9e82019-10-29 10:07:08 -040071 , fTextureView(view)
72 , fDescSetCache(kMaxCachedDescSets) {
Greg Daniel0fc4d2d2017-10-12 11:23:36 -040073 SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == info.fLevelCount));
Greg Daniela7b7fe02019-09-26 15:18:32 -040074 // 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());
Greg Daniel164a9f02016-02-22 09:56:40 -050077}
78
Greg Daniel475eb702018-09-28 14:16:50 -040079sk_sp<GrVkTexture> GrVkTexture::MakeNewTexture(GrVkGpu* gpu, SkBudgeted budgeted,
Brian Salomona56a7462020-02-07 14:17:25 -050080 SkISize dimensions,
Greg Daniel475eb702018-09-28 14:16:50 -040081 const GrVkImage::ImageDesc& imageDesc,
82 GrMipMapsStatus mipMapsStatus) {
Greg Daniel164a9f02016-02-22 09:56:40 -050083 SkASSERT(imageDesc.fUsageFlags & VK_IMAGE_USAGE_SAMPLED_BIT);
84
egdanielb2df0c22016-05-13 11:30:37 -070085 GrVkImageInfo info;
86 if (!GrVkImage::InitImageInfo(gpu, imageDesc, &info)) {
Greg Daniel164a9f02016-02-22 09:56:40 -050087 return nullptr;
88 }
89
Greg Daniel7e000222018-12-03 10:08:21 -050090 const GrVkImageView* imageView = GrVkImageView::Create(
91 gpu, info.fImage, info.fFormat, GrVkImageView::kColor_Type, info.fLevelCount,
92 info.fYcbcrConversionInfo);
egdanielb2df0c22016-05-13 11:30:37 -070093 if (!imageView) {
94 GrVkImage::DestroyImageInfo(gpu, &info);
95 return nullptr;
96 }
Greg Daniel52e16d92018-04-10 09:34:07 -040097 sk_sp<GrVkImageLayout> layout(new GrVkImageLayout(info.fImageLayout));
Greg Daniel164a9f02016-02-22 09:56:40 -050098
Brian Salomona56a7462020-02-07 14:17:25 -050099 return sk_sp<GrVkTexture>(new GrVkTexture(gpu, budgeted, dimensions, info, std::move(layout),
Greg Daniel52e16d92018-04-10 09:34:07 -0400100 imageView, mipMapsStatus));
Greg Daniel164a9f02016-02-22 09:56:40 -0500101}
102
Brian Salomone8a766b2019-07-19 14:24:36 -0400103sk_sp<GrVkTexture> GrVkTexture::MakeWrappedTexture(GrVkGpu* gpu,
Brian Salomona56a7462020-02-07 14:17:25 -0500104 SkISize dimensions,
Greg Daniel1591c382017-08-17 15:37:20 -0400105 GrWrapOwnership wrapOwnership,
Brian Salomone8a766b2019-07-19 14:24:36 -0400106 GrWrapCacheable cacheable,
107 GrIOType ioType,
Greg Daniel52e16d92018-04-10 09:34:07 -0400108 const GrVkImageInfo& info,
109 sk_sp<GrVkImageLayout> layout) {
Jim Van Verth658d4992019-07-11 14:07:53 -0400110 // 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));
Greg Daniel164a9f02016-02-22 09:56:40 -0500113
Greg Daniel7e000222018-12-03 10:08:21 -0500114 const GrVkImageView* imageView = GrVkImageView::Create(
115 gpu, info.fImage, info.fFormat, GrVkImageView::kColor_Type, info.fLevelCount,
116 info.fYcbcrConversionInfo);
egdanielb2df0c22016-05-13 11:30:37 -0700117 if (!imageView) {
jvanverthfd359ca2016-03-18 11:57:24 -0700118 return nullptr;
119 }
120
Greg Daniel52e16d92018-04-10 09:34:07 -0400121 GrMipMapsStatus mipMapsStatus = info.fLevelCount > 1 ? GrMipMapsStatus::kValid
122 : GrMipMapsStatus::kNotAllocated;
Greg Daniel0fc4d2d2017-10-12 11:23:36 -0400123
Greg Daniel1591c382017-08-17 15:37:20 -0400124 GrBackendObjectOwnership ownership = kBorrow_GrWrapOwnership == wrapOwnership
125 ? GrBackendObjectOwnership::kBorrowed : GrBackendObjectOwnership::kOwned;
Greg Daniela7b7fe02019-09-26 15:18:32 -0400126 bool isExternal = info.fYcbcrConversionInfo.isValid() &&
127 (info.fYcbcrConversionInfo.fExternalFormat != 0);
Brian Salomona56a7462020-02-07 14:17:25 -0500128 return sk_sp<GrVkTexture>(new GrVkTexture(gpu, dimensions, info, std::move(layout), imageView,
Greg Daniela7b7fe02019-09-26 15:18:32 -0400129 mipMapsStatus, ownership, cacheable, ioType,
130 isExternal));
Greg Daniel164a9f02016-02-22 09:56:40 -0500131}
132
133GrVkTexture::~GrVkTexture() {
134 // either release or abandon should have been called by the owner of this object.
135 SkASSERT(!fTextureView);
136}
137
138void GrVkTexture::onRelease() {
Brian Salomone80b8092019-03-08 13:25:19 -0500139 // 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.
Brian Salomon9bc76d92019-01-24 12:18:33 -0500142 if (this->hasResource() && this->resource()->isOwnedByCommandBuffer()) {
Brian Salomone80b8092019-03-08 13:25:19 -0500143 this->removeFinishIdleProcs();
Brian Salomon9bc76d92019-01-24 12:18:33 -0500144 }
Brian Salomon614c1a82018-12-19 15:42:06 -0500145
Greg Daniel164a9f02016-02-22 09:56:40 -0500146 // 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
Greg Daniel793c9e82019-10-29 10:07:08 -0400152 fDescSetCache.reset();
153
kkinnunen2e6055b2016-04-22 01:48:29 -0700154 this->releaseImage(this->getVkGpu());
Greg Daniel164a9f02016-02-22 09:56:40 -0500155
156 INHERITED::onRelease();
157}
158
Greg Daniel793c9e82019-10-29 10:07:08 -0400159struct GrVkTexture::DescriptorCacheEntry {
160 DescriptorCacheEntry(const GrVkDescriptorSet* fDescSet, GrVkGpu* gpu)
161 : fDescriptorSet(fDescSet), fGpu(gpu) {}
162 ~DescriptorCacheEntry() {
163 if (fDescriptorSet) {
164 fDescriptorSet->recycle(fGpu);
165 }
166 }
167
168 const GrVkDescriptorSet* fDescriptorSet;
169 GrVkGpu* fGpu;
170};
171
Greg Daniel164a9f02016-02-22 09:56:40 -0500172void GrVkTexture::onAbandon() {
Brian Salomone80b8092019-03-08 13:25:19 -0500173 // 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.
Brian Salomon9bc76d92019-01-24 12:18:33 -0500176 if (this->hasResource() && this->resource()->isOwnedByCommandBuffer()) {
Brian Salomone80b8092019-03-08 13:25:19 -0500177 this->removeFinishIdleProcs();
Brian Salomon9bc76d92019-01-24 12:18:33 -0500178 }
179
Brian Salomon614c1a82018-12-19 15:42:06 -0500180 // we create this and don't hand it off, so we should always destroy it
Greg Daniel164a9f02016-02-22 09:56:40 -0500181 if (fTextureView) {
Greg Danielf0e04f02019-12-04 15:17:54 -0500182 fTextureView->unref(this->getVkGpu());
Greg Daniel164a9f02016-02-22 09:56:40 -0500183 fTextureView = nullptr;
184 }
185
Greg Daniel793c9e82019-10-29 10:07:08 -0400186 fDescSetCache.reset();
187
Greg Danielf0e04f02019-12-04 15:17:54 -0500188 this->releaseImage(this->getVkGpu());
Greg Daniel164a9f02016-02-22 09:56:40 -0500189 INHERITED::onAbandon();
190}
191
Robert Phillipsb67821d2017-12-13 15:00:45 -0500192GrBackendTexture GrVkTexture::getBackendTexture() const {
Brian Salomon4456a0d2019-07-18 15:05:11 -0400193 return GrBackendTexture(this->width(), this->height(), fInfo, this->grVkImageLayout());
Robert Phillipsb67821d2017-12-13 15:00:45 -0500194}
195
Greg Daniel164a9f02016-02-22 09:56:40 -0500196GrVkGpu* GrVkTexture::getVkGpu() const {
197 SkASSERT(!this->wasDestroyed());
198 return static_cast<GrVkGpu*>(this->getGpu());
199}
jvanverth62340062016-04-26 08:01:44 -0700200
Brian Osman2b23c4b2018-06-01 12:25:08 -0400201const GrVkImageView* GrVkTexture::textureView() {
202 return fTextureView;
brianosmanf05ab1b2016-05-12 11:01:10 -0700203}
204
Brian Salomone80b8092019-03-08 13:25:19 -0500205void 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 }
Brian Salomon614c1a82018-12-19 15:42:06 -0500211 }
212}
213
Brian Salomone80b8092019-03-08 13:25:19 -0500214void 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
Robert Phillipsbf8bf832019-08-30 13:13:44 -0400229void GrVkTexture::willRemoveLastRef() {
Brian Salomone80b8092019-03-08 13:25:19 -0500230 if (!fIdleProcs.count()) {
Brian Salomon614c1a82018-12-19 15:42:06 -0500231 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.
Brian Salomon9bc76d92019-01-24 12:18:33 -0500235 auto* resource = this->hasResource() ? this->resource() : nullptr;
Brian Salomone80b8092019-03-08 13:25:19 -0500236 bool callFinishProcs = !resource || !resource->isOwnedByCommandBuffer();
237 if (callFinishProcs) {
238 // Everything must go!
239 fIdleProcs.reset();
240 resource->resetIdleProcs();
241 } else {
242 // The procs that should be called on flush but not finish are those that are owned
243 // by the GrVkTexture and not the Resource. We do this by copying the resource's array
244 // and thereby dropping refs to procs we own but the resource does not.
245 SkASSERT(resource);
246 fIdleProcs.reset(resource->idleProcCnt());
247 for (int i = 0; i < fIdleProcs.count(); ++i) {
248 fIdleProcs[i] = resource->idleProc(i);
Brian Salomonb2c5dae2019-03-04 10:25:17 -0500249 }
Brian Salomon9bc76d92019-01-24 12:18:33 -0500250 }
Brian Salomone80b8092019-03-08 13:25:19 -0500251}
252
253void GrVkTexture::removeFinishIdleProcs() {
254 // This should only be called by onRelease/onAbandon when we have already checked for a
255 // resource.
256 const auto* resource = this->resource();
257 SkASSERT(resource);
258 SkSTArray<4, sk_sp<GrRefCntedCallback>> procsToKeep;
259 int resourceIdx = 0;
260 // The idle procs that are common between the GrVkTexture and its Resource should be found in
261 // the same order.
262 for (int i = 0; i < fIdleProcs.count(); ++i) {
263 if (fIdleProcs[i] == resource->idleProc(resourceIdx)) {
264 ++resourceIdx;
265 } else {
266 procsToKeep.push_back(fIdleProcs[i]);
267 }
268 }
269 SkASSERT(resourceIdx == resource->idleProcCnt());
270 fIdleProcs = procsToKeep;
Brian Salomon614c1a82018-12-19 15:42:06 -0500271}
Greg Daniel793c9e82019-10-29 10:07:08 -0400272
Brian Salomonccb61422020-01-09 10:46:36 -0500273const GrVkDescriptorSet* GrVkTexture::cachedSingleDescSet(GrSamplerState state) {
Greg Daniel793c9e82019-10-29 10:07:08 -0400274 if (std::unique_ptr<DescriptorCacheEntry>* e = fDescSetCache.find(state)) {
275 return (*e)->fDescriptorSet;
276 }
277 return nullptr;
278}
279
Brian Salomonccb61422020-01-09 10:46:36 -0500280void GrVkTexture::addDescriptorSetToCache(const GrVkDescriptorSet* descSet, GrSamplerState state) {
Greg Daniel793c9e82019-10-29 10:07:08 -0400281 SkASSERT(!fDescSetCache.find(state));
282 descSet->ref();
283 fDescSetCache.insert(state,
284 std::unique_ptr<DescriptorCacheEntry>(
285 new DescriptorCacheEntry(descSet, this->getVkGpu())));
286}