blob: 30e477ab53edbcb5508c8200a837ad1feaf2902e [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"
fmalitac3470342015-09-04 11:36:39 -070013#include "SkPicture.h"
14#include "SkPictureRecorder.h"
fmalita2be71252015-09-03 07:17:25 -070015#include "SkPixelSerializer.h"
reed871872f2015-06-22 12:48:26 -070016#include "SkRRect.h"
fmalitac3470342015-09-04 11:36:39 -070017#include "SkStream.h"
reed871872f2015-06-22 12:48:26 -070018#include "SkSurface.h"
19#include "SkUtils.h"
20#include "Test.h"
21
22#if SK_SUPPORT_GPU
23#include "GrContextFactory.h"
24#include "GrTest.h"
25#include "gl/GrGLInterface.h"
26#include "gl/GrGLUtil.h"
27#else
28class GrContextFactory;
29class GrContext;
30#endif
31
32static void assert_equal(skiatest::Reporter* reporter, SkImage* a, const SkIRect* subsetA,
33 SkImage* b) {
34 const int widthA = subsetA ? subsetA->width() : a->width();
35 const int heightA = subsetA ? subsetA->height() : a->height();
36
37 REPORTER_ASSERT(reporter, widthA == b->width());
38 REPORTER_ASSERT(reporter, heightA == b->height());
39#if 0
40 // see skbug.com/3965
41 bool AO = a->isOpaque();
42 bool BO = b->isOpaque();
43 REPORTER_ASSERT(reporter, AO == BO);
44#endif
45
46 SkImageInfo info = SkImageInfo::MakeN32(widthA, heightA,
47 a->isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
48 SkAutoPixmapStorage pmapA, pmapB;
49 pmapA.alloc(info);
50 pmapB.alloc(info);
51
52 const int srcX = subsetA ? subsetA->x() : 0;
53 const int srcY = subsetA ? subsetA->y() : 0;
54
55 REPORTER_ASSERT(reporter, a->readPixels(pmapA, srcX, srcY));
56 REPORTER_ASSERT(reporter, b->readPixels(pmapB, 0, 0));
57
58 const size_t widthBytes = widthA * info.bytesPerPixel();
59 for (int y = 0; y < heightA; ++y) {
60 REPORTER_ASSERT(reporter, !memcmp(pmapA.addr32(0, y), pmapB.addr32(0, y), widthBytes));
61 }
62}
63
64static SkImage* make_image(GrContext* ctx, int w, int h, const SkIRect& ir) {
65 const SkImageInfo info = SkImageInfo::MakeN32(w, h, kOpaque_SkAlphaType);
66 SkAutoTUnref<SkSurface> surface(ctx ?
67 SkSurface::NewRenderTarget(ctx, SkSurface::kNo_Budgeted, info) :
68 SkSurface::NewRaster(info));
69 SkCanvas* canvas = surface->getCanvas();
70 canvas->clear(SK_ColorWHITE);
71
72 SkPaint paint;
73 paint.setColor(SK_ColorBLACK);
74 canvas->drawRect(SkRect::Make(ir), paint);
75 return surface->newImageSnapshot();
76}
77
78static void test_encode(skiatest::Reporter* reporter, GrContext* ctx) {
79 const SkIRect ir = SkIRect::MakeXYWH(5, 5, 10, 10);
80 SkAutoTUnref<SkImage> orig(make_image(ctx, 20, 20, ir));
81 SkAutoTUnref<SkData> origEncoded(orig->encode());
82 REPORTER_ASSERT(reporter, origEncoded);
83 REPORTER_ASSERT(reporter, origEncoded->size() > 0);
84
85 SkAutoTUnref<SkImage> decoded(SkImage::NewFromEncoded(origEncoded));
86 REPORTER_ASSERT(reporter, decoded);
halcanary96fcdcc2015-08-27 07:41:13 -070087 assert_equal(reporter, orig, nullptr, decoded);
reed871872f2015-06-22 12:48:26 -070088
89 // Now see if we can instantiate an image from a subset of the surface/origEncoded
90
91 decoded.reset(SkImage::NewFromEncoded(origEncoded, &ir));
92 REPORTER_ASSERT(reporter, decoded);
93 assert_equal(reporter, orig, &ir, decoded);
94}
95
96DEF_TEST(Image_Encode_Cpu, reporter) {
halcanary96fcdcc2015-08-27 07:41:13 -070097 test_encode(reporter, nullptr);
reed871872f2015-06-22 12:48:26 -070098}
99
100#if SK_SUPPORT_GPU
101DEF_GPUTEST(Image_Encode_Gpu, reporter, factory) {
102 GrContext* ctx = factory->get(GrContextFactory::kNative_GLContextType);
103 if (!ctx) {
104 REPORTER_ASSERT(reporter, false);
105 return;
106 }
107 test_encode(reporter, ctx);
108}
109#endif
reed759373a2015-07-03 21:01:10 -0700110
fmalita2be71252015-09-03 07:17:25 -0700111namespace {
112
113const char* kSerializedData = "serialized";
114
115class MockSerializer : public SkPixelSerializer {
fmalitac3470342015-09-04 11:36:39 -0700116public:
117 MockSerializer(SkData* (*func)()) : fFunc(func), fDidEncode(false) { }
118
119 bool didEncode() const { return fDidEncode; }
120
fmalita2be71252015-09-03 07:17:25 -0700121protected:
122 bool onUseEncodedData(const void*, size_t) override {
123 return false;
124 }
125
126 SkData* onEncodePixels(const SkImageInfo&, const void*, size_t) override {
fmalitac3470342015-09-04 11:36:39 -0700127 fDidEncode = true;
128 return fFunc();
fmalita2be71252015-09-03 07:17:25 -0700129 }
fmalitac3470342015-09-04 11:36:39 -0700130
131private:
132 SkData* (*fFunc)();
133 bool fDidEncode;
134
135 typedef SkPixelSerializer INHERITED;
fmalita2be71252015-09-03 07:17:25 -0700136};
137
138} // anonymous namespace
139
140// Test that SkImage encoding observes custom pixel serializers.
141DEF_TEST(Image_Encode_Serializer, reporter) {
fmalitac3470342015-09-04 11:36:39 -0700142 MockSerializer serializer([]() -> SkData* { return SkData::NewWithCString(kSerializedData); });
fmalita2be71252015-09-03 07:17:25 -0700143 const SkIRect ir = SkIRect::MakeXYWH(5, 5, 10, 10);
144 SkAutoTUnref<SkImage> image(make_image(nullptr, 20, 20, ir));
145 SkAutoTUnref<SkData> encoded(image->encode(&serializer));
146 SkAutoTUnref<SkData> reference(SkData::NewWithCString(kSerializedData));
147
fmalitac3470342015-09-04 11:36:39 -0700148 REPORTER_ASSERT(reporter, serializer.didEncode());
fmalita2be71252015-09-03 07:17:25 -0700149 REPORTER_ASSERT(reporter, encoded);
150 REPORTER_ASSERT(reporter, encoded->size() > 0);
151 REPORTER_ASSERT(reporter, encoded->equals(reference));
152}
153
fmalitac3470342015-09-04 11:36:39 -0700154// Test that image encoding failures do not break picture serialization/deserialization.
155DEF_TEST(Image_Serialize_Encoding_Failure, reporter) {
156 SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterN32Premul(100, 100));
157 surface->getCanvas()->clear(SK_ColorGREEN);
158 SkAutoTUnref<SkImage> image(surface->newImageSnapshot());
159 REPORTER_ASSERT(reporter, image);
160
161 SkPictureRecorder recorder;
162 SkCanvas* canvas = recorder.beginRecording(100, 100);
163 canvas->drawImage(image, 0, 0);
164 SkAutoTUnref<SkPicture> picture(recorder.endRecording());
165 REPORTER_ASSERT(reporter, picture);
166 REPORTER_ASSERT(reporter, picture->approximateOpCount() > 0);
167
168 MockSerializer emptySerializer([]() -> SkData* { return SkData::NewEmpty(); });
169 MockSerializer nullSerializer([]() -> SkData* { return nullptr; });
170 MockSerializer* serializers[] = { &emptySerializer, &nullSerializer };
171
172 for (size_t i = 0; i < SK_ARRAY_COUNT(serializers); ++i) {
173 SkDynamicMemoryWStream wstream;
174 REPORTER_ASSERT(reporter, !serializers[i]->didEncode());
175 picture->serialize(&wstream, serializers[i]);
176 REPORTER_ASSERT(reporter, serializers[i]->didEncode());
177
178 SkAutoTDelete<SkStream> rstream(wstream.detachAsStream());
179 SkAutoTUnref<SkPicture> deserialized(SkPicture::CreateFromStream(rstream));
180 REPORTER_ASSERT(reporter, deserialized);
181 REPORTER_ASSERT(reporter, deserialized->approximateOpCount() > 0);
182 }
183}
184
reed759373a2015-07-03 21:01:10 -0700185DEF_TEST(Image_NewRasterCopy, reporter) {
186 const SkPMColor red = SkPackARGB32(0xFF, 0xFF, 0, 0);
187 const SkPMColor green = SkPackARGB32(0xFF, 0, 0xFF, 0);
188 const SkPMColor blue = SkPackARGB32(0xFF, 0, 0, 0xFF);
189 SkPMColor colors[] = { red, green, blue, 0 };
halcanary385fe4d2015-08-26 13:07:48 -0700190 SkAutoTUnref<SkColorTable> ctable(new SkColorTable(colors, SK_ARRAY_COUNT(colors)));
reed759373a2015-07-03 21:01:10 -0700191 // The colortable made a copy, so we can trash the original colors
192 memset(colors, 0xFF, sizeof(colors));
193
194 const SkImageInfo srcInfo = SkImageInfo::Make(2, 2, kIndex_8_SkColorType, kPremul_SkAlphaType);
195 const size_t srcRowBytes = 2 * sizeof(uint8_t);
196 uint8_t indices[] = { 0, 1, 2, 3 };
197 SkAutoTUnref<SkImage> image(SkImage::NewRasterCopy(srcInfo, indices, srcRowBytes, ctable));
198 // The image made a copy, so we can trash the original indices
199 memset(indices, 0xFF, sizeof(indices));
200
201 const SkImageInfo dstInfo = SkImageInfo::MakeN32Premul(2, 2);
202 const size_t dstRowBytes = 2 * sizeof(SkPMColor);
203 SkPMColor pixels[4];
204 memset(pixels, 0xFF, sizeof(pixels)); // init with values we don't expect
205 image->readPixels(dstInfo, pixels, dstRowBytes, 0, 0);
206 REPORTER_ASSERT(reporter, red == pixels[0]);
207 REPORTER_ASSERT(reporter, green == pixels[1]);
208 REPORTER_ASSERT(reporter, blue == pixels[2]);
209 REPORTER_ASSERT(reporter, 0 == pixels[3]);
210}
fmalita8c0144c2015-07-22 05:56:16 -0700211
212// Test that a draw that only partially covers the drawing surface isn't
213// interpreted as covering the entire drawing surface (i.e., exercise one of the
214// conditions of SkCanvas::wouldOverwriteEntireSurface()).
215DEF_TEST(Image_RetainSnapshot, reporter) {
216 const SkPMColor red = SkPackARGB32(0xFF, 0xFF, 0, 0);
217 const SkPMColor green = SkPackARGB32(0xFF, 0, 0xFF, 0);
218 SkImageInfo info = SkImageInfo::MakeN32Premul(2, 2);
219 SkAutoTUnref<SkSurface> surface(SkSurface::NewRaster(info));
220 surface->getCanvas()->clear(0xFF00FF00);
221
222 SkPMColor pixels[4];
223 memset(pixels, 0xFF, sizeof(pixels)); // init with values we don't expect
224 const SkImageInfo dstInfo = SkImageInfo::MakeN32Premul(2, 2);
225 const size_t dstRowBytes = 2 * sizeof(SkPMColor);
226
227 SkAutoTUnref<SkImage> image1(surface->newImageSnapshot());
228 REPORTER_ASSERT(reporter, image1->readPixels(dstInfo, pixels, dstRowBytes, 0, 0));
229 for (size_t i = 0; i < SK_ARRAY_COUNT(pixels); ++i) {
230 REPORTER_ASSERT(reporter, pixels[i] == green);
231 }
232
233 SkPaint paint;
234 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
235 paint.setColor(SK_ColorRED);
236
237 surface->getCanvas()->drawRect(SkRect::MakeXYWH(1, 1, 1, 1), paint);
238
239 SkAutoTUnref<SkImage> image2(surface->newImageSnapshot());
240 REPORTER_ASSERT(reporter, image2->readPixels(dstInfo, pixels, dstRowBytes, 0, 0));
241 REPORTER_ASSERT(reporter, pixels[0] == green);
242 REPORTER_ASSERT(reporter, pixels[1] == green);
243 REPORTER_ASSERT(reporter, pixels[2] == green);
244 REPORTER_ASSERT(reporter, pixels[3] == red);
245}
reed80c772b2015-07-30 18:58:23 -0700246
247/////////////////////////////////////////////////////////////////////////////////////////////////
248#include "SkImageGenerator.h"
249#include "SkData.h"
250
251const uint8_t tiny_png[] = {
252 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
253 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x64,
254 0x08, 0x06, 0x00, 0x00, 0x00, 0x70, 0xe2, 0x95, 0x54, 0x00, 0x00, 0x00,
255 0x01, 0x73, 0x52, 0x47, 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
256 0x01, 0x6b, 0x49, 0x44, 0x41, 0x54, 0x78, 0x01, 0xed, 0xd3, 0x41, 0x11,
257 0x00, 0x20, 0x0c, 0xc4, 0x40, 0xc0, 0xbf, 0xe7, 0xc2, 0xa0, 0x22, 0x8f,
258 0xad, 0x82, 0x4c, 0xd2, 0xdb, 0xf3, 0x6e, 0xb9, 0x8c, 0x81, 0x93, 0x21,
259 0x01, 0xf2, 0x0d, 0x08, 0x12, 0x7b, 0x04, 0x41, 0x04, 0x89, 0x19, 0x88,
260 0xe1, 0x58, 0x88, 0x20, 0x31, 0x03, 0x31, 0x1c, 0x0b, 0x11, 0x24, 0x66,
261 0x20, 0x86, 0x63, 0x21, 0x82, 0xc4, 0x0c, 0xc4, 0x70, 0x2c, 0x44, 0x90,
262 0x98, 0x81, 0x18, 0x8e, 0x85, 0x08, 0x12, 0x33, 0x10, 0xc3, 0xb1, 0x10,
263 0x41, 0x62, 0x06, 0x62, 0x38, 0x16, 0x22, 0x48, 0xcc, 0x40, 0x0c, 0xc7,
264 0x42, 0x04, 0x89, 0x19, 0x88, 0xe1, 0x58, 0x88, 0x20, 0x31, 0x03, 0x31,
265 0x1c, 0x0b, 0x11, 0x24, 0x66, 0x20, 0x86, 0x63, 0x21, 0x82, 0xc4, 0x0c,
266 0xc4, 0x70, 0x2c, 0x44, 0x90, 0x98, 0x81, 0x18, 0x8e, 0x85, 0x08, 0x12,
267 0x33, 0x10, 0xc3, 0xb1, 0x10, 0x41, 0x62, 0x06, 0x62, 0x38, 0x16, 0x22,
268 0x48, 0xcc, 0x40, 0x0c, 0xc7, 0x42, 0x04, 0x89, 0x19, 0x88, 0xe1, 0x58,
269 0x88, 0x20, 0x31, 0x03, 0x31, 0x1c, 0x0b, 0x11, 0x24, 0x66, 0x20, 0x86,
270 0x63, 0x21, 0x82, 0xc4, 0x0c, 0xc4, 0x70, 0x2c, 0x44, 0x90, 0x98, 0x81,
271 0x18, 0x8e, 0x85, 0x08, 0x12, 0x33, 0x10, 0xc3, 0xb1, 0x10, 0x41, 0x62,
272 0x06, 0x62, 0x38, 0x16, 0x22, 0x48, 0xcc, 0x40, 0x0c, 0xc7, 0x42, 0x04,
273 0x89, 0x19, 0x88, 0xe1, 0x58, 0x88, 0x20, 0x31, 0x03, 0x31, 0x1c, 0x0b,
274 0x11, 0x24, 0x66, 0x20, 0x86, 0x63, 0x21, 0x82, 0xc4, 0x0c, 0xc4, 0x70,
275 0x2c, 0x44, 0x90, 0x98, 0x81, 0x18, 0x8e, 0x85, 0x08, 0x12, 0x33, 0x10,
276 0xc3, 0xb1, 0x10, 0x41, 0x62, 0x06, 0x62, 0x38, 0x16, 0x22, 0x48, 0xcc,
277 0x40, 0x0c, 0xc7, 0x42, 0x04, 0x89, 0x19, 0x88, 0xe1, 0x58, 0x88, 0x20,
278 0x31, 0x03, 0x31, 0x1c, 0x0b, 0x11, 0x24, 0x66, 0x20, 0x86, 0x63, 0x21,
279 0x82, 0xc4, 0x0c, 0xc4, 0x70, 0x2c, 0x44, 0x90, 0x98, 0x81, 0x18, 0x8e,
280 0x85, 0x08, 0x12, 0x33, 0x10, 0xc3, 0xb1, 0x10, 0x41, 0x62, 0x06, 0x62,
281 0x38, 0x16, 0x22, 0x48, 0xcc, 0x40, 0x0c, 0xc7, 0x42, 0x04, 0x89, 0x19,
282 0x88, 0xe1, 0x58, 0x88, 0x20, 0x31, 0x03, 0x31, 0x1c, 0x0b, 0x11, 0x24,
283 0x66, 0x20, 0x86, 0x63, 0x21, 0x82, 0xc4, 0x0c, 0xc4, 0x70, 0x2c, 0x44,
284 0x90, 0x98, 0x81, 0x18, 0x8e, 0x85, 0x08, 0x12, 0x33, 0x10, 0xc3, 0xb1,
285 0x10, 0x41, 0x62, 0x06, 0x62, 0x38, 0x16, 0x22, 0x48, 0xcc, 0x40, 0x0c,
286 0xc7, 0x42, 0x62, 0x41, 0x2e, 0x08, 0x60, 0x04, 0xc4, 0x4c, 0x5d, 0x6e,
287 0xf2, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60,
288 0x82
289};
290
291static void make_bitmap_lazy(SkBitmap* bm) {
292 SkAutoTUnref<SkData> data(SkData::NewWithoutCopy(tiny_png, sizeof(tiny_png)));
293 SkInstallDiscardablePixelRef(data, bm);
294}
295
296static void make_bitmap_mutable(SkBitmap* bm) {
297 bm->allocN32Pixels(10, 10);
298}
299
300static void make_bitmap_immutable(SkBitmap* bm) {
301 bm->allocN32Pixels(10, 10);
302 bm->setImmutable();
303}
304
305DEF_TEST(image_newfrombitmap, reporter) {
306 const struct {
307 void (*fMakeProc)(SkBitmap*);
308 bool fExpectPeekSuccess;
309 bool fExpectSharedID;
fmalitaddbbdda2015-08-20 08:47:26 -0700310 bool fExpectLazy;
reed80c772b2015-07-30 18:58:23 -0700311 } rec[] = {
fmalitaddbbdda2015-08-20 08:47:26 -0700312 { make_bitmap_lazy, false, true, true },
313 { make_bitmap_mutable, true, false, false },
314 { make_bitmap_immutable, true, true, false },
reed80c772b2015-07-30 18:58:23 -0700315 };
316
317 for (size_t i = 0; i < SK_ARRAY_COUNT(rec); ++i) {
318 SkBitmap bm;
319 rec[i].fMakeProc(&bm);
320
321 SkAutoTUnref<SkImage> image(SkImage::NewFromBitmap(bm));
322 SkPixmap pmap;
323
324 const bool sharedID = (image->uniqueID() == bm.getGenerationID());
325 REPORTER_ASSERT(reporter, sharedID == rec[i].fExpectSharedID);
326
reed80c772b2015-07-30 18:58:23 -0700327 const bool peekSuccess = image->peekPixels(&pmap);
328 REPORTER_ASSERT(reporter, peekSuccess == rec[i].fExpectPeekSuccess);
fmalitaddbbdda2015-08-20 08:47:26 -0700329
330 const bool lazy = image->isLazyGenerated();
331 REPORTER_ASSERT(reporter, lazy == rec[i].fExpectLazy);
reed80c772b2015-07-30 18:58:23 -0700332 }
333}
reed6f1216a2015-08-04 08:10:13 -0700334
335///////////////////////////////////////////////////////////////////////////////////////////////////
336#if SK_SUPPORT_GPU
337
338static SkImage* make_gpu_image(GrContext* ctx, const SkImageInfo& info, SkColor color) {
339 const SkSurface::Budgeted budgeted = SkSurface::kNo_Budgeted;
340 SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTarget(ctx, budgeted, info, 0));
341 surface->getCanvas()->drawColor(color);
342 return surface->newImageSnapshot();
343}
344
345#include "SkBitmapCache.h"
346
347/*
348 * This tests the caching (and preemptive purge) of the raster equivalent of a gpu-image.
349 * We cache it for performance when drawing into a raster surface.
350 *
351 * A cleaner test would know if each drawImage call triggered a read-back from the gpu,
352 * but we don't have that facility (at the moment) so we use a little internal knowledge
353 * of *how* the raster version is cached, and look for that.
354 */
355DEF_GPUTEST(SkImage_Gpu2Cpu, reporter, factory) {
356 GrContext* ctx = factory->get(GrContextFactory::kNative_GLContextType);
357 if (!ctx) {
358 REPORTER_ASSERT(reporter, false);
359 return;
360 }
361
362 const SkImageInfo info = SkImageInfo::MakeN32Premul(10, 10);
363 SkAutoTUnref<SkImage> image(make_gpu_image(ctx, info, SK_ColorRED));
364 const uint32_t uniqueID = image->uniqueID();
365
366 SkAutoTUnref<SkSurface> surface(SkSurface::NewRaster(info));
367
368 // now we can test drawing a gpu-backed image into a cpu-backed surface
369
370 {
371 SkBitmap cachedBitmap;
372 REPORTER_ASSERT(reporter, !SkBitmapCache::Find(uniqueID, &cachedBitmap));
373 }
374
375 surface->getCanvas()->drawImage(image, 0, 0);
376 {
377 SkBitmap cachedBitmap;
378 if (SkBitmapCache::Find(uniqueID, &cachedBitmap)) {
379 REPORTER_ASSERT(reporter, cachedBitmap.getGenerationID() == uniqueID);
380 REPORTER_ASSERT(reporter, cachedBitmap.isImmutable());
381 REPORTER_ASSERT(reporter, cachedBitmap.getPixels());
382 } else {
383 // unexpected, but not really a bug, since the cache is global and this test may be
384 // run w/ other threads competing for its budget.
385 SkDebugf("SkImage_Gpu2Cpu : cachedBitmap was already purged\n");
386 }
387 }
388
389 image.reset(nullptr);
390 {
391 SkBitmap cachedBitmap;
392 REPORTER_ASSERT(reporter, !SkBitmapCache::Find(uniqueID, &cachedBitmap));
393 }
394}
395#endif