xref: /aosp_15_r20/external/skia/tests/SpecialImageTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2016 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 #include "include/core/SkAlphaType.h"
9 #include "include/core/SkBitmap.h"
10 #include "include/core/SkCanvas.h"
11 #include "include/core/SkColor.h"
12 #include "include/core/SkColorSpace.h"
13 #include "include/core/SkColorType.h"
14 #include "include/core/SkImage.h"
15 #include "include/core/SkImageInfo.h"
16 #include "include/core/SkPaint.h"
17 #include "include/core/SkRect.h"
18 #include "include/core/SkRefCnt.h"
19 #include "include/core/SkScalar.h"
20 #include "include/core/SkSize.h"
21 #include "include/core/SkSurface.h"
22 #include "include/core/SkSurfaceProps.h"
23 #include "include/core/SkTypes.h"
24 #include "include/gpu/GpuTypes.h"
25 #include "include/gpu/ganesh/GrDirectContext.h"
26 #include "include/gpu/ganesh/SkSurfaceGanesh.h"
27 #include "src/core/SkSpecialImage.h"
28 #include "src/gpu/ganesh/GrColorInfo.h" // IWYU pragma: keep
29 #include "src/gpu/ganesh/GrSurfaceProxyView.h"
30 #include "src/gpu/ganesh/SkGr.h"
31 #include "src/gpu/ganesh/image/SkSpecialImage_Ganesh.h"
32 #include "tests/CtsEnforcement.h"
33 #include "tests/Test.h"
34 
35 #include <utility>
36 
37 class GrRecordingContext;
38 struct GrContextOptions;
39 
40 // This test creates backing resources exactly sized to [kFullSize x kFullSize].
41 // It then wraps them in an SkSpecialImage with only the center (red) region being active.
42 // It then draws the SkSpecialImage to a full sized (all blue) canvas and checks that none
43 // of the inactive (green) region leaked out.
44 
45 static const int kSmallerSize = 10;
46 static const int kPad = 3;
47 static const int kFullSize = kSmallerSize + 2 * kPad;
48 
49 // Create a bitmap with red in the center and green around it
create_bm()50 static SkBitmap create_bm() {
51     SkImageInfo ii = SkImageInfo::Make(kFullSize, kFullSize, kRGBA_8888_SkColorType,
52                                        kPremul_SkAlphaType);
53 
54     SkBitmap bm;
55     bm.allocPixels(ii);
56 
57     SkCanvas temp(bm);
58 
59     temp.clear(SK_ColorGREEN);
60     SkPaint p;
61     p.setColor(SK_ColorRED);
62     p.setAntiAlias(false);
63 
64     temp.drawRect(SkRect::MakeXYWH(SkIntToScalar(kPad), SkIntToScalar(kPad),
65                                    SkIntToScalar(kSmallerSize), SkIntToScalar(kSmallerSize)),
66                   p);
67 
68     bm.setImmutable();
69     return bm;
70 }
71 
72 // Basic test of the SkSpecialImage public API (e.g., peekTexture, peekPixels & draw)
test_image(const sk_sp<SkSpecialImage> & img,skiatest::Reporter * reporter,GrRecordingContext * rContext,bool isGPUBacked)73 static void test_image(const sk_sp<SkSpecialImage>& img, skiatest::Reporter* reporter,
74                        GrRecordingContext* rContext, bool isGPUBacked) {
75     const SkIRect subset = img->subset();
76     REPORTER_ASSERT(reporter, kPad == subset.left());
77     REPORTER_ASSERT(reporter, kPad == subset.top());
78     REPORTER_ASSERT(reporter, kSmallerSize == subset.width());
79     REPORTER_ASSERT(reporter, kSmallerSize == subset.height());
80 
81     //--------------
82     // Test that isTextureBacked reports the correct backing type
83     REPORTER_ASSERT(reporter, isGPUBacked == img->isGaneshBacked());
84     REPORTER_ASSERT(reporter, !img->isGraphiteBacked());
85 
86     //--------------
87     // Test view - only succeeds if it's Ganesh backed
88     if (rContext) {
89         GrSurfaceProxyView view = SkSpecialImages::AsView(rContext, img);
90         REPORTER_ASSERT(reporter, SkToBool(view.asTextureProxy()) == isGPUBacked);
91     }
92 
93     //--------------
94     // Test AsBitmap - this only works for raster-backed special images
95     if (!img->isGaneshBacked() && !img->isGraphiteBacked()) {
96         SkBitmap bitmap;
97         REPORTER_ASSERT(reporter, SkSpecialImages::AsBitmap(img.get(), &bitmap));
98         REPORTER_ASSERT(reporter, kSmallerSize == bitmap.width());
99         REPORTER_ASSERT(reporter, kSmallerSize == bitmap.height());
100     } else {
101         SkBitmap bitmap;
102         REPORTER_ASSERT(reporter, !SkSpecialImages::AsBitmap(img.get(), &bitmap));
103     }
104 
105     //--------------
106     // Test that draw restricts itself to the subset
107     SkImageInfo imageInfo = SkImageInfo::Make(SkISize::Make(kFullSize, kFullSize),
108                                               kN32_SkColorType,
109                                               kPremul_SkAlphaType,
110                                               sk_ref_sp(img->getColorSpace()));
111     sk_sp<SkSurface> surf = isGPUBacked
112             ? SkSurfaces::RenderTarget(rContext, skgpu::Budgeted::kNo, imageInfo)
113             : SkSurfaces::Raster(imageInfo, {});
114 
115     SkCanvas* canvas = surf->getCanvas();
116 
117     canvas->clear(SK_ColorBLUE);
118     img->draw(canvas, SkIntToScalar(kPad), SkIntToScalar(kPad));
119 
120     SkBitmap bm;
121     bm.allocN32Pixels(kFullSize, kFullSize, false);
122 
123     bool result = canvas->readPixels(bm.info(), bm.getPixels(), bm.rowBytes(), 0, 0);
124     SkASSERT_RELEASE(result);
125 
126     // Only the center (red) portion should've been drawn into the canvas
127     REPORTER_ASSERT(reporter, SK_ColorBLUE == bm.getColor(kPad-1, kPad-1));
128     REPORTER_ASSERT(reporter, SK_ColorRED  == bm.getColor(kPad, kPad));
129     REPORTER_ASSERT(reporter, SK_ColorRED  == bm.getColor(kSmallerSize+kPad-1,
130                                                           kSmallerSize+kPad-1));
131     REPORTER_ASSERT(reporter, SK_ColorBLUE == bm.getColor(kSmallerSize+kPad,
132                                                           kSmallerSize+kPad));
133 }
134 
DEF_TEST(SpecialImage_Raster,reporter)135 DEF_TEST(SpecialImage_Raster, reporter) {
136     SkBitmap bm = create_bm();
137 
138     sk_sp<SkSpecialImage> fullSImage(SkSpecialImages::MakeFromRaster(
139             SkIRect::MakeWH(kFullSize, kFullSize), bm, SkSurfaceProps()));
140 
141     const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
142 
143     {
144         sk_sp<SkSpecialImage> subSImg1(
145                 SkSpecialImages::MakeFromRaster(subset, bm, SkSurfaceProps()));
146         test_image(subSImg1, reporter, nullptr, false);
147     }
148 
149     {
150         sk_sp<SkSpecialImage> subSImg2(fullSImage->makeSubset(subset));
151         test_image(subSImg2, reporter, nullptr, false);
152     }
153 }
154 
test_specialimage_image(skiatest::Reporter * reporter)155 static void test_specialimage_image(skiatest::Reporter* reporter) {
156     SkBitmap bm = create_bm();
157 
158     sk_sp<SkImage> fullImage(bm.asImage());
159 
160     sk_sp<SkSpecialImage> fullSImage(SkSpecialImages::MakeFromRaster(
161             SkIRect::MakeWH(kFullSize, kFullSize), fullImage, SkSurfaceProps()));
162 
163     const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
164 
165     {
166         sk_sp<SkSpecialImage> subSImg1(
167                 SkSpecialImages::MakeFromRaster(subset, fullImage, SkSurfaceProps()));
168         test_image(subSImg1, reporter, nullptr, false);
169     }
170 
171     {
172         sk_sp<SkSpecialImage> subSImg2(fullSImage->makeSubset(subset));
173         test_image(subSImg2, reporter, nullptr, false);
174     }
175 }
176 
DEF_TEST(SpecialImage_Image_Legacy,reporter)177 DEF_TEST(SpecialImage_Image_Legacy, reporter) {
178     test_specialimage_image(reporter);
179 }
180 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SpecialImage_Gpu,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)181 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SpecialImage_Gpu,
182                                        reporter,
183                                        ctxInfo,
184                                        CtsEnforcement::kApiLevel_T) {
185     auto context = ctxInfo.directContext();
186     SkBitmap bm = create_bm();
187     auto [view, ct] = GrMakeUncachedBitmapProxyView(context, bm);
188     if (!view) {
189         return;
190     }
191 
192     sk_sp<SkSpecialImage> fullSImg =
193             SkSpecialImages::MakeDeferredFromGpu(context,
194                                                  SkIRect::MakeWH(kFullSize, kFullSize),
195                                                  kNeedNewImageUniqueID_SpecialImage,
196                                                  view,
197                                                  {ct, kPremul_SkAlphaType, nullptr},
198                                                  SkSurfaceProps());
199 
200     const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
201 
202     {
203         sk_sp<SkSpecialImage> subSImg1 =
204                 SkSpecialImages::MakeDeferredFromGpu(context,
205                                                      subset,
206                                                      kNeedNewImageUniqueID_SpecialImage,
207                                                      std::move(view),
208                                                      {ct, kPremul_SkAlphaType, nullptr},
209                                                      SkSurfaceProps());
210         test_image(subSImg1, reporter, context, true);
211     }
212 
213     {
214         sk_sp<SkSpecialImage> subSImg2 = fullSImg->makeSubset(subset);
215         test_image(subSImg2, reporter, context, true);
216     }
217 }
218