• 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 "src/core/SkAutoPixmapStorage.h"
14 #include "src/core/SkSpecialImage.h"
15 #include "src/core/SkSpecialSurface.h"
16 #include "tests/Test.h"
17 
18 #include "include/gpu/GrBackendSurface.h"
19 #include "include/gpu/GrContext.h"
20 #include "src/gpu/GrBitmapTextureMaker.h"
21 #include "src/gpu/GrContextPriv.h"
22 #include "src/gpu/GrProxyProvider.h"
23 #include "src/gpu/GrSurfaceProxy.h"
24 #include "src/gpu/GrTextureProxy.h"
25 #include "src/gpu/SkGr.h"
26 
27 
28 // This test creates backing resources exactly sized to [kFullSize x kFullSize].
29 // It then wraps them in an SkSpecialImage with only the center (red) region being active.
30 // It then draws the SkSpecialImage to a full sized (all blue) canvas and checks that none
31 // of the inactive (green) region leaked out.
32 
33 static const int kSmallerSize = 10;
34 static const int kPad = 3;
35 static const int kFullSize = kSmallerSize + 2 * kPad;
36 
37 // Create a bitmap with red in the center and green around it
create_bm()38 static SkBitmap create_bm() {
39     SkImageInfo ii = SkImageInfo::Make(kFullSize, kFullSize, kRGBA_8888_SkColorType,
40                                        kPremul_SkAlphaType);
41 
42     SkBitmap bm;
43     bm.allocPixels(ii);
44 
45     SkCanvas temp(bm);
46 
47     temp.clear(SK_ColorGREEN);
48     SkPaint p;
49     p.setColor(SK_ColorRED);
50     p.setAntiAlias(false);
51 
52     temp.drawRect(SkRect::MakeXYWH(SkIntToScalar(kPad), SkIntToScalar(kPad),
53                                    SkIntToScalar(kSmallerSize), SkIntToScalar(kSmallerSize)),
54                   p);
55 
56     bm.setImmutable();
57     return bm;
58 }
59 
60 // Basic test of the SkSpecialImage public API (e.g., peekTexture, peekPixels & draw)
test_image(const sk_sp<SkSpecialImage> & img,skiatest::Reporter * reporter,GrContext * context,bool isGPUBacked)61 static void test_image(const sk_sp<SkSpecialImage>& img, skiatest::Reporter* reporter,
62                        GrContext* context, bool isGPUBacked) {
63     const SkIRect subset = img->subset();
64     REPORTER_ASSERT(reporter, kPad == subset.left());
65     REPORTER_ASSERT(reporter, kPad == subset.top());
66     REPORTER_ASSERT(reporter, kSmallerSize == subset.width());
67     REPORTER_ASSERT(reporter, kSmallerSize == subset.height());
68 
69     //--------------
70     // Test that isTextureBacked reports the correct backing type
71     REPORTER_ASSERT(reporter, isGPUBacked == img->isTextureBacked());
72 
73     //--------------
74     // Test view - as long as there is a context this should succeed
75     if (context) {
76         GrSurfaceProxyView view = img->view(context);
77         REPORTER_ASSERT(reporter, view.asTextureProxy());
78     }
79 
80     //--------------
81     // Test getROPixels - this should always succeed regardless of backing store
82     SkBitmap bitmap;
83     REPORTER_ASSERT(reporter, img->getROPixels(&bitmap));
84     REPORTER_ASSERT(reporter, kSmallerSize == bitmap.width());
85     REPORTER_ASSERT(reporter, kSmallerSize == bitmap.height());
86 
87     //--------------
88     // Test that draw restricts itself to the subset
89     sk_sp<SkSpecialSurface> surf(img->makeSurface(kN32_SkColorType, img->getColorSpace(),
90                                                   SkISize::Make(kFullSize, kFullSize),
91                                                   kPremul_SkAlphaType));
92 
93     SkCanvas* canvas = surf->getCanvas();
94 
95     canvas->clear(SK_ColorBLUE);
96     img->draw(canvas, SkIntToScalar(kPad), SkIntToScalar(kPad), nullptr);
97 
98     SkBitmap bm;
99     bm.allocN32Pixels(kFullSize, kFullSize, false);
100 
101     bool result = canvas->readPixels(bm.info(), bm.getPixels(), bm.rowBytes(), 0, 0);
102     SkASSERT_RELEASE(result);
103 
104     // Only the center (red) portion should've been drawn into the canvas
105     REPORTER_ASSERT(reporter, SK_ColorBLUE == bm.getColor(kPad-1, kPad-1));
106     REPORTER_ASSERT(reporter, SK_ColorRED  == bm.getColor(kPad, kPad));
107     REPORTER_ASSERT(reporter, SK_ColorRED  == bm.getColor(kSmallerSize+kPad-1,
108                                                           kSmallerSize+kPad-1));
109     REPORTER_ASSERT(reporter, SK_ColorBLUE == bm.getColor(kSmallerSize+kPad,
110                                                           kSmallerSize+kPad));
111 
112     //--------------
113     // Test that asImage & makeTightSurface return appropriately sized objects
114     // of the correct backing type
115     SkIRect newSubset = SkIRect::MakeWH(subset.width(), subset.height());
116     {
117         sk_sp<SkImage> tightImg(img->asImage(&newSubset));
118 
119         REPORTER_ASSERT(reporter, tightImg->width() == subset.width());
120         REPORTER_ASSERT(reporter, tightImg->height() == subset.height());
121         REPORTER_ASSERT(reporter, isGPUBacked == tightImg->isTextureBacked());
122         SkPixmap tmpPixmap;
123         REPORTER_ASSERT(reporter, isGPUBacked != !!tightImg->peekPixels(&tmpPixmap));
124     }
125     {
126         sk_sp<SkSurface> tightSurf(img->makeTightSurface(kN32_SkColorType, img->getColorSpace(),
127                                                          subset.size()));
128 
129         REPORTER_ASSERT(reporter, tightSurf->width() == subset.width());
130         REPORTER_ASSERT(reporter, tightSurf->height() == subset.height());
131         GrBackendTexture backendTex = tightSurf->getBackendTexture(
132                                                     SkSurface::kDiscardWrite_BackendHandleAccess);
133         REPORTER_ASSERT(reporter, isGPUBacked == backendTex.isValid());
134         SkPixmap tmpPixmap;
135         REPORTER_ASSERT(reporter, isGPUBacked != !!tightSurf->peekPixels(&tmpPixmap));
136     }
137 }
138 
DEF_TEST(SpecialImage_Raster,reporter)139 DEF_TEST(SpecialImage_Raster, reporter) {
140     SkBitmap bm = create_bm();
141 
142     sk_sp<SkSpecialImage> fullSImage(SkSpecialImage::MakeFromRaster(
143                                                             SkIRect::MakeWH(kFullSize, kFullSize),
144                                                             bm));
145 
146     const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
147 
148     {
149         sk_sp<SkSpecialImage> subSImg1(SkSpecialImage::MakeFromRaster(subset, bm));
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(SkImage::MakeFromBitmap(bm));
163 
164     sk_sp<SkSpecialImage> fullSImage(SkSpecialImage::MakeFromImage(
165                                                             nullptr,
166                                                             SkIRect::MakeWH(kFullSize, kFullSize),
167                                                             fullImage));
168 
169     const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
170 
171     {
172         sk_sp<SkSpecialImage> subSImg1(SkSpecialImage::MakeFromImage(nullptr, subset, fullImage));
173         test_image(subSImg1, reporter, nullptr, false);
174     }
175 
176     {
177         sk_sp<SkSpecialImage> subSImg2(fullSImage->makeSubset(subset));
178         test_image(subSImg2, reporter, nullptr, false);
179     }
180 }
181 
DEF_TEST(SpecialImage_Image_Legacy,reporter)182 DEF_TEST(SpecialImage_Image_Legacy, reporter) {
183     test_specialimage_image(reporter);
184 }
185 
test_texture_backed(skiatest::Reporter * reporter,const sk_sp<SkSpecialImage> & orig,const sk_sp<SkSpecialImage> & gpuBacked)186 static void test_texture_backed(skiatest::Reporter* reporter,
187                                 const sk_sp<SkSpecialImage>& orig,
188                                 const sk_sp<SkSpecialImage>& gpuBacked) {
189     REPORTER_ASSERT(reporter, gpuBacked);
190     REPORTER_ASSERT(reporter, gpuBacked->isTextureBacked());
191     REPORTER_ASSERT(reporter, gpuBacked->uniqueID() == orig->uniqueID());
192     REPORTER_ASSERT(reporter, gpuBacked->subset().width() == orig->subset().width() &&
193                               gpuBacked->subset().height() == orig->subset().height());
194     REPORTER_ASSERT(reporter, gpuBacked->getColorSpace() == orig->getColorSpace());
195 }
196 
197 // Test out the SkSpecialImage::makeTextureImage entry point
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SpecialImage_MakeTexture,reporter,ctxInfo)198 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SpecialImage_MakeTexture, reporter, ctxInfo) {
199     GrContext* context = ctxInfo.grContext();
200     SkBitmap bm = create_bm();
201 
202     const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
203 
204     {
205         // raster
206         sk_sp<SkSpecialImage> rasterImage(SkSpecialImage::MakeFromRaster(
207                                                                         SkIRect::MakeWH(kFullSize,
208                                                                                         kFullSize),
209                                                                         bm));
210 
211         {
212             sk_sp<SkSpecialImage> fromRaster(rasterImage->makeTextureImage(context));
213             test_texture_backed(reporter, rasterImage, fromRaster);
214         }
215 
216         {
217             sk_sp<SkSpecialImage> subRasterImage(rasterImage->makeSubset(subset));
218 
219             sk_sp<SkSpecialImage> fromSubRaster(subRasterImage->makeTextureImage(context));
220             test_texture_backed(reporter, subRasterImage, fromSubRaster);
221         }
222     }
223 
224     {
225         // gpu
226         GrBitmapTextureMaker maker(context, bm);
227         auto[view, grCT] = maker.view(GrMipMapped::kNo);
228         if (!view.proxy()) {
229             return;
230         }
231 
232         sk_sp<SkSpecialImage> gpuImage(SkSpecialImage::MakeDeferredFromGpu(
233                                                             context,
234                                                             SkIRect::MakeWH(kFullSize, kFullSize),
235                                                             kNeedNewImageUniqueID_SpecialImage,
236                                                             std::move(view),
237                                                             grCT,
238                                                             nullptr));
239 
240         {
241             sk_sp<SkSpecialImage> fromGPU(gpuImage->makeTextureImage(context));
242             test_texture_backed(reporter, gpuImage, fromGPU);
243         }
244 
245         {
246             sk_sp<SkSpecialImage> subGPUImage(gpuImage->makeSubset(subset));
247 
248             sk_sp<SkSpecialImage> fromSubGPU(subGPUImage->makeTextureImage(context));
249             test_texture_backed(reporter, subGPUImage, fromSubGPU);
250         }
251     }
252 }
253 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SpecialImage_Gpu,reporter,ctxInfo)254 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SpecialImage_Gpu, reporter, ctxInfo) {
255     GrContext* context = ctxInfo.grContext();
256     SkBitmap bm = create_bm();
257     GrBitmapTextureMaker maker(context, bm);
258     auto[view, grCT] = maker.view(GrMipMapped::kNo);
259     if (!view.proxy()) {
260         return;
261     }
262 
263     sk_sp<SkSpecialImage> fullSImg(SkSpecialImage::MakeDeferredFromGpu(
264                                                             context,
265                                                             SkIRect::MakeWH(kFullSize, kFullSize),
266                                                             kNeedNewImageUniqueID_SpecialImage,
267                                                             view,
268                                                             grCT,
269                                                             nullptr));
270 
271     const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
272 
273     {
274         sk_sp<SkSpecialImage> subSImg1(SkSpecialImage::MakeDeferredFromGpu(
275                                                                context, subset,
276                                                                kNeedNewImageUniqueID_SpecialImage,
277                                                                std::move(view),
278                                                                grCT,
279                                                                nullptr));
280         test_image(subSImg1, reporter, context, true);
281     }
282 
283     {
284         sk_sp<SkSpecialImage> subSImg2(fullSImg->makeSubset(subset));
285         test_image(subSImg2, reporter, context, true);
286     }
287 }
288 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SpecialImage_ReadbackAndCachingSubsets_Gpu,reporter,ctxInfo)289 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SpecialImage_ReadbackAndCachingSubsets_Gpu, reporter, ctxInfo) {
290     GrContext* context = ctxInfo.grContext();
291     SkImageInfo ii = SkImageInfo::Make(50, 50, kN32_SkColorType, kPremul_SkAlphaType);
292     auto surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, ii);
293 
294     // Fill out our surface:
295     // Green | Blue
296     //  Red  | Green
297     {
298         surface->getCanvas()->clear(SK_ColorGREEN);
299         SkPaint p;
300         p.setColor(SK_ColorRED);
301         surface->getCanvas()->drawRect(SkRect::MakeXYWH(0, 25, 25, 25), p);
302         p.setColor(SK_ColorBLUE);
303         surface->getCanvas()->drawRect(SkRect::MakeXYWH(25, 0, 25, 25), p);
304     }
305 
306     auto image = surface->makeImageSnapshot();
307     auto redImg  = SkSpecialImage::MakeFromImage(context, SkIRect::MakeXYWH(10, 30, 10, 10), image);
308     auto blueImg = SkSpecialImage::MakeFromImage(context, SkIRect::MakeXYWH(30, 10, 10, 10), image);
309 
310     // This isn't necessary, but if it ever becomes false, then the cache collision bug that we're
311     // checking below is irrelevant.
312     REPORTER_ASSERT(reporter, redImg->uniqueID() == blueImg->uniqueID());
313 
314     SkBitmap redBM, blueBM;
315     SkAssertResult(redImg->getROPixels(&redBM));
316     SkAssertResult(blueImg->getROPixels(&blueBM));
317 
318     // Each image should read from the correct sub-rect. Past bugs (skbug.com/8448) have included:
319     // - Always reading back from (0, 0), producing green
320     // - Incorrectly hitting the cache on the 2nd read-back, causing blueBM to be red
321     REPORTER_ASSERT(reporter, redBM.getColor(0, 0) == SK_ColorRED,
322                     "0x%08x != 0x%08x", redBM.getColor(0, 0), SK_ColorRED);
323     REPORTER_ASSERT(reporter, blueBM.getColor(0, 0) == SK_ColorBLUE,
324                     "0x%08x != 0x%08x", blueBM.getColor(0, 0), SK_ColorBLUE);
325 }
326