xref: /aosp_15_r20/external/skia/tests/PinnedImageTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2017 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 // This is a GPU-backend specific test.
9 #include "include/android/SkImageAndroid.h"
10 #include "include/core/SkAlphaType.h"
11 #include "include/core/SkBitmap.h"
12 #include "include/core/SkCanvas.h"
13 #include "include/core/SkColor.h"
14 #include "include/core/SkColorType.h"
15 #include "include/core/SkImage.h"
16 #include "include/core/SkImageInfo.h"
17 #include "include/core/SkMatrix.h"
18 #include "include/core/SkRefCnt.h"
19 #include "include/core/SkSamplingOptions.h"
20 #include "include/core/SkSurface.h"
21 #include "include/core/SkTileMode.h"
22 #include "include/core/SkTypes.h"
23 #include "include/gpu/GpuTypes.h"
24 #include "include/gpu/ganesh/GrDirectContext.h"
25 #include "include/gpu/ganesh/SkSurfaceGanesh.h"
26 #include "include/gpu/ganesh/mock/GrMockTypes.h"
27 #include "src/gpu/ganesh/GrFragmentProcessor.h" // IWYU pragma: keep
28 #include "src/gpu/ganesh/SkGr.h"
29 #include "src/gpu/ganesh/image/GrImageUtils.h"
30 #include "tests/CtsEnforcement.h"
31 #include "tests/Test.h"
32 #include "tools/gpu/ContextType.h"
33 #include "tools/gpu/FenceSync.h"
34 
35 #include <string>
36 
37 class GrRecordingContext;
38 struct GrContextOptions;
39 
40 using namespace sk_gpu_test;
41 
surface_is_expected_color(SkSurface * surf,const SkImageInfo & ii,SkColor color)42 static bool surface_is_expected_color(SkSurface* surf, const SkImageInfo& ii, SkColor color) {
43     SkBitmap bm;
44     bm.allocPixels(ii);
45 
46     surf->readPixels(bm, 0, 0);
47 
48     for (int y = 0; y < bm.height(); ++y) {
49         for (int x = 0; x < bm.width(); ++x) {
50             if (bm.getColor(x, y) != color) {
51                 return false;
52             }
53         }
54     }
55 
56     return true;
57 }
58 
basic_test(skiatest::Reporter * reporter,GrRecordingContext * rContext)59 static void basic_test(skiatest::Reporter* reporter, GrRecordingContext* rContext) {
60     skiatest::ReporterContext subtest(reporter, "basic_test");
61     const SkImageInfo ii = SkImageInfo::Make(64, 64, kN32_SkColorType, kPremul_SkAlphaType);
62 
63     SkBitmap bm;
64     bm.allocPixels(ii);
65 
66     SkCanvas bmCanvas(bm);
67     bmCanvas.clear(SK_ColorRED);
68 
69     // We start off with the raster image being all red.
70     sk_sp<SkImage> img = SkImages::PinnableRasterFromBitmap(bm);
71     REPORTER_ASSERT(reporter, img, "PinnableImageFromBitmap returned null");
72 
73     sk_sp<SkSurface> gpuSurface = SkSurfaces::RenderTarget(rContext, skgpu::Budgeted::kYes, ii);
74     SkCanvas* canvas = gpuSurface->getCanvas();
75 
76     // w/o pinning - the gpu draw always reflects the current state of the underlying bitmap
77     {
78         canvas->drawImage(img, 0, 0);
79         REPORTER_ASSERT(reporter, surface_is_expected_color(gpuSurface.get(), ii, SK_ColorRED));
80 
81         bmCanvas.clear(SK_ColorGREEN);
82 
83         canvas->drawImage(img, 0, 0);
84         REPORTER_ASSERT(reporter, surface_is_expected_color(gpuSurface.get(), ii, SK_ColorGREEN));
85     }
86 
87     // w/ pinning - the gpu draw is stuck at the pinned state
88     {
89         bool ok = skgpu::ganesh::PinAsTexture(rContext, img.get()); // pin at blue
90         REPORTER_ASSERT(reporter, ok, "PinAsTexture did not succeed");
91 
92         canvas->drawImage(img, 0, 0);
93         REPORTER_ASSERT(reporter, surface_is_expected_color(gpuSurface.get(), ii, SK_ColorGREEN));
94 
95         bmCanvas.clear(SK_ColorBLUE);
96 
97         canvas->drawImage(img, 0, 0);
98         REPORTER_ASSERT(reporter, surface_is_expected_color(gpuSurface.get(), ii, SK_ColorGREEN));
99 
100         skgpu::ganesh::UnpinTexture(rContext, img.get());
101     }
102 
103     // once unpinned local changes will be picked up
104     {
105         canvas->drawImage(img, 0, 0);
106         REPORTER_ASSERT(reporter, surface_is_expected_color(gpuSurface.get(), ii, SK_ColorBLUE));
107     }
108 }
109 
110 // Deleting the context while there are still pinned images shouldn't result in a crash.
cleanup_test(skiatest::Reporter * reporter)111 static void cleanup_test(skiatest::Reporter* reporter) {
112     skiatest::ReporterContext subtest(reporter, "cleanup_test");
113     const SkImageInfo ii = SkImageInfo::Make(64, 64, kN32_SkColorType, kPremul_SkAlphaType);
114 
115     SkBitmap bm;
116     bm.allocPixels(ii);
117 
118     SkCanvas bmCanvas(bm);
119     bmCanvas.clear(SK_ColorRED);
120 
121     GrMockOptions options;
122     sk_sp<GrDirectContext> mockContext = GrDirectContext::MakeMock(&options);
123 
124     for (int i = 0; i < skgpu::kContextTypeCount; ++i) {
125         auto ctxType = static_cast<skgpu::ContextType>(i);
126 
127         {
128             sk_sp<SkImage> img;
129             GrDirectContext* dContext = nullptr;
130 
131             {
132                 GrContextFactory testFactory;
133                 ContextInfo info = testFactory.getContextInfo(ctxType);
134                 dContext = info.directContext();
135                 if (!dContext) {
136                     continue;
137                 }
138 
139                 img = SkImages::PinnableRasterFromBitmap(bm);
140                 if (!skgpu::ganesh::PinAsTexture(dContext, img.get())) {
141                     continue;
142                 }
143                 // Pinning on a second context should be blocked.
144                 REPORTER_ASSERT(reporter, !skgpu::ganesh::PinAsTexture(mockContext.get(),
145                                                                        img.get()));
146             }
147 
148             // The context used to pin the image is gone at this point!
149             // "context" isn't technically used in this call but it can't be null!
150             // We don't really want to support this use case but it currently happens.
151             skgpu::ganesh::UnpinTexture(dContext, img.get());
152         }
153     }
154 }
155 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(PinnedImageTest,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)156 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(PinnedImageTest,
157                                        reporter,
158                                        ctxInfo,
159                                        CtsEnforcement::kApiLevel_T) {
160 
161     basic_test(reporter, ctxInfo.directContext());
162     cleanup_test(reporter);
163 }
164 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(PinnedImageTest_AsGaneshView,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)165 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(PinnedImageTest_AsGaneshView,
166                                        reporter,
167                                        ctxInfo,
168                                        CtsEnforcement::kApiLevel_T) {
169     GrRecordingContext* rContext = ctxInfo.directContext();
170     const SkImageInfo ii = SkImageInfo::Make(64, 64, kN32_SkColorType, kPremul_SkAlphaType);
171 
172     SkBitmap bm;
173     bm.allocPixels(ii);
174 
175     SkCanvas bmCanvas(bm);
176     bmCanvas.clear(SK_ColorMAGENTA); // arbitrary color
177 
178     sk_sp<SkImage> img = SkImages::PinnableRasterFromBitmap(bm);
179     REPORTER_ASSERT(reporter, img, "PinnableImageFromBitmap returned null");
180 
181     {
182         skiatest::ReporterContext subtest(reporter, "cached path");
183         auto [view, colortype] = skgpu::ganesh::AsView(rContext, img, skgpu::Mipmapped::kNo,
184                    GrImageTexGenPolicy::kDraw);
185         REPORTER_ASSERT(reporter, view, "AsView returned falsey view");
186     }
187 
188     {
189         skiatest::ReporterContext subtest(reporter, "unncached path");
190         auto [view, colortype] = skgpu::ganesh::AsView(rContext, img, skgpu::Mipmapped::kNo,
191                    GrImageTexGenPolicy::kNew_Uncached_Unbudgeted);
192         REPORTER_ASSERT(reporter, view, "AsView returned falsey view");
193     }
194 }
195 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(PinnedImageTest_AsFragmentProcessor,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)196 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(PinnedImageTest_AsFragmentProcessor,
197                                        reporter,
198                                        ctxInfo,
199                                        CtsEnforcement::kApiLevel_T) {
200     GrRecordingContext* rContext = ctxInfo.directContext();
201     const SkImageInfo ii = SkImageInfo::Make(64, 64, kN32_SkColorType, kPremul_SkAlphaType);
202 
203     SkBitmap bm;
204     bm.allocPixels(ii);
205 
206     SkCanvas bmCanvas(bm);
207     bmCanvas.clear(SK_ColorMAGENTA); // arbitrary color
208 
209     sk_sp<SkImage> img = SkImages::PinnableRasterFromBitmap(bm);
210     REPORTER_ASSERT(reporter, img, "PinnableImageFromBitmap returned null");
211 
212     SkTileMode tm[2] = {SkTileMode::kClamp, SkTileMode::kClamp};
213 
214     auto fp = skgpu::ganesh::AsFragmentProcessor(
215             rContext, img.get(), SkSamplingOptions({1/3, 1/3}), tm,
216             SkMatrix::I(), nullptr, nullptr);
217     REPORTER_ASSERT(reporter, fp, "AsFragmentProcessor returned falsey processor");
218 }
219