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