blob: 5d09f66fcaf243b4fe4d53595ad494af42b427dc [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"
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"
Greg Daniel164a9f02016-02-22 09:56:40 -050015
Mike Kleinc0bd9f92019-04-23 12:05:21 -050016#include "include/gpu/vk/GrVkTypes.h"
jvanverthfd359ca2016-03-18 11:57:24 -070017
Greg Daniel164a9f02016-02-22 09:56:40 -050018#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.
21GrVkTexture::GrVkTexture(GrVkGpu* gpu,
kkinnunen2e6055b2016-04-22 01:48:29 -070022 SkBudgeted budgeted,
Greg Daniel164a9f02016-02-22 09:56:40 -050023 const GrSurfaceDesc& desc,
egdanielb2df0c22016-05-13 11:30:37 -070024 const GrVkImageInfo& info,
Greg Daniel52e16d92018-04-10 09:34:07 -040025 sk_sp<GrVkImageLayout> layout,
Greg Daniel834f1202017-10-09 15:06:20 -040026 const GrVkImageView* view,
Greg Daniel0fc4d2d2017-10-12 11:23:36 -040027 GrMipMapsStatus mipMapsStatus)
Brian Salomona9c22572019-08-05 12:57:09 -040028 : GrSurface(gpu, {desc.fWidth, desc.fHeight}, desc.fConfig, info.fProtected)
Brian Salomon60dd8c72018-07-30 10:24:13 -040029 , GrVkImage(info, std::move(layout), GrBackendObjectOwnership::kOwned)
Brian Salomona9c22572019-08-05 12:57:09 -040030 , INHERITED(gpu, {desc.fWidth, desc.fHeight}, desc.fConfig, info.fProtected,
31 GrTextureType::k2D, mipMapsStatus)
Brian Salomon60dd8c72018-07-30 10:24:13 -040032 , fTextureView(view) {
Greg Daniel0fc4d2d2017-10-12 11:23:36 -040033 SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == info.fLevelCount));
kkinnunen2e6055b2016-04-22 01:48:29 -070034 this->registerWithCache(budgeted);
Jim Van Verthe3671012019-09-18 09:53:31 -040035 if (GrVkFormatIsCompressed(info.fFormat)) {
Jim Van Verth1676cb92019-01-15 13:24:45 -050036 this->setReadOnly();
37 }
kkinnunen2e6055b2016-04-22 01:48:29 -070038}
39
Brian Salomonfa2ebea2019-01-24 15:58:58 -050040GrVkTexture::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)
Brian Salomona9c22572019-08-05 12:57:09 -040044 : GrSurface(gpu, {desc.fWidth, desc.fHeight}, desc.fConfig, info.fProtected)
Brian Salomon60dd8c72018-07-30 10:24:13 -040045 , GrVkImage(info, std::move(layout), ownership)
Brian Salomona9c22572019-08-05 12:57:09 -040046 , INHERITED(gpu, {desc.fWidth, desc.fHeight}, desc.fConfig, info.fProtected,
47 GrTextureType::k2D, mipMapsStatus)
Brian Salomon60dd8c72018-07-30 10:24:13 -040048 , fTextureView(view) {
Greg Daniel0fc4d2d2017-10-12 11:23:36 -040049 SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == info.fLevelCount));
Brian Salomonc67c31c2018-12-06 10:00:03 -050050 if (ioType == kRead_GrIOType) {
51 this->setReadOnly();
52 }
Brian Salomonfa2ebea2019-01-24 15:58:58 -050053 this->registerWithCacheWrapped(cacheable);
Greg Daniel164a9f02016-02-22 09:56:40 -050054}
55
56// Because this class is virtually derived from GrSurface we must explicitly call its constructor.
57GrVkTexture::GrVkTexture(GrVkGpu* gpu,
58 const GrSurfaceDesc& desc,
egdanielb2df0c22016-05-13 11:30:37 -070059 const GrVkImageInfo& info,
Greg Daniel52e16d92018-04-10 09:34:07 -040060 sk_sp<GrVkImageLayout> layout,
egdanielb2df0c22016-05-13 11:30:37 -070061 const GrVkImageView* view,
Greg Daniel0fc4d2d2017-10-12 11:23:36 -040062 GrMipMapsStatus mipMapsStatus,
63 GrBackendObjectOwnership ownership)
Brian Salomona9c22572019-08-05 12:57:09 -040064 : GrSurface(gpu, {desc.fWidth, desc.fHeight}, desc.fConfig, info.fProtected)
Brian Salomon60dd8c72018-07-30 10:24:13 -040065 , GrVkImage(info, layout, ownership)
Brian Salomona9c22572019-08-05 12:57:09 -040066 , INHERITED(gpu, {desc.fWidth, desc.fHeight}, desc.fConfig, info.fProtected,
67 GrTextureType::k2D, mipMapsStatus)
Brian Salomon60dd8c72018-07-30 10:24:13 -040068 , fTextureView(view) {
Greg Daniel0fc4d2d2017-10-12 11:23:36 -040069 SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == info.fLevelCount));
Greg Daniel164a9f02016-02-22 09:56:40 -050070}
71
Greg Daniel475eb702018-09-28 14:16:50 -040072sk_sp<GrVkTexture> GrVkTexture::MakeNewTexture(GrVkGpu* gpu, SkBudgeted budgeted,
73 const GrSurfaceDesc& desc,
74 const GrVkImage::ImageDesc& imageDesc,
75 GrMipMapsStatus mipMapsStatus) {
Greg Daniel164a9f02016-02-22 09:56:40 -050076 SkASSERT(imageDesc.fUsageFlags & VK_IMAGE_USAGE_SAMPLED_BIT);
77
egdanielb2df0c22016-05-13 11:30:37 -070078 GrVkImageInfo info;
79 if (!GrVkImage::InitImageInfo(gpu, imageDesc, &info)) {
Greg Daniel164a9f02016-02-22 09:56:40 -050080 return nullptr;
81 }
82
Greg Daniel7e000222018-12-03 10:08:21 -050083 const GrVkImageView* imageView = GrVkImageView::Create(
84 gpu, info.fImage, info.fFormat, GrVkImageView::kColor_Type, info.fLevelCount,
85 info.fYcbcrConversionInfo);
egdanielb2df0c22016-05-13 11:30:37 -070086 if (!imageView) {
87 GrVkImage::DestroyImageInfo(gpu, &info);
88 return nullptr;
89 }
Greg Daniel52e16d92018-04-10 09:34:07 -040090 sk_sp<GrVkImageLayout> layout(new GrVkImageLayout(info.fImageLayout));
Greg Daniel164a9f02016-02-22 09:56:40 -050091
Greg Daniel52e16d92018-04-10 09:34:07 -040092 return sk_sp<GrVkTexture>(new GrVkTexture(gpu, budgeted, desc, info, std::move(layout),
93 imageView, mipMapsStatus));
Greg Daniel164a9f02016-02-22 09:56:40 -050094}
95
Brian Salomone8a766b2019-07-19 14:24:36 -040096sk_sp<GrVkTexture> GrVkTexture::MakeWrappedTexture(GrVkGpu* gpu,
97 const GrSurfaceDesc& desc,
Greg Daniel1591c382017-08-17 15:37:20 -040098 GrWrapOwnership wrapOwnership,
Brian Salomone8a766b2019-07-19 14:24:36 -040099 GrWrapCacheable cacheable,
100 GrIOType ioType,
Greg Daniel52e16d92018-04-10 09:34:07 -0400101 const GrVkImageInfo& info,
102 sk_sp<GrVkImageLayout> layout) {
Jim Van Verth658d4992019-07-11 14:07:53 -0400103 // 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));
Greg Daniel164a9f02016-02-22 09:56:40 -0500106
Greg Daniel7e000222018-12-03 10:08:21 -0500107 const GrVkImageView* imageView = GrVkImageView::Create(
108 gpu, info.fImage, info.fFormat, GrVkImageView::kColor_Type, info.fLevelCount,
109 info.fYcbcrConversionInfo);
egdanielb2df0c22016-05-13 11:30:37 -0700110 if (!imageView) {
jvanverthfd359ca2016-03-18 11:57:24 -0700111 return nullptr;
112 }
113
Greg Daniel52e16d92018-04-10 09:34:07 -0400114 GrMipMapsStatus mipMapsStatus = info.fLevelCount > 1 ? GrMipMapsStatus::kValid
115 : GrMipMapsStatus::kNotAllocated;
Greg Daniel0fc4d2d2017-10-12 11:23:36 -0400116
Greg Daniel1591c382017-08-17 15:37:20 -0400117 GrBackendObjectOwnership ownership = kBorrow_GrWrapOwnership == wrapOwnership
118 ? GrBackendObjectOwnership::kBorrowed : GrBackendObjectOwnership::kOwned;
Brian Salomonfa2ebea2019-01-24 15:58:58 -0500119 return sk_sp<GrVkTexture>(new GrVkTexture(gpu, desc, info, std::move(layout), imageView,
120 mipMapsStatus, ownership, cacheable, ioType));
Greg Daniel164a9f02016-02-22 09:56:40 -0500121}
122
123GrVkTexture::~GrVkTexture() {
124 // either release or abandon should have been called by the owner of this object.
125 SkASSERT(!fTextureView);
126}
127
128void GrVkTexture::onRelease() {
Brian Salomone80b8092019-03-08 13:25:19 -0500129 // 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.
Brian Salomon9bc76d92019-01-24 12:18:33 -0500132 if (this->hasResource() && this->resource()->isOwnedByCommandBuffer()) {
Brian Salomone80b8092019-03-08 13:25:19 -0500133 this->removeFinishIdleProcs();
Brian Salomon9bc76d92019-01-24 12:18:33 -0500134 }
Brian Salomon614c1a82018-12-19 15:42:06 -0500135
Greg Daniel164a9f02016-02-22 09:56:40 -0500136 // 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
kkinnunen2e6055b2016-04-22 01:48:29 -0700142 this->releaseImage(this->getVkGpu());
Greg Daniel164a9f02016-02-22 09:56:40 -0500143
144 INHERITED::onRelease();
145}
146
147void GrVkTexture::onAbandon() {
Brian Salomone80b8092019-03-08 13:25:19 -0500148 // 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.
Brian Salomon9bc76d92019-01-24 12:18:33 -0500151 if (this->hasResource() && this->resource()->isOwnedByCommandBuffer()) {
Brian Salomone80b8092019-03-08 13:25:19 -0500152 this->removeFinishIdleProcs();
Brian Salomon9bc76d92019-01-24 12:18:33 -0500153 }
154
Brian Salomon614c1a82018-12-19 15:42:06 -0500155 // we create this and don't hand it off, so we should always destroy it
Greg Daniel164a9f02016-02-22 09:56:40 -0500156 if (fTextureView) {
157 fTextureView->unrefAndAbandon();
158 fTextureView = nullptr;
159 }
160
161 this->abandonImage();
162 INHERITED::onAbandon();
163}
164
Robert Phillipsb67821d2017-12-13 15:00:45 -0500165GrBackendTexture GrVkTexture::getBackendTexture() const {
Brian Salomon4456a0d2019-07-18 15:05:11 -0400166 return GrBackendTexture(this->width(), this->height(), fInfo, this->grVkImageLayout());
Robert Phillipsb67821d2017-12-13 15:00:45 -0500167}
168
Greg Daniel164a9f02016-02-22 09:56:40 -0500169GrVkGpu* GrVkTexture::getVkGpu() const {
170 SkASSERT(!this->wasDestroyed());
171 return static_cast<GrVkGpu*>(this->getGpu());
172}
jvanverth62340062016-04-26 08:01:44 -0700173
Brian Osman2b23c4b2018-06-01 12:25:08 -0400174const GrVkImageView* GrVkTexture::textureView() {
175 return fTextureView;
brianosmanf05ab1b2016-05-12 11:01:10 -0700176}
177
Brian Salomone80b8092019-03-08 13:25:19 -0500178void 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 }
Brian Salomon614c1a82018-12-19 15:42:06 -0500184 }
185}
186
Brian Salomone80b8092019-03-08 13:25:19 -0500187void 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
Robert Phillipsbf8bf832019-08-30 13:13:44 -0400202void GrVkTexture::willRemoveLastRef() {
Brian Salomone80b8092019-03-08 13:25:19 -0500203 if (!fIdleProcs.count()) {
Brian Salomon614c1a82018-12-19 15:42:06 -0500204 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.
Brian Salomon9bc76d92019-01-24 12:18:33 -0500208 auto* resource = this->hasResource() ? this->resource() : nullptr;
Brian Salomone80b8092019-03-08 13:25:19 -0500209 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);
Brian Salomonb2c5dae2019-03-04 10:25:17 -0500222 }
Brian Salomon9bc76d92019-01-24 12:18:33 -0500223 }
Brian Salomone80b8092019-03-08 13:25:19 -0500224}
225
226void 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;
Brian Salomon614c1a82018-12-19 15:42:06 -0500244}