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 // 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)
29 , GrVkImage(info, std::move(layout), GrBackendObjectOwnership::kOwned)
30 , INHERITED(gpu, desc, GrTextureType::k2D, mipMapsStatus)
31 , fTextureView(view) {
32 SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == info.fLevelCount));
33 this->registerWithCache(budgeted);
34 if (GrPixelConfigIsCompressed(desc.fConfig)) {
35 this->setReadOnly();
36 }
37 }
38
GrVkTexture(GrVkGpu * gpu,const GrSurfaceDesc & desc,const GrVkImageInfo & info,sk_sp<GrVkImageLayout> layout,const GrVkImageView * view,GrMipMapsStatus mipMapsStatus,GrBackendObjectOwnership ownership,GrWrapCacheable cacheable,GrIOType ioType)39 GrVkTexture::GrVkTexture(GrVkGpu* gpu, const GrSurfaceDesc& desc, const GrVkImageInfo& info,
40 sk_sp<GrVkImageLayout> layout, const GrVkImageView* view,
41 GrMipMapsStatus mipMapsStatus, GrBackendObjectOwnership ownership,
42 GrWrapCacheable cacheable, GrIOType ioType)
43 : GrSurface(gpu, desc)
44 , GrVkImage(info, std::move(layout), ownership)
45 , INHERITED(gpu, desc, GrTextureType::k2D, mipMapsStatus)
46 , fTextureView(view) {
47 SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == info.fLevelCount));
48 if (ioType == kRead_GrIOType) {
49 this->setReadOnly();
50 }
51 this->registerWithCacheWrapped(cacheable);
52 }
53
54 // 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)55 GrVkTexture::GrVkTexture(GrVkGpu* gpu,
56 const GrSurfaceDesc& desc,
57 const GrVkImageInfo& info,
58 sk_sp<GrVkImageLayout> layout,
59 const GrVkImageView* view,
60 GrMipMapsStatus mipMapsStatus,
61 GrBackendObjectOwnership ownership)
62 : GrSurface(gpu, desc)
63 , GrVkImage(info, layout, ownership)
64 , INHERITED(gpu, desc, GrTextureType::k2D, mipMapsStatus)
65 , fTextureView(view) {
66 SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == info.fLevelCount));
67 }
68
MakeNewTexture(GrVkGpu * gpu,SkBudgeted budgeted,const GrSurfaceDesc & desc,const GrVkImage::ImageDesc & imageDesc,GrMipMapsStatus mipMapsStatus)69 sk_sp<GrVkTexture> GrVkTexture::MakeNewTexture(GrVkGpu* gpu, SkBudgeted budgeted,
70 const GrSurfaceDesc& desc,
71 const GrVkImage::ImageDesc& imageDesc,
72 GrMipMapsStatus mipMapsStatus) {
73 SkASSERT(imageDesc.fUsageFlags & VK_IMAGE_USAGE_SAMPLED_BIT);
74
75 GrVkImageInfo info;
76 if (!GrVkImage::InitImageInfo(gpu, imageDesc, &info)) {
77 return nullptr;
78 }
79
80 const GrVkImageView* imageView = GrVkImageView::Create(
81 gpu, info.fImage, info.fFormat, GrVkImageView::kColor_Type, info.fLevelCount,
82 info.fYcbcrConversionInfo);
83 if (!imageView) {
84 GrVkImage::DestroyImageInfo(gpu, &info);
85 return nullptr;
86 }
87 sk_sp<GrVkImageLayout> layout(new GrVkImageLayout(info.fImageLayout));
88
89 return sk_sp<GrVkTexture>(new GrVkTexture(gpu, budgeted, desc, info, std::move(layout),
90 imageView, mipMapsStatus));
91 }
92
MakeWrappedTexture(GrVkGpu * gpu,const GrSurfaceDesc & desc,GrWrapOwnership wrapOwnership,GrWrapCacheable cacheable,GrIOType ioType,const GrVkImageInfo & info,sk_sp<GrVkImageLayout> layout)93 sk_sp<GrVkTexture> GrVkTexture::MakeWrappedTexture(GrVkGpu* gpu, const GrSurfaceDesc& desc,
94 GrWrapOwnership wrapOwnership,
95 GrWrapCacheable cacheable, GrIOType ioType,
96 const GrVkImageInfo& info,
97 sk_sp<GrVkImageLayout> layout) {
98 // Wrapped textures require both image and allocation (because they can be mapped)
99 SkASSERT(VK_NULL_HANDLE != info.fImage && VK_NULL_HANDLE != info.fAlloc.fMemory);
100
101 const GrVkImageView* imageView = GrVkImageView::Create(
102 gpu, info.fImage, info.fFormat, GrVkImageView::kColor_Type, info.fLevelCount,
103 info.fYcbcrConversionInfo);
104 if (!imageView) {
105 return nullptr;
106 }
107
108 GrMipMapsStatus mipMapsStatus = info.fLevelCount > 1 ? GrMipMapsStatus::kValid
109 : GrMipMapsStatus::kNotAllocated;
110
111 GrBackendObjectOwnership ownership = kBorrow_GrWrapOwnership == wrapOwnership
112 ? GrBackendObjectOwnership::kBorrowed : GrBackendObjectOwnership::kOwned;
113 return sk_sp<GrVkTexture>(new GrVkTexture(gpu, desc, info, std::move(layout), imageView,
114 mipMapsStatus, ownership, cacheable, ioType));
115 }
116
~GrVkTexture()117 GrVkTexture::~GrVkTexture() {
118 // either release or abandon should have been called by the owner of this object.
119 SkASSERT(!fTextureView);
120 }
121
onRelease()122 void GrVkTexture::onRelease() {
123 // We're about to be severed from our GrVkResource. If there is an idle proc we have to decide
124 // who will handle it. If the resource is still tied to a command buffer we let it handle it.
125 // Otherwise, we handle it.
126 if (this->hasResource() && this->resource()->isOwnedByCommandBuffer()) {
127 fIdleProc = nullptr;
128 fIdleProcContext = nullptr;
129 }
130
131 // we create this and don't hand it off, so we should always destroy it
132 if (fTextureView) {
133 fTextureView->unref(this->getVkGpu());
134 fTextureView = nullptr;
135 }
136
137 this->releaseImage(this->getVkGpu());
138
139 INHERITED::onRelease();
140 }
141
onAbandon()142 void GrVkTexture::onAbandon() {
143 // We're about to be severed from our GrVkResource. If there is an idle proc we have to decide
144 // who will handle it. If the resource is still tied to a command buffer we let it handle it.
145 // Otherwise, we handle it.
146 if (this->hasResource() && this->resource()->isOwnedByCommandBuffer()) {
147 fIdleProc = nullptr;
148 fIdleProcContext = nullptr;
149 }
150
151 // we create this and don't hand it off, so we should always destroy it
152 if (fTextureView) {
153 fTextureView->unrefAndAbandon();
154 fTextureView = nullptr;
155 }
156
157 this->abandonImage();
158 INHERITED::onAbandon();
159 }
160
getBackendTexture() const161 GrBackendTexture GrVkTexture::getBackendTexture() const {
162 return GrBackendTexture(this->width(), this->height(), fInfo, this->grVkImageLayout());
163 }
164
getVkGpu() const165 GrVkGpu* GrVkTexture::getVkGpu() const {
166 SkASSERT(!this->wasDestroyed());
167 return static_cast<GrVkGpu*>(this->getGpu());
168 }
169
textureView()170 const GrVkImageView* GrVkTexture::textureView() {
171 return fTextureView;
172 }
173
setIdleProc(IdleProc proc,void * context)174 void GrVkTexture::setIdleProc(IdleProc proc, void* context) {
175 fIdleProc = proc;
176 fIdleProcContext = context;
177 if (auto* resource = this->resource()) {
178 resource->setIdleProc(proc ? this : nullptr, proc, context);
179 }
180 }
181
removedLastRefOrPendingIO()182 void GrVkTexture::removedLastRefOrPendingIO() {
183 if (!fIdleProc) {
184 return;
185 }
186 // This is called when the GrTexture is purgeable. However, we need to check whether the
187 // Resource is still owned by any command buffers. If it is then it will call the proc.
188 auto* resource = this->hasResource() ? this->resource() : nullptr;
189 if (resource && resource->isOwnedByCommandBuffer()) {
190 return;
191 }
192 fIdleProc(fIdleProcContext);
193 fIdleProc = nullptr;
194 fIdleProcContext = nullptr;
195 if (resource) {
196 resource->setIdleProc(nullptr, nullptr, nullptr);
197 }
198 }
199