1 /*
2 * Copyright 2021 Google LLC
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/graphite/TextureProxy.h"
9
10 #include "include/gpu/graphite/Recorder.h"
11 #include "src/core/SkMipmap.h"
12 #include "src/gpu/graphite/Caps.h"
13 #include "src/gpu/graphite/RecorderPriv.h"
14 #include "src/gpu/graphite/ResourceProvider.h"
15 #include "src/gpu/graphite/ScratchResourceManager.h"
16 #include "src/gpu/graphite/Texture.h"
17 #include "src/gpu/graphite/TextureUtils.h"
18
19 namespace skgpu::graphite {
20
TextureProxy(SkISize dimensions,const TextureInfo & info,std::string_view label,skgpu::Budgeted budgeted)21 TextureProxy::TextureProxy(SkISize dimensions,
22 const TextureInfo& info,
23 std::string_view label,
24 skgpu::Budgeted budgeted)
25 : fDimensions(dimensions)
26 , fInfo(info)
27 , fLabel(label)
28 , fBudgeted(budgeted)
29 , fVolatile(Volatile::kNo) {
30 SkASSERT(fInfo.isValid());
31 }
32
TextureProxy(sk_sp<Texture> texture)33 TextureProxy::TextureProxy(sk_sp<Texture> texture)
34 : fDimensions(texture->dimensions())
35 , fInfo(texture->textureInfo())
36 , fLabel(texture->getLabel())
37 , fBudgeted(texture->budgeted())
38 , fVolatile(Volatile::kNo)
39 , fTexture(std::move(texture)) {
40 SkASSERT(fInfo.isValid());
41 }
42
TextureProxy(SkISize dimensions,const TextureInfo & textureInfo,skgpu::Budgeted budgeted,Volatile isVolatile,LazyInstantiateCallback && callback)43 TextureProxy::TextureProxy(SkISize dimensions,
44 const TextureInfo& textureInfo,
45 skgpu::Budgeted budgeted,
46 Volatile isVolatile,
47 LazyInstantiateCallback&& callback)
48 : fDimensions(dimensions)
49 , fInfo(textureInfo)
50 , fBudgeted(budgeted)
51 , fVolatile(isVolatile)
52 , fLazyInstantiateCallback(std::move(callback)) {
53 SkASSERT(fInfo.isValid());
54 SkASSERT(fLazyInstantiateCallback);
55 }
56
~TextureProxy()57 TextureProxy::~TextureProxy() {}
58
dimensions() const59 SkISize TextureProxy::dimensions() const {
60 SkASSERT(!this->isFullyLazy() || this->isInstantiated());
61 return this->isInstantiated() ? fTexture->dimensions() : fDimensions;
62 }
63
isLazy() const64 bool TextureProxy::isLazy() const {
65 return SkToBool(fLazyInstantiateCallback);
66 }
67
isFullyLazy() const68 bool TextureProxy::isFullyLazy() const {
69 bool result = fDimensions.width() < 0;
70 SkASSERT(result == (fDimensions.height() < 0));
71 SkASSERT(!result || this->isLazy());
72 return result;
73 }
74
isVolatile() const75 bool TextureProxy::isVolatile() const {
76 SkASSERT(fVolatile == Volatile::kNo || SkToBool(fLazyInstantiateCallback));
77
78 return fVolatile == Volatile::kYes;
79 }
80
uninstantiatedGpuMemorySize() const81 size_t TextureProxy::uninstantiatedGpuMemorySize() const {
82 return ComputeSize(fDimensions, fInfo);
83 }
84
instantiate(ResourceProvider * resourceProvider)85 bool TextureProxy::instantiate(ResourceProvider* resourceProvider) {
86 SkASSERT(!this->isLazy());
87
88 if (fTexture) {
89 return true;
90 }
91
92 // TODO(389908374): Once all tasks use the ScratchResourceManager, this can be updated to just
93 // finding and creating a non-shareable AND non-budgeted texture.
94 fTexture = resourceProvider->findOrCreateNonShareableTexture(
95 fDimensions, fInfo, fLabel, fBudgeted);
96 if (!fTexture) {
97 return false;
98 }
99 SkDEBUGCODE(this->validateTexture(fTexture.get()));
100 return true;
101 }
102
lazyInstantiate(ResourceProvider * resourceProvider)103 bool TextureProxy::lazyInstantiate(ResourceProvider* resourceProvider) {
104 SkASSERT(this->isLazy());
105
106 if (fTexture) {
107 return true;
108 }
109
110 fTexture = fLazyInstantiateCallback(resourceProvider);
111 if (!fTexture) {
112 return false;
113 }
114 SkDEBUGCODE(this->validateTexture(fTexture.get()));
115 return true;
116 }
117
InstantiateIfNotLazy(ResourceProvider * resourceProvider,TextureProxy * textureProxy)118 bool TextureProxy::InstantiateIfNotLazy(ResourceProvider* resourceProvider,
119 TextureProxy* textureProxy) {
120 if (textureProxy->isLazy()) {
121 return true;
122 }
123
124 return textureProxy->instantiate(resourceProvider);
125 }
126
InstantiateIfNotLazy(ScratchResourceManager * scratchManager,TextureProxy * textureProxy)127 bool TextureProxy::InstantiateIfNotLazy(ScratchResourceManager* scratchManager,
128 TextureProxy* textureProxy) {
129 if (textureProxy->isLazy() || textureProxy->isInstantiated()) {
130 return true;
131 }
132
133 textureProxy->fTexture = scratchManager->getScratchTexture(textureProxy->dimensions(),
134 textureProxy->textureInfo(),
135 textureProxy->fLabel);
136 if (!textureProxy->fTexture) {
137 return false;
138 }
139 SkDEBUGCODE(textureProxy->validateTexture(textureProxy->fTexture.get()));
140 return true;
141 }
142
143
deinstantiate()144 void TextureProxy::deinstantiate() {
145 SkASSERT(fVolatile == Volatile::kYes && SkToBool(fLazyInstantiateCallback));
146
147 fTexture.reset();
148 }
149
refTexture() const150 sk_sp<Texture> TextureProxy::refTexture() const {
151 return fTexture;
152 }
153
texture() const154 const Texture* TextureProxy::texture() const {
155 return fTexture.get();
156 }
157
Make(const Caps * caps,ResourceProvider * resourceProvider,SkISize dimensions,const TextureInfo & textureInfo,std::string_view label,skgpu::Budgeted budgeted)158 sk_sp<TextureProxy> TextureProxy::Make(const Caps* caps,
159 ResourceProvider* resourceProvider,
160 SkISize dimensions,
161 const TextureInfo& textureInfo,
162 std::string_view label,
163 skgpu::Budgeted budgeted) {
164 if (dimensions.width() < 1 || dimensions.height() < 1 ||
165 dimensions.width() > caps->maxTextureSize() ||
166 dimensions.height() > caps->maxTextureSize() ||
167 !textureInfo.isValid()) {
168 return nullptr;
169 }
170
171 sk_sp<TextureProxy> proxy{new TextureProxy(dimensions,
172 textureInfo,
173 std::move(label),
174 budgeted)};
175 if (budgeted == Budgeted::kNo) {
176 // Instantiate immediately to avoid races later on if the client starts to use the wrapping
177 // object on multiple threads.
178 if (!proxy->instantiate(resourceProvider)) {
179 return nullptr;
180 }
181 }
182 return proxy;
183 }
184
MakeLazy(const Caps * caps,SkISize dimensions,const TextureInfo & textureInfo,skgpu::Budgeted budgeted,Volatile isVolatile,LazyInstantiateCallback && callback)185 sk_sp<TextureProxy> TextureProxy::MakeLazy(const Caps* caps,
186 SkISize dimensions,
187 const TextureInfo& textureInfo,
188 skgpu::Budgeted budgeted,
189 Volatile isVolatile,
190 LazyInstantiateCallback&& callback) {
191 SkASSERT(textureInfo.isValid());
192 if (dimensions.width() < 1 || dimensions.height() < 1 ||
193 dimensions.width() > caps->maxTextureSize() ||
194 dimensions.height() > caps->maxTextureSize()) {
195 return nullptr;
196 }
197
198 return sk_sp<TextureProxy>(new TextureProxy(dimensions,
199 textureInfo,
200 budgeted,
201 isVolatile,
202 std::move(callback)));
203 }
204
MakeFullyLazy(const TextureInfo & textureInfo,skgpu::Budgeted budgeted,Volatile isVolatile,LazyInstantiateCallback && callback)205 sk_sp<TextureProxy> TextureProxy::MakeFullyLazy(const TextureInfo& textureInfo,
206 skgpu::Budgeted budgeted,
207 Volatile isVolatile,
208 LazyInstantiateCallback&& callback) {
209 SkASSERT(textureInfo.isValid());
210
211 return sk_sp<TextureProxy>(new TextureProxy(SkISize::Make(-1, -1),
212 textureInfo,
213 budgeted,
214 isVolatile,
215 std::move(callback)));
216 }
217
Wrap(sk_sp<Texture> texture)218 sk_sp<TextureProxy> TextureProxy::Wrap(sk_sp<Texture> texture) {
219 return sk_sp<TextureProxy>(new TextureProxy(std::move(texture)));
220 }
221
222 #ifdef SK_DEBUG
validateTexture(const Texture * texture)223 void TextureProxy::validateTexture(const Texture* texture) {
224 SkASSERT(this->isFullyLazy() || fDimensions == texture->dimensions());
225 SkASSERTF(fInfo.canBeFulfilledBy(texture->textureInfo()),
226 "proxy->fInfo[%s] incompatible with texture->fInfo[%s]",
227 fInfo.toString().c_str(),
228 texture->textureInfo().toString().c_str());
229 }
230 #endif
231
232 } // namespace skgpu::graphite
233