• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/SkBitmap.h"
9 #include "include/core/SkCanvas.h"
10 #include "include/core/SkImage.h"
11 #include "include/core/SkPixmap.h"
12 #include "include/core/SkSurface.h"
13 #include "include/gpu/GrBackendSurface.h"
14 #include "include/gpu/GrDirectContext.h"
15 #include "src/core/SkAutoPixmapStorage.h"
16 #include "src/core/SkSpecialImage.h"
17 #include "src/core/SkSpecialSurface.h"
18 #include "src/gpu/GrDirectContextPriv.h"
19 #include "src/gpu/GrProxyProvider.h"
20 #include "src/gpu/GrSurfaceProxy.h"
21 #include "src/gpu/GrTextureProxy.h"
22 #include "src/gpu/SkGr.h"
23 #include "tests/Test.h"
24 
25 // This test creates backing resources exactly sized to [kFullSize x kFullSize].
26 // It then wraps them in an SkSpecialImage with only the center (red) region being active.
27 // It then draws the SkSpecialImage to a full sized (all blue) canvas and checks that none
28 // of the inactive (green) region leaked out.
29 
30 static const int kSmallerSize = 10;
31 static const int kPad = 3;
32 static const int kFullSize = kSmallerSize + 2 * kPad;
33 
34 // Create a bitmap with red in the center and green around it
create_bm()35 static SkBitmap create_bm() {
36     SkImageInfo ii = SkImageInfo::Make(kFullSize, kFullSize, kRGBA_8888_SkColorType,
37                                        kPremul_SkAlphaType);
38 
39     SkBitmap bm;
40     bm.allocPixels(ii);
41 
42     SkCanvas temp(bm);
43 
44     temp.clear(SK_ColorGREEN);
45     SkPaint p;
46     p.setColor(SK_ColorRED);
47     p.setAntiAlias(false);
48 
49     temp.drawRect(SkRect::MakeXYWH(SkIntToScalar(kPad), SkIntToScalar(kPad),
50                                    SkIntToScalar(kSmallerSize), SkIntToScalar(kSmallerSize)),
51                   p);
52 
53     bm.setImmutable();
54     return bm;
55 }
56 
57 // 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)58 static void test_image(const sk_sp<SkSpecialImage>& img, skiatest::Reporter* reporter,
59                        GrRecordingContext* rContext, bool isGPUBacked) {
60     const SkIRect subset = img->subset();
61     REPORTER_ASSERT(reporter, kPad == subset.left());
62     REPORTER_ASSERT(reporter, kPad == subset.top());
63     REPORTER_ASSERT(reporter, kSmallerSize == subset.width());
64     REPORTER_ASSERT(reporter, kSmallerSize == subset.height());
65 
66     //--------------
67     // Test that isTextureBacked reports the correct backing type
68     REPORTER_ASSERT(reporter, isGPUBacked == img->isTextureBacked());
69 
70     //--------------
71     // Test view - as long as there is a context this should succeed
72     if (rContext) {
73         GrSurfaceProxyView view = img->view(rContext);
74         REPORTER_ASSERT(reporter, view.asTextureProxy());
75     }
76 
77     //--------------
78     // Test getROPixels - this only works for raster-backed special images
79     if (!img->isTextureBacked()) {
80         SkBitmap bitmap;
81         REPORTER_ASSERT(reporter, img->getROPixels(&bitmap));
82         REPORTER_ASSERT(reporter, kSmallerSize == bitmap.width());
83         REPORTER_ASSERT(reporter, kSmallerSize == bitmap.height());
84     }
85 
86     //--------------
87     // Test that draw restricts itself to the subset
88     sk_sp<SkSpecialSurface> surf(img->makeSurface(kN32_SkColorType, img->getColorSpace(),
89                                                   SkISize::Make(kFullSize, kFullSize),
90                                                   kPremul_SkAlphaType, SkSurfaceProps()));
91 
92     SkCanvas* canvas = surf->getCanvas();
93 
94     canvas->clear(SK_ColorBLUE);
95     img->draw(canvas, SkIntToScalar(kPad), SkIntToScalar(kPad));
96 
97     SkBitmap bm;
98     bm.allocN32Pixels(kFullSize, kFullSize, false);
99 
100     bool result = canvas->readPixels(bm.info(), bm.getPixels(), bm.rowBytes(), 0, 0);
101     SkASSERT_RELEASE(result);
102 
103     // Only the center (red) portion should've been drawn into the canvas
104     REPORTER_ASSERT(reporter, SK_ColorBLUE == bm.getColor(kPad-1, kPad-1));
105     REPORTER_ASSERT(reporter, SK_ColorRED  == bm.getColor(kPad, kPad));
106     REPORTER_ASSERT(reporter, SK_ColorRED  == bm.getColor(kSmallerSize+kPad-1,
107                                                           kSmallerSize+kPad-1));
108     REPORTER_ASSERT(reporter, SK_ColorBLUE == bm.getColor(kSmallerSize+kPad,
109                                                           kSmallerSize+kPad));
110 
111     //--------------
112     // Test that asImage & makeTightSurface return appropriately sized objects
113     // of the correct backing type
114     SkIRect newSubset = SkIRect::MakeWH(subset.width(), subset.height());
115     {
116         sk_sp<SkImage> tightImg(img->asImage(&newSubset));
117 
118         REPORTER_ASSERT(reporter, tightImg->width() == subset.width());
119         REPORTER_ASSERT(reporter, tightImg->height() == subset.height());
120         REPORTER_ASSERT(reporter, isGPUBacked == tightImg->isTextureBacked());
121         SkPixmap tmpPixmap;
122         REPORTER_ASSERT(reporter, isGPUBacked != !!tightImg->peekPixels(&tmpPixmap));
123     }
124     {
125         sk_sp<SkSurface> tightSurf(img->makeTightSurface(kN32_SkColorType, img->getColorSpace(),
126                                                          subset.size()));
127 
128         REPORTER_ASSERT(reporter, tightSurf->width() == subset.width());
129         REPORTER_ASSERT(reporter, tightSurf->height() == subset.height());
130         GrBackendTexture backendTex = tightSurf->getBackendTexture(
131                                                     SkSurface::kDiscardWrite_BackendHandleAccess);
132         REPORTER_ASSERT(reporter, isGPUBacked == backendTex.isValid());
133         SkPixmap tmpPixmap;
134         REPORTER_ASSERT(reporter, isGPUBacked != !!tightSurf->peekPixels(&tmpPixmap));
135     }
136 }
137 
DEF_TEST(SpecialImage_Raster,reporter)138 DEF_TEST(SpecialImage_Raster, reporter) {
139     SkBitmap bm = create_bm();
140 
141     sk_sp<SkSpecialImage> fullSImage(SkSpecialImage::MakeFromRaster(
142                                                             SkIRect::MakeWH(kFullSize, kFullSize),
143                                                             bm, SkSurfaceProps()));
144 
145     const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
146 
147     {
148         sk_sp<SkSpecialImage> subSImg1(SkSpecialImage::MakeFromRaster(subset, bm,
149                                                                       SkSurfaceProps()));
150         test_image(subSImg1, reporter, nullptr, false);
151     }
152 
153     {
154         sk_sp<SkSpecialImage> subSImg2(fullSImage->makeSubset(subset));
155         test_image(subSImg2, reporter, nullptr, false);
156     }
157 }
158 
test_specialimage_image(skiatest::Reporter * reporter)159 static void test_specialimage_image(skiatest::Reporter* reporter) {
160     SkBitmap bm = create_bm();
161 
162     sk_sp<SkImage> fullImage(bm.asImage());
163 
164     sk_sp<SkSpecialImage> fullSImage(SkSpecialImage::MakeFromImage(
165                                                             nullptr,
166                                                             SkIRect::MakeWH(kFullSize, kFullSize),
167                                                             fullImage,
168                                                             SkSurfaceProps()));
169 
170     const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
171 
172     {
173         sk_sp<SkSpecialImage> subSImg1(SkSpecialImage::MakeFromImage(nullptr, subset, fullImage,
174                                                                      SkSurfaceProps()));
175         test_image(subSImg1, reporter, nullptr, false);
176     }
177 
178     {
179         sk_sp<SkSpecialImage> subSImg2(fullSImage->makeSubset(subset));
180         test_image(subSImg2, reporter, nullptr, false);
181     }
182 }
183 
DEF_TEST(SpecialImage_Image_Legacy,reporter)184 DEF_TEST(SpecialImage_Image_Legacy, reporter) {
185     test_specialimage_image(reporter);
186 }
187 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SpecialImage_Gpu,reporter,ctxInfo)188 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SpecialImage_Gpu, reporter, ctxInfo) {
189     auto context = ctxInfo.directContext();
190     SkBitmap bm = create_bm();
191     auto [view, ct] = GrMakeUncachedBitmapProxyView(context, bm);
192     if (!view) {
193         return;
194     }
195 
196     sk_sp<SkSpecialImage> fullSImg =
197             SkSpecialImage::MakeDeferredFromGpu(context,
198                                                 SkIRect::MakeWH(kFullSize, kFullSize),
199                                                 kNeedNewImageUniqueID_SpecialImage,
200                                                 view,
201                                                 ct,
202                                                 nullptr,
203                                                 SkSurfaceProps());
204 
205     const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
206 
207     {
208         sk_sp<SkSpecialImage> subSImg1 = SkSpecialImage::MakeDeferredFromGpu(
209                 context,
210                 subset,
211                 kNeedNewImageUniqueID_SpecialImage,
212                 std::move(view),
213                 ct,
214                 nullptr,
215                 SkSurfaceProps());
216         test_image(subSImg1, reporter, context, true);
217     }
218 
219     {
220         sk_sp<SkSpecialImage> subSImg2 = fullSImg->makeSubset(subset);
221         test_image(subSImg2, reporter, context, true);
222     }
223 }
224