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