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