1 /*
2 * Copyright 2022 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 "tests/Test.h"
9
10 #include "include/core/SkBitmap.h"
11 #include "include/core/SkCanvas.h"
12 #include "include/core/SkColorSpace.h"
13 #include "include/gpu/graphite/BackendTexture.h"
14 #include "include/gpu/graphite/Context.h"
15 #include "include/gpu/graphite/Image.h"
16 #include "include/gpu/graphite/Recorder.h"
17 #include "include/gpu/graphite/Surface.h"
18 #include "src/gpu/graphite/Caps.h"
19 #include "src/gpu/graphite/ContextPriv.h"
20 #include "src/gpu/graphite/RecorderPriv.h"
21 #include "src/gpu/graphite/ResourceProvider.h"
22 #include "src/gpu/graphite/Texture.h"
23 #include "src/gpu/graphite/TextureProxy.h"
24
25 namespace skgpu::graphite {
26
DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(GraphiteTextureProxyTest,reporter,context,CtsEnforcement::kApiLevel_V)27 DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(GraphiteTextureProxyTest, reporter, context,
28 CtsEnforcement::kApiLevel_V) {
29 const Caps* caps = context->priv().caps();
30 constexpr SkISize kValidSize = SkISize::Make(1, 1);
31 constexpr SkISize kInvalidSize = SkISize::MakeEmpty();
32 constexpr SkColorType kValidColorType = kRGBA_8888_SkColorType;
33 constexpr SkColorType kInvalidColorType = kUnknown_SkColorType;
34
35 Protected isProtected = Protected(caps->protectedSupport());
36
37 std::unique_ptr<Recorder> recorder = context->makeRecorder();
38 ResourceProvider* resourceProvider = recorder->priv().resourceProvider();
39 const TextureInfo textureInfo = caps->getDefaultSampledTextureInfo(
40 kValidColorType, Mipmapped::kNo, isProtected, Renderable::kNo);
41 BackendTexture backendTexture = recorder->createBackendTexture(kValidSize, textureInfo);
42 sk_sp<Texture> texture = resourceProvider->createWrappedTexture(backendTexture,
43 "TextureProxyTestWrappedTex");
44
45 auto makeProxy = [&](SkISize dimensions, SkColorType colorType, Mipmapped mipmapped,
46 Protected isProtected, Renderable renderable, Budgeted budgeted) {
47 auto textureInfo = caps->getDefaultSampledTextureInfo(colorType, mipmapped,
48 isProtected, renderable);
49 return TextureProxy::Make(caps, recorder->priv().resourceProvider(),
50 dimensions, textureInfo, "TextureProxyTestTexture", budgeted);
51 };
52
53 auto nullCallback = [](ResourceProvider*) -> sk_sp<Texture> { return nullptr; };
54 auto callback = [texture](ResourceProvider*) -> sk_sp<Texture> { return texture; };
55
56 // Assign to assignableTexture before instantiating with this callback.
57 sk_sp<Texture> assignableTexture;
58 auto assignableCallback = [&assignableTexture](ResourceProvider*) -> sk_sp<Texture> {
59 return assignableTexture;
60 };
61
62 // Invalid parameters.
63 sk_sp<TextureProxy> textureProxy;
64 textureProxy = makeProxy(kInvalidSize,
65 kValidColorType,
66 Mipmapped::kNo,
67 isProtected,
68 Renderable::kNo,
69 skgpu::Budgeted::kNo);
70 REPORTER_ASSERT(reporter, textureProxy == nullptr);
71 textureProxy = makeProxy(kValidSize,
72 kInvalidColorType,
73 Mipmapped::kNo,
74 isProtected,
75 Renderable::kNo,
76 skgpu::Budgeted::kNo);
77 REPORTER_ASSERT(reporter, textureProxy == nullptr);
78
79 // Non-budgeted, non-lazy TextureProxy is instantiated on return
80 textureProxy = makeProxy(kValidSize,
81 kValidColorType,
82 Mipmapped::kNo,
83 isProtected,
84 Renderable::kNo,
85 skgpu::Budgeted::kNo);
86 REPORTER_ASSERT(reporter, !textureProxy->isLazy());
87 REPORTER_ASSERT(reporter, !textureProxy->isFullyLazy());
88 REPORTER_ASSERT(reporter, !textureProxy->isVolatile());
89 REPORTER_ASSERT(reporter, textureProxy->isInstantiated());
90 REPORTER_ASSERT(reporter, textureProxy->dimensions() == kValidSize);
91
92 // Budgeted, non-lazy TextureProxy, successful instantiation later on
93 textureProxy = makeProxy(kValidSize,
94 kValidColorType,
95 Mipmapped::kNo,
96 isProtected,
97 Renderable::kNo,
98 skgpu::Budgeted::kYes);
99 REPORTER_ASSERT(reporter, !textureProxy->isLazy());
100 REPORTER_ASSERT(reporter, !textureProxy->isFullyLazy());
101 REPORTER_ASSERT(reporter, !textureProxy->isVolatile());
102 REPORTER_ASSERT(reporter, !textureProxy->isInstantiated());
103 REPORTER_ASSERT(reporter, textureProxy->dimensions() == kValidSize);
104
105 bool instantiateSuccess = textureProxy->instantiate(resourceProvider);
106 REPORTER_ASSERT(reporter, instantiateSuccess);
107 REPORTER_ASSERT(reporter, textureProxy->isInstantiated());
108 REPORTER_ASSERT(reporter, textureProxy->dimensions() == kValidSize);
109 const Texture* createdTexture = textureProxy->texture();
110
111 instantiateSuccess = textureProxy->instantiate(resourceProvider);
112 REPORTER_ASSERT(reporter, instantiateSuccess);
113 REPORTER_ASSERT(reporter, textureProxy->texture() == createdTexture);
114
115 // Lazy, non-volatile TextureProxy, unsuccessful instantiation.
116 textureProxy = TextureProxy::MakeLazy(
117 caps, kValidSize, textureInfo, skgpu::Budgeted::kNo, Volatile::kNo, nullCallback);
118 REPORTER_ASSERT(reporter, textureProxy->isLazy());
119 REPORTER_ASSERT(reporter, !textureProxy->isFullyLazy());
120 REPORTER_ASSERT(reporter, !textureProxy->isVolatile());
121
122 instantiateSuccess = textureProxy->lazyInstantiate(resourceProvider);
123 REPORTER_ASSERT(reporter, !instantiateSuccess);
124 REPORTER_ASSERT(reporter, !textureProxy->isInstantiated());
125
126 // Lazy, non-volatile TextureProxy, successful instantiation.
127 textureProxy = TextureProxy::MakeLazy(
128 caps, kValidSize, textureInfo, skgpu::Budgeted::kNo, Volatile::kNo, callback);
129
130 instantiateSuccess = textureProxy->lazyInstantiate(resourceProvider);
131 REPORTER_ASSERT(reporter, instantiateSuccess);
132 REPORTER_ASSERT(reporter, textureProxy->texture() == texture.get());
133
134 // Lazy, volatile TextureProxy, unsuccessful instantiation.
135 textureProxy = TextureProxy::MakeLazy(
136 caps, kValidSize, textureInfo, skgpu::Budgeted::kNo, Volatile::kYes, nullCallback);
137 REPORTER_ASSERT(reporter, textureProxy->isLazy());
138 REPORTER_ASSERT(reporter, !textureProxy->isFullyLazy());
139 REPORTER_ASSERT(reporter, textureProxy->isVolatile());
140
141 instantiateSuccess = textureProxy->lazyInstantiate(resourceProvider);
142 REPORTER_ASSERT(reporter, !instantiateSuccess);
143 REPORTER_ASSERT(reporter, !textureProxy->isInstantiated());
144
145 // Lazy, volatile TextureProxy, successful instantiation.
146 textureProxy = TextureProxy::MakeLazy(
147 caps, kValidSize, textureInfo, skgpu::Budgeted::kNo, Volatile::kYes, callback);
148
149 instantiateSuccess = textureProxy->lazyInstantiate(resourceProvider);
150 REPORTER_ASSERT(reporter, instantiateSuccess);
151 REPORTER_ASSERT(reporter, textureProxy->texture() == texture.get());
152
153 textureProxy->deinstantiate();
154 REPORTER_ASSERT(reporter, !textureProxy->isInstantiated());
155
156 // Fully-lazy TextureProxy.
157 textureProxy = TextureProxy::MakeFullyLazy(
158 textureInfo, skgpu::Budgeted::kNo, Volatile::kYes, assignableCallback);
159 REPORTER_ASSERT(reporter, textureProxy->isLazy());
160 REPORTER_ASSERT(reporter, textureProxy->isFullyLazy());
161 REPORTER_ASSERT(reporter, textureProxy->isVolatile());
162
163 assignableTexture = texture;
164 instantiateSuccess = textureProxy->lazyInstantiate(resourceProvider);
165 REPORTER_ASSERT(reporter, instantiateSuccess);
166 REPORTER_ASSERT(reporter, textureProxy->isInstantiated());
167 REPORTER_ASSERT(reporter, textureProxy->isFullyLazy());
168 REPORTER_ASSERT(reporter, textureProxy->dimensions() == kValidSize);
169
170 textureProxy->deinstantiate();
171 REPORTER_ASSERT(reporter, !textureProxy->isInstantiated());
172 REPORTER_ASSERT(reporter, textureProxy->isFullyLazy());
173
174 constexpr SkISize kLargerSize = SkISize::Make(2, 2);
175 BackendTexture largerBackendTexture =
176 recorder->createBackendTexture(kLargerSize, textureInfo);
177 assignableTexture = resourceProvider->createWrappedTexture(largerBackendTexture,
178 "TextureProxyTestWrappedTex");
179 instantiateSuccess = textureProxy->lazyInstantiate(resourceProvider);
180 REPORTER_ASSERT(reporter, instantiateSuccess);
181 REPORTER_ASSERT(reporter, textureProxy->dimensions() == kLargerSize);
182
183 // InstantiateIfNotLazy tests.
184 textureProxy = makeProxy(kValidSize,
185 kValidColorType,
186 Mipmapped::kNo,
187 isProtected,
188 Renderable::kNo,
189 skgpu::Budgeted::kYes);
190 instantiateSuccess = TextureProxy::InstantiateIfNotLazy(resourceProvider, textureProxy.get());
191 REPORTER_ASSERT(reporter, instantiateSuccess);
192
193 textureProxy = TextureProxy::MakeLazy(
194 caps, kValidSize, textureInfo, skgpu::Budgeted::kNo, Volatile::kNo, nullCallback);
195 instantiateSuccess = TextureProxy::InstantiateIfNotLazy(resourceProvider, textureProxy.get());
196 REPORTER_ASSERT(reporter, instantiateSuccess);
197 // Clean up the backend textures.
198 recorder->deleteBackendTexture(backendTexture);
199 recorder->deleteBackendTexture(largerBackendTexture);
200 }
201
DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(GraphiteTextureTooLargeTest,reporter,context,CtsEnforcement::kApiLevel_V)202 DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(GraphiteTextureTooLargeTest, reporter, context,
203 CtsEnforcement::kApiLevel_V) {
204 std::unique_ptr<Recorder> recorder = context->makeRecorder();
205 const Caps* caps = context->priv().caps();
206
207 // Try to create a texture that is too large for the backend.
208 SkBitmap bitmap;
209 SkISize dimensions = SkISize::Make(caps->maxTextureSize() + 1, 1);
210 bitmap.allocPixels(SkImageInfo::Make(
211 dimensions, SkColorType::kRGBA_8888_SkColorType, SkAlphaType::kPremul_SkAlphaType));
212 sk_sp<SkImage> rasterImage = SkImages::RasterFromBitmap(bitmap);
213 sk_sp<SkImage> graphiteImage =
214 SkImages::TextureFromImage(recorder.get(), rasterImage.get(), /*requiredProps=*/{});
215
216 // Image creation should have failed.
217 REPORTER_ASSERT(reporter, !graphiteImage);
218
219 // Snapping should still succeed, no texture upload should actually be attempted.
220 REPORTER_ASSERT(reporter, recorder->snap());
221 }
222
DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(GraphiteLazyTextureInvalidDimensions,reporter,context,CtsEnforcement::kApiLevel_V)223 DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(GraphiteLazyTextureInvalidDimensions, reporter, context,
224 CtsEnforcement::kApiLevel_V) {
225 class FulfillContext {
226 public:
227 FulfillContext(BackendTexture backendTexture) : fBackendTexture(backendTexture) {}
228
229 static std::tuple<BackendTexture, void*> Fulfill(void* ctx) {
230 FulfillContext* self = reinterpret_cast<FulfillContext*>(ctx);
231 return {self->fBackendTexture, nullptr};
232 }
233
234 BackendTexture fBackendTexture;
235 };
236
237 std::unique_ptr<Recorder> recorder = context->makeRecorder();
238 const Caps* caps = context->priv().caps();
239
240 // Try to create textures with invalid dimensions.
241 SkISize largeDimensions = SkISize::Make(caps->maxTextureSize() + 1, 1);
242 SkISize negativeDimensions = SkISize::Make(-1, -1);
243
244 for (const SkISize& dimensions : {largeDimensions, negativeDimensions}) {
245 SkImageInfo imageInfo = SkImageInfo::Make(
246 dimensions, SkColorType::kRGBA_8888_SkColorType, SkAlphaType::kPremul_SkAlphaType);
247 TextureInfo textureInfo = caps->getDefaultSampledTextureInfo(
248 imageInfo.colorInfo().colorType(), Mipmapped::kNo, Protected::kNo, Renderable::kNo);
249
250 // The created BackendTexture should be invalid, so an invalid texture would be used to
251 // fulfill the promise image created later, if we were to attempt to draw it.
252 BackendTexture backendTexture =
253 recorder->createBackendTexture(imageInfo.dimensions(), textureInfo);
254 FulfillContext fulfillContext(backendTexture);
255 REPORTER_ASSERT(reporter, !backendTexture.isValid());
256
257 // Drawing should still succeed, as no image draw should actually be attempted with this
258 // texture.
259 SkImageInfo surfaceImageInfo = SkImageInfo::Make(
260 1, 1, SkColorType::kRGBA_8888_SkColorType, SkAlphaType::kPremul_SkAlphaType);
261 sk_sp<SkSurface> surface = SkSurfaces::RenderTarget(recorder.get(), surfaceImageInfo);
262 sk_sp<SkImage> promiseImage = SkImages::PromiseTextureFrom(recorder.get(),
263 imageInfo.dimensions(),
264 textureInfo,
265 imageInfo.colorInfo(),
266 Volatile::kNo,
267 FulfillContext::Fulfill,
268 nullptr,
269 nullptr,
270 &fulfillContext);
271
272 surface->getCanvas()->drawImage(promiseImage, 0.0f, 0.0f);
273 std::unique_ptr<Recording> recording = recorder->snap();
274 REPORTER_ASSERT(reporter, context->insertRecording({recording.get()}));
275 // Clean up backend texture
276 context->deleteBackendTexture(fulfillContext.fBackendTexture);
277 }
278 }
279
280 } // namespace skgpu::graphite
281