blob: d271966979a036325841658011bf5ca18e706edc [file] [log] [blame]
reed871872f2015-06-22 12:48:26 -07001/*
2 * Copyright 2015 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 "SkCanvas.h"
9#include "SkData.h"
10#include "SkDevice.h"
11#include "SkImageEncoder.h"
12#include "SkImage_Base.h"
fmalita2be71252015-09-03 07:17:25 -070013#include "SkPixelSerializer.h"
reed871872f2015-06-22 12:48:26 -070014#include "SkRRect.h"
15#include "SkSurface.h"
16#include "SkUtils.h"
17#include "Test.h"
18
19#if SK_SUPPORT_GPU
20#include "GrContextFactory.h"
21#include "GrTest.h"
22#include "gl/GrGLInterface.h"
23#include "gl/GrGLUtil.h"
24#else
25class GrContextFactory;
26class GrContext;
27#endif
28
29static void assert_equal(skiatest::Reporter* reporter, SkImage* a, const SkIRect* subsetA,
30 SkImage* b) {
31 const int widthA = subsetA ? subsetA->width() : a->width();
32 const int heightA = subsetA ? subsetA->height() : a->height();
33
34 REPORTER_ASSERT(reporter, widthA == b->width());
35 REPORTER_ASSERT(reporter, heightA == b->height());
36#if 0
37 // see skbug.com/3965
38 bool AO = a->isOpaque();
39 bool BO = b->isOpaque();
40 REPORTER_ASSERT(reporter, AO == BO);
41#endif
42
43 SkImageInfo info = SkImageInfo::MakeN32(widthA, heightA,
44 a->isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
45 SkAutoPixmapStorage pmapA, pmapB;
46 pmapA.alloc(info);
47 pmapB.alloc(info);
48
49 const int srcX = subsetA ? subsetA->x() : 0;
50 const int srcY = subsetA ? subsetA->y() : 0;
51
52 REPORTER_ASSERT(reporter, a->readPixels(pmapA, srcX, srcY));
53 REPORTER_ASSERT(reporter, b->readPixels(pmapB, 0, 0));
54
55 const size_t widthBytes = widthA * info.bytesPerPixel();
56 for (int y = 0; y < heightA; ++y) {
57 REPORTER_ASSERT(reporter, !memcmp(pmapA.addr32(0, y), pmapB.addr32(0, y), widthBytes));
58 }
59}
60
61static SkImage* make_image(GrContext* ctx, int w, int h, const SkIRect& ir) {
62 const SkImageInfo info = SkImageInfo::MakeN32(w, h, kOpaque_SkAlphaType);
63 SkAutoTUnref<SkSurface> surface(ctx ?
64 SkSurface::NewRenderTarget(ctx, SkSurface::kNo_Budgeted, info) :
65 SkSurface::NewRaster(info));
66 SkCanvas* canvas = surface->getCanvas();
67 canvas->clear(SK_ColorWHITE);
68
69 SkPaint paint;
70 paint.setColor(SK_ColorBLACK);
71 canvas->drawRect(SkRect::Make(ir), paint);
72 return surface->newImageSnapshot();
73}
74
75static void test_encode(skiatest::Reporter* reporter, GrContext* ctx) {
76 const SkIRect ir = SkIRect::MakeXYWH(5, 5, 10, 10);
77 SkAutoTUnref<SkImage> orig(make_image(ctx, 20, 20, ir));
78 SkAutoTUnref<SkData> origEncoded(orig->encode());
79 REPORTER_ASSERT(reporter, origEncoded);
80 REPORTER_ASSERT(reporter, origEncoded->size() > 0);
81
82 SkAutoTUnref<SkImage> decoded(SkImage::NewFromEncoded(origEncoded));
83 REPORTER_ASSERT(reporter, decoded);
halcanary96fcdcc2015-08-27 07:41:13 -070084 assert_equal(reporter, orig, nullptr, decoded);
reed871872f2015-06-22 12:48:26 -070085
86 // Now see if we can instantiate an image from a subset of the surface/origEncoded
87
88 decoded.reset(SkImage::NewFromEncoded(origEncoded, &ir));
89 REPORTER_ASSERT(reporter, decoded);
90 assert_equal(reporter, orig, &ir, decoded);
91}
92
93DEF_TEST(Image_Encode_Cpu, reporter) {
halcanary96fcdcc2015-08-27 07:41:13 -070094 test_encode(reporter, nullptr);
reed871872f2015-06-22 12:48:26 -070095}
96
97#if SK_SUPPORT_GPU
98DEF_GPUTEST(Image_Encode_Gpu, reporter, factory) {
99 GrContext* ctx = factory->get(GrContextFactory::kNative_GLContextType);
100 if (!ctx) {
101 REPORTER_ASSERT(reporter, false);
102 return;
103 }
104 test_encode(reporter, ctx);
105}
106#endif
reed759373a2015-07-03 21:01:10 -0700107
fmalita2be71252015-09-03 07:17:25 -0700108namespace {
109
110const char* kSerializedData = "serialized";
111
112class MockSerializer : public SkPixelSerializer {
113protected:
114 bool onUseEncodedData(const void*, size_t) override {
115 return false;
116 }
117
118 SkData* onEncodePixels(const SkImageInfo&, const void*, size_t) override {
119 return SkData::NewWithCString(kSerializedData);
120 }
121};
122
123} // anonymous namespace
124
125// Test that SkImage encoding observes custom pixel serializers.
126DEF_TEST(Image_Encode_Serializer, reporter) {
127 MockSerializer serializer;
128 const SkIRect ir = SkIRect::MakeXYWH(5, 5, 10, 10);
129 SkAutoTUnref<SkImage> image(make_image(nullptr, 20, 20, ir));
130 SkAutoTUnref<SkData> encoded(image->encode(&serializer));
131 SkAutoTUnref<SkData> reference(SkData::NewWithCString(kSerializedData));
132
133 REPORTER_ASSERT(reporter, encoded);
134 REPORTER_ASSERT(reporter, encoded->size() > 0);
135 REPORTER_ASSERT(reporter, encoded->equals(reference));
136}
137
reed759373a2015-07-03 21:01:10 -0700138DEF_TEST(Image_NewRasterCopy, reporter) {
139 const SkPMColor red = SkPackARGB32(0xFF, 0xFF, 0, 0);
140 const SkPMColor green = SkPackARGB32(0xFF, 0, 0xFF, 0);
141 const SkPMColor blue = SkPackARGB32(0xFF, 0, 0, 0xFF);
142 SkPMColor colors[] = { red, green, blue, 0 };
halcanary385fe4d2015-08-26 13:07:48 -0700143 SkAutoTUnref<SkColorTable> ctable(new SkColorTable(colors, SK_ARRAY_COUNT(colors)));
reed759373a2015-07-03 21:01:10 -0700144 // The colortable made a copy, so we can trash the original colors
145 memset(colors, 0xFF, sizeof(colors));
146
147 const SkImageInfo srcInfo = SkImageInfo::Make(2, 2, kIndex_8_SkColorType, kPremul_SkAlphaType);
148 const size_t srcRowBytes = 2 * sizeof(uint8_t);
149 uint8_t indices[] = { 0, 1, 2, 3 };
150 SkAutoTUnref<SkImage> image(SkImage::NewRasterCopy(srcInfo, indices, srcRowBytes, ctable));
151 // The image made a copy, so we can trash the original indices
152 memset(indices, 0xFF, sizeof(indices));
153
154 const SkImageInfo dstInfo = SkImageInfo::MakeN32Premul(2, 2);
155 const size_t dstRowBytes = 2 * sizeof(SkPMColor);
156 SkPMColor pixels[4];
157 memset(pixels, 0xFF, sizeof(pixels)); // init with values we don't expect
158 image->readPixels(dstInfo, pixels, dstRowBytes, 0, 0);
159 REPORTER_ASSERT(reporter, red == pixels[0]);
160 REPORTER_ASSERT(reporter, green == pixels[1]);
161 REPORTER_ASSERT(reporter, blue == pixels[2]);
162 REPORTER_ASSERT(reporter, 0 == pixels[3]);
163}
fmalita8c0144c2015-07-22 05:56:16 -0700164
165// Test that a draw that only partially covers the drawing surface isn't
166// interpreted as covering the entire drawing surface (i.e., exercise one of the
167// conditions of SkCanvas::wouldOverwriteEntireSurface()).
168DEF_TEST(Image_RetainSnapshot, reporter) {
169 const SkPMColor red = SkPackARGB32(0xFF, 0xFF, 0, 0);
170 const SkPMColor green = SkPackARGB32(0xFF, 0, 0xFF, 0);
171 SkImageInfo info = SkImageInfo::MakeN32Premul(2, 2);
172 SkAutoTUnref<SkSurface> surface(SkSurface::NewRaster(info));
173 surface->getCanvas()->clear(0xFF00FF00);
174
175 SkPMColor pixels[4];
176 memset(pixels, 0xFF, sizeof(pixels)); // init with values we don't expect
177 const SkImageInfo dstInfo = SkImageInfo::MakeN32Premul(2, 2);
178 const size_t dstRowBytes = 2 * sizeof(SkPMColor);
179
180 SkAutoTUnref<SkImage> image1(surface->newImageSnapshot());
181 REPORTER_ASSERT(reporter, image1->readPixels(dstInfo, pixels, dstRowBytes, 0, 0));
182 for (size_t i = 0; i < SK_ARRAY_COUNT(pixels); ++i) {
183 REPORTER_ASSERT(reporter, pixels[i] == green);
184 }
185
186 SkPaint paint;
187 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
188 paint.setColor(SK_ColorRED);
189
190 surface->getCanvas()->drawRect(SkRect::MakeXYWH(1, 1, 1, 1), paint);
191
192 SkAutoTUnref<SkImage> image2(surface->newImageSnapshot());
193 REPORTER_ASSERT(reporter, image2->readPixels(dstInfo, pixels, dstRowBytes, 0, 0));
194 REPORTER_ASSERT(reporter, pixels[0] == green);
195 REPORTER_ASSERT(reporter, pixels[1] == green);
196 REPORTER_ASSERT(reporter, pixels[2] == green);
197 REPORTER_ASSERT(reporter, pixels[3] == red);
198}
reed80c772b2015-07-30 18:58:23 -0700199
200/////////////////////////////////////////////////////////////////////////////////////////////////
201#include "SkImageGenerator.h"
202#include "SkData.h"
203
204const uint8_t tiny_png[] = {
205 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
206 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x64,
207 0x08, 0x06, 0x00, 0x00, 0x00, 0x70, 0xe2, 0x95, 0x54, 0x00, 0x00, 0x00,
208 0x01, 0x73, 0x52, 0x47, 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
209 0x01, 0x6b, 0x49, 0x44, 0x41, 0x54, 0x78, 0x01, 0xed, 0xd3, 0x41, 0x11,
210 0x00, 0x20, 0x0c, 0xc4, 0x40, 0xc0, 0xbf, 0xe7, 0xc2, 0xa0, 0x22, 0x8f,
211 0xad, 0x82, 0x4c, 0xd2, 0xdb, 0xf3, 0x6e, 0xb9, 0x8c, 0x81, 0x93, 0x21,
212 0x01, 0xf2, 0x0d, 0x08, 0x12, 0x7b, 0x04, 0x41, 0x04, 0x89, 0x19, 0x88,
213 0xe1, 0x58, 0x88, 0x20, 0x31, 0x03, 0x31, 0x1c, 0x0b, 0x11, 0x24, 0x66,
214 0x20, 0x86, 0x63, 0x21, 0x82, 0xc4, 0x0c, 0xc4, 0x70, 0x2c, 0x44, 0x90,
215 0x98, 0x81, 0x18, 0x8e, 0x85, 0x08, 0x12, 0x33, 0x10, 0xc3, 0xb1, 0x10,
216 0x41, 0x62, 0x06, 0x62, 0x38, 0x16, 0x22, 0x48, 0xcc, 0x40, 0x0c, 0xc7,
217 0x42, 0x04, 0x89, 0x19, 0x88, 0xe1, 0x58, 0x88, 0x20, 0x31, 0x03, 0x31,
218 0x1c, 0x0b, 0x11, 0x24, 0x66, 0x20, 0x86, 0x63, 0x21, 0x82, 0xc4, 0x0c,
219 0xc4, 0x70, 0x2c, 0x44, 0x90, 0x98, 0x81, 0x18, 0x8e, 0x85, 0x08, 0x12,
220 0x33, 0x10, 0xc3, 0xb1, 0x10, 0x41, 0x62, 0x06, 0x62, 0x38, 0x16, 0x22,
221 0x48, 0xcc, 0x40, 0x0c, 0xc7, 0x42, 0x04, 0x89, 0x19, 0x88, 0xe1, 0x58,
222 0x88, 0x20, 0x31, 0x03, 0x31, 0x1c, 0x0b, 0x11, 0x24, 0x66, 0x20, 0x86,
223 0x63, 0x21, 0x82, 0xc4, 0x0c, 0xc4, 0x70, 0x2c, 0x44, 0x90, 0x98, 0x81,
224 0x18, 0x8e, 0x85, 0x08, 0x12, 0x33, 0x10, 0xc3, 0xb1, 0x10, 0x41, 0x62,
225 0x06, 0x62, 0x38, 0x16, 0x22, 0x48, 0xcc, 0x40, 0x0c, 0xc7, 0x42, 0x04,
226 0x89, 0x19, 0x88, 0xe1, 0x58, 0x88, 0x20, 0x31, 0x03, 0x31, 0x1c, 0x0b,
227 0x11, 0x24, 0x66, 0x20, 0x86, 0x63, 0x21, 0x82, 0xc4, 0x0c, 0xc4, 0x70,
228 0x2c, 0x44, 0x90, 0x98, 0x81, 0x18, 0x8e, 0x85, 0x08, 0x12, 0x33, 0x10,
229 0xc3, 0xb1, 0x10, 0x41, 0x62, 0x06, 0x62, 0x38, 0x16, 0x22, 0x48, 0xcc,
230 0x40, 0x0c, 0xc7, 0x42, 0x04, 0x89, 0x19, 0x88, 0xe1, 0x58, 0x88, 0x20,
231 0x31, 0x03, 0x31, 0x1c, 0x0b, 0x11, 0x24, 0x66, 0x20, 0x86, 0x63, 0x21,
232 0x82, 0xc4, 0x0c, 0xc4, 0x70, 0x2c, 0x44, 0x90, 0x98, 0x81, 0x18, 0x8e,
233 0x85, 0x08, 0x12, 0x33, 0x10, 0xc3, 0xb1, 0x10, 0x41, 0x62, 0x06, 0x62,
234 0x38, 0x16, 0x22, 0x48, 0xcc, 0x40, 0x0c, 0xc7, 0x42, 0x04, 0x89, 0x19,
235 0x88, 0xe1, 0x58, 0x88, 0x20, 0x31, 0x03, 0x31, 0x1c, 0x0b, 0x11, 0x24,
236 0x66, 0x20, 0x86, 0x63, 0x21, 0x82, 0xc4, 0x0c, 0xc4, 0x70, 0x2c, 0x44,
237 0x90, 0x98, 0x81, 0x18, 0x8e, 0x85, 0x08, 0x12, 0x33, 0x10, 0xc3, 0xb1,
238 0x10, 0x41, 0x62, 0x06, 0x62, 0x38, 0x16, 0x22, 0x48, 0xcc, 0x40, 0x0c,
239 0xc7, 0x42, 0x62, 0x41, 0x2e, 0x08, 0x60, 0x04, 0xc4, 0x4c, 0x5d, 0x6e,
240 0xf2, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60,
241 0x82
242};
243
244static void make_bitmap_lazy(SkBitmap* bm) {
245 SkAutoTUnref<SkData> data(SkData::NewWithoutCopy(tiny_png, sizeof(tiny_png)));
246 SkInstallDiscardablePixelRef(data, bm);
247}
248
249static void make_bitmap_mutable(SkBitmap* bm) {
250 bm->allocN32Pixels(10, 10);
251}
252
253static void make_bitmap_immutable(SkBitmap* bm) {
254 bm->allocN32Pixels(10, 10);
255 bm->setImmutable();
256}
257
258DEF_TEST(image_newfrombitmap, reporter) {
259 const struct {
260 void (*fMakeProc)(SkBitmap*);
261 bool fExpectPeekSuccess;
262 bool fExpectSharedID;
fmalitaddbbdda2015-08-20 08:47:26 -0700263 bool fExpectLazy;
reed80c772b2015-07-30 18:58:23 -0700264 } rec[] = {
fmalitaddbbdda2015-08-20 08:47:26 -0700265 { make_bitmap_lazy, false, true, true },
266 { make_bitmap_mutable, true, false, false },
267 { make_bitmap_immutable, true, true, false },
reed80c772b2015-07-30 18:58:23 -0700268 };
269
270 for (size_t i = 0; i < SK_ARRAY_COUNT(rec); ++i) {
271 SkBitmap bm;
272 rec[i].fMakeProc(&bm);
273
274 SkAutoTUnref<SkImage> image(SkImage::NewFromBitmap(bm));
275 SkPixmap pmap;
276
277 const bool sharedID = (image->uniqueID() == bm.getGenerationID());
278 REPORTER_ASSERT(reporter, sharedID == rec[i].fExpectSharedID);
279
reed80c772b2015-07-30 18:58:23 -0700280 const bool peekSuccess = image->peekPixels(&pmap);
281 REPORTER_ASSERT(reporter, peekSuccess == rec[i].fExpectPeekSuccess);
fmalitaddbbdda2015-08-20 08:47:26 -0700282
283 const bool lazy = image->isLazyGenerated();
284 REPORTER_ASSERT(reporter, lazy == rec[i].fExpectLazy);
reed80c772b2015-07-30 18:58:23 -0700285 }
286}
reed6f1216a2015-08-04 08:10:13 -0700287
288///////////////////////////////////////////////////////////////////////////////////////////////////
289#if SK_SUPPORT_GPU
290
291static SkImage* make_gpu_image(GrContext* ctx, const SkImageInfo& info, SkColor color) {
292 const SkSurface::Budgeted budgeted = SkSurface::kNo_Budgeted;
293 SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTarget(ctx, budgeted, info, 0));
294 surface->getCanvas()->drawColor(color);
295 return surface->newImageSnapshot();
296}
297
298#include "SkBitmapCache.h"
299
300/*
301 * This tests the caching (and preemptive purge) of the raster equivalent of a gpu-image.
302 * We cache it for performance when drawing into a raster surface.
303 *
304 * A cleaner test would know if each drawImage call triggered a read-back from the gpu,
305 * but we don't have that facility (at the moment) so we use a little internal knowledge
306 * of *how* the raster version is cached, and look for that.
307 */
308DEF_GPUTEST(SkImage_Gpu2Cpu, reporter, factory) {
309 GrContext* ctx = factory->get(GrContextFactory::kNative_GLContextType);
310 if (!ctx) {
311 REPORTER_ASSERT(reporter, false);
312 return;
313 }
314
315 const SkImageInfo info = SkImageInfo::MakeN32Premul(10, 10);
316 SkAutoTUnref<SkImage> image(make_gpu_image(ctx, info, SK_ColorRED));
317 const uint32_t uniqueID = image->uniqueID();
318
319 SkAutoTUnref<SkSurface> surface(SkSurface::NewRaster(info));
320
321 // now we can test drawing a gpu-backed image into a cpu-backed surface
322
323 {
324 SkBitmap cachedBitmap;
325 REPORTER_ASSERT(reporter, !SkBitmapCache::Find(uniqueID, &cachedBitmap));
326 }
327
328 surface->getCanvas()->drawImage(image, 0, 0);
329 {
330 SkBitmap cachedBitmap;
331 if (SkBitmapCache::Find(uniqueID, &cachedBitmap)) {
332 REPORTER_ASSERT(reporter, cachedBitmap.getGenerationID() == uniqueID);
333 REPORTER_ASSERT(reporter, cachedBitmap.isImmutable());
334 REPORTER_ASSERT(reporter, cachedBitmap.getPixels());
335 } else {
336 // unexpected, but not really a bug, since the cache is global and this test may be
337 // run w/ other threads competing for its budget.
338 SkDebugf("SkImage_Gpu2Cpu : cachedBitmap was already purged\n");
339 }
340 }
341
342 image.reset(nullptr);
343 {
344 SkBitmap cachedBitmap;
345 REPORTER_ASSERT(reporter, !SkBitmapCache::Find(uniqueID, &cachedBitmap));
346 }
347}
348#endif