xref: /aosp_15_r20/external/skia/tests/graphite/TextureProxyTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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